Compare commits
181 Commits
Author | SHA1 | Date |
---|---|---|
|
dae717db45 | |
|
bcb7c6f857 | |
|
4dcd51f3d4 | |
|
29f98ae0b3 | |
|
7d42288f63 | |
|
500ddc43b2 | |
|
ed231150f5 | |
|
8eb6015afb | |
|
e922caa44b | |
|
e010dd8db8 | |
|
f24b031a7a | |
|
f70702879d | |
|
0c0d7fadd1 | |
|
d6b26e48cb | |
|
a0f0cd9242 | |
|
ec1a351222 | |
|
4189c8bc95 | |
|
75e625746d | |
|
93d4db9ae7 | |
|
9c83aadec6 | |
|
bea646f33f | |
|
3330c91ca1 | |
|
c19e9b90a5 | |
|
f2e5211c96 | |
|
9e5fb10d9e | |
|
d180ac6c77 | |
|
bdcc9439f1 | |
|
f76212d6fa | |
|
1bf1ffb836 | |
|
aca81f2e2c | |
|
69febd97d8 | |
|
a00010d8aa | |
|
dc68a453bb | |
|
fac83ce705 | |
|
0b4ccd846c | |
|
7609724d85 | |
|
ec7ccef247 | |
|
01a2d801e1 | |
|
8a57345794 | |
|
49c1dac6a9 | |
|
8d1b0b3969 | |
|
36fc980ca9 | |
|
1632f3de15 | |
|
1645098a9c | |
|
8717c17359 | |
|
86c5c94646 | |
|
b5057268ff | |
|
242d431be0 | |
|
bf6b44440e | |
|
9281e54ec5 | |
|
98bc417e90 | |
|
d41fec073f | |
|
68d138007f | |
|
682a11b956 | |
|
fdc36f0429 | |
|
0a0303d824 | |
|
9348af6462 | |
|
a9edb876a0 | |
|
a0457e6fd6 | |
|
ae21642e70 | |
|
1c673d44a7 | |
|
052a13b09f | |
|
55825b6614 | |
|
c02c5672c0 | |
|
4903dc7950 | |
|
c01499decb | |
|
ace016cf13 | |
|
85549cfb78 | |
|
bb49983da4 | |
|
f9b7b5fea3 | |
|
b33bf7cc53 | |
|
d0aefa7a6b | |
|
f0d5222281 | |
|
409ece74e1 | |
|
f15403d312 | |
|
00a5463aec | |
|
5256b38fb9 | |
|
078c366a67 | |
|
0cabb8a28c | |
|
f5f856dea6 | |
|
5a4c2cb3b2 | |
|
93814476d8 | |
|
b945940689 | |
|
c967a6dfec | |
|
a45585be98 | |
|
9d2b82bb2c | |
|
6385cbc258 | |
|
64d800cfea | |
|
ac2ec07bbf | |
|
bb49e4d143 | |
|
9ee771aba2 | |
|
7cdf62f1a2 | |
|
7e16303cd6 | |
|
bb2e45875d | |
|
59d25c8804 | |
|
ab2e7fcabc | |
|
1def1163ac | |
|
1cf8702b71 | |
|
df29951635 | |
|
c1a59ac9b2 | |
|
e84ee08afe | |
|
7e815fc868 | |
|
b876af269c | |
|
926b903dd4 | |
|
e319d21149 | |
|
78c8ae824b | |
|
6943d09ada | |
|
cf242560d2 | |
|
d379a15e23 | |
|
8dcb95bf88 | |
|
aa02cdaba8 | |
|
72549b17c2 | |
|
ca02ea199d | |
|
1b5d5ce6a5 | |
|
d93d7b0ca7 | |
|
9d66687a77 | |
|
01d51e04bd | |
|
75723bfdca | |
|
b103f0eef6 | |
|
4574105a66 | |
|
27fc4f77db | |
|
8c125533f2 | |
|
6a016f8302 | |
|
7e4f080618 | |
|
d4718ba562 | |
|
a33960aa22 | |
|
4e1d78f50c | |
|
28773c99b2 | |
|
785a2ef789 | |
|
30dfa7cc7a | |
|
121079fa82 | |
|
af1b337515 | |
|
e872d13f22 | |
|
22d429a855 | |
|
cfe0a0ca25 | |
|
ea5c803f5a | |
|
777e040eea | |
|
c4e67882b2 | |
|
3e96bd1302 | |
|
982fd25a62 | |
|
c4d1c54bad | |
|
199a6d1123 | |
|
f2a2becc06 | |
|
faead2336c | |
|
6e03d2cc84 | |
|
51a5e1c472 | |
|
28d13db797 | |
|
25fa723ff7 | |
|
b8857cde03 | |
|
5f9eaa9b66 | |
|
07d588201a | |
|
48b5b6992f | |
|
3affa650bc | |
|
e091ab4278 | |
|
6a80015097 | |
|
9bf01f2212 | |
|
bae1ed24cc | |
|
c0c6d0e107 | |
|
f11edf7690 | |
|
2a27d21435 | |
|
9d26e0ffa2 | |
|
0a988abf2a | |
|
b52c7a6ca2 | |
|
609e3fea9e | |
|
c4a453bfba | |
|
72fa73ce95 | |
|
2d40bc39ed | |
|
d8bf9d279f | |
|
5736afbcdb | |
|
4d278de297 | |
|
22d79a203e | |
|
6a5804619c | |
|
4df350d9bd | |
|
0d6e337e2a | |
|
c0876f39de | |
|
f4e81a5732 | |
|
d3f9c970dd | |
|
c860a66dd2 | |
|
4c610df43d | |
|
1ebe8c0053 | |
|
008588eeb7 |
|
@ -0,0 +1,40 @@
|
|||
version: 2
|
||||
enable-beta-ecosystems: true
|
||||
updates:
|
||||
- package-ecosystem: gomod
|
||||
directory: "/"
|
||||
allow:
|
||||
- dependency-type: "all"
|
||||
schedule:
|
||||
interval: weekly
|
||||
groups:
|
||||
golang-dependencies:
|
||||
patterns:
|
||||
- "github.com/golang*"
|
||||
k8s-dependencies:
|
||||
patterns:
|
||||
- "k8s.io*"
|
||||
- "sigs.k8s.io*"
|
||||
- "github.com/kubernetes-csi*"
|
||||
github-dependencies:
|
||||
patterns:
|
||||
- "*"
|
||||
exclude-patterns:
|
||||
- "github.com/golang*"
|
||||
- "k8s.io*"
|
||||
- "sigs.k8s.io*"
|
||||
- "github.com/kubernetes-csi*"
|
||||
labels:
|
||||
- "area/dependency"
|
||||
- "release-note-none"
|
||||
- "ok-to-test"
|
||||
open-pull-requests-limit: 10
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- "area/dependency"
|
||||
- "release-note-none"
|
||||
- "ok-to-test"
|
||||
open-pull-requests-limit: 10
|
|
@ -0,0 +1,237 @@
|
|||
# Release notes for v0.10.0
|
||||
|
||||
[Documentation](https://kubernetes-csi.github.io/)
|
||||
|
||||
# Changelog since 0.9.0
|
||||
|
||||
## Changes by Kind
|
||||
|
||||
### Feature
|
||||
|
||||
- Added support structured logging ([#208](https://github.com/kubernetes-csi/external-health-monitor/pull/208), [@bells17](https://github.com/bells17))
|
||||
|
||||
### Uncategorized
|
||||
|
||||
- Update kubernetes dependencies to v1.28.0 ([#207](https://github.com/kubernetes-csi/external-health-monitor/pull/207), [@Sneha-at](https://github.com/Sneha-at))
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Added
|
||||
- github.com/alecthomas/kingpin/v2: [v2.3.2](https://github.com/alecthomas/kingpin/v2/tree/v2.3.2)
|
||||
- github.com/benbjohnson/clock: [v1.1.0](https://github.com/benbjohnson/clock/tree/v1.1.0)
|
||||
- github.com/cpuguy83/go-md2man/v2: [v2.0.2](https://github.com/cpuguy83/go-md2man/v2/tree/v2.0.2)
|
||||
- github.com/google/gnostic-models: [v0.6.8](https://github.com/google/gnostic-models/tree/v0.6.8)
|
||||
- github.com/russross/blackfriday/v2: [v2.1.0](https://github.com/russross/blackfriday/v2/tree/v2.1.0)
|
||||
- github.com/xhit/go-str2duration/v2: [v2.1.0](https://github.com/xhit/go-str2duration/v2/tree/v2.1.0)
|
||||
- google.golang.org/genproto/googleapis/api: 782d3b1
|
||||
- google.golang.org/genproto/googleapis/rpc: 782d3b1
|
||||
|
||||
### Changed
|
||||
- cloud.google.com/go/compute: v1.18.0 → v1.21.0
|
||||
- cloud.google.com/go: v0.110.0 → v0.34.0
|
||||
- github.com/alecthomas/units: [f65c72e → b94a6e3](https://github.com/alecthomas/units/compare/f65c72e...b94a6e3)
|
||||
- github.com/cenkalti/backoff/v4: [v4.1.3 → v4.2.1](https://github.com/cenkalti/backoff/v4/compare/v4.1.3...v4.2.1)
|
||||
- github.com/cncf/xds/go: [32f1caf → e9ce688](https://github.com/cncf/xds/go/compare/32f1caf...e9ce688)
|
||||
- github.com/envoyproxy/go-control-plane: [v0.11.0 → v0.11.1](https://github.com/envoyproxy/go-control-plane/compare/v0.11.0...v0.11.1)
|
||||
- github.com/envoyproxy/protoc-gen-validate: [v0.10.0 → v1.0.2](https://github.com/envoyproxy/protoc-gen-validate/compare/v0.10.0...v1.0.2)
|
||||
- github.com/go-kit/log: [v0.2.0 → v0.2.1](https://github.com/go-kit/log/compare/v0.2.0...v0.2.1)
|
||||
- github.com/go-logr/logr: [v1.2.3 → v1.2.4](https://github.com/go-logr/logr/compare/v1.2.3...v1.2.4)
|
||||
- github.com/go-openapi/jsonreference: [v0.20.1 → v0.20.2](https://github.com/go-openapi/jsonreference/compare/v0.20.1...v0.20.2)
|
||||
- github.com/go-task/slim-sprig: [348f09d → 52ccab3](https://github.com/go-task/slim-sprig/compare/348f09d...52ccab3)
|
||||
- github.com/google/gnostic: [v0.6.9 → v0.5.7-v3refs](https://github.com/google/gnostic/compare/v0.6.9...v0.5.7-v3refs)
|
||||
- github.com/inconshreveable/mousetrap: [v1.0.1 → v1.1.0](https://github.com/inconshreveable/mousetrap/compare/v1.0.1...v1.1.0)
|
||||
- github.com/kr/pretty: [v0.3.0 → v0.3.1](https://github.com/kr/pretty/compare/v0.3.0...v0.3.1)
|
||||
- github.com/kubernetes-csi/csi-lib-utils: [v0.13.0 → v0.14.0](https://github.com/kubernetes-csi/csi-lib-utils/compare/v0.13.0...v0.14.0)
|
||||
- github.com/moby/term: [39b0c02 → 1aeaba8](https://github.com/moby/term/compare/39b0c02...1aeaba8)
|
||||
- github.com/onsi/ginkgo/v2: [v2.9.1 → v2.9.4](https://github.com/onsi/ginkgo/v2/compare/v2.9.1...v2.9.4)
|
||||
- github.com/onsi/gomega: [v1.27.4 → v1.27.6](https://github.com/onsi/gomega/compare/v1.27.4...v1.27.6)
|
||||
- github.com/prometheus/client_golang: [v1.14.0 → v1.16.0](https://github.com/prometheus/client_golang/compare/v1.14.0...v1.16.0)
|
||||
- github.com/prometheus/client_model: [v0.3.0 → v0.4.0](https://github.com/prometheus/client_model/compare/v0.3.0...v0.4.0)
|
||||
- github.com/prometheus/common: [v0.37.0 → v0.44.0](https://github.com/prometheus/common/compare/v0.37.0...v0.44.0)
|
||||
- github.com/prometheus/procfs: [v0.8.0 → v0.10.1](https://github.com/prometheus/procfs/compare/v0.8.0...v0.10.1)
|
||||
- github.com/spf13/cobra: [v1.6.0 → v1.7.0](https://github.com/spf13/cobra/compare/v1.6.0...v1.7.0)
|
||||
- github.com/stretchr/testify: [v1.8.2 → v1.8.4](https://github.com/stretchr/testify/compare/v1.8.2...v1.8.4)
|
||||
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp: v0.35.0 → v0.35.1
|
||||
- go.uber.org/atomic: v1.7.0 → v1.10.0
|
||||
- go.uber.org/goleak: v1.2.0 → v1.2.1
|
||||
- go.uber.org/multierr: v1.6.0 → v1.11.0
|
||||
- golang.org/x/crypto: 089bfa5 → v0.11.0
|
||||
- golang.org/x/exp: 6cc2880 → 509febe
|
||||
- golang.org/x/lint: 738671d → 1621716
|
||||
- golang.org/x/net: v0.8.0 → v0.13.0
|
||||
- golang.org/x/oauth2: v0.6.0 → v0.10.0
|
||||
- golang.org/x/sync: 0de741c → v0.3.0
|
||||
- golang.org/x/sys: v0.6.0 → v0.10.0
|
||||
- golang.org/x/term: v0.6.0 → v0.10.0
|
||||
- golang.org/x/text: v0.8.0 → v0.11.0
|
||||
- golang.org/x/time: v0.1.0 → v0.3.0
|
||||
- golang.org/x/tools: v0.7.0 → v0.8.0
|
||||
- google.golang.org/genproto: 7f2fa6f → 782d3b1
|
||||
- google.golang.org/grpc: v1.55.0 → v1.58.0
|
||||
- google.golang.org/protobuf: v1.30.0 → v1.31.0
|
||||
- honnef.co/go/tools: v0.0.1-2020.1.4 → ea95bdf
|
||||
- k8s.io/api: v0.27.0 → v0.28.0
|
||||
- k8s.io/apimachinery: v0.27.0 → v0.28.0
|
||||
- k8s.io/client-go: v0.27.0 → v0.28.0
|
||||
- k8s.io/component-base: v0.26.0 → v0.28.0
|
||||
- k8s.io/kube-openapi: 15aac26 → 2695361
|
||||
- k8s.io/utils: a36077c → d93618c
|
||||
|
||||
### Removed
|
||||
- cloud.google.com/go/accessapproval: v1.6.0
|
||||
- cloud.google.com/go/accesscontextmanager: v1.6.0
|
||||
- cloud.google.com/go/aiplatform: v1.35.0
|
||||
- cloud.google.com/go/analytics: v0.18.0
|
||||
- cloud.google.com/go/apigateway: v1.5.0
|
||||
- cloud.google.com/go/apigeeconnect: v1.5.0
|
||||
- cloud.google.com/go/apigeeregistry: v0.5.0
|
||||
- cloud.google.com/go/apikeys: v0.5.0
|
||||
- cloud.google.com/go/appengine: v1.6.0
|
||||
- cloud.google.com/go/area120: v0.7.1
|
||||
- cloud.google.com/go/artifactregistry: v1.11.2
|
||||
- cloud.google.com/go/asset: v1.11.1
|
||||
- cloud.google.com/go/assuredworkloads: v1.10.0
|
||||
- cloud.google.com/go/automl: v1.12.0
|
||||
- cloud.google.com/go/baremetalsolution: v0.5.0
|
||||
- cloud.google.com/go/batch: v0.7.0
|
||||
- cloud.google.com/go/beyondcorp: v0.4.0
|
||||
- cloud.google.com/go/bigquery: v1.48.0
|
||||
- cloud.google.com/go/billing: v1.12.0
|
||||
- cloud.google.com/go/binaryauthorization: v1.5.0
|
||||
- cloud.google.com/go/certificatemanager: v1.6.0
|
||||
- cloud.google.com/go/channel: v1.11.0
|
||||
- cloud.google.com/go/cloudbuild: v1.7.0
|
||||
- cloud.google.com/go/clouddms: v1.5.0
|
||||
- cloud.google.com/go/cloudtasks: v1.9.0
|
||||
- cloud.google.com/go/contactcenterinsights: v1.6.0
|
||||
- cloud.google.com/go/container: v1.13.1
|
||||
- cloud.google.com/go/containeranalysis: v0.7.0
|
||||
- cloud.google.com/go/datacatalog: v1.12.0
|
||||
- cloud.google.com/go/dataflow: v0.8.0
|
||||
- cloud.google.com/go/dataform: v0.6.0
|
||||
- cloud.google.com/go/datafusion: v1.6.0
|
||||
- cloud.google.com/go/datalabeling: v0.7.0
|
||||
- cloud.google.com/go/dataplex: v1.5.2
|
||||
- cloud.google.com/go/dataproc: v1.12.0
|
||||
- cloud.google.com/go/dataqna: v0.7.0
|
||||
- cloud.google.com/go/datastore: v1.10.0
|
||||
- cloud.google.com/go/datastream: v1.6.0
|
||||
- cloud.google.com/go/deploy: v1.6.0
|
||||
- cloud.google.com/go/dialogflow: v1.31.0
|
||||
- cloud.google.com/go/dlp: v1.9.0
|
||||
- cloud.google.com/go/documentai: v1.16.0
|
||||
- cloud.google.com/go/domains: v0.8.0
|
||||
- cloud.google.com/go/edgecontainer: v0.3.0
|
||||
- cloud.google.com/go/errorreporting: v0.3.0
|
||||
- cloud.google.com/go/essentialcontacts: v1.5.0
|
||||
- cloud.google.com/go/eventarc: v1.10.0
|
||||
- cloud.google.com/go/filestore: v1.5.0
|
||||
- cloud.google.com/go/firestore: v1.9.0
|
||||
- cloud.google.com/go/functions: v1.10.0
|
||||
- cloud.google.com/go/gaming: v1.9.0
|
||||
- cloud.google.com/go/gkebackup: v0.4.0
|
||||
- cloud.google.com/go/gkeconnect: v0.7.0
|
||||
- cloud.google.com/go/gkehub: v0.11.0
|
||||
- cloud.google.com/go/gkemulticloud: v0.5.0
|
||||
- cloud.google.com/go/gsuiteaddons: v1.5.0
|
||||
- cloud.google.com/go/iam: v0.12.0
|
||||
- cloud.google.com/go/iap: v1.6.0
|
||||
- cloud.google.com/go/ids: v1.3.0
|
||||
- cloud.google.com/go/iot: v1.5.0
|
||||
- cloud.google.com/go/kms: v1.9.0
|
||||
- cloud.google.com/go/language: v1.9.0
|
||||
- cloud.google.com/go/lifesciences: v0.8.0
|
||||
- cloud.google.com/go/logging: v1.7.0
|
||||
- cloud.google.com/go/longrunning: v0.4.1
|
||||
- cloud.google.com/go/managedidentities: v1.5.0
|
||||
- cloud.google.com/go/maps: v0.6.0
|
||||
- cloud.google.com/go/mediatranslation: v0.7.0
|
||||
- cloud.google.com/go/memcache: v1.9.0
|
||||
- cloud.google.com/go/metastore: v1.10.0
|
||||
- cloud.google.com/go/monitoring: v1.12.0
|
||||
- cloud.google.com/go/networkconnectivity: v1.10.0
|
||||
- cloud.google.com/go/networkmanagement: v1.6.0
|
||||
- cloud.google.com/go/networksecurity: v0.7.0
|
||||
- cloud.google.com/go/notebooks: v1.7.0
|
||||
- cloud.google.com/go/optimization: v1.3.1
|
||||
- cloud.google.com/go/orchestration: v1.6.0
|
||||
- cloud.google.com/go/orgpolicy: v1.10.0
|
||||
- cloud.google.com/go/osconfig: v1.11.0
|
||||
- cloud.google.com/go/oslogin: v1.9.0
|
||||
- cloud.google.com/go/phishingprotection: v0.7.0
|
||||
- cloud.google.com/go/policytroubleshooter: v1.5.0
|
||||
- cloud.google.com/go/privatecatalog: v0.7.0
|
||||
- cloud.google.com/go/pubsub: v1.28.0
|
||||
- cloud.google.com/go/pubsublite: v1.6.0
|
||||
- cloud.google.com/go/recaptchaenterprise/v2: v2.6.0
|
||||
- cloud.google.com/go/recommendationengine: v0.7.0
|
||||
- cloud.google.com/go/recommender: v1.9.0
|
||||
- cloud.google.com/go/redis: v1.11.0
|
||||
- cloud.google.com/go/resourcemanager: v1.5.0
|
||||
- cloud.google.com/go/resourcesettings: v1.5.0
|
||||
- cloud.google.com/go/retail: v1.12.0
|
||||
- cloud.google.com/go/run: v0.8.0
|
||||
- cloud.google.com/go/scheduler: v1.8.0
|
||||
- cloud.google.com/go/secretmanager: v1.10.0
|
||||
- cloud.google.com/go/security: v1.12.0
|
||||
- cloud.google.com/go/securitycenter: v1.18.1
|
||||
- cloud.google.com/go/servicecontrol: v1.11.0
|
||||
- cloud.google.com/go/servicedirectory: v1.8.0
|
||||
- cloud.google.com/go/servicemanagement: v1.6.0
|
||||
- cloud.google.com/go/serviceusage: v1.5.0
|
||||
- cloud.google.com/go/shell: v1.6.0
|
||||
- cloud.google.com/go/spanner: v1.44.0
|
||||
- cloud.google.com/go/speech: v1.14.1
|
||||
- cloud.google.com/go/storage: v1.10.0
|
||||
- cloud.google.com/go/storagetransfer: v1.7.0
|
||||
- cloud.google.com/go/talent: v1.5.0
|
||||
- cloud.google.com/go/texttospeech: v1.6.0
|
||||
- cloud.google.com/go/tpu: v1.5.0
|
||||
- cloud.google.com/go/trace: v1.8.0
|
||||
- cloud.google.com/go/translate: v1.6.0
|
||||
- cloud.google.com/go/video: v1.13.0
|
||||
- cloud.google.com/go/videointelligence: v1.10.0
|
||||
- cloud.google.com/go/vision/v2: v2.6.0
|
||||
- cloud.google.com/go/vmmigration: v1.5.0
|
||||
- cloud.google.com/go/vmwareengine: v0.2.2
|
||||
- cloud.google.com/go/vpcaccess: v1.6.0
|
||||
- cloud.google.com/go/webrisk: v1.8.0
|
||||
- cloud.google.com/go/websecurityscanner: v1.5.0
|
||||
- cloud.google.com/go/workflows: v1.10.0
|
||||
- dmitri.shuralyov.com/gpu/mtl: 666a987
|
||||
- github.com/BurntSushi/xgb: [27f1227](https://github.com/BurntSushi/xgb/tree/27f1227)
|
||||
- github.com/OneOfOne/xxhash: [v1.2.2](https://github.com/OneOfOne/xxhash/tree/v1.2.2)
|
||||
- github.com/alecthomas/template: [fb15b89](https://github.com/alecthomas/template/tree/fb15b89)
|
||||
- github.com/buger/jsonparser: [v1.1.1](https://github.com/buger/jsonparser/tree/v1.1.1)
|
||||
- github.com/cespare/xxhash: [v1.1.0](https://github.com/cespare/xxhash/tree/v1.1.0)
|
||||
- github.com/docopt/docopt-go: [ee0de3b](https://github.com/docopt/docopt-go/tree/ee0de3b)
|
||||
- github.com/flowstack/go-jsonschema: [v0.1.1](https://github.com/flowstack/go-jsonschema/tree/v0.1.1)
|
||||
- github.com/go-gl/glfw/v3.3/glfw: [6f7a984](https://github.com/go-gl/glfw/v3.3/glfw/tree/6f7a984)
|
||||
- github.com/go-gl/glfw: [e6da0ac](https://github.com/go-gl/glfw/tree/e6da0ac)
|
||||
- github.com/go-kit/kit: [v0.9.0](https://github.com/go-kit/kit/tree/v0.9.0)
|
||||
- github.com/go-stack/stack: [v1.8.0](https://github.com/go-stack/stack/tree/v1.8.0)
|
||||
- github.com/google/martian/v3: [v3.0.0](https://github.com/google/martian/v3/tree/v3.0.0)
|
||||
- github.com/google/martian: [v2.1.0+incompatible](https://github.com/google/martian/tree/v2.1.0)
|
||||
- github.com/google/renameio: [v0.1.0](https://github.com/google/renameio/tree/v0.1.0)
|
||||
- github.com/googleapis/gax-go/v2: [v2.0.5](https://github.com/googleapis/gax-go/v2/tree/v2.0.5)
|
||||
- github.com/hashicorp/golang-lru: [v0.5.1](https://github.com/hashicorp/golang-lru/tree/v0.5.1)
|
||||
- github.com/jstemmer/go-junit-report: [v0.9.1](https://github.com/jstemmer/go-junit-report/tree/v0.9.1)
|
||||
- github.com/konsorten/go-windows-terminal-sequences: [v1.0.3](https://github.com/konsorten/go-windows-terminal-sequences/tree/v1.0.3)
|
||||
- github.com/kr/logfmt: [b84e30a](https://github.com/kr/logfmt/tree/b84e30a)
|
||||
- github.com/mitchellh/mapstructure: [v1.1.2](https://github.com/mitchellh/mapstructure/tree/v1.1.2)
|
||||
- github.com/sirupsen/logrus: [v1.6.0](https://github.com/sirupsen/logrus/tree/v1.6.0)
|
||||
- github.com/spaolacci/murmur3: [f09979e](https://github.com/spaolacci/murmur3/tree/f09979e)
|
||||
- github.com/stoewer/go-strcase: [v1.2.0](https://github.com/stoewer/go-strcase/tree/v1.2.0)
|
||||
- github.com/xeipuuv/gojsonpointer: [4e3ac27](https://github.com/xeipuuv/gojsonpointer/tree/4e3ac27)
|
||||
- github.com/xeipuuv/gojsonreference: [bd5ef7b](https://github.com/xeipuuv/gojsonreference/tree/bd5ef7b)
|
||||
- github.com/xeipuuv/gojsonschema: [v1.2.0](https://github.com/xeipuuv/gojsonschema/tree/v1.2.0)
|
||||
- go.opencensus.io: v0.22.4
|
||||
- golang.org/x/image: cff245a
|
||||
- golang.org/x/mobile: d2bd2a2
|
||||
- google.golang.org/api: v0.30.0
|
||||
- gopkg.in/alecthomas/kingpin.v2: v2.2.6
|
||||
- gopkg.in/errgo.v2: v2.1.0
|
||||
- gotest.tools/v3: v3.0.3
|
||||
- rsc.io/binaryregexp: v0.2.0
|
||||
- rsc.io/quote/v3: v3.1.0
|
||||
- rsc.io/sampler: v1.3.0
|
|
@ -0,0 +1,67 @@
|
|||
# Release notes for v0.11.0
|
||||
|
||||
[Documentation](https://kubernetes-csi.github.io/)
|
||||
|
||||
# Changelog since 0.10.0
|
||||
|
||||
## Changes by Kind
|
||||
|
||||
### Uncategorized
|
||||
|
||||
- Update kubernetes dependencies to v1.29.0 ([#226](https://github.com/kubernetes-csi/external-health-monitor/pull/226), [@sunnylovestiramisu](https://github.com/sunnylovestiramisu))
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Added
|
||||
- github.com/gorilla/websocket: [v1.5.0](https://github.com/gorilla/websocket/tree/v1.5.0)
|
||||
- go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc: v0.44.0
|
||||
|
||||
### Changed
|
||||
- cloud.google.com/go/compute: v1.21.0 → v1.23.0
|
||||
- github.com/container-storage-interface/spec: [v1.8.0 → v1.9.0](https://github.com/container-storage-interface/spec/compare/v1.8.0...v1.9.0)
|
||||
- github.com/emicklei/go-restful/v3: [v3.9.0 → v3.11.0](https://github.com/emicklei/go-restful/v3/compare/v3.9.0...v3.11.0)
|
||||
- github.com/go-logr/logr: [v1.2.4 → v1.3.0](https://github.com/go-logr/logr/compare/v1.2.4...v1.3.0)
|
||||
- github.com/golang/glog: [v1.1.0 → v1.1.2](https://github.com/golang/glog/compare/v1.1.0...v1.1.2)
|
||||
- github.com/google/go-cmp: [v0.5.9 → v0.6.0](https://github.com/google/go-cmp/compare/v0.5.9...v0.6.0)
|
||||
- github.com/google/uuid: [v1.3.1 → v1.4.0](https://github.com/google/uuid/compare/v1.3.1...v1.4.0)
|
||||
- github.com/grpc-ecosystem/grpc-gateway/v2: [v2.7.0 → v2.16.0](https://github.com/grpc-ecosystem/grpc-gateway/v2/compare/v2.7.0...v2.16.0)
|
||||
- github.com/kubernetes-csi/csi-lib-utils: [v0.14.0 → v0.17.0](https://github.com/kubernetes-csi/csi-lib-utils/compare/v0.14.0...v0.17.0)
|
||||
- github.com/kubernetes-csi/csi-test/v5: [v5.1.0 → v5.2.0](https://github.com/kubernetes-csi/csi-test/v5/compare/v5.1.0...v5.2.0)
|
||||
- github.com/onsi/ginkgo/v2: [v2.12.0 → v2.13.1](https://github.com/onsi/ginkgo/v2/compare/v2.12.0...v2.13.1)
|
||||
- github.com/onsi/gomega: [v1.27.10 → v1.30.0](https://github.com/onsi/gomega/compare/v1.27.10...v1.30.0)
|
||||
- github.com/yuin/goldmark: [v1.3.5 → v1.4.13](https://github.com/yuin/goldmark/compare/v1.3.5...v1.4.13)
|
||||
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp: v0.35.1 → v0.44.0
|
||||
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc: v1.10.0 → v1.19.0
|
||||
- go.opentelemetry.io/otel/exporters/otlp/otlptrace: v1.10.0 → v1.19.0
|
||||
- go.opentelemetry.io/otel/metric: v0.31.0 → v1.19.0
|
||||
- go.opentelemetry.io/otel/sdk: v1.10.0 → v1.19.0
|
||||
- go.opentelemetry.io/otel/trace: v1.10.0 → v1.19.0
|
||||
- go.opentelemetry.io/otel: v1.10.0 → v1.19.0
|
||||
- go.opentelemetry.io/proto/otlp: v0.19.0 → v1.0.0
|
||||
- go.uber.org/goleak: v1.2.1 → v1.1.10
|
||||
- golang.org/x/crypto: v0.12.0 → v0.15.0
|
||||
- golang.org/x/net: v0.14.0 → v0.18.0
|
||||
- golang.org/x/oauth2: v0.10.0 → v0.13.0
|
||||
- golang.org/x/sync: v0.3.0 → v0.4.0
|
||||
- golang.org/x/sys: v0.11.0 → v0.14.0
|
||||
- golang.org/x/term: v0.11.0 → v0.14.0
|
||||
- golang.org/x/text: v0.12.0 → v0.14.0
|
||||
- golang.org/x/tools: v0.12.0 → v0.14.0
|
||||
- google.golang.org/appengine: v1.6.7 → v1.6.8
|
||||
- google.golang.org/genproto/googleapis/api: 782d3b1 → d307bd8
|
||||
- google.golang.org/genproto/googleapis/rpc: 782d3b1 → bbf56f3
|
||||
- google.golang.org/genproto: 782d3b1 → d783a09
|
||||
- google.golang.org/grpc: v1.58.0 → v1.60.1
|
||||
- k8s.io/api: v0.28.0 → v0.29.0
|
||||
- k8s.io/apimachinery: v0.28.0 → v0.29.0
|
||||
- k8s.io/client-go: v0.28.0 → v0.29.0
|
||||
- k8s.io/component-base: v0.28.0 → v0.29.0
|
||||
- k8s.io/gengo: 485abfe → 9cce18d
|
||||
- k8s.io/klog/v2: v2.100.1 → v2.110.1
|
||||
- k8s.io/kube-openapi: 2695361 → 2dd684a
|
||||
- k8s.io/utils: d93618c → 3b25d92
|
||||
- sigs.k8s.io/structured-merge-diff/v4: v4.2.3 → v4.4.1
|
||||
|
||||
### Removed
|
||||
- github.com/google/gnostic: [v0.5.7-v3refs](https://github.com/google/gnostic/tree/v0.5.7-v3refs)
|
||||
- go.opentelemetry.io/otel/exporters/otlp/internal/retry: v1.10.0
|
|
@ -0,0 +1,88 @@
|
|||
# Release notes for v0.12.0
|
||||
|
||||
[Documentation](https://kubernetes-csi.github.io/)
|
||||
|
||||
# Changelog since 0.11.0
|
||||
|
||||
## Changes by Kind
|
||||
|
||||
### Feature
|
||||
|
||||
- Added support for contextual logging. ([#246](https://github.com/kubernetes-csi/external-health-monitor/pull/246), [@bells17](https://github.com/bells17))
|
||||
- Updated Kubernetes deps to v1.30 ([#250](https://github.com/kubernetes-csi/external-health-monitor/pull/250), [@jsafrane](https://github.com/jsafrane))
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Added
|
||||
- github.com/fxamacker/cbor/v2: [v2.6.0](https://github.com/fxamacker/cbor/v2/tree/v2.6.0)
|
||||
- github.com/x448/float16: [v0.8.4](https://github.com/x448/float16/tree/v0.8.4)
|
||||
- k8s.io/gengo/v2: 51d4e06
|
||||
|
||||
### Changed
|
||||
- cloud.google.com/go/compute/metadata: v0.2.3 → v0.3.0
|
||||
- cloud.google.com/go/compute: v1.23.0 → v1.25.1
|
||||
- github.com/alecthomas/kingpin/v2: [v2.3.2 → v2.4.0](https://github.com/alecthomas/kingpin/v2/compare/v2.3.2...v2.4.0)
|
||||
- github.com/cespare/xxhash/v2: [v2.2.0 → v2.3.0](https://github.com/cespare/xxhash/v2/compare/v2.2.0...v2.3.0)
|
||||
- github.com/cncf/xds/go: [e9ce688 → 8a4994d](https://github.com/cncf/xds/go/compare/e9ce688...8a4994d)
|
||||
- github.com/cpuguy83/go-md2man/v2: [v2.0.2 → v2.0.3](https://github.com/cpuguy83/go-md2man/v2/compare/v2.0.2...v2.0.3)
|
||||
- github.com/emicklei/go-restful/v3: [v3.11.0 → v3.12.0](https://github.com/emicklei/go-restful/v3/compare/v3.11.0...v3.12.0)
|
||||
- github.com/envoyproxy/go-control-plane: [v0.11.1 → v0.12.0](https://github.com/envoyproxy/go-control-plane/compare/v0.11.1...v0.12.0)
|
||||
- github.com/envoyproxy/protoc-gen-validate: [v1.0.2 → v1.0.4](https://github.com/envoyproxy/protoc-gen-validate/compare/v1.0.2...v1.0.4)
|
||||
- github.com/evanphx/json-patch: [v5.6.0+incompatible → v5.9.0+incompatible](https://github.com/evanphx/json-patch/compare/v5.6.0...v5.9.0)
|
||||
- github.com/go-logr/logr: [v1.3.0 → v1.4.1](https://github.com/go-logr/logr/compare/v1.3.0...v1.4.1)
|
||||
- github.com/go-logr/zapr: [v1.2.3 → v1.3.0](https://github.com/go-logr/zapr/compare/v1.2.3...v1.3.0)
|
||||
- github.com/go-openapi/jsonpointer: [v0.19.6 → v0.21.0](https://github.com/go-openapi/jsonpointer/compare/v0.19.6...v0.21.0)
|
||||
- github.com/go-openapi/jsonreference: [v0.20.2 → v0.21.0](https://github.com/go-openapi/jsonreference/compare/v0.20.2...v0.21.0)
|
||||
- github.com/go-openapi/swag: [v0.22.3 → v0.23.0](https://github.com/go-openapi/swag/compare/v0.22.3...v0.23.0)
|
||||
- github.com/golang/glog: [v1.1.2 → v1.2.0](https://github.com/golang/glog/compare/v1.1.2...v1.2.0)
|
||||
- github.com/golang/protobuf: [v1.5.3 → v1.5.4](https://github.com/golang/protobuf/compare/v1.5.3...v1.5.4)
|
||||
- github.com/google/uuid: [v1.4.0 → v1.6.0](https://github.com/google/uuid/compare/v1.4.0...v1.6.0)
|
||||
- github.com/kubernetes-csi/csi-lib-utils: [v0.17.0 → v0.18.0](https://github.com/kubernetes-csi/csi-lib-utils/compare/v0.17.0...v0.18.0)
|
||||
- github.com/onsi/ginkgo/v2: [v2.13.1 → v2.15.0](https://github.com/onsi/ginkgo/v2/compare/v2.13.1...v2.15.0)
|
||||
- github.com/onsi/gomega: [v1.30.0 → v1.31.0](https://github.com/onsi/gomega/compare/v1.30.0...v1.31.0)
|
||||
- github.com/prometheus/client_golang: [v1.16.0 → v1.19.1](https://github.com/prometheus/client_golang/compare/v1.16.0...v1.19.1)
|
||||
- github.com/prometheus/client_model: [v0.4.0 → v0.6.1](https://github.com/prometheus/client_model/compare/v0.4.0...v0.6.1)
|
||||
- github.com/prometheus/common: [v0.44.0 → v0.53.0](https://github.com/prometheus/common/compare/v0.44.0...v0.53.0)
|
||||
- github.com/prometheus/procfs: [v0.10.1 → v0.15.0](https://github.com/prometheus/procfs/compare/v0.10.1...v0.15.0)
|
||||
- github.com/rogpeppe/go-internal: [v1.10.0 → v1.11.0](https://github.com/rogpeppe/go-internal/compare/v1.10.0...v1.11.0)
|
||||
- github.com/spf13/cobra: [v1.7.0 → v1.8.0](https://github.com/spf13/cobra/compare/v1.7.0...v1.8.0)
|
||||
- github.com/stretchr/objx: [v0.5.0 → v0.5.2](https://github.com/stretchr/objx/compare/v0.5.0...v0.5.2)
|
||||
- github.com/stretchr/testify: [v1.8.4 → v1.9.0](https://github.com/stretchr/testify/compare/v1.8.4...v1.9.0)
|
||||
- github.com/yuin/goldmark: [v1.4.13 → v1.3.5](https://github.com/yuin/goldmark/compare/v1.4.13...v1.3.5)
|
||||
- go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc: v0.44.0 → v0.51.0
|
||||
- go.opentelemetry.io/otel/metric: v1.19.0 → v1.26.0
|
||||
- go.opentelemetry.io/otel/trace: v1.19.0 → v1.26.0
|
||||
- go.opentelemetry.io/otel: v1.19.0 → v1.26.0
|
||||
- go.uber.org/goleak: v1.1.10 → v1.3.0
|
||||
- go.uber.org/zap: v1.19.0 → v1.27.0
|
||||
- golang.org/x/crypto: v0.15.0 → v0.23.0
|
||||
- golang.org/x/mod: v0.8.0 → v0.15.0
|
||||
- golang.org/x/net: v0.18.0 → v0.25.0
|
||||
- golang.org/x/oauth2: v0.13.0 → v0.20.0
|
||||
- golang.org/x/sync: v0.4.0 → v0.7.0
|
||||
- golang.org/x/sys: v0.14.0 → v0.20.0
|
||||
- golang.org/x/term: v0.14.0 → v0.20.0
|
||||
- golang.org/x/text: v0.14.0 → v0.15.0
|
||||
- golang.org/x/time: v0.3.0 → v0.5.0
|
||||
- golang.org/x/tools: v0.14.0 → v0.18.0
|
||||
- google.golang.org/genproto/googleapis/api: d307bd8 → 94a12d6
|
||||
- google.golang.org/genproto/googleapis/rpc: bbf56f3 → 94a12d6
|
||||
- google.golang.org/grpc: v1.60.1 → v1.64.0
|
||||
- google.golang.org/protobuf: v1.31.0 → v1.34.1
|
||||
- k8s.io/api: v0.29.0 → v0.30.0
|
||||
- k8s.io/apimachinery: v0.29.0 → v0.30.0
|
||||
- k8s.io/client-go: v0.29.0 → v0.30.0
|
||||
- k8s.io/component-base: v0.29.0 → v0.30.0
|
||||
- k8s.io/klog/v2: v2.110.1 → v2.120.1
|
||||
- k8s.io/kube-openapi: 2dd684a → 70dd376
|
||||
- sigs.k8s.io/yaml: v1.3.0 → v1.4.0
|
||||
|
||||
### Removed
|
||||
- github.com/benbjohnson/clock: [v1.1.0](https://github.com/benbjohnson/clock/tree/v1.1.0)
|
||||
- github.com/cncf/udpa/go: [c52dc94](https://github.com/cncf/udpa/go/tree/c52dc94)
|
||||
- github.com/creack/pty: [v1.1.9](https://github.com/creack/pty/tree/v1.1.9)
|
||||
- github.com/kr/pty: [v1.1.1](https://github.com/kr/pty/tree/v1.1.1)
|
||||
- go.uber.org/atomic: v1.10.0
|
||||
- golang.org/x/lint: 1621716
|
||||
- google.golang.org/genproto: d783a09
|
||||
- k8s.io/gengo: 9cce18d
|
|
@ -0,0 +1,84 @@
|
|||
# Release notes for v0.13.0
|
||||
|
||||
[Documentation](https://kubernetes-csi.github.io/)
|
||||
|
||||
# Changelog since 0.12.0
|
||||
|
||||
## Changes by Kind
|
||||
|
||||
### Bug or Regression
|
||||
|
||||
- Update csi-lib-utils to v0.18.1 ([#257](https://github.com/kubernetes-csi/external-health-monitor/pull/257), [@rhrmo](https://github.com/rhrmo))
|
||||
|
||||
### Other (Cleanup or Flake)
|
||||
|
||||
- Updates Kubernetes dependencies to 1.31.0-rc.0 ([#266](https://github.com/kubernetes-csi/external-health-monitor/pull/266), [@dfajmon](https://github.com/dfajmon))
|
||||
- Updates Kubernetes dependencies to v1.31.0 ([#270](https://github.com/kubernetes-csi/external-health-monitor/pull/270), [@dfajmon](https://github.com/dfajmon))
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Added
|
||||
- cel.dev/expr: v0.15.0
|
||||
- github.com/go-task/slim-sprig/v3: [v3.0.0](https://github.com/go-task/slim-sprig/tree/v3.0.0)
|
||||
- github.com/klauspost/compress: [v1.17.9](https://github.com/klauspost/compress/tree/v1.17.9)
|
||||
- github.com/kylelemons/godebug: [v1.1.0](https://github.com/kylelemons/godebug/tree/v1.1.0)
|
||||
- gopkg.in/evanphx/json-patch.v4: v4.12.0
|
||||
|
||||
### Changed
|
||||
- github.com/cenkalti/backoff/v4: [v4.2.1 → v4.3.0](https://github.com/cenkalti/backoff/compare/v4.2.1...v4.3.0)
|
||||
- github.com/cncf/xds/go: [8a4994d → 555b57e](https://github.com/cncf/xds/compare/8a4994d...555b57e)
|
||||
- github.com/cpuguy83/go-md2man/v2: [v2.0.3 → v2.0.4](https://github.com/cpuguy83/go-md2man/compare/v2.0.3...v2.0.4)
|
||||
- github.com/davecgh/go-spew: [v1.1.1 → d8f796a](https://github.com/davecgh/go-spew/compare/v1.1.1...d8f796a)
|
||||
- github.com/emicklei/go-restful/v3: [v3.12.0 → v3.12.1](https://github.com/emicklei/go-restful/compare/v3.12.0...v3.12.1)
|
||||
- github.com/felixge/httpsnoop: [v1.0.3 → v1.0.4](https://github.com/felixge/httpsnoop/compare/v1.0.3...v1.0.4)
|
||||
- github.com/fxamacker/cbor/v2: [v2.6.0 → v2.7.0](https://github.com/fxamacker/cbor/compare/v2.6.0...v2.7.0)
|
||||
- github.com/go-logr/logr: [v1.4.1 → v1.4.2](https://github.com/go-logr/logr/compare/v1.4.1...v1.4.2)
|
||||
- github.com/golang/glog: [v1.2.0 → v1.2.1](https://github.com/golang/glog/compare/v1.2.0...v1.2.1)
|
||||
- github.com/google/pprof: [4bb14d4 → 4bfdf5a](https://github.com/google/pprof/compare/4bb14d4...4bfdf5a)
|
||||
- github.com/grpc-ecosystem/grpc-gateway/v2: [v2.16.0 → v2.20.0](https://github.com/grpc-ecosystem/grpc-gateway/compare/v2.16.0...v2.20.0)
|
||||
- github.com/kubernetes-csi/csi-lib-utils: [v0.18.0 → v0.19.0](https://github.com/kubernetes-csi/csi-lib-utils/compare/v0.18.0...v0.19.0)
|
||||
- github.com/moby/spdystream: [v0.2.0 → v0.4.0](https://github.com/moby/spdystream/compare/v0.2.0...v0.4.0)
|
||||
- github.com/moby/term: [1aeaba8 → v0.5.0](https://github.com/moby/term/compare/1aeaba8...v0.5.0)
|
||||
- github.com/onsi/ginkgo/v2: [v2.15.0 → v2.19.0](https://github.com/onsi/ginkgo/compare/v2.15.0...v2.19.0)
|
||||
- github.com/onsi/gomega: [v1.31.0 → v1.33.1](https://github.com/onsi/gomega/compare/v1.31.0...v1.33.1)
|
||||
- github.com/pmezard/go-difflib: [v1.0.0 → 5d4384e](https://github.com/pmezard/go-difflib/compare/v1.0.0...5d4384e)
|
||||
- github.com/prometheus/client_golang: [v1.19.1 → v1.20.0](https://github.com/prometheus/client_golang/compare/v1.19.1...v1.20.0)
|
||||
- github.com/prometheus/common: [v0.53.0 → v0.55.0](https://github.com/prometheus/common/compare/v0.53.0...v0.55.0)
|
||||
- github.com/prometheus/procfs: [v0.15.0 → v0.15.1](https://github.com/prometheus/procfs/compare/v0.15.0...v0.15.1)
|
||||
- github.com/rogpeppe/go-internal: [v1.11.0 → v1.12.0](https://github.com/rogpeppe/go-internal/compare/v1.11.0...v1.12.0)
|
||||
- github.com/spf13/cobra: [v1.8.0 → v1.8.1](https://github.com/spf13/cobra/compare/v1.8.0...v1.8.1)
|
||||
- go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc: v0.51.0 → v0.53.0
|
||||
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp: v0.44.0 → v0.53.0
|
||||
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc: v1.19.0 → v1.27.0
|
||||
- go.opentelemetry.io/otel/exporters/otlp/otlptrace: v1.19.0 → v1.28.0
|
||||
- go.opentelemetry.io/otel/metric: v1.26.0 → v1.28.0
|
||||
- go.opentelemetry.io/otel/sdk: v1.19.0 → v1.28.0
|
||||
- go.opentelemetry.io/otel/trace: v1.26.0 → v1.28.0
|
||||
- go.opentelemetry.io/otel: v1.26.0 → v1.28.0
|
||||
- go.opentelemetry.io/proto/otlp: v1.0.0 → v1.3.1
|
||||
- golang.org/x/crypto: v0.23.0 → v0.26.0
|
||||
- golang.org/x/mod: v0.15.0 → v0.17.0
|
||||
- golang.org/x/net: v0.25.0 → v0.28.0
|
||||
- golang.org/x/oauth2: v0.20.0 → v0.22.0
|
||||
- golang.org/x/sync: v0.7.0 → v0.8.0
|
||||
- golang.org/x/sys: v0.20.0 → v0.23.0
|
||||
- golang.org/x/term: v0.20.0 → v0.23.0
|
||||
- golang.org/x/text: v0.15.0 → v0.17.0
|
||||
- golang.org/x/time: v0.5.0 → v0.6.0
|
||||
- golang.org/x/tools: v0.18.0 → e35e4cc
|
||||
- google.golang.org/genproto/googleapis/api: 94a12d6 → 5315273
|
||||
- google.golang.org/genproto/googleapis/rpc: 94a12d6 → f6361c8
|
||||
- google.golang.org/grpc: v1.64.0 → v1.65.0
|
||||
- google.golang.org/protobuf: v1.34.1 → v1.34.2
|
||||
- k8s.io/api: v0.30.0 → v0.31.0
|
||||
- k8s.io/apimachinery: v0.30.0 → v0.31.0
|
||||
- k8s.io/client-go: v0.30.0 → v0.31.0
|
||||
- k8s.io/component-base: v0.30.0 → v0.31.0
|
||||
- k8s.io/klog/v2: v2.120.1 → v2.130.1
|
||||
- k8s.io/utils: 3b25d92 → 18e509b
|
||||
|
||||
### Removed
|
||||
- cloud.google.com/go/compute: v1.25.1
|
||||
- github.com/evanphx/json-patch: [v5.9.0+incompatible](https://github.com/evanphx/json-patch/tree/v5.9.0)
|
||||
- github.com/matttproud/golang_protobuf_extensions: [v1.0.4](https://github.com/matttproud/golang_protobuf_extensions/tree/v1.0.4)
|
||||
- google.golang.org/appengine: v1.6.8
|
|
@ -0,0 +1,83 @@
|
|||
# Release notes for v0.14.0
|
||||
|
||||
[Documentation](https://kubernetes-csi.github.io/)
|
||||
|
||||
# Changelog since 0.13.0
|
||||
|
||||
## Changes by Kind
|
||||
|
||||
### Other (Cleanup or Flake)
|
||||
|
||||
- Update Kubernetes dependencies to 1.32.0 ([#298](https://github.com/kubernetes-csi/external-health-monitor/pull/298), [@dfajmon](https://github.com/dfajmon))
|
||||
|
||||
### Uncategorized
|
||||
|
||||
- Only watch Pods and Nodes when Node Watcher is enabled. ([#285](https://github.com/kubernetes-csi/external-health-monitor/pull/285), [@iltyty](https://github.com/iltyty))
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Added
|
||||
- github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp: [v1.24.2](https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp/tree/v1.24.2)
|
||||
- github.com/planetscale/vtprotobuf: [0393e58](https://github.com/planetscale/vtprotobuf/tree/0393e58)
|
||||
- go.opentelemetry.io/auto/sdk: v1.1.0
|
||||
- go.opentelemetry.io/contrib/detectors/gcp: v1.31.0
|
||||
- go.opentelemetry.io/otel/sdk/metric: v1.31.0
|
||||
|
||||
### Changed
|
||||
- cel.dev/expr: v0.15.0 → v0.16.2
|
||||
- cloud.google.com/go/compute/metadata: v0.3.0 → v0.5.2
|
||||
- github.com/Azure/go-ansiterm: [d185dfc → 306776e](https://github.com/Azure/go-ansiterm/compare/d185dfc...306776e)
|
||||
- github.com/NYTimes/gziphandler: [56545f4 → v1.1.1](https://github.com/NYTimes/gziphandler/compare/56545f4...v1.1.1)
|
||||
- github.com/cncf/xds/go: [555b57e → b4127c9](https://github.com/cncf/xds/go/compare/555b57e...b4127c9)
|
||||
- github.com/container-storage-interface/spec: [v1.9.0 → v1.11.0](https://github.com/container-storage-interface/spec/compare/v1.9.0...v1.11.0)
|
||||
- github.com/envoyproxy/go-control-plane: [v0.12.0 → v0.13.1](https://github.com/envoyproxy/go-control-plane/compare/v0.12.0...v0.13.1)
|
||||
- github.com/envoyproxy/protoc-gen-validate: [v1.0.4 → v1.1.0](https://github.com/envoyproxy/protoc-gen-validate/compare/v1.0.4...v1.1.0)
|
||||
- github.com/golang/glog: [v1.2.1 → v1.2.2](https://github.com/golang/glog/compare/v1.2.1...v1.2.2)
|
||||
- github.com/google/gnostic-models: [v0.6.8 → v0.6.9](https://github.com/google/gnostic-models/compare/v0.6.8...v0.6.9)
|
||||
- github.com/google/pprof: [4bfdf5a → d1b30fe](https://github.com/google/pprof/compare/4bfdf5a...d1b30fe)
|
||||
- github.com/gregjones/httpcache: [9cad4c3 → 901d907](https://github.com/gregjones/httpcache/compare/9cad4c3...901d907)
|
||||
- github.com/klauspost/compress: [v1.17.9 → v1.17.11](https://github.com/klauspost/compress/compare/v1.17.9...v1.17.11)
|
||||
- github.com/kubernetes-csi/csi-lib-utils: [v0.19.0 → v0.20.0](https://github.com/kubernetes-csi/csi-lib-utils/compare/v0.19.0...v0.20.0)
|
||||
- github.com/kubernetes-csi/csi-test/v5: [v5.2.0 → v5.3.1](https://github.com/kubernetes-csi/csi-test/v5/compare/v5.2.0...v5.3.1)
|
||||
- github.com/mailru/easyjson: [v0.7.7 → v0.9.0](https://github.com/mailru/easyjson/compare/v0.7.7...v0.9.0)
|
||||
- github.com/moby/spdystream: [v0.4.0 → v0.5.0](https://github.com/moby/spdystream/compare/v0.4.0...v0.5.0)
|
||||
- github.com/onsi/ginkgo/v2: [v2.19.0 → v2.21.0](https://github.com/onsi/ginkgo/v2/compare/v2.19.0...v2.21.0)
|
||||
- github.com/onsi/gomega: [v1.33.1 → v1.35.1](https://github.com/onsi/gomega/compare/v1.33.1...v1.35.1)
|
||||
- github.com/prometheus/client_golang: [v1.20.0 → v1.20.5](https://github.com/prometheus/client_golang/compare/v1.20.0...v1.20.5)
|
||||
- github.com/prometheus/common: [v0.55.0 → v0.61.0](https://github.com/prometheus/common/compare/v0.55.0...v0.61.0)
|
||||
- github.com/rogpeppe/go-internal: [v1.12.0 → v1.13.1](https://github.com/rogpeppe/go-internal/compare/v1.12.0...v1.13.1)
|
||||
- github.com/stretchr/testify: [v1.9.0 → v1.10.0](https://github.com/stretchr/testify/compare/v1.9.0...v1.10.0)
|
||||
- go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc: v0.53.0 → v0.58.0
|
||||
- go.opentelemetry.io/otel/metric: v1.28.0 → v1.33.0
|
||||
- go.opentelemetry.io/otel/sdk: v1.28.0 → v1.31.0
|
||||
- go.opentelemetry.io/otel/trace: v1.28.0 → v1.33.0
|
||||
- go.opentelemetry.io/otel: v1.28.0 → v1.33.0
|
||||
- golang.org/x/crypto: v0.26.0 → v0.30.0
|
||||
- golang.org/x/mod: v0.17.0 → v0.20.0
|
||||
- golang.org/x/net: v0.28.0 → v0.32.0
|
||||
- golang.org/x/oauth2: v0.22.0 → v0.24.0
|
||||
- golang.org/x/sync: v0.8.0 → v0.10.0
|
||||
- golang.org/x/sys: v0.23.0 → v0.28.0
|
||||
- golang.org/x/term: v0.23.0 → v0.27.0
|
||||
- golang.org/x/text: v0.17.0 → v0.21.0
|
||||
- golang.org/x/time: v0.6.0 → v0.8.0
|
||||
- golang.org/x/tools: e35e4cc → v0.26.0
|
||||
- golang.org/x/xerrors: 04be3eb → 5ec99f8
|
||||
- google.golang.org/genproto/googleapis/api: 5315273 → 796eee8
|
||||
- google.golang.org/genproto/googleapis/rpc: f6361c8 → 9240e9c
|
||||
- google.golang.org/grpc: v1.65.0 → v1.69.0
|
||||
- google.golang.org/protobuf: v1.34.2 → v1.36.0
|
||||
- k8s.io/api: v0.31.0 → v0.32.0
|
||||
- k8s.io/apimachinery: v0.31.0 → v0.32.0
|
||||
- k8s.io/client-go: v0.31.0 → v0.32.0
|
||||
- k8s.io/component-base: v0.31.0 → v0.32.0
|
||||
- k8s.io/gengo/v2: 51d4e06 → a7b603a
|
||||
- k8s.io/kube-openapi: 70dd376 → 2c72e55
|
||||
- k8s.io/utils: 18e509b → 24370be
|
||||
- sigs.k8s.io/json: bc3834c → cfa47c3
|
||||
- sigs.k8s.io/structured-merge-diff/v4: v4.4.1 → v4.5.0
|
||||
|
||||
### Removed
|
||||
- github.com/asaskevich/govalidator: [f61b66f](https://github.com/asaskevich/govalidator/tree/f61b66f)
|
||||
- github.com/golang/groupcache: [41bb18b](https://github.com/golang/groupcache/tree/41bb18b)
|
||||
- github.com/imdario/mergo: [v0.3.13](https://github.com/imdario/mergo/tree/v0.3.13)
|
|
@ -0,0 +1,56 @@
|
|||
# Release notes for v0.15.0
|
||||
|
||||
[Documentation](https://kubernetes-csi.github.io/)
|
||||
|
||||
# Changelog since 0.14.0
|
||||
|
||||
## Changes by Kind
|
||||
|
||||
### Feature
|
||||
|
||||
- Add a new `--automaxprocs` flag to set the `GOMAXPROCS` environment variable to match the configured Linux container CPU quota. ([#325](https://github.com/kubernetes-csi/external-health-monitor/pull/325), [@nixpanic](https://github.com/nixpanic))
|
||||
- Update kubernetes dependencies to v1.33.0 ([#324](https://github.com/kubernetes-csi/external-health-monitor/pull/324), [@Aishwarya-Hebbar](https://github.com/Aishwarya-Hebbar))
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Added
|
||||
- github.com/prashantv/gostub: [v1.1.0](https://github.com/prashantv/gostub/tree/v1.1.0)
|
||||
- go.uber.org/automaxprocs: v1.6.0
|
||||
- sigs.k8s.io/randfill: v1.0.0
|
||||
|
||||
### Changed
|
||||
- github.com/google/btree: [v1.0.1 → v1.1.3](https://github.com/google/btree/compare/v1.0.1...v1.1.3)
|
||||
- github.com/google/go-cmp: [v0.6.0 → v0.7.0](https://github.com/google/go-cmp/compare/v0.6.0...v0.7.0)
|
||||
- github.com/google/gofuzz: [v1.2.0 → v1.0.0](https://github.com/google/gofuzz/compare/v1.2.0...v1.0.0)
|
||||
- github.com/gorilla/websocket: [v1.5.0 → e064f32](https://github.com/gorilla/websocket/compare/v1.5.0...e064f32)
|
||||
- github.com/grpc-ecosystem/grpc-gateway/v2: [v2.20.0 → v2.24.0](https://github.com/grpc-ecosystem/grpc-gateway/v2/compare/v2.20.0...v2.24.0)
|
||||
- github.com/klauspost/compress: [v1.17.11 → v1.18.0](https://github.com/klauspost/compress/compare/v1.17.11...v1.18.0)
|
||||
- github.com/kubernetes-csi/csi-lib-utils: [v0.20.0 → v0.22.0](https://github.com/kubernetes-csi/csi-lib-utils/compare/v0.20.0...v0.22.0)
|
||||
- github.com/prometheus/client_golang: [v1.20.5 → v1.22.0](https://github.com/prometheus/client_golang/compare/v1.20.5...v1.22.0)
|
||||
- github.com/prometheus/common: [v0.61.0 → v0.62.0](https://github.com/prometheus/common/compare/v0.61.0...v0.62.0)
|
||||
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp: v0.53.0 → v0.58.0
|
||||
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc: v1.27.0 → v1.33.0
|
||||
- go.opentelemetry.io/otel/exporters/otlp/otlptrace: v1.28.0 → v1.33.0
|
||||
- go.opentelemetry.io/otel/sdk: v1.31.0 → v1.33.0
|
||||
- go.opentelemetry.io/proto/otlp: v1.3.1 → v1.4.0
|
||||
- golang.org/x/crypto: v0.30.0 → v0.36.0
|
||||
- golang.org/x/net: v0.32.0 → v0.38.0
|
||||
- golang.org/x/oauth2: v0.24.0 → v0.27.0
|
||||
- golang.org/x/sync: v0.10.0 → v0.12.0
|
||||
- golang.org/x/sys: v0.28.0 → v0.31.0
|
||||
- golang.org/x/term: v0.27.0 → v0.30.0
|
||||
- golang.org/x/text: v0.21.0 → v0.23.0
|
||||
- golang.org/x/time: v0.8.0 → v0.9.0
|
||||
- google.golang.org/genproto/googleapis/api: 796eee8 → e6fa225
|
||||
- google.golang.org/grpc: v1.69.0 → v1.69.2
|
||||
- google.golang.org/protobuf: v1.36.0 → v1.36.5
|
||||
- k8s.io/api: v0.32.0 → v0.33.0
|
||||
- k8s.io/apimachinery: v0.32.0 → v0.33.0
|
||||
- k8s.io/client-go: v0.32.0 → v0.33.0
|
||||
- k8s.io/component-base: v0.32.0 → v0.33.0
|
||||
- k8s.io/kube-openapi: 2c72e55 → c8a335a
|
||||
- sigs.k8s.io/structured-merge-diff/v4: v4.5.0 → v4.6.0
|
||||
|
||||
### Removed
|
||||
- github.com/go-kit/log: [v0.2.1](https://github.com/go-kit/log/tree/v0.2.1)
|
||||
- github.com/go-logfmt/logfmt: [v0.5.1](https://github.com/go-logfmt/logfmt/tree/v0.5.1)
|
|
@ -0,0 +1,137 @@
|
|||
# Release notes for v0.8.0
|
||||
|
||||
[Documentation](https://kubernetes-csi.github.io/)
|
||||
|
||||
# Changelog since 0.7.0
|
||||
|
||||
## Changes by Kind
|
||||
|
||||
### Uncategorized
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Added
|
||||
- github.com/cenkalti/backoff/v4: [v4.1.3](https://github.com/cenkalti/backoff/v4/tree/v4.1.3)
|
||||
- github.com/go-logr/stdr: [v1.2.2](https://github.com/go-logr/stdr/tree/v1.2.2)
|
||||
- github.com/grpc-ecosystem/grpc-gateway/v2: [v2.7.0](https://github.com/grpc-ecosystem/grpc-gateway/v2/tree/v2.7.0)
|
||||
- go.opentelemetry.io/otel/exporters/otlp/internal/retry: v1.10.0
|
||||
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc: v1.10.0
|
||||
- go.opentelemetry.io/otel/exporters/otlp/otlptrace: v1.10.0
|
||||
|
||||
### Changed
|
||||
- github.com/felixge/httpsnoop: [v1.0.1 → v1.0.3](https://github.com/felixge/httpsnoop/compare/v1.0.1...v1.0.3)
|
||||
- github.com/inconshreveable/mousetrap: [v1.0.0 → v1.0.1](https://github.com/inconshreveable/mousetrap/compare/v1.0.0...v1.0.1)
|
||||
- github.com/kubernetes-csi/csi-lib-utils: [v0.11.0 → v0.12.0](https://github.com/kubernetes-csi/csi-lib-utils/compare/v0.11.0...v0.12.0)
|
||||
- github.com/moby/term: [3f7ff69 → 39b0c02](https://github.com/moby/term/compare/3f7ff69...39b0c02)
|
||||
- github.com/onsi/ginkgo/v2: [v2.1.6 → v2.4.0](https://github.com/onsi/ginkgo/v2/compare/v2.1.6...v2.4.0)
|
||||
- github.com/onsi/gomega: [v1.20.1 → v1.23.0](https://github.com/onsi/gomega/compare/v1.20.1...v1.23.0)
|
||||
- github.com/prometheus/client_golang: [v1.13.1 → v1.14.0](https://github.com/prometheus/client_golang/compare/v1.13.1...v1.14.0)
|
||||
- github.com/spf13/cobra: [v1.4.0 → v1.6.0](https://github.com/spf13/cobra/compare/v1.4.0...v1.6.0)
|
||||
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp: v0.20.0 → v0.35.0
|
||||
- go.opentelemetry.io/otel/metric: v0.20.0 → v0.31.0
|
||||
- go.opentelemetry.io/otel/sdk: v0.20.0 → v1.10.0
|
||||
- go.opentelemetry.io/otel/trace: v0.20.0 → v1.10.0
|
||||
- go.opentelemetry.io/otel: v0.20.0 → v1.10.0
|
||||
- go.opentelemetry.io/proto/otlp: v0.7.0 → v0.19.0
|
||||
- golang.org/x/crypto: 3147a52 → 089bfa5
|
||||
- golang.org/x/lint: 6edffad → 738671d
|
||||
- golang.org/x/net: v0.1.0 → v0.4.0
|
||||
- golang.org/x/sys: v0.1.0 → v0.3.0
|
||||
- golang.org/x/term: v0.1.0 → v0.3.0
|
||||
- golang.org/x/text: v0.4.0 → v0.5.0
|
||||
- google.golang.org/grpc: v1.50.1 → v1.51.0
|
||||
- k8s.io/api: v0.25.3 → v0.26.0
|
||||
- k8s.io/apimachinery: v0.25.3 → v0.26.0
|
||||
- k8s.io/client-go: v0.25.3 → v0.26.0
|
||||
- k8s.io/component-base: v0.25.3 → v0.26.0
|
||||
- k8s.io/utils: 61b03e2 → 1a15be2
|
||||
|
||||
### Removed
|
||||
- cloud.google.com/go/firestore: v1.1.0
|
||||
- github.com/Azure/go-autorest/autorest/adal: [v0.9.20](https://github.com/Azure/go-autorest/autorest/adal/tree/v0.9.20)
|
||||
- github.com/Azure/go-autorest/autorest/date: [v0.3.0](https://github.com/Azure/go-autorest/autorest/date/tree/v0.3.0)
|
||||
- github.com/Azure/go-autorest/autorest/mocks: [v0.4.1](https://github.com/Azure/go-autorest/autorest/mocks/tree/v0.4.1)
|
||||
- github.com/Azure/go-autorest/autorest: [v0.11.27](https://github.com/Azure/go-autorest/autorest/tree/v0.11.27)
|
||||
- github.com/Azure/go-autorest/logger: [v0.2.1](https://github.com/Azure/go-autorest/logger/tree/v0.2.1)
|
||||
- github.com/Azure/go-autorest/tracing: [v0.6.0](https://github.com/Azure/go-autorest/tracing/tree/v0.6.0)
|
||||
- github.com/Azure/go-autorest: [v14.2.0+incompatible](https://github.com/Azure/go-autorest/tree/v14.2.0)
|
||||
- github.com/armon/circbuf: [bbbad09](https://github.com/armon/circbuf/tree/bbbad09)
|
||||
- github.com/armon/go-metrics: [f0300d1](https://github.com/armon/go-metrics/tree/f0300d1)
|
||||
- github.com/armon/go-radix: [7fddfc3](https://github.com/armon/go-radix/tree/7fddfc3)
|
||||
- github.com/benbjohnson/clock: [v1.0.3](https://github.com/benbjohnson/clock/tree/v1.0.3)
|
||||
- github.com/bgentry/speakeasy: [v0.1.0](https://github.com/bgentry/speakeasy/tree/v0.1.0)
|
||||
- github.com/bketelsen/crypt: [5cbc8cc](https://github.com/bketelsen/crypt/tree/5cbc8cc)
|
||||
- github.com/blang/semver: [v3.5.1+incompatible](https://github.com/blang/semver/tree/v3.5.1)
|
||||
- github.com/coreos/bbolt: [v1.3.2](https://github.com/coreos/bbolt/tree/v1.3.2)
|
||||
- github.com/coreos/etcd: [v3.3.13+incompatible](https://github.com/coreos/etcd/tree/v3.3.13)
|
||||
- github.com/coreos/go-semver: [v0.3.0](https://github.com/coreos/go-semver/tree/v0.3.0)
|
||||
- github.com/coreos/go-systemd: [95778df](https://github.com/coreos/go-systemd/tree/95778df)
|
||||
- github.com/coreos/pkg: [399ea9e](https://github.com/coreos/pkg/tree/399ea9e)
|
||||
- github.com/cpuguy83/go-md2man/v2: [v2.0.0](https://github.com/cpuguy83/go-md2man/v2/tree/v2.0.0)
|
||||
- github.com/creack/pty: [v1.1.11](https://github.com/creack/pty/tree/v1.1.11)
|
||||
- github.com/dgrijalva/jwt-go: [v3.2.0+incompatible](https://github.com/dgrijalva/jwt-go/tree/v3.2.0)
|
||||
- github.com/dgryski/go-sip13: [e10d5fe](https://github.com/dgryski/go-sip13/tree/e10d5fe)
|
||||
- github.com/emicklei/go-restful: [ff4f55a](https://github.com/emicklei/go-restful/tree/ff4f55a)
|
||||
- github.com/fatih/color: [v1.7.0](https://github.com/fatih/color/tree/v1.7.0)
|
||||
- github.com/form3tech-oss/jwt-go: [v3.2.3+incompatible](https://github.com/form3tech-oss/jwt-go/tree/v3.2.3)
|
||||
- github.com/golang-jwt/jwt/v4: [v4.2.0](https://github.com/golang-jwt/jwt/v4/tree/v4.2.0)
|
||||
- github.com/googleapis/gnostic: [v0.5.5](https://github.com/googleapis/gnostic/tree/v0.5.5)
|
||||
- github.com/gopherjs/gopherjs: [0766667](https://github.com/gopherjs/gopherjs/tree/0766667)
|
||||
- github.com/gorilla/websocket: [v1.4.2](https://github.com/gorilla/websocket/tree/v1.4.2)
|
||||
- github.com/grpc-ecosystem/go-grpc-middleware: [v1.0.0](https://github.com/grpc-ecosystem/go-grpc-middleware/tree/v1.0.0)
|
||||
- github.com/grpc-ecosystem/go-grpc-prometheus: [v1.2.0](https://github.com/grpc-ecosystem/go-grpc-prometheus/tree/v1.2.0)
|
||||
- github.com/hashicorp/consul/api: [v1.1.0](https://github.com/hashicorp/consul/api/tree/v1.1.0)
|
||||
- github.com/hashicorp/consul/sdk: [v0.1.1](https://github.com/hashicorp/consul/sdk/tree/v0.1.1)
|
||||
- github.com/hashicorp/errwrap: [v1.0.0](https://github.com/hashicorp/errwrap/tree/v1.0.0)
|
||||
- github.com/hashicorp/go-cleanhttp: [v0.5.1](https://github.com/hashicorp/go-cleanhttp/tree/v0.5.1)
|
||||
- github.com/hashicorp/go-immutable-radix: [v1.0.0](https://github.com/hashicorp/go-immutable-radix/tree/v1.0.0)
|
||||
- github.com/hashicorp/go-msgpack: [v0.5.3](https://github.com/hashicorp/go-msgpack/tree/v0.5.3)
|
||||
- github.com/hashicorp/go-multierror: [v1.0.0](https://github.com/hashicorp/go-multierror/tree/v1.0.0)
|
||||
- github.com/hashicorp/go-rootcerts: [v1.0.0](https://github.com/hashicorp/go-rootcerts/tree/v1.0.0)
|
||||
- github.com/hashicorp/go-sockaddr: [v1.0.0](https://github.com/hashicorp/go-sockaddr/tree/v1.0.0)
|
||||
- github.com/hashicorp/go-syslog: [v1.0.0](https://github.com/hashicorp/go-syslog/tree/v1.0.0)
|
||||
- github.com/hashicorp/go-uuid: [v1.0.1](https://github.com/hashicorp/go-uuid/tree/v1.0.1)
|
||||
- github.com/hashicorp/go.net: [v0.0.1](https://github.com/hashicorp/go.net/tree/v0.0.1)
|
||||
- github.com/hashicorp/hcl: [v1.0.0](https://github.com/hashicorp/hcl/tree/v1.0.0)
|
||||
- github.com/hashicorp/logutils: [v1.0.0](https://github.com/hashicorp/logutils/tree/v1.0.0)
|
||||
- github.com/hashicorp/mdns: [v1.0.0](https://github.com/hashicorp/mdns/tree/v1.0.0)
|
||||
- github.com/hashicorp/memberlist: [v0.1.3](https://github.com/hashicorp/memberlist/tree/v0.1.3)
|
||||
- github.com/hashicorp/serf: [v0.8.2](https://github.com/hashicorp/serf/tree/v0.8.2)
|
||||
- github.com/jonboulle/clockwork: [v0.1.0](https://github.com/jonboulle/clockwork/tree/v0.1.0)
|
||||
- github.com/jtolds/gls: [v4.20.0+incompatible](https://github.com/jtolds/gls/tree/v4.20.0)
|
||||
- github.com/magiconair/properties: [v1.8.1](https://github.com/magiconair/properties/tree/v1.8.1)
|
||||
- github.com/mattn/go-colorable: [v0.0.9](https://github.com/mattn/go-colorable/tree/v0.0.9)
|
||||
- github.com/mattn/go-isatty: [v0.0.3](https://github.com/mattn/go-isatty/tree/v0.0.3)
|
||||
- github.com/miekg/dns: [v1.0.14](https://github.com/miekg/dns/tree/v1.0.14)
|
||||
- github.com/mitchellh/cli: [v1.0.0](https://github.com/mitchellh/cli/tree/v1.0.0)
|
||||
- github.com/mitchellh/go-homedir: [v1.1.0](https://github.com/mitchellh/go-homedir/tree/v1.1.0)
|
||||
- github.com/mitchellh/go-testing-interface: [v1.0.0](https://github.com/mitchellh/go-testing-interface/tree/v1.0.0)
|
||||
- github.com/mitchellh/gox: [v0.4.0](https://github.com/mitchellh/gox/tree/v0.4.0)
|
||||
- github.com/mitchellh/iochan: [v1.0.0](https://github.com/mitchellh/iochan/tree/v1.0.0)
|
||||
- github.com/oklog/ulid: [v1.3.1](https://github.com/oklog/ulid/tree/v1.3.1)
|
||||
- github.com/pascaldekloe/goe: [57f6aae](https://github.com/pascaldekloe/goe/tree/57f6aae)
|
||||
- github.com/pelletier/go-toml: [v1.2.0](https://github.com/pelletier/go-toml/tree/v1.2.0)
|
||||
- github.com/posener/complete: [v1.1.1](https://github.com/posener/complete/tree/v1.1.1)
|
||||
- github.com/prometheus/tsdb: [v0.7.1](https://github.com/prometheus/tsdb/tree/v0.7.1)
|
||||
- github.com/russross/blackfriday/v2: [v2.0.1](https://github.com/russross/blackfriday/v2/tree/v2.0.1)
|
||||
- github.com/ryanuber/columnize: [9b3edd6](https://github.com/ryanuber/columnize/tree/9b3edd6)
|
||||
- github.com/sean-/seed: [e2103e2](https://github.com/sean-/seed/tree/e2103e2)
|
||||
- github.com/shurcooL/sanitized_anchor_name: [v1.0.0](https://github.com/shurcooL/sanitized_anchor_name/tree/v1.0.0)
|
||||
- github.com/smartystreets/assertions: [b2de0cb](https://github.com/smartystreets/assertions/tree/b2de0cb)
|
||||
- github.com/smartystreets/goconvey: [v1.6.4](https://github.com/smartystreets/goconvey/tree/v1.6.4)
|
||||
- github.com/soheilhy/cmux: [v0.1.4](https://github.com/soheilhy/cmux/tree/v0.1.4)
|
||||
- github.com/spf13/afero: [v1.2.2](https://github.com/spf13/afero/tree/v1.2.2)
|
||||
- github.com/spf13/cast: [v1.3.0](https://github.com/spf13/cast/tree/v1.3.0)
|
||||
- github.com/spf13/jwalterweatherman: [v1.0.0](https://github.com/spf13/jwalterweatherman/tree/v1.0.0)
|
||||
- github.com/spf13/viper: [v1.7.0](https://github.com/spf13/viper/tree/v1.7.0)
|
||||
- github.com/subosito/gotenv: [v1.2.0](https://github.com/subosito/gotenv/tree/v1.2.0)
|
||||
- github.com/tmc/grpc-websocket-proxy: [0ad062e](https://github.com/tmc/grpc-websocket-proxy/tree/0ad062e)
|
||||
- github.com/xiang90/probing: [43a291a](https://github.com/xiang90/probing/tree/43a291a)
|
||||
- go.etcd.io/bbolt: v1.3.2
|
||||
- go.opentelemetry.io/contrib: v0.20.0
|
||||
- go.opentelemetry.io/otel/exporters/otlp: v0.20.0
|
||||
- go.opentelemetry.io/otel/oteltest: v0.20.0
|
||||
- go.opentelemetry.io/otel/sdk/export/metric: v0.20.0
|
||||
- go.opentelemetry.io/otel/sdk/metric: v0.20.0
|
||||
- gopkg.in/ini.v1: v1.51.0
|
||||
- gopkg.in/resty.v1: v1.12.0
|
|
@ -0,0 +1,180 @@
|
|||
# Release notes for v0.9.0
|
||||
|
||||
[Documentation](https://kubernetes-csi.github.io/)
|
||||
|
||||
# Changelog since 0.8.0
|
||||
|
||||
## Changes by Kind
|
||||
|
||||
### Uncategorized
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Added
|
||||
- cloud.google.com/go/apigeeregistry: v0.5.0
|
||||
- cloud.google.com/go/apikeys: v0.5.0
|
||||
- cloud.google.com/go/compute/metadata: v0.2.3
|
||||
- cloud.google.com/go/errorreporting: v0.3.0
|
||||
- cloud.google.com/go/firestore: v1.9.0
|
||||
- cloud.google.com/go/logging: v1.7.0
|
||||
- cloud.google.com/go/maps: v0.6.0
|
||||
- cloud.google.com/go/pubsublite: v1.6.0
|
||||
- cloud.google.com/go/spanner: v1.44.0
|
||||
- cloud.google.com/go/vmwareengine: v0.2.2
|
||||
- github.com/creack/pty: [v1.1.9](https://github.com/creack/pty/tree/v1.1.9)
|
||||
|
||||
### Changed
|
||||
- cloud.google.com/go/accessapproval: v1.4.0 → v1.6.0
|
||||
- cloud.google.com/go/accesscontextmanager: v1.3.0 → v1.6.0
|
||||
- cloud.google.com/go/aiplatform: v1.24.0 → v1.35.0
|
||||
- cloud.google.com/go/analytics: v0.12.0 → v0.18.0
|
||||
- cloud.google.com/go/apigateway: v1.3.0 → v1.5.0
|
||||
- cloud.google.com/go/apigeeconnect: v1.3.0 → v1.5.0
|
||||
- cloud.google.com/go/appengine: v1.4.0 → v1.6.0
|
||||
- cloud.google.com/go/area120: v0.6.0 → v0.7.1
|
||||
- cloud.google.com/go/artifactregistry: v1.8.0 → v1.11.2
|
||||
- cloud.google.com/go/asset: v1.9.0 → v1.11.1
|
||||
- cloud.google.com/go/assuredworkloads: v1.8.0 → v1.10.0
|
||||
- cloud.google.com/go/automl: v1.7.0 → v1.12.0
|
||||
- cloud.google.com/go/baremetalsolution: v0.3.0 → v0.5.0
|
||||
- cloud.google.com/go/batch: v0.3.0 → v0.7.0
|
||||
- cloud.google.com/go/beyondcorp: v0.2.0 → v0.4.0
|
||||
- cloud.google.com/go/bigquery: v1.42.0 → v1.48.0
|
||||
- cloud.google.com/go/billing: v1.6.0 → v1.12.0
|
||||
- cloud.google.com/go/binaryauthorization: v1.3.0 → v1.5.0
|
||||
- cloud.google.com/go/certificatemanager: v1.3.0 → v1.6.0
|
||||
- cloud.google.com/go/channel: v1.8.0 → v1.11.0
|
||||
- cloud.google.com/go/cloudbuild: v1.3.0 → v1.7.0
|
||||
- cloud.google.com/go/clouddms: v1.3.0 → v1.5.0
|
||||
- cloud.google.com/go/cloudtasks: v1.7.0 → v1.9.0
|
||||
- cloud.google.com/go/compute: v1.7.0 → v1.18.0
|
||||
- cloud.google.com/go/contactcenterinsights: v1.3.0 → v1.6.0
|
||||
- cloud.google.com/go/container: v1.6.0 → v1.13.1
|
||||
- cloud.google.com/go/containeranalysis: v0.6.0 → v0.7.0
|
||||
- cloud.google.com/go/datacatalog: v1.7.0 → v1.12.0
|
||||
- cloud.google.com/go/dataflow: v0.7.0 → v0.8.0
|
||||
- cloud.google.com/go/dataform: v0.4.0 → v0.6.0
|
||||
- cloud.google.com/go/datafusion: v1.4.0 → v1.6.0
|
||||
- cloud.google.com/go/datalabeling: v0.6.0 → v0.7.0
|
||||
- cloud.google.com/go/dataplex: v1.3.0 → v1.5.2
|
||||
- cloud.google.com/go/dataproc: v1.7.0 → v1.12.0
|
||||
- cloud.google.com/go/dataqna: v0.6.0 → v0.7.0
|
||||
- cloud.google.com/go/datastore: v1.1.0 → v1.10.0
|
||||
- cloud.google.com/go/datastream: v1.4.0 → v1.6.0
|
||||
- cloud.google.com/go/deploy: v1.4.0 → v1.6.0
|
||||
- cloud.google.com/go/dialogflow: v1.18.0 → v1.31.0
|
||||
- cloud.google.com/go/dlp: v1.6.0 → v1.9.0
|
||||
- cloud.google.com/go/documentai: v1.9.0 → v1.16.0
|
||||
- cloud.google.com/go/domains: v0.7.0 → v0.8.0
|
||||
- cloud.google.com/go/edgecontainer: v0.2.0 → v0.3.0
|
||||
- cloud.google.com/go/essentialcontacts: v1.3.0 → v1.5.0
|
||||
- cloud.google.com/go/eventarc: v1.7.0 → v1.10.0
|
||||
- cloud.google.com/go/filestore: v1.3.0 → v1.5.0
|
||||
- cloud.google.com/go/functions: v1.8.0 → v1.10.0
|
||||
- cloud.google.com/go/gaming: v1.7.0 → v1.9.0
|
||||
- cloud.google.com/go/gkebackup: v0.2.0 → v0.4.0
|
||||
- cloud.google.com/go/gkeconnect: v0.6.0 → v0.7.0
|
||||
- cloud.google.com/go/gkehub: v0.10.0 → v0.11.0
|
||||
- cloud.google.com/go/gkemulticloud: v0.3.0 → v0.5.0
|
||||
- cloud.google.com/go/gsuiteaddons: v1.3.0 → v1.5.0
|
||||
- cloud.google.com/go/iam: v0.6.0 → v0.12.0
|
||||
- cloud.google.com/go/iap: v1.4.0 → v1.6.0
|
||||
- cloud.google.com/go/ids: v1.1.0 → v1.3.0
|
||||
- cloud.google.com/go/iot: v1.3.0 → v1.5.0
|
||||
- cloud.google.com/go/kms: v1.5.0 → v1.9.0
|
||||
- cloud.google.com/go/language: v1.7.0 → v1.9.0
|
||||
- cloud.google.com/go/lifesciences: v0.6.0 → v0.8.0
|
||||
- cloud.google.com/go/longrunning: v0.1.1 → v0.4.1
|
||||
- cloud.google.com/go/managedidentities: v1.3.0 → v1.5.0
|
||||
- cloud.google.com/go/mediatranslation: v0.6.0 → v0.7.0
|
||||
- cloud.google.com/go/memcache: v1.6.0 → v1.9.0
|
||||
- cloud.google.com/go/metastore: v1.7.0 → v1.10.0
|
||||
- cloud.google.com/go/monitoring: v1.7.0 → v1.12.0
|
||||
- cloud.google.com/go/networkconnectivity: v1.6.0 → v1.10.0
|
||||
- cloud.google.com/go/networkmanagement: v1.4.0 → v1.6.0
|
||||
- cloud.google.com/go/networksecurity: v0.6.0 → v0.7.0
|
||||
- cloud.google.com/go/notebooks: v1.4.0 → v1.7.0
|
||||
- cloud.google.com/go/optimization: v1.1.0 → v1.3.1
|
||||
- cloud.google.com/go/orchestration: v1.3.0 → v1.6.0
|
||||
- cloud.google.com/go/orgpolicy: v1.4.0 → v1.10.0
|
||||
- cloud.google.com/go/osconfig: v1.9.0 → v1.11.0
|
||||
- cloud.google.com/go/oslogin: v1.6.0 → v1.9.0
|
||||
- cloud.google.com/go/phishingprotection: v0.6.0 → v0.7.0
|
||||
- cloud.google.com/go/policytroubleshooter: v1.3.0 → v1.5.0
|
||||
- cloud.google.com/go/privatecatalog: v0.6.0 → v0.7.0
|
||||
- cloud.google.com/go/pubsub: v1.3.1 → v1.28.0
|
||||
- cloud.google.com/go/recaptchaenterprise/v2: v2.4.0 → v2.6.0
|
||||
- cloud.google.com/go/recommendationengine: v0.6.0 → v0.7.0
|
||||
- cloud.google.com/go/recommender: v1.7.0 → v1.9.0
|
||||
- cloud.google.com/go/redis: v1.9.0 → v1.11.0
|
||||
- cloud.google.com/go/resourcemanager: v1.3.0 → v1.5.0
|
||||
- cloud.google.com/go/resourcesettings: v1.3.0 → v1.5.0
|
||||
- cloud.google.com/go/retail: v1.10.0 → v1.12.0
|
||||
- cloud.google.com/go/run: v0.2.0 → v0.8.0
|
||||
- cloud.google.com/go/scheduler: v1.6.0 → v1.8.0
|
||||
- cloud.google.com/go/secretmanager: v1.8.0 → v1.10.0
|
||||
- cloud.google.com/go/security: v1.9.0 → v1.12.0
|
||||
- cloud.google.com/go/securitycenter: v1.15.0 → v1.18.1
|
||||
- cloud.google.com/go/servicecontrol: v1.4.0 → v1.11.0
|
||||
- cloud.google.com/go/servicedirectory: v1.6.0 → v1.8.0
|
||||
- cloud.google.com/go/servicemanagement: v1.4.0 → v1.6.0
|
||||
- cloud.google.com/go/serviceusage: v1.3.0 → v1.5.0
|
||||
- cloud.google.com/go/shell: v1.3.0 → v1.6.0
|
||||
- cloud.google.com/go/speech: v1.8.0 → v1.14.1
|
||||
- cloud.google.com/go/storagetransfer: v1.5.0 → v1.7.0
|
||||
- cloud.google.com/go/talent: v1.3.0 → v1.5.0
|
||||
- cloud.google.com/go/texttospeech: v1.4.0 → v1.6.0
|
||||
- cloud.google.com/go/tpu: v1.3.0 → v1.5.0
|
||||
- cloud.google.com/go/trace: v1.3.0 → v1.8.0
|
||||
- cloud.google.com/go/translate: v1.3.0 → v1.6.0
|
||||
- cloud.google.com/go/video: v1.8.0 → v1.13.0
|
||||
- cloud.google.com/go/videointelligence: v1.8.0 → v1.10.0
|
||||
- cloud.google.com/go/vision/v2: v2.4.0 → v2.6.0
|
||||
- cloud.google.com/go/vmmigration: v1.2.0 → v1.5.0
|
||||
- cloud.google.com/go/vpcaccess: v1.4.0 → v1.6.0
|
||||
- cloud.google.com/go/webrisk: v1.6.0 → v1.8.0
|
||||
- cloud.google.com/go/websecurityscanner: v1.3.0 → v1.5.0
|
||||
- cloud.google.com/go/workflows: v1.8.0 → v1.10.0
|
||||
- cloud.google.com/go: v0.105.0 → v0.110.0
|
||||
- github.com/census-instrumentation/opencensus-proto: [v0.2.1 → v0.4.1](https://github.com/census-instrumentation/opencensus-proto/compare/v0.2.1...v0.4.1)
|
||||
- github.com/cespare/xxhash/v2: [v2.1.2 → v2.2.0](https://github.com/cespare/xxhash/v2/compare/v2.1.2...v2.2.0)
|
||||
- github.com/cncf/udpa/go: [04548b0 → c52dc94](https://github.com/cncf/udpa/go/compare/04548b0...c52dc94)
|
||||
- github.com/cncf/xds/go: [cb28da3 → 32f1caf](https://github.com/cncf/xds/go/compare/cb28da3...32f1caf)
|
||||
- github.com/container-storage-interface/spec: [v1.7.0 → v1.8.0](https://github.com/container-storage-interface/spec/compare/v1.7.0...v1.8.0)
|
||||
- github.com/envoyproxy/go-control-plane: [49ff273 → v0.11.0](https://github.com/envoyproxy/go-control-plane/compare/49ff273...v0.11.0)
|
||||
- github.com/envoyproxy/protoc-gen-validate: [v0.1.0 → v0.10.0](https://github.com/envoyproxy/protoc-gen-validate/compare/v0.1.0...v0.10.0)
|
||||
- github.com/go-openapi/jsonpointer: [v0.19.5 → v0.19.6](https://github.com/go-openapi/jsonpointer/compare/v0.19.5...v0.19.6)
|
||||
- github.com/go-openapi/jsonreference: [v0.20.0 → v0.20.1](https://github.com/go-openapi/jsonreference/compare/v0.20.0...v0.20.1)
|
||||
- github.com/golang/glog: [23def4e → v1.1.0](https://github.com/golang/glog/compare/23def4e...v1.1.0)
|
||||
- github.com/golang/protobuf: [v1.5.2 → v1.5.3](https://github.com/golang/protobuf/compare/v1.5.2...v1.5.3)
|
||||
- github.com/google/pprof: [94a9f03 → 4bb14d4](https://github.com/google/pprof/compare/94a9f03...4bb14d4)
|
||||
- github.com/kr/pretty: [v0.2.0 → v0.3.0](https://github.com/kr/pretty/compare/v0.2.0...v0.3.0)
|
||||
- github.com/kubernetes-csi/csi-lib-utils: [v0.12.0 → v0.13.0](https://github.com/kubernetes-csi/csi-lib-utils/compare/v0.12.0...v0.13.0)
|
||||
- github.com/onsi/ginkgo/v2: [v2.4.0 → v2.9.1](https://github.com/onsi/ginkgo/v2/compare/v2.4.0...v2.9.1)
|
||||
- github.com/onsi/gomega: [v1.23.0 → v1.27.4](https://github.com/onsi/gomega/compare/v1.23.0...v1.27.4)
|
||||
- github.com/rogpeppe/go-internal: [v1.3.0 → v1.10.0](https://github.com/rogpeppe/go-internal/compare/v1.3.0...v1.10.0)
|
||||
- github.com/stretchr/testify: [v1.8.1 → v1.8.2](https://github.com/stretchr/testify/compare/v1.8.1...v1.8.2)
|
||||
- golang.org/x/mod: 86c51ed → v0.8.0
|
||||
- golang.org/x/net: v0.4.0 → v0.8.0
|
||||
- golang.org/x/oauth2: v0.1.0 → v0.6.0
|
||||
- golang.org/x/sys: v0.3.0 → v0.6.0
|
||||
- golang.org/x/term: v0.3.0 → v0.6.0
|
||||
- golang.org/x/text: v0.5.0 → v0.8.0
|
||||
- golang.org/x/tools: v0.1.12 → v0.7.0
|
||||
- golang.org/x/xerrors: 5ec99f8 → 04be3eb
|
||||
- google.golang.org/genproto: 115e99e → 7f2fa6f
|
||||
- google.golang.org/grpc: v1.51.0 → v1.55.0
|
||||
- google.golang.org/protobuf: v1.28.1 → v1.30.0
|
||||
- k8s.io/api: v0.26.0 → v0.27.0
|
||||
- k8s.io/apimachinery: v0.26.0 → v0.27.0
|
||||
- k8s.io/client-go: v0.26.0 → v0.27.0
|
||||
- k8s.io/klog/v2: v2.80.1 → v2.100.1
|
||||
- k8s.io/kube-openapi: 172d655 → 15aac26
|
||||
- k8s.io/utils: 1a15be2 → a36077c
|
||||
- sigs.k8s.io/json: f223a00 → bc3834c
|
||||
|
||||
### Removed
|
||||
- github.com/PuerkitoBio/purell: [v1.1.1](https://github.com/PuerkitoBio/purell/tree/v1.1.1)
|
||||
- github.com/PuerkitoBio/urlesc: [de5bf2a](https://github.com/PuerkitoBio/urlesc/tree/de5bf2a)
|
||||
- github.com/elazarl/goproxy: [947c36d](https://github.com/elazarl/goproxy/tree/947c36d)
|
||||
- github.com/niemeyer/pretty: [a10e7ca](https://github.com/niemeyer/pretty/tree/a10e7ca)
|
5
Makefile
5
Makefile
|
@ -14,7 +14,10 @@
|
|||
|
||||
.PHONY: all csi-external-health-monitor-controller clean test
|
||||
|
||||
CMDS=csi-external-health-monitor-controller
|
||||
CMDS=csi-external-health-monitor-controller
|
||||
all: build
|
||||
|
||||
include release-tools/build.make
|
||||
|
||||
# Check contextual logging.
|
||||
test: test-logcheck
|
||||
|
|
|
@ -96,7 +96,7 @@ Check if there are events on PVCs or Pods that report abnormal volume condition
|
|||
|
||||
- `kubeconfig <path>`: Path to Kubernetes client configuration that the external-health-monitor-controller uses to connect to the Kubernetes API server. When omitted, default token provided by Kubernetes will be used. This option is useful only when the external-health-monitor-controller does not run as a Kubernetes pod, e.g. for debugging.
|
||||
|
||||
- `resync <duration>`: Internal resync interval when the monitor controller re-evaluates all existing resource objects that it was watching and tries to fulfill them. It does not affect re-tries of failed calls! It should be used only when there is a bug in Kubernetes watch logic. The default is ten mintiues.
|
||||
- `resync <duration>`: Internal resync interval when the monitor controller re-evaluates all existing resource objects that it was watching and tries to fulfill them. It does not affect re-tries of failed calls! It should be used only when there is a bug in Kubernetes watch logic. The default is ten minutes.
|
||||
|
||||
- `csiAddress <path-to-csi>`: This is the path to the CSI Driver socket inside the pod that the external-health-monitor-controller container will use to issue CSI operations (/run/csi/socket is used by default).
|
||||
|
||||
|
@ -104,7 +104,7 @@ Check if there are events on PVCs or Pods that report abnormal volume condition
|
|||
|
||||
- `timeout <duration>`: Timeout of all calls to CSI Driver. It should be set to value that accommodates the majority of `ListVolumes`, `ControllerGetVolume` calls. 15 seconds is used by default.
|
||||
|
||||
- `list-volumes-interval <duration>`: Interval of monitoring volume health condition by invoking the RPC interface of `ListVolumes`. You can adjust it to change the frequency of the evaluation process. Five mintiues by default if not set.
|
||||
- `list-volumes-interval <duration>`: Interval of monitoring volume health condition by invoking the RPC interface of `ListVolumes`. You can adjust it to change the frequency of the evaluation process. Five minutes by default if not set.
|
||||
|
||||
- `enable-node-watcher <boolean>`: Enable node-watcher. node-watcher evaluates volume health condition by checking node status periodically.
|
||||
|
||||
|
@ -116,6 +116,10 @@ Check if there are events on PVCs or Pods that report abnormal volume condition
|
|||
|
||||
- `metrics-address`: (deprecated) The TCP network address where the Prometheus metrics endpoint will run (example: :8080, which corresponds to port 8080 on local host). The default is the empty string, which means the metrics and leader election check endpoint is disabled.
|
||||
|
||||
- `--automaxprocs`: Automatically set the `GOMAXPROCS` environment variable to match the configured Linux container CPU quota. Defaults to false.
|
||||
|
||||
* [Arguments set by the `k8s.io/component-base/logs` package for klog](https://github.com/kubernetes/component-base/blob/v0.28.0-rc.0/logs/api/v1/options.go#L337-L355) are supported, such as `--v <log level>` and `--logging-format <log format>`.
|
||||
|
||||
## Community, discussion, contribution, and support
|
||||
|
||||
Learn how to engage with the Kubernetes community on the [community page](http://kubernetes.io/community/).
|
||||
|
|
|
@ -32,6 +32,10 @@ import (
|
|||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/component-base/featuregate"
|
||||
"k8s.io/component-base/logs"
|
||||
logsapi "k8s.io/component-base/logs/api/v1"
|
||||
_ "k8s.io/component-base/logs/json/register"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"github.com/container-storage-interface/spec/lib/go/csi"
|
||||
|
@ -39,6 +43,7 @@ import (
|
|||
"github.com/kubernetes-csi/csi-lib-utils/leaderelection"
|
||||
"github.com/kubernetes-csi/csi-lib-utils/metrics"
|
||||
"github.com/kubernetes-csi/csi-lib-utils/rpc"
|
||||
"github.com/kubernetes-csi/csi-lib-utils/standardflags"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
monitorcontroller "github.com/kubernetes-csi/external-health-monitor/pkg/controller"
|
||||
|
@ -81,19 +86,28 @@ var (
|
|||
)
|
||||
|
||||
func main() {
|
||||
klog.InitFlags(nil)
|
||||
flag.Set("logtostderr", "true")
|
||||
fg := featuregate.NewFeatureGate()
|
||||
logsapi.AddFeatureGates(fg)
|
||||
c := logsapi.NewLoggingConfiguration()
|
||||
logsapi.AddGoFlags(c, flag.CommandLine)
|
||||
logs.InitLogs()
|
||||
standardflags.AddAutomaxprocs(klog.Infof)
|
||||
flag.Parse()
|
||||
logger := klog.Background()
|
||||
if err := logsapi.ValidateAndApply(c, fg); err != nil {
|
||||
logger.Error(err, "LoggingConfiguration is invalid")
|
||||
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
|
||||
}
|
||||
|
||||
if *showVersion {
|
||||
fmt.Println(os.Args[0], version)
|
||||
return
|
||||
}
|
||||
klog.Infof("Version: %s", version)
|
||||
logger.Info("Version", "version", version)
|
||||
|
||||
if *metricsAddress != "" && *httpEndpoint != "" {
|
||||
klog.Error("only one of `--metrics-address` and `--http-endpoint` can be set.")
|
||||
os.Exit(1)
|
||||
logger.Error(nil, "Only one of `--metrics-address` and `--http-endpoint` can be set.")
|
||||
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
|
||||
}
|
||||
addr := *metricsAddress
|
||||
if addr == "" {
|
||||
|
@ -103,19 +117,19 @@ func main() {
|
|||
// Create the client config. Use kubeconfig if given, otherwise assume in-cluster.
|
||||
config, err := buildConfig(*kubeconfig)
|
||||
if err != nil {
|
||||
klog.Error(err.Error())
|
||||
os.Exit(1)
|
||||
logger.Error(err, "Failed to build a Kubernetes config")
|
||||
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
|
||||
}
|
||||
|
||||
if *workerThreads == 0 {
|
||||
klog.Error("option -worker-threads must be greater than zero")
|
||||
os.Exit(1)
|
||||
logger.Error(nil, "Option --worker-threads must be greater than zero")
|
||||
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
|
||||
}
|
||||
|
||||
clientset, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
klog.Error(err.Error())
|
||||
os.Exit(1)
|
||||
logger.Error(err, "Failed to create a Clientset")
|
||||
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
|
||||
}
|
||||
|
||||
factory := informers.NewSharedInformerFactory(clientset, *resync)
|
||||
|
@ -123,27 +137,29 @@ func main() {
|
|||
metricsManager := metrics.NewCSIMetricsManager("" /* driverName */)
|
||||
|
||||
// Connect to CSI.
|
||||
csiConn, err := connection.Connect(*csiAddress, metricsManager, connection.OnConnectionLoss(connection.ExitOnConnectionLoss()))
|
||||
ctx := context.Background()
|
||||
csiConn, err := connection.Connect(ctx, *csiAddress, metricsManager, connection.OnConnectionLoss(connection.ExitOnConnectionLoss()))
|
||||
if err != nil {
|
||||
klog.Error(err.Error())
|
||||
os.Exit(1)
|
||||
logger.Error(err, "Failed to connect to the CSI driver")
|
||||
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
|
||||
}
|
||||
|
||||
err = rpc.ProbeForever(csiConn, *timeout)
|
||||
err = rpc.ProbeForever(ctx, csiConn, *timeout)
|
||||
if err != nil {
|
||||
klog.Error(err.Error())
|
||||
os.Exit(1)
|
||||
logger.Error(err, "Failed to probe the CSI driver")
|
||||
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
|
||||
}
|
||||
|
||||
// Find driver name.
|
||||
ctx, cancel := context.WithTimeout(context.Background(), csiTimeout)
|
||||
cancelationCtx, cancel := context.WithTimeout(context.Background(), csiTimeout)
|
||||
cancelationCtx = klog.NewContext(cancelationCtx, logger)
|
||||
defer cancel()
|
||||
storageDriver, err := rpc.GetDriverName(ctx, csiConn)
|
||||
storageDriver, err := rpc.GetDriverName(cancelationCtx, csiConn)
|
||||
if err != nil {
|
||||
klog.Error(err.Error())
|
||||
os.Exit(1)
|
||||
logger.Error(err, "Failed to get the CSI driver name")
|
||||
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
|
||||
}
|
||||
klog.V(2).Infof("CSI driver name: %q", storageDriver)
|
||||
logger.V(2).Info("CSI driver name", "driver", storageDriver)
|
||||
metricsManager.SetDriverName(storageDriver)
|
||||
|
||||
// Prepare HTTP endpoint for metrics + leader election healthz
|
||||
|
@ -151,45 +167,46 @@ func main() {
|
|||
if addr != "" {
|
||||
metricsManager.RegisterToServer(mux, *metricsPath)
|
||||
go func() {
|
||||
klog.Infof("ServeMux listening at %q", addr)
|
||||
logger.Info("ServeMux listening", "address", addr)
|
||||
err := http.ListenAndServe(addr, mux)
|
||||
if err != nil {
|
||||
klog.Fatalf("Failed to start HTTP server at specified address (%q) and metrics path (%q): %s", addr, *metricsPath, err)
|
||||
logger.Error(err, "Failed to start HTTP server at specified address and metrics path", "address", addr, "path", *metricsPath)
|
||||
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
supportsService, err := supportsPluginControllerService(ctx, csiConn)
|
||||
supportsService, err := supportsPluginControllerService(cancelationCtx, csiConn)
|
||||
if err != nil {
|
||||
klog.Error(err.Error())
|
||||
os.Exit(1)
|
||||
logger.Error(err, "Failed to check whether the CSI driver supports the Plugin Controller Service")
|
||||
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
|
||||
}
|
||||
if !supportsService {
|
||||
klog.V(2).Infof("CSI driver does not support Plugin Controller Service, exiting")
|
||||
os.Exit(1)
|
||||
logger.V(2).Info("CSI driver does not support Plugin Controller Service, exiting")
|
||||
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
|
||||
}
|
||||
|
||||
supportControllerListVolumes, err := supportControllerListVolumes(ctx, csiConn)
|
||||
supportControllerListVolumes, err := supportControllerListVolumes(cancelationCtx, csiConn)
|
||||
if err != nil {
|
||||
klog.Error(err.Error())
|
||||
os.Exit(1)
|
||||
logger.Error(err, "Failed to check whether the CSI driver supports the Controller Service ListVolumes")
|
||||
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
|
||||
}
|
||||
|
||||
supportControllerGetVolume, err := supportControllerGetVolume(ctx, csiConn)
|
||||
supportControllerGetVolume, err := supportControllerGetVolume(cancelationCtx, csiConn)
|
||||
if err != nil {
|
||||
klog.Error(err.Error())
|
||||
os.Exit(1)
|
||||
logger.Error(err, "Failed to check whether the CSI driver supports the Controller Service GetVolume")
|
||||
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
|
||||
}
|
||||
|
||||
supportControllerVolumeCondition, err := supportControllerVolumeCondition(ctx, csiConn)
|
||||
supportControllerVolumeCondition, err := supportControllerVolumeCondition(cancelationCtx, csiConn)
|
||||
if err != nil {
|
||||
klog.Error(err.Error())
|
||||
os.Exit(1)
|
||||
logger.Error(err, "Failed to check whether the CSI driver supports the Controller Service VolumeCondition")
|
||||
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
|
||||
}
|
||||
|
||||
if (!supportControllerListVolumes && !supportControllerGetVolume) || !supportControllerVolumeCondition {
|
||||
klog.V(2).Infof("CSI driver does not support Controller ListVolumes and GetVolume service or does not implement VolumeCondition, exiting")
|
||||
os.Exit(1)
|
||||
logger.V(2).Info("CSI driver does not support Controller ListVolumes and GetVolume service or does not implement VolumeCondition, exiting")
|
||||
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
|
||||
}
|
||||
|
||||
option := monitorcontroller.PVMonitorOptions{
|
||||
|
@ -206,21 +223,27 @@ func main() {
|
|||
NodeListAndAddInterval: *nodeListAndAddInterval,
|
||||
}
|
||||
|
||||
broadcaster := record.NewBroadcaster()
|
||||
broadcaster := record.NewBroadcaster(record.WithContext(ctx))
|
||||
broadcaster.StartRecordingToSink(&corev1.EventSinkImpl{Interface: clientset.CoreV1().Events(v1.NamespaceAll)})
|
||||
eventRecorder := broadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: fmt.Sprintf("csi-pv-monitor-controller-%s", option.DriverName)})
|
||||
eventRecorder := broadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: fmt.Sprintf("csi-pv-monitor-controller-%s", option.DriverName)}).WithLogger(logger)
|
||||
|
||||
monitorController := monitorcontroller.NewPVMonitorController(clientset, csiConn, factory.Core().V1().PersistentVolumes(),
|
||||
factory.Core().V1().PersistentVolumeClaims(), factory.Core().V1().Pods(), factory.Core().V1().Nodes(), factory.Core().V1().Events(), eventRecorder, &option)
|
||||
monitorController := monitorcontroller.NewPVMonitorController(
|
||||
logger,
|
||||
clientset,
|
||||
csiConn,
|
||||
factory,
|
||||
eventRecorder,
|
||||
&option,
|
||||
)
|
||||
|
||||
run := func(ctx context.Context) {
|
||||
stopCh := ctx.Done()
|
||||
factory.Start(stopCh)
|
||||
monitorController.Run(int(*workerThreads), stopCh)
|
||||
monitorController.Run(ctx, int(*workerThreads))
|
||||
}
|
||||
|
||||
if !*enableLeaderElection {
|
||||
run(context.TODO())
|
||||
run(ctx)
|
||||
} else {
|
||||
// Name of config map with leader election lock
|
||||
lockName := "external-health-monitor-leader-" + storageDriver
|
||||
|
@ -236,9 +259,17 @@ func main() {
|
|||
le.WithLeaseDuration(*leaderElectionLeaseDuration)
|
||||
le.WithRenewDeadline(*leaderElectionRenewDeadline)
|
||||
le.WithRetryPeriod(*leaderElectionRetryPeriod)
|
||||
le.WithContext(ctx)
|
||||
|
||||
// TODO: The broadcaster and eventRecorder in the leaderelection package
|
||||
// within csi-lib-utils do not support contextual logging.
|
||||
// To fully support contextual logging in external-health-monitor,
|
||||
// an upgrade of csi-lib-utils version will be necessary
|
||||
// after contextual logging support is added to csi-lib-utils.
|
||||
// https://github.com/kubernetes-sigs/sig-storage-lib-external-provisioner/pull/171
|
||||
if err := le.Run(); err != nil {
|
||||
klog.Fatalf("failed to initialize leader election: %v", err)
|
||||
logger.Error(err, "Failed to initialize leader election")
|
||||
klog.FlushAndExit(klog.ExitFlushTimeout, 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
117
go.mod
117
go.mod
|
@ -1,70 +1,87 @@
|
|||
module github.com/kubernetes-csi/external-health-monitor
|
||||
|
||||
go 1.18
|
||||
go 1.24.0
|
||||
|
||||
toolchain go1.24.2
|
||||
|
||||
require (
|
||||
github.com/container-storage-interface/spec v1.6.0
|
||||
github.com/container-storage-interface/spec v1.11.0
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/imdario/mergo v0.3.11 // indirect
|
||||
github.com/kubernetes-csi/csi-lib-utils v0.11.0
|
||||
github.com/kubernetes-csi/csi-test/v5 v5.0.0
|
||||
github.com/stretchr/testify v1.7.0
|
||||
google.golang.org/grpc v1.48.0
|
||||
k8s.io/api v0.25.0
|
||||
k8s.io/apimachinery v0.25.0
|
||||
k8s.io/client-go v0.25.0
|
||||
k8s.io/klog/v2 v2.70.1
|
||||
github.com/kubernetes-csi/csi-lib-utils v0.22.0
|
||||
github.com/kubernetes-csi/csi-test/v5 v5.3.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
google.golang.org/grpc v1.69.2
|
||||
k8s.io/api v0.33.1
|
||||
k8s.io/apimachinery v0.33.1
|
||||
k8s.io/client-go v0.33.1
|
||||
k8s.io/component-base v0.33.1
|
||||
k8s.io/klog/v2 v2.130.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/blang/semver v3.5.1+incompatible // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.8.0 // indirect
|
||||
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.5 // indirect
|
||||
github.com/go-openapi/swag v0.19.14 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.1 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-logr/zapr v1.3.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/gnostic v0.5.7-v3refs // indirect
|
||||
github.com/google/go-cmp v0.5.8 // indirect
|
||||
github.com/google/gnostic-models v0.6.9 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||
github.com/mailru/easyjson v0.9.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.11.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.26.0 // indirect
|
||||
github.com/prometheus/procfs v0.6.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_golang v1.22.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/spf13/cobra v1.8.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
golang.org/x/net v0.0.0-20220802222814-0bcc04d9c69b // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
|
||||
golang.org/x/sys v0.0.0-20220731174439-a90be440212d // indirect
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 // indirect
|
||||
go.opentelemetry.io/otel v1.33.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.33.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.33.0 // indirect
|
||||
go.uber.org/automaxprocs v1.6.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/oauth2 v0.27.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/term v0.30.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
golang.org/x/time v0.9.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484 // indirect
|
||||
google.golang.org/protobuf v1.36.5 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/component-base v0.22.0 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect
|
||||
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect
|
||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
|
||||
sigs.k8s.io/yaml v1.2.0 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
)
|
||||
|
||||
replace k8s.io/api => k8s.io/api v0.33.0
|
||||
|
||||
replace k8s.io/apimachinery => k8s.io/apimachinery v0.33.0
|
||||
|
||||
replace k8s.io/client-go => k8s.io/client-go v0.33.0
|
||||
|
||||
replace k8s.io/component-base => k8s.io/component-base v0.33.0
|
||||
|
|
920
go.sum
920
go.sum
|
@ -1,842 +1,222 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M=
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
|
||||
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
|
||||
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
|
||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/container-storage-interface/spec v1.5.0/go.mod h1:8K96oQNkJ7pFcC2R9Z1ynGGBB1I93kcS6PGg3SsOk8s=
|
||||
github.com/container-storage-interface/spec v1.6.0 h1:vwN9uCciKygX/a0toYryoYD5+qI9ZFeAMuhEEKO+JBA=
|
||||
github.com/container-storage-interface/spec v1.6.0/go.mod h1:8K96oQNkJ7pFcC2R9Z1ynGGBB1I93kcS6PGg3SsOk8s=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/container-storage-interface/spec v1.11.0 h1:H/YKTOeUZwHtyPOr9raR+HgFmGluGCklulxDYxSdVNM=
|
||||
github.com/container-storage-interface/spec v1.11.0/go.mod h1:DtUvaQszPml1YJfIK7c00mlv6/g4wNMLanLgiUbKFRI=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw=
|
||||
github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
|
||||
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
||||
github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM=
|
||||
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng=
|
||||
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU=
|
||||
github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/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/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
|
||||
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
|
||||
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
|
||||
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
|
||||
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
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/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
||||
github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54=
|
||||
github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
|
||||
github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
|
||||
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
|
||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
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/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kubernetes-csi/csi-lib-utils v0.11.0 h1:FHWOBtAZBA/hVk7v/qaXgG9Sxv0/n06DebPFuDwumqg=
|
||||
github.com/kubernetes-csi/csi-lib-utils v0.11.0/go.mod h1:BmGZZB16L18+9+Lgg9YWwBKfNEHIDdgGfAyuW6p2NV0=
|
||||
github.com/kubernetes-csi/csi-test/v5 v5.0.0 h1:GJ0M+ppcKgWhafXH3B2Ssfw1Egzly9GlMx3JOQApekM=
|
||||
github.com/kubernetes-csi/csi-test/v5 v5.0.0/go.mod h1:jVEIqf8Nv1roo/4zhl/r6Tc68MAgRX/OQSQK0azTHyo=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A=
|
||||
github.com/kubernetes-csi/csi-lib-utils v0.22.0 h1:EUAs1+uHGps3OtVj4XVx16urhpI02eu+Z8Vps6plpHY=
|
||||
github.com/kubernetes-csi/csi-lib-utils v0.22.0/go.mod h1:f+PalKyS4Ujsjb9+m6Rj0W6c28y3nfea3paQ/VqjI28=
|
||||
github.com/kubernetes-csi/csi-test/v5 v5.3.1 h1:Wiukp1In+kif+BFo6q2ExjgB+MbrAz4jZWzGfijypuY=
|
||||
github.com/kubernetes-csi/csi-test/v5 v5.3.1/go.mod h1:7hA2cSYJ6T8CraEZPA6zqkLZwemjBD54XAnPsPC3VpA=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
||||
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||
github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY=
|
||||
github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
|
||||
github.com/onsi/gomega v1.20.0 h1:8W0cWlwFkflGPLltQvLRB7ZVD5HuP6ng320w2IS245Q=
|
||||
github.com/onsi/gomega v1.20.0/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
|
||||
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
||||
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
|
||||
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
||||
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
||||
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
||||
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
|
||||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4=
|
||||
go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
|
||||
go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
|
||||
go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
|
||||
go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
|
||||
go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
|
||||
go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
|
||||
go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
|
||||
go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 h1:PS8wXpbyaDJQ2VDHHncMe9Vct0Zn1fEjpsjrLxGJoSc=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0/go.mod h1:HDBUsEjOuRC0EzKZ1bSaRGZWUBAzo+MhAcUUORSr4D0=
|
||||
go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw=
|
||||
go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I=
|
||||
go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ=
|
||||
go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M=
|
||||
go.opentelemetry.io/otel/sdk v1.33.0 h1:iax7M131HuAm9QkZotNHEfstof92xM+N8sr3uHXc2IM=
|
||||
go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
|
||||
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
|
||||
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
|
||||
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
||||
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220802222814-0bcc04d9c69b h1:3ogNYyK4oIQdIKzTu68hQrr4iuVxF3AxKl9Aj/eDrw0=
|
||||
golang.org/x/net v0.0.0-20220802222814-0bcc04d9c69b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg=
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
|
||||
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220731174439-a90be440212d h1:Sv5ogFZatcgIMMtBSTTAgMYsicp25MXBubjXNDKwm80=
|
||||
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
||||
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
|
||||
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201209185603-f92720507ed4/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w=
|
||||
google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484 h1:Z7FRVJPSMaHQxD0uXU8WdgFh8PseLM8Q8NzhnpMrBhQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA=
|
||||
google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU=
|
||||
google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
k8s.io/api v0.22.0/go.mod h1:0AoXXqst47OI/L0oGKq9DG61dvGRPXs7X4/B7KyjBCU=
|
||||
k8s.io/api v0.25.0 h1:H+Q4ma2U/ww0iGB78ijZx6DRByPz6/733jIuFpX70e0=
|
||||
k8s.io/api v0.25.0/go.mod h1:ttceV1GyV1i1rnmvzT3BST08N6nGt+dudGrquzVQWPk=
|
||||
k8s.io/apimachinery v0.22.0/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0=
|
||||
k8s.io/apimachinery v0.25.0 h1:MlP0r6+3XbkUG2itd6vp3oxbtdQLQI94fD5gCS+gnoU=
|
||||
k8s.io/apimachinery v0.25.0/go.mod h1:qMx9eAk0sZQGsXGu86fab8tZdffHbwUfsvzqKn4mfB0=
|
||||
k8s.io/client-go v0.22.0/go.mod h1:GUjIuXR5PiEv/RVK5OODUsm6eZk7wtSWZSaSJbpFdGg=
|
||||
k8s.io/client-go v0.25.0 h1:CVWIaCETLMBNiTUta3d5nzRbXvY5Hy9Dpl+VvREpu5E=
|
||||
k8s.io/client-go v0.25.0/go.mod h1:lxykvypVfKilxhTklov0wz1FoaUZ8X4EwbhS6rpRfN8=
|
||||
k8s.io/component-base v0.22.0 h1:ZTmX8hUqH9T9gc0mM42O+KDgtwTYbVTt2MwmLP0eK8A=
|
||||
k8s.io/component-base v0.22.0/go.mod h1:SXj6Z+V6P6GsBhHZVbWCw9hFjUdUYnJerlhhPnYCBCg=
|
||||
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
|
||||
k8s.io/klog/v2 v2.70.1 h1:7aaoSdahviPmR+XkS7FyxlkkXs6tHISSG03RxleQAVQ=
|
||||
k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
|
||||
k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 h1:MQ8BAZPZlWk3S9K4a9NCkIFQtZShWqoha7snGixVgEA=
|
||||
k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1/go.mod h1:C/N6wCaBHeBHkHUesQOQy2/MZqGgMAFPqGsGQLdbZBU=
|
||||
k8s.io/utils v0.0.0-20210707171843-4b05e18ac7d9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed h1:jAne/RjBTyawwAy0utX5eqigAwz/lQhTmy+Hr/Cpue4=
|
||||
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k=
|
||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
|
||||
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
|
||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||
k8s.io/api v0.33.0 h1:yTgZVn1XEe6opVpP1FylmNrIFWuDqe2H0V8CT5gxfIU=
|
||||
k8s.io/api v0.33.0/go.mod h1:CTO61ECK/KU7haa3qq8sarQ0biLq2ju405IZAd9zsiM=
|
||||
k8s.io/apimachinery v0.33.0 h1:1a6kHrJxb2hs4t8EE5wuR/WxKDwGN1FKH3JvDtA0CIQ=
|
||||
k8s.io/apimachinery v0.33.0/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
|
||||
k8s.io/client-go v0.33.0 h1:UASR0sAYVUzs2kYuKn/ZakZlcs2bEHaizrrHUZg0G98=
|
||||
k8s.io/client-go v0.33.0/go.mod h1:kGkd+l/gNGg8GYWAPr0xF1rRKvVWvzh9vmZAMXtaKOg=
|
||||
k8s.io/component-base v0.33.0 h1:Ot4PyJI+0JAD9covDhwLp9UNkUja209OzsJ4FzScBNk=
|
||||
k8s.io/component-base v0.33.0/go.mod h1:aXYZLbw3kihdkOPMDhWbjGCO6sg+luw554KP51t8qCU=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8=
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0=
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
|
||||
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
||||
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
|
|
|
@ -9,10 +9,13 @@ import (
|
|||
"k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/klog/v2/ktesting"
|
||||
_ "k8s.io/klog/v2/ktesting/init"
|
||||
|
||||
"github.com/container-storage-interface/spec/lib/go/csi"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/kubernetes-csi/csi-test/v5/driver"
|
||||
"github.com/kubernetes-csi/csi-test/v5/utils"
|
||||
"github.com/kubernetes-csi/external-health-monitor/pkg/mock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -52,7 +55,6 @@ func runTest(t *testing.T, tc *testCase) {
|
|||
informers := informers.NewSharedInformerFactory(client, 0)
|
||||
pvInformer := informers.Core().V1().PersistentVolumes()
|
||||
pvcInformer := informers.Core().V1().PersistentVolumeClaims()
|
||||
podInformer := informers.Core().V1().Pods()
|
||||
nodeInformer := informers.Core().V1().Nodes()
|
||||
eventInformer := informers.Core().V1().Events()
|
||||
option := &PVMonitorOptions{
|
||||
|
@ -90,8 +92,9 @@ func runTest(t *testing.T, tc *testCase) {
|
|||
assert.Nil(err)
|
||||
}
|
||||
|
||||
logger, ctx := ktesting.NewTestContext(t)
|
||||
mockCSIcontrollerServer(controllerServer, tc.supportListVolumes, volumes)
|
||||
pvMonitorController := NewPVMonitorController(client, csiConn, pvInformer, pvcInformer, podInformer, nodeInformer, eventInformer, &eventRecorder, option)
|
||||
pvMonitorController := NewPVMonitorController(logger, client, csiConn, informers, &eventRecorder, option)
|
||||
assert.NotNil(pvMonitorController)
|
||||
|
||||
if tc.hasRecoveryEvent {
|
||||
|
@ -99,10 +102,10 @@ func runTest(t *testing.T, tc *testCase) {
|
|||
assert.Nil(err)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.TODO())
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
stopCh := ctx.Done()
|
||||
informers.Start(stopCh)
|
||||
go pvMonitorController.Run(1, stopCh)
|
||||
go pvMonitorController.Run(ctx, 1)
|
||||
|
||||
event, err := mock.WatchEvent(tc.wantAbnormalEvent, eventStore)
|
||||
if tc.wantAbnormalEvent {
|
||||
|
@ -137,7 +140,7 @@ func mockCSIcontrollerServer(csiControllerServer *driver.MockControllerServer, s
|
|||
Entries: volumeResponseEntries,
|
||||
NextToken: "",
|
||||
}
|
||||
csiControllerServer.EXPECT().ListVolumes(gomock.Any(), in).Return(out, nil).Times(100000)
|
||||
csiControllerServer.EXPECT().ListVolumes(gomock.Any(), utils.Protobuf(in)).Return(out, nil).Times(100000)
|
||||
} else {
|
||||
for _, volume := range objects {
|
||||
|
||||
|
@ -150,7 +153,7 @@ func mockCSIcontrollerServer(csiControllerServer *driver.MockControllerServer, s
|
|||
VolumeCondition: volume.Condition,
|
||||
},
|
||||
}
|
||||
csiControllerServer.EXPECT().ControllerGetVolume(gomock.Any(), in).Return(out, nil).Times(100000)
|
||||
csiControllerServer.EXPECT().ControllerGetVolume(gomock.Any(), utils.Protobuf(in)).Return(out, nil).Times(100000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,10 +17,9 @@ limitations under the License.
|
|||
package pv_monitor_controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
@ -31,6 +30,7 @@ import (
|
|||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"github.com/kubernetes-csi/external-health-monitor/pkg/util"
|
||||
)
|
||||
|
@ -71,9 +71,18 @@ type NodeWatcher struct {
|
|||
}
|
||||
|
||||
// NewNodeWatcher creates a node watcher object that will watch the nodes
|
||||
func NewNodeWatcher(driverName string, client kubernetes.Interface, volumeLister corelisters.PersistentVolumeLister,
|
||||
pvcLister corelisters.PersistentVolumeClaimLister, nodeInformer coreinformers.NodeInformer,
|
||||
recorder record.EventRecorder, pvcToPodsCache *util.PVCToPodsCache, nodeWorkerExecuteInterval time.Duration, nodeListAndAddInterval time.Duration) *NodeWatcher {
|
||||
func NewNodeWatcher(
|
||||
logger klog.Logger,
|
||||
driverName string,
|
||||
client kubernetes.Interface,
|
||||
volumeLister corelisters.PersistentVolumeLister,
|
||||
pvcLister corelisters.PersistentVolumeClaimLister,
|
||||
nodeInformer coreinformers.NodeInformer,
|
||||
recorder record.EventRecorder,
|
||||
pvcToPodsCache *util.PVCToPodsCache,
|
||||
nodeWorkerExecuteInterval time.Duration,
|
||||
nodeListAndAddInterval time.Duration,
|
||||
) *NodeWatcher {
|
||||
|
||||
watcher := &NodeWatcher{
|
||||
driverName: driverName,
|
||||
|
@ -91,12 +100,12 @@ func NewNodeWatcher(driverName string, client kubernetes.Interface, volumeLister
|
|||
|
||||
nodeInformer.Informer().AddEventHandler(
|
||||
cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) { watcher.enqueueWork(obj) },
|
||||
AddFunc: func(obj interface{}) { watcher.enqueueWork(logger, obj) },
|
||||
UpdateFunc: func(oldObj, newObj interface{}) {
|
||||
watcher.enqueueWork(newObj)
|
||||
watcher.enqueueWork(logger, newObj)
|
||||
},
|
||||
DeleteFunc: func(obj interface{}) {
|
||||
watcher.enqueueWork(obj)
|
||||
watcher.enqueueWork(logger, obj)
|
||||
},
|
||||
},
|
||||
)
|
||||
|
@ -107,49 +116,52 @@ func NewNodeWatcher(driverName string, client kubernetes.Interface, volumeLister
|
|||
}
|
||||
|
||||
// enqueueWork adds node to given work queue.
|
||||
func (watcher *NodeWatcher) enqueueWork(obj interface{}) {
|
||||
func (watcher *NodeWatcher) enqueueWork(logger klog.Logger, obj interface{}) {
|
||||
// Beware of "xxx deleted" events
|
||||
if unknown, ok := obj.(cache.DeletedFinalStateUnknown); ok && unknown.Obj != nil {
|
||||
obj = unknown.Obj
|
||||
}
|
||||
objName, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
|
||||
if err != nil {
|
||||
klog.Errorf("failed to get key from object: %v", err)
|
||||
logger.Error(err, "Failed to get key from object")
|
||||
return
|
||||
}
|
||||
klog.V(6).Infof("enqueued %q for sync", objName)
|
||||
logger.V(6).Info("Enqueued ObjectName for sync", "objectName", objName)
|
||||
watcher.nodeQueue.Add(objName)
|
||||
}
|
||||
|
||||
// addNodesToQueue adds all existing nodes to queue periodically
|
||||
func (watcher *NodeWatcher) addNodesToQueue() {
|
||||
klog.V(4).Infof("resyncing Node watcher")
|
||||
func (watcher *NodeWatcher) addNodesToQueue(ctx context.Context) {
|
||||
logger := klog.FromContext(ctx)
|
||||
logger.V(4).Info("Resyncing Node watcher")
|
||||
|
||||
nodes, err := watcher.nodeLister.List(labels.NewSelector())
|
||||
if err != nil {
|
||||
klog.Warningf("cannot list nodes: %s", err)
|
||||
logger.Info("Cannot list nodes", "err", err)
|
||||
return
|
||||
}
|
||||
for _, node := range nodes {
|
||||
watcher.enqueueWork(node)
|
||||
watcher.enqueueWork(logger, node)
|
||||
}
|
||||
}
|
||||
|
||||
// Run starts all of this controller's control loops
|
||||
func (watcher *NodeWatcher) Run(stopCh <-chan struct{}) {
|
||||
func (watcher *NodeWatcher) Run(ctx context.Context) {
|
||||
logger := klog.FromContext(ctx)
|
||||
defer watcher.nodeQueue.ShutDown()
|
||||
if !cache.WaitForCacheSync(stopCh, watcher.nodeListerSynced) {
|
||||
klog.Errorf("Cannot sync cache")
|
||||
if !cache.WaitForCacheSync(ctx.Done(), watcher.nodeListerSynced) {
|
||||
logger.Error(nil, "Cannot sync cache")
|
||||
return
|
||||
}
|
||||
|
||||
go wait.Until(watcher.addNodesToQueue, watcher.nodeListAndAddInterval, stopCh)
|
||||
go wait.Until(watcher.WatchNodes, watcher.nodeWorkerExecuteInterval, stopCh)
|
||||
<-stopCh
|
||||
go wait.UntilWithContext(ctx, watcher.addNodesToQueue, watcher.nodeListAndAddInterval)
|
||||
go wait.UntilWithContext(ctx, watcher.WatchNodes, watcher.nodeWorkerExecuteInterval)
|
||||
<-ctx.Done()
|
||||
}
|
||||
|
||||
// WatchNodes periodically checks if nodes break down
|
||||
func (watcher *NodeWatcher) WatchNodes() {
|
||||
func (watcher *NodeWatcher) WatchNodes(ctx context.Context) {
|
||||
logger := klog.FromContext(ctx)
|
||||
workFunc := func() bool {
|
||||
keyObj, quit := watcher.nodeQueue.Get()
|
||||
if quit {
|
||||
|
@ -157,39 +169,38 @@ func (watcher *NodeWatcher) WatchNodes() {
|
|||
}
|
||||
defer watcher.nodeQueue.Done(keyObj)
|
||||
key := keyObj.(string)
|
||||
klog.V(4).Infof("WatchNode: %s", key)
|
||||
logger.V(4).Info("WatchNode", "node", key)
|
||||
|
||||
_, name, err := cache.SplitMetaNamespaceKey(key)
|
||||
if err != nil {
|
||||
klog.Errorf("error getting name of node %q from informer: %v", key, err)
|
||||
logger.Error(err, "Error getting name of node from informer", "node", key)
|
||||
return false
|
||||
}
|
||||
node, err := watcher.nodeLister.Get(name)
|
||||
if err == nil {
|
||||
// The node still exists in informer cache, the event must have
|
||||
// been add/update/sync
|
||||
watcher.updateNode(key, node)
|
||||
watcher.updateNode(logger, node)
|
||||
return false
|
||||
}
|
||||
if !errors.IsNotFound(err) {
|
||||
klog.V(2).Infof("error getting node %q from informer: %v", key, err)
|
||||
logger.V(2).Info("Error getting node from informer", "node", key, "err", err)
|
||||
return false
|
||||
}
|
||||
|
||||
// The node is not in informer cache, the event must be
|
||||
// "delete"
|
||||
watcher.deleteNode(key, node)
|
||||
// The node is not in informer cache, the event must be "delete"
|
||||
watcher.deleteNode(logger, node)
|
||||
return false
|
||||
}
|
||||
for {
|
||||
if quit := workFunc(); quit {
|
||||
klog.Infof("volume worker queue shutting down")
|
||||
logger.Info("Volume worker queue shutting down")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (watcher *NodeWatcher) updateNode(key string, node *v1.Node) {
|
||||
func (watcher *NodeWatcher) updateNode(logger klog.Logger, node *v1.Node) {
|
||||
// TODO: if node is ready, check if node was ever marked down, if yes, reset it
|
||||
if watcher.isNodeReady(node) {
|
||||
// The node status is ok, but if it was marked before, remove the mark
|
||||
|
@ -201,25 +212,25 @@ func (watcher *NodeWatcher) updateNode(key string, node *v1.Node) {
|
|||
// if the node was ever marked down, reset PVCs status on it
|
||||
if watcher.nodeEverMarkedDown[node.Name] {
|
||||
// TODO: reset PVCs status on the node
|
||||
err := watcher.cleanNodeFailureConditionForPVC(node)
|
||||
err := watcher.cleanNodeFailureConditionForPVC(logger, node)
|
||||
if err == nil {
|
||||
// when node recovers and send recovery event successfully, remove the node from the map
|
||||
delete(watcher.nodeEverMarkedDown, node.Name)
|
||||
} else {
|
||||
klog.Errorf("clean node failure message error: %+v", err)
|
||||
logger.Error(err, "Clean node failure message error")
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if watcher.isNodeBroken(node) {
|
||||
klog.Infof("node: %s is broken", node.Name)
|
||||
if watcher.isNodeBroken(logger, node) {
|
||||
logger.Info("Node is broken", "node", node.Name)
|
||||
// mark all PVCs/Pods on this node
|
||||
err := watcher.markPVCsAndPodsOnUnhealthyNode(node)
|
||||
err := watcher.markPVCsAndPodsOnUnhealthyNode(logger, node)
|
||||
if err != nil {
|
||||
klog.Errorf("mark PVCs on not ready node failed, re-enqueue")
|
||||
logger.Error(err, "Mark PVCs on not ready node failed, re-enqueue")
|
||||
// if error happened, re-enqueue
|
||||
watcher.enqueueWork(node)
|
||||
watcher.enqueueWork(logger, node)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -244,7 +255,7 @@ func (watcher *NodeWatcher) isNodeReady(node *v1.Node) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (watcher *NodeWatcher) isNodeBroken(node *v1.Node) bool {
|
||||
func (watcher *NodeWatcher) isNodeBroken(logger klog.Logger, node *v1.Node) bool {
|
||||
if node.Status.Phase == v1.NodeTerminated {
|
||||
return true
|
||||
}
|
||||
|
@ -258,7 +269,7 @@ func (watcher *NodeWatcher) isNodeBroken(node *v1.Node) bool {
|
|||
if timeInterval.Seconds() > DefaultNodeNotReadyTimeDuration.Seconds() {
|
||||
return true
|
||||
}
|
||||
klog.V(6).Infof("node:%s is not ready, but less than 5 minutes", node.Name)
|
||||
logger.V(6).Info("Node is not ready, but less than 5 minutes", "node", node.Name)
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -271,22 +282,22 @@ func (watcher *NodeWatcher) isNodeBroken(node *v1.Node) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (watcher *NodeWatcher) deleteNode(key string, node *v1.Node) {
|
||||
klog.Infof("node:%s is deleted, so mark the PVs on the node", node.Name)
|
||||
func (watcher *NodeWatcher) deleteNode(logger klog.Logger, node *v1.Node) {
|
||||
logger.Info("Node is deleted, so mark the PVs on the node", "node", node.Name)
|
||||
|
||||
// mark all PVs on this node
|
||||
err := watcher.markPVCsAndPodsOnUnhealthyNode(node)
|
||||
err := watcher.markPVCsAndPodsOnUnhealthyNode(logger, node)
|
||||
if err != nil {
|
||||
klog.Errorf("marking PVs failed: %v", err)
|
||||
logger.Error(err, "Marking PVs failed")
|
||||
// must re-enqueue here, because we can not get this from informer(node-lister) any more
|
||||
watcher.enqueueWork(node)
|
||||
watcher.enqueueWork(logger, node)
|
||||
}
|
||||
}
|
||||
|
||||
func (watcher *NodeWatcher) cleanNodeFailureConditionForPVC(node *v1.Node) error {
|
||||
func (watcher *NodeWatcher) cleanNodeFailureConditionForPVC(logger klog.Logger, node *v1.Node) error {
|
||||
pvs, err := watcher.volumeLister.List(labels.NewSelector())
|
||||
if err != nil {
|
||||
klog.Warningf("cannot list pvs: %s", err)
|
||||
logger.Info("Cannot list pvs", "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -300,7 +311,7 @@ func (watcher *NodeWatcher) cleanNodeFailureConditionForPVC(node *v1.Node) error
|
|||
}
|
||||
|
||||
pods := watcher.pvcToPodsCache.GetPodsByPVC(pv.Spec.ClaimRef.Namespace, pv.Spec.ClaimRef.Name)
|
||||
if pods == nil || len(pods) == 0 {
|
||||
if len(pods) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -317,7 +328,7 @@ func (watcher *NodeWatcher) cleanNodeFailureConditionForPVC(node *v1.Node) error
|
|||
// TODO: add events to Pods instead
|
||||
pvc, err := watcher.pvcLister.PersistentVolumeClaims(pv.Spec.ClaimRef.Namespace).Get(pv.Spec.ClaimRef.Name)
|
||||
if err != nil {
|
||||
klog.Errorf("get PVC[%s] from PVC lister error: %+v", pv.Spec.ClaimRef.Namespace+"/"+pv.Spec.ClaimRef.Name, err)
|
||||
logger.Error(err, "Get PVC from PVC lister error", "pvc", klog.KRef(pv.Spec.ClaimRef.Namespace, pv.Spec.ClaimRef.Name))
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -329,10 +340,10 @@ func (watcher *NodeWatcher) cleanNodeFailureConditionForPVC(node *v1.Node) error
|
|||
return nil
|
||||
}
|
||||
|
||||
func (watcher *NodeWatcher) markPVCsAndPodsOnUnhealthyNode(node *v1.Node) error {
|
||||
func (watcher *NodeWatcher) markPVCsAndPodsOnUnhealthyNode(logger klog.Logger, node *v1.Node) error {
|
||||
pvs, err := watcher.volumeLister.List(labels.NewSelector())
|
||||
if err != nil {
|
||||
klog.Warningf("cannot list pvs: %s", err)
|
||||
logger.Info("Cannot list pvs", "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -346,7 +357,7 @@ func (watcher *NodeWatcher) markPVCsAndPodsOnUnhealthyNode(node *v1.Node) error
|
|||
}
|
||||
|
||||
pods := watcher.pvcToPodsCache.GetPodsByPVC(pv.Spec.ClaimRef.Namespace, pv.Spec.ClaimRef.Name)
|
||||
if pods == nil || len(pods) == 0 {
|
||||
if len(pods) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -362,7 +373,7 @@ func (watcher *NodeWatcher) markPVCsAndPodsOnUnhealthyNode(node *v1.Node) error
|
|||
|
||||
pvc, err := watcher.pvcLister.PersistentVolumeClaims(pv.Spec.ClaimRef.Namespace).Get(pv.Spec.ClaimRef.Name)
|
||||
if err != nil {
|
||||
klog.Errorf("get PVC[%s] from PVC lister error: %+v", pv.Spec.ClaimRef.Namespace+"/"+pv.Spec.ClaimRef.Name, err)
|
||||
logger.Error(err, "Get PVC from PVC lister error", "pvc", klog.KRef(pv.Spec.ClaimRef.Namespace, pv.Spec.ClaimRef.Name))
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -17,24 +17,24 @@ limitations under the License.
|
|||
package pv_monitor_controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
coreinformers "k8s.io/client-go/informers/core/v1"
|
||||
"k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
corelisters "k8s.io/client-go/listers/core/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
handler "github.com/kubernetes-csi/external-health-monitor/pkg/csi-handler"
|
||||
"github.com/kubernetes-csi/external-health-monitor/pkg/util"
|
||||
|
@ -96,9 +96,14 @@ type PVMonitorOptions struct {
|
|||
}
|
||||
|
||||
// NewPVMonitorController creates PV monitor controller
|
||||
func NewPVMonitorController(client kubernetes.Interface, conn *grpc.ClientConn, pvInformer coreinformers.PersistentVolumeInformer,
|
||||
pvcInformer coreinformers.PersistentVolumeClaimInformer, podInformer coreinformers.PodInformer, nodeInformer coreinformers.NodeInformer, eventInformer coreinformers.EventInformer, eventRecorder record.EventRecorder, option *PVMonitorOptions) *PVMonitorController {
|
||||
|
||||
func NewPVMonitorController(
|
||||
logger klog.Logger,
|
||||
client kubernetes.Interface,
|
||||
conn *grpc.ClientConn,
|
||||
factory informers.SharedInformerFactory,
|
||||
eventRecorder record.EventRecorder,
|
||||
option *PVMonitorOptions,
|
||||
) *PVMonitorController {
|
||||
ctrl := &PVMonitorController{
|
||||
csiConn: conn,
|
||||
eventRecorder: eventRecorder,
|
||||
|
@ -115,30 +120,34 @@ func NewPVMonitorController(client kubernetes.Interface, conn *grpc.ClientConn,
|
|||
PVWorkerExecuteInterval: option.PVWorkerExecuteInterval,
|
||||
VolumeListAndAddInterval: option.VolumeListAndAddInterval,
|
||||
}
|
||||
ctrl.setupPVInformer(factory)
|
||||
ctrl.setupPVCInformer(factory)
|
||||
ctrl.setupEventInformer(factory)
|
||||
ctrl.setupPVChecker(factory, client, conn, option)
|
||||
ctrl.setupPodNodeInformersIfNecessary(factory, logger, option)
|
||||
return ctrl
|
||||
}
|
||||
|
||||
// PV informer
|
||||
pvInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
func (ctrl *PVMonitorController) setupPVInformer(factory informers.SharedInformerFactory) {
|
||||
informer := factory.Core().V1().PersistentVolumes()
|
||||
informer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: ctrl.pvAdded,
|
||||
// we do not care about PV changes, so do not need UpdateFunc here.
|
||||
// deleted PVs will not be readded to the queue, so do not need DeleteFunc here
|
||||
})
|
||||
ctrl.pvLister = pvInformer.Lister()
|
||||
ctrl.pvListerSynced = pvInformer.Informer().HasSynced
|
||||
ctrl.pvLister = informer.Lister()
|
||||
ctrl.pvListerSynced = informer.Informer().HasSynced
|
||||
}
|
||||
|
||||
// PVC informer
|
||||
ctrl.pvcLister = pvcInformer.Lister()
|
||||
ctrl.pvcListerSynced = pvcInformer.Informer().HasSynced
|
||||
func (ctrl *PVMonitorController) setupPVCInformer(factory informers.SharedInformerFactory) {
|
||||
informer := factory.Core().V1().PersistentVolumeClaims()
|
||||
ctrl.pvcLister = informer.Lister()
|
||||
ctrl.pvcListerSynced = informer.Informer().HasSynced
|
||||
}
|
||||
|
||||
// Pod informer
|
||||
podInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: ctrl.podAdded,
|
||||
// UpdateFunc: ctrl.podUpdated, TODO: do we need this ?
|
||||
DeleteFunc: ctrl.podDeleted,
|
||||
})
|
||||
ctrl.podLister = podInformer.Lister()
|
||||
ctrl.podListerSynced = podInformer.Informer().HasSynced
|
||||
|
||||
eventInformer.Informer().AddIndexers(cache.Indexers{
|
||||
func (ctrl *PVMonitorController) setupEventInformer(factory informers.SharedInformerFactory) {
|
||||
informer := factory.Core().V1().Events()
|
||||
informer.Informer().AddIndexers(cache.Indexers{
|
||||
util.DefaultEventIndexerName: func(obj interface{}) ([]string, error) {
|
||||
event := obj.(*v1.Event)
|
||||
if event != nil {
|
||||
|
@ -149,56 +158,107 @@ func NewPVMonitorController(client kubernetes.Interface, conn *grpc.ClientConn,
|
|||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (ctrl *PVMonitorController) setupPVChecker(
|
||||
factory informers.SharedInformerFactory,
|
||||
client kubernetes.Interface,
|
||||
conn *grpc.ClientConn,
|
||||
option *PVMonitorOptions,
|
||||
) {
|
||||
ctrl.pvChecker = handler.NewPVHealthConditionChecker(
|
||||
option.DriverName,
|
||||
conn,
|
||||
client,
|
||||
option.ContextTimeout,
|
||||
ctrl.pvcLister,
|
||||
ctrl.pvLister,
|
||||
factory.Core().V1().Events(),
|
||||
ctrl.eventRecorder,
|
||||
)
|
||||
}
|
||||
|
||||
func (ctrl *PVMonitorController) setupPodNodeInformersIfNecessary(factory informers.SharedInformerFactory, logger klog.Logger, option *PVMonitorOptions) {
|
||||
if ctrl.enableNodeWatcher {
|
||||
ctrl.nodeWatcher = NewNodeWatcher(ctrl.driverName, ctrl.client, ctrl.pvLister, ctrl.pvcLister, nodeInformer, ctrl.eventRecorder, ctrl.pvcToPodsCache, option.NodeWorkerExecuteInterval, option.NodeListAndAddInterval)
|
||||
ctrl.setupPodInformer(factory)
|
||||
ctrl.setupNodeWatcher(factory, logger, option)
|
||||
}
|
||||
}
|
||||
|
||||
ctrl.pvChecker = handler.NewPVHealthConditionChecker(option.DriverName, conn, client, option.ContextTimeout, ctrl.pvcLister, ctrl.pvLister, eventInformer, ctrl.eventRecorder)
|
||||
func (ctrl *PVMonitorController) setupPodInformer(factory informers.SharedInformerFactory) {
|
||||
informer := factory.Core().V1().Pods()
|
||||
informer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: ctrl.podAdded,
|
||||
// UpdateFunc: ctrl.podUpdated, TODO: do we need this ?
|
||||
DeleteFunc: ctrl.podDeleted,
|
||||
})
|
||||
ctrl.podLister = informer.Lister()
|
||||
ctrl.podListerSynced = informer.Informer().HasSynced
|
||||
}
|
||||
|
||||
return ctrl
|
||||
func (ctrl *PVMonitorController) setupNodeWatcher(factory informers.SharedInformerFactory, logger klog.Logger, option *PVMonitorOptions) {
|
||||
ctrl.nodeWatcher = NewNodeWatcher(
|
||||
logger,
|
||||
ctrl.driverName,
|
||||
ctrl.client,
|
||||
ctrl.pvLister,
|
||||
ctrl.pvcLister,
|
||||
factory.Core().V1().Nodes(),
|
||||
ctrl.eventRecorder,
|
||||
ctrl.pvcToPodsCache,
|
||||
option.NodeWorkerExecuteInterval,
|
||||
option.NodeListAndAddInterval,
|
||||
)
|
||||
}
|
||||
|
||||
// Run runs the volume health condition checking method
|
||||
func (ctrl *PVMonitorController) Run(workers int, stopCh <-chan struct{}) {
|
||||
func (ctrl *PVMonitorController) Run(ctx context.Context, workers int) {
|
||||
defer ctrl.pvQueue.ShutDown()
|
||||
|
||||
klog.Infof("Starting CSI External PV Health Monitor Controller")
|
||||
defer klog.Infof("Shutting down CSI External PV Health Monitor Controller")
|
||||
logger := klog.FromContext(ctx)
|
||||
logger.Info("Starting CSI External PV Health Monitor Controller")
|
||||
defer logger.Info("Shutting down CSI External PV Health Monitor Controller")
|
||||
|
||||
if !cache.WaitForCacheSync(stopCh, ctrl.pvcListerSynced, ctrl.pvListerSynced, ctrl.podListerSynced) {
|
||||
klog.Errorf("Cannot sync cache")
|
||||
if !waitForCacheSyncSucceed(ctx, ctrl) {
|
||||
logger.Error(nil, "Cannot sync cache")
|
||||
return
|
||||
}
|
||||
|
||||
if ctrl.enableNodeWatcher {
|
||||
go ctrl.nodeWatcher.Run(stopCh)
|
||||
go ctrl.nodeWatcher.Run(ctx)
|
||||
}
|
||||
|
||||
// TODO: we need to cache the PVs info and get the diff so that we can identify the NotFound error
|
||||
// if storage support List Volumes RPC, ListVolumes is preferred for performance reasons
|
||||
if ctrl.supportListVolumes {
|
||||
go wait.Until(ctrl.checkPVsHealthConditionByListVolumes, ctrl.ListVolumesInterval, stopCh)
|
||||
go wait.UntilWithContext(ctx, ctrl.checkPVsHealthConditionByListVolumes, ctrl.ListVolumesInterval)
|
||||
} else {
|
||||
for i := 0; i < workers; i++ {
|
||||
go wait.Until(ctrl.checkPVWorker, ctrl.PVWorkerExecuteInterval, stopCh)
|
||||
go wait.UntilWithContext(ctx, ctrl.checkPVWorker, ctrl.PVWorkerExecuteInterval)
|
||||
}
|
||||
|
||||
go wait.Until(func() {
|
||||
go wait.UntilWithContext(ctx, func(ctx context.Context) {
|
||||
logger := klog.FromContext(ctx)
|
||||
err := ctrl.AddPVsToQueue()
|
||||
if err != nil {
|
||||
klog.Errorf("Failed to reconcile volumes: %v", err)
|
||||
logger.Error(err, "Failed to reconcile volumes")
|
||||
}
|
||||
}, ctrl.VolumeListAndAddInterval, stopCh)
|
||||
}, ctrl.VolumeListAndAddInterval)
|
||||
}
|
||||
|
||||
<-stopCh
|
||||
<-ctx.Done()
|
||||
}
|
||||
|
||||
func (ctrl *PVMonitorController) checkPVsHealthConditionByListVolumes() {
|
||||
err := ctrl.pvChecker.CheckControllerListVolumeStatuses()
|
||||
func waitForCacheSyncSucceed(ctx context.Context, ctrl *PVMonitorController) bool {
|
||||
return cache.WaitForCacheSync(ctx.Done(), ctrl.pvListerSynced, ctrl.pvcListerSynced) &&
|
||||
(!ctrl.enableNodeWatcher || cache.WaitForCacheSync(ctx.Done(), ctrl.podListerSynced))
|
||||
}
|
||||
|
||||
func (ctrl *PVMonitorController) checkPVsHealthConditionByListVolumes(ctx context.Context) {
|
||||
logger := klog.FromContext(ctx)
|
||||
err := ctrl.pvChecker.CheckControllerListVolumeStatuses(ctx)
|
||||
if err != nil {
|
||||
klog.Errorf("check controller volume status error: %+v", err)
|
||||
logger.Error(err, "Check controller volume status error")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -226,15 +286,16 @@ func (ctrl *PVMonitorController) AddPVsToQueue() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (ctrl *PVMonitorController) checkPVWorker() {
|
||||
func (ctrl *PVMonitorController) checkPVWorker(ctx context.Context) {
|
||||
key, quit := ctrl.pvQueue.Get()
|
||||
if quit {
|
||||
return
|
||||
}
|
||||
defer ctrl.pvQueue.Done(key)
|
||||
|
||||
logger := klog.FromContext(ctx)
|
||||
pvName := key.(string)
|
||||
klog.V(4).Infof("Started PV processing PV %q", pvName)
|
||||
logger.V(4).Info("Started PV processing", "pv", pvName)
|
||||
|
||||
// get PV to process
|
||||
pv, err := ctrl.pvLister.Get(pvName)
|
||||
|
@ -245,27 +306,27 @@ func (ctrl *PVMonitorController) checkPVWorker() {
|
|||
// delete pv from cache here so that we do not need to handle pv deletion events
|
||||
delete(ctrl.pvEnqueued, pvName)
|
||||
ctrl.Unlock()
|
||||
klog.V(3).Infof("PV %q deleted, ignoring", pvName)
|
||||
logger.V(3).Info("PV deleted, ignoring", "pv", pvName)
|
||||
return
|
||||
}
|
||||
klog.Errorf("Error getting PersistentVolume %q: %v", pvName, err)
|
||||
logger.Error(err, "Error getting PersistentVolume", "pv", pvName)
|
||||
ctrl.pvQueue.Add(pvName)
|
||||
return
|
||||
}
|
||||
|
||||
if pv.DeletionTimestamp != nil {
|
||||
klog.Infof("PV: %s is being deleted now, skip checking health condition", pv.Name)
|
||||
logger.Info("PV is being deleted now, skip checking health condition", "pv", pv.Name)
|
||||
return
|
||||
}
|
||||
|
||||
if pv.Status.Phase != v1.VolumeBound {
|
||||
klog.Infof("PV: %s status is not bound, remove it from the queue", pv.Name)
|
||||
logger.Info("PV status is not bound, remove it from the queue", "pv", pv.Name)
|
||||
return
|
||||
}
|
||||
|
||||
err = ctrl.pvChecker.CheckControllerVolumeStatus(pv)
|
||||
err = ctrl.pvChecker.CheckControllerVolumeStatus(ctx, pv)
|
||||
if err != nil {
|
||||
klog.Errorf("check controller volume status error: %+v", err)
|
||||
logger.Error(err, "Check controller volume status error")
|
||||
}
|
||||
|
||||
// re-enqueue anyway
|
||||
|
|
|
@ -23,14 +23,13 @@ import (
|
|||
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
coreinformers "k8s.io/client-go/informers/core/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
corelisters "k8s.io/client-go/listers/core/v1"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"github.com/kubernetes-csi/external-health-monitor/pkg/util"
|
||||
)
|
||||
|
@ -53,8 +52,16 @@ type PVHealthConditionChecker struct {
|
|||
}
|
||||
|
||||
// NewPVHealthConditionChecker returns an instance of PVHealthConditionChecker
|
||||
func NewPVHealthConditionChecker(name string, conn *grpc.ClientConn, kClient kubernetes.Interface, timeout time.Duration,
|
||||
pvcLister corelisters.PersistentVolumeClaimLister, pvLister corelisters.PersistentVolumeLister, eventInformer coreinformers.EventInformer, recorder record.EventRecorder) *PVHealthConditionChecker {
|
||||
func NewPVHealthConditionChecker(
|
||||
name string,
|
||||
conn *grpc.ClientConn,
|
||||
kClient kubernetes.Interface,
|
||||
timeout time.Duration,
|
||||
pvcLister corelisters.PersistentVolumeClaimLister,
|
||||
pvLister corelisters.PersistentVolumeLister,
|
||||
eventInformer coreinformers.EventInformer,
|
||||
recorder record.EventRecorder,
|
||||
) *PVHealthConditionChecker {
|
||||
return &PVHealthConditionChecker{
|
||||
driverName: name,
|
||||
csiConn: conn,
|
||||
|
@ -64,14 +71,13 @@ func NewPVHealthConditionChecker(name string, conn *grpc.ClientConn, kClient kub
|
|||
pvLister: pvLister,
|
||||
timeout: timeout,
|
||||
eventInformer: eventInformer,
|
||||
|
||||
csiPVHandler: NewCSIPVHandler(conn),
|
||||
csiPVHandler: NewCSIPVHandler(conn),
|
||||
}
|
||||
}
|
||||
|
||||
// CheckControllerListVolumeStatuses checks volumes health condition by ListVolumes
|
||||
func (checker *PVHealthConditionChecker) CheckControllerListVolumeStatuses() error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), checker.timeout)
|
||||
func (checker *PVHealthConditionChecker) CheckControllerListVolumeStatuses(ctx context.Context) error {
|
||||
ctx, cancel := context.WithTimeout(ctx, checker.timeout)
|
||||
defer cancel()
|
||||
|
||||
result, err := checker.csiPVHandler.ControllerListVolumeConditions(ctx)
|
||||
|
@ -84,20 +90,21 @@ func (checker *PVHealthConditionChecker) CheckControllerListVolumeStatuses() err
|
|||
return err
|
||||
}
|
||||
|
||||
logger := klog.FromContext(ctx)
|
||||
for _, pv := range pvs {
|
||||
if pv.Spec.CSI == nil || pv.Spec.CSI.Driver != checker.driverName {
|
||||
klog.Infof("csi source is nil or the volume is not managed by this checker/monitor")
|
||||
logger.Info("CSI source is nil or the volume is not managed by this checker/monitor")
|
||||
continue
|
||||
}
|
||||
|
||||
if pv.Status.Phase != v1.VolumeBound {
|
||||
klog.Infof("PV: %s status is not bound", pv.Name)
|
||||
logger.Info("PV status is not bound", "pv", pv.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
volumeHandle, err := checker.GetVolumeHandle(pv)
|
||||
if err != nil {
|
||||
klog.Errorf("Get volume handle error: %+v", err)
|
||||
logger.Error(err, "Get volume handle error")
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -108,7 +115,7 @@ func (checker *PVHealthConditionChecker) CheckControllerListVolumeStatuses() err
|
|||
|
||||
pvc, err := checker.pvcLister.PersistentVolumeClaims(pv.Spec.ClaimRef.Namespace).Get(pv.Spec.ClaimRef.Name)
|
||||
if err != nil {
|
||||
klog.Errorf("Get PVC error: %+v", err)
|
||||
logger.Error(err, "Get PVC error")
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -117,7 +124,7 @@ func (checker *PVHealthConditionChecker) CheckControllerListVolumeStatuses() err
|
|||
checker.eventRecorder.Event(pvc, v1.EventTypeWarning, "VolumeConditionAbnormal", volumeCondition.GetMessage())
|
||||
} else {
|
||||
// Send recovery event if the abnormal event was sent and unexpired
|
||||
checker.sendRecoveryEventToPVC(pvc, volumeCondition)
|
||||
checker.sendRecoveryEventToPVC(logger, pvc)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,7 +141,7 @@ func (checker *PVHealthConditionChecker) GetVolumeHandle(pv *v1.PersistentVolume
|
|||
}
|
||||
|
||||
// CheckControllerVolumeStatus checks volume status in controller side
|
||||
func (checker *PVHealthConditionChecker) CheckControllerVolumeStatus(pv *v1.PersistentVolume) error {
|
||||
func (checker *PVHealthConditionChecker) CheckControllerVolumeStatus(ctx context.Context, pv *v1.PersistentVolume) error {
|
||||
if pv.Spec.CSI == nil || pv.Spec.CSI.Driver != checker.driverName {
|
||||
return fmt.Errorf("csi source is nil or the volume is not managed by this checker/monitor")
|
||||
}
|
||||
|
@ -143,12 +150,13 @@ func (checker *PVHealthConditionChecker) CheckControllerVolumeStatus(pv *v1.Pers
|
|||
return fmt.Errorf("PV: %s status is not bound", pv.Name)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), checker.timeout)
|
||||
ctx, cancel := context.WithTimeout(ctx, checker.timeout)
|
||||
defer cancel()
|
||||
|
||||
logger := klog.FromContext(ctx)
|
||||
volumeHandle, err := checker.GetVolumeHandle(pv)
|
||||
if err != nil {
|
||||
klog.Errorf("Get volume handle error: %+v", err)
|
||||
logger.Error(err, "Get volume handle error")
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -172,56 +180,7 @@ func (checker *PVHealthConditionChecker) CheckControllerVolumeStatus(pv *v1.Pers
|
|||
checker.eventRecorder.Event(pvc, v1.EventTypeWarning, "VolumeConditionAbnormal", volumeCondition.GetMessage())
|
||||
} else {
|
||||
// Send recovery event if the abnormal event was sent and unexpired
|
||||
checker.sendRecoveryEventToPVC(pvc, volumeCondition)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckNodeVolumeStatus checks volume status in node side
|
||||
func (checker *PVHealthConditionChecker) CheckNodeVolumeStatus(kubeletRootPath string, supportStageUnstage bool, pv *v1.PersistentVolume, pod *v1.Pod) error {
|
||||
if pv.Spec.CSI == nil || pv.Spec.CSI.Driver != checker.driverName {
|
||||
return fmt.Errorf("csi source is nil or the volume is not managed by this checker/monitor")
|
||||
}
|
||||
|
||||
if pv.Status.Phase != v1.VolumeBound {
|
||||
return fmt.Errorf("PV: %s status is not bound", pv.Name)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), checker.timeout)
|
||||
defer cancel()
|
||||
|
||||
volumeHandle, err := checker.GetVolumeHandle(pv)
|
||||
if err != nil {
|
||||
klog.Errorf("Get volume handle error: %+v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if len(volumeHandle) == 0 {
|
||||
return fmt.Errorf("volume handle in csi source is empty")
|
||||
}
|
||||
|
||||
var volumePath, stagingTargetPath string
|
||||
|
||||
isBlock := *pv.Spec.VolumeMode == v1.PersistentVolumeBlock
|
||||
volumePath = util.GetVolumePath(kubeletRootPath, pv.Name, string(pod.UID), isBlock)
|
||||
|
||||
if supportStageUnstage {
|
||||
stagingTargetPath, err = util.MakeDeviceMountPath(kubeletRootPath, pv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
volumeCondition, err := checker.csiPVHandler.NodeGetVolumeCondition(ctx, volumeHandle, volumePath, stagingTargetPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if volumeCondition.GetAbnormal() {
|
||||
checker.eventRecorder.Event(pod, v1.EventTypeWarning, "VolumeConditionAbnormal", volumeCondition.GetMessage())
|
||||
} else {
|
||||
return checker.sendRecoveryEventToPod(pod, volumeCondition)
|
||||
checker.sendRecoveryEventToPVC(logger, pvc)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -230,34 +189,15 @@ func (checker *PVHealthConditionChecker) CheckNodeVolumeStatus(kubeletRootPath s
|
|||
// sendRecoveryEventToPVC sends the recovery event to the pvc
|
||||
// If the volume condition is normal and abnormal event wasn't expired,
|
||||
// PVHealthConditionChecker should send recovery event.
|
||||
func (checker *PVHealthConditionChecker) sendRecoveryEventToPVC(pvc *v1.PersistentVolumeClaim, volumeCondition *VolumeConditionResult) {
|
||||
func (checker *PVHealthConditionChecker) sendRecoveryEventToPVC(logger klog.Logger, pvc *v1.PersistentVolumeClaim) {
|
||||
pvcUID := string(pvc.ObjectMeta.GetUID())
|
||||
key := fmt.Sprintf("%s:%s:%s", pvcUID, v1.EventTypeWarning, "VolumeConditionAbnormal")
|
||||
events, err := checker.eventInformer.Informer().GetIndexer().ByIndex(util.DefaultEventIndexerName, key)
|
||||
if err != nil {
|
||||
klog.Warningf("Get abnormal event from indexer failed: %+v", err)
|
||||
logger.Info("Get abnormal event from indexer failed", "err", err)
|
||||
}
|
||||
|
||||
if len(events) > 0 {
|
||||
checker.eventRecorder.Event(pvc, v1.EventTypeNormal, "VolumeConditionNormal", util.DefaultRecoveryEventMessage)
|
||||
}
|
||||
}
|
||||
|
||||
// sendRecoveryEventToPod sends the recovery event to the pod
|
||||
// If the volume condition is normal and abnormal event wasn't expired,
|
||||
// PVHealthConditionChecker should send recovery event.
|
||||
func (checker *PVHealthConditionChecker) sendRecoveryEventToPod(pod *v1.Pod, volumeCondition *VolumeConditionResult) error {
|
||||
podUID := string(pod.ObjectMeta.GetUID())
|
||||
key := fmt.Sprintf("%s:%s:%s", podUID, v1.EventTypeWarning, "VolumeConditionAbnormal")
|
||||
events, err := checker.eventInformer.Informer().GetIndexer().ByIndex(util.DefaultEventIndexerName, key)
|
||||
if err != nil {
|
||||
klog.Warningf("Get abnormal event from indexer failed: %+v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(events) > 0 {
|
||||
checker.eventRecorder.Event(pod, v1.EventTypeNormal, "VolumeConditionNormal", util.DefaultRecoveryEventMessage)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -5,15 +5,16 @@ import (
|
|||
"time"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
informerV1 "k8s.io/client-go/informers/core/v1"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/klog/v2/ktesting"
|
||||
_ "k8s.io/klog/v2/ktesting/init"
|
||||
|
||||
"github.com/container-storage-interface/spec/lib/go/csi"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/kubernetes-csi/csi-test/v5/driver"
|
||||
"github.com/kubernetes-csi/csi-test/v5/utils"
|
||||
"github.com/kubernetes-csi/external-health-monitor/pkg/mock"
|
||||
"github.com/kubernetes-csi/external-health-monitor/pkg/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -120,8 +121,9 @@ func TestPVHealthConditionChecker_CheckControllerListVolumeStatuses(t *testing.T
|
|||
NextToken: "",
|
||||
}
|
||||
|
||||
checker.csiControllerServer.EXPECT().ListVolumes(gomock.Any(), in).Return(out, nil).Times(1)
|
||||
if err := checker.pvHealthConditionChecker.CheckControllerListVolumeStatuses(); (err != nil) != tt.wantErr {
|
||||
_, ctx := ktesting.NewTestContext(t)
|
||||
checker.csiControllerServer.EXPECT().ListVolumes(gomock.Any(), utils.Protobuf(in)).Return(out, nil).Times(1)
|
||||
if err := checker.pvHealthConditionChecker.CheckControllerListVolumeStatuses(ctx); (err != nil) != tt.wantErr {
|
||||
t.Errorf("PVHealthConditionChecker.CheckControllerListVolumeStatuses() error = %v", err)
|
||||
}
|
||||
|
||||
|
@ -238,8 +240,9 @@ func TestPVHealthConditionChecker_CheckControllerVolumeStatus(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
checker.csiControllerServer.EXPECT().ControllerGetVolume(gomock.Any(), in).Return(out, nil).Times(1)
|
||||
if err := checker.pvHealthConditionChecker.CheckControllerVolumeStatus(tt.pv); (err != nil) != tt.wantErr {
|
||||
_, ctx := ktesting.NewTestContext(t)
|
||||
checker.csiControllerServer.EXPECT().ControllerGetVolume(gomock.Any(), utils.Protobuf(in)).Return(out, nil).Times(1)
|
||||
if err := checker.pvHealthConditionChecker.CheckControllerVolumeStatus(ctx, tt.pv); (err != nil) != tt.wantErr {
|
||||
t.Errorf("PVHealthConditionChecker.CheckControllerVolumeStatus() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
|
||||
|
@ -253,102 +256,3 @@ func TestPVHealthConditionChecker_CheckControllerVolumeStatus(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPVHealthConditionChecker_CheckNodeVolumeStatus(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
tests := []struct {
|
||||
name string
|
||||
pv *v1.PersistentVolume
|
||||
pvc *v1.PersistentVolumeClaim
|
||||
pod *v1.Pod
|
||||
wantErr bool
|
||||
wantAbnormalEvent bool
|
||||
kubeletRootPath string
|
||||
volumeId string
|
||||
supportStageUnstage bool
|
||||
}{
|
||||
{
|
||||
name: "VolumeConditionNormal Case",
|
||||
pvc: mock.CreatePVC(1, 2, "pvc", "uid", mock.DefaultNS, "pv", v1.ClaimBound),
|
||||
pv: mock.CreatePV(2, "pvc", "pv", mock.DefaultNS, "2", "uid", &mock.FSVolumeMode, v1.VolumeBound),
|
||||
pod: &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
UID: "1",
|
||||
},
|
||||
},
|
||||
volumeId: "2",
|
||||
},
|
||||
{
|
||||
name: "PV without CSI driver Case",
|
||||
pvc: mock.CreatePVC(1, 2, "pvc", "uid", mock.DefaultNS, "pv", v1.ClaimBound),
|
||||
pv: mock.CreatePVWithoutCSIDriver(2, "pvc", "pv", mock.DefaultNS, "1", "uid", v1.VolumeBound, &mock.FSVolumeMode),
|
||||
wantErr: true,
|
||||
pod: &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
UID: "1",
|
||||
},
|
||||
},
|
||||
volumeId: "1",
|
||||
},
|
||||
{
|
||||
name: "PV isn't in VolumeBound state",
|
||||
pvc: mock.CreatePVC(1, 2, "pvc", "uid", mock.DefaultNS, "pv", v1.ClaimBound),
|
||||
pv: mock.CreatePV(2, "pvc", "pv", mock.DefaultNS, "1", "uid", &mock.FSVolumeMode, v1.VolumePending),
|
||||
wantErr: true,
|
||||
pod: &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
UID: "1",
|
||||
},
|
||||
},
|
||||
volumeId: "1",
|
||||
},
|
||||
{
|
||||
name: "PV with nil VolumeHandle",
|
||||
pvc: mock.CreatePVC(1, 2, "pvc", "uid", mock.DefaultNS, "pv", v1.ClaimBound),
|
||||
pv: mock.CreatePVWithNilVolumeHandle(2, "pvc", "pv", mock.DefaultNS, "1", "uid", v1.VolumePending, &mock.FSVolumeMode),
|
||||
wantErr: true,
|
||||
pod: &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
UID: "1",
|
||||
},
|
||||
},
|
||||
volumeId: "1",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
checker := createMockPVHealthConditionChecker(t)
|
||||
if err := checker.pvInformer.Informer().GetStore().Add(tt.pv); err != nil {
|
||||
t.Errorf("PVHealthConditionChecker.CheckControllerListVolumeStatuses() error = %v", err)
|
||||
}
|
||||
|
||||
if err := checker.pvcInformer.Informer().GetStore().Add(tt.pvc); err != nil {
|
||||
t.Errorf("PVHealthConditionChecker.CheckControllerListVolumeStatuses() error = %v", err)
|
||||
}
|
||||
isBlock := *tt.pv.Spec.VolumeMode == v1.PersistentVolumeBlock
|
||||
volumePath := util.GetVolumePath(tt.kubeletRootPath, tt.pv.Name, string(tt.pod.ObjectMeta.UID), isBlock)
|
||||
|
||||
in := &csi.NodeGetVolumeStatsRequest{
|
||||
VolumeId: tt.volumeId,
|
||||
VolumePath: volumePath,
|
||||
StagingTargetPath: "",
|
||||
}
|
||||
out := &csi.NodeGetVolumeStatsResponse{
|
||||
VolumeCondition: volumeMap[tt.volumeId].Condition,
|
||||
}
|
||||
checker.csiNodeServer.EXPECT().NodeGetVolumeStats(gomock.Any(), in).Return(out, nil).Times(1)
|
||||
|
||||
if err := checker.pvHealthConditionChecker.CheckNodeVolumeStatus(tt.kubeletRootPath, tt.supportStageUnstage, tt.pv, tt.pod); (err != nil) != tt.wantErr {
|
||||
t.Errorf("PVHealthConditionChecker.CheckNodeVolumeStatus() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
|
||||
event, err := mock.WatchEvent(tt.wantAbnormalEvent, checker.eventStore)
|
||||
if tt.wantAbnormalEvent {
|
||||
assert.Nil(err)
|
||||
assert.EqualValues(event, mock.AbnormalEvent)
|
||||
} else {
|
||||
assert.EqualValues(mock.ErrorWatchTimeout.Error(), err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ import (
|
|||
|
||||
"github.com/container-storage-interface/spec/lib/go/csi"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/kubernetes-csi/csi-test/v5/utils"
|
||||
"github.com/kubernetes-csi/external-health-monitor/pkg/mock"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
// Test Data
|
||||
|
@ -48,10 +48,6 @@ type VolumeSample struct {
|
|||
Condition *csi.VolumeCondition
|
||||
}
|
||||
|
||||
type csiConnection struct {
|
||||
conn *grpc.ClientConn
|
||||
}
|
||||
|
||||
func Test_csiPVHandler_ControllerListVolumeConditions(t *testing.T) {
|
||||
mockController, driver, _, controllerServer, _, csiConn, err := mock.CreateMockServer(t)
|
||||
if err != nil {
|
||||
|
@ -82,7 +78,7 @@ func Test_csiPVHandler_ControllerListVolumeConditions(t *testing.T) {
|
|||
NextToken: "",
|
||||
}
|
||||
|
||||
controllerServer.EXPECT().ListVolumes(gomock.Any(), in).Return(out, nil).Times(1)
|
||||
controllerServer.EXPECT().ListVolumes(gomock.Any(), utils.Protobuf(in)).Return(out, nil).Times(1)
|
||||
tests := []struct {
|
||||
name string
|
||||
want map[string]*VolumeConditionResult
|
||||
|
@ -161,7 +157,7 @@ func Test_csiPVHandler_ControllerGetVolumeCondition(t *testing.T) {
|
|||
VolumeCondition: volumeMap[tt.volumeId].Condition,
|
||||
},
|
||||
}
|
||||
controllerServer.EXPECT().ControllerGetVolume(gomock.Any(), in).Return(out, nil).Times(1)
|
||||
controllerServer.EXPECT().ControllerGetVolume(gomock.Any(), utils.Protobuf(in)).Return(out, nil).Times(1)
|
||||
got, err := handler.ControllerGetVolumeCondition(context.Background(), tt.volumeId)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("csiPVHandler.ControllerGetVolumeCondition() error = %v, wantErr %v", err, tt.wantErr)
|
||||
|
@ -234,7 +230,7 @@ func Test_csiPVHandler_NodeGetVolumeCondition(t *testing.T) {
|
|||
out := &csi.NodeGetVolumeStatsResponse{
|
||||
VolumeCondition: volumeMap[tt.args.volumeID].Condition,
|
||||
}
|
||||
nodeServer.EXPECT().NodeGetVolumeStats(gomock.Any(), in).Return(out, nil).Times(1)
|
||||
nodeServer.EXPECT().NodeGetVolumeStats(gomock.Any(), utils.Protobuf(in)).Return(out, nil).Times(1)
|
||||
got, err := handler.NodeGetVolumeCondition(tt.args.ctx, tt.args.volumeID, tt.args.volumePath, tt.args.volumeStagingPath)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("csiPVHandler.NodeGetVolumeCondition() error = %v, wantErr %v", err, tt.wantErr)
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
package mock
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -69,9 +70,9 @@ func QuantityGB(i int) resource.Quantity {
|
|||
return *q
|
||||
}
|
||||
|
||||
func New(address string) (*grpc.ClientConn, error) {
|
||||
func New(ctx context.Context, address string) (*grpc.ClientConn, error) {
|
||||
metricsManager := metrics.NewCSIMetricsManager("fake.csi.driver.io" /* driverName */)
|
||||
conn, err := connection.Connect(address, metricsManager)
|
||||
conn, err := connection.Connect(ctx, address, metricsManager)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -100,7 +101,7 @@ func createMockServer(t *testing.T, tmpdir string) (*gomock.Controller,
|
|||
|
||||
// Create a client connection to it
|
||||
addr := drv.Address()
|
||||
csiConn, err := New(addr)
|
||||
csiConn, err := New(context.Background(), addr)
|
||||
assert.Nil(t, err)
|
||||
|
||||
return mockController, drv, identityServer, controllerServer, nodeServer, csiConn, nil
|
||||
|
@ -108,7 +109,7 @@ func createMockServer(t *testing.T, tmpdir string) (*gomock.Controller,
|
|||
|
||||
func tempDir(t *testing.T) string {
|
||||
assert := assert.New(t)
|
||||
dir, err := ioutil.TempDir("", "external-provisioner-test")
|
||||
dir, err := os.MkdirTemp("", "external-provisioner-test")
|
||||
assert.Nil(err)
|
||||
return dir
|
||||
}
|
||||
|
@ -157,7 +158,7 @@ func createPVC(requestGB, capacityGB int, name, uid, namespace, volumeName strin
|
|||
UID: types.UID(uid),
|
||||
},
|
||||
Spec: v1.PersistentVolumeClaimSpec{
|
||||
Resources: v1.ResourceRequirements{
|
||||
Resources: v1.VolumeResourceRequirements{
|
||||
Requests: map[v1.ResourceName]resource.Quantity{
|
||||
v1.ResourceStorage: request,
|
||||
},
|
||||
|
|
|
@ -43,6 +43,6 @@ func TestMakeDeviceMountPath(t *testing.T) {
|
|||
expectedMountPath := "/var/lib/kubelet/plugins/kubernetes.io/csi/pv/pvc-431ceccf-7999-11ea-ab4a-fa163ffd8213/globalmount"
|
||||
pv := &v1.PersistentVolume{}
|
||||
pv.Name = "pvc-431ceccf-7999-11ea-ab4a-fa163ffd8213"
|
||||
actualMountPath, err := MakeDeviceMountPath(kubeletRootDir, pv)
|
||||
actualMountPath, _ := MakeDeviceMountPath(kubeletRootDir, pv)
|
||||
assert.Equal(expectedMountPath, actualMountPath)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
version: 2
|
||||
enable-beta-ecosystems: true
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
labels:
|
||||
- "area/dependency"
|
||||
- "release-note-none"
|
||||
- "ok-to-test"
|
||||
open-pull-requests-limit: 10
|
|
@ -0,0 +1,15 @@
|
|||
# GitHub Action to automate the identification of common misspellings in text files.
|
||||
# https://github.com/codespell-project/actions-codespell
|
||||
# https://github.com/codespell-project/codespell
|
||||
name: codespell
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
codespell:
|
||||
name: Check for spelling errors
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: codespell-project/actions-codespell@master
|
||||
with:
|
||||
check_filenames: true
|
||||
skip: "*.png,*.jpg,*.svg,*.sum,./.git,./.github/workflows/codespell.yml,./prow.sh"
|
|
@ -0,0 +1,29 @@
|
|||
name: Run Trivy scanner for Go version vulnerabilities
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
jobs:
|
||||
trivy:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Get Go version
|
||||
id: go-version
|
||||
run: |
|
||||
GO_VERSION=$(cat prow.sh | grep "configvar CSI_PROW_GO_VERSION_BUILD" | awk '{print $3}' | sed 's/"//g')
|
||||
echo "version=$GO_VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Run Trivy scanner for Go version vulnerabilities
|
||||
uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
image-ref: 'golang:${{ steps.go-version.outputs.version }}'
|
||||
format: 'table'
|
||||
exit-code: '1'
|
||||
ignore-unfixed: true
|
||||
vuln-type: 'library'
|
||||
severity: 'CRITICAL,HIGH,MEDIUM,LOW,UNKNOWN'
|
|
@ -18,20 +18,24 @@ aliases:
|
|||
# when they are temporarily unable to review PRs.
|
||||
kubernetes-csi-reviewers:
|
||||
- andyzhangx
|
||||
- carlory
|
||||
- chrishenzie
|
||||
- ggriffiths
|
||||
- gnufied
|
||||
- humblec
|
||||
- mauriciopoppe
|
||||
- j-griffith
|
||||
- Jiawei0227
|
||||
- jingxu97
|
||||
- jsafrane
|
||||
- pohly
|
||||
- RaunakShah
|
||||
- sunnylovestiramisu
|
||||
- xing-yang
|
||||
|
||||
# This documents who previously contributed to Kubernetes-CSI
|
||||
# as approver.
|
||||
emeritus_approvers:
|
||||
- Jiawei0227
|
||||
- lpabon
|
||||
- sbezverk
|
||||
- vladimirvivien
|
||||
|
|
|
@ -17,7 +17,7 @@ The release manager must:
|
|||
Whenever a new Kubernetes minor version is released, our kubernetes-csi CI jobs
|
||||
must be updated.
|
||||
|
||||
[Our CI jobs](https://k8s-testgrid.appspot.com/sig-storage-csi-ci) have the
|
||||
[Our CI jobs](https://testgrid.k8s.io/sig-storage-csi-ci) have the
|
||||
naming convention `<hostpath-deployment-version>-on-<kubernetes-version>`.
|
||||
|
||||
1. Jobs should be actively monitored to find and fix failures in sidecars and
|
||||
|
@ -46,52 +46,51 @@ naming convention `<hostpath-deployment-version>-on-<kubernetes-version>`.
|
|||
## Release Process
|
||||
1. Identify all issues and ongoing PRs that should go into the release, and
|
||||
drive them to resolution.
|
||||
1. Download the latest version of the
|
||||
[K8s release notes generator](https://github.com/kubernetes/release/tree/HEAD/cmd/release-notes)
|
||||
1. Create a
|
||||
[Github personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)
|
||||
with `repo:public_repo` access
|
||||
1. Generate release notes for the release. Replace arguments with the relevant
|
||||
information.
|
||||
* Clean up old cached information (also needed if you are generating release
|
||||
notes for multiple repos)
|
||||
```bash
|
||||
rm -rf /tmp/k8s-repo
|
||||
```
|
||||
* For new minor releases on master:
|
||||
```bash
|
||||
GITHUB_TOKEN=<token> release-notes \
|
||||
--discover=mergebase-to-latest \
|
||||
--org=kubernetes-csi \
|
||||
--repo=external-provisioner \
|
||||
--required-author="" \
|
||||
--markdown-links \
|
||||
--output out.md
|
||||
```
|
||||
* For new patch releases on a release branch:
|
||||
```bash
|
||||
GITHUB_TOKEN=<token> release-notes \
|
||||
--discover=patch-to-latest \
|
||||
--branch=release-1.1 \
|
||||
--org=kubernetes-csi \
|
||||
--repo=external-provisioner \
|
||||
--required-author="" \
|
||||
--markdown-links \
|
||||
--output out.md
|
||||
```
|
||||
1. Compare the generated output to the new commits for the release to check if
|
||||
any notable change missed a release note.
|
||||
1. Reword release notes as needed. Make sure to check notes for breaking
|
||||
changes and deprecations.
|
||||
1. If release is a new major/minor version, create a new `CHANGELOG-<major>.<minor>.md`
|
||||
file. Otherwise, add the release notes to the top of the existing CHANGELOG
|
||||
file for that minor version.
|
||||
1. Submit a PR for the CHANGELOG changes.
|
||||
1. Update dependencies for sidecars
|
||||
1. For new minor versions, use
|
||||
[go-modules-update.sh](https://github.com/kubernetes-csi/csi-release-tools/blob/HEAD/go-modules-update.sh),
|
||||
1. For CVE fixes on patch versions, use
|
||||
[go-modules-targeted-update.sh](https://github.com/kubernetes-csi/csi-release-tools/blob/HEAD/go-modules-targeted-update.sh),
|
||||
Read the instructions at the top of the script.
|
||||
1. Check that all [canary CI
|
||||
jobs](https://testgrid.k8s.io/sig-storage-csi-ci) are passing,
|
||||
and that test coverage is adequate for the changes that are going into the release.
|
||||
1. Check that the post-\<sidecar\>-push-images builds are succeeding.
|
||||
[Example](https://testgrid.k8s.io/sig-storage-image-build#post-external-snapshotter-push-images)
|
||||
1. Generate release notes.
|
||||
1. Download the latest version of the [K8s release notes generator](https://github.com/kubernetes/release/tree/HEAD/cmd/release-notes)
|
||||
1. Create a
|
||||
[Github personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)
|
||||
with `repo:public_repo` access
|
||||
1. For patch release, use the script generate_patch_release_notes.sh. Read the instructions at the top of the
|
||||
script. The script also creates PRs for each branch.
|
||||
1. For new minor releases, follow these steps and replace arguments with the relevant
|
||||
information.
|
||||
* Clean up old cached information (also needed if you are generating release
|
||||
notes for multiple repos)
|
||||
```bash
|
||||
rm -rf /tmp/k8s-repo
|
||||
```
|
||||
* For new minor releases on master:
|
||||
```bash
|
||||
GITHUB_TOKEN=<token> release-notes \
|
||||
--discover=mergebase-to-latest \
|
||||
--org=kubernetes-csi \
|
||||
--repo=external-provisioner \
|
||||
--required-author="" \
|
||||
--markdown-links \
|
||||
--output out.md
|
||||
```
|
||||
1. Compare the generated output to the new commits for the release to check if
|
||||
any notable change missed a release note.
|
||||
1. Reword release notes as needed, ideally in the original PRs so that the
|
||||
release notes can be regenerated. Make sure to check notes for breaking
|
||||
changes and deprecations.
|
||||
1. If release is a new major/minor version, create a new `CHANGELOG-<major>.<minor>.md`
|
||||
file.
|
||||
1. Submit a PR for the CHANGELOG changes.
|
||||
1. Submit a PR for README changes, in particular, Compatibility, Feature status,
|
||||
and any other sections that may need updating.
|
||||
1. Check that all [canary CI
|
||||
jobs](https://k8s-testgrid.appspot.com/sig-storage-csi-ci) are passing,
|
||||
and that test coverage is adequate for the changes that are going into the release.
|
||||
1. Make sure that no new PRs have merged in the meantime, and no PRs are in
|
||||
flight and soon to be merged.
|
||||
1. Create a new release following a previous release as a template. Be sure to select the correct
|
||||
|
@ -99,10 +98,10 @@ naming convention `<hostpath-deployment-version>-on-<kubernetes-version>`.
|
|||
[external-provisioner example](https://github.com/kubernetes-csi/external-provisioner/releases/new)
|
||||
1. If release was a new major/minor version, create a new `release-<minor>`
|
||||
branch at that commit.
|
||||
1. Check [image build status](https://k8s-testgrid.appspot.com/sig-storage-image-build).
|
||||
1. Promote images from k8s-staging-sig-storage to k8s.gcr.io/sig-storage. From
|
||||
1. Check [image build status](https://testgrid.k8s.io/sig-storage-image-build).
|
||||
1. Promote images from k8s-staging-sig-storage to registry.k8s.io/sig-storage. From
|
||||
the [k8s image
|
||||
repo](https://github.com/kubernetes/k8s.io/tree/HEAD/k8s.gcr.io/images/k8s-staging-sig-storage),
|
||||
repo](https://github.com/kubernetes/k8s.io/tree/HEAD/registry.k8s.io/images/k8s-staging-sig-storage),
|
||||
run `./generate.sh > images.yaml`, and send a PR with the updated images.
|
||||
Once merged, the image promoter will copy the images from staging to prod.
|
||||
1. Update [kubernetes-csi/docs](https://github.com/kubernetes-csi/docs) sidecar
|
||||
|
@ -118,7 +117,7 @@ naming convention `<hostpath-deployment-version>-on-<kubernetes-version>`.
|
|||
|
||||
The following jobs are triggered after tagging to produce the corresponding
|
||||
image(s):
|
||||
https://k8s-testgrid.appspot.com/sig-storage-image-build
|
||||
https://testgrid.k8s.io/sig-storage-image-build
|
||||
|
||||
Clicking on a failed build job opens that job in https://prow.k8s.io. Next to
|
||||
the job title is a rerun icon (circle with arrow). Clicking it opens a popup
|
||||
|
|
|
@ -45,9 +45,10 @@ REV=$(shell git describe --long --tags --match='v*' --dirty 2>/dev/null || git r
|
|||
# Determined dynamically.
|
||||
IMAGE_TAGS=
|
||||
|
||||
# A "canary" image gets built if the current commit is the head of the remote "master" branch.
|
||||
# A "canary" image gets built if the current commit is the head of the remote "master" or "main" branch.
|
||||
# That branch does not exist when building some other branch in TravisCI.
|
||||
IMAGE_TAGS+=$(shell if [ "$$(git rev-list -n1 HEAD)" = "$$(git rev-list -n1 origin/master 2>/dev/null)" ]; then echo "canary"; fi)
|
||||
IMAGE_TAGS+=$(shell if [ "$$(git rev-list -n1 HEAD)" = "$$(git rev-list -n1 origin/main 2>/dev/null)" ]; then echo "canary"; fi)
|
||||
|
||||
# A "X.Y.Z-canary" image gets built if the current commit is the head of a "origin/release-X.Y.Z" branch.
|
||||
# The actual suffix does not matter, only the "release-" prefix is checked.
|
||||
|
@ -62,9 +63,9 @@ IMAGE_NAME=$(REGISTRY_NAME)/$*
|
|||
|
||||
ifdef V
|
||||
# Adding "-alsologtostderr" assumes that all test binaries contain glog. This is not guaranteed.
|
||||
TESTARGS = -v -args -alsologtostderr -v 5
|
||||
TESTARGS = -race -v -args -alsologtostderr -v 5
|
||||
else
|
||||
TESTARGS =
|
||||
TESTARGS = -race
|
||||
endif
|
||||
|
||||
# Specific packages can be excluded from each of the tests below by setting the *_FILTER_CMD variables
|
||||
|
@ -143,12 +144,12 @@ DOCKER_BUILDX_CREATE_ARGS ?=
|
|||
# Windows binaries can be built before adding a Dockerfile for it.
|
||||
#
|
||||
# BUILD_PLATFORMS determines which individual images are included in the multiarch image.
|
||||
# PULL_BASE_REF must be set to 'master', 'release-x.y', or a tag name, and determines
|
||||
# PULL_BASE_REF must be set to 'master', 'main', 'release-x.y', or a tag name, and determines
|
||||
# the tag for the resulting multiarch image.
|
||||
$(CMDS:%=push-multiarch-%): push-multiarch-%: check-pull-base-ref build-%
|
||||
set -ex; \
|
||||
export DOCKER_CLI_EXPERIMENTAL=enabled; \
|
||||
docker buildx create $(DOCKER_BUILDX_CREATE_ARGS) --use --name multiarchimage-buildertest; \
|
||||
docker buildx create $(DOCKER_BUILDX_CREATE_ARGS) --use --name multiarchimage-buildertest --driver-opt image=moby/buildkit:v0.10.6; \
|
||||
trap "docker buildx rm multiarchimage-buildertest" EXIT; \
|
||||
dockerfile_linux=$$(if [ -e ./$(CMDS_DIR)/$*/Dockerfile ]; then echo ./$(CMDS_DIR)/$*/Dockerfile; else echo Dockerfile; fi); \
|
||||
dockerfile_windows=$$(if [ -e ./$(CMDS_DIR)/$*/Dockerfile.Windows ]; then echo ./$(CMDS_DIR)/$*/Dockerfile.Windows; else echo Dockerfile.Windows; fi); \
|
||||
|
@ -191,7 +192,7 @@ $(CMDS:%=push-multiarch-%): push-multiarch-%: check-pull-base-ref build-%
|
|||
done; \
|
||||
docker manifest push -p $(IMAGE_NAME):$$tag; \
|
||||
}; \
|
||||
if [ $(PULL_BASE_REF) = "master" ]; then \
|
||||
if [ $(PULL_BASE_REF) = "master" ] || [ $(PULL_BASE_REF) = "main" ]; then \
|
||||
: "creating or overwriting canary image"; \
|
||||
pushMultiArch canary; \
|
||||
elif echo $(PULL_BASE_REF) | grep -q -e 'release-*' ; then \
|
||||
|
@ -209,7 +210,7 @@ $(CMDS:%=push-multiarch-%): push-multiarch-%: check-pull-base-ref build-%
|
|||
.PHONY: check-pull-base-ref
|
||||
check-pull-base-ref:
|
||||
if ! [ "$(PULL_BASE_REF)" ]; then \
|
||||
echo >&2 "ERROR: PULL_BASE_REF must be set to 'master', 'release-x.y', or a tag name."; \
|
||||
echo >&2 "ERROR: PULL_BASE_REF must be set to 'master', 'main', 'release-x.y', or a tag name."; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
|
@ -322,3 +323,10 @@ test-spelling:
|
|||
test-boilerplate:
|
||||
@ echo; echo "### $@:"
|
||||
@ ./release-tools/verify-boilerplate.sh "$(pwd)"
|
||||
|
||||
# Test klog usage. This test is optional and must be explicitly added to `test` target in the main Makefile:
|
||||
# test: test-logcheck
|
||||
.PHONY: test-logcheck
|
||||
test-logcheck:
|
||||
@ echo; echo "### $@:"
|
||||
@ ./release-tools/verify-logcheck.sh
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
# See https://github.com/kubernetes/test-infra/blob/HEAD/config/jobs/image-pushing/README.md
|
||||
# for more details on image pushing process in Kubernetes.
|
||||
#
|
||||
# To promote release images, see https://github.com/kubernetes/k8s.io/tree/HEAD/k8s.gcr.io/images/k8s-staging-sig-storage.
|
||||
# To promote release images, see https://github.com/kubernetes/k8s.io/tree/HEAD/registry.k8s.io/images/k8s-staging-sig-storage.
|
||||
|
||||
# This must be specified in seconds. If omitted, defaults to 600s (10 mins).
|
||||
# Building three images in external-snapshotter takes more than an hour.
|
||||
|
@ -26,7 +26,7 @@ steps:
|
|||
# The image must contain bash and curl. Ideally it should also contain
|
||||
# the desired version of Go (currently defined in release-tools/prow.sh),
|
||||
# but that just speeds up the build and is not required.
|
||||
- name: 'gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20210917-12df099d55'
|
||||
- name: 'gcr.io/k8s-testimages/gcb-docker-gcloud:v20240718-5ef92b5c36'
|
||||
entrypoint: ./.cloudbuild.sh
|
||||
env:
|
||||
- GIT_TAG=${_GIT_TAG}
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
# Copyright 2023 The Kubernetes Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import argparse
|
||||
import datetime
|
||||
import re
|
||||
from collections import defaultdict
|
||||
import subprocess
|
||||
import shutil
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
def check_gh_command():
|
||||
"""
|
||||
Pretty much everything is processed from `gh`
|
||||
Check that the `gh` command is in the path before anything else
|
||||
"""
|
||||
if not shutil.which('gh'):
|
||||
print("Error: The `gh` command is not available in the PATH.")
|
||||
print("Please install the GitHub CLI (https://cli.github.com/) and try again.")
|
||||
exit(1)
|
||||
|
||||
def duration_ago(dt):
|
||||
"""
|
||||
Humanize duration outputs
|
||||
"""
|
||||
delta = relativedelta(datetime.datetime.now(), dt)
|
||||
if delta.years > 0:
|
||||
return f"{delta.years} year{'s' if delta.years > 1 else ''} ago"
|
||||
elif delta.months > 0:
|
||||
return f"{delta.months} month{'s' if delta.months > 1 else ''} ago"
|
||||
elif delta.days > 0:
|
||||
return f"{delta.days} day{'s' if delta.days > 1 else ''} ago"
|
||||
elif delta.hours > 0:
|
||||
return f"{delta.hours} hour{'s' if delta.hours > 1 else ''} ago"
|
||||
elif delta.minutes > 0:
|
||||
return f"{delta.minutes} minute{'s' if delta.minutes > 1 else ''} ago"
|
||||
else:
|
||||
return "just now"
|
||||
|
||||
def parse_version(version):
|
||||
"""
|
||||
Parse version assuming it is in the form of v1.2.3
|
||||
"""
|
||||
pattern = r"v(\d+)\.(\d+)\.(\d+)"
|
||||
match = re.match(pattern, version)
|
||||
if match:
|
||||
major, minor, patch = map(int, match.groups())
|
||||
return (major, minor, patch)
|
||||
|
||||
def end_of_life_grouped_versions(versions):
|
||||
"""
|
||||
Calculate the end of life date for a minor release version according to : https://kubernetes-csi.github.io/docs/project-policies.html#support
|
||||
|
||||
The input is an array of tuples of:
|
||||
* grouped versions (e.g. 1.0, 1.1)
|
||||
* array of that contains all versions and their release date (e.g. 1.0.0, 01-01-2013)
|
||||
|
||||
versions structure example :
|
||||
[((3, 5), [('v3.5.0', datetime.datetime(2023, 4, 27, 22, 28, 6))]),
|
||||
((3, 4),
|
||||
[('v3.4.1', datetime.datetime(2023, 4, 5, 17, 41, 15)),
|
||||
('v3.4.0', datetime.datetime(2022, 12, 27, 23, 43, 41))])]
|
||||
"""
|
||||
supported_versions = []
|
||||
# Prepare dates for later calculation
|
||||
now = datetime.datetime.now()
|
||||
one_year = datetime.timedelta(days=365)
|
||||
three_months = datetime.timedelta(days=90)
|
||||
|
||||
# get the newer versions on top
|
||||
sorted_versions_list = sorted(versions.items(), key=lambda x: x[0], reverse=True)
|
||||
|
||||
# the latest version is always supported no matter the release date
|
||||
latest = sorted_versions_list.pop(0)
|
||||
supported_versions.append(latest[1][-1])
|
||||
|
||||
for v in sorted_versions_list:
|
||||
first_release = v[1][-1]
|
||||
last_release = v[1][0]
|
||||
# if the release is less than a year old we support the latest patch version
|
||||
if now - first_release[1] < one_year:
|
||||
supported_versions.append(last_release)
|
||||
# if the main release is older than a year and has a recent path, this is supported
|
||||
elif now - last_release[1] < three_months:
|
||||
supported_versions.append(last_release)
|
||||
return supported_versions
|
||||
|
||||
def get_release_docker_image(repo, version):
|
||||
"""
|
||||
Extract docker image name from the release page documentation
|
||||
"""
|
||||
output = subprocess.check_output(['gh', 'release', '-R', repo, 'view', version], text=True)
|
||||
#Extract matching image name excluding `
|
||||
match = re.search(r"docker pull ([\.\/\-\:\w\d]*)", output)
|
||||
docker_image = match.group(1) if match else ''
|
||||
return((version, docker_image))
|
||||
|
||||
def get_versions_from_releases(repo):
|
||||
"""
|
||||
Using `gh` cli get the github releases page details then
|
||||
create a list of grouped version on major.minor
|
||||
and for each give all major.minor.patch with release dates
|
||||
"""
|
||||
# Run the `gh release` command to get the release list
|
||||
output = subprocess.check_output(['gh', 'release', '-R', repo, 'list'], text=True)
|
||||
# Parse the output and group by major and minor version numbers
|
||||
versions = defaultdict(lambda: [])
|
||||
for line in output.strip().split('\n'):
|
||||
parts = line.split('\t')
|
||||
# pprint.pprint(parts)
|
||||
version = parts[0]
|
||||
parsed_version = parse_version(version)
|
||||
if parsed_version is None:
|
||||
continue
|
||||
major, minor, patch = parsed_version
|
||||
|
||||
published = datetime.datetime.strptime(parts[3], '%Y-%m-%dT%H:%M:%SZ')
|
||||
versions[(major, minor)].append((version, published))
|
||||
return(versions)
|
||||
|
||||
|
||||
def main():
|
||||
manual = """
|
||||
This script lists the supported versions Github releases according to https://kubernetes-csi.github.io/docs/project-policies.html#support
|
||||
It has been designed to help to update the tables from : https://kubernetes-csi.github.io/docs/sidecar-containers.html\n\n
|
||||
It can take multiple repos as argument, for all CSI sidecars details you can run:
|
||||
./get_supported_version_csi-sidecar.py -R kubernetes-csi/external-attacher -R kubernetes-csi/external-provisioner -R kubernetes-csi/external-resizer -R kubernetes-csi/external-snapshotter -R kubernetes-csi/livenessprobe -R kubernetes-csi/node-driver-registrar -R kubernetes-csi/external-health-monitor\n
|
||||
With the output you can then update the documentation manually.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, description=manual)
|
||||
parser.add_argument('--repo', '-R', required=True, action='append', dest='repos', help='The name of the repository in the format owner/repo.')
|
||||
parser.add_argument('--display', '-d', action='store_true', help='(default) Display EOL versions with their dates', default=True)
|
||||
parser.add_argument('--doc', '-D', action='store_true', help='Helper to https://kubernetes-csi.github.io/docs/ that prints Docker image for each EOL version')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Verify pre-reqs
|
||||
check_gh_command()
|
||||
|
||||
# Process all repos
|
||||
for repo in args.repos:
|
||||
versions = get_versions_from_releases(repo)
|
||||
eol_versions = end_of_life_grouped_versions(versions)
|
||||
|
||||
if args.display:
|
||||
print(f"Supported versions with release date and age of `{repo}`:\n")
|
||||
for version in eol_versions:
|
||||
print(f"{version[0]}\t{version[1].strftime('%Y-%m-%d')}\t{duration_ago(version[1])}")
|
||||
|
||||
# TODO : generate proper doc output for the tables of: https://kubernetes-csi.github.io/docs/sidecar-containers.html
|
||||
if args.doc:
|
||||
print("\nSupported Versions with docker images for each end of life version:\n")
|
||||
for version in eol_versions:
|
||||
_, image = get_release_docker_image(repo, version[0])
|
||||
print(f"{version[0]}\t{image}")
|
||||
print()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -24,7 +24,6 @@ package main
|
|||
import (
|
||||
"encoding/xml"
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"regexp"
|
||||
)
|
||||
|
@ -56,6 +55,7 @@ type TestCase struct {
|
|||
Name string `xml:"name,attr"`
|
||||
Time string `xml:"time,attr"`
|
||||
SystemOut string `xml:"system-out,omitempty"`
|
||||
SystemErr string `xml:"system-err,omitempty"`
|
||||
Failure string `xml:"failure,omitempty"`
|
||||
Skipped SkipReason `xml:"skipped,omitempty"`
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ func main() {
|
|||
}
|
||||
} else {
|
||||
var err error
|
||||
data, err = ioutil.ReadFile(input)
|
||||
data, err = os.ReadFile(input)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ func main() {
|
|||
if err := xml.Unmarshal(data, &junitv2); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
junit = junitv2.TestSuite
|
||||
junit.TestCases = append(junit.TestCases, junitv2.TestSuite.TestCases...)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,7 +142,7 @@ func main() {
|
|||
panic(err)
|
||||
}
|
||||
} else {
|
||||
if err := ioutil.WriteFile(*output, data, 0644); err != nil {
|
||||
if err := os.WriteFile(*output, data, 0644); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Copyright 2023 The Kubernetes Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
# Usage: generate_patch_release_notes.sh
|
||||
#
|
||||
# Generates and creates PRs for kubernetes-csi patch releases.
|
||||
#
|
||||
# Required environment variables
|
||||
# CSI_RELEASE_TOKEN: Github token needed for generating release notes
|
||||
# GITHUB_USER: Github username to create PRs with
|
||||
#
|
||||
# Required tools:
|
||||
# - gh
|
||||
# - release-notes (https://github.com/kubernetes/release/blob/master/cmd/release-notes/README.md)
|
||||
#
|
||||
# Instructions:
|
||||
# 1. Install the required tools
|
||||
# 2. Login with "gh auth login"
|
||||
# 3. Copy this script to the kubernetes-csi directory (one directory above the repos)
|
||||
# 4. Update the repos and versions in the $releases array
|
||||
# 5. Set environment variables
|
||||
# 6. Run script from the kubernetes-csi directory
|
||||
#
|
||||
# Caveats:
|
||||
# - This script doesn't handle regenerating and updating existing PRs yet.
|
||||
# It might work if you comment out the PR creation line
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
releases=(
|
||||
# "external-attacher 4.4.1"
|
||||
# "external-provisioner 3.6.1"
|
||||
# "external-snapshotter 6.2.3"
|
||||
)
|
||||
|
||||
function gen_patch_relnotes() {
|
||||
rm out.md || true
|
||||
rm -rf /tmp/k8s-repo || true
|
||||
GITHUB_TOKEN="$CSI_RELEASE_TOKEN" \
|
||||
release-notes --start-rev="$3" --end-rev="$2" --branch="$2" \
|
||||
--org=kubernetes-csi --repo="$1" \
|
||||
--required-author="" --markdown-links --output out.md
|
||||
}
|
||||
|
||||
for rel in "${releases[@]}"; do
|
||||
read -r repo version <<< "$rel"
|
||||
|
||||
# Parse minor version
|
||||
minorPatchPattern="(^[[:digit:]]+\.[[:digit:]]+)\.([[:digit:]]+)"
|
||||
[[ "$version" =~ $minorPatchPattern ]]
|
||||
minor="${BASH_REMATCH[1]}"
|
||||
patch="${BASH_REMATCH[2]}"
|
||||
|
||||
echo "$repo $version $minor $patch"
|
||||
prevPatch="$((patch-1))"
|
||||
prevVer="v$minor.$prevPatch"
|
||||
|
||||
pushd "$repo/CHANGELOG"
|
||||
|
||||
git fetch upstream
|
||||
|
||||
# Create branch
|
||||
branch="changelog-release-$minor"
|
||||
git checkout master
|
||||
git branch -D "$branch" || true
|
||||
git checkout --track "upstream/release-$minor" -b "$branch"
|
||||
|
||||
# Generate release notes
|
||||
gen_patch_relnotes "$repo" "release-$minor" "$prevVer"
|
||||
cat > tmp.md <<EOF
|
||||
# Release notes for v$version
|
||||
|
||||
[Documentation](https://kubernetes-csi.github.io)
|
||||
|
||||
EOF
|
||||
|
||||
cat out.md >> tmp.md
|
||||
echo >> tmp.md
|
||||
rm out.md
|
||||
|
||||
file="CHANGELOG-$minor.md"
|
||||
cat "$file" >> tmp.md
|
||||
mv tmp.md "$file"
|
||||
|
||||
git add -u
|
||||
git commit -m "Add changelog for $version"
|
||||
git push -f origin "$branch"
|
||||
|
||||
# Create PR
|
||||
prbody=$(cat <<EOF
|
||||
\`\`\`release-note
|
||||
NONE
|
||||
\`\`\`
|
||||
EOF
|
||||
)
|
||||
gh pr create --title="Changelog for v$version" --body "$prbody" --head "$GITHUB_USER:$branch" --base "release-$minor" --repo="kubernetes-csi/$repo"
|
||||
|
||||
popd
|
||||
done
|
|
@ -0,0 +1,96 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Copyright 2023 The Kubernetes Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
# Usage: go-modules-targeted-update.sh
|
||||
#
|
||||
# Batch update specific dependencies for sidecars.
|
||||
#
|
||||
# Required environment variables
|
||||
# CSI_RELEASE_TOKEN: Github token needed for generating release notes
|
||||
# GITHUB_USER: Github username to create PRs with
|
||||
#
|
||||
# Instructions:
|
||||
# 1. Login with "gh auth login"
|
||||
# 2. Copy this script to the Github org directory (one directory above the
|
||||
# repos)
|
||||
# 3. Change $modules, $releases and $org if needed.
|
||||
# 4. Set environment variables
|
||||
# 5. Run script from the Github org directory
|
||||
#
|
||||
# Caveats:
|
||||
# - This script doesn't handle interface incompatibility of updates.
|
||||
# You need to resolve interface incompatibility case by case. The
|
||||
# most frequent case is to update the interface(new parameters,
|
||||
# name change of the method, etc.)in the sidecar repo and make sure
|
||||
# the build and test pass.
|
||||
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
org="kubernetes-csi"
|
||||
|
||||
modules=(
|
||||
"github.com/kubernetes-csi/csi-lib-utils@v0.15.1"
|
||||
)
|
||||
|
||||
releases=(
|
||||
#"external-attacher release-4.4"
|
||||
#"external-provisioner release-3.6"
|
||||
#"external-resizer release-1.9"
|
||||
#"external-snapshotter release-6.3"
|
||||
#"node-driver-registrar release-2.9"
|
||||
)
|
||||
|
||||
for rel in "${releases[@]}"; do
|
||||
|
||||
read -r repo branch <<< "$rel"
|
||||
if [ "$repo" != "#" ]; then
|
||||
(
|
||||
cd "$repo"
|
||||
git fetch upstream
|
||||
|
||||
if [ "$(git rev-parse --verify "module-update-$branch" 2>/dev/null)" ]; then
|
||||
git checkout master && git branch -D "module-update-$branch"
|
||||
fi
|
||||
git checkout -B "module-update-$branch" "upstream/$branch"
|
||||
|
||||
for mod in "${modules[@]}"; do
|
||||
go get "$mod"
|
||||
done
|
||||
go mod tidy
|
||||
go mod vendor
|
||||
|
||||
git add --all
|
||||
git commit -m "Update go modules"
|
||||
git push origin "module-update-$branch" --force
|
||||
|
||||
# Create PR
|
||||
prbody=$(cat <<EOF
|
||||
Updated the following go modules:
|
||||
|
||||
${modules[@]}
|
||||
|
||||
\`\`\`release-note
|
||||
NONE
|
||||
\`\`\`
|
||||
EOF
|
||||
)
|
||||
gh pr create --title="[$branch] Update go modules" --body "$prbody" --head "$GITHUB_USER:module-update-$branch" --base "$branch" --repo="$org/$repo"
|
||||
)
|
||||
fi
|
||||
done
|
|
@ -0,0 +1,129 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Copyright 2023 The Kubernetes Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
# Usage: go-modules-update.sh
|
||||
#
|
||||
# Batch update dependencies for sidecars.
|
||||
#
|
||||
# Required environment variables
|
||||
# CSI_RELEASE_TOKEN: Github token needed for generating release notes
|
||||
# GITHUB_USER: Github username to create PRs with
|
||||
#
|
||||
# Instructions:
|
||||
# 1. Login with "gh auth login"
|
||||
# 2. Copy this script to the kubernetes-csi directory (one directory above the
|
||||
# repos)
|
||||
# 3. Update the repos and master branch so locally it has the latest upstream
|
||||
# change
|
||||
# 4. Set environment variables
|
||||
# 5. Run script from the kubernetes-csi directory
|
||||
#
|
||||
# Caveats:
|
||||
# - This script doesn't handle interface incompatibility of updates.
|
||||
# You need to resolve interface incompatibility case by case. The
|
||||
# most frequent case is to update the interface(new parameters,
|
||||
# name change of the method, etc.)in the sidecar repo and make sure
|
||||
# the build and test pass.
|
||||
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
MAX_RETRY=10
|
||||
|
||||
# Get the options
|
||||
while getopts ":u:v:" option; do
|
||||
case $option in
|
||||
u) # Set username
|
||||
username=$OPTARG;;
|
||||
v) # Set version
|
||||
v=$OPTARG;;
|
||||
\?) # Invalid option
|
||||
echo "Error: Invalid option: $OPTARG"
|
||||
exit;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Only need to do this once
|
||||
gh auth login
|
||||
|
||||
while read -r repo branches; do
|
||||
if [ "$repo" != "#" ]; then
|
||||
(
|
||||
cd "$repo"
|
||||
git fetch origin
|
||||
for i in $branches; do
|
||||
if [ "$(git rev-parse --verify "module-update-$i" 2>/dev/null)" ]; then
|
||||
git checkout master && git branch -d "module-update-$i"
|
||||
fi
|
||||
git checkout -B "module-update-$i" "origin/$i"
|
||||
rm -rf .git/MERGE*
|
||||
if ! git subtree pull --squash --prefix=release-tools https://github.com/kubernetes-csi/csi-release-tools.git master; then
|
||||
# Sometimes "--squash" leads to merge conflicts. Because we know that "release-tools"
|
||||
# is an unmodified copy of csi-release-tools, we can automatically resolve that
|
||||
# by replacing it completely.
|
||||
if [ -e .git/MERGE_MSG ] && [ -e .git/FETCH_HEAD ] && grep -q "^# Conflict" .git/MERGE_MSG; then
|
||||
rm -rf release-tools
|
||||
mkdir release-tools
|
||||
git archive FETCH_HEAD | tar -C release-tools -xf -
|
||||
git add release-tools
|
||||
git commit --file=.git/MERGE_MSG
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
RETRY=0
|
||||
while ! ./release-tools/go-get-kubernetes.sh -p "$v" && RETRY < $MAX_RETRY
|
||||
do
|
||||
RETRY=$((RETRY+1))
|
||||
go mod tidy && go mod vendor && go mod tidy
|
||||
done
|
||||
go mod tidy && go mod vendor && go mod tidy
|
||||
git add --all
|
||||
git commit -m "Update dependency go modules for k8s v$v"
|
||||
git remote set-url origin "https://github.com/$username/$repo.git"
|
||||
make test
|
||||
git push origin "module-update-$i" --force
|
||||
# Create PR
|
||||
prbody=$(cat <<EOF
|
||||
Ran kubernetes-csi/csi-release-tools go-get-kubernetes.sh -p ${v}.
|
||||
|
||||
|
||||
\`\`\`release-note
|
||||
Update kubernetes dependencies to v${v}
|
||||
\`\`\`
|
||||
EOF
|
||||
)
|
||||
gh pr create --title="Update dependency go modules for k8s v$v" --body "$prbody" --head "$username:module-update-master" --base "master" --repo="kubernetes-csi/$repo"
|
||||
done
|
||||
)
|
||||
fi
|
||||
done <<EOF
|
||||
csi-driver-host-path master
|
||||
csi-driver-iscsi master
|
||||
csi-driver-nfs master
|
||||
csi-lib-utils master
|
||||
csi-proxy master
|
||||
csi-test master
|
||||
external-attacher master
|
||||
external-health-monitor master
|
||||
external-provisioner master
|
||||
external-resizer master
|
||||
external-snapshotter master
|
||||
livenessprobe master
|
||||
node-driver-registrar master
|
||||
EOF
|
|
@ -78,7 +78,7 @@ version_to_git () {
|
|||
# the list of windows versions was matched from:
|
||||
# - https://hub.docker.com/_/microsoft-windows-nanoserver
|
||||
# - https://hub.docker.com/_/microsoft-windows-servercore
|
||||
configvar CSI_PROW_BUILD_PLATFORMS "linux amd64 amd64; linux ppc64le ppc64le -ppc64le; linux s390x s390x -s390x; linux arm arm -arm; linux arm64 arm64 -arm64; linux arm arm/v7 -armv7; windows amd64 amd64 .exe nanoserver:1809 servercore:ltsc2019; windows amd64 amd64 .exe nanoserver:20H2 servercore:20H2; windows amd64 amd64 .exe nanoserver:ltsc2022 servercore:ltsc2022" "Go target platforms (= GOOS + GOARCH) and file suffix of the resulting binaries"
|
||||
configvar CSI_PROW_BUILD_PLATFORMS "linux amd64 amd64; linux ppc64le ppc64le -ppc64le; linux s390x s390x -s390x; linux arm arm -arm; linux arm64 arm64 -arm64; linux arm arm/v7 -armv7; windows amd64 amd64 .exe nanoserver:1809 servercore:ltsc2019; windows amd64 amd64 .exe nanoserver:ltsc2022 servercore:ltsc2022" "Go target platforms (= GOOS + GOARCH) and file suffix of the resulting binaries"
|
||||
|
||||
# If we have a vendor directory, then use it. We must be careful to only
|
||||
# use this for "make" invocations inside the project's repo itself because
|
||||
|
@ -86,7 +86,7 @@ configvar CSI_PROW_BUILD_PLATFORMS "linux amd64 amd64; linux ppc64le ppc64le -pp
|
|||
# which is disabled with GOFLAGS=-mod=vendor).
|
||||
configvar GOFLAGS_VENDOR "$( [ -d vendor ] && echo '-mod=vendor' )" "Go flags for using the vendor directory"
|
||||
|
||||
configvar CSI_PROW_GO_VERSION_BUILD "1.18" "Go version for building the component" # depends on component's source code
|
||||
configvar CSI_PROW_GO_VERSION_BUILD "1.24.2" "Go version for building the component" # depends on component's source code
|
||||
configvar CSI_PROW_GO_VERSION_E2E "" "override Go version for building the Kubernetes E2E test suite" # normally doesn't need to be set, see install_e2e
|
||||
configvar CSI_PROW_GO_VERSION_SANITY "${CSI_PROW_GO_VERSION_BUILD}" "Go version for building the csi-sanity test suite" # depends on CSI_PROW_SANITY settings below
|
||||
configvar CSI_PROW_GO_VERSION_KIND "${CSI_PROW_GO_VERSION_BUILD}" "Go version for building 'kind'" # depends on CSI_PROW_KIND_VERSION below
|
||||
|
@ -101,7 +101,10 @@ configvar CSI_PROW_GINKGO_VERSION v1.7.0 "Ginkgo"
|
|||
|
||||
# Ginkgo runs the E2E test in parallel. The default is based on the number
|
||||
# of CPUs, but typically this can be set to something higher in the job.
|
||||
configvar CSI_PROW_GINKO_PARALLEL "-p" "Ginko parallelism parameter(s)"
|
||||
configvar CSI_PROW_GINKGO_PARALLEL "-p" "Ginkgo parallelism parameter(s)"
|
||||
|
||||
# Timeout value for the overall ginkgo test suite.
|
||||
configvar CSI_PROW_GINKGO_TIMEOUT "1h" "Ginkgo timeout"
|
||||
|
||||
# Enables building the code in the repository. On by default, can be
|
||||
# disabled in jobs which only use pre-built components.
|
||||
|
@ -141,7 +144,7 @@ kind_version_default () {
|
|||
latest|master)
|
||||
echo main;;
|
||||
*)
|
||||
echo v0.14.0;;
|
||||
echo v0.25.0;;
|
||||
esac
|
||||
}
|
||||
|
||||
|
@ -152,13 +155,13 @@ configvar CSI_PROW_KIND_VERSION "$(kind_version_default)" "kind"
|
|||
|
||||
# kind images to use. Must match the kind version.
|
||||
# The release notes of each kind release list the supported images.
|
||||
configvar CSI_PROW_KIND_IMAGES "kindest/node:v1.24.0@sha256:0866296e693efe1fed79d5e6c7af8df71fc73ae45e3679af05342239cdc5bc8e
|
||||
kindest/node:v1.23.6@sha256:b1fa224cc6c7ff32455e0b1fd9cbfd3d3bc87ecaa8fcb06961ed1afb3db0f9ae
|
||||
kindest/node:v1.22.9@sha256:8135260b959dfe320206eb36b3aeda9cffcb262f4b44cda6b33f7bb73f453105
|
||||
kindest/node:v1.21.12@sha256:f316b33dd88f8196379f38feb80545ef3ed44d9197dca1bfd48bcb1583210207
|
||||
kindest/node:v1.20.15@sha256:6f2d011dffe182bad80b85f6c00e8ca9d86b5b8922cdf433d53575c4c5212248
|
||||
kindest/node:v1.19.16@sha256:d9c819e8668de8d5030708e484a9fdff44d95ec4675d136ef0a0a584e587f65c
|
||||
kindest/node:v1.18.20@sha256:738cdc23ed4be6cc0b7ea277a2ebcc454c8373d7d8fb991a7fcdbd126188e6d7" "kind images"
|
||||
configvar CSI_PROW_KIND_IMAGES "kindest/node:v1.32.0@sha256:2458b423d635d7b01637cac2d6de7e1c1dca1148a2ba2e90975e214ca849e7cb
|
||||
kindest/node:v1.31.2@sha256:18fbefc20a7113353c7b75b5c869d7145a6abd6269154825872dc59c1329912e
|
||||
kindest/node:v1.30.6@sha256:b6d08db72079ba5ae1f4a88a09025c0a904af3b52387643c285442afb05ab994
|
||||
kindest/node:v1.29.10@sha256:3b2d8c31753e6c8069d4fc4517264cd20e86fd36220671fb7d0a5855103aa84b
|
||||
kindest/node:v1.28.15@sha256:a7c05c7ae043a0b8c818f5a06188bc2c4098f6cb59ca7d1856df00375d839251
|
||||
kindest/node:v1.27.16@sha256:2d21a61643eafc439905e18705b8186f3296384750a835ad7a005dceb9546d20
|
||||
kindest/node:v1.26.15@sha256:c79602a44b4056d7e48dc20f7504350f1e87530fe953428b792def00bc1076dd" "kind images"
|
||||
|
||||
# By default, this script tests sidecars with the CSI hostpath driver,
|
||||
# using the install_csi_driver function. That function depends on
|
||||
|
@ -196,7 +199,7 @@ kindest/node:v1.18.20@sha256:738cdc23ed4be6cc0b7ea277a2ebcc454c8373d7d8fb991a7fc
|
|||
# If the deployment script is called with CSI_PROW_TEST_DRIVER=<file name> as
|
||||
# environment variable, then it must write a suitable test driver configuration
|
||||
# into that file in addition to installing the driver.
|
||||
configvar CSI_PROW_DRIVER_VERSION "v1.8.0" "CSI driver version"
|
||||
configvar CSI_PROW_DRIVER_VERSION "v1.15.0" "CSI driver version"
|
||||
configvar CSI_PROW_DRIVER_REPO https://github.com/kubernetes-csi/csi-driver-host-path "CSI driver repo"
|
||||
configvar CSI_PROW_DEPLOYMENT "" "deployment"
|
||||
configvar CSI_PROW_DEPLOYMENT_SUFFIX "" "additional suffix in kubernetes-x.yy[suffix].yaml files"
|
||||
|
@ -228,13 +231,19 @@ configvar CSI_PROW_E2E_VERSION "$(version_to_git "${CSI_PROW_KUBERNETES_VERSION}
|
|||
configvar CSI_PROW_E2E_REPO "https://github.com/kubernetes/kubernetes" "E2E repo"
|
||||
configvar CSI_PROW_E2E_IMPORT_PATH "k8s.io/kubernetes" "E2E package"
|
||||
|
||||
# Local path & package path for e2e tests. Set to "none" to disable.
|
||||
# When using versioned go modules, the import path is the module path whereas the path
|
||||
# should not contain the version and be the directory where the module is checked out.
|
||||
configvar CSI_PROW_SIDECAR_E2E_IMPORT_PATH "none" "CSI Sidecar E2E package (go import path)"
|
||||
configvar CSI_PROW_SIDECAR_E2E_PATH "${CSI_PROW_SIDECAR_E2E_IMPORT_PATH}" "CSI Sidecar E2E path (directory)"
|
||||
|
||||
# csi-sanity testing from the csi-test repo can be run against the installed
|
||||
# CSI driver. For this to work, deploying the driver must expose the Unix domain
|
||||
# csi.sock as a TCP service for use by the csi-sanity command, which runs outside
|
||||
# of the cluster. The alternative would have been to (cross-)compile csi-sanity
|
||||
# and install it inside the cluster, which is not necessarily easier.
|
||||
configvar CSI_PROW_SANITY_REPO https://github.com/kubernetes-csi/csi-test "csi-test repo"
|
||||
configvar CSI_PROW_SANITY_VERSION v5.0.0 "csi-test version"
|
||||
configvar CSI_PROW_SANITY_VERSION v5.3.1 "csi-test version"
|
||||
configvar CSI_PROW_SANITY_PACKAGE_PATH github.com/kubernetes-csi/csi-test "csi-test package"
|
||||
configvar CSI_PROW_SANITY_SERVICE "hostpath-service" "Kubernetes TCP service name that exposes csi.sock"
|
||||
configvar CSI_PROW_SANITY_POD "csi-hostpathplugin-0" "Kubernetes pod with CSI driver"
|
||||
|
@ -242,7 +251,7 @@ configvar CSI_PROW_SANITY_CONTAINER "hostpath" "Kubernetes container with CSI dr
|
|||
|
||||
# The version of dep to use for 'make test-vendor'. Ignored if the project doesn't
|
||||
# use dep. Only binary releases of dep are supported (https://github.com/golang/dep/releases).
|
||||
configvar CSI_PROW_DEP_VERSION v0.5.1 "golang dep version to be used for vendor checking"
|
||||
configvar CSI_PROW_DEP_VERSION v0.5.4 "golang dep version to be used for vendor checking"
|
||||
|
||||
# Each job can run one or more of the following tests, identified by
|
||||
# a single word:
|
||||
|
@ -282,13 +291,18 @@ tests_enabled () {
|
|||
sanity_enabled () {
|
||||
[ "${CSI_PROW_TESTS_SANITY}" = "sanity" ] && tests_enabled "sanity"
|
||||
}
|
||||
|
||||
sidecar_tests_enabled () {
|
||||
[ "${CSI_PROW_SIDECAR_E2E_IMPORT_PATH}" != "none" ]
|
||||
}
|
||||
|
||||
tests_need_kind () {
|
||||
tests_enabled "parallel" "serial" "serial-alpha" "parallel-alpha" ||
|
||||
sanity_enabled
|
||||
sanity_enabled || sidecar_tests_enabled
|
||||
}
|
||||
tests_need_non_alpha_cluster () {
|
||||
tests_enabled "parallel" "serial" ||
|
||||
sanity_enabled
|
||||
sanity_enabled || sidecar_tests_enabled
|
||||
}
|
||||
tests_need_alpha_cluster () {
|
||||
tests_enabled "parallel-alpha" "serial-alpha"
|
||||
|
@ -352,6 +366,11 @@ configvar CSI_PROW_E2E_ALPHA_GATES "$(get_versioned_variable CSI_PROW_E2E_ALPHA_
|
|||
configvar CSI_PROW_E2E_GATES_LATEST '' "non alpha feature gates for latest Kubernetes"
|
||||
configvar CSI_PROW_E2E_GATES "$(get_versioned_variable CSI_PROW_E2E_GATES "${csi_prow_kubernetes_version_suffix}")" "non alpha E2E feature gates"
|
||||
|
||||
# Focus for local tests run in the sidecar E2E repo. Only used if CSI_PROW_SIDECAR_E2E_IMPORT_PATH
|
||||
# is not set to "none". If empty, all tests in the sidecar repo will be run.
|
||||
configvar CSI_PROW_SIDECAR_E2E_FOCUS '' "tags for local E2E tests"
|
||||
configvar CSI_PROW_SIDECAR_E2E_SKIP '' "local tests that need to be skipped"
|
||||
|
||||
# Which external-snapshotter tag to use for the snapshotter CRD and snapshot-controller deployment
|
||||
default_csi_snapshotter_version () {
|
||||
if [ "${CSI_PROW_KUBERNETES_VERSION}" = "latest" ] || [ "${CSI_PROW_DRIVER_CANARY}" = "canary" ]; then
|
||||
|
@ -368,7 +387,7 @@ configvar CSI_SNAPSHOTTER_VERSION "$(default_csi_snapshotter_version)" "external
|
|||
# whether they can run with the current cluster provider, but until
|
||||
# they are, we filter them out by name. Like the other test selection
|
||||
# variables, this is again a space separated list of regular expressions.
|
||||
configvar CSI_PROW_E2E_SKIP 'Disruptive' "tests that need to be skipped"
|
||||
configvar CSI_PROW_E2E_SKIP '\[Disruptive\]|\[Feature:SELinux\]' "tests that need to be skipped"
|
||||
|
||||
# This creates directories that are required for testing.
|
||||
ensure_paths () {
|
||||
|
@ -406,7 +425,7 @@ die () {
|
|||
exit 1
|
||||
}
|
||||
|
||||
# Ensure that PATH has the desired version of the Go tools, then run command given as argument.
|
||||
# Ensure we use the desired version of the Go tools, then run command given as argument.
|
||||
# Empty parameter uses the already installed Go. In Prow, that version is kept up-to-date by
|
||||
# bumping the container image regularly.
|
||||
run_with_go () {
|
||||
|
@ -414,15 +433,16 @@ run_with_go () {
|
|||
version="$1"
|
||||
shift
|
||||
|
||||
if ! [ "$version" ] || go version 2>/dev/null | grep -q "go$version"; then
|
||||
run "$@"
|
||||
else
|
||||
if ! [ -d "${CSI_PROW_WORK}/go-$version" ]; then
|
||||
run curl --fail --location "https://dl.google.com/go/go$version.linux-amd64.tar.gz" | tar -C "${CSI_PROW_WORK}" -zxf - || die "installation of Go $version failed"
|
||||
mv "${CSI_PROW_WORK}/go" "${CSI_PROW_WORK}/go-$version"
|
||||
if [ "$version" ]; then
|
||||
version=go$version
|
||||
if [ "$(GOTOOLCHAIN=$version go version | cut -d' ' -f3)" != "$version" ]; then
|
||||
die "Please install Go 1.21+"
|
||||
fi
|
||||
PATH="${CSI_PROW_WORK}/go-$version/bin:$PATH" run "$@"
|
||||
else
|
||||
version=local
|
||||
fi
|
||||
# Set GOMODCACHE to make sure Kubernetes does not need to download again.
|
||||
GOTOOLCHAIN=$version GOMODCACHE="$(go env GOMODCACHE)" run "$@"
|
||||
}
|
||||
|
||||
# Ensure that we have the desired version of kind.
|
||||
|
@ -456,7 +476,7 @@ install_dep () {
|
|||
if dep version 2>/dev/null | grep -q "version:.*${CSI_PROW_DEP_VERSION}$"; then
|
||||
return
|
||||
fi
|
||||
run curl --fail --location -o "${CSI_PROW_WORK}/bin/dep" "https://github.com/golang/dep/releases/download/v0.5.4/dep-linux-amd64" &&
|
||||
run curl --fail --location -o "${CSI_PROW_WORK}/bin/dep" "https://github.com/golang/dep/releases/download/${CSI_PROW_DEP_VERSION}/dep-linux-amd64" &&
|
||||
chmod u+x "${CSI_PROW_WORK}/bin/dep"
|
||||
}
|
||||
|
||||
|
@ -548,7 +568,15 @@ go_version_for_kubernetes () (
|
|||
local version="$2"
|
||||
local go_version
|
||||
|
||||
# We use the minimal Go version specified for each K8S release (= minimum_go_version in hack/lib/golang.sh).
|
||||
# Try to get the version for .go-version
|
||||
go_version="$( cat "$path/.go-version" )"
|
||||
if [ "$go_version" ]; then
|
||||
echo "$go_version"
|
||||
return
|
||||
fi
|
||||
|
||||
# Fall back to hack/lib/golang.sh parsing.
|
||||
# This is necessary in v1.26.0 and older Kubernetes releases that do not have .go-version.
|
||||
# More recent versions might also work, but we don't want to count on that.
|
||||
go_version="$(grep minimum_go_version= "$path/hack/lib/golang.sh" | sed -e 's/.*=go//')"
|
||||
if ! [ "$go_version" ]; then
|
||||
|
@ -597,7 +625,7 @@ start_cluster () {
|
|||
go_version="$(go_version_for_kubernetes "${CSI_PROW_WORK}/src/kubernetes" "$version")" || die "cannot proceed without knowing Go version for Kubernetes"
|
||||
# Changing into the Kubernetes source code directory is a workaround for https://github.com/kubernetes-sigs/kind/issues/1910
|
||||
# shellcheck disable=SC2046
|
||||
(cd "${CSI_PROW_WORK}/src/kubernetes" && run_with_go "$go_version" kind build node-image --image csiprow/node:latest --kube-root "${CSI_PROW_WORK}/src/kubernetes") || die "'kind build node-image' failed"
|
||||
(cd "${CSI_PROW_WORK}/src/kubernetes" && run_with_go "$go_version" kind build node-image "${CSI_PROW_WORK}/src/kubernetes" --image csiprow/node:latest) || die "'kind build node-image' failed"
|
||||
csi_prow_kind_have_kubernetes=true
|
||||
fi
|
||||
image="csiprow/node:latest"
|
||||
|
@ -859,10 +887,17 @@ install_snapshot_controller() {
|
|||
cnt=0
|
||||
expected_running_pods=$(kubectl apply --dry-run=client -o "jsonpath={.spec.replicas}" -f "$SNAPSHOT_CONTROLLER_YAML")
|
||||
expected_namespace=$(kubectl apply --dry-run=client -o "jsonpath={.metadata.namespace}" -f "$SNAPSHOT_CONTROLLER_YAML")
|
||||
while [ "$(kubectl get pods -n "$expected_namespace" -l app=snapshot-controller | grep 'Running' -c)" -lt "$expected_running_pods" ]; do
|
||||
expect_key='app\.kubernetes\.io/name'
|
||||
expected_label=$(kubectl apply --dry-run=client -o "jsonpath={.spec.template.metadata.labels['$expect_key']}" -f "$SNAPSHOT_CONTROLLER_YAML")
|
||||
if [ -z "${expected_label}" ]; then
|
||||
expect_key='app'
|
||||
expected_label=$(kubectl apply --dry-run=client -o "jsonpath={.spec.template.metadata.labels['$expect_key']}" -f "$SNAPSHOT_CONTROLLER_YAML")
|
||||
fi
|
||||
expect_key=${expect_key//\\/}
|
||||
while [ "$(kubectl get pods -n "$expected_namespace" -l "$expect_key"="$expected_label" | grep 'Running' -c)" -lt "$expected_running_pods" ]; do
|
||||
if [ $cnt -gt 30 ]; then
|
||||
echo "snapshot-controller pod status:"
|
||||
kubectl describe pods -n "$expected_namespace" -l app=snapshot-controller
|
||||
kubectl describe pods -n "$expected_namespace" -l "$expect_key"="$expected_label"
|
||||
echo >&2 "ERROR: snapshot controller not ready after over 5 min"
|
||||
exit 1
|
||||
fi
|
||||
|
@ -942,6 +977,9 @@ install_e2e () {
|
|||
return
|
||||
fi
|
||||
|
||||
if sidecar_tests_enabled; then
|
||||
run_with_go "${CSI_PROW_GO_VERSION_BUILD}" go test -c -o "${CSI_PROW_WORK}/e2e-local.test" "${CSI_PROW_SIDECAR_E2E_IMPORT_PATH}"
|
||||
fi
|
||||
git_checkout "${CSI_PROW_E2E_REPO}" "${GOPATH}/src/${CSI_PROW_E2E_IMPORT_PATH}" "${CSI_PROW_E2E_VERSION}" --depth=1 &&
|
||||
if [ "${CSI_PROW_E2E_IMPORT_PATH}" = "k8s.io/kubernetes" ]; then
|
||||
patch_kubernetes "${GOPATH}/src/${CSI_PROW_E2E_IMPORT_PATH}" "${CSI_PROW_WORK}" &&
|
||||
|
@ -992,13 +1030,21 @@ run_e2e () (
|
|||
# the full Kubernetes E2E testsuite while only running a few tests.
|
||||
move_junit () {
|
||||
if ls "${ARTIFACTS}"/junit_[0-9]*.xml 2>/dev/null >/dev/null; then
|
||||
run_filter_junit -t="External.Storage|CSI.mock.volume" -o "${ARTIFACTS}/junit_${name}.xml" "${ARTIFACTS}"/junit_[0-9]*.xml && rm -f "${ARTIFACTS}"/junit_[0-9]*.xml
|
||||
mkdir -p "${ARTIFACTS}/junit/${name}" &&
|
||||
mkdir -p "${ARTIFACTS}/junit/steps" &&
|
||||
run_filter_junit -t="External.Storage|CSI.mock.volume" -o "${ARTIFACTS}/junit/steps/junit_${name}.xml" "${ARTIFACTS}"/junit_[0-9]*.xml &&
|
||||
mv "${ARTIFACTS}"/junit_[0-9]*.xml "${ARTIFACTS}/junit/${name}/"
|
||||
fi
|
||||
}
|
||||
trap move_junit EXIT
|
||||
|
||||
cd "${GOPATH}/src/${CSI_PROW_E2E_IMPORT_PATH}" &&
|
||||
run_with_loggers env KUBECONFIG="$KUBECONFIG" KUBE_TEST_REPO_LIST="$(if [ -e "${CSI_PROW_WORK}/e2e-repo-list" ]; then echo "${CSI_PROW_WORK}/e2e-repo-list"; fi)" ginkgo -v "$@" "${CSI_PROW_WORK}/e2e.test" -- -report-dir "${ARTIFACTS}" -storage.testdriver="${CSI_PROW_WORK}/test-driver.yaml"
|
||||
if [ "${name}" == "local" ]; then
|
||||
cd "${GOPATH}/src/${CSI_PROW_SIDECAR_E2E_PATH}" &&
|
||||
run_with_loggers env KUBECONFIG="$KUBECONFIG" KUBE_TEST_REPO_LIST="$(if [ -e "${CSI_PROW_WORK}/e2e-repo-list" ]; then echo "${CSI_PROW_WORK}/e2e-repo-list"; fi)" ginkgo --timeout="${CSI_PROW_GINKGO_TIMEOUT}" -v "$@" "${CSI_PROW_WORK}/e2e-local.test" -- -report-dir "${ARTIFACTS}" -report-prefix local
|
||||
else
|
||||
cd "${GOPATH}/src/${CSI_PROW_E2E_IMPORT_PATH}" &&
|
||||
run_with_loggers env KUBECONFIG="$KUBECONFIG" KUBE_TEST_REPO_LIST="$(if [ -e "${CSI_PROW_WORK}/e2e-repo-list" ]; then echo "${CSI_PROW_WORK}/e2e-repo-list"; fi)" ginkgo --timeout="${CSI_PROW_GINKGO_TIMEOUT}" -v "$@" "${CSI_PROW_WORK}/e2e.test" -- -report-dir "${ARTIFACTS}" -storage.testdriver="${CSI_PROW_WORK}/test-driver.yaml"
|
||||
fi
|
||||
)
|
||||
|
||||
# Run csi-sanity against installed CSI driver.
|
||||
|
@ -1064,13 +1110,14 @@ kubectl exec "$pod" -c "${CSI_PROW_SANITY_CONTAINER}" -- /bin/sh -c "\${CHECK_PA
|
|||
EOF
|
||||
|
||||
chmod u+x "${CSI_PROW_WORK}"/*dir_in_pod.sh
|
||||
mkdir -p "${ARTIFACTS}/junit/steps"
|
||||
|
||||
# This cannot run in parallel, because -csi.junitfile output
|
||||
# from different Ginkgo nodes would go to the same file. Also the
|
||||
# staging and target directories are the same.
|
||||
run_with_loggers "${CSI_PROW_WORK}/csi-sanity" \
|
||||
-ginkgo.v \
|
||||
-csi.junitfile "${ARTIFACTS}/junit_sanity.xml" \
|
||||
-csi.junitfile "${ARTIFACTS}/junit/steps/junit_sanity.xml" \
|
||||
-csi.endpoint "dns:///$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' csi-prow-control-plane):$(kubectl get "services/${CSI_PROW_SANITY_SERVICE}" -o "jsonpath={..nodePort}")" \
|
||||
-csi.stagingdir "/tmp/staging" \
|
||||
-csi.mountdir "/tmp/mount" \
|
||||
|
@ -1100,7 +1147,8 @@ make_test_to_junit () {
|
|||
# Plain make-test.xml was not delivered as text/xml by the web
|
||||
# server and ignored by spyglass. It seems that the name has to
|
||||
# match junit*.xml.
|
||||
out="${ARTIFACTS}/junit_make_test.xml"
|
||||
out="${ARTIFACTS}/junit/steps/junit_make_test.xml"
|
||||
mkdir -p "$(dirname "$out")"
|
||||
testname=
|
||||
echo "<testsuite>" >>"$out"
|
||||
|
||||
|
@ -1284,7 +1332,7 @@ main () {
|
|||
if tests_enabled "parallel"; then
|
||||
# Ignore: Double quote to prevent globbing and word splitting.
|
||||
# shellcheck disable=SC2086
|
||||
if ! run_e2e parallel ${CSI_PROW_GINKO_PARALLEL} \
|
||||
if ! run_e2e parallel ${CSI_PROW_GINKGO_PARALLEL} \
|
||||
-focus="$focus" \
|
||||
-skip="$(regex_join "${CSI_PROW_E2E_SERIAL}" "${CSI_PROW_E2E_ALPHA}" "${CSI_PROW_E2E_SKIP}")"; then
|
||||
warn "E2E parallel failed"
|
||||
|
@ -1294,7 +1342,7 @@ main () {
|
|||
# Run tests that are feature tagged, but non-alpha
|
||||
# Ignore: Double quote to prevent globbing and word splitting.
|
||||
# shellcheck disable=SC2086
|
||||
if ! run_e2e parallel-features ${CSI_PROW_GINKO_PARALLEL} \
|
||||
if ! run_e2e parallel-features ${CSI_PROW_GINKGO_PARALLEL} \
|
||||
-focus="$focus.*($(regex_join "${CSI_PROW_E2E_FOCUS}"))" \
|
||||
-skip="$(regex_join "${CSI_PROW_E2E_SERIAL}")"; then
|
||||
warn "E2E parallel features failed"
|
||||
|
@ -1310,6 +1358,15 @@ main () {
|
|||
ret=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if sidecar_tests_enabled; then
|
||||
if ! run_e2e local \
|
||||
-focus="${CSI_PROW_SIDECAR_E2E_FOCUS}" \
|
||||
-skip="$(regex_join "${CSI_PROW_E2E_SERIAL}")"; then
|
||||
warn "E2E sidecar failed"
|
||||
ret=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
delete_cluster_inside_prow_job non-alpha
|
||||
fi
|
||||
|
@ -1333,7 +1390,7 @@ main () {
|
|||
if tests_enabled "parallel-alpha"; then
|
||||
# Ignore: Double quote to prevent globbing and word splitting.
|
||||
# shellcheck disable=SC2086
|
||||
if ! run_e2e parallel-alpha ${CSI_PROW_GINKO_PARALLEL} \
|
||||
if ! run_e2e parallel-alpha ${CSI_PROW_GINKGO_PARALLEL} \
|
||||
-focus="$focus.*($(regex_join "${CSI_PROW_E2E_ALPHA}"))" \
|
||||
-skip="$(regex_join "${CSI_PROW_E2E_SERIAL}" "${CSI_PROW_E2E_SKIP}")"; then
|
||||
warn "E2E parallel alpha failed"
|
||||
|
@ -1355,8 +1412,8 @@ main () {
|
|||
fi
|
||||
|
||||
# Merge all junit files into one. This gets rid of duplicated "skipped" tests.
|
||||
if ls "${ARTIFACTS}"/junit_*.xml 2>/dev/null >&2; then
|
||||
run_filter_junit -o "${CSI_PROW_WORK}/junit_final.xml" "${ARTIFACTS}"/junit_*.xml && rm "${ARTIFACTS}"/junit_*.xml && mv "${CSI_PROW_WORK}/junit_final.xml" "${ARTIFACTS}"
|
||||
if ls "${ARTIFACTS}"/junit/steps/junit_*.xml 2>/dev/null >&2; then
|
||||
run_filter_junit -o "${ARTIFACTS}/junit_final.xml" "${ARTIFACTS}"/junit/steps/junit_*.xml
|
||||
fi
|
||||
|
||||
return "$ret"
|
||||
|
|
|
@ -20,11 +20,17 @@
|
|||
|
||||
set -ex
|
||||
|
||||
# Prow checks out repos with --filter=blob:none. This breaks
|
||||
# "git subtree pull" unless we enable fetching missing file content.
|
||||
GIT_NO_LAZY_FETCH=0
|
||||
export GIT_NO_LAZY_FETCH
|
||||
|
||||
# It must be called inside the updated csi-release-tools repo.
|
||||
CSI_RELEASE_TOOLS_DIR="$(pwd)"
|
||||
|
||||
# Update the other repo.
|
||||
cd "$PULL_TEST_REPO_DIR"
|
||||
git reset --hard # Shouldn't be necessary, but somehow is to avoid "fatal: working tree has modifications. Cannot add." (https://stackoverflow.com/questions/3623351/git-subtree-pull-says-that-the-working-tree-has-modifications-but-git-status-sa)
|
||||
git subtree pull --squash --prefix=release-tools "$CSI_RELEASE_TOOLS_DIR" master
|
||||
git log -n2
|
||||
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright 2024 The Kubernetes Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# This script uses the logcheck tool to analyze the source code
|
||||
# for proper usage of klog contextual logging.
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
LOGCHECK_VERSION=${1:-0.8.2}
|
||||
|
||||
# This will canonicalize the path
|
||||
CSI_LIB_UTIL_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")"/.. && pwd -P)
|
||||
|
||||
# Create a temporary directory for installing logcheck and
|
||||
# set up a trap command to remove it when the script exits.
|
||||
CSI_LIB_UTIL_TEMP=$(mktemp -d 2>/dev/null || mktemp -d -t csi-lib-utils.XXXXXX)
|
||||
trap 'rm -rf "${CSI_LIB_UTIL_TEMP}"' EXIT
|
||||
|
||||
echo "Installing logcheck to temp dir: sigs.k8s.io/logtools/logcheck@v${LOGCHECK_VERSION}"
|
||||
GOBIN="${CSI_LIB_UTIL_TEMP}" go install "sigs.k8s.io/logtools/logcheck@v${LOGCHECK_VERSION}"
|
||||
echo "Verifying logcheck: ${CSI_LIB_UTIL_TEMP}/logcheck -check-contextual ${CSI_LIB_UTIL_ROOT}/..."
|
||||
"${CSI_LIB_UTIL_TEMP}/logcheck" -check-contextual -check-with-helpers "${CSI_LIB_UTIL_ROOT}/..."
|
|
@ -1,5 +0,0 @@
|
|||
*.sublime-*
|
||||
.DS_Store
|
||||
*.swp
|
||||
*.swo
|
||||
tags
|
|
@ -1,12 +0,0 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- 1.4.x
|
||||
- 1.5.x
|
||||
- 1.6.x
|
||||
- 1.7.x
|
||||
- 1.8.x
|
||||
- 1.9.x
|
||||
- "1.10.x"
|
||||
- "1.11.x"
|
||||
- tip
|
|
@ -1,12 +0,0 @@
|
|||
Copyright (c) 2012, Martin Angers
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,188 +0,0 @@
|
|||
# Purell
|
||||
|
||||
Purell is a tiny Go library to normalize URLs. It returns a pure URL. Pure-ell. Sanitizer and all. Yeah, I know...
|
||||
|
||||
Based on the [wikipedia paper][wiki] and the [RFC 3986 document][rfc].
|
||||
|
||||
[](http://travis-ci.org/PuerkitoBio/purell)
|
||||
|
||||
## Install
|
||||
|
||||
`go get github.com/PuerkitoBio/purell`
|
||||
|
||||
## Changelog
|
||||
|
||||
* **v1.1.1** : Fix failing test due to Go1.12 changes (thanks to @ianlancetaylor).
|
||||
* **2016-11-14 (v1.1.0)** : IDN: Conform to RFC 5895: Fold character width (thanks to @beeker1121).
|
||||
* **2016-07-27 (v1.0.0)** : Normalize IDN to ASCII (thanks to @zenovich).
|
||||
* **2015-02-08** : Add fix for relative paths issue ([PR #5][pr5]) and add fix for unnecessary encoding of reserved characters ([see issue #7][iss7]).
|
||||
* **v0.2.0** : Add benchmarks, Attempt IDN support.
|
||||
* **v0.1.0** : Initial release.
|
||||
|
||||
## Examples
|
||||
|
||||
From `example_test.go` (note that in your code, you would import "github.com/PuerkitoBio/purell", and would prefix references to its methods and constants with "purell."):
|
||||
|
||||
```go
|
||||
package purell
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func ExampleNormalizeURLString() {
|
||||
if normalized, err := NormalizeURLString("hTTp://someWEBsite.com:80/Amazing%3f/url/",
|
||||
FlagLowercaseScheme|FlagLowercaseHost|FlagUppercaseEscapes); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
fmt.Print(normalized)
|
||||
}
|
||||
// Output: http://somewebsite.com:80/Amazing%3F/url/
|
||||
}
|
||||
|
||||
func ExampleMustNormalizeURLString() {
|
||||
normalized := MustNormalizeURLString("hTTpS://someWEBsite.com:443/Amazing%fa/url/",
|
||||
FlagsUnsafeGreedy)
|
||||
fmt.Print(normalized)
|
||||
|
||||
// Output: http://somewebsite.com/Amazing%FA/url
|
||||
}
|
||||
|
||||
func ExampleNormalizeURL() {
|
||||
if u, err := url.Parse("Http://SomeUrl.com:8080/a/b/.././c///g?c=3&a=1&b=9&c=0#target"); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
normalized := NormalizeURL(u, FlagsUsuallySafeGreedy|FlagRemoveDuplicateSlashes|FlagRemoveFragment)
|
||||
fmt.Print(normalized)
|
||||
}
|
||||
|
||||
// Output: http://someurl.com:8080/a/c/g?c=3&a=1&b=9&c=0
|
||||
}
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
As seen in the examples above, purell offers three methods, `NormalizeURLString(string, NormalizationFlags) (string, error)`, `MustNormalizeURLString(string, NormalizationFlags) (string)` and `NormalizeURL(*url.URL, NormalizationFlags) (string)`. They all normalize the provided URL based on the specified flags. Here are the available flags:
|
||||
|
||||
```go
|
||||
const (
|
||||
// Safe normalizations
|
||||
FlagLowercaseScheme NormalizationFlags = 1 << iota // HTTP://host -> http://host, applied by default in Go1.1
|
||||
FlagLowercaseHost // http://HOST -> http://host
|
||||
FlagUppercaseEscapes // http://host/t%ef -> http://host/t%EF
|
||||
FlagDecodeUnnecessaryEscapes // http://host/t%41 -> http://host/tA
|
||||
FlagEncodeNecessaryEscapes // http://host/!"#$ -> http://host/%21%22#$
|
||||
FlagRemoveDefaultPort // http://host:80 -> http://host
|
||||
FlagRemoveEmptyQuerySeparator // http://host/path? -> http://host/path
|
||||
|
||||
// Usually safe normalizations
|
||||
FlagRemoveTrailingSlash // http://host/path/ -> http://host/path
|
||||
FlagAddTrailingSlash // http://host/path -> http://host/path/ (should choose only one of these add/remove trailing slash flags)
|
||||
FlagRemoveDotSegments // http://host/path/./a/b/../c -> http://host/path/a/c
|
||||
|
||||
// Unsafe normalizations
|
||||
FlagRemoveDirectoryIndex // http://host/path/index.html -> http://host/path/
|
||||
FlagRemoveFragment // http://host/path#fragment -> http://host/path
|
||||
FlagForceHTTP // https://host -> http://host
|
||||
FlagRemoveDuplicateSlashes // http://host/path//a///b -> http://host/path/a/b
|
||||
FlagRemoveWWW // http://www.host/ -> http://host/
|
||||
FlagAddWWW // http://host/ -> http://www.host/ (should choose only one of these add/remove WWW flags)
|
||||
FlagSortQuery // http://host/path?c=3&b=2&a=1&b=1 -> http://host/path?a=1&b=1&b=2&c=3
|
||||
|
||||
// Normalizations not in the wikipedia article, required to cover tests cases
|
||||
// submitted by jehiah
|
||||
FlagDecodeDWORDHost // http://1113982867 -> http://66.102.7.147
|
||||
FlagDecodeOctalHost // http://0102.0146.07.0223 -> http://66.102.7.147
|
||||
FlagDecodeHexHost // http://0x42660793 -> http://66.102.7.147
|
||||
FlagRemoveUnnecessaryHostDots // http://.host../path -> http://host/path
|
||||
FlagRemoveEmptyPortSeparator // http://host:/path -> http://host/path
|
||||
|
||||
// Convenience set of safe normalizations
|
||||
FlagsSafe NormalizationFlags = FlagLowercaseHost | FlagLowercaseScheme | FlagUppercaseEscapes | FlagDecodeUnnecessaryEscapes | FlagEncodeNecessaryEscapes | FlagRemoveDefaultPort | FlagRemoveEmptyQuerySeparator
|
||||
|
||||
// For convenience sets, "greedy" uses the "remove trailing slash" and "remove www. prefix" flags,
|
||||
// while "non-greedy" uses the "add (or keep) the trailing slash" and "add www. prefix".
|
||||
|
||||
// Convenience set of usually safe normalizations (includes FlagsSafe)
|
||||
FlagsUsuallySafeGreedy NormalizationFlags = FlagsSafe | FlagRemoveTrailingSlash | FlagRemoveDotSegments
|
||||
FlagsUsuallySafeNonGreedy NormalizationFlags = FlagsSafe | FlagAddTrailingSlash | FlagRemoveDotSegments
|
||||
|
||||
// Convenience set of unsafe normalizations (includes FlagsUsuallySafe)
|
||||
FlagsUnsafeGreedy NormalizationFlags = FlagsUsuallySafeGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagRemoveWWW | FlagSortQuery
|
||||
FlagsUnsafeNonGreedy NormalizationFlags = FlagsUsuallySafeNonGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagAddWWW | FlagSortQuery
|
||||
|
||||
// Convenience set of all available flags
|
||||
FlagsAllGreedy = FlagsUnsafeGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
|
||||
FlagsAllNonGreedy = FlagsUnsafeNonGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
|
||||
)
|
||||
```
|
||||
|
||||
For convenience, the set of flags `FlagsSafe`, `FlagsUsuallySafe[Greedy|NonGreedy]`, `FlagsUnsafe[Greedy|NonGreedy]` and `FlagsAll[Greedy|NonGreedy]` are provided for the similarly grouped normalizations on [wikipedia's URL normalization page][wiki]. You can add (using the bitwise OR `|` operator) or remove (using the bitwise AND NOT `&^` operator) individual flags from the sets if required, to build your own custom set.
|
||||
|
||||
The [full godoc reference is available on gopkgdoc][godoc].
|
||||
|
||||
Some things to note:
|
||||
|
||||
* `FlagDecodeUnnecessaryEscapes`, `FlagEncodeNecessaryEscapes`, `FlagUppercaseEscapes` and `FlagRemoveEmptyQuerySeparator` are always implicitly set, because internally, the URL string is parsed as an URL object, which automatically decodes unnecessary escapes, uppercases and encodes necessary ones, and removes empty query separators (an unnecessary `?` at the end of the url). So this operation cannot **not** be done. For this reason, `FlagRemoveEmptyQuerySeparator` (as well as the other three) has been included in the `FlagsSafe` convenience set, instead of `FlagsUnsafe`, where Wikipedia puts it.
|
||||
|
||||
* The `FlagDecodeUnnecessaryEscapes` decodes the following escapes (*from -> to*):
|
||||
- %24 -> $
|
||||
- %26 -> &
|
||||
- %2B-%3B -> +,-./0123456789:;
|
||||
- %3D -> =
|
||||
- %40-%5A -> @ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
- %5F -> _
|
||||
- %61-%7A -> abcdefghijklmnopqrstuvwxyz
|
||||
- %7E -> ~
|
||||
|
||||
|
||||
* When the `NormalizeURL` function is used (passing an URL object), this source URL object is modified (that is, after the call, the URL object will be modified to reflect the normalization).
|
||||
|
||||
* The *replace IP with domain name* normalization (`http://208.77.188.166/ → http://www.example.com/`) is obviously not possible for a library without making some network requests. This is not implemented in purell.
|
||||
|
||||
* The *remove unused query string parameters* and *remove default query parameters* are also not implemented, since this is a very case-specific normalization, and it is quite trivial to do with an URL object.
|
||||
|
||||
### Safe vs Usually Safe vs Unsafe
|
||||
|
||||
Purell allows you to control the level of risk you take while normalizing an URL. You can aggressively normalize, play it totally safe, or anything in between.
|
||||
|
||||
Consider the following URL:
|
||||
|
||||
`HTTPS://www.RooT.com/toto/t%45%1f///a/./b/../c/?z=3&w=2&a=4&w=1#invalid`
|
||||
|
||||
Normalizing with the `FlagsSafe` gives:
|
||||
|
||||
`https://www.root.com/toto/tE%1F///a/./b/../c/?z=3&w=2&a=4&w=1#invalid`
|
||||
|
||||
With the `FlagsUsuallySafeGreedy`:
|
||||
|
||||
`https://www.root.com/toto/tE%1F///a/c?z=3&w=2&a=4&w=1#invalid`
|
||||
|
||||
And with `FlagsUnsafeGreedy`:
|
||||
|
||||
`http://root.com/toto/tE%1F/a/c?a=4&w=1&w=2&z=3`
|
||||
|
||||
## TODOs
|
||||
|
||||
* Add a class/default instance to allow specifying custom directory index names? At the moment, removing directory index removes `(^|/)((?:default|index)\.\w{1,4})$`.
|
||||
|
||||
## Thanks / Contributions
|
||||
|
||||
@rogpeppe
|
||||
@jehiah
|
||||
@opennota
|
||||
@pchristopher1275
|
||||
@zenovich
|
||||
@beeker1121
|
||||
|
||||
## License
|
||||
|
||||
The [BSD 3-Clause license][bsd].
|
||||
|
||||
[bsd]: http://opensource.org/licenses/BSD-3-Clause
|
||||
[wiki]: http://en.wikipedia.org/wiki/URL_normalization
|
||||
[rfc]: http://tools.ietf.org/html/rfc3986#section-6
|
||||
[godoc]: http://go.pkgdoc.org/github.com/PuerkitoBio/purell
|
||||
[pr5]: https://github.com/PuerkitoBio/purell/pull/5
|
||||
[iss7]: https://github.com/PuerkitoBio/purell/issues/7
|
|
@ -1,379 +0,0 @@
|
|||
/*
|
||||
Package purell offers URL normalization as described on the wikipedia page:
|
||||
http://en.wikipedia.org/wiki/URL_normalization
|
||||
*/
|
||||
package purell
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/PuerkitoBio/urlesc"
|
||||
"golang.org/x/net/idna"
|
||||
"golang.org/x/text/unicode/norm"
|
||||
"golang.org/x/text/width"
|
||||
)
|
||||
|
||||
// A set of normalization flags determines how a URL will
|
||||
// be normalized.
|
||||
type NormalizationFlags uint
|
||||
|
||||
const (
|
||||
// Safe normalizations
|
||||
FlagLowercaseScheme NormalizationFlags = 1 << iota // HTTP://host -> http://host, applied by default in Go1.1
|
||||
FlagLowercaseHost // http://HOST -> http://host
|
||||
FlagUppercaseEscapes // http://host/t%ef -> http://host/t%EF
|
||||
FlagDecodeUnnecessaryEscapes // http://host/t%41 -> http://host/tA
|
||||
FlagEncodeNecessaryEscapes // http://host/!"#$ -> http://host/%21%22#$
|
||||
FlagRemoveDefaultPort // http://host:80 -> http://host
|
||||
FlagRemoveEmptyQuerySeparator // http://host/path? -> http://host/path
|
||||
|
||||
// Usually safe normalizations
|
||||
FlagRemoveTrailingSlash // http://host/path/ -> http://host/path
|
||||
FlagAddTrailingSlash // http://host/path -> http://host/path/ (should choose only one of these add/remove trailing slash flags)
|
||||
FlagRemoveDotSegments // http://host/path/./a/b/../c -> http://host/path/a/c
|
||||
|
||||
// Unsafe normalizations
|
||||
FlagRemoveDirectoryIndex // http://host/path/index.html -> http://host/path/
|
||||
FlagRemoveFragment // http://host/path#fragment -> http://host/path
|
||||
FlagForceHTTP // https://host -> http://host
|
||||
FlagRemoveDuplicateSlashes // http://host/path//a///b -> http://host/path/a/b
|
||||
FlagRemoveWWW // http://www.host/ -> http://host/
|
||||
FlagAddWWW // http://host/ -> http://www.host/ (should choose only one of these add/remove WWW flags)
|
||||
FlagSortQuery // http://host/path?c=3&b=2&a=1&b=1 -> http://host/path?a=1&b=1&b=2&c=3
|
||||
|
||||
// Normalizations not in the wikipedia article, required to cover tests cases
|
||||
// submitted by jehiah
|
||||
FlagDecodeDWORDHost // http://1113982867 -> http://66.102.7.147
|
||||
FlagDecodeOctalHost // http://0102.0146.07.0223 -> http://66.102.7.147
|
||||
FlagDecodeHexHost // http://0x42660793 -> http://66.102.7.147
|
||||
FlagRemoveUnnecessaryHostDots // http://.host../path -> http://host/path
|
||||
FlagRemoveEmptyPortSeparator // http://host:/path -> http://host/path
|
||||
|
||||
// Convenience set of safe normalizations
|
||||
FlagsSafe NormalizationFlags = FlagLowercaseHost | FlagLowercaseScheme | FlagUppercaseEscapes | FlagDecodeUnnecessaryEscapes | FlagEncodeNecessaryEscapes | FlagRemoveDefaultPort | FlagRemoveEmptyQuerySeparator
|
||||
|
||||
// For convenience sets, "greedy" uses the "remove trailing slash" and "remove www. prefix" flags,
|
||||
// while "non-greedy" uses the "add (or keep) the trailing slash" and "add www. prefix".
|
||||
|
||||
// Convenience set of usually safe normalizations (includes FlagsSafe)
|
||||
FlagsUsuallySafeGreedy NormalizationFlags = FlagsSafe | FlagRemoveTrailingSlash | FlagRemoveDotSegments
|
||||
FlagsUsuallySafeNonGreedy NormalizationFlags = FlagsSafe | FlagAddTrailingSlash | FlagRemoveDotSegments
|
||||
|
||||
// Convenience set of unsafe normalizations (includes FlagsUsuallySafe)
|
||||
FlagsUnsafeGreedy NormalizationFlags = FlagsUsuallySafeGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagRemoveWWW | FlagSortQuery
|
||||
FlagsUnsafeNonGreedy NormalizationFlags = FlagsUsuallySafeNonGreedy | FlagRemoveDirectoryIndex | FlagRemoveFragment | FlagForceHTTP | FlagRemoveDuplicateSlashes | FlagAddWWW | FlagSortQuery
|
||||
|
||||
// Convenience set of all available flags
|
||||
FlagsAllGreedy = FlagsUnsafeGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
|
||||
FlagsAllNonGreedy = FlagsUnsafeNonGreedy | FlagDecodeDWORDHost | FlagDecodeOctalHost | FlagDecodeHexHost | FlagRemoveUnnecessaryHostDots | FlagRemoveEmptyPortSeparator
|
||||
)
|
||||
|
||||
const (
|
||||
defaultHttpPort = ":80"
|
||||
defaultHttpsPort = ":443"
|
||||
)
|
||||
|
||||
// Regular expressions used by the normalizations
|
||||
var rxPort = regexp.MustCompile(`(:\d+)/?$`)
|
||||
var rxDirIndex = regexp.MustCompile(`(^|/)((?:default|index)\.\w{1,4})$`)
|
||||
var rxDupSlashes = regexp.MustCompile(`/{2,}`)
|
||||
var rxDWORDHost = regexp.MustCompile(`^(\d+)((?:\.+)?(?:\:\d*)?)$`)
|
||||
var rxOctalHost = regexp.MustCompile(`^(0\d*)\.(0\d*)\.(0\d*)\.(0\d*)((?:\.+)?(?:\:\d*)?)$`)
|
||||
var rxHexHost = regexp.MustCompile(`^0x([0-9A-Fa-f]+)((?:\.+)?(?:\:\d*)?)$`)
|
||||
var rxHostDots = regexp.MustCompile(`^(.+?)(:\d+)?$`)
|
||||
var rxEmptyPort = regexp.MustCompile(`:+$`)
|
||||
|
||||
// Map of flags to implementation function.
|
||||
// FlagDecodeUnnecessaryEscapes has no action, since it is done automatically
|
||||
// by parsing the string as an URL. Same for FlagUppercaseEscapes and FlagRemoveEmptyQuerySeparator.
|
||||
|
||||
// Since maps have undefined traversing order, make a slice of ordered keys
|
||||
var flagsOrder = []NormalizationFlags{
|
||||
FlagLowercaseScheme,
|
||||
FlagLowercaseHost,
|
||||
FlagRemoveDefaultPort,
|
||||
FlagRemoveDirectoryIndex,
|
||||
FlagRemoveDotSegments,
|
||||
FlagRemoveFragment,
|
||||
FlagForceHTTP, // Must be after remove default port (because https=443/http=80)
|
||||
FlagRemoveDuplicateSlashes,
|
||||
FlagRemoveWWW,
|
||||
FlagAddWWW,
|
||||
FlagSortQuery,
|
||||
FlagDecodeDWORDHost,
|
||||
FlagDecodeOctalHost,
|
||||
FlagDecodeHexHost,
|
||||
FlagRemoveUnnecessaryHostDots,
|
||||
FlagRemoveEmptyPortSeparator,
|
||||
FlagRemoveTrailingSlash, // These two (add/remove trailing slash) must be last
|
||||
FlagAddTrailingSlash,
|
||||
}
|
||||
|
||||
// ... and then the map, where order is unimportant
|
||||
var flags = map[NormalizationFlags]func(*url.URL){
|
||||
FlagLowercaseScheme: lowercaseScheme,
|
||||
FlagLowercaseHost: lowercaseHost,
|
||||
FlagRemoveDefaultPort: removeDefaultPort,
|
||||
FlagRemoveDirectoryIndex: removeDirectoryIndex,
|
||||
FlagRemoveDotSegments: removeDotSegments,
|
||||
FlagRemoveFragment: removeFragment,
|
||||
FlagForceHTTP: forceHTTP,
|
||||
FlagRemoveDuplicateSlashes: removeDuplicateSlashes,
|
||||
FlagRemoveWWW: removeWWW,
|
||||
FlagAddWWW: addWWW,
|
||||
FlagSortQuery: sortQuery,
|
||||
FlagDecodeDWORDHost: decodeDWORDHost,
|
||||
FlagDecodeOctalHost: decodeOctalHost,
|
||||
FlagDecodeHexHost: decodeHexHost,
|
||||
FlagRemoveUnnecessaryHostDots: removeUnncessaryHostDots,
|
||||
FlagRemoveEmptyPortSeparator: removeEmptyPortSeparator,
|
||||
FlagRemoveTrailingSlash: removeTrailingSlash,
|
||||
FlagAddTrailingSlash: addTrailingSlash,
|
||||
}
|
||||
|
||||
// MustNormalizeURLString returns the normalized string, and panics if an error occurs.
|
||||
// It takes an URL string as input, as well as the normalization flags.
|
||||
func MustNormalizeURLString(u string, f NormalizationFlags) string {
|
||||
result, e := NormalizeURLString(u, f)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// NormalizeURLString returns the normalized string, or an error if it can't be parsed into an URL object.
|
||||
// It takes an URL string as input, as well as the normalization flags.
|
||||
func NormalizeURLString(u string, f NormalizationFlags) (string, error) {
|
||||
parsed, err := url.Parse(u)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if f&FlagLowercaseHost == FlagLowercaseHost {
|
||||
parsed.Host = strings.ToLower(parsed.Host)
|
||||
}
|
||||
|
||||
// The idna package doesn't fully conform to RFC 5895
|
||||
// (https://tools.ietf.org/html/rfc5895), so we do it here.
|
||||
// Taken from Go 1.8 cycle source, courtesy of bradfitz.
|
||||
// TODO: Remove when (if?) idna package conforms to RFC 5895.
|
||||
parsed.Host = width.Fold.String(parsed.Host)
|
||||
parsed.Host = norm.NFC.String(parsed.Host)
|
||||
if parsed.Host, err = idna.ToASCII(parsed.Host); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return NormalizeURL(parsed, f), nil
|
||||
}
|
||||
|
||||
// NormalizeURL returns the normalized string.
|
||||
// It takes a parsed URL object as input, as well as the normalization flags.
|
||||
func NormalizeURL(u *url.URL, f NormalizationFlags) string {
|
||||
for _, k := range flagsOrder {
|
||||
if f&k == k {
|
||||
flags[k](u)
|
||||
}
|
||||
}
|
||||
return urlesc.Escape(u)
|
||||
}
|
||||
|
||||
func lowercaseScheme(u *url.URL) {
|
||||
if len(u.Scheme) > 0 {
|
||||
u.Scheme = strings.ToLower(u.Scheme)
|
||||
}
|
||||
}
|
||||
|
||||
func lowercaseHost(u *url.URL) {
|
||||
if len(u.Host) > 0 {
|
||||
u.Host = strings.ToLower(u.Host)
|
||||
}
|
||||
}
|
||||
|
||||
func removeDefaultPort(u *url.URL) {
|
||||
if len(u.Host) > 0 {
|
||||
scheme := strings.ToLower(u.Scheme)
|
||||
u.Host = rxPort.ReplaceAllStringFunc(u.Host, func(val string) string {
|
||||
if (scheme == "http" && val == defaultHttpPort) || (scheme == "https" && val == defaultHttpsPort) {
|
||||
return ""
|
||||
}
|
||||
return val
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func removeTrailingSlash(u *url.URL) {
|
||||
if l := len(u.Path); l > 0 {
|
||||
if strings.HasSuffix(u.Path, "/") {
|
||||
u.Path = u.Path[:l-1]
|
||||
}
|
||||
} else if l = len(u.Host); l > 0 {
|
||||
if strings.HasSuffix(u.Host, "/") {
|
||||
u.Host = u.Host[:l-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func addTrailingSlash(u *url.URL) {
|
||||
if l := len(u.Path); l > 0 {
|
||||
if !strings.HasSuffix(u.Path, "/") {
|
||||
u.Path += "/"
|
||||
}
|
||||
} else if l = len(u.Host); l > 0 {
|
||||
if !strings.HasSuffix(u.Host, "/") {
|
||||
u.Host += "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removeDotSegments(u *url.URL) {
|
||||
if len(u.Path) > 0 {
|
||||
var dotFree []string
|
||||
var lastIsDot bool
|
||||
|
||||
sections := strings.Split(u.Path, "/")
|
||||
for _, s := range sections {
|
||||
if s == ".." {
|
||||
if len(dotFree) > 0 {
|
||||
dotFree = dotFree[:len(dotFree)-1]
|
||||
}
|
||||
} else if s != "." {
|
||||
dotFree = append(dotFree, s)
|
||||
}
|
||||
lastIsDot = (s == "." || s == "..")
|
||||
}
|
||||
// Special case if host does not end with / and new path does not begin with /
|
||||
u.Path = strings.Join(dotFree, "/")
|
||||
if u.Host != "" && !strings.HasSuffix(u.Host, "/") && !strings.HasPrefix(u.Path, "/") {
|
||||
u.Path = "/" + u.Path
|
||||
}
|
||||
// Special case if the last segment was a dot, make sure the path ends with a slash
|
||||
if lastIsDot && !strings.HasSuffix(u.Path, "/") {
|
||||
u.Path += "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removeDirectoryIndex(u *url.URL) {
|
||||
if len(u.Path) > 0 {
|
||||
u.Path = rxDirIndex.ReplaceAllString(u.Path, "$1")
|
||||
}
|
||||
}
|
||||
|
||||
func removeFragment(u *url.URL) {
|
||||
u.Fragment = ""
|
||||
}
|
||||
|
||||
func forceHTTP(u *url.URL) {
|
||||
if strings.ToLower(u.Scheme) == "https" {
|
||||
u.Scheme = "http"
|
||||
}
|
||||
}
|
||||
|
||||
func removeDuplicateSlashes(u *url.URL) {
|
||||
if len(u.Path) > 0 {
|
||||
u.Path = rxDupSlashes.ReplaceAllString(u.Path, "/")
|
||||
}
|
||||
}
|
||||
|
||||
func removeWWW(u *url.URL) {
|
||||
if len(u.Host) > 0 && strings.HasPrefix(strings.ToLower(u.Host), "www.") {
|
||||
u.Host = u.Host[4:]
|
||||
}
|
||||
}
|
||||
|
||||
func addWWW(u *url.URL) {
|
||||
if len(u.Host) > 0 && !strings.HasPrefix(strings.ToLower(u.Host), "www.") {
|
||||
u.Host = "www." + u.Host
|
||||
}
|
||||
}
|
||||
|
||||
func sortQuery(u *url.URL) {
|
||||
q := u.Query()
|
||||
|
||||
if len(q) > 0 {
|
||||
arKeys := make([]string, len(q))
|
||||
i := 0
|
||||
for k := range q {
|
||||
arKeys[i] = k
|
||||
i++
|
||||
}
|
||||
sort.Strings(arKeys)
|
||||
buf := new(bytes.Buffer)
|
||||
for _, k := range arKeys {
|
||||
sort.Strings(q[k])
|
||||
for _, v := range q[k] {
|
||||
if buf.Len() > 0 {
|
||||
buf.WriteRune('&')
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf("%s=%s", k, urlesc.QueryEscape(v)))
|
||||
}
|
||||
}
|
||||
|
||||
// Rebuild the raw query string
|
||||
u.RawQuery = buf.String()
|
||||
}
|
||||
}
|
||||
|
||||
func decodeDWORDHost(u *url.URL) {
|
||||
if len(u.Host) > 0 {
|
||||
if matches := rxDWORDHost.FindStringSubmatch(u.Host); len(matches) > 2 {
|
||||
var parts [4]int64
|
||||
|
||||
dword, _ := strconv.ParseInt(matches[1], 10, 0)
|
||||
for i, shift := range []uint{24, 16, 8, 0} {
|
||||
parts[i] = dword >> shift & 0xFF
|
||||
}
|
||||
u.Host = fmt.Sprintf("%d.%d.%d.%d%s", parts[0], parts[1], parts[2], parts[3], matches[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func decodeOctalHost(u *url.URL) {
|
||||
if len(u.Host) > 0 {
|
||||
if matches := rxOctalHost.FindStringSubmatch(u.Host); len(matches) > 5 {
|
||||
var parts [4]int64
|
||||
|
||||
for i := 1; i <= 4; i++ {
|
||||
parts[i-1], _ = strconv.ParseInt(matches[i], 8, 0)
|
||||
}
|
||||
u.Host = fmt.Sprintf("%d.%d.%d.%d%s", parts[0], parts[1], parts[2], parts[3], matches[5])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func decodeHexHost(u *url.URL) {
|
||||
if len(u.Host) > 0 {
|
||||
if matches := rxHexHost.FindStringSubmatch(u.Host); len(matches) > 2 {
|
||||
// Conversion is safe because of regex validation
|
||||
parsed, _ := strconv.ParseInt(matches[1], 16, 0)
|
||||
// Set host as DWORD (base 10) encoded host
|
||||
u.Host = fmt.Sprintf("%d%s", parsed, matches[2])
|
||||
// The rest is the same as decoding a DWORD host
|
||||
decodeDWORDHost(u)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removeUnncessaryHostDots(u *url.URL) {
|
||||
if len(u.Host) > 0 {
|
||||
if matches := rxHostDots.FindStringSubmatch(u.Host); len(matches) > 1 {
|
||||
// Trim the leading and trailing dots
|
||||
u.Host = strings.Trim(matches[1], ".")
|
||||
if len(matches) > 2 {
|
||||
u.Host += matches[2]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removeEmptyPortSeparator(u *url.URL) {
|
||||
if len(u.Host) > 0 {
|
||||
u.Host = rxEmptyPort.ReplaceAllString(u.Host, "")
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- 1.4.x
|
||||
- 1.5.x
|
||||
- 1.6.x
|
||||
- 1.7.x
|
||||
- 1.8.x
|
||||
- tip
|
||||
|
||||
install:
|
||||
- go build .
|
||||
|
||||
script:
|
||||
- go test -v
|
|
@ -1,16 +0,0 @@
|
|||
urlesc [](https://travis-ci.org/PuerkitoBio/urlesc) [](http://godoc.org/github.com/PuerkitoBio/urlesc)
|
||||
======
|
||||
|
||||
Package urlesc implements query escaping as per RFC 3986.
|
||||
|
||||
It contains some parts of the net/url package, modified so as to allow
|
||||
some reserved characters incorrectly escaped by net/url (see [issue 5684](https://github.com/golang/go/issues/5684)).
|
||||
|
||||
## Install
|
||||
|
||||
go get github.com/PuerkitoBio/urlesc
|
||||
|
||||
## License
|
||||
|
||||
Go license (BSD-3-Clause)
|
||||
|
|
@ -1,180 +0,0 @@
|
|||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package urlesc implements query escaping as per RFC 3986.
|
||||
// It contains some parts of the net/url package, modified so as to allow
|
||||
// some reserved characters incorrectly escaped by net/url.
|
||||
// See https://github.com/golang/go/issues/5684
|
||||
package urlesc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type encoding int
|
||||
|
||||
const (
|
||||
encodePath encoding = 1 + iota
|
||||
encodeUserPassword
|
||||
encodeQueryComponent
|
||||
encodeFragment
|
||||
)
|
||||
|
||||
// Return true if the specified character should be escaped when
|
||||
// appearing in a URL string, according to RFC 3986.
|
||||
func shouldEscape(c byte, mode encoding) bool {
|
||||
// §2.3 Unreserved characters (alphanum)
|
||||
if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' {
|
||||
return false
|
||||
}
|
||||
|
||||
switch c {
|
||||
case '-', '.', '_', '~': // §2.3 Unreserved characters (mark)
|
||||
return false
|
||||
|
||||
// §2.2 Reserved characters (reserved)
|
||||
case ':', '/', '?', '#', '[', ']', '@', // gen-delims
|
||||
'!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=': // sub-delims
|
||||
// Different sections of the URL allow a few of
|
||||
// the reserved characters to appear unescaped.
|
||||
switch mode {
|
||||
case encodePath: // §3.3
|
||||
// The RFC allows sub-delims and : @.
|
||||
// '/', '[' and ']' can be used to assign meaning to individual path
|
||||
// segments. This package only manipulates the path as a whole,
|
||||
// so we allow those as well. That leaves only ? and # to escape.
|
||||
return c == '?' || c == '#'
|
||||
|
||||
case encodeUserPassword: // §3.2.1
|
||||
// The RFC allows : and sub-delims in
|
||||
// userinfo. The parsing of userinfo treats ':' as special so we must escape
|
||||
// all the gen-delims.
|
||||
return c == ':' || c == '/' || c == '?' || c == '#' || c == '[' || c == ']' || c == '@'
|
||||
|
||||
case encodeQueryComponent: // §3.4
|
||||
// The RFC allows / and ?.
|
||||
return c != '/' && c != '?'
|
||||
|
||||
case encodeFragment: // §4.1
|
||||
// The RFC text is silent but the grammar allows
|
||||
// everything, so escape nothing but #
|
||||
return c == '#'
|
||||
}
|
||||
}
|
||||
|
||||
// Everything else must be escaped.
|
||||
return true
|
||||
}
|
||||
|
||||
// QueryEscape escapes the string so it can be safely placed
|
||||
// inside a URL query.
|
||||
func QueryEscape(s string) string {
|
||||
return escape(s, encodeQueryComponent)
|
||||
}
|
||||
|
||||
func escape(s string, mode encoding) string {
|
||||
spaceCount, hexCount := 0, 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if shouldEscape(c, mode) {
|
||||
if c == ' ' && mode == encodeQueryComponent {
|
||||
spaceCount++
|
||||
} else {
|
||||
hexCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if spaceCount == 0 && hexCount == 0 {
|
||||
return s
|
||||
}
|
||||
|
||||
t := make([]byte, len(s)+2*hexCount)
|
||||
j := 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
switch c := s[i]; {
|
||||
case c == ' ' && mode == encodeQueryComponent:
|
||||
t[j] = '+'
|
||||
j++
|
||||
case shouldEscape(c, mode):
|
||||
t[j] = '%'
|
||||
t[j+1] = "0123456789ABCDEF"[c>>4]
|
||||
t[j+2] = "0123456789ABCDEF"[c&15]
|
||||
j += 3
|
||||
default:
|
||||
t[j] = s[i]
|
||||
j++
|
||||
}
|
||||
}
|
||||
return string(t)
|
||||
}
|
||||
|
||||
var uiReplacer = strings.NewReplacer(
|
||||
"%21", "!",
|
||||
"%27", "'",
|
||||
"%28", "(",
|
||||
"%29", ")",
|
||||
"%2A", "*",
|
||||
)
|
||||
|
||||
// unescapeUserinfo unescapes some characters that need not to be escaped as per RFC3986.
|
||||
func unescapeUserinfo(s string) string {
|
||||
return uiReplacer.Replace(s)
|
||||
}
|
||||
|
||||
// Escape reassembles the URL into a valid URL string.
|
||||
// The general form of the result is one of:
|
||||
//
|
||||
// scheme:opaque
|
||||
// scheme://userinfo@host/path?query#fragment
|
||||
//
|
||||
// If u.Opaque is non-empty, String uses the first form;
|
||||
// otherwise it uses the second form.
|
||||
//
|
||||
// In the second form, the following rules apply:
|
||||
// - if u.Scheme is empty, scheme: is omitted.
|
||||
// - if u.User is nil, userinfo@ is omitted.
|
||||
// - if u.Host is empty, host/ is omitted.
|
||||
// - if u.Scheme and u.Host are empty and u.User is nil,
|
||||
// the entire scheme://userinfo@host/ is omitted.
|
||||
// - if u.Host is non-empty and u.Path begins with a /,
|
||||
// the form host/path does not add its own /.
|
||||
// - if u.RawQuery is empty, ?query is omitted.
|
||||
// - if u.Fragment is empty, #fragment is omitted.
|
||||
func Escape(u *url.URL) string {
|
||||
var buf bytes.Buffer
|
||||
if u.Scheme != "" {
|
||||
buf.WriteString(u.Scheme)
|
||||
buf.WriteByte(':')
|
||||
}
|
||||
if u.Opaque != "" {
|
||||
buf.WriteString(u.Opaque)
|
||||
} else {
|
||||
if u.Scheme != "" || u.Host != "" || u.User != nil {
|
||||
buf.WriteString("//")
|
||||
if ui := u.User; ui != nil {
|
||||
buf.WriteString(unescapeUserinfo(ui.String()))
|
||||
buf.WriteByte('@')
|
||||
}
|
||||
if h := u.Host; h != "" {
|
||||
buf.WriteString(h)
|
||||
}
|
||||
}
|
||||
if u.Path != "" && u.Path[0] != '/' && u.Host != "" {
|
||||
buf.WriteByte('/')
|
||||
}
|
||||
buf.WriteString(escape(u.Path, encodePath))
|
||||
}
|
||||
if u.RawQuery != "" {
|
||||
buf.WriteByte('?')
|
||||
buf.WriteString(u.RawQuery)
|
||||
}
|
||||
if u.Fragment != "" {
|
||||
buf.WriteByte('#')
|
||||
buf.WriteString(escape(u.Fragment, encodeFragment))
|
||||
}
|
||||
return buf.String()
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
language: go
|
||||
matrix:
|
||||
include:
|
||||
- go: 1.4.3
|
||||
- go: 1.5.4
|
||||
- go: 1.6.3
|
||||
- go: 1.7
|
||||
- go: tip
|
||||
allow_failures:
|
||||
- go: tip
|
||||
install:
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
- go get github.com/mattn/goveralls
|
||||
script:
|
||||
- echo "Test and track coverage" ; $HOME/gopath/bin/goveralls -package "." -service=travis-ci
|
||||
-repotoken $COVERALLS_TOKEN
|
||||
- echo "Build examples" ; cd examples && go build
|
||||
- echo "Check if gofmt'd" ; diff -u <(echo -n) <(gofmt -d -s .)
|
||||
env:
|
||||
global:
|
||||
secure: HroGEAUQpVq9zX1b1VIkraLiywhGbzvNnTZq2TMxgK7JHP8xqNplAeF1izrR2i4QLL9nsY+9WtYss4QuPvEtZcVHUobw6XnL6radF7jS1LgfYZ9Y7oF+zogZ2I5QUMRLGA7rcxQ05s7mKq3XZQfeqaNts4bms/eZRefWuaFZbkw=
|
|
@ -1,194 +0,0 @@
|
|||
semver for golang [](https://travis-ci.org/blang/semver) [](https://godoc.org/github.com/blang/semver) [](https://coveralls.io/r/blang/semver?branch=master)
|
||||
======
|
||||
|
||||
semver is a [Semantic Versioning](http://semver.org/) library written in golang. It fully covers spec version `2.0.0`.
|
||||
|
||||
Usage
|
||||
-----
|
||||
```bash
|
||||
$ go get github.com/blang/semver
|
||||
```
|
||||
Note: Always vendor your dependencies or fix on a specific version tag.
|
||||
|
||||
```go
|
||||
import github.com/blang/semver
|
||||
v1, err := semver.Make("1.0.0-beta")
|
||||
v2, err := semver.Make("2.0.0-beta")
|
||||
v1.Compare(v2)
|
||||
```
|
||||
|
||||
Also check the [GoDocs](http://godoc.org/github.com/blang/semver).
|
||||
|
||||
Why should I use this lib?
|
||||
-----
|
||||
|
||||
- Fully spec compatible
|
||||
- No reflection
|
||||
- No regex
|
||||
- Fully tested (Coverage >99%)
|
||||
- Readable parsing/validation errors
|
||||
- Fast (See [Benchmarks](#benchmarks))
|
||||
- Only Stdlib
|
||||
- Uses values instead of pointers
|
||||
- Many features, see below
|
||||
|
||||
|
||||
Features
|
||||
-----
|
||||
|
||||
- Parsing and validation at all levels
|
||||
- Comparator-like comparisons
|
||||
- Compare Helper Methods
|
||||
- InPlace manipulation
|
||||
- Ranges `>=1.0.0 <2.0.0 || >=3.0.0 !3.0.1-beta.1`
|
||||
- Wildcards `>=1.x`, `<=2.5.x`
|
||||
- Sortable (implements sort.Interface)
|
||||
- database/sql compatible (sql.Scanner/Valuer)
|
||||
- encoding/json compatible (json.Marshaler/Unmarshaler)
|
||||
|
||||
Ranges
|
||||
------
|
||||
|
||||
A `Range` is a set of conditions which specify which versions satisfy the range.
|
||||
|
||||
A condition is composed of an operator and a version. The supported operators are:
|
||||
|
||||
- `<1.0.0` Less than `1.0.0`
|
||||
- `<=1.0.0` Less than or equal to `1.0.0`
|
||||
- `>1.0.0` Greater than `1.0.0`
|
||||
- `>=1.0.0` Greater than or equal to `1.0.0`
|
||||
- `1.0.0`, `=1.0.0`, `==1.0.0` Equal to `1.0.0`
|
||||
- `!1.0.0`, `!=1.0.0` Not equal to `1.0.0`. Excludes version `1.0.0`.
|
||||
|
||||
Note that spaces between the operator and the version will be gracefully tolerated.
|
||||
|
||||
A `Range` can link multiple `Ranges` separated by space:
|
||||
|
||||
Ranges can be linked by logical AND:
|
||||
|
||||
- `>1.0.0 <2.0.0` would match between both ranges, so `1.1.1` and `1.8.7` but not `1.0.0` or `2.0.0`
|
||||
- `>1.0.0 <3.0.0 !2.0.3-beta.2` would match every version between `1.0.0` and `3.0.0` except `2.0.3-beta.2`
|
||||
|
||||
Ranges can also be linked by logical OR:
|
||||
|
||||
- `<2.0.0 || >=3.0.0` would match `1.x.x` and `3.x.x` but not `2.x.x`
|
||||
|
||||
AND has a higher precedence than OR. It's not possible to use brackets.
|
||||
|
||||
Ranges can be combined by both AND and OR
|
||||
|
||||
- `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`, but not `4.2.1`, `2.1.1`
|
||||
|
||||
Range usage:
|
||||
|
||||
```
|
||||
v, err := semver.Parse("1.2.3")
|
||||
range, err := semver.ParseRange(">1.0.0 <2.0.0 || >=3.0.0")
|
||||
if range(v) {
|
||||
//valid
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Example
|
||||
-----
|
||||
|
||||
Have a look at full examples in [examples/main.go](examples/main.go)
|
||||
|
||||
```go
|
||||
import github.com/blang/semver
|
||||
|
||||
v, err := semver.Make("0.0.1-alpha.preview+123.github")
|
||||
fmt.Printf("Major: %d\n", v.Major)
|
||||
fmt.Printf("Minor: %d\n", v.Minor)
|
||||
fmt.Printf("Patch: %d\n", v.Patch)
|
||||
fmt.Printf("Pre: %s\n", v.Pre)
|
||||
fmt.Printf("Build: %s\n", v.Build)
|
||||
|
||||
// Prerelease versions array
|
||||
if len(v.Pre) > 0 {
|
||||
fmt.Println("Prerelease versions:")
|
||||
for i, pre := range v.Pre {
|
||||
fmt.Printf("%d: %q\n", i, pre)
|
||||
}
|
||||
}
|
||||
|
||||
// Build meta data array
|
||||
if len(v.Build) > 0 {
|
||||
fmt.Println("Build meta data:")
|
||||
for i, build := range v.Build {
|
||||
fmt.Printf("%d: %q\n", i, build)
|
||||
}
|
||||
}
|
||||
|
||||
v001, err := semver.Make("0.0.1")
|
||||
// Compare using helpers: v.GT(v2), v.LT, v.GTE, v.LTE
|
||||
v001.GT(v) == true
|
||||
v.LT(v001) == true
|
||||
v.GTE(v) == true
|
||||
v.LTE(v) == true
|
||||
|
||||
// Or use v.Compare(v2) for comparisons (-1, 0, 1):
|
||||
v001.Compare(v) == 1
|
||||
v.Compare(v001) == -1
|
||||
v.Compare(v) == 0
|
||||
|
||||
// Manipulate Version in place:
|
||||
v.Pre[0], err = semver.NewPRVersion("beta")
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing pre release version: %q", err)
|
||||
}
|
||||
|
||||
fmt.Println("\nValidate versions:")
|
||||
v.Build[0] = "?"
|
||||
|
||||
err = v.Validate()
|
||||
if err != nil {
|
||||
fmt.Printf("Validation failed: %s\n", err)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Benchmarks
|
||||
-----
|
||||
|
||||
BenchmarkParseSimple-4 5000000 390 ns/op 48 B/op 1 allocs/op
|
||||
BenchmarkParseComplex-4 1000000 1813 ns/op 256 B/op 7 allocs/op
|
||||
BenchmarkParseAverage-4 1000000 1171 ns/op 163 B/op 4 allocs/op
|
||||
BenchmarkStringSimple-4 20000000 119 ns/op 16 B/op 1 allocs/op
|
||||
BenchmarkStringLarger-4 10000000 206 ns/op 32 B/op 2 allocs/op
|
||||
BenchmarkStringComplex-4 5000000 324 ns/op 80 B/op 3 allocs/op
|
||||
BenchmarkStringAverage-4 5000000 273 ns/op 53 B/op 2 allocs/op
|
||||
BenchmarkValidateSimple-4 200000000 9.33 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkValidateComplex-4 3000000 469 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkValidateAverage-4 5000000 256 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkCompareSimple-4 100000000 11.8 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkCompareComplex-4 50000000 30.8 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkCompareAverage-4 30000000 41.5 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkSort-4 3000000 419 ns/op 256 B/op 2 allocs/op
|
||||
BenchmarkRangeParseSimple-4 2000000 850 ns/op 192 B/op 5 allocs/op
|
||||
BenchmarkRangeParseAverage-4 1000000 1677 ns/op 400 B/op 10 allocs/op
|
||||
BenchmarkRangeParseComplex-4 300000 5214 ns/op 1440 B/op 30 allocs/op
|
||||
BenchmarkRangeMatchSimple-4 50000000 25.6 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkRangeMatchAverage-4 30000000 56.4 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkRangeMatchComplex-4 10000000 153 ns/op 0 B/op 0 allocs/op
|
||||
|
||||
See benchmark cases at [semver_test.go](semver_test.go)
|
||||
|
||||
|
||||
Motivation
|
||||
-----
|
||||
|
||||
I simply couldn't find any lib supporting the full spec. Others were just wrong or used reflection and regex which i don't like.
|
||||
|
||||
|
||||
Contribution
|
||||
-----
|
||||
|
||||
Feel free to make a pull request. For bigger changes create a issue first to discuss about it.
|
||||
|
||||
|
||||
License
|
||||
-----
|
||||
|
||||
See [LICENSE](LICENSE) file.
|
|
@ -1,17 +0,0 @@
|
|||
{
|
||||
"author": "blang",
|
||||
"bugs": {
|
||||
"URL": "https://github.com/blang/semver/issues",
|
||||
"url": "https://github.com/blang/semver/issues"
|
||||
},
|
||||
"gx": {
|
||||
"dvcsimport": "github.com/blang/semver"
|
||||
},
|
||||
"gxVersion": "0.10.0",
|
||||
"language": "go",
|
||||
"license": "MIT",
|
||||
"name": "semver",
|
||||
"releaseCmd": "git commit -a -m \"gx publish $VERSION\"",
|
||||
"version": "3.5.1"
|
||||
}
|
||||
|
0
vendor/github.com/blang/semver/LICENSE → vendor/github.com/blang/semver/v4/LICENSE
generated
vendored
0
vendor/github.com/blang/semver/LICENSE → vendor/github.com/blang/semver/v4/LICENSE
generated
vendored
0
vendor/github.com/blang/semver/json.go → vendor/github.com/blang/semver/v4/json.go
generated
vendored
0
vendor/github.com/blang/semver/json.go → vendor/github.com/blang/semver/v4/json.go
generated
vendored
2
vendor/github.com/blang/semver/range.go → vendor/github.com/blang/semver/v4/range.go
generated
vendored
2
vendor/github.com/blang/semver/range.go → vendor/github.com/blang/semver/v4/range.go
generated
vendored
|
@ -327,7 +327,7 @@ func expandWildcardVersion(parts [][]string) ([][]string, error) {
|
|||
for _, p := range parts {
|
||||
var newParts []string
|
||||
for _, ap := range p {
|
||||
if strings.Index(ap, "x") != -1 {
|
||||
if strings.Contains(ap, "x") {
|
||||
opStr, vStr, err := splitComparatorVersion(ap)
|
||||
if err != nil {
|
||||
return nil, err
|
72
vendor/github.com/blang/semver/semver.go → vendor/github.com/blang/semver/v4/semver.go
generated
vendored
72
vendor/github.com/blang/semver/semver.go → vendor/github.com/blang/semver/v4/semver.go
generated
vendored
|
@ -26,7 +26,7 @@ type Version struct {
|
|||
Minor uint64
|
||||
Patch uint64
|
||||
Pre []PRVersion
|
||||
Build []string //No Precendence
|
||||
Build []string //No Precedence
|
||||
}
|
||||
|
||||
// Version to string
|
||||
|
@ -61,6 +61,18 @@ func (v Version) String() string {
|
|||
return string(b)
|
||||
}
|
||||
|
||||
// FinalizeVersion discards prerelease and build number and only returns
|
||||
// major, minor and patch number.
|
||||
func (v Version) FinalizeVersion() string {
|
||||
b := make([]byte, 0, 5)
|
||||
b = strconv.AppendUint(b, v.Major, 10)
|
||||
b = append(b, '.')
|
||||
b = strconv.AppendUint(b, v.Minor, 10)
|
||||
b = append(b, '.')
|
||||
b = strconv.AppendUint(b, v.Patch, 10)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// Equals checks if v is equal to o.
|
||||
func (v Version) Equals(o Version) bool {
|
||||
return (v.Compare(o) == 0)
|
||||
|
@ -161,6 +173,27 @@ func (v Version) Compare(o Version) int {
|
|||
|
||||
}
|
||||
|
||||
// IncrementPatch increments the patch version
|
||||
func (v *Version) IncrementPatch() error {
|
||||
v.Patch++
|
||||
return nil
|
||||
}
|
||||
|
||||
// IncrementMinor increments the minor version
|
||||
func (v *Version) IncrementMinor() error {
|
||||
v.Minor++
|
||||
v.Patch = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
// IncrementMajor increments the major version
|
||||
func (v *Version) IncrementMajor() error {
|
||||
v.Major++
|
||||
v.Minor = 0
|
||||
v.Patch = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate validates v and returns error in case
|
||||
func (v Version) Validate() error {
|
||||
// Major, Minor, Patch already validated using uint64
|
||||
|
@ -189,10 +222,10 @@ func (v Version) Validate() error {
|
|||
}
|
||||
|
||||
// New is an alias for Parse and returns a pointer, parses version string and returns a validated Version or error
|
||||
func New(s string) (vp *Version, err error) {
|
||||
func New(s string) (*Version, error) {
|
||||
v, err := Parse(s)
|
||||
vp = &v
|
||||
return
|
||||
vp := &v
|
||||
return vp, err
|
||||
}
|
||||
|
||||
// Make is an alias for Parse, parses version string and returns a validated Version or error
|
||||
|
@ -202,14 +235,25 @@ func Make(s string) (Version, error) {
|
|||
|
||||
// ParseTolerant allows for certain version specifications that do not strictly adhere to semver
|
||||
// specs to be parsed by this library. It does so by normalizing versions before passing them to
|
||||
// Parse(). It currently trims spaces, removes a "v" prefix, and adds a 0 patch number to versions
|
||||
// with only major and minor components specified
|
||||
// Parse(). It currently trims spaces, removes a "v" prefix, adds a 0 patch number to versions
|
||||
// with only major and minor components specified, and removes leading 0s.
|
||||
func ParseTolerant(s string) (Version, error) {
|
||||
s = strings.TrimSpace(s)
|
||||
s = strings.TrimPrefix(s, "v")
|
||||
|
||||
// Split into major.minor.(patch+pr+meta)
|
||||
parts := strings.SplitN(s, ".", 3)
|
||||
// Remove leading zeros.
|
||||
for i, p := range parts {
|
||||
if len(p) > 1 {
|
||||
p = strings.TrimLeft(p, "0")
|
||||
if len(p) == 0 || !strings.ContainsAny(p[0:1], "0123456789") {
|
||||
p = "0" + p
|
||||
}
|
||||
parts[i] = p
|
||||
}
|
||||
}
|
||||
// Fill up shortened versions.
|
||||
if len(parts) < 3 {
|
||||
if strings.ContainsAny(parts[len(parts)-1], "+-") {
|
||||
return Version{}, errors.New("Short version cannot contain PreRelease/Build meta data")
|
||||
|
@ -217,8 +261,8 @@ func ParseTolerant(s string) (Version, error) {
|
|||
for len(parts) < 3 {
|
||||
parts = append(parts, "0")
|
||||
}
|
||||
s = strings.Join(parts, ".")
|
||||
}
|
||||
s = strings.Join(parts, ".")
|
||||
|
||||
return Parse(s)
|
||||
}
|
||||
|
@ -416,3 +460,17 @@ func NewBuildVersion(s string) (string, error) {
|
|||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// FinalizeVersion returns the major, minor and patch number only and discards
|
||||
// prerelease and build number.
|
||||
func FinalizeVersion(s string) (string, error) {
|
||||
v, err := Parse(s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
v.Pre = nil
|
||||
v.Build = nil
|
||||
|
||||
finalVer := v.String()
|
||||
return finalVer, nil
|
||||
}
|
0
vendor/github.com/blang/semver/sort.go → vendor/github.com/blang/semver/v4/sort.go
generated
vendored
0
vendor/github.com/blang/semver/sort.go → vendor/github.com/blang/semver/v4/sort.go
generated
vendored
2
vendor/github.com/blang/semver/sql.go → vendor/github.com/blang/semver/v4/sql.go
generated
vendored
2
vendor/github.com/blang/semver/sql.go → vendor/github.com/blang/semver/v4/sql.go
generated
vendored
|
@ -14,7 +14,7 @@ func (v *Version) Scan(src interface{}) (err error) {
|
|||
case []byte:
|
||||
str = string(src)
|
||||
default:
|
||||
return fmt.Errorf("Version.Scan: cannot convert %T to string.", src)
|
||||
return fmt.Errorf("version.Scan: cannot convert %T to string", src)
|
||||
}
|
||||
|
||||
if t, err := Parse(str); err == nil {
|
|
@ -1,8 +0,0 @@
|
|||
language: go
|
||||
go:
|
||||
- "1.x"
|
||||
- master
|
||||
env:
|
||||
- TAGS=""
|
||||
- TAGS="-tags purego"
|
||||
script: go test $TAGS -v ./...
|
|
@ -1,10 +1,9 @@
|
|||
# xxhash
|
||||
|
||||
[](https://godoc.org/github.com/cespare/xxhash)
|
||||
[](https://travis-ci.org/cespare/xxhash)
|
||||
[](https://pkg.go.dev/github.com/cespare/xxhash/v2)
|
||||
[](https://github.com/cespare/xxhash/actions/workflows/test.yml)
|
||||
|
||||
xxhash is a Go implementation of the 64-bit
|
||||
[xxHash](http://cyan4973.github.io/xxHash/) algorithm, XXH64. This is a
|
||||
xxhash is a Go implementation of the 64-bit [xxHash] algorithm, XXH64. This is a
|
||||
high-quality hashing algorithm that is much faster than anything in the Go
|
||||
standard library.
|
||||
|
||||
|
@ -25,8 +24,11 @@ func (*Digest) WriteString(string) (int, error)
|
|||
func (*Digest) Sum64() uint64
|
||||
```
|
||||
|
||||
This implementation provides a fast pure-Go implementation and an even faster
|
||||
assembly implementation for amd64.
|
||||
The package is written with optimized pure Go and also contains even faster
|
||||
assembly implementations for amd64 and arm64. If desired, the `purego` build tag
|
||||
opts into using the Go code even on those architectures.
|
||||
|
||||
[xxHash]: http://cyan4973.github.io/xxHash/
|
||||
|
||||
## Compatibility
|
||||
|
||||
|
@ -45,23 +47,28 @@ I recommend using the latest release of Go.
|
|||
Here are some quick benchmarks comparing the pure-Go and assembly
|
||||
implementations of Sum64.
|
||||
|
||||
| input size | purego | asm |
|
||||
| --- | --- | --- |
|
||||
| 5 B | 979.66 MB/s | 1291.17 MB/s |
|
||||
| 100 B | 7475.26 MB/s | 7973.40 MB/s |
|
||||
| 4 KB | 17573.46 MB/s | 17602.65 MB/s |
|
||||
| 10 MB | 17131.46 MB/s | 17142.16 MB/s |
|
||||
| input size | purego | asm |
|
||||
| ---------- | --------- | --------- |
|
||||
| 4 B | 1.3 GB/s | 1.2 GB/s |
|
||||
| 16 B | 2.9 GB/s | 3.5 GB/s |
|
||||
| 100 B | 6.9 GB/s | 8.1 GB/s |
|
||||
| 4 KB | 11.7 GB/s | 16.7 GB/s |
|
||||
| 10 MB | 12.0 GB/s | 17.3 GB/s |
|
||||
|
||||
These numbers were generated on Ubuntu 18.04 with an Intel i7-8700K CPU using
|
||||
the following commands under Go 1.11.2:
|
||||
These numbers were generated on Ubuntu 20.04 with an Intel Xeon Platinum 8252C
|
||||
CPU using the following commands under Go 1.19.2:
|
||||
|
||||
```
|
||||
$ go test -tags purego -benchtime 10s -bench '/xxhash,direct,bytes'
|
||||
$ go test -benchtime 10s -bench '/xxhash,direct,bytes'
|
||||
benchstat <(go test -tags purego -benchtime 500ms -count 15 -bench 'Sum64$')
|
||||
benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$')
|
||||
```
|
||||
|
||||
## Projects using this package
|
||||
|
||||
- [InfluxDB](https://github.com/influxdata/influxdb)
|
||||
- [Prometheus](https://github.com/prometheus/prometheus)
|
||||
- [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics)
|
||||
- [FreeCache](https://github.com/coocood/freecache)
|
||||
- [FastCache](https://github.com/VictoriaMetrics/fastcache)
|
||||
- [Ristretto](https://github.com/dgraph-io/ristretto)
|
||||
- [Badger](https://github.com/dgraph-io/badger)
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
set -eu -o pipefail
|
||||
|
||||
# Small convenience script for running the tests with various combinations of
|
||||
# arch/tags. This assumes we're running on amd64 and have qemu available.
|
||||
|
||||
go test ./...
|
||||
go test -tags purego ./...
|
||||
GOARCH=arm64 go test
|
||||
GOARCH=arm64 go test -tags purego
|
|
@ -16,21 +16,16 @@ const (
|
|||
prime5 uint64 = 2870177450012600261
|
||||
)
|
||||
|
||||
// NOTE(caleb): I'm using both consts and vars of the primes. Using consts where
|
||||
// possible in the Go code is worth a small (but measurable) performance boost
|
||||
// by avoiding some MOVQs. Vars are needed for the asm and also are useful for
|
||||
// convenience in the Go code in a few places where we need to intentionally
|
||||
// avoid constant arithmetic (e.g., v1 := prime1 + prime2 fails because the
|
||||
// result overflows a uint64).
|
||||
var (
|
||||
prime1v = prime1
|
||||
prime2v = prime2
|
||||
prime3v = prime3
|
||||
prime4v = prime4
|
||||
prime5v = prime5
|
||||
)
|
||||
// Store the primes in an array as well.
|
||||
//
|
||||
// The consts are used when possible in Go code to avoid MOVs but we need a
|
||||
// contiguous array for the assembly code.
|
||||
var primes = [...]uint64{prime1, prime2, prime3, prime4, prime5}
|
||||
|
||||
// Digest implements hash.Hash64.
|
||||
//
|
||||
// Note that a zero-valued Digest is not ready to receive writes.
|
||||
// Call Reset or create a Digest using New before calling other methods.
|
||||
type Digest struct {
|
||||
v1 uint64
|
||||
v2 uint64
|
||||
|
@ -41,19 +36,31 @@ type Digest struct {
|
|||
n int // how much of mem is used
|
||||
}
|
||||
|
||||
// New creates a new Digest that computes the 64-bit xxHash algorithm.
|
||||
// New creates a new Digest with a zero seed.
|
||||
func New() *Digest {
|
||||
return NewWithSeed(0)
|
||||
}
|
||||
|
||||
// NewWithSeed creates a new Digest with the given seed.
|
||||
func NewWithSeed(seed uint64) *Digest {
|
||||
var d Digest
|
||||
d.Reset()
|
||||
d.ResetWithSeed(seed)
|
||||
return &d
|
||||
}
|
||||
|
||||
// Reset clears the Digest's state so that it can be reused.
|
||||
// It uses a seed value of zero.
|
||||
func (d *Digest) Reset() {
|
||||
d.v1 = prime1v + prime2
|
||||
d.v2 = prime2
|
||||
d.v3 = 0
|
||||
d.v4 = -prime1v
|
||||
d.ResetWithSeed(0)
|
||||
}
|
||||
|
||||
// ResetWithSeed clears the Digest's state so that it can be reused.
|
||||
// It uses the given seed to initialize the state.
|
||||
func (d *Digest) ResetWithSeed(seed uint64) {
|
||||
d.v1 = seed + prime1 + prime2
|
||||
d.v2 = seed + prime2
|
||||
d.v3 = seed
|
||||
d.v4 = seed - prime1
|
||||
d.total = 0
|
||||
d.n = 0
|
||||
}
|
||||
|
@ -69,21 +76,23 @@ func (d *Digest) Write(b []byte) (n int, err error) {
|
|||
n = len(b)
|
||||
d.total += uint64(n)
|
||||
|
||||
memleft := d.mem[d.n&(len(d.mem)-1):]
|
||||
|
||||
if d.n+n < 32 {
|
||||
// This new data doesn't even fill the current block.
|
||||
copy(d.mem[d.n:], b)
|
||||
copy(memleft, b)
|
||||
d.n += n
|
||||
return
|
||||
}
|
||||
|
||||
if d.n > 0 {
|
||||
// Finish off the partial block.
|
||||
copy(d.mem[d.n:], b)
|
||||
c := copy(memleft, b)
|
||||
d.v1 = round(d.v1, u64(d.mem[0:8]))
|
||||
d.v2 = round(d.v2, u64(d.mem[8:16]))
|
||||
d.v3 = round(d.v3, u64(d.mem[16:24]))
|
||||
d.v4 = round(d.v4, u64(d.mem[24:32]))
|
||||
b = b[32-d.n:]
|
||||
b = b[c:]
|
||||
d.n = 0
|
||||
}
|
||||
|
||||
|
@ -133,21 +142,20 @@ func (d *Digest) Sum64() uint64 {
|
|||
|
||||
h += d.total
|
||||
|
||||
i, end := 0, d.n
|
||||
for ; i+8 <= end; i += 8 {
|
||||
k1 := round(0, u64(d.mem[i:i+8]))
|
||||
b := d.mem[:d.n&(len(d.mem)-1)]
|
||||
for ; len(b) >= 8; b = b[8:] {
|
||||
k1 := round(0, u64(b[:8]))
|
||||
h ^= k1
|
||||
h = rol27(h)*prime1 + prime4
|
||||
}
|
||||
if i+4 <= end {
|
||||
h ^= uint64(u32(d.mem[i:i+4])) * prime1
|
||||
if len(b) >= 4 {
|
||||
h ^= uint64(u32(b[:4])) * prime1
|
||||
h = rol23(h)*prime2 + prime3
|
||||
i += 4
|
||||
b = b[4:]
|
||||
}
|
||||
for i < end {
|
||||
h ^= uint64(d.mem[i]) * prime5
|
||||
for ; len(b) > 0; b = b[1:] {
|
||||
h ^= uint64(b[0]) * prime5
|
||||
h = rol11(h) * prime1
|
||||
i++
|
||||
}
|
||||
|
||||
h ^= h >> 33
|
||||
|
@ -193,7 +201,6 @@ func (d *Digest) UnmarshalBinary(b []byte) error {
|
|||
b, d.v4 = consumeUint64(b)
|
||||
b, d.total = consumeUint64(b)
|
||||
copy(d.mem[:], b)
|
||||
b = b[len(d.mem):]
|
||||
d.n = int(d.total % uint64(len(d.mem)))
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,215 +1,209 @@
|
|||
//go:build !appengine && gc && !purego
|
||||
// +build !appengine
|
||||
// +build gc
|
||||
// +build !purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// Register allocation:
|
||||
// AX h
|
||||
// CX pointer to advance through b
|
||||
// DX n
|
||||
// BX loop end
|
||||
// R8 v1, k1
|
||||
// R9 v2
|
||||
// R10 v3
|
||||
// R11 v4
|
||||
// R12 tmp
|
||||
// R13 prime1v
|
||||
// R14 prime2v
|
||||
// R15 prime4v
|
||||
// Registers:
|
||||
#define h AX
|
||||
#define d AX
|
||||
#define p SI // pointer to advance through b
|
||||
#define n DX
|
||||
#define end BX // loop end
|
||||
#define v1 R8
|
||||
#define v2 R9
|
||||
#define v3 R10
|
||||
#define v4 R11
|
||||
#define x R12
|
||||
#define prime1 R13
|
||||
#define prime2 R14
|
||||
#define prime4 DI
|
||||
|
||||
// round reads from and advances the buffer pointer in CX.
|
||||
// It assumes that R13 has prime1v and R14 has prime2v.
|
||||
#define round(r) \
|
||||
MOVQ (CX), R12 \
|
||||
ADDQ $8, CX \
|
||||
IMULQ R14, R12 \
|
||||
ADDQ R12, r \
|
||||
ROLQ $31, r \
|
||||
IMULQ R13, r
|
||||
#define round(acc, x) \
|
||||
IMULQ prime2, x \
|
||||
ADDQ x, acc \
|
||||
ROLQ $31, acc \
|
||||
IMULQ prime1, acc
|
||||
|
||||
// mergeRound applies a merge round on the two registers acc and val.
|
||||
// It assumes that R13 has prime1v, R14 has prime2v, and R15 has prime4v.
|
||||
#define mergeRound(acc, val) \
|
||||
IMULQ R14, val \
|
||||
ROLQ $31, val \
|
||||
IMULQ R13, val \
|
||||
XORQ val, acc \
|
||||
IMULQ R13, acc \
|
||||
ADDQ R15, acc
|
||||
// round0 performs the operation x = round(0, x).
|
||||
#define round0(x) \
|
||||
IMULQ prime2, x \
|
||||
ROLQ $31, x \
|
||||
IMULQ prime1, x
|
||||
|
||||
// mergeRound applies a merge round on the two registers acc and x.
|
||||
// It assumes that prime1, prime2, and prime4 have been loaded.
|
||||
#define mergeRound(acc, x) \
|
||||
round0(x) \
|
||||
XORQ x, acc \
|
||||
IMULQ prime1, acc \
|
||||
ADDQ prime4, acc
|
||||
|
||||
// blockLoop processes as many 32-byte blocks as possible,
|
||||
// updating v1, v2, v3, and v4. It assumes that there is at least one block
|
||||
// to process.
|
||||
#define blockLoop() \
|
||||
loop: \
|
||||
MOVQ +0(p), x \
|
||||
round(v1, x) \
|
||||
MOVQ +8(p), x \
|
||||
round(v2, x) \
|
||||
MOVQ +16(p), x \
|
||||
round(v3, x) \
|
||||
MOVQ +24(p), x \
|
||||
round(v4, x) \
|
||||
ADDQ $32, p \
|
||||
CMPQ p, end \
|
||||
JLE loop
|
||||
|
||||
// func Sum64(b []byte) uint64
|
||||
TEXT ·Sum64(SB), NOSPLIT, $0-32
|
||||
TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32
|
||||
// Load fixed primes.
|
||||
MOVQ ·prime1v(SB), R13
|
||||
MOVQ ·prime2v(SB), R14
|
||||
MOVQ ·prime4v(SB), R15
|
||||
MOVQ ·primes+0(SB), prime1
|
||||
MOVQ ·primes+8(SB), prime2
|
||||
MOVQ ·primes+24(SB), prime4
|
||||
|
||||
// Load slice.
|
||||
MOVQ b_base+0(FP), CX
|
||||
MOVQ b_len+8(FP), DX
|
||||
LEAQ (CX)(DX*1), BX
|
||||
MOVQ b_base+0(FP), p
|
||||
MOVQ b_len+8(FP), n
|
||||
LEAQ (p)(n*1), end
|
||||
|
||||
// The first loop limit will be len(b)-32.
|
||||
SUBQ $32, BX
|
||||
SUBQ $32, end
|
||||
|
||||
// Check whether we have at least one block.
|
||||
CMPQ DX, $32
|
||||
CMPQ n, $32
|
||||
JLT noBlocks
|
||||
|
||||
// Set up initial state (v1, v2, v3, v4).
|
||||
MOVQ R13, R8
|
||||
ADDQ R14, R8
|
||||
MOVQ R14, R9
|
||||
XORQ R10, R10
|
||||
XORQ R11, R11
|
||||
SUBQ R13, R11
|
||||
MOVQ prime1, v1
|
||||
ADDQ prime2, v1
|
||||
MOVQ prime2, v2
|
||||
XORQ v3, v3
|
||||
XORQ v4, v4
|
||||
SUBQ prime1, v4
|
||||
|
||||
// Loop until CX > BX.
|
||||
blockLoop:
|
||||
round(R8)
|
||||
round(R9)
|
||||
round(R10)
|
||||
round(R11)
|
||||
blockLoop()
|
||||
|
||||
CMPQ CX, BX
|
||||
JLE blockLoop
|
||||
MOVQ v1, h
|
||||
ROLQ $1, h
|
||||
MOVQ v2, x
|
||||
ROLQ $7, x
|
||||
ADDQ x, h
|
||||
MOVQ v3, x
|
||||
ROLQ $12, x
|
||||
ADDQ x, h
|
||||
MOVQ v4, x
|
||||
ROLQ $18, x
|
||||
ADDQ x, h
|
||||
|
||||
MOVQ R8, AX
|
||||
ROLQ $1, AX
|
||||
MOVQ R9, R12
|
||||
ROLQ $7, R12
|
||||
ADDQ R12, AX
|
||||
MOVQ R10, R12
|
||||
ROLQ $12, R12
|
||||
ADDQ R12, AX
|
||||
MOVQ R11, R12
|
||||
ROLQ $18, R12
|
||||
ADDQ R12, AX
|
||||
|
||||
mergeRound(AX, R8)
|
||||
mergeRound(AX, R9)
|
||||
mergeRound(AX, R10)
|
||||
mergeRound(AX, R11)
|
||||
mergeRound(h, v1)
|
||||
mergeRound(h, v2)
|
||||
mergeRound(h, v3)
|
||||
mergeRound(h, v4)
|
||||
|
||||
JMP afterBlocks
|
||||
|
||||
noBlocks:
|
||||
MOVQ ·prime5v(SB), AX
|
||||
MOVQ ·primes+32(SB), h
|
||||
|
||||
afterBlocks:
|
||||
ADDQ DX, AX
|
||||
ADDQ n, h
|
||||
|
||||
// Right now BX has len(b)-32, and we want to loop until CX > len(b)-8.
|
||||
ADDQ $24, BX
|
||||
ADDQ $24, end
|
||||
CMPQ p, end
|
||||
JG try4
|
||||
|
||||
CMPQ CX, BX
|
||||
JG fourByte
|
||||
loop8:
|
||||
MOVQ (p), x
|
||||
ADDQ $8, p
|
||||
round0(x)
|
||||
XORQ x, h
|
||||
ROLQ $27, h
|
||||
IMULQ prime1, h
|
||||
ADDQ prime4, h
|
||||
|
||||
wordLoop:
|
||||
// Calculate k1.
|
||||
MOVQ (CX), R8
|
||||
ADDQ $8, CX
|
||||
IMULQ R14, R8
|
||||
ROLQ $31, R8
|
||||
IMULQ R13, R8
|
||||
CMPQ p, end
|
||||
JLE loop8
|
||||
|
||||
XORQ R8, AX
|
||||
ROLQ $27, AX
|
||||
IMULQ R13, AX
|
||||
ADDQ R15, AX
|
||||
try4:
|
||||
ADDQ $4, end
|
||||
CMPQ p, end
|
||||
JG try1
|
||||
|
||||
CMPQ CX, BX
|
||||
JLE wordLoop
|
||||
MOVL (p), x
|
||||
ADDQ $4, p
|
||||
IMULQ prime1, x
|
||||
XORQ x, h
|
||||
|
||||
fourByte:
|
||||
ADDQ $4, BX
|
||||
CMPQ CX, BX
|
||||
JG singles
|
||||
ROLQ $23, h
|
||||
IMULQ prime2, h
|
||||
ADDQ ·primes+16(SB), h
|
||||
|
||||
MOVL (CX), R8
|
||||
ADDQ $4, CX
|
||||
IMULQ R13, R8
|
||||
XORQ R8, AX
|
||||
|
||||
ROLQ $23, AX
|
||||
IMULQ R14, AX
|
||||
ADDQ ·prime3v(SB), AX
|
||||
|
||||
singles:
|
||||
ADDQ $4, BX
|
||||
CMPQ CX, BX
|
||||
try1:
|
||||
ADDQ $4, end
|
||||
CMPQ p, end
|
||||
JGE finalize
|
||||
|
||||
singlesLoop:
|
||||
MOVBQZX (CX), R12
|
||||
ADDQ $1, CX
|
||||
IMULQ ·prime5v(SB), R12
|
||||
XORQ R12, AX
|
||||
loop1:
|
||||
MOVBQZX (p), x
|
||||
ADDQ $1, p
|
||||
IMULQ ·primes+32(SB), x
|
||||
XORQ x, h
|
||||
ROLQ $11, h
|
||||
IMULQ prime1, h
|
||||
|
||||
ROLQ $11, AX
|
||||
IMULQ R13, AX
|
||||
|
||||
CMPQ CX, BX
|
||||
JL singlesLoop
|
||||
CMPQ p, end
|
||||
JL loop1
|
||||
|
||||
finalize:
|
||||
MOVQ AX, R12
|
||||
SHRQ $33, R12
|
||||
XORQ R12, AX
|
||||
IMULQ R14, AX
|
||||
MOVQ AX, R12
|
||||
SHRQ $29, R12
|
||||
XORQ R12, AX
|
||||
IMULQ ·prime3v(SB), AX
|
||||
MOVQ AX, R12
|
||||
SHRQ $32, R12
|
||||
XORQ R12, AX
|
||||
MOVQ h, x
|
||||
SHRQ $33, x
|
||||
XORQ x, h
|
||||
IMULQ prime2, h
|
||||
MOVQ h, x
|
||||
SHRQ $29, x
|
||||
XORQ x, h
|
||||
IMULQ ·primes+16(SB), h
|
||||
MOVQ h, x
|
||||
SHRQ $32, x
|
||||
XORQ x, h
|
||||
|
||||
MOVQ AX, ret+24(FP)
|
||||
MOVQ h, ret+24(FP)
|
||||
RET
|
||||
|
||||
// writeBlocks uses the same registers as above except that it uses AX to store
|
||||
// the d pointer.
|
||||
|
||||
// func writeBlocks(d *Digest, b []byte) int
|
||||
TEXT ·writeBlocks(SB), NOSPLIT, $0-40
|
||||
TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40
|
||||
// Load fixed primes needed for round.
|
||||
MOVQ ·prime1v(SB), R13
|
||||
MOVQ ·prime2v(SB), R14
|
||||
MOVQ ·primes+0(SB), prime1
|
||||
MOVQ ·primes+8(SB), prime2
|
||||
|
||||
// Load slice.
|
||||
MOVQ b_base+8(FP), CX
|
||||
MOVQ b_len+16(FP), DX
|
||||
LEAQ (CX)(DX*1), BX
|
||||
SUBQ $32, BX
|
||||
MOVQ b_base+8(FP), p
|
||||
MOVQ b_len+16(FP), n
|
||||
LEAQ (p)(n*1), end
|
||||
SUBQ $32, end
|
||||
|
||||
// Load vN from d.
|
||||
MOVQ d+0(FP), AX
|
||||
MOVQ 0(AX), R8 // v1
|
||||
MOVQ 8(AX), R9 // v2
|
||||
MOVQ 16(AX), R10 // v3
|
||||
MOVQ 24(AX), R11 // v4
|
||||
MOVQ s+0(FP), d
|
||||
MOVQ 0(d), v1
|
||||
MOVQ 8(d), v2
|
||||
MOVQ 16(d), v3
|
||||
MOVQ 24(d), v4
|
||||
|
||||
// We don't need to check the loop condition here; this function is
|
||||
// always called with at least one block of data to process.
|
||||
blockLoop:
|
||||
round(R8)
|
||||
round(R9)
|
||||
round(R10)
|
||||
round(R11)
|
||||
|
||||
CMPQ CX, BX
|
||||
JLE blockLoop
|
||||
blockLoop()
|
||||
|
||||
// Copy vN back to d.
|
||||
MOVQ R8, 0(AX)
|
||||
MOVQ R9, 8(AX)
|
||||
MOVQ R10, 16(AX)
|
||||
MOVQ R11, 24(AX)
|
||||
MOVQ v1, 0(d)
|
||||
MOVQ v2, 8(d)
|
||||
MOVQ v3, 16(d)
|
||||
MOVQ v4, 24(d)
|
||||
|
||||
// The number of bytes written is CX minus the old base pointer.
|
||||
SUBQ b_base+8(FP), CX
|
||||
MOVQ CX, ret+32(FP)
|
||||
// The number of bytes written is p minus the old base pointer.
|
||||
SUBQ b_base+8(FP), p
|
||||
MOVQ p, ret+32(FP)
|
||||
|
||||
RET
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
//go:build !appengine && gc && !purego
|
||||
// +build !appengine
|
||||
// +build gc
|
||||
// +build !purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// Registers:
|
||||
#define digest R1
|
||||
#define h R2 // return value
|
||||
#define p R3 // input pointer
|
||||
#define n R4 // input length
|
||||
#define nblocks R5 // n / 32
|
||||
#define prime1 R7
|
||||
#define prime2 R8
|
||||
#define prime3 R9
|
||||
#define prime4 R10
|
||||
#define prime5 R11
|
||||
#define v1 R12
|
||||
#define v2 R13
|
||||
#define v3 R14
|
||||
#define v4 R15
|
||||
#define x1 R20
|
||||
#define x2 R21
|
||||
#define x3 R22
|
||||
#define x4 R23
|
||||
|
||||
#define round(acc, x) \
|
||||
MADD prime2, acc, x, acc \
|
||||
ROR $64-31, acc \
|
||||
MUL prime1, acc
|
||||
|
||||
// round0 performs the operation x = round(0, x).
|
||||
#define round0(x) \
|
||||
MUL prime2, x \
|
||||
ROR $64-31, x \
|
||||
MUL prime1, x
|
||||
|
||||
#define mergeRound(acc, x) \
|
||||
round0(x) \
|
||||
EOR x, acc \
|
||||
MADD acc, prime4, prime1, acc
|
||||
|
||||
// blockLoop processes as many 32-byte blocks as possible,
|
||||
// updating v1, v2, v3, and v4. It assumes that n >= 32.
|
||||
#define blockLoop() \
|
||||
LSR $5, n, nblocks \
|
||||
PCALIGN $16 \
|
||||
loop: \
|
||||
LDP.P 16(p), (x1, x2) \
|
||||
LDP.P 16(p), (x3, x4) \
|
||||
round(v1, x1) \
|
||||
round(v2, x2) \
|
||||
round(v3, x3) \
|
||||
round(v4, x4) \
|
||||
SUB $1, nblocks \
|
||||
CBNZ nblocks, loop
|
||||
|
||||
// func Sum64(b []byte) uint64
|
||||
TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32
|
||||
LDP b_base+0(FP), (p, n)
|
||||
|
||||
LDP ·primes+0(SB), (prime1, prime2)
|
||||
LDP ·primes+16(SB), (prime3, prime4)
|
||||
MOVD ·primes+32(SB), prime5
|
||||
|
||||
CMP $32, n
|
||||
CSEL LT, prime5, ZR, h // if n < 32 { h = prime5 } else { h = 0 }
|
||||
BLT afterLoop
|
||||
|
||||
ADD prime1, prime2, v1
|
||||
MOVD prime2, v2
|
||||
MOVD $0, v3
|
||||
NEG prime1, v4
|
||||
|
||||
blockLoop()
|
||||
|
||||
ROR $64-1, v1, x1
|
||||
ROR $64-7, v2, x2
|
||||
ADD x1, x2
|
||||
ROR $64-12, v3, x3
|
||||
ROR $64-18, v4, x4
|
||||
ADD x3, x4
|
||||
ADD x2, x4, h
|
||||
|
||||
mergeRound(h, v1)
|
||||
mergeRound(h, v2)
|
||||
mergeRound(h, v3)
|
||||
mergeRound(h, v4)
|
||||
|
||||
afterLoop:
|
||||
ADD n, h
|
||||
|
||||
TBZ $4, n, try8
|
||||
LDP.P 16(p), (x1, x2)
|
||||
|
||||
round0(x1)
|
||||
|
||||
// NOTE: here and below, sequencing the EOR after the ROR (using a
|
||||
// rotated register) is worth a small but measurable speedup for small
|
||||
// inputs.
|
||||
ROR $64-27, h
|
||||
EOR x1 @> 64-27, h, h
|
||||
MADD h, prime4, prime1, h
|
||||
|
||||
round0(x2)
|
||||
ROR $64-27, h
|
||||
EOR x2 @> 64-27, h, h
|
||||
MADD h, prime4, prime1, h
|
||||
|
||||
try8:
|
||||
TBZ $3, n, try4
|
||||
MOVD.P 8(p), x1
|
||||
|
||||
round0(x1)
|
||||
ROR $64-27, h
|
||||
EOR x1 @> 64-27, h, h
|
||||
MADD h, prime4, prime1, h
|
||||
|
||||
try4:
|
||||
TBZ $2, n, try2
|
||||
MOVWU.P 4(p), x2
|
||||
|
||||
MUL prime1, x2
|
||||
ROR $64-23, h
|
||||
EOR x2 @> 64-23, h, h
|
||||
MADD h, prime3, prime2, h
|
||||
|
||||
try2:
|
||||
TBZ $1, n, try1
|
||||
MOVHU.P 2(p), x3
|
||||
AND $255, x3, x1
|
||||
LSR $8, x3, x2
|
||||
|
||||
MUL prime5, x1
|
||||
ROR $64-11, h
|
||||
EOR x1 @> 64-11, h, h
|
||||
MUL prime1, h
|
||||
|
||||
MUL prime5, x2
|
||||
ROR $64-11, h
|
||||
EOR x2 @> 64-11, h, h
|
||||
MUL prime1, h
|
||||
|
||||
try1:
|
||||
TBZ $0, n, finalize
|
||||
MOVBU (p), x4
|
||||
|
||||
MUL prime5, x4
|
||||
ROR $64-11, h
|
||||
EOR x4 @> 64-11, h, h
|
||||
MUL prime1, h
|
||||
|
||||
finalize:
|
||||
EOR h >> 33, h
|
||||
MUL prime2, h
|
||||
EOR h >> 29, h
|
||||
MUL prime3, h
|
||||
EOR h >> 32, h
|
||||
|
||||
MOVD h, ret+24(FP)
|
||||
RET
|
||||
|
||||
// func writeBlocks(d *Digest, b []byte) int
|
||||
TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40
|
||||
LDP ·primes+0(SB), (prime1, prime2)
|
||||
|
||||
// Load state. Assume v[1-4] are stored contiguously.
|
||||
MOVD d+0(FP), digest
|
||||
LDP 0(digest), (v1, v2)
|
||||
LDP 16(digest), (v3, v4)
|
||||
|
||||
LDP b_base+8(FP), (p, n)
|
||||
|
||||
blockLoop()
|
||||
|
||||
// Store updated state.
|
||||
STP (v1, v2), 0(digest)
|
||||
STP (v3, v4), 16(digest)
|
||||
|
||||
BIC $31, n
|
||||
MOVD n, ret+32(FP)
|
||||
RET
|
|
@ -1,10 +1,12 @@
|
|||
//go:build (amd64 || arm64) && !appengine && gc && !purego
|
||||
// +build amd64 arm64
|
||||
// +build !appengine
|
||||
// +build gc
|
||||
// +build !purego
|
||||
|
||||
package xxhash
|
||||
|
||||
// Sum64 computes the 64-bit xxHash digest of b.
|
||||
// Sum64 computes the 64-bit xxHash digest of b with a zero seed.
|
||||
//
|
||||
//go:noescape
|
||||
func Sum64(b []byte) uint64
|
|
@ -1,8 +1,9 @@
|
|||
// +build !amd64 appengine !gc purego
|
||||
//go:build (!amd64 && !arm64) || appengine || !gc || purego
|
||||
// +build !amd64,!arm64 appengine !gc purego
|
||||
|
||||
package xxhash
|
||||
|
||||
// Sum64 computes the 64-bit xxHash digest of b.
|
||||
// Sum64 computes the 64-bit xxHash digest of b with a zero seed.
|
||||
func Sum64(b []byte) uint64 {
|
||||
// A simpler version would be
|
||||
// d := New()
|
||||
|
@ -14,10 +15,10 @@ func Sum64(b []byte) uint64 {
|
|||
var h uint64
|
||||
|
||||
if n >= 32 {
|
||||
v1 := prime1v + prime2
|
||||
v1 := primes[0] + prime2
|
||||
v2 := prime2
|
||||
v3 := uint64(0)
|
||||
v4 := -prime1v
|
||||
v4 := -primes[0]
|
||||
for len(b) >= 32 {
|
||||
v1 = round(v1, u64(b[0:8:len(b)]))
|
||||
v2 = round(v2, u64(b[8:16:len(b)]))
|
||||
|
@ -36,19 +37,18 @@ func Sum64(b []byte) uint64 {
|
|||
|
||||
h += uint64(n)
|
||||
|
||||
i, end := 0, len(b)
|
||||
for ; i+8 <= end; i += 8 {
|
||||
k1 := round(0, u64(b[i:i+8:len(b)]))
|
||||
for ; len(b) >= 8; b = b[8:] {
|
||||
k1 := round(0, u64(b[:8]))
|
||||
h ^= k1
|
||||
h = rol27(h)*prime1 + prime4
|
||||
}
|
||||
if i+4 <= end {
|
||||
h ^= uint64(u32(b[i:i+4:len(b)])) * prime1
|
||||
if len(b) >= 4 {
|
||||
h ^= uint64(u32(b[:4])) * prime1
|
||||
h = rol23(h)*prime2 + prime3
|
||||
i += 4
|
||||
b = b[4:]
|
||||
}
|
||||
for ; i < end; i++ {
|
||||
h ^= uint64(b[i]) * prime5
|
||||
for ; len(b) > 0; b = b[1:] {
|
||||
h ^= uint64(b[0]) * prime5
|
||||
h = rol11(h) * prime1
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
//go:build appengine
|
||||
// +build appengine
|
||||
|
||||
// This file contains the safe implementations of otherwise unsafe-using code.
|
||||
|
||||
package xxhash
|
||||
|
||||
// Sum64String computes the 64-bit xxHash digest of s.
|
||||
// Sum64String computes the 64-bit xxHash digest of s with a zero seed.
|
||||
func Sum64String(s string) uint64 {
|
||||
return Sum64([]byte(s))
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !appengine
|
||||
// +build !appengine
|
||||
|
||||
// This file encapsulates usage of unsafe.
|
||||
|
@ -6,41 +7,52 @@
|
|||
package xxhash
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Notes:
|
||||
//
|
||||
// See https://groups.google.com/d/msg/golang-nuts/dcjzJy-bSpw/tcZYBzQqAQAJ
|
||||
// for some discussion about these unsafe conversions.
|
||||
//
|
||||
// In the future it's possible that compiler optimizations will make these
|
||||
// unsafe operations unnecessary: https://golang.org/issue/2205.
|
||||
//
|
||||
// Both of these wrapper functions still incur function call overhead since they
|
||||
// will not be inlined. We could write Go/asm copies of Sum64 and Digest.Write
|
||||
// for strings to squeeze out a bit more speed. Mid-stack inlining should
|
||||
// eventually fix this.
|
||||
// XxxString functions unnecessary by realizing that calls such as
|
||||
// Sum64([]byte(s)) don't need to copy s. See https://go.dev/issue/2205.
|
||||
// If that happens, even if we keep these functions they can be replaced with
|
||||
// the trivial safe code.
|
||||
|
||||
// Sum64String computes the 64-bit xxHash digest of s.
|
||||
// NOTE: The usual way of doing an unsafe string-to-[]byte conversion is:
|
||||
//
|
||||
// var b []byte
|
||||
// bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
||||
// bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
|
||||
// bh.Len = len(s)
|
||||
// bh.Cap = len(s)
|
||||
//
|
||||
// Unfortunately, as of Go 1.15.3 the inliner's cost model assigns a high enough
|
||||
// weight to this sequence of expressions that any function that uses it will
|
||||
// not be inlined. Instead, the functions below use a different unsafe
|
||||
// conversion designed to minimize the inliner weight and allow both to be
|
||||
// inlined. There is also a test (TestInlining) which verifies that these are
|
||||
// inlined.
|
||||
//
|
||||
// See https://github.com/golang/go/issues/42739 for discussion.
|
||||
|
||||
// Sum64String computes the 64-bit xxHash digest of s with a zero seed.
|
||||
// It may be faster than Sum64([]byte(s)) by avoiding a copy.
|
||||
func Sum64String(s string) uint64 {
|
||||
var b []byte
|
||||
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
||||
bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
|
||||
bh.Len = len(s)
|
||||
bh.Cap = len(s)
|
||||
b := *(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)}))
|
||||
return Sum64(b)
|
||||
}
|
||||
|
||||
// WriteString adds more data to d. It always returns len(s), nil.
|
||||
// It may be faster than Write([]byte(s)) by avoiding a copy.
|
||||
func (d *Digest) WriteString(s string) (n int, err error) {
|
||||
var b []byte
|
||||
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
||||
bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
|
||||
bh.Len = len(s)
|
||||
bh.Cap = len(s)
|
||||
return d.Write(b)
|
||||
d.Write(*(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)})))
|
||||
// d.Write always returns len(s), nil.
|
||||
// Ignoring the return output and returning these fixed values buys a
|
||||
// savings of 6 in the inliner's cost model.
|
||||
return len(s), nil
|
||||
}
|
||||
|
||||
// sliceHeader is similar to reflect.SliceHeader, but it assumes that the layout
|
||||
// of the first two words is the same as the layout of a string.
|
||||
type sliceHeader struct {
|
||||
s string
|
||||
cap int
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
1487
vendor/github.com/container-storage-interface/spec/lib/go/csi/csi_grpc.pb.go
generated
vendored
Normal file
1487
vendor/github.com/container-storage-interface/spec/lib/go/csi/csi_grpc.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,48 @@
|
|||
# Change history of go-restful
|
||||
|
||||
## [v3.8.0] - 20221-06-06
|
||||
|
||||
## [v3.12.1] - 2024-05-28
|
||||
|
||||
- fix misroute when dealing multiple webservice with regex (#549) (thanks Haitao Chen)
|
||||
|
||||
## [v3.12.0] - 2024-03-11
|
||||
|
||||
- add Flush method #529 (#538)
|
||||
- fix: Improper handling of empty POST requests (#543)
|
||||
|
||||
## [v3.11.3] - 2024-01-09
|
||||
|
||||
- better not have 2 tags on one commit
|
||||
|
||||
## [v3.11.1, v3.11.2] - 2024-01-09
|
||||
|
||||
- fix by restoring custom JSON handler functions (Mike Beaumont #540)
|
||||
|
||||
## [v3.12.0] - 2023-08-19
|
||||
|
||||
- restored behavior as <= v3.9.0 with option to change path strategy using TrimRightSlashEnabled.
|
||||
|
||||
## [v3.10.2] - 2023-03-09 - DO NOT USE
|
||||
|
||||
- introduced MergePathStrategy to be able to revert behaviour of path concatenation to 3.9.0
|
||||
see comment in Readme how to customize this behaviour.
|
||||
|
||||
## [v3.10.1] - 2022-11-19 - DO NOT USE
|
||||
|
||||
- fix broken 3.10.0 by using path package for joining paths
|
||||
|
||||
## [v3.10.0] - 2022-10-11 - BROKEN
|
||||
|
||||
- changed tokenizer to match std route match behavior; do not trimright the path (#511)
|
||||
- Add MIME_ZIP (#512)
|
||||
- Add MIME_ZIP and HEADER_ContentDisposition (#513)
|
||||
- Changed how to get query parameter issue #510
|
||||
|
||||
## [v3.9.0] - 2022-07-21
|
||||
|
||||
- add support for http.Handler implementations to work as FilterFunction, issue #504 (thanks to https://github.com/ggicci)
|
||||
|
||||
## [v3.8.0] - 2022-06-06
|
||||
|
||||
- use exact matching of allowed domain entries, issue #489 (#493)
|
||||
- this changes fixes [security] Authorization Bypass Through User-Controlled Key
|
||||
|
|
|
@ -2,7 +2,6 @@ go-restful
|
|||
==========
|
||||
package for building REST-style Web Services using Google Go
|
||||
|
||||
[](https://travis-ci.org/emicklei/go-restful)
|
||||
[](https://goreportcard.com/report/github.com/emicklei/go-restful)
|
||||
[](https://pkg.go.dev/github.com/emicklei/go-restful)
|
||||
[](https://codecov.io/gh/emicklei/go-restful)
|
||||
|
@ -79,11 +78,12 @@ func (u UserResource) findUser(request *restful.Request, response *restful.Respo
|
|||
- Content encoding (gzip,deflate) of request and response payloads
|
||||
- Automatic responses on OPTIONS (using a filter)
|
||||
- Automatic CORS request handling (using a filter)
|
||||
- API declaration for Swagger UI ([go-restful-openapi](https://github.com/emicklei/go-restful-openapi), see [go-restful-swagger12](https://github.com/emicklei/go-restful-swagger12))
|
||||
- API declaration for Swagger UI ([go-restful-openapi](https://github.com/emicklei/go-restful-openapi))
|
||||
- Panic recovery to produce HTTP 500, customizable using RecoverHandler(...)
|
||||
- Route errors produce HTTP 404/405/406/415 errors, customizable using ServiceErrorHandler(...)
|
||||
- Configurable (trace) logging
|
||||
- Customizable gzip/deflate readers and writers using CompressorProvider registration
|
||||
- Inject your own http.Handler using the `HttpMiddlewareHandlerToFilter` function
|
||||
|
||||
## How to customize
|
||||
There are several hooks to customize the behavior of the go-restful package.
|
||||
|
@ -94,7 +94,7 @@ There are several hooks to customize the behavior of the go-restful package.
|
|||
- Trace logging
|
||||
- Compression
|
||||
- Encoders for other serializers
|
||||
- Use [jsoniter](https://github.com/json-iterator/go) by build this package using a tag, e.g. `go build -tags=jsoniter .`
|
||||
- Use the package variable `TrimRightSlashEnabled` (default true) to control the behavior of matching routes that end with a slash `/`
|
||||
|
||||
## Resources
|
||||
|
||||
|
@ -107,4 +107,4 @@ There are several hooks to customize the behavior of the go-restful package.
|
|||
|
||||
Type ```git shortlog -s``` for a full list of contributors.
|
||||
|
||||
© 2012 - 2022, http://ernestmicklei.com. MIT License. Contributions are welcome.
|
||||
© 2012 - 2023, http://ernestmicklei.com. MIT License. Contributions are welcome.
|
||||
|
|
|
@ -49,6 +49,16 @@ func (c *CompressingResponseWriter) CloseNotify() <-chan bool {
|
|||
return c.writer.(http.CloseNotifier).CloseNotify()
|
||||
}
|
||||
|
||||
// Flush is part of http.Flusher interface. Noop if the underlying writer doesn't support it.
|
||||
func (c *CompressingResponseWriter) Flush() {
|
||||
flusher, ok := c.writer.(http.Flusher)
|
||||
if !ok {
|
||||
// writer doesn't support http.Flusher interface
|
||||
return
|
||||
}
|
||||
flusher.Flush()
|
||||
}
|
||||
|
||||
// Close the underlying compressor
|
||||
func (c *CompressingResponseWriter) Close() error {
|
||||
if c.isCompressorClosed() {
|
||||
|
|
|
@ -7,12 +7,14 @@ package restful
|
|||
const (
|
||||
MIME_XML = "application/xml" // Accept or Content-Type used in Consumes() and/or Produces()
|
||||
MIME_JSON = "application/json" // Accept or Content-Type used in Consumes() and/or Produces()
|
||||
MIME_ZIP = "application/zip" // Accept or Content-Type used in Consumes() and/or Produces()
|
||||
MIME_OCTET = "application/octet-stream" // If Content-Type is not present in request, use the default
|
||||
|
||||
HEADER_Allow = "Allow"
|
||||
HEADER_Accept = "Accept"
|
||||
HEADER_Origin = "Origin"
|
||||
HEADER_ContentType = "Content-Type"
|
||||
HEADER_ContentDisposition = "Content-Disposition"
|
||||
HEADER_LastModified = "Last-Modified"
|
||||
HEADER_AcceptEncoding = "Accept-Encoding"
|
||||
HEADER_ContentEncoding = "Content-Encoding"
|
||||
|
|
|
@ -46,10 +46,10 @@ func (c CurlyRouter) SelectRoute(
|
|||
// selectRoutes return a collection of Route from a WebService that matches the path tokens from the request.
|
||||
func (c CurlyRouter) selectRoutes(ws *WebService, requestTokens []string) sortableCurlyRoutes {
|
||||
candidates := make(sortableCurlyRoutes, 0, 8)
|
||||
for _, each := range ws.routes {
|
||||
matches, paramCount, staticCount := c.matchesRouteByPathTokens(each.pathParts, requestTokens, each.hasCustomVerb)
|
||||
for _, eachRoute := range ws.routes {
|
||||
matches, paramCount, staticCount := c.matchesRouteByPathTokens(eachRoute.pathParts, requestTokens, eachRoute.hasCustomVerb)
|
||||
if matches {
|
||||
candidates.add(curlyRoute{each, paramCount, staticCount}) // TODO make sure Routes() return pointers?
|
||||
candidates.add(curlyRoute{eachRoute, paramCount, staticCount}) // TODO make sure Routes() return pointers?
|
||||
}
|
||||
}
|
||||
sort.Sort(candidates)
|
||||
|
@ -72,7 +72,7 @@ func (c CurlyRouter) matchesRouteByPathTokens(routeTokens, requestTokens []strin
|
|||
return false, 0, 0
|
||||
}
|
||||
requestToken := requestTokens[i]
|
||||
if routeHasCustomVerb && hasCustomVerb(routeToken){
|
||||
if routeHasCustomVerb && hasCustomVerb(routeToken) {
|
||||
if !isMatchCustomVerb(routeToken, requestToken) {
|
||||
return false, 0, 0
|
||||
}
|
||||
|
@ -129,44 +129,52 @@ func (c CurlyRouter) detectRoute(candidateRoutes sortableCurlyRoutes, httpReques
|
|||
// detectWebService returns the best matching webService given the list of path tokens.
|
||||
// see also computeWebserviceScore
|
||||
func (c CurlyRouter) detectWebService(requestTokens []string, webServices []*WebService) *WebService {
|
||||
var best *WebService
|
||||
var bestWs *WebService
|
||||
score := -1
|
||||
for _, each := range webServices {
|
||||
matches, eachScore := c.computeWebserviceScore(requestTokens, each.pathExpr.tokens)
|
||||
for _, eachWS := range webServices {
|
||||
matches, eachScore := c.computeWebserviceScore(requestTokens, eachWS.pathExpr.tokens)
|
||||
if matches && (eachScore > score) {
|
||||
best = each
|
||||
bestWs = eachWS
|
||||
score = eachScore
|
||||
}
|
||||
}
|
||||
return best
|
||||
return bestWs
|
||||
}
|
||||
|
||||
// computeWebserviceScore returns whether tokens match and
|
||||
// the weighted score of the longest matching consecutive tokens from the beginning.
|
||||
func (c CurlyRouter) computeWebserviceScore(requestTokens []string, tokens []string) (bool, int) {
|
||||
if len(tokens) > len(requestTokens) {
|
||||
func (c CurlyRouter) computeWebserviceScore(requestTokens []string, routeTokens []string) (bool, int) {
|
||||
if len(routeTokens) > len(requestTokens) {
|
||||
return false, 0
|
||||
}
|
||||
score := 0
|
||||
for i := 0; i < len(tokens); i++ {
|
||||
each := requestTokens[i]
|
||||
other := tokens[i]
|
||||
if len(each) == 0 && len(other) == 0 {
|
||||
for i := 0; i < len(routeTokens); i++ {
|
||||
eachRequestToken := requestTokens[i]
|
||||
eachRouteToken := routeTokens[i]
|
||||
if len(eachRequestToken) == 0 && len(eachRouteToken) == 0 {
|
||||
score++
|
||||
continue
|
||||
}
|
||||
if len(other) > 0 && strings.HasPrefix(other, "{") {
|
||||
if len(eachRouteToken) > 0 && strings.HasPrefix(eachRouteToken, "{") {
|
||||
// no empty match
|
||||
if len(each) == 0 {
|
||||
if len(eachRequestToken) == 0 {
|
||||
return false, score
|
||||
}
|
||||
score += 1
|
||||
score++
|
||||
|
||||
if colon := strings.Index(eachRouteToken, ":"); colon != -1 {
|
||||
// match by regex
|
||||
matchesToken, _ := c.regularMatchesPathToken(eachRouteToken, colon, eachRequestToken)
|
||||
if matchesToken {
|
||||
score++ // extra score for regex match
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// not a parameter
|
||||
if each != other {
|
||||
if eachRequestToken != eachRouteToken {
|
||||
return false, score
|
||||
}
|
||||
score += (len(tokens) - i) * 10 //fuzzy
|
||||
score += (len(routeTokens) - i) * 10 //fuzzy
|
||||
}
|
||||
}
|
||||
return true, score
|
||||
|
|
|
@ -5,11 +5,18 @@ package restful
|
|||
// that can be found in the LICENSE file.
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
MarshalIndent = json.MarshalIndent
|
||||
NewDecoder = json.NewDecoder
|
||||
NewEncoder = json.NewEncoder
|
||||
)
|
||||
|
||||
// EntityReaderWriter can read and write values using an encoding such as JSON,XML.
|
||||
type EntityReaderWriter interface {
|
||||
// Read a serialized version of the value from the request.
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package restful
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// HttpMiddlewareHandler is a function that takes a http.Handler and returns a http.Handler
|
||||
type HttpMiddlewareHandler func(http.Handler) http.Handler
|
||||
|
||||
// HttpMiddlewareHandlerToFilter converts a HttpMiddlewareHandler to a FilterFunction.
|
||||
func HttpMiddlewareHandlerToFilter(middleware HttpMiddlewareHandler) FilterFunction {
|
||||
return func(req *Request, resp *Response, chain *FilterChain) {
|
||||
next := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
req.Request = r
|
||||
resp.ResponseWriter = rw
|
||||
chain.ProcessFilter(req, resp)
|
||||
})
|
||||
|
||||
middleware(next).ServeHTTP(resp.ResponseWriter, req.Request)
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
// +build !jsoniter
|
||||
|
||||
package restful
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
var (
|
||||
MarshalIndent = json.MarshalIndent
|
||||
NewDecoder = json.NewDecoder
|
||||
NewEncoder = json.NewEncoder
|
||||
)
|
|
@ -1,12 +0,0 @@
|
|||
// +build jsoniter
|
||||
|
||||
package restful
|
||||
|
||||
import "github.com/json-iterator/go"
|
||||
|
||||
var (
|
||||
json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
MarshalIndent = json.MarshalIndent
|
||||
NewDecoder = json.NewDecoder
|
||||
NewEncoder = json.NewEncoder
|
||||
)
|
|
@ -155,7 +155,7 @@ func (r RouterJSR311) detectRoute(routes []Route, httpRequest *http.Request) (*R
|
|||
method, length := httpRequest.Method, httpRequest.Header.Get("Content-Length")
|
||||
if (method == http.MethodPost ||
|
||||
method == http.MethodPut ||
|
||||
method == http.MethodPatch) && length == "" {
|
||||
method == http.MethodPatch) && (length == "" || length == "0") {
|
||||
return nil, NewError(
|
||||
http.StatusUnsupportedMediaType,
|
||||
fmt.Sprintf("415: Unsupported Media Type\n\nAvailable representations: %s", strings.Join(available, ", ")),
|
||||
|
|
|
@ -22,6 +22,9 @@ const (
|
|||
// FormParameterKind = indicator of Request parameter type "form"
|
||||
FormParameterKind
|
||||
|
||||
// MultiPartFormParameterKind = indicator of Request parameter type "multipart/form-data"
|
||||
MultiPartFormParameterKind
|
||||
|
||||
// CollectionFormatCSV comma separated values `foo,bar`
|
||||
CollectionFormatCSV = CollectionFormat("csv")
|
||||
|
||||
|
@ -108,6 +111,11 @@ func (p *Parameter) beForm() *Parameter {
|
|||
return p
|
||||
}
|
||||
|
||||
func (p *Parameter) beMultiPartForm() *Parameter {
|
||||
p.data.Kind = MultiPartFormParameterKind
|
||||
return p
|
||||
}
|
||||
|
||||
// Required sets the required field and returns the receiver
|
||||
func (p *Parameter) Required(required bool) *Parameter {
|
||||
p.data.Required = required
|
||||
|
|
|
@ -31,7 +31,8 @@ func NewRequest(httpRequest *http.Request) *Request {
|
|||
// a "Unable to unmarshal content of type:" response is returned.
|
||||
// Valid values are restful.MIME_JSON and restful.MIME_XML
|
||||
// Example:
|
||||
// restful.DefaultRequestContentType(restful.MIME_JSON)
|
||||
//
|
||||
// restful.DefaultRequestContentType(restful.MIME_JSON)
|
||||
func DefaultRequestContentType(mime string) {
|
||||
defaultRequestContentType = mime
|
||||
}
|
||||
|
@ -48,7 +49,7 @@ func (r *Request) PathParameters() map[string]string {
|
|||
|
||||
// QueryParameter returns the (first) Query parameter value by its name
|
||||
func (r *Request) QueryParameter(name string) string {
|
||||
return r.Request.FormValue(name)
|
||||
return r.Request.URL.Query().Get(name)
|
||||
}
|
||||
|
||||
// QueryParameters returns the all the query parameters values by name
|
||||
|
|
|
@ -109,6 +109,9 @@ func (r *Response) EntityWriter() (EntityReaderWriter, bool) {
|
|||
if DefaultResponseMimeType == MIME_XML {
|
||||
return entityAccessRegistry.accessorAt(MIME_XML)
|
||||
}
|
||||
if DefaultResponseMimeType == MIME_ZIP {
|
||||
return entityAccessRegistry.accessorAt(MIME_ZIP)
|
||||
}
|
||||
// Fallback to whatever the route says it can produce.
|
||||
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
|
||||
for _, each := range r.routeProduces {
|
||||
|
|
|
@ -40,7 +40,8 @@ type Route struct {
|
|||
ParameterDocs []*Parameter
|
||||
ResponseErrors map[int]ResponseError
|
||||
DefaultResponse *ResponseError
|
||||
ReadSample, WriteSample interface{} // structs that model an example request or response payload
|
||||
ReadSample, WriteSample interface{} // structs that model an example request or response payload
|
||||
WriteSamples []interface{} // if more than one return types is possible (oneof) then this will contain multiple values
|
||||
|
||||
// Extra information used to store custom information about the route.
|
||||
Metadata map[string]interface{}
|
||||
|
@ -164,7 +165,13 @@ func tokenizePath(path string) []string {
|
|||
if "/" == path {
|
||||
return nil
|
||||
}
|
||||
return strings.Split(strings.Trim(path, "/"), "/")
|
||||
if TrimRightSlashEnabled {
|
||||
// 3.9.0
|
||||
return strings.Split(strings.Trim(path, "/"), "/")
|
||||
} else {
|
||||
// 3.10.2
|
||||
return strings.Split(strings.TrimLeft(path, "/"), "/")
|
||||
}
|
||||
}
|
||||
|
||||
// for debugging
|
||||
|
@ -176,3 +183,9 @@ func (r *Route) String() string {
|
|||
func (r *Route) EnableContentEncoding(enabled bool) {
|
||||
r.contentEncodingEnabled = &enabled
|
||||
}
|
||||
|
||||
// TrimRightSlashEnabled controls whether
|
||||
// - path on route building is using path.Join
|
||||
// - the path of the incoming request is trimmed of its slash suffux.
|
||||
// Value of true matches the behavior of <= 3.9.0
|
||||
var TrimRightSlashEnabled = true
|
||||
|
|
|
@ -7,6 +7,7 @@ package restful
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
@ -30,27 +31,29 @@ type RouteBuilder struct {
|
|||
typeNameHandleFunc TypeNameHandleFunction // required
|
||||
|
||||
// documentation
|
||||
doc string
|
||||
notes string
|
||||
operation string
|
||||
readSample, writeSample interface{}
|
||||
parameters []*Parameter
|
||||
errorMap map[int]ResponseError
|
||||
defaultResponse *ResponseError
|
||||
metadata map[string]interface{}
|
||||
extensions map[string]interface{}
|
||||
deprecated bool
|
||||
contentEncodingEnabled *bool
|
||||
doc string
|
||||
notes string
|
||||
operation string
|
||||
readSample interface{}
|
||||
writeSamples []interface{}
|
||||
parameters []*Parameter
|
||||
errorMap map[int]ResponseError
|
||||
defaultResponse *ResponseError
|
||||
metadata map[string]interface{}
|
||||
extensions map[string]interface{}
|
||||
deprecated bool
|
||||
contentEncodingEnabled *bool
|
||||
}
|
||||
|
||||
// Do evaluates each argument with the RouteBuilder itself.
|
||||
// This allows you to follow DRY principles without breaking the fluent programming style.
|
||||
// Example:
|
||||
// ws.Route(ws.DELETE("/{name}").To(t.deletePerson).Do(Returns200, Returns500))
|
||||
//
|
||||
// func Returns500(b *RouteBuilder) {
|
||||
// b.Returns(500, "Internal Server Error", restful.ServiceError{})
|
||||
// }
|
||||
// ws.Route(ws.DELETE("/{name}").To(t.deletePerson).Do(Returns200, Returns500))
|
||||
//
|
||||
// func Returns500(b *RouteBuilder) {
|
||||
// b.Returns(500, "Internal Server Error", restful.ServiceError{})
|
||||
// }
|
||||
func (b *RouteBuilder) Do(oneArgBlocks ...func(*RouteBuilder)) *RouteBuilder {
|
||||
for _, each := range oneArgBlocks {
|
||||
each(b)
|
||||
|
@ -133,9 +136,9 @@ func (b RouteBuilder) ParameterNamed(name string) (p *Parameter) {
|
|||
return p
|
||||
}
|
||||
|
||||
// Writes tells what resource type will be written as the response payload. Optional.
|
||||
func (b *RouteBuilder) Writes(sample interface{}) *RouteBuilder {
|
||||
b.writeSample = sample
|
||||
// Writes tells which one of the resource types will be written as the response payload. Optional.
|
||||
func (b *RouteBuilder) Writes(samples ...interface{}) *RouteBuilder {
|
||||
b.writeSamples = samples // oneof
|
||||
return b
|
||||
}
|
||||
|
||||
|
@ -340,19 +343,29 @@ func (b *RouteBuilder) Build() Route {
|
|||
ResponseErrors: b.errorMap,
|
||||
DefaultResponse: b.defaultResponse,
|
||||
ReadSample: b.readSample,
|
||||
WriteSample: b.writeSample,
|
||||
WriteSamples: b.writeSamples,
|
||||
Metadata: b.metadata,
|
||||
Deprecated: b.deprecated,
|
||||
contentEncodingEnabled: b.contentEncodingEnabled,
|
||||
allowedMethodsWithoutContentType: b.allowedMethodsWithoutContentType,
|
||||
}
|
||||
// set WriteSample if one specified
|
||||
if len(b.writeSamples) == 1 {
|
||||
route.WriteSample = b.writeSamples[0]
|
||||
}
|
||||
route.Extensions = b.extensions
|
||||
route.postBuild()
|
||||
return route
|
||||
}
|
||||
|
||||
func concatPath(path1, path2 string) string {
|
||||
return strings.TrimRight(path1, "/") + "/" + strings.TrimLeft(path2, "/")
|
||||
// merge two paths using the current (package global) merge path strategy.
|
||||
func concatPath(rootPath, routePath string) string {
|
||||
|
||||
if TrimRightSlashEnabled {
|
||||
return strings.TrimRight(rootPath, "/") + "/" + strings.TrimLeft(routePath, "/")
|
||||
} else {
|
||||
return path.Join(rootPath, routePath)
|
||||
}
|
||||
}
|
||||
|
||||
var anonymousFuncCount int32
|
||||
|
|
|
@ -165,6 +165,18 @@ func FormParameter(name, description string) *Parameter {
|
|||
return p
|
||||
}
|
||||
|
||||
// MultiPartFormParameter creates a new Parameter of kind Form (using multipart/form-data) for documentation purposes.
|
||||
// It is initialized as required with string as its DataType.
|
||||
func (w *WebService) MultiPartFormParameter(name, description string) *Parameter {
|
||||
return MultiPartFormParameter(name, description)
|
||||
}
|
||||
|
||||
func MultiPartFormParameter(name, description string) *Parameter {
|
||||
p := &Parameter{&ParameterData{Name: name, Description: description, Required: false, DataType: "string"}}
|
||||
p.beMultiPartForm()
|
||||
return p
|
||||
}
|
||||
|
||||
// Route creates a new Route using the RouteBuilder and add to the ordered list of Routes.
|
||||
func (w *WebService) Route(builder *RouteBuilder) *WebService {
|
||||
w.routesLock.Lock()
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
|
@ -0,0 +1,104 @@
|
|||
# Do not delete linter settings. Linters like gocritic can be enabled on the command line.
|
||||
|
||||
linters-settings:
|
||||
depguard:
|
||||
rules:
|
||||
prevent_unmaintained_packages:
|
||||
list-mode: strict
|
||||
files:
|
||||
- $all
|
||||
- "!$test"
|
||||
allow:
|
||||
- $gostd
|
||||
- github.com/x448/float16
|
||||
deny:
|
||||
- pkg: io/ioutil
|
||||
desc: "replaced by io and os packages since Go 1.16: https://tip.golang.org/doc/go1.16#ioutil"
|
||||
dupl:
|
||||
threshold: 100
|
||||
funlen:
|
||||
lines: 100
|
||||
statements: 50
|
||||
goconst:
|
||||
ignore-tests: true
|
||||
min-len: 2
|
||||
min-occurrences: 3
|
||||
gocritic:
|
||||
enabled-tags:
|
||||
- diagnostic
|
||||
- experimental
|
||||
- opinionated
|
||||
- performance
|
||||
- style
|
||||
disabled-checks:
|
||||
- commentedOutCode
|
||||
- dupImport # https://github.com/go-critic/go-critic/issues/845
|
||||
- ifElseChain
|
||||
- octalLiteral
|
||||
- paramTypeCombine
|
||||
- whyNoLint
|
||||
gofmt:
|
||||
simplify: false
|
||||
goimports:
|
||||
local-prefixes: github.com/fxamacker/cbor
|
||||
golint:
|
||||
min-confidence: 0
|
||||
govet:
|
||||
check-shadowing: true
|
||||
lll:
|
||||
line-length: 140
|
||||
maligned:
|
||||
suggest-new: true
|
||||
misspell:
|
||||
locale: US
|
||||
staticcheck:
|
||||
checks: ["all"]
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- asciicheck
|
||||
- bidichk
|
||||
- depguard
|
||||
- errcheck
|
||||
- exportloopref
|
||||
- goconst
|
||||
- gocritic
|
||||
- gocyclo
|
||||
- gofmt
|
||||
- goimports
|
||||
- goprintffuncname
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- misspell
|
||||
- nilerr
|
||||
- revive
|
||||
- staticcheck
|
||||
- stylecheck
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unused
|
||||
|
||||
issues:
|
||||
# max-issues-per-linter default is 50. Set to 0 to disable limit.
|
||||
max-issues-per-linter: 0
|
||||
# max-same-issues default is 3. Set to 0 to disable limit.
|
||||
max-same-issues: 0
|
||||
|
||||
exclude-rules:
|
||||
- path: decode.go
|
||||
text: "string ` overflows ` has (\\d+) occurrences, make it a constant"
|
||||
- path: decode.go
|
||||
text: "string ` \\(range is \\[` has (\\d+) occurrences, make it a constant"
|
||||
- path: decode.go
|
||||
text: "string `, ` has (\\d+) occurrences, make it a constant"
|
||||
- path: decode.go
|
||||
text: "string ` overflows Go's int64` has (\\d+) occurrences, make it a constant"
|
||||
- path: decode.go
|
||||
text: "string `\\]\\)` has (\\d+) occurrences, make it a constant"
|
||||
- path: valid.go
|
||||
text: "string ` for type ` has (\\d+) occurrences, make it a constant"
|
||||
- path: valid.go
|
||||
text: "string `cbor: ` has (\\d+) occurrences, make it a constant"
|
|
@ -0,0 +1,133 @@
|
|||
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, caste, color, religion, or sexual
|
||||
identity and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
faye.github@gmail.com.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series of
|
||||
actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or permanent
|
||||
ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the
|
||||
community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.1, available at
|
||||
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
||||
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
||||
[https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
|
@ -0,0 +1,41 @@
|
|||
# How to contribute
|
||||
|
||||
You can contribute by using the library, opening issues, or opening pull requests.
|
||||
|
||||
## Bug reports and security vulnerabilities
|
||||
|
||||
Most issues are tracked publicly on [GitHub](https://github.com/fxamacker/cbor/issues).
|
||||
|
||||
To report security vulnerabilities, please email faye.github@gmail.com and allow time for the problem to be resolved before disclosing it to the public. For more info, see [Security Policy](https://github.com/fxamacker/cbor#security-policy).
|
||||
|
||||
Please do not send data that might contain personally identifiable information, even if you think you have permission. That type of support requires payment and a signed contract where I'm indemnified, held harmless, and defended by you for any data you send to me.
|
||||
|
||||
## Pull requests
|
||||
|
||||
Please [create an issue](https://github.com/fxamacker/cbor/issues/new/choose) before you begin work on a PR. The improvement may have already been considered, etc.
|
||||
|
||||
Pull requests have signing requirements and must not be anonymous. Exceptions are usually made for docs and CI scripts.
|
||||
|
||||
See the [Pull Request Template](https://github.com/fxamacker/cbor/blob/master/.github/pull_request_template.md) for details.
|
||||
|
||||
Pull requests have a greater chance of being approved if:
|
||||
- it does not reduce speed, increase memory use, reduce security, etc. for people not using the new option or feature.
|
||||
- it has > 97% code coverage.
|
||||
|
||||
## Describe your issue
|
||||
|
||||
Clearly describe the issue:
|
||||
* If it's a bug, please provide: **version of this library** and **Go** (`go version`), **unmodified error message**, and describe **how to reproduce it**. Also state **what you expected to happen** instead of the error.
|
||||
* If you propose a change or addition, try to give an example how the improved code could look like or how to use it.
|
||||
* If you found a compilation error, please confirm you're using a supported version of Go. If you are, then provide the output of `go version` first, followed by the complete error message.
|
||||
|
||||
## Please don't
|
||||
|
||||
Please don't send data containing personally identifiable information, even if you think you have permission. That type of support requires payment and a contract where I'm indemnified, held harmless, and defended for any data you send to me.
|
||||
|
||||
Please don't send CBOR data larger than 1024 bytes by email. If you want to send crash-producing CBOR data > 1024 bytes by email, please get my permission before sending it to me.
|
||||
|
||||
## Credits
|
||||
|
||||
- This guide used nlohmann/json contribution guidelines for inspiration as suggested in issue #22.
|
||||
- Special thanks to @lukseven for pointing out the contribution guidelines didn't mention signing requirements.
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019-present Faye Amacker
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,691 @@
|
|||
# CBOR Codec in Go
|
||||
|
||||
<!-- [](#cbor-library-in-go) -->
|
||||
|
||||
[fxamacker/cbor](https://github.com/fxamacker/cbor) is a library for encoding and decoding [CBOR](https://www.rfc-editor.org/info/std94) and [CBOR Sequences](https://www.rfc-editor.org/rfc/rfc8742.html).
|
||||
|
||||
CBOR is a [trusted alternative](https://www.rfc-editor.org/rfc/rfc8949.html#name-comparison-of-other-binary-) to JSON, MessagePack, Protocol Buffers, etc. CBOR is an Internet Standard defined by [IETF STD 94 (RFC 8949)](https://www.rfc-editor.org/info/std94) and is designed to be relevant for decades.
|
||||
|
||||
`fxamacker/cbor` is used in projects by Arm Ltd., Cisco, EdgeX Foundry, Flow Foundation, Fraunhofer‑AISEC, Kubernetes, Let's Encrypt (ISRG), Linux Foundation, Microsoft, Mozilla, Oasis Protocol, Tailscale, Teleport, [etc](https://github.com/fxamacker/cbor#who-uses-fxamackercbor).
|
||||
|
||||
See [Quick Start](#quick-start) and [Releases](https://github.com/fxamacker/cbor/releases/). 🆕 `UnmarshalFirst` and `DiagnoseFirst` can decode CBOR Sequences. `cbor.MarshalToBuffer()` and `UserBufferEncMode` accepts user-specified buffer.
|
||||
|
||||
## fxamacker/cbor
|
||||
|
||||
[](https://github.com/fxamacker/cbor/actions?query=workflow%3Aci)
|
||||
[](https://github.com/fxamacker/cbor/actions?query=workflow%3A%22cover+%E2%89%A596%25%22)
|
||||
[](https://github.com/fxamacker/cbor/actions/workflows/codeql-analysis.yml)
|
||||
[](#fuzzing-and-code-coverage)
|
||||
[](https://goreportcard.com/report/github.com/fxamacker/cbor)
|
||||
|
||||
`fxamacker/cbor` is a CBOR codec in full conformance with [IETF STD 94 (RFC 8949)](https://www.rfc-editor.org/info/std94). It also supports CBOR Sequences ([RFC 8742](https://www.rfc-editor.org/rfc/rfc8742.html)) and Extended Diagnostic Notation ([Appendix G of RFC 8610](https://www.rfc-editor.org/rfc/rfc8610.html#appendix-G)).
|
||||
|
||||
Features include full support for CBOR tags, [Core Deterministic Encoding](https://www.rfc-editor.org/rfc/rfc8949.html#name-core-deterministic-encoding), duplicate map key detection, etc.
|
||||
|
||||
Design balances trade-offs between security, speed, concurrency, encoded data size, usability, etc.
|
||||
|
||||
<details><summary>Highlights</summary><p/>
|
||||
|
||||
__🚀 Speed__
|
||||
|
||||
Encoding and decoding is fast without using Go's `unsafe` package. Slower settings are opt-in. Default limits allow very fast and memory efficient rejection of malformed CBOR data.
|
||||
|
||||
__🔒 Security__
|
||||
|
||||
Decoder has configurable limits that defend against malicious inputs. Duplicate map key detection is supported. By contrast, `encoding/gob` is [not designed to be hardened against adversarial inputs](https://pkg.go.dev/encoding/gob#hdr-Security).
|
||||
|
||||
Codec passed multiple confidential security assessments in 2022. No vulnerabilities found in subset of codec in a [nonconfidential security assessment](https://github.com/veraison/go-cose/blob/v1.0.0-rc.1/reports/NCC_Microsoft-go-cose-Report_2022-05-26_v1.0.pdf) prepared by NCC Group for Microsoft Corporation.
|
||||
|
||||
__🗜️ Data Size__
|
||||
|
||||
Struct tags (`toarray`, `keyasint`, `omitempty`) automatically reduce size of encoded structs. Encoding optionally shrinks float64→32→16 when values fit.
|
||||
|
||||
__:jigsaw: Usability__
|
||||
|
||||
API is mostly same as `encoding/json` plus interfaces that simplify concurrency for CBOR options. Encoding and decoding modes can be created at startup and reused by any goroutines.
|
||||
|
||||
Presets include Core Deterministic Encoding, Preferred Serialization, CTAP2 Canonical CBOR, etc.
|
||||
|
||||
__📆 Extensibility__
|
||||
|
||||
Features include CBOR [extension points](https://www.rfc-editor.org/rfc/rfc8949.html#section-7.1) (e.g. CBOR tags) and extensive settings. API has interfaces that allow users to create custom encoding and decoding without modifying this library.
|
||||
|
||||
<hr/>
|
||||
|
||||
</details>
|
||||
|
||||
### Secure Decoding with Configurable Settings
|
||||
|
||||
`fxamacker/cbor` has configurable limits, etc. that defend against malicious CBOR data.
|
||||
|
||||
By contrast, `encoding/gob` is [not designed to be hardened against adversarial inputs](https://pkg.go.dev/encoding/gob#hdr-Security).
|
||||
|
||||
<details><summary>Example decoding with encoding/gob 💥 fatal error (out of memory)</summary><p/>
|
||||
|
||||
```Go
|
||||
// Example of encoding/gob having "fatal error: runtime: out of memory"
|
||||
// while decoding 181 bytes.
|
||||
package main
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Example data is from https://github.com/golang/go/issues/24446
|
||||
// (shortened to 181 bytes).
|
||||
const data = "4dffb503010102303001ff30000109010130010800010130010800010130" +
|
||||
"01ffb80001014a01ffb60001014b01ff860001013001ff860001013001ff" +
|
||||
"860001013001ff860001013001ffb80000001eff850401010e3030303030" +
|
||||
"30303030303030303001ff3000010c0104000016ffb70201010830303030" +
|
||||
"3030303001ff3000010c000030ffb6040405fcff00303030303030303030" +
|
||||
"303030303030303030303030303030303030303030303030303030303030" +
|
||||
"30"
|
||||
|
||||
type X struct {
|
||||
J *X
|
||||
K map[string]int
|
||||
}
|
||||
|
||||
func main() {
|
||||
raw, _ := hex.DecodeString(data)
|
||||
decoder := gob.NewDecoder(bytes.NewReader(raw))
|
||||
|
||||
var x X
|
||||
decoder.Decode(&x) // fatal error: runtime: out of memory
|
||||
fmt.Println("Decoding finished.")
|
||||
}
|
||||
```
|
||||
|
||||
<hr/>
|
||||
|
||||
</details>
|
||||
|
||||
`fxamacker/cbor` is fast at rejecting malformed CBOR data. E.g. attempts to
|
||||
decode 10 bytes of malicious CBOR data to `[]byte` (with default settings):
|
||||
|
||||
| Codec | Speed (ns/op) | Memory | Allocs |
|
||||
| :---- | ------------: | -----: | -----: |
|
||||
| fxamacker/cbor 2.5.0 | 44 ± 5% | 32 B/op | 2 allocs/op |
|
||||
| ugorji/go 1.2.11 | 5353261 ± 4% | 67111321 B/op | 13 allocs/op |
|
||||
|
||||
<details><summary>Benchmark details</summary><p/>
|
||||
|
||||
Latest comparison used:
|
||||
- Input: `[]byte{0x9B, 0x00, 0x00, 0x42, 0xFA, 0x42, 0xFA, 0x42, 0xFA, 0x42}`
|
||||
- go1.19.10, linux/amd64, i5-13600K (disabled all e-cores, DDR4 @2933)
|
||||
- go test -bench=. -benchmem -count=20
|
||||
|
||||
#### Prior comparisons
|
||||
|
||||
| Codec | Speed (ns/op) | Memory | Allocs |
|
||||
| :---- | ------------: | -----: | -----: |
|
||||
| fxamacker/cbor 2.5.0-beta2 | 44.33 ± 2% | 32 B/op | 2 allocs/op |
|
||||
| fxamacker/cbor 0.1.0 - 2.4.0 | ~44.68 ± 6% | 32 B/op | 2 allocs/op |
|
||||
| ugorji/go 1.2.10 | 5524792.50 ± 3% | 67110491 B/op | 12 allocs/op |
|
||||
| ugorji/go 1.1.0 - 1.2.6 | 💥 runtime: | out of memory: | cannot allocate |
|
||||
|
||||
- Input: `[]byte{0x9B, 0x00, 0x00, 0x42, 0xFA, 0x42, 0xFA, 0x42, 0xFA, 0x42}`
|
||||
- go1.19.6, linux/amd64, i5-13600K (DDR4)
|
||||
- go test -bench=. -benchmem -count=20
|
||||
|
||||
<hr/>
|
||||
|
||||
</details>
|
||||
|
||||
### Smaller Encodings with Struct Tags
|
||||
|
||||
Struct tags (`toarray`, `keyasint`, `omitempty`) reduce encoded size of structs.
|
||||
|
||||
<details><summary>Example encoding 3-level nested Go struct to 1 byte CBOR</summary><p/>
|
||||
|
||||
https://go.dev/play/p/YxwvfPdFQG2
|
||||
|
||||
```Go
|
||||
// Example encoding nested struct (with omitempty tag)
|
||||
// - encoding/json: 18 byte JSON
|
||||
// - fxamacker/cbor: 1 byte CBOR
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/fxamacker/cbor/v2"
|
||||
)
|
||||
|
||||
type GrandChild struct {
|
||||
Quux int `json:",omitempty"`
|
||||
}
|
||||
|
||||
type Child struct {
|
||||
Baz int `json:",omitempty"`
|
||||
Qux GrandChild `json:",omitempty"`
|
||||
}
|
||||
|
||||
type Parent struct {
|
||||
Foo Child `json:",omitempty"`
|
||||
Bar int `json:",omitempty"`
|
||||
}
|
||||
|
||||
func cb() {
|
||||
results, _ := cbor.Marshal(Parent{})
|
||||
fmt.Println("hex(CBOR): " + hex.EncodeToString(results))
|
||||
|
||||
text, _ := cbor.Diagnose(results) // Diagnostic Notation
|
||||
fmt.Println("DN: " + text)
|
||||
}
|
||||
|
||||
func js() {
|
||||
results, _ := json.Marshal(Parent{})
|
||||
fmt.Println("hex(JSON): " + hex.EncodeToString(results))
|
||||
|
||||
text := string(results) // JSON
|
||||
fmt.Println("JSON: " + text)
|
||||
}
|
||||
|
||||
func main() {
|
||||
cb()
|
||||
fmt.Println("-------------")
|
||||
js()
|
||||
}
|
||||
```
|
||||
|
||||
Output (DN is Diagnostic Notation):
|
||||
```
|
||||
hex(CBOR): a0
|
||||
DN: {}
|
||||
-------------
|
||||
hex(JSON): 7b22466f6f223a7b22517578223a7b7d7d7d
|
||||
JSON: {"Foo":{"Qux":{}}}
|
||||
```
|
||||
|
||||
<hr/>
|
||||
|
||||
</details>
|
||||
|
||||
Example using different struct tags together:
|
||||
|
||||

|
||||
|
||||
API is mostly same as `encoding/json`, plus interfaces that simplify concurrency for CBOR options.
|
||||
|
||||
## Quick Start
|
||||
|
||||
__Install__: `go get github.com/fxamacker/cbor/v2` and `import "github.com/fxamacker/cbor/v2"`.
|
||||
|
||||
### Key Points
|
||||
|
||||
This library can encode and decode CBOR (RFC 8949) and CBOR Sequences (RFC 8742).
|
||||
|
||||
- __CBOR data item__ is a single piece of CBOR data and its structure may contain 0 or more nested data items.
|
||||
- __CBOR sequence__ is a concatenation of 0 or more encoded CBOR data items.
|
||||
|
||||
Configurable limits and options can be used to balance trade-offs.
|
||||
|
||||
- Encoding and decoding modes are created from options (settings).
|
||||
- Modes can be created at startup and reused.
|
||||
- Modes are safe for concurrent use.
|
||||
|
||||
### Default Mode
|
||||
|
||||
Package level functions only use this library's default settings.
|
||||
They provide the "default mode" of encoding and decoding.
|
||||
|
||||
```go
|
||||
// API matches encoding/json for Marshal, Unmarshal, Encode, Decode, etc.
|
||||
b, err = cbor.Marshal(v) // encode v to []byte b
|
||||
err = cbor.Unmarshal(b, &v) // decode []byte b to v
|
||||
decoder = cbor.NewDecoder(r) // create decoder with io.Reader r
|
||||
err = decoder.Decode(&v) // decode a CBOR data item to v
|
||||
|
||||
// v2.7.0 added MarshalToBuffer() and UserBufferEncMode interface.
|
||||
err = cbor.MarshalToBuffer(v, b) // encode v to b instead of using built-in buf pool.
|
||||
|
||||
// v2.5.0 added new functions that return remaining bytes.
|
||||
|
||||
// UnmarshalFirst decodes first CBOR data item and returns remaining bytes.
|
||||
rest, err = cbor.UnmarshalFirst(b, &v) // decode []byte b to v
|
||||
|
||||
// DiagnoseFirst translates first CBOR data item to text and returns remaining bytes.
|
||||
text, rest, err = cbor.DiagnoseFirst(b) // decode []byte b to Diagnostic Notation text
|
||||
|
||||
// NOTE: Unmarshal returns ExtraneousDataError if there are remaining bytes,
|
||||
// but new funcs UnmarshalFirst and DiagnoseFirst do not.
|
||||
```
|
||||
|
||||
__IMPORTANT__: 👉 CBOR settings allow trade-offs between speed, security, encoding size, etc.
|
||||
|
||||
- Different CBOR libraries may use different default settings.
|
||||
- CBOR-based formats or protocols usually require specific settings.
|
||||
|
||||
For example, WebAuthn uses "CTAP2 Canonical CBOR" which is available as a preset.
|
||||
|
||||
### Presets
|
||||
|
||||
Presets can be used as-is or as a starting point for custom settings.
|
||||
|
||||
```go
|
||||
// EncOptions is a struct of encoder settings.
|
||||
func CoreDetEncOptions() EncOptions // RFC 8949 Core Deterministic Encoding
|
||||
func PreferredUnsortedEncOptions() EncOptions // RFC 8949 Preferred Serialization
|
||||
func CanonicalEncOptions() EncOptions // RFC 7049 Canonical CBOR
|
||||
func CTAP2EncOptions() EncOptions // FIDO2 CTAP2 Canonical CBOR
|
||||
```
|
||||
|
||||
Presets are used to create custom modes.
|
||||
|
||||
### Custom Modes
|
||||
|
||||
Modes are created from settings. Once created, modes have immutable settings.
|
||||
|
||||
💡 Create the mode at startup and reuse it. It is safe for concurrent use.
|
||||
|
||||
```Go
|
||||
// Create encoding mode.
|
||||
opts := cbor.CoreDetEncOptions() // use preset options as a starting point
|
||||
opts.Time = cbor.TimeUnix // change any settings if needed
|
||||
em, err := opts.EncMode() // create an immutable encoding mode
|
||||
|
||||
// Reuse the encoding mode. It is safe for concurrent use.
|
||||
|
||||
// API matches encoding/json.
|
||||
b, err := em.Marshal(v) // encode v to []byte b
|
||||
encoder := em.NewEncoder(w) // create encoder with io.Writer w
|
||||
err := encoder.Encode(v) // encode v to io.Writer w
|
||||
```
|
||||
|
||||
Default mode and custom modes automatically apply struct tags.
|
||||
|
||||
### User Specified Buffer for Encoding (v2.7.0)
|
||||
|
||||
`UserBufferEncMode` interface extends `EncMode` interface to add `MarshalToBuffer()`. It accepts a user-specified buffer instead of using built-in buffer pool.
|
||||
|
||||
```Go
|
||||
em, err := myEncOptions.UserBufferEncMode() // create UserBufferEncMode mode
|
||||
|
||||
var buf bytes.Buffer
|
||||
err = em.MarshalToBuffer(v, &buf) // encode v to provided buf
|
||||
```
|
||||
|
||||
### Struct Tags
|
||||
|
||||
Struct tags (`toarray`, `keyasint`, `omitempty`) reduce encoded size of structs.
|
||||
|
||||
<details><summary>Example encoding 3-level nested Go struct to 1 byte CBOR</summary><p/>
|
||||
|
||||
https://go.dev/play/p/YxwvfPdFQG2
|
||||
|
||||
```Go
|
||||
// Example encoding nested struct (with omitempty tag)
|
||||
// - encoding/json: 18 byte JSON
|
||||
// - fxamacker/cbor: 1 byte CBOR
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/fxamacker/cbor/v2"
|
||||
)
|
||||
|
||||
type GrandChild struct {
|
||||
Quux int `json:",omitempty"`
|
||||
}
|
||||
|
||||
type Child struct {
|
||||
Baz int `json:",omitempty"`
|
||||
Qux GrandChild `json:",omitempty"`
|
||||
}
|
||||
|
||||
type Parent struct {
|
||||
Foo Child `json:",omitempty"`
|
||||
Bar int `json:",omitempty"`
|
||||
}
|
||||
|
||||
func cb() {
|
||||
results, _ := cbor.Marshal(Parent{})
|
||||
fmt.Println("hex(CBOR): " + hex.EncodeToString(results))
|
||||
|
||||
text, _ := cbor.Diagnose(results) // Diagnostic Notation
|
||||
fmt.Println("DN: " + text)
|
||||
}
|
||||
|
||||
func js() {
|
||||
results, _ := json.Marshal(Parent{})
|
||||
fmt.Println("hex(JSON): " + hex.EncodeToString(results))
|
||||
|
||||
text := string(results) // JSON
|
||||
fmt.Println("JSON: " + text)
|
||||
}
|
||||
|
||||
func main() {
|
||||
cb()
|
||||
fmt.Println("-------------")
|
||||
js()
|
||||
}
|
||||
```
|
||||
|
||||
Output (DN is Diagnostic Notation):
|
||||
```
|
||||
hex(CBOR): a0
|
||||
DN: {}
|
||||
-------------
|
||||
hex(JSON): 7b22466f6f223a7b22517578223a7b7d7d7d
|
||||
JSON: {"Foo":{"Qux":{}}}
|
||||
```
|
||||
|
||||
<hr/>
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary>Example using several struct tags</summary><p/>
|
||||
|
||||

|
||||
|
||||
</details>
|
||||
|
||||
Struct tags simplify use of CBOR-based protocols that require CBOR arrays or maps with integer keys.
|
||||
|
||||
### CBOR Tags
|
||||
|
||||
CBOR tags are specified in a `TagSet`.
|
||||
|
||||
Custom modes can be created with a `TagSet` to handle CBOR tags.
|
||||
|
||||
```go
|
||||
em, err := opts.EncMode() // no CBOR tags
|
||||
em, err := opts.EncModeWithTags(ts) // immutable CBOR tags
|
||||
em, err := opts.EncModeWithSharedTags(ts) // mutable shared CBOR tags
|
||||
```
|
||||
|
||||
`TagSet` and modes using it are safe for concurrent use. Equivalent API is available for `DecMode`.
|
||||
|
||||
<details><summary>Example using TagSet and TagOptions</summary><p/>
|
||||
|
||||
```go
|
||||
// Use signedCWT struct defined in "Decoding CWT" example.
|
||||
|
||||
// Create TagSet (safe for concurrency).
|
||||
tags := cbor.NewTagSet()
|
||||
// Register tag COSE_Sign1 18 with signedCWT type.
|
||||
tags.Add(
|
||||
cbor.TagOptions{EncTag: cbor.EncTagRequired, DecTag: cbor.DecTagRequired},
|
||||
reflect.TypeOf(signedCWT{}),
|
||||
18)
|
||||
|
||||
// Create DecMode with immutable tags.
|
||||
dm, _ := cbor.DecOptions{}.DecModeWithTags(tags)
|
||||
|
||||
// Unmarshal to signedCWT with tag support.
|
||||
var v signedCWT
|
||||
if err := dm.Unmarshal(data, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create EncMode with immutable tags.
|
||||
em, _ := cbor.EncOptions{}.EncModeWithTags(tags)
|
||||
|
||||
// Marshal signedCWT with tag number.
|
||||
if data, err := cbor.Marshal(v); err != nil {
|
||||
return err
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Functions and Interfaces
|
||||
|
||||
<details><summary>Functions and interfaces at a glance</summary><p/>
|
||||
|
||||
Common functions with same API as `encoding/json`:
|
||||
- `Marshal`, `Unmarshal`
|
||||
- `NewEncoder`, `(*Encoder).Encode`
|
||||
- `NewDecoder`, `(*Decoder).Decode`
|
||||
|
||||
NOTE: `Unmarshal` will return `ExtraneousDataError` if there are remaining bytes
|
||||
because RFC 8949 treats CBOR data item with remaining bytes as malformed.
|
||||
- 💡 Use `UnmarshalFirst` to decode first CBOR data item and return any remaining bytes.
|
||||
|
||||
Other useful functions:
|
||||
- `Diagnose`, `DiagnoseFirst` produce human-readable [Extended Diagnostic Notation](https://www.rfc-editor.org/rfc/rfc8610.html#appendix-G) from CBOR data.
|
||||
- `UnmarshalFirst` decodes first CBOR data item and return any remaining bytes.
|
||||
- `Wellformed` returns true if the the CBOR data item is well-formed.
|
||||
|
||||
Interfaces identical or comparable to Go `encoding` packages include:
|
||||
`Marshaler`, `Unmarshaler`, `BinaryMarshaler`, and `BinaryUnmarshaler`.
|
||||
|
||||
The `RawMessage` type can be used to delay CBOR decoding or precompute CBOR encoding.
|
||||
|
||||
</details>
|
||||
|
||||
### Security Tips
|
||||
|
||||
🔒 Use Go's `io.LimitReader` to limit size when decoding very large or indefinite size data.
|
||||
|
||||
Default limits may need to be increased for systems handling very large data (e.g. blockchains).
|
||||
|
||||
`DecOptions` can be used to modify default limits for `MaxArrayElements`, `MaxMapPairs`, and `MaxNestedLevels`.
|
||||
|
||||
## Status
|
||||
|
||||
v2.7.0 (June 23, 2024) adds features and improvements that help large projects (e.g. Kubernetes) use CBOR as an alternative to JSON and Protocol Buffers. Other improvements include speedups, improved memory use, bug fixes, new serialization options, etc. It passed fuzz tests (5+ billion executions) and is production quality.
|
||||
|
||||
For more details, see [release notes](https://github.com/fxamacker/cbor/releases).
|
||||
|
||||
### Prior Release
|
||||
|
||||
[v2.6.0](https://github.com/fxamacker/cbor/releases/tag/v2.6.0) (February 2024) adds important new features, optimizations, and bug fixes. It is especially useful to systems that need to convert data between CBOR and JSON. New options and optimizations improve handling of bignum, integers, maps, and strings.
|
||||
|
||||
v2.5.0 was released on Sunday, August 13, 2023 with new features and important bug fixes. It is fuzz tested and production quality after extended beta [v2.5.0-beta](https://github.com/fxamacker/cbor/releases/tag/v2.5.0-beta) (Dec 2022) -> [v2.5.0](https://github.com/fxamacker/cbor/releases/tag/v2.5.0) (Aug 2023).
|
||||
|
||||
__IMPORTANT__: 👉 Before upgrading from v2.4 or older release, please read the notable changes highlighted in the release notes. v2.5.0 is a large release with bug fixes to error handling for extraneous data in `Unmarshal`, etc. that should be reviewed before upgrading.
|
||||
|
||||
See [v2.5.0 release notes](https://github.com/fxamacker/cbor/releases/tag/v2.5.0) for list of new features, improvements, and bug fixes.
|
||||
|
||||
See ["Version and API Changes"](https://github.com/fxamacker/cbor#versions-and-api-changes) section for more info about version numbering, etc.
|
||||
|
||||
<!--
|
||||
<details><summary>👉 Benchmark Comparison: v2.4.0 vs v2.5.0</summary><p/>
|
||||
|
||||
TODO: Update to v2.4.0 vs 2.5.0 (not beta2).
|
||||
|
||||
Comparison of v2.4.0 vs v2.5.0-beta2 provided by @448 (edited to fit width).
|
||||
|
||||
PR [#382](https://github.com/fxamacker/cbor/pull/382) returns buffer to pool in `Encode()`. It adds a bit of overhead to `Encode()` but `NewEncoder().Encode()` is a lot faster and uses less memory as shown here:
|
||||
|
||||
```
|
||||
$ benchstat bench-v2.4.0.log bench-f9e6291.log
|
||||
goos: linux
|
||||
goarch: amd64
|
||||
pkg: github.com/fxamacker/cbor/v2
|
||||
cpu: 12th Gen Intel(R) Core(TM) i7-12700H
|
||||
│ bench-v2.4.0.log │ bench-f9e6291.log │
|
||||
│ sec/op │ sec/op vs base │
|
||||
NewEncoderEncode/Go_bool_to_CBOR_bool-20 236.70n ± 2% 58.04n ± 1% -75.48% (p=0.000 n=10)
|
||||
NewEncoderEncode/Go_uint64_to_CBOR_positive_int-20 238.00n ± 2% 63.93n ± 1% -73.14% (p=0.000 n=10)
|
||||
NewEncoderEncode/Go_int64_to_CBOR_negative_int-20 238.65n ± 2% 64.88n ± 1% -72.81% (p=0.000 n=10)
|
||||
NewEncoderEncode/Go_float64_to_CBOR_float-20 242.00n ± 2% 63.00n ± 1% -73.97% (p=0.000 n=10)
|
||||
NewEncoderEncode/Go_[]uint8_to_CBOR_bytes-20 245.60n ± 1% 68.55n ± 1% -72.09% (p=0.000 n=10)
|
||||
NewEncoderEncode/Go_string_to_CBOR_text-20 243.20n ± 3% 68.39n ± 1% -71.88% (p=0.000 n=10)
|
||||
NewEncoderEncode/Go_[]int_to_CBOR_array-20 563.0n ± 2% 378.3n ± 0% -32.81% (p=0.000 n=10)
|
||||
NewEncoderEncode/Go_map[string]string_to_CBOR_map-20 2.043µ ± 2% 1.906µ ± 2% -6.75% (p=0.000 n=10)
|
||||
geomean 349.7n 122.7n -64.92%
|
||||
|
||||
│ bench-v2.4.0.log │ bench-f9e6291.log │
|
||||
│ B/op │ B/op vs base │
|
||||
NewEncoderEncode/Go_bool_to_CBOR_bool-20 128.0 ± 0% 0.0 ± 0% -100.00% (p=0.000 n=10)
|
||||
NewEncoderEncode/Go_uint64_to_CBOR_positive_int-20 128.0 ± 0% 0.0 ± 0% -100.00% (p=0.000 n=10)
|
||||
NewEncoderEncode/Go_int64_to_CBOR_negative_int-20 128.0 ± 0% 0.0 ± 0% -100.00% (p=0.000 n=10)
|
||||
NewEncoderEncode/Go_float64_to_CBOR_float-20 128.0 ± 0% 0.0 ± 0% -100.00% (p=0.000 n=10)
|
||||
NewEncoderEncode/Go_[]uint8_to_CBOR_bytes-20 128.0 ± 0% 0.0 ± 0% -100.00% (p=0.000 n=10)
|
||||
NewEncoderEncode/Go_string_to_CBOR_text-20 128.0 ± 0% 0.0 ± 0% -100.00% (p=0.000 n=10)
|
||||
NewEncoderEncode/Go_[]int_to_CBOR_array-20 128.0 ± 0% 0.0 ± 0% -100.00% (p=0.000 n=10)
|
||||
NewEncoderEncode/Go_map[string]string_to_CBOR_map-20 544.0 ± 0% 416.0 ± 0% -23.53% (p=0.000 n=10)
|
||||
geomean 153.4 ? ¹ ²
|
||||
¹ summaries must be >0 to compute geomean
|
||||
² ratios must be >0 to compute geomean
|
||||
|
||||
│ bench-v2.4.0.log │ bench-f9e6291.log │
|
||||
│ allocs/op │ allocs/op vs base │
|
||||
NewEncoderEncode/Go_bool_to_CBOR_bool-20 2.000 ± 0% 0.000 ± 0% -100.00% (p=0.000 n=10)
|
||||
NewEncoderEncode/Go_uint64_to_CBOR_positive_int-20 2.000 ± 0% 0.000 ± 0% -100.00% (p=0.000 n=10)
|
||||
NewEncoderEncode/Go_int64_to_CBOR_negative_int-20 2.000 ± 0% 0.000 ± 0% -100.00% (p=0.000 n=10)
|
||||
NewEncoderEncode/Go_float64_to_CBOR_float-20 2.000 ± 0% 0.000 ± 0% -100.00% (p=0.000 n=10)
|
||||
NewEncoderEncode/Go_[]uint8_to_CBOR_bytes-20 2.000 ± 0% 0.000 ± 0% -100.00% (p=0.000 n=10)
|
||||
NewEncoderEncode/Go_string_to_CBOR_text-20 2.000 ± 0% 0.000 ± 0% -100.00% (p=0.000 n=10)
|
||||
NewEncoderEncode/Go_[]int_to_CBOR_array-20 2.000 ± 0% 0.000 ± 0% -100.00% (p=0.000 n=10)
|
||||
NewEncoderEncode/Go_map[string]string_to_CBOR_map-20 28.00 ± 0% 26.00 ± 0% -7.14% (p=0.000 n=10)
|
||||
geomean 2.782 ? ¹ ²
|
||||
¹ summaries must be >0 to compute geomean
|
||||
² ratios must be >0 to compute geomean
|
||||
```
|
||||
|
||||
</details>
|
||||
-->
|
||||
|
||||
## Who uses fxamacker/cbor
|
||||
|
||||
`fxamacker/cbor` is used in projects by Arm Ltd., Berlin Institute of Health at Charité, Chainlink, Cisco, Confidential Computing Consortium, ConsenSys, Dapper Labs, EdgeX Foundry, F5, FIDO Alliance, Fraunhofer‑AISEC, Kubernetes, Let's Encrypt (ISRG), Linux Foundation, Matrix.org, Microsoft, Mozilla, National Cybersecurity Agency of France (govt), Netherlands (govt), Oasis Protocol, Smallstep, Tailscale, Taurus SA, Teleport, TIBCO, and others.
|
||||
|
||||
`fxamacker/cbor` passed multiple confidential security assessments. A [nonconfidential security assessment](https://github.com/veraison/go-cose/blob/v1.0.0-rc.1/reports/NCC_Microsoft-go-cose-Report_2022-05-26_v1.0.pdf) (prepared by NCC Group for Microsoft Corporation) includes a subset of fxamacker/cbor v2.4.0 in its scope.
|
||||
|
||||
## Standards
|
||||
|
||||
`fxamacker/cbor` is a CBOR codec in full conformance with [IETF STD 94 (RFC 8949)](https://www.rfc-editor.org/info/std94). It also supports CBOR Sequences ([RFC 8742](https://www.rfc-editor.org/rfc/rfc8742.html)) and Extended Diagnostic Notation ([Appendix G of RFC 8610](https://www.rfc-editor.org/rfc/rfc8610.html#appendix-G)).
|
||||
|
||||
Notable CBOR features include:
|
||||
|
||||
| CBOR Feature | Description |
|
||||
| :--- | :--- |
|
||||
| CBOR tags | API supports built-in and user-defined tags. |
|
||||
| Preferred serialization | Integers encode to fewest bytes. Optional float64 → float32 → float16. |
|
||||
| Map key sorting | Unsorted, length-first (Canonical CBOR), and bytewise-lexicographic (CTAP2). |
|
||||
| Duplicate map keys | Always forbid for encoding and option to allow/forbid for decoding. |
|
||||
| Indefinite length data | Option to allow/forbid for encoding and decoding. |
|
||||
| Well-formedness | Always checked and enforced. |
|
||||
| Basic validity checks | Optionally check UTF-8 validity and duplicate map keys. |
|
||||
| Security considerations | Prevent integer overflow and resource exhaustion (RFC 8949 Section 10). |
|
||||
|
||||
Known limitations are noted in the [Limitations section](#limitations).
|
||||
|
||||
Go nil values for slices, maps, pointers, etc. are encoded as CBOR null. Empty slices, maps, etc. are encoded as empty CBOR arrays and maps.
|
||||
|
||||
Decoder checks for all required well-formedness errors, including all "subkinds" of syntax errors and too little data.
|
||||
|
||||
After well-formedness is verified, basic validity errors are handled as follows:
|
||||
|
||||
* Invalid UTF-8 string: Decoder has option to check and return invalid UTF-8 string error. This check is enabled by default.
|
||||
* Duplicate keys in a map: Decoder has options to ignore or enforce rejection of duplicate map keys.
|
||||
|
||||
When decoding well-formed CBOR arrays and maps, decoder saves the first error it encounters and continues with the next item. Options to handle this differently may be added in the future.
|
||||
|
||||
By default, decoder treats time values of floating-point NaN and Infinity as if they are CBOR Null or CBOR Undefined.
|
||||
|
||||
__Click to expand topic:__
|
||||
|
||||
<details>
|
||||
<summary>Duplicate Map Keys</summary><p>
|
||||
|
||||
This library provides options for fast detection and rejection of duplicate map keys based on applying a Go-specific data model to CBOR's extended generic data model in order to determine duplicate vs distinct map keys. Detection relies on whether the CBOR map key would be a duplicate "key" when decoded and applied to the user-provided Go map or struct.
|
||||
|
||||
`DupMapKeyQuiet` turns off detection of duplicate map keys. It tries to use a "keep fastest" method by choosing either "keep first" or "keep last" depending on the Go data type.
|
||||
|
||||
`DupMapKeyEnforcedAPF` enforces detection and rejection of duplidate map keys. Decoding stops immediately and returns `DupMapKeyError` when the first duplicate key is detected. The error includes the duplicate map key and the index number.
|
||||
|
||||
APF suffix means "Allow Partial Fill" so the destination map or struct can contain some decoded values at the time of error. It is the caller's responsibility to respond to the `DupMapKeyError` by discarding the partially filled result if that's required by their protocol.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Tag Validity</summary><p>
|
||||
|
||||
This library checks tag validity for built-in tags (currently tag numbers 0, 1, 2, 3, and 55799):
|
||||
|
||||
* Inadmissible type for tag content
|
||||
* Inadmissible value for tag content
|
||||
|
||||
Unknown tag data items (not tag number 0, 1, 2, 3, or 55799) are handled in two ways:
|
||||
|
||||
* When decoding into an empty interface, unknown tag data item will be decoded into `cbor.Tag` data type, which contains tag number and tag content. The tag content will be decoded into the default Go data type for the CBOR data type.
|
||||
* When decoding into other Go types, unknown tag data item is decoded into the specified Go type. If Go type is registered with a tag number, the tag number can optionally be verified.
|
||||
|
||||
Decoder also has an option to forbid tag data items (treat any tag data item as error) which is specified by protocols such as CTAP2 Canonical CBOR.
|
||||
|
||||
For more information, see [decoding options](#decoding-options-1) and [tag options](#tag-options).
|
||||
|
||||
</details>
|
||||
|
||||
## Limitations
|
||||
|
||||
If any of these limitations prevent you from using this library, please open an issue along with a link to your project.
|
||||
|
||||
* CBOR `Undefined` (0xf7) value decodes to Go's `nil` value. CBOR `Null` (0xf6) more closely matches Go's `nil`.
|
||||
* CBOR map keys with data types not supported by Go for map keys are ignored and an error is returned after continuing to decode remaining items.
|
||||
* When decoding registered CBOR tag data to interface type, decoder creates a pointer to registered Go type matching CBOR tag number. Requiring a pointer for this is a Go limitation.
|
||||
|
||||
## Fuzzing and Code Coverage
|
||||
|
||||
__Code coverage__ is always 95% or higher (with `go test -cover`) when tagging a release.
|
||||
|
||||
__Coverage-guided fuzzing__ must pass billions of execs using before tagging a release. Fuzzing is done using nonpublic code which may eventually get merged into this project. Until then, reports like OpenSSF Scorecard can't detect fuzz tests being used by this project.
|
||||
|
||||
<hr>
|
||||
|
||||
## Versions and API Changes
|
||||
This project uses [Semantic Versioning](https://semver.org), so the API is always backwards compatible unless the major version number changes.
|
||||
|
||||
These functions have signatures identical to encoding/json and their API will continue to match `encoding/json` even after major new releases:
|
||||
`Marshal`, `Unmarshal`, `NewEncoder`, `NewDecoder`, `(*Encoder).Encode`, and `(*Decoder).Decode`.
|
||||
|
||||
Exclusions from SemVer:
|
||||
- Newly added API documented as "subject to change".
|
||||
- Newly added API in the master branch that has never been tagged in non-beta release.
|
||||
- If function parameters are unchanged, bug fixes that change behavior (e.g. return error for edge case was missed in prior version). We try to highlight these in the release notes and add extended beta period. E.g. [v2.5.0-beta](https://github.com/fxamacker/cbor/releases/tag/v2.5.0-beta) (Dec 2022) -> [v2.5.0](https://github.com/fxamacker/cbor/releases/tag/v2.5.0) (Aug 2023).
|
||||
|
||||
This project avoids breaking changes to behavior of encoding and decoding functions unless required to improve conformance with supported RFCs (e.g. RFC 8949, RFC 8742, etc.) Visible changes that don't improve conformance to standards are typically made available as new opt-in settings or new functions.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project has adopted the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md). Contact [faye.github@gmail.com](mailto:faye.github@gmail.com) with any questions or comments.
|
||||
|
||||
## Contributing
|
||||
|
||||
Please open an issue before beginning work on a PR. The improvement may have already been considered, etc.
|
||||
|
||||
For more info, see [How to Contribute](CONTRIBUTING.md).
|
||||
|
||||
## Security Policy
|
||||
|
||||
Security fixes are provided for the latest released version of fxamacker/cbor.
|
||||
|
||||
For the full text of the Security Policy, see [SECURITY.md](SECURITY.md).
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
Many thanks to all the contributors on this project!
|
||||
|
||||
I'm especially grateful to Bastian Müller and Dieter Shirley for suggesting and collaborating on CBOR stream mode, and much more.
|
||||
|
||||
I'm very grateful to Stefan Tatschner, Yawning Angel, Jernej Kos, x448, ZenGround0, and Jakob Borg for their contributions or support in the very early days.
|
||||
|
||||
Big thanks to Ben Luddy for his contributions in v2.6.0 and v2.7.0.
|
||||
|
||||
This library clearly wouldn't be possible without Carsten Bormann authoring CBOR RFCs.
|
||||
|
||||
Special thanks to Laurence Lundblade and Jeffrey Yasskin for their help on IETF mailing list or at [7049bis](https://github.com/cbor-wg/CBORbis).
|
||||
|
||||
Huge thanks to The Go Authors for creating a fun and practical programming language with batteries included!
|
||||
|
||||
This library uses `x448/float16` which used to be included. As a standalone package, `x448/float16` is useful to other projects as well.
|
||||
|
||||
## License
|
||||
|
||||
Copyright © 2019-2024 [Faye Amacker](https://github.com/fxamacker).
|
||||
|
||||
fxamacker/cbor is licensed under the MIT License. See [LICENSE](LICENSE) for the full license text.
|
||||
|
||||
<hr>
|
|
@ -0,0 +1,7 @@
|
|||
# Security Policy
|
||||
|
||||
Security fixes are provided for the latest released version of fxamacker/cbor.
|
||||
|
||||
If the security vulnerability is already known to the public, then you can open an issue as a bug report.
|
||||
|
||||
To report security vulnerabilities not yet known to the public, please email faye.github@gmail.com and allow time for the problem to be resolved before reporting it to the public.
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright (c) Faye Amacker. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
|
||||
package cbor
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// ByteString represents CBOR byte string (major type 2). ByteString can be used
|
||||
// when using a Go []byte is not possible or convenient. For example, Go doesn't
|
||||
// allow []byte as map key, so ByteString can be used to support data formats
|
||||
// having CBOR map with byte string keys. ByteString can also be used to
|
||||
// encode invalid UTF-8 string as CBOR byte string.
|
||||
// See DecOption.MapKeyByteStringMode for more details.
|
||||
type ByteString string
|
||||
|
||||
// Bytes returns bytes representing ByteString.
|
||||
func (bs ByteString) Bytes() []byte {
|
||||
return []byte(bs)
|
||||
}
|
||||
|
||||
// MarshalCBOR encodes ByteString as CBOR byte string (major type 2).
|
||||
func (bs ByteString) MarshalCBOR() ([]byte, error) {
|
||||
e := getEncodeBuffer()
|
||||
defer putEncodeBuffer(e)
|
||||
|
||||
// Encode length
|
||||
encodeHead(e, byte(cborTypeByteString), uint64(len(bs)))
|
||||
|
||||
// Encode data
|
||||
buf := make([]byte, e.Len()+len(bs))
|
||||
n := copy(buf, e.Bytes())
|
||||
copy(buf[n:], bs)
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
// UnmarshalCBOR decodes CBOR byte string (major type 2) to ByteString.
|
||||
// Decoding CBOR null and CBOR undefined sets ByteString to be empty.
|
||||
func (bs *ByteString) UnmarshalCBOR(data []byte) error {
|
||||
if bs == nil {
|
||||
return errors.New("cbor.ByteString: UnmarshalCBOR on nil pointer")
|
||||
}
|
||||
|
||||
// Decoding CBOR null and CBOR undefined to ByteString resets data.
|
||||
// This behavior is similar to decoding CBOR null and CBOR undefined to []byte.
|
||||
if len(data) == 1 && (data[0] == 0xf6 || data[0] == 0xf7) {
|
||||
*bs = ""
|
||||
return nil
|
||||
}
|
||||
|
||||
d := decoder{data: data, dm: defaultDecMode}
|
||||
|
||||
// Check if CBOR data type is byte string
|
||||
if typ := d.nextCBORType(); typ != cborTypeByteString {
|
||||
return &UnmarshalTypeError{CBORType: typ.String(), GoType: typeByteString.String()}
|
||||
}
|
||||
|
||||
b, _ := d.parseByteString()
|
||||
*bs = ByteString(b)
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,363 @@
|
|||
// Copyright (c) Faye Amacker. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
|
||||
package cbor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type encodeFuncs struct {
|
||||
ef encodeFunc
|
||||
ief isEmptyFunc
|
||||
}
|
||||
|
||||
var (
|
||||
decodingStructTypeCache sync.Map // map[reflect.Type]*decodingStructType
|
||||
encodingStructTypeCache sync.Map // map[reflect.Type]*encodingStructType
|
||||
encodeFuncCache sync.Map // map[reflect.Type]encodeFuncs
|
||||
typeInfoCache sync.Map // map[reflect.Type]*typeInfo
|
||||
)
|
||||
|
||||
type specialType int
|
||||
|
||||
const (
|
||||
specialTypeNone specialType = iota
|
||||
specialTypeUnmarshalerIface
|
||||
specialTypeEmptyIface
|
||||
specialTypeIface
|
||||
specialTypeTag
|
||||
specialTypeTime
|
||||
)
|
||||
|
||||
type typeInfo struct {
|
||||
elemTypeInfo *typeInfo
|
||||
keyTypeInfo *typeInfo
|
||||
typ reflect.Type
|
||||
kind reflect.Kind
|
||||
nonPtrType reflect.Type
|
||||
nonPtrKind reflect.Kind
|
||||
spclType specialType
|
||||
}
|
||||
|
||||
func newTypeInfo(t reflect.Type) *typeInfo {
|
||||
tInfo := typeInfo{typ: t, kind: t.Kind()}
|
||||
|
||||
for t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
|
||||
k := t.Kind()
|
||||
|
||||
tInfo.nonPtrType = t
|
||||
tInfo.nonPtrKind = k
|
||||
|
||||
if k == reflect.Interface {
|
||||
if t.NumMethod() == 0 {
|
||||
tInfo.spclType = specialTypeEmptyIface
|
||||
} else {
|
||||
tInfo.spclType = specialTypeIface
|
||||
}
|
||||
} else if t == typeTag {
|
||||
tInfo.spclType = specialTypeTag
|
||||
} else if t == typeTime {
|
||||
tInfo.spclType = specialTypeTime
|
||||
} else if reflect.PtrTo(t).Implements(typeUnmarshaler) {
|
||||
tInfo.spclType = specialTypeUnmarshalerIface
|
||||
}
|
||||
|
||||
switch k {
|
||||
case reflect.Array, reflect.Slice:
|
||||
tInfo.elemTypeInfo = getTypeInfo(t.Elem())
|
||||
case reflect.Map:
|
||||
tInfo.keyTypeInfo = getTypeInfo(t.Key())
|
||||
tInfo.elemTypeInfo = getTypeInfo(t.Elem())
|
||||
}
|
||||
|
||||
return &tInfo
|
||||
}
|
||||
|
||||
type decodingStructType struct {
|
||||
fields fields
|
||||
fieldIndicesByName map[string]int
|
||||
err error
|
||||
toArray bool
|
||||
}
|
||||
|
||||
// The stdlib errors.Join was introduced in Go 1.20, and we still support Go 1.17, so instead,
|
||||
// here's a very basic implementation of an aggregated error.
|
||||
type multierror []error
|
||||
|
||||
func (m multierror) Error() string {
|
||||
var sb strings.Builder
|
||||
for i, err := range m {
|
||||
sb.WriteString(err.Error())
|
||||
if i < len(m)-1 {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func getDecodingStructType(t reflect.Type) *decodingStructType {
|
||||
if v, _ := decodingStructTypeCache.Load(t); v != nil {
|
||||
return v.(*decodingStructType)
|
||||
}
|
||||
|
||||
flds, structOptions := getFields(t)
|
||||
|
||||
toArray := hasToArrayOption(structOptions)
|
||||
|
||||
var errs []error
|
||||
for i := 0; i < len(flds); i++ {
|
||||
if flds[i].keyAsInt {
|
||||
nameAsInt, numErr := strconv.Atoi(flds[i].name)
|
||||
if numErr != nil {
|
||||
errs = append(errs, errors.New("cbor: failed to parse field name \""+flds[i].name+"\" to int ("+numErr.Error()+")"))
|
||||
break
|
||||
}
|
||||
flds[i].nameAsInt = int64(nameAsInt)
|
||||
}
|
||||
|
||||
flds[i].typInfo = getTypeInfo(flds[i].typ)
|
||||
}
|
||||
|
||||
fieldIndicesByName := make(map[string]int, len(flds))
|
||||
for i, fld := range flds {
|
||||
if _, ok := fieldIndicesByName[fld.name]; ok {
|
||||
errs = append(errs, fmt.Errorf("cbor: two or more fields of %v have the same name %q", t, fld.name))
|
||||
continue
|
||||
}
|
||||
fieldIndicesByName[fld.name] = i
|
||||
}
|
||||
|
||||
var err error
|
||||
{
|
||||
var multi multierror
|
||||
for _, each := range errs {
|
||||
if each != nil {
|
||||
multi = append(multi, each)
|
||||
}
|
||||
}
|
||||
if len(multi) == 1 {
|
||||
err = multi[0]
|
||||
} else if len(multi) > 1 {
|
||||
err = multi
|
||||
}
|
||||
}
|
||||
|
||||
structType := &decodingStructType{
|
||||
fields: flds,
|
||||
fieldIndicesByName: fieldIndicesByName,
|
||||
err: err,
|
||||
toArray: toArray,
|
||||
}
|
||||
decodingStructTypeCache.Store(t, structType)
|
||||
return structType
|
||||
}
|
||||
|
||||
type encodingStructType struct {
|
||||
fields fields
|
||||
bytewiseFields fields
|
||||
lengthFirstFields fields
|
||||
omitEmptyFieldsIdx []int
|
||||
err error
|
||||
toArray bool
|
||||
}
|
||||
|
||||
func (st *encodingStructType) getFields(em *encMode) fields {
|
||||
switch em.sort {
|
||||
case SortNone, SortFastShuffle:
|
||||
return st.fields
|
||||
case SortLengthFirst:
|
||||
return st.lengthFirstFields
|
||||
default:
|
||||
return st.bytewiseFields
|
||||
}
|
||||
}
|
||||
|
||||
type bytewiseFieldSorter struct {
|
||||
fields fields
|
||||
}
|
||||
|
||||
func (x *bytewiseFieldSorter) Len() int {
|
||||
return len(x.fields)
|
||||
}
|
||||
|
||||
func (x *bytewiseFieldSorter) Swap(i, j int) {
|
||||
x.fields[i], x.fields[j] = x.fields[j], x.fields[i]
|
||||
}
|
||||
|
||||
func (x *bytewiseFieldSorter) Less(i, j int) bool {
|
||||
return bytes.Compare(x.fields[i].cborName, x.fields[j].cborName) <= 0
|
||||
}
|
||||
|
||||
type lengthFirstFieldSorter struct {
|
||||
fields fields
|
||||
}
|
||||
|
||||
func (x *lengthFirstFieldSorter) Len() int {
|
||||
return len(x.fields)
|
||||
}
|
||||
|
||||
func (x *lengthFirstFieldSorter) Swap(i, j int) {
|
||||
x.fields[i], x.fields[j] = x.fields[j], x.fields[i]
|
||||
}
|
||||
|
||||
func (x *lengthFirstFieldSorter) Less(i, j int) bool {
|
||||
if len(x.fields[i].cborName) != len(x.fields[j].cborName) {
|
||||
return len(x.fields[i].cborName) < len(x.fields[j].cborName)
|
||||
}
|
||||
return bytes.Compare(x.fields[i].cborName, x.fields[j].cborName) <= 0
|
||||
}
|
||||
|
||||
func getEncodingStructType(t reflect.Type) (*encodingStructType, error) {
|
||||
if v, _ := encodingStructTypeCache.Load(t); v != nil {
|
||||
structType := v.(*encodingStructType)
|
||||
return structType, structType.err
|
||||
}
|
||||
|
||||
flds, structOptions := getFields(t)
|
||||
|
||||
if hasToArrayOption(structOptions) {
|
||||
return getEncodingStructToArrayType(t, flds)
|
||||
}
|
||||
|
||||
var err error
|
||||
var hasKeyAsInt bool
|
||||
var hasKeyAsStr bool
|
||||
var omitEmptyIdx []int
|
||||
e := getEncodeBuffer()
|
||||
for i := 0; i < len(flds); i++ {
|
||||
// Get field's encodeFunc
|
||||
flds[i].ef, flds[i].ief = getEncodeFunc(flds[i].typ)
|
||||
if flds[i].ef == nil {
|
||||
err = &UnsupportedTypeError{t}
|
||||
break
|
||||
}
|
||||
|
||||
// Encode field name
|
||||
if flds[i].keyAsInt {
|
||||
nameAsInt, numErr := strconv.Atoi(flds[i].name)
|
||||
if numErr != nil {
|
||||
err = errors.New("cbor: failed to parse field name \"" + flds[i].name + "\" to int (" + numErr.Error() + ")")
|
||||
break
|
||||
}
|
||||
flds[i].nameAsInt = int64(nameAsInt)
|
||||
if nameAsInt >= 0 {
|
||||
encodeHead(e, byte(cborTypePositiveInt), uint64(nameAsInt))
|
||||
} else {
|
||||
n := nameAsInt*(-1) - 1
|
||||
encodeHead(e, byte(cborTypeNegativeInt), uint64(n))
|
||||
}
|
||||
flds[i].cborName = make([]byte, e.Len())
|
||||
copy(flds[i].cborName, e.Bytes())
|
||||
e.Reset()
|
||||
|
||||
hasKeyAsInt = true
|
||||
} else {
|
||||
encodeHead(e, byte(cborTypeTextString), uint64(len(flds[i].name)))
|
||||
flds[i].cborName = make([]byte, e.Len()+len(flds[i].name))
|
||||
n := copy(flds[i].cborName, e.Bytes())
|
||||
copy(flds[i].cborName[n:], flds[i].name)
|
||||
e.Reset()
|
||||
|
||||
// If cborName contains a text string, then cborNameByteString contains a
|
||||
// string that has the byte string major type but is otherwise identical to
|
||||
// cborName.
|
||||
flds[i].cborNameByteString = make([]byte, len(flds[i].cborName))
|
||||
copy(flds[i].cborNameByteString, flds[i].cborName)
|
||||
// Reset encoded CBOR type to byte string, preserving the "additional
|
||||
// information" bits:
|
||||
flds[i].cborNameByteString[0] = byte(cborTypeByteString) |
|
||||
getAdditionalInformation(flds[i].cborNameByteString[0])
|
||||
|
||||
hasKeyAsStr = true
|
||||
}
|
||||
|
||||
// Check if field can be omitted when empty
|
||||
if flds[i].omitEmpty {
|
||||
omitEmptyIdx = append(omitEmptyIdx, i)
|
||||
}
|
||||
}
|
||||
putEncodeBuffer(e)
|
||||
|
||||
if err != nil {
|
||||
structType := &encodingStructType{err: err}
|
||||
encodingStructTypeCache.Store(t, structType)
|
||||
return structType, structType.err
|
||||
}
|
||||
|
||||
// Sort fields by canonical order
|
||||
bytewiseFields := make(fields, len(flds))
|
||||
copy(bytewiseFields, flds)
|
||||
sort.Sort(&bytewiseFieldSorter{bytewiseFields})
|
||||
|
||||
lengthFirstFields := bytewiseFields
|
||||
if hasKeyAsInt && hasKeyAsStr {
|
||||
lengthFirstFields = make(fields, len(flds))
|
||||
copy(lengthFirstFields, flds)
|
||||
sort.Sort(&lengthFirstFieldSorter{lengthFirstFields})
|
||||
}
|
||||
|
||||
structType := &encodingStructType{
|
||||
fields: flds,
|
||||
bytewiseFields: bytewiseFields,
|
||||
lengthFirstFields: lengthFirstFields,
|
||||
omitEmptyFieldsIdx: omitEmptyIdx,
|
||||
}
|
||||
|
||||
encodingStructTypeCache.Store(t, structType)
|
||||
return structType, structType.err
|
||||
}
|
||||
|
||||
func getEncodingStructToArrayType(t reflect.Type, flds fields) (*encodingStructType, error) {
|
||||
for i := 0; i < len(flds); i++ {
|
||||
// Get field's encodeFunc
|
||||
flds[i].ef, flds[i].ief = getEncodeFunc(flds[i].typ)
|
||||
if flds[i].ef == nil {
|
||||
structType := &encodingStructType{err: &UnsupportedTypeError{t}}
|
||||
encodingStructTypeCache.Store(t, structType)
|
||||
return structType, structType.err
|
||||
}
|
||||
}
|
||||
|
||||
structType := &encodingStructType{
|
||||
fields: flds,
|
||||
toArray: true,
|
||||
}
|
||||
encodingStructTypeCache.Store(t, structType)
|
||||
return structType, structType.err
|
||||
}
|
||||
|
||||
func getEncodeFunc(t reflect.Type) (encodeFunc, isEmptyFunc) {
|
||||
if v, _ := encodeFuncCache.Load(t); v != nil {
|
||||
fs := v.(encodeFuncs)
|
||||
return fs.ef, fs.ief
|
||||
}
|
||||
ef, ief := getEncodeFuncInternal(t)
|
||||
encodeFuncCache.Store(t, encodeFuncs{ef, ief})
|
||||
return ef, ief
|
||||
}
|
||||
|
||||
func getTypeInfo(t reflect.Type) *typeInfo {
|
||||
if v, _ := typeInfoCache.Load(t); v != nil {
|
||||
return v.(*typeInfo)
|
||||
}
|
||||
tInfo := newTypeInfo(t)
|
||||
typeInfoCache.Store(t, tInfo)
|
||||
return tInfo
|
||||
}
|
||||
|
||||
func hasToArrayOption(tag string) bool {
|
||||
s := ",toarray"
|
||||
idx := strings.Index(tag, s)
|
||||
return idx >= 0 && (len(tag) == idx+len(s) || tag[idx+len(s)] == ',')
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
// Copyright (c) Faye Amacker. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
|
||||
package cbor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type cborType uint8
|
||||
|
||||
const (
|
||||
cborTypePositiveInt cborType = 0x00
|
||||
cborTypeNegativeInt cborType = 0x20
|
||||
cborTypeByteString cborType = 0x40
|
||||
cborTypeTextString cborType = 0x60
|
||||
cborTypeArray cborType = 0x80
|
||||
cborTypeMap cborType = 0xa0
|
||||
cborTypeTag cborType = 0xc0
|
||||
cborTypePrimitives cborType = 0xe0
|
||||
)
|
||||
|
||||
func (t cborType) String() string {
|
||||
switch t {
|
||||
case cborTypePositiveInt:
|
||||
return "positive integer"
|
||||
case cborTypeNegativeInt:
|
||||
return "negative integer"
|
||||
case cborTypeByteString:
|
||||
return "byte string"
|
||||
case cborTypeTextString:
|
||||
return "UTF-8 text string"
|
||||
case cborTypeArray:
|
||||
return "array"
|
||||
case cborTypeMap:
|
||||
return "map"
|
||||
case cborTypeTag:
|
||||
return "tag"
|
||||
case cborTypePrimitives:
|
||||
return "primitives"
|
||||
default:
|
||||
return "Invalid type " + strconv.Itoa(int(t))
|
||||
}
|
||||
}
|
||||
|
||||
type additionalInformation uint8
|
||||
|
||||
const (
|
||||
maxAdditionalInformationWithoutArgument = 23
|
||||
additionalInformationWith1ByteArgument = 24
|
||||
additionalInformationWith2ByteArgument = 25
|
||||
additionalInformationWith4ByteArgument = 26
|
||||
additionalInformationWith8ByteArgument = 27
|
||||
|
||||
// For major type 7.
|
||||
additionalInformationAsFalse = 20
|
||||
additionalInformationAsTrue = 21
|
||||
additionalInformationAsNull = 22
|
||||
additionalInformationAsUndefined = 23
|
||||
additionalInformationAsFloat16 = 25
|
||||
additionalInformationAsFloat32 = 26
|
||||
additionalInformationAsFloat64 = 27
|
||||
|
||||
// For major type 2, 3, 4, 5.
|
||||
additionalInformationAsIndefiniteLengthFlag = 31
|
||||
)
|
||||
|
||||
const (
|
||||
maxSimpleValueInAdditionalInformation = 23
|
||||
minSimpleValueIn1ByteArgument = 32
|
||||
)
|
||||
|
||||
func (ai additionalInformation) isIndefiniteLength() bool {
|
||||
return ai == additionalInformationAsIndefiniteLengthFlag
|
||||
}
|
||||
|
||||
const (
|
||||
// From RFC 8949 Section 3:
|
||||
// "The initial byte of each encoded data item contains both information about the major type
|
||||
// (the high-order 3 bits, described in Section 3.1) and additional information
|
||||
// (the low-order 5 bits)."
|
||||
|
||||
// typeMask is used to extract major type in initial byte of encoded data item.
|
||||
typeMask = 0xe0
|
||||
|
||||
// additionalInformationMask is used to extract additional information in initial byte of encoded data item.
|
||||
additionalInformationMask = 0x1f
|
||||
)
|
||||
|
||||
func getType(raw byte) cborType {
|
||||
return cborType(raw & typeMask)
|
||||
}
|
||||
|
||||
func getAdditionalInformation(raw byte) byte {
|
||||
return raw & additionalInformationMask
|
||||
}
|
||||
|
||||
func isBreakFlag(raw byte) bool {
|
||||
return raw == cborBreakFlag
|
||||
}
|
||||
|
||||
func parseInitialByte(b byte) (t cborType, ai byte) {
|
||||
return getType(b), getAdditionalInformation(b)
|
||||
}
|
||||
|
||||
const (
|
||||
tagNumRFC3339Time = 0
|
||||
tagNumEpochTime = 1
|
||||
tagNumUnsignedBignum = 2
|
||||
tagNumNegativeBignum = 3
|
||||
tagNumExpectedLaterEncodingBase64URL = 21
|
||||
tagNumExpectedLaterEncodingBase64 = 22
|
||||
tagNumExpectedLaterEncodingBase16 = 23
|
||||
tagNumSelfDescribedCBOR = 55799
|
||||
)
|
||||
|
||||
const (
|
||||
cborBreakFlag = byte(0xff)
|
||||
cborByteStringWithIndefiniteLengthHead = byte(0x5f)
|
||||
cborTextStringWithIndefiniteLengthHead = byte(0x7f)
|
||||
cborArrayWithIndefiniteLengthHead = byte(0x9f)
|
||||
cborMapWithIndefiniteLengthHead = byte(0xbf)
|
||||
)
|
||||
|
||||
var (
|
||||
cborFalse = []byte{0xf4}
|
||||
cborTrue = []byte{0xf5}
|
||||
cborNil = []byte{0xf6}
|
||||
cborNaN = []byte{0xf9, 0x7e, 0x00}
|
||||
cborPositiveInfinity = []byte{0xf9, 0x7c, 0x00}
|
||||
cborNegativeInfinity = []byte{0xf9, 0xfc, 0x00}
|
||||
)
|
||||
|
||||
// validBuiltinTag checks that supported built-in tag numbers are followed by expected content types.
|
||||
func validBuiltinTag(tagNum uint64, contentHead byte) error {
|
||||
t := getType(contentHead)
|
||||
switch tagNum {
|
||||
case tagNumRFC3339Time:
|
||||
// Tag content (date/time text string in RFC 3339 format) must be string type.
|
||||
if t != cborTypeTextString {
|
||||
return newInadmissibleTagContentTypeError(
|
||||
tagNumRFC3339Time,
|
||||
"text string",
|
||||
t.String())
|
||||
}
|
||||
return nil
|
||||
|
||||
case tagNumEpochTime:
|
||||
// Tag content (epoch date/time) must be uint, int, or float type.
|
||||
if t != cborTypePositiveInt && t != cborTypeNegativeInt && (contentHead < 0xf9 || contentHead > 0xfb) {
|
||||
return newInadmissibleTagContentTypeError(
|
||||
tagNumEpochTime,
|
||||
"integer or floating-point number",
|
||||
t.String())
|
||||
}
|
||||
return nil
|
||||
|
||||
case tagNumUnsignedBignum, tagNumNegativeBignum:
|
||||
// Tag content (bignum) must be byte type.
|
||||
if t != cborTypeByteString {
|
||||
return newInadmissibleTagContentTypeErrorf(
|
||||
fmt.Sprintf(
|
||||
"tag number %d or %d must be followed by byte string, got %s",
|
||||
tagNumUnsignedBignum,
|
||||
tagNumNegativeBignum,
|
||||
t.String(),
|
||||
))
|
||||
}
|
||||
return nil
|
||||
|
||||
case tagNumExpectedLaterEncodingBase64URL, tagNumExpectedLaterEncodingBase64, tagNumExpectedLaterEncodingBase16:
|
||||
// From RFC 8949 3.4.5.2:
|
||||
// The data item tagged can be a byte string or any other data item. In the latter
|
||||
// case, the tag applies to all of the byte string data items contained in the data
|
||||
// item, except for those contained in a nested data item tagged with an expected
|
||||
// conversion.
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,724 @@
|
|||
// Copyright (c) Faye Amacker. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
|
||||
package cbor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base32"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"unicode/utf16"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/x448/float16"
|
||||
)
|
||||
|
||||
// DiagMode is the main interface for CBOR diagnostic notation.
|
||||
type DiagMode interface {
|
||||
// Diagnose returns extended diagnostic notation (EDN) of CBOR data items using this DiagMode.
|
||||
Diagnose([]byte) (string, error)
|
||||
|
||||
// DiagnoseFirst returns extended diagnostic notation (EDN) of the first CBOR data item using the DiagMode. Any remaining bytes are returned in rest.
|
||||
DiagnoseFirst([]byte) (string, []byte, error)
|
||||
|
||||
// DiagOptions returns user specified options used to create this DiagMode.
|
||||
DiagOptions() DiagOptions
|
||||
}
|
||||
|
||||
// ByteStringEncoding specifies the base encoding that byte strings are notated.
|
||||
type ByteStringEncoding uint8
|
||||
|
||||
const (
|
||||
// ByteStringBase16Encoding encodes byte strings in base16, without padding.
|
||||
ByteStringBase16Encoding ByteStringEncoding = iota
|
||||
|
||||
// ByteStringBase32Encoding encodes byte strings in base32, without padding.
|
||||
ByteStringBase32Encoding
|
||||
|
||||
// ByteStringBase32HexEncoding encodes byte strings in base32hex, without padding.
|
||||
ByteStringBase32HexEncoding
|
||||
|
||||
// ByteStringBase64Encoding encodes byte strings in base64url, without padding.
|
||||
ByteStringBase64Encoding
|
||||
|
||||
maxByteStringEncoding
|
||||
)
|
||||
|
||||
func (bse ByteStringEncoding) valid() error {
|
||||
if bse >= maxByteStringEncoding {
|
||||
return errors.New("cbor: invalid ByteStringEncoding " + strconv.Itoa(int(bse)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DiagOptions specifies Diag options.
|
||||
type DiagOptions struct {
|
||||
// ByteStringEncoding specifies the base encoding that byte strings are notated.
|
||||
// Default is ByteStringBase16Encoding.
|
||||
ByteStringEncoding ByteStringEncoding
|
||||
|
||||
// ByteStringHexWhitespace specifies notating with whitespace in byte string
|
||||
// when ByteStringEncoding is ByteStringBase16Encoding.
|
||||
ByteStringHexWhitespace bool
|
||||
|
||||
// ByteStringText specifies notating with text in byte string
|
||||
// if it is a valid UTF-8 text.
|
||||
ByteStringText bool
|
||||
|
||||
// ByteStringEmbeddedCBOR specifies notating embedded CBOR in byte string
|
||||
// if it is a valid CBOR bytes.
|
||||
ByteStringEmbeddedCBOR bool
|
||||
|
||||
// CBORSequence specifies notating CBOR sequences.
|
||||
// otherwise, it returns an error if there are more bytes after the first CBOR.
|
||||
CBORSequence bool
|
||||
|
||||
// FloatPrecisionIndicator specifies appending a suffix to indicate float precision.
|
||||
// Refer to https://www.rfc-editor.org/rfc/rfc8949.html#name-encoding-indicators.
|
||||
FloatPrecisionIndicator bool
|
||||
|
||||
// MaxNestedLevels specifies the max nested levels allowed for any combination of CBOR array, maps, and tags.
|
||||
// Default is 32 levels and it can be set to [4, 65535]. Note that higher maximum levels of nesting can
|
||||
// require larger amounts of stack to deserialize. Don't increase this higher than you require.
|
||||
MaxNestedLevels int
|
||||
|
||||
// MaxArrayElements specifies the max number of elements for CBOR arrays.
|
||||
// Default is 128*1024=131072 and it can be set to [16, 2147483647]
|
||||
MaxArrayElements int
|
||||
|
||||
// MaxMapPairs specifies the max number of key-value pairs for CBOR maps.
|
||||
// Default is 128*1024=131072 and it can be set to [16, 2147483647]
|
||||
MaxMapPairs int
|
||||
}
|
||||
|
||||
// DiagMode returns a DiagMode with immutable options.
|
||||
func (opts DiagOptions) DiagMode() (DiagMode, error) {
|
||||
return opts.diagMode()
|
||||
}
|
||||
|
||||
func (opts DiagOptions) diagMode() (*diagMode, error) {
|
||||
if err := opts.ByteStringEncoding.valid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
decMode, err := DecOptions{
|
||||
MaxNestedLevels: opts.MaxNestedLevels,
|
||||
MaxArrayElements: opts.MaxArrayElements,
|
||||
MaxMapPairs: opts.MaxMapPairs,
|
||||
}.decMode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &diagMode{
|
||||
byteStringEncoding: opts.ByteStringEncoding,
|
||||
byteStringHexWhitespace: opts.ByteStringHexWhitespace,
|
||||
byteStringText: opts.ByteStringText,
|
||||
byteStringEmbeddedCBOR: opts.ByteStringEmbeddedCBOR,
|
||||
cborSequence: opts.CBORSequence,
|
||||
floatPrecisionIndicator: opts.FloatPrecisionIndicator,
|
||||
decMode: decMode,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type diagMode struct {
|
||||
byteStringEncoding ByteStringEncoding
|
||||
byteStringHexWhitespace bool
|
||||
byteStringText bool
|
||||
byteStringEmbeddedCBOR bool
|
||||
cborSequence bool
|
||||
floatPrecisionIndicator bool
|
||||
decMode *decMode
|
||||
}
|
||||
|
||||
// DiagOptions returns user specified options used to create this DiagMode.
|
||||
func (dm *diagMode) DiagOptions() DiagOptions {
|
||||
return DiagOptions{
|
||||
ByteStringEncoding: dm.byteStringEncoding,
|
||||
ByteStringHexWhitespace: dm.byteStringHexWhitespace,
|
||||
ByteStringText: dm.byteStringText,
|
||||
ByteStringEmbeddedCBOR: dm.byteStringEmbeddedCBOR,
|
||||
CBORSequence: dm.cborSequence,
|
||||
FloatPrecisionIndicator: dm.floatPrecisionIndicator,
|
||||
MaxNestedLevels: dm.decMode.maxNestedLevels,
|
||||
MaxArrayElements: dm.decMode.maxArrayElements,
|
||||
MaxMapPairs: dm.decMode.maxMapPairs,
|
||||
}
|
||||
}
|
||||
|
||||
// Diagnose returns extended diagnostic notation (EDN) of CBOR data items using the DiagMode.
|
||||
func (dm *diagMode) Diagnose(data []byte) (string, error) {
|
||||
return newDiagnose(data, dm.decMode, dm).diag(dm.cborSequence)
|
||||
}
|
||||
|
||||
// DiagnoseFirst returns extended diagnostic notation (EDN) of the first CBOR data item using the DiagMode. Any remaining bytes are returned in rest.
|
||||
func (dm *diagMode) DiagnoseFirst(data []byte) (diagNotation string, rest []byte, err error) {
|
||||
return newDiagnose(data, dm.decMode, dm).diagFirst()
|
||||
}
|
||||
|
||||
var defaultDiagMode, _ = DiagOptions{}.diagMode()
|
||||
|
||||
// Diagnose returns extended diagnostic notation (EDN) of CBOR data items
|
||||
// using the default diagnostic mode.
|
||||
//
|
||||
// Refer to https://www.rfc-editor.org/rfc/rfc8949.html#name-diagnostic-notation.
|
||||
func Diagnose(data []byte) (string, error) {
|
||||
return defaultDiagMode.Diagnose(data)
|
||||
}
|
||||
|
||||
// Diagnose returns extended diagnostic notation (EDN) of the first CBOR data item using the DiagMode. Any remaining bytes are returned in rest.
|
||||
func DiagnoseFirst(data []byte) (diagNotation string, rest []byte, err error) {
|
||||
return defaultDiagMode.DiagnoseFirst(data)
|
||||
}
|
||||
|
||||
type diagnose struct {
|
||||
dm *diagMode
|
||||
d *decoder
|
||||
w *bytes.Buffer
|
||||
}
|
||||
|
||||
func newDiagnose(data []byte, decm *decMode, diagm *diagMode) *diagnose {
|
||||
return &diagnose{
|
||||
dm: diagm,
|
||||
d: &decoder{data: data, dm: decm},
|
||||
w: &bytes.Buffer{},
|
||||
}
|
||||
}
|
||||
|
||||
func (di *diagnose) diag(cborSequence bool) (string, error) {
|
||||
// CBOR Sequence
|
||||
firstItem := true
|
||||
for {
|
||||
switch err := di.wellformed(cborSequence); err {
|
||||
case nil:
|
||||
if !firstItem {
|
||||
di.w.WriteString(", ")
|
||||
}
|
||||
firstItem = false
|
||||
if itemErr := di.item(); itemErr != nil {
|
||||
return di.w.String(), itemErr
|
||||
}
|
||||
|
||||
case io.EOF:
|
||||
if firstItem {
|
||||
return di.w.String(), err
|
||||
}
|
||||
return di.w.String(), nil
|
||||
|
||||
default:
|
||||
return di.w.String(), err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (di *diagnose) diagFirst() (diagNotation string, rest []byte, err error) {
|
||||
err = di.wellformed(true)
|
||||
if err == nil {
|
||||
err = di.item()
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
// Return EDN and the rest of the data slice (which might be len 0)
|
||||
return di.w.String(), di.d.data[di.d.off:], nil
|
||||
}
|
||||
|
||||
return di.w.String(), nil, err
|
||||
}
|
||||
|
||||
func (di *diagnose) wellformed(allowExtraData bool) error {
|
||||
off := di.d.off
|
||||
err := di.d.wellformed(allowExtraData, false)
|
||||
di.d.off = off
|
||||
return err
|
||||
}
|
||||
|
||||
func (di *diagnose) item() error { //nolint:gocyclo
|
||||
initialByte := di.d.data[di.d.off]
|
||||
switch initialByte {
|
||||
case cborByteStringWithIndefiniteLengthHead,
|
||||
cborTextStringWithIndefiniteLengthHead: // indefinite-length byte/text string
|
||||
di.d.off++
|
||||
if isBreakFlag(di.d.data[di.d.off]) {
|
||||
di.d.off++
|
||||
switch initialByte {
|
||||
case cborByteStringWithIndefiniteLengthHead:
|
||||
// indefinite-length bytes with no chunks.
|
||||
di.w.WriteString(`''_`)
|
||||
return nil
|
||||
case cborTextStringWithIndefiniteLengthHead:
|
||||
// indefinite-length text with no chunks.
|
||||
di.w.WriteString(`""_`)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
di.w.WriteString("(_ ")
|
||||
|
||||
i := 0
|
||||
for !di.d.foundBreak() {
|
||||
if i > 0 {
|
||||
di.w.WriteString(", ")
|
||||
}
|
||||
|
||||
i++
|
||||
// wellformedIndefiniteString() already checked that the next item is a byte/text string.
|
||||
if err := di.item(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
di.w.WriteByte(')')
|
||||
return nil
|
||||
|
||||
case cborArrayWithIndefiniteLengthHead: // indefinite-length array
|
||||
di.d.off++
|
||||
di.w.WriteString("[_ ")
|
||||
|
||||
i := 0
|
||||
for !di.d.foundBreak() {
|
||||
if i > 0 {
|
||||
di.w.WriteString(", ")
|
||||
}
|
||||
|
||||
i++
|
||||
if err := di.item(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
di.w.WriteByte(']')
|
||||
return nil
|
||||
|
||||
case cborMapWithIndefiniteLengthHead: // indefinite-length map
|
||||
di.d.off++
|
||||
di.w.WriteString("{_ ")
|
||||
|
||||
i := 0
|
||||
for !di.d.foundBreak() {
|
||||
if i > 0 {
|
||||
di.w.WriteString(", ")
|
||||
}
|
||||
|
||||
i++
|
||||
// key
|
||||
if err := di.item(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
di.w.WriteString(": ")
|
||||
|
||||
// value
|
||||
if err := di.item(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
di.w.WriteByte('}')
|
||||
return nil
|
||||
}
|
||||
|
||||
t := di.d.nextCBORType()
|
||||
switch t {
|
||||
case cborTypePositiveInt:
|
||||
_, _, val := di.d.getHead()
|
||||
di.w.WriteString(strconv.FormatUint(val, 10))
|
||||
return nil
|
||||
|
||||
case cborTypeNegativeInt:
|
||||
_, _, val := di.d.getHead()
|
||||
if val > math.MaxInt64 {
|
||||
// CBOR negative integer overflows int64, use big.Int to store value.
|
||||
bi := new(big.Int)
|
||||
bi.SetUint64(val)
|
||||
bi.Add(bi, big.NewInt(1))
|
||||
bi.Neg(bi)
|
||||
di.w.WriteString(bi.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
nValue := int64(-1) ^ int64(val)
|
||||
di.w.WriteString(strconv.FormatInt(nValue, 10))
|
||||
return nil
|
||||
|
||||
case cborTypeByteString:
|
||||
b, _ := di.d.parseByteString()
|
||||
return di.encodeByteString(b)
|
||||
|
||||
case cborTypeTextString:
|
||||
b, err := di.d.parseTextString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return di.encodeTextString(string(b), '"')
|
||||
|
||||
case cborTypeArray:
|
||||
_, _, val := di.d.getHead()
|
||||
count := int(val)
|
||||
di.w.WriteByte('[')
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
if i > 0 {
|
||||
di.w.WriteString(", ")
|
||||
}
|
||||
if err := di.item(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
di.w.WriteByte(']')
|
||||
return nil
|
||||
|
||||
case cborTypeMap:
|
||||
_, _, val := di.d.getHead()
|
||||
count := int(val)
|
||||
di.w.WriteByte('{')
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
if i > 0 {
|
||||
di.w.WriteString(", ")
|
||||
}
|
||||
// key
|
||||
if err := di.item(); err != nil {
|
||||
return err
|
||||
}
|
||||
di.w.WriteString(": ")
|
||||
// value
|
||||
if err := di.item(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
di.w.WriteByte('}')
|
||||
return nil
|
||||
|
||||
case cborTypeTag:
|
||||
_, _, tagNum := di.d.getHead()
|
||||
switch tagNum {
|
||||
case tagNumUnsignedBignum:
|
||||
if nt := di.d.nextCBORType(); nt != cborTypeByteString {
|
||||
return newInadmissibleTagContentTypeError(
|
||||
tagNumUnsignedBignum,
|
||||
"byte string",
|
||||
nt.String())
|
||||
}
|
||||
|
||||
b, _ := di.d.parseByteString()
|
||||
bi := new(big.Int).SetBytes(b)
|
||||
di.w.WriteString(bi.String())
|
||||
return nil
|
||||
|
||||
case tagNumNegativeBignum:
|
||||
if nt := di.d.nextCBORType(); nt != cborTypeByteString {
|
||||
return newInadmissibleTagContentTypeError(
|
||||
tagNumNegativeBignum,
|
||||
"byte string",
|
||||
nt.String(),
|
||||
)
|
||||
}
|
||||
|
||||
b, _ := di.d.parseByteString()
|
||||
bi := new(big.Int).SetBytes(b)
|
||||
bi.Add(bi, big.NewInt(1))
|
||||
bi.Neg(bi)
|
||||
di.w.WriteString(bi.String())
|
||||
return nil
|
||||
|
||||
default:
|
||||
di.w.WriteString(strconv.FormatUint(tagNum, 10))
|
||||
di.w.WriteByte('(')
|
||||
if err := di.item(); err != nil {
|
||||
return err
|
||||
}
|
||||
di.w.WriteByte(')')
|
||||
return nil
|
||||
}
|
||||
|
||||
case cborTypePrimitives:
|
||||
_, ai, val := di.d.getHead()
|
||||
switch ai {
|
||||
case additionalInformationAsFalse:
|
||||
di.w.WriteString("false")
|
||||
return nil
|
||||
|
||||
case additionalInformationAsTrue:
|
||||
di.w.WriteString("true")
|
||||
return nil
|
||||
|
||||
case additionalInformationAsNull:
|
||||
di.w.WriteString("null")
|
||||
return nil
|
||||
|
||||
case additionalInformationAsUndefined:
|
||||
di.w.WriteString("undefined")
|
||||
return nil
|
||||
|
||||
case additionalInformationAsFloat16,
|
||||
additionalInformationAsFloat32,
|
||||
additionalInformationAsFloat64:
|
||||
return di.encodeFloat(ai, val)
|
||||
|
||||
default:
|
||||
di.w.WriteString("simple(")
|
||||
di.w.WriteString(strconv.FormatUint(val, 10))
|
||||
di.w.WriteByte(')')
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeU16 format a rune as "\uxxxx"
|
||||
func (di *diagnose) writeU16(val rune) {
|
||||
di.w.WriteString("\\u")
|
||||
var in [2]byte
|
||||
in[0] = byte(val >> 8)
|
||||
in[1] = byte(val)
|
||||
sz := hex.EncodedLen(len(in))
|
||||
di.w.Grow(sz)
|
||||
dst := di.w.Bytes()[di.w.Len() : di.w.Len()+sz]
|
||||
hex.Encode(dst, in[:])
|
||||
di.w.Write(dst)
|
||||
}
|
||||
|
||||
var rawBase32Encoding = base32.StdEncoding.WithPadding(base32.NoPadding)
|
||||
var rawBase32HexEncoding = base32.HexEncoding.WithPadding(base32.NoPadding)
|
||||
|
||||
func (di *diagnose) encodeByteString(val []byte) error {
|
||||
if len(val) > 0 {
|
||||
if di.dm.byteStringText && utf8.Valid(val) {
|
||||
return di.encodeTextString(string(val), '\'')
|
||||
}
|
||||
|
||||
if di.dm.byteStringEmbeddedCBOR {
|
||||
di2 := newDiagnose(val, di.dm.decMode, di.dm)
|
||||
// should always notating embedded CBOR sequence.
|
||||
if str, err := di2.diag(true); err == nil {
|
||||
di.w.WriteString("<<")
|
||||
di.w.WriteString(str)
|
||||
di.w.WriteString(">>")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch di.dm.byteStringEncoding {
|
||||
case ByteStringBase16Encoding:
|
||||
di.w.WriteString("h'")
|
||||
if di.dm.byteStringHexWhitespace {
|
||||
sz := hex.EncodedLen(len(val))
|
||||
if len(val) > 0 {
|
||||
sz += len(val) - 1
|
||||
}
|
||||
di.w.Grow(sz)
|
||||
|
||||
dst := di.w.Bytes()[di.w.Len():]
|
||||
for i := range val {
|
||||
if i > 0 {
|
||||
dst = append(dst, ' ')
|
||||
}
|
||||
hex.Encode(dst[len(dst):len(dst)+2], val[i:i+1])
|
||||
dst = dst[:len(dst)+2]
|
||||
}
|
||||
di.w.Write(dst)
|
||||
} else {
|
||||
sz := hex.EncodedLen(len(val))
|
||||
di.w.Grow(sz)
|
||||
dst := di.w.Bytes()[di.w.Len() : di.w.Len()+sz]
|
||||
hex.Encode(dst, val)
|
||||
di.w.Write(dst)
|
||||
}
|
||||
di.w.WriteByte('\'')
|
||||
return nil
|
||||
|
||||
case ByteStringBase32Encoding:
|
||||
di.w.WriteString("b32'")
|
||||
sz := rawBase32Encoding.EncodedLen(len(val))
|
||||
di.w.Grow(sz)
|
||||
dst := di.w.Bytes()[di.w.Len() : di.w.Len()+sz]
|
||||
rawBase32Encoding.Encode(dst, val)
|
||||
di.w.Write(dst)
|
||||
di.w.WriteByte('\'')
|
||||
return nil
|
||||
|
||||
case ByteStringBase32HexEncoding:
|
||||
di.w.WriteString("h32'")
|
||||
sz := rawBase32HexEncoding.EncodedLen(len(val))
|
||||
di.w.Grow(sz)
|
||||
dst := di.w.Bytes()[di.w.Len() : di.w.Len()+sz]
|
||||
rawBase32HexEncoding.Encode(dst, val)
|
||||
di.w.Write(dst)
|
||||
di.w.WriteByte('\'')
|
||||
return nil
|
||||
|
||||
case ByteStringBase64Encoding:
|
||||
di.w.WriteString("b64'")
|
||||
sz := base64.RawURLEncoding.EncodedLen(len(val))
|
||||
di.w.Grow(sz)
|
||||
dst := di.w.Bytes()[di.w.Len() : di.w.Len()+sz]
|
||||
base64.RawURLEncoding.Encode(dst, val)
|
||||
di.w.Write(dst)
|
||||
di.w.WriteByte('\'')
|
||||
return nil
|
||||
|
||||
default:
|
||||
// It should not be possible for users to construct a *diagMode with an invalid byte
|
||||
// string encoding.
|
||||
panic(fmt.Sprintf("diagmode has invalid ByteStringEncoding %v", di.dm.byteStringEncoding))
|
||||
}
|
||||
}
|
||||
|
||||
const utf16SurrSelf = rune(0x10000)
|
||||
|
||||
// quote should be either `'` or `"`
|
||||
func (di *diagnose) encodeTextString(val string, quote byte) error {
|
||||
di.w.WriteByte(quote)
|
||||
|
||||
for i := 0; i < len(val); {
|
||||
if b := val[i]; b < utf8.RuneSelf {
|
||||
switch {
|
||||
case b == '\t', b == '\n', b == '\r', b == '\\', b == quote:
|
||||
di.w.WriteByte('\\')
|
||||
|
||||
switch b {
|
||||
case '\t':
|
||||
b = 't'
|
||||
case '\n':
|
||||
b = 'n'
|
||||
case '\r':
|
||||
b = 'r'
|
||||
}
|
||||
di.w.WriteByte(b)
|
||||
|
||||
case b >= ' ' && b <= '~':
|
||||
di.w.WriteByte(b)
|
||||
|
||||
default:
|
||||
di.writeU16(rune(b))
|
||||
}
|
||||
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
c, size := utf8.DecodeRuneInString(val[i:])
|
||||
switch {
|
||||
case c == utf8.RuneError:
|
||||
return &SemanticError{"cbor: invalid UTF-8 string"}
|
||||
|
||||
case c < utf16SurrSelf:
|
||||
di.writeU16(c)
|
||||
|
||||
default:
|
||||
c1, c2 := utf16.EncodeRune(c)
|
||||
di.writeU16(c1)
|
||||
di.writeU16(c2)
|
||||
}
|
||||
|
||||
i += size
|
||||
}
|
||||
|
||||
di.w.WriteByte(quote)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (di *diagnose) encodeFloat(ai byte, val uint64) error {
|
||||
f64 := float64(0)
|
||||
switch ai {
|
||||
case additionalInformationAsFloat16:
|
||||
f16 := float16.Frombits(uint16(val))
|
||||
switch {
|
||||
case f16.IsNaN():
|
||||
di.w.WriteString("NaN")
|
||||
return nil
|
||||
case f16.IsInf(1):
|
||||
di.w.WriteString("Infinity")
|
||||
return nil
|
||||
case f16.IsInf(-1):
|
||||
di.w.WriteString("-Infinity")
|
||||
return nil
|
||||
default:
|
||||
f64 = float64(f16.Float32())
|
||||
}
|
||||
|
||||
case additionalInformationAsFloat32:
|
||||
f32 := math.Float32frombits(uint32(val))
|
||||
switch {
|
||||
case f32 != f32:
|
||||
di.w.WriteString("NaN")
|
||||
return nil
|
||||
case f32 > math.MaxFloat32:
|
||||
di.w.WriteString("Infinity")
|
||||
return nil
|
||||
case f32 < -math.MaxFloat32:
|
||||
di.w.WriteString("-Infinity")
|
||||
return nil
|
||||
default:
|
||||
f64 = float64(f32)
|
||||
}
|
||||
|
||||
case additionalInformationAsFloat64:
|
||||
f64 = math.Float64frombits(val)
|
||||
switch {
|
||||
case f64 != f64:
|
||||
di.w.WriteString("NaN")
|
||||
return nil
|
||||
case f64 > math.MaxFloat64:
|
||||
di.w.WriteString("Infinity")
|
||||
return nil
|
||||
case f64 < -math.MaxFloat64:
|
||||
di.w.WriteString("-Infinity")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
// Use ES6 number to string conversion which should match most JSON generators.
|
||||
// Inspired by https://github.com/golang/go/blob/4df10fba1687a6d4f51d7238a403f8f2298f6a16/src/encoding/json/encode.go#L585
|
||||
const bitSize = 64
|
||||
b := make([]byte, 0, 32)
|
||||
if abs := math.Abs(f64); abs != 0 && (abs < 1e-6 || abs >= 1e21) {
|
||||
b = strconv.AppendFloat(b, f64, 'e', -1, bitSize)
|
||||
// clean up e-09 to e-9
|
||||
n := len(b)
|
||||
if n >= 4 && string(b[n-4:n-1]) == "e-0" {
|
||||
b = append(b[:n-2], b[n-1])
|
||||
}
|
||||
} else {
|
||||
b = strconv.AppendFloat(b, f64, 'f', -1, bitSize)
|
||||
}
|
||||
|
||||
// add decimal point and trailing zero if needed
|
||||
if bytes.IndexByte(b, '.') < 0 {
|
||||
if i := bytes.IndexByte(b, 'e'); i < 0 {
|
||||
b = append(b, '.', '0')
|
||||
} else {
|
||||
b = append(b[:i+2], b[i:]...)
|
||||
b[i] = '.'
|
||||
b[i+1] = '0'
|
||||
}
|
||||
}
|
||||
|
||||
di.w.WriteString(string(b))
|
||||
|
||||
if di.dm.floatPrecisionIndicator {
|
||||
switch ai {
|
||||
case additionalInformationAsFloat16:
|
||||
di.w.WriteString("_1")
|
||||
return nil
|
||||
|
||||
case additionalInformationAsFloat32:
|
||||
di.w.WriteString("_2")
|
||||
return nil
|
||||
|
||||
case additionalInformationAsFloat64:
|
||||
di.w.WriteString("_3")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
// Copyright (c) Faye Amacker. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
|
||||
/*
|
||||
Package cbor is a modern CBOR codec (RFC 8949 & RFC 7049) with CBOR tags,
|
||||
Go struct tags (toarray/keyasint/omitempty), Core Deterministic Encoding,
|
||||
CTAP2, Canonical CBOR, float64->32->16, and duplicate map key detection.
|
||||
|
||||
Encoding options allow "preferred serialization" by encoding integers and floats
|
||||
to their smallest forms (e.g. float16) when values fit.
|
||||
|
||||
Struct tags like "keyasint", "toarray" and "omitempty" make CBOR data smaller
|
||||
and easier to use with structs.
|
||||
|
||||
For example, "toarray" tag makes struct fields encode to CBOR array elements. And
|
||||
"keyasint" makes a field encode to an element of CBOR map with specified int key.
|
||||
|
||||
Latest docs can be viewed at https://github.com/fxamacker/cbor#cbor-library-in-go
|
||||
|
||||
# Basics
|
||||
|
||||
The Quick Start guide is at https://github.com/fxamacker/cbor#quick-start
|
||||
|
||||
Function signatures identical to encoding/json include:
|
||||
|
||||
Marshal, Unmarshal, NewEncoder, NewDecoder, (*Encoder).Encode, (*Decoder).Decode.
|
||||
|
||||
Standard interfaces include:
|
||||
|
||||
BinaryMarshaler, BinaryUnmarshaler, Marshaler, and Unmarshaler.
|
||||
|
||||
Custom encoding and decoding is possible by implementing standard interfaces for
|
||||
user-defined Go types.
|
||||
|
||||
Codec functions are available at package-level (using defaults options) or by
|
||||
creating modes from options at runtime.
|
||||
|
||||
"Mode" in this API means definite way of encoding (EncMode) or decoding (DecMode).
|
||||
|
||||
EncMode and DecMode interfaces are created from EncOptions or DecOptions structs.
|
||||
|
||||
em, err := cbor.EncOptions{...}.EncMode()
|
||||
em, err := cbor.CanonicalEncOptions().EncMode()
|
||||
em, err := cbor.CTAP2EncOptions().EncMode()
|
||||
|
||||
Modes use immutable options to avoid side-effects and simplify concurrency. Behavior of
|
||||
modes won't accidentally change at runtime after they're created.
|
||||
|
||||
Modes are intended to be reused and are safe for concurrent use.
|
||||
|
||||
EncMode and DecMode Interfaces
|
||||
|
||||
// EncMode interface uses immutable options and is safe for concurrent use.
|
||||
type EncMode interface {
|
||||
Marshal(v interface{}) ([]byte, error)
|
||||
NewEncoder(w io.Writer) *Encoder
|
||||
EncOptions() EncOptions // returns copy of options
|
||||
}
|
||||
|
||||
// DecMode interface uses immutable options and is safe for concurrent use.
|
||||
type DecMode interface {
|
||||
Unmarshal(data []byte, v interface{}) error
|
||||
NewDecoder(r io.Reader) *Decoder
|
||||
DecOptions() DecOptions // returns copy of options
|
||||
}
|
||||
|
||||
Using Default Encoding Mode
|
||||
|
||||
b, err := cbor.Marshal(v)
|
||||
|
||||
encoder := cbor.NewEncoder(w)
|
||||
err = encoder.Encode(v)
|
||||
|
||||
Using Default Decoding Mode
|
||||
|
||||
err := cbor.Unmarshal(b, &v)
|
||||
|
||||
decoder := cbor.NewDecoder(r)
|
||||
err = decoder.Decode(&v)
|
||||
|
||||
Creating and Using Encoding Modes
|
||||
|
||||
// Create EncOptions using either struct literal or a function.
|
||||
opts := cbor.CanonicalEncOptions()
|
||||
|
||||
// If needed, modify encoding options
|
||||
opts.Time = cbor.TimeUnix
|
||||
|
||||
// Create reusable EncMode interface with immutable options, safe for concurrent use.
|
||||
em, err := opts.EncMode()
|
||||
|
||||
// Use EncMode like encoding/json, with same function signatures.
|
||||
b, err := em.Marshal(v)
|
||||
// or
|
||||
encoder := em.NewEncoder(w)
|
||||
err := encoder.Encode(v)
|
||||
|
||||
// NOTE: Both em.Marshal(v) and encoder.Encode(v) use encoding options
|
||||
// specified during creation of em (encoding mode).
|
||||
|
||||
# CBOR Options
|
||||
|
||||
Predefined Encoding Options: https://github.com/fxamacker/cbor#predefined-encoding-options
|
||||
|
||||
Encoding Options: https://github.com/fxamacker/cbor#encoding-options
|
||||
|
||||
Decoding Options: https://github.com/fxamacker/cbor#decoding-options
|
||||
|
||||
# Struct Tags
|
||||
|
||||
Struct tags like `cbor:"name,omitempty"` and `json:"name,omitempty"` work as expected.
|
||||
If both struct tags are specified then `cbor` is used.
|
||||
|
||||
Struct tags like "keyasint", "toarray", and "omitempty" make it easy to use
|
||||
very compact formats like COSE and CWT (CBOR Web Tokens) with structs.
|
||||
|
||||
For example, "toarray" makes struct fields encode to array elements. And "keyasint"
|
||||
makes struct fields encode to elements of CBOR map with int keys.
|
||||
|
||||
https://raw.githubusercontent.com/fxamacker/images/master/cbor/v2.0.0/cbor_easy_api.png
|
||||
|
||||
Struct tags are listed at https://github.com/fxamacker/cbor#struct-tags-1
|
||||
|
||||
# Tests and Fuzzing
|
||||
|
||||
Over 375 tests are included in this package. Cover-guided fuzzing is handled by
|
||||
a private fuzzer that replaced fxamacker/cbor-fuzz years ago.
|
||||
*/
|
||||
package cbor
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,94 @@
|
|||
// Copyright (c) Faye Amacker. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
|
||||
//go:build go1.20
|
||||
|
||||
package cbor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type mapKeyValueEncodeFunc struct {
|
||||
kf, ef encodeFunc
|
||||
kpool, vpool sync.Pool
|
||||
}
|
||||
|
||||
func (me *mapKeyValueEncodeFunc) encodeKeyValues(e *bytes.Buffer, em *encMode, v reflect.Value, kvs []keyValue) error {
|
||||
iterk := me.kpool.Get().(*reflect.Value)
|
||||
defer func() {
|
||||
iterk.SetZero()
|
||||
me.kpool.Put(iterk)
|
||||
}()
|
||||
iterv := me.vpool.Get().(*reflect.Value)
|
||||
defer func() {
|
||||
iterv.SetZero()
|
||||
me.vpool.Put(iterv)
|
||||
}()
|
||||
|
||||
if kvs == nil {
|
||||
for i, iter := 0, v.MapRange(); iter.Next(); i++ {
|
||||
iterk.SetIterKey(iter)
|
||||
iterv.SetIterValue(iter)
|
||||
|
||||
if err := me.kf(e, em, *iterk); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := me.ef(e, em, *iterv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
initial := e.Len()
|
||||
for i, iter := 0, v.MapRange(); iter.Next(); i++ {
|
||||
iterk.SetIterKey(iter)
|
||||
iterv.SetIterValue(iter)
|
||||
|
||||
offset := e.Len()
|
||||
if err := me.kf(e, em, *iterk); err != nil {
|
||||
return err
|
||||
}
|
||||
valueOffset := e.Len()
|
||||
if err := me.ef(e, em, *iterv); err != nil {
|
||||
return err
|
||||
}
|
||||
kvs[i] = keyValue{
|
||||
offset: offset - initial,
|
||||
valueOffset: valueOffset - initial,
|
||||
nextOffset: e.Len() - initial,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getEncodeMapFunc(t reflect.Type) encodeFunc {
|
||||
kf, _ := getEncodeFunc(t.Key())
|
||||
ef, _ := getEncodeFunc(t.Elem())
|
||||
if kf == nil || ef == nil {
|
||||
return nil
|
||||
}
|
||||
mkv := &mapKeyValueEncodeFunc{
|
||||
kf: kf,
|
||||
ef: ef,
|
||||
kpool: sync.Pool{
|
||||
New: func() interface{} {
|
||||
rk := reflect.New(t.Key()).Elem()
|
||||
return &rk
|
||||
},
|
||||
},
|
||||
vpool: sync.Pool{
|
||||
New: func() interface{} {
|
||||
rv := reflect.New(t.Elem()).Elem()
|
||||
return &rv
|
||||
},
|
||||
},
|
||||
}
|
||||
return mapEncodeFunc{
|
||||
e: mkv.encodeKeyValues,
|
||||
}.encode
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright (c) Faye Amacker. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
|
||||
//go:build !go1.20
|
||||
|
||||
package cbor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type mapKeyValueEncodeFunc struct {
|
||||
kf, ef encodeFunc
|
||||
}
|
||||
|
||||
func (me *mapKeyValueEncodeFunc) encodeKeyValues(e *bytes.Buffer, em *encMode, v reflect.Value, kvs []keyValue) error {
|
||||
if kvs == nil {
|
||||
for i, iter := 0, v.MapRange(); iter.Next(); i++ {
|
||||
if err := me.kf(e, em, iter.Key()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := me.ef(e, em, iter.Value()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
initial := e.Len()
|
||||
for i, iter := 0, v.MapRange(); iter.Next(); i++ {
|
||||
offset := e.Len()
|
||||
if err := me.kf(e, em, iter.Key()); err != nil {
|
||||
return err
|
||||
}
|
||||
valueOffset := e.Len()
|
||||
if err := me.ef(e, em, iter.Value()); err != nil {
|
||||
return err
|
||||
}
|
||||
kvs[i] = keyValue{
|
||||
offset: offset - initial,
|
||||
valueOffset: valueOffset - initial,
|
||||
nextOffset: e.Len() - initial,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getEncodeMapFunc(t reflect.Type) encodeFunc {
|
||||
kf, _ := getEncodeFunc(t.Key())
|
||||
ef, _ := getEncodeFunc(t.Elem())
|
||||
if kf == nil || ef == nil {
|
||||
return nil
|
||||
}
|
||||
mkv := &mapKeyValueEncodeFunc{kf: kf, ef: ef}
|
||||
return mapEncodeFunc{
|
||||
e: mkv.encodeKeyValues,
|
||||
}.encode
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package cbor
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// SimpleValue represents CBOR simple value.
|
||||
// CBOR simple value is:
|
||||
// - an extension point like CBOR tag.
|
||||
// - a subset of CBOR major type 7 that isn't floating-point.
|
||||
// - "identified by a number between 0 and 255, but distinct from that number itself".
|
||||
// For example, "a simple value 2 is not equivalent to an integer 2" as a CBOR map key.
|
||||
//
|
||||
// CBOR simple values identified by 20..23 are: "false", "true" , "null", and "undefined".
|
||||
// Other CBOR simple values are currently unassigned/reserved by IANA.
|
||||
type SimpleValue uint8
|
||||
|
||||
var (
|
||||
typeSimpleValue = reflect.TypeOf(SimpleValue(0))
|
||||
)
|
||||
|
||||
// MarshalCBOR encodes SimpleValue as CBOR simple value (major type 7).
|
||||
func (sv SimpleValue) MarshalCBOR() ([]byte, error) {
|
||||
// RFC 8949 3.3. Floating-Point Numbers and Values with No Content says:
|
||||
// "An encoder MUST NOT issue two-byte sequences that start with 0xf8
|
||||
// (major type 7, additional information 24) and continue with a byte
|
||||
// less than 0x20 (32 decimal). Such sequences are not well-formed.
|
||||
// (This implies that an encoder cannot encode false, true, null, or
|
||||
// undefined in two-byte sequences and that only the one-byte variants
|
||||
// of these are well-formed; more generally speaking, each simple value
|
||||
// only has a single representation variant)."
|
||||
|
||||
switch {
|
||||
case sv <= maxSimpleValueInAdditionalInformation:
|
||||
return []byte{byte(cborTypePrimitives) | byte(sv)}, nil
|
||||
|
||||
case sv >= minSimpleValueIn1ByteArgument:
|
||||
return []byte{byte(cborTypePrimitives) | additionalInformationWith1ByteArgument, byte(sv)}, nil
|
||||
|
||||
default:
|
||||
return nil, &UnsupportedValueError{msg: fmt.Sprintf("SimpleValue(%d)", sv)}
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalCBOR decodes CBOR simple value (major type 7) to SimpleValue.
|
||||
func (sv *SimpleValue) UnmarshalCBOR(data []byte) error {
|
||||
if sv == nil {
|
||||
return errors.New("cbor.SimpleValue: UnmarshalCBOR on nil pointer")
|
||||
}
|
||||
|
||||
d := decoder{data: data, dm: defaultDecMode}
|
||||
|
||||
typ, ai, val := d.getHead()
|
||||
|
||||
if typ != cborTypePrimitives {
|
||||
return &UnmarshalTypeError{CBORType: typ.String(), GoType: "SimpleValue"}
|
||||
}
|
||||
if ai > additionalInformationWith1ByteArgument {
|
||||
return &UnmarshalTypeError{CBORType: typ.String(), GoType: "SimpleValue", errorMsg: "not simple values"}
|
||||
}
|
||||
|
||||
// It is safe to cast val to uint8 here because
|
||||
// - data is already verified to be well-formed CBOR simple value and
|
||||
// - val is <= math.MaxUint8.
|
||||
*sv = SimpleValue(val)
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,277 @@
|
|||
// Copyright (c) Faye Amacker. All rights reserved.
|
||||
// Licensed under the MIT License. See LICENSE in the project root for license information.
|
||||
|
||||
package cbor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Decoder reads and decodes CBOR values from io.Reader.
|
||||
type Decoder struct {
|
||||
r io.Reader
|
||||
d decoder
|
||||
buf []byte
|
||||
off int // next read offset in buf
|
||||
bytesRead int
|
||||
}
|
||||
|
||||
// NewDecoder returns a new decoder that reads and decodes from r using
|
||||
// the default decoding options.
|
||||
func NewDecoder(r io.Reader) *Decoder {
|
||||
return defaultDecMode.NewDecoder(r)
|
||||
}
|
||||
|
||||
// Decode reads CBOR value and decodes it into the value pointed to by v.
|
||||
func (dec *Decoder) Decode(v interface{}) error {
|
||||
_, err := dec.readNext()
|
||||
if err != nil {
|
||||
// Return validation error or read error.
|
||||
return err
|
||||
}
|
||||
|
||||
dec.d.reset(dec.buf[dec.off:])
|
||||
err = dec.d.value(v)
|
||||
|
||||
// Increment dec.off even if decoding err is not nil because
|
||||
// dec.d.off points to the next CBOR data item if current
|
||||
// CBOR data item is valid but failed to be decoded into v.
|
||||
// This allows next CBOR data item to be decoded in next
|
||||
// call to this function.
|
||||
dec.off += dec.d.off
|
||||
dec.bytesRead += dec.d.off
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Skip skips to the next CBOR data item (if there is any),
|
||||
// otherwise it returns error such as io.EOF, io.UnexpectedEOF, etc.
|
||||
func (dec *Decoder) Skip() error {
|
||||
n, err := dec.readNext()
|
||||
if err != nil {
|
||||
// Return validation error or read error.
|
||||
return err
|
||||
}
|
||||
|
||||
dec.off += n
|
||||
dec.bytesRead += n
|
||||
return nil
|
||||
}
|
||||
|
||||
// NumBytesRead returns the number of bytes read.
|
||||
func (dec *Decoder) NumBytesRead() int {
|
||||
return dec.bytesRead
|
||||
}
|
||||
|
||||
// Buffered returns a reader for data remaining in Decoder's buffer.
|
||||
// Returned reader is valid until the next call to Decode or Skip.
|
||||
func (dec *Decoder) Buffered() io.Reader {
|
||||
return bytes.NewReader(dec.buf[dec.off:])
|
||||
}
|
||||
|
||||
// readNext() reads next CBOR data item from Reader to buffer.
|
||||
// It returns the size of next CBOR data item.
|
||||
// It also returns validation error or read error if any.
|
||||
func (dec *Decoder) readNext() (int, error) {
|
||||
var readErr error
|
||||
var validErr error
|
||||
|
||||
for {
|
||||
// Process any unread data in dec.buf.
|
||||
if dec.off < len(dec.buf) {
|
||||
dec.d.reset(dec.buf[dec.off:])
|
||||
off := dec.off // Save offset before data validation
|
||||
validErr = dec.d.wellformed(true, false)
|
||||
dec.off = off // Restore offset
|
||||
|
||||
if validErr == nil {
|
||||
return dec.d.off, nil
|
||||
}
|
||||
|
||||
if validErr != io.ErrUnexpectedEOF {
|
||||
return 0, validErr
|
||||
}
|
||||
|
||||
// Process last read error on io.ErrUnexpectedEOF.
|
||||
if readErr != nil {
|
||||
if readErr == io.EOF {
|
||||
// current CBOR data item is incomplete.
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
return 0, readErr
|
||||
}
|
||||
}
|
||||
|
||||
// More data is needed and there was no read error.
|
||||
var n int
|
||||
for n == 0 {
|
||||
n, readErr = dec.read()
|
||||
if n == 0 && readErr != nil {
|
||||
// No more data can be read and read error is encountered.
|
||||
// At this point, validErr is either nil or io.ErrUnexpectedEOF.
|
||||
if readErr == io.EOF {
|
||||
if validErr == io.ErrUnexpectedEOF {
|
||||
// current CBOR data item is incomplete.
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
}
|
||||
return 0, readErr
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, dec.buf contains new data from last read (n > 0).
|
||||
}
|
||||
}
|
||||
|
||||
// read() reads data from Reader to buffer.
|
||||
// It returns number of bytes read and any read error encountered.
|
||||
// Postconditions:
|
||||
// - dec.buf contains previously unread data and new data.
|
||||
// - dec.off is 0.
|
||||
func (dec *Decoder) read() (int, error) {
|
||||
// Grow buf if needed.
|
||||
const minRead = 512
|
||||
if cap(dec.buf)-len(dec.buf)+dec.off < minRead {
|
||||
oldUnreadBuf := dec.buf[dec.off:]
|
||||
dec.buf = make([]byte, len(dec.buf)-dec.off, 2*cap(dec.buf)+minRead)
|
||||
dec.overwriteBuf(oldUnreadBuf)
|
||||
}
|
||||
|
||||
// Copy unread data over read data and reset off to 0.
|
||||
if dec.off > 0 {
|
||||
dec.overwriteBuf(dec.buf[dec.off:])
|
||||
}
|
||||
|
||||
// Read from reader and reslice buf.
|
||||
n, err := dec.r.Read(dec.buf[len(dec.buf):cap(dec.buf)])
|
||||
dec.buf = dec.buf[0 : len(dec.buf)+n]
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (dec *Decoder) overwriteBuf(newBuf []byte) {
|
||||
n := copy(dec.buf, newBuf)
|
||||
dec.buf = dec.buf[:n]
|
||||
dec.off = 0
|
||||
}
|
||||
|
||||
// Encoder writes CBOR values to io.Writer.
|
||||
type Encoder struct {
|
||||
w io.Writer
|
||||
em *encMode
|
||||
indefTypes []cborType
|
||||
}
|
||||
|
||||
// NewEncoder returns a new encoder that writes to w using the default encoding options.
|
||||
func NewEncoder(w io.Writer) *Encoder {
|
||||
return defaultEncMode.NewEncoder(w)
|
||||
}
|
||||
|
||||
// Encode writes the CBOR encoding of v.
|
||||
func (enc *Encoder) Encode(v interface{}) error {
|
||||
if len(enc.indefTypes) > 0 && v != nil {
|
||||
indefType := enc.indefTypes[len(enc.indefTypes)-1]
|
||||
if indefType == cborTypeTextString {
|
||||
k := reflect.TypeOf(v).Kind()
|
||||
if k != reflect.String {
|
||||
return errors.New("cbor: cannot encode item type " + k.String() + " for indefinite-length text string")
|
||||
}
|
||||
} else if indefType == cborTypeByteString {
|
||||
t := reflect.TypeOf(v)
|
||||
k := t.Kind()
|
||||
if (k != reflect.Array && k != reflect.Slice) || t.Elem().Kind() != reflect.Uint8 {
|
||||
return errors.New("cbor: cannot encode item type " + k.String() + " for indefinite-length byte string")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buf := getEncodeBuffer()
|
||||
|
||||
err := encode(buf, enc.em, reflect.ValueOf(v))
|
||||
if err == nil {
|
||||
_, err = enc.w.Write(buf.Bytes())
|
||||
}
|
||||
|
||||
putEncodeBuffer(buf)
|
||||
return err
|
||||
}
|
||||
|
||||
// StartIndefiniteByteString starts byte string encoding of indefinite length.
|
||||
// Subsequent calls of (*Encoder).Encode() encodes definite length byte strings
|
||||
// ("chunks") as one contiguous string until EndIndefinite is called.
|
||||
func (enc *Encoder) StartIndefiniteByteString() error {
|
||||
return enc.startIndefinite(cborTypeByteString)
|
||||
}
|
||||
|
||||
// StartIndefiniteTextString starts text string encoding of indefinite length.
|
||||
// Subsequent calls of (*Encoder).Encode() encodes definite length text strings
|
||||
// ("chunks") as one contiguous string until EndIndefinite is called.
|
||||
func (enc *Encoder) StartIndefiniteTextString() error {
|
||||
return enc.startIndefinite(cborTypeTextString)
|
||||
}
|
||||
|
||||
// StartIndefiniteArray starts array encoding of indefinite length.
|
||||
// Subsequent calls of (*Encoder).Encode() encodes elements of the array
|
||||
// until EndIndefinite is called.
|
||||
func (enc *Encoder) StartIndefiniteArray() error {
|
||||
return enc.startIndefinite(cborTypeArray)
|
||||
}
|
||||
|
||||
// StartIndefiniteMap starts array encoding of indefinite length.
|
||||
// Subsequent calls of (*Encoder).Encode() encodes elements of the map
|
||||
// until EndIndefinite is called.
|
||||
func (enc *Encoder) StartIndefiniteMap() error {
|
||||
return enc.startIndefinite(cborTypeMap)
|
||||
}
|
||||
|
||||
// EndIndefinite closes last opened indefinite length value.
|
||||
func (enc *Encoder) EndIndefinite() error {
|
||||
if len(enc.indefTypes) == 0 {
|
||||
return errors.New("cbor: cannot encode \"break\" code outside indefinite length values")
|
||||
}
|
||||
_, err := enc.w.Write([]byte{cborBreakFlag})
|
||||
if err == nil {
|
||||
enc.indefTypes = enc.indefTypes[:len(enc.indefTypes)-1]
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
var cborIndefHeader = map[cborType][]byte{
|
||||
cborTypeByteString: {cborByteStringWithIndefiniteLengthHead},
|
||||
cborTypeTextString: {cborTextStringWithIndefiniteLengthHead},
|
||||
cborTypeArray: {cborArrayWithIndefiniteLengthHead},
|
||||
cborTypeMap: {cborMapWithIndefiniteLengthHead},
|
||||
}
|
||||
|
||||
func (enc *Encoder) startIndefinite(typ cborType) error {
|
||||
if enc.em.indefLength == IndefLengthForbidden {
|
||||
return &IndefiniteLengthError{typ}
|
||||
}
|
||||
_, err := enc.w.Write(cborIndefHeader[typ])
|
||||
if err == nil {
|
||||
enc.indefTypes = append(enc.indefTypes, typ)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// RawMessage is a raw encoded CBOR value.
|
||||
type RawMessage []byte
|
||||
|
||||
// MarshalCBOR returns m or CBOR nil if m is nil.
|
||||
func (m RawMessage) MarshalCBOR() ([]byte, error) {
|
||||
if len(m) == 0 {
|
||||
return cborNil, nil
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalCBOR creates a copy of data and saves to *m.
|
||||
func (m *RawMessage) UnmarshalCBOR(data []byte) error {
|
||||
if m == nil {
|
||||
return errors.New("cbor.RawMessage: UnmarshalCBOR on nil pointer")
|
||||
}
|
||||
*m = append((*m)[0:0], data...)
|
||||
return nil
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue