mirror of https://github.com/kubernetes/kops.git
Update dependencies
This commit is contained in:
parent
d269ac2994
commit
f9d9b112d0
31
go.mod
31
go.mod
|
@ -14,29 +14,29 @@ require (
|
|||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.0
|
||||
github.com/MakeNowJust/heredoc/v2 v2.0.1
|
||||
github.com/Masterminds/sprig/v3 v3.2.3
|
||||
github.com/Masterminds/sprig/v3 v3.3.0
|
||||
github.com/apparentlymart/go-cidr v1.1.0
|
||||
github.com/aws/amazon-ec2-instance-selector/v2 v2.4.2-0.20231216170552-14d4dfcbaadf
|
||||
github.com/aws/aws-sdk-go-v2 v1.30.4
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.30
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.29
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.31
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.30
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12
|
||||
github.com/aws/aws-sdk-go-v2/service/autoscaling v1.43.5
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.176.0
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.177.0
|
||||
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.26.5
|
||||
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.34.2
|
||||
github.com/aws/aws-sdk-go-v2/service/eventbridge v1.33.5
|
||||
github.com/aws/aws-sdk-go-v2/service/iam v1.35.0
|
||||
github.com/aws/aws-sdk-go-v2/service/kms v1.35.5
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.43.0
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.60.1
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.61.0
|
||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.34.5
|
||||
github.com/aws/aws-sdk-go-v2/service/ssm v1.52.6
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.30.5
|
||||
github.com/aws/smithy-go v1.20.4
|
||||
github.com/blang/semver/v4 v4.0.0
|
||||
github.com/cert-manager/cert-manager v1.15.3
|
||||
github.com/digitalocean/godo v1.120.0
|
||||
github.com/digitalocean/godo v1.121.0
|
||||
github.com/go-ini/ini v1.67.0
|
||||
github.com/go-jose/go-jose/v4 v4.0.4
|
||||
github.com/go-logr/logr v1.4.2
|
||||
|
@ -74,8 +74,8 @@ require (
|
|||
golang.org/x/oauth2 v0.22.0
|
||||
golang.org/x/sync v0.8.0
|
||||
golang.org/x/sys v0.24.0
|
||||
google.golang.org/api v0.194.0
|
||||
google.golang.org/grpc v1.65.0
|
||||
google.golang.org/api v0.195.0
|
||||
google.golang.org/grpc v1.66.0
|
||||
google.golang.org/protobuf v1.34.2
|
||||
gopkg.in/gcfg.v1 v1.2.3
|
||||
gopkg.in/inf.v0 v0.9.1
|
||||
|
@ -87,7 +87,7 @@ require (
|
|||
k8s.io/cloud-provider-aws v1.31.0
|
||||
k8s.io/cloud-provider-gcp/providers v0.28.2
|
||||
k8s.io/component-base v0.31.0
|
||||
k8s.io/gengo v0.0.0-20240815230951-44b8d154562d
|
||||
k8s.io/gengo v0.0.0-20240826214909-a7b603a56eb7
|
||||
k8s.io/klog/v2 v2.130.1
|
||||
k8s.io/kubectl v0.31.0
|
||||
k8s.io/kubelet v0.31.0
|
||||
|
@ -101,6 +101,7 @@ require (
|
|||
require (
|
||||
cloud.google.com/go/auth v0.9.1 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect
|
||||
dario.cat/mergo v1.0.1 // indirect
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
||||
|
@ -108,7 +109,7 @@ require (
|
|||
github.com/GoogleCloudPlatform/k8s-cloud-provider v1.25.0 // indirect
|
||||
github.com/MakeNowJust/heredoc v1.0.0 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.2.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.3.0 // indirect
|
||||
github.com/Microsoft/hcsshim v0.11.4 // indirect
|
||||
github.com/armon/go-metrics v0.4.1 // indirect
|
||||
github.com/atotto/clipboard v0.1.4 // indirect
|
||||
|
@ -188,7 +189,7 @@ require (
|
|||
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||
github.com/hashicorp/hcl v1.0.1-vault-5 // indirect
|
||||
github.com/hashicorp/memberlist v0.3.1 // indirect
|
||||
github.com/huandu/xstrings v1.4.0 // indirect
|
||||
github.com/huandu/xstrings v1.5.0 // indirect
|
||||
github.com/imdario/mergo v0.3.16 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 // indirect
|
||||
|
@ -245,11 +246,11 @@ require (
|
|||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/sahilm/fuzzy v0.1.0 // indirect
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
|
||||
github.com/shopspring/decimal v1.3.1 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/cast v1.7.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/vbatts/tar-split v0.11.3 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
|
@ -263,8 +264,8 @@ require (
|
|||
golang.org/x/time v0.6.0 // indirect
|
||||
golang.org/x/tools v0.24.0 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240730163845-b1a4ccb954bf // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240823204242-4ba0660f739c // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
|
|
76
go.sum
76
go.sum
|
@ -5,6 +5,8 @@ cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy
|
|||
cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc=
|
||||
cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY=
|
||||
cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
|
||||
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8=
|
||||
|
@ -48,11 +50,10 @@ github.com/MakeNowJust/heredoc/v2 v2.0.1 h1:rlCHh70XXXv7toz95ajQWOWQnN4WNLt0TdpZ
|
|||
github.com/MakeNowJust/heredoc/v2 v2.0.1/go.mod h1:6/2Abh5s+hc3g9nbWLe9ObDIOhaRrqsyY9MWy+4JdRM=
|
||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
|
||||
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
|
||||
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
|
||||
github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0=
|
||||
github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
||||
github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=
|
||||
github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8=
|
||||
|
@ -82,10 +83,10 @@ github.com/aws/aws-sdk-go-v2 v1.30.4 h1:frhcagrVNrzmT95RJImMHgabt99vkXGslubDaDag
|
|||
github.com/aws/aws-sdk-go-v2 v1.30.4/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4 h1:70PVAiL15/aBMh5LThwgXdSQorVr91L127ttckI9QQU=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4/go.mod h1:/MQxMqci8tlqDH+pjmoLu1i0tbWCUP1hhyMRuFxpQCw=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.30 h1:AQF3/+rOgeJBQP3iI4vojlPib5X6eeOYoa/af7OxAYg=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.30/go.mod h1:yxqvuubha9Vw8stEgNiStO+yZpP68Wm9hLmcm+R/Qk4=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.29 h1:CwGsupsXIlAFYuDVHv1nnK0wnxO0wZ/g1L8DSK/xiIw=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.29/go.mod h1:BPJ/yXV92ZVq6G8uYvbU0gSl8q94UB63nMT5ctNO38g=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.31 h1:kxBoRsjhT3pq0cKthgj6RU6bXTm/2SgdoUMyrVw0rAI=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.31/go.mod h1:z04nZdSWFPaDwK3DdJOG2r+scLQzMYuJeW0CujEm9FM=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.30 h1:aau/oYFtibVovr2rDt8FHlU17BTicFEMAi29V1U+L5Q=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.30/go.mod h1:BPJ/yXV92ZVq6G8uYvbU0gSl8q94UB63nMT5ctNO38g=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 h1:yjwoSyDZF8Jth+mUk5lSPJCkMC0lMy6FaCD51jm6ayE=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12/go.mod h1:fuR57fAgMk7ot3WcNQfb6rSEn+SUffl7ri+aa8uKysI=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41/go.mod h1:CrObHAuPneJBlfEJ5T3szXOUkLEThaGfvnhTf33buas=
|
||||
|
@ -100,8 +101,8 @@ github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.16 h1:mimdLQkIX1zr8GIPY1ZtALdBQGx
|
|||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.16/go.mod h1:YHk6owoSwrIsok+cAH9PENCOGoH5PU2EllX4vLtSrsY=
|
||||
github.com/aws/aws-sdk-go-v2/service/autoscaling v1.43.5 h1:b9wq1tEV06De56Vzpif7MFtMmErKWh+WureDxMwItnE=
|
||||
github.com/aws/aws-sdk-go-v2/service/autoscaling v1.43.5/go.mod h1:dDC/8RWLlLrUEoVJB04yka2iIWkFdtAAliefSH+FUlo=
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.176.0 h1:fWhkSvaQqa5eWiRwBw10FUnk1YatAQ9We4GdGxKiCtg=
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.176.0/go.mod h1:ISODge3zgdwOEa4Ou6WM9PKbxJWJ15DYKnr2bfmCAIA=
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.177.0 h1:LAdDRIj5BEZM9fLDTUWUyPzWvv5A++nCEps/RGmZNOo=
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.177.0/go.mod h1:ISODge3zgdwOEa4Ou6WM9PKbxJWJ15DYKnr2bfmCAIA=
|
||||
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.26.5 h1:DjOizZWhTjae9Qc4Dln6yle4Bb+CtVWQVS9cpAyE1sg=
|
||||
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.26.5/go.mod h1:LmgiPApGNIhqMYvqutZx8OZp/ia8Dzp89BaqH8TaQQ8=
|
||||
github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.34.2 h1:pWaVzH7OFh4MmHTjIGBNRTbFauJDVpIaRTtGF1BEq2o=
|
||||
|
@ -124,8 +125,8 @@ github.com/aws/aws-sdk-go-v2/service/pricing v1.21.6 h1:k/f3T13s7wx/By6aKovlVsjd
|
|||
github.com/aws/aws-sdk-go-v2/service/pricing v1.21.6/go.mod h1:9n3tkRCngy3+Iw/8vK3C69iXh22SCGsy3yn16nTxH+s=
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.43.0 h1:xtp7jye7KhWu4ptBs5yh1Vep0vLAGSNGmArOUp997DU=
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.43.0/go.mod h1:QN7tFo/W8QjLCR6aPZqMZKaVQJiAp95r/g78x1LWtkA=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.60.1 h1:mx2ucgtv+MWzJesJY9Ig/8AFHgoE5FwLXwUVgW/FGdI=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.60.1/go.mod h1:BSPI0EfnYUuNHPS0uqIo5VrRwzie+Fp+YhQOUs16sKI=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.61.0 h1:Wb544Wh+xfSXqJ/j3R4aX9wrKUoZsJNmilBYZb3mKQ4=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.61.0/go.mod h1:BSPI0EfnYUuNHPS0uqIo5VrRwzie+Fp+YhQOUs16sKI=
|
||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.34.5 h1:HYyVDOC2/PIg+3oBX1q0wtDU5kONki6lrgIG0afrBkY=
|
||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.34.5/go.mod h1:7idt3XszF6sE9WPS1GqZRiDJOxw4oPtlRBXodWnCGjU=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssm v1.52.6 h1:uvd3OF/3jt2csfs2xZ64NIOukDY/YJYZiHqT9vP3Mhg=
|
||||
|
@ -200,8 +201,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
|||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
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/digitalocean/godo v1.120.0 h1:t2DpzIitSnCDNQM7svSW4+cZd8E4Lv6+r8y33Kym0Xw=
|
||||
github.com/digitalocean/godo v1.120.0/go.mod h1:WQVH83OHUy6gC4gXpEVQKtxTd4L5oCp+5OialidkPLY=
|
||||
github.com/digitalocean/godo v1.121.0 h1:ilXiHuEnhbJs2fmFEPX0r/QQ6KfiOIMAhJN3f8NiCfI=
|
||||
github.com/digitalocean/godo v1.121.0/go.mod h1:WQVH83OHUy6gC4gXpEVQKtxTd4L5oCp+5OialidkPLY=
|
||||
github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc=
|
||||
github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2/go.mod h1:WHNsWjnIn2V1LYOrME7e8KxSeKunYHsxEm4am0BUtcI=
|
||||
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
|
||||
|
@ -359,7 +360,6 @@ github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO
|
|||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
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.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
|
@ -414,10 +414,8 @@ github.com/hashicorp/memberlist v0.3.1 h1:MXgUXLqva1QvpVEDQW1IQLG0wivQAtmFlHRQ+1
|
|||
github.com/hashicorp/memberlist v0.3.1/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
|
||||
github.com/hetznercloud/hcloud-go v1.59.1 h1:YwRRO4KemQZWsyL3Yp3cUH0Z7MQQ94keiBJ/VaTmlsM=
|
||||
github.com/hetznercloud/hcloud-go v1.59.1/go.mod h1:oTebZCjd+osj75jlI76Z+zjN1sTxmMiQ1MWoO8aRl1c=
|
||||
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
|
||||
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
|
||||
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
|
||||
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
|
@ -480,7 +478,6 @@ github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKju
|
|||
github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs=
|
||||
github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
|
@ -490,7 +487,6 @@ github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQ
|
|||
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
|
||||
|
@ -612,9 +608,8 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUt
|
|||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
||||
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
|
||||
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
|
||||
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.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
|
@ -624,9 +619,8 @@ github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9yS
|
|||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
|
||||
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
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=
|
||||
|
@ -644,7 +638,6 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/
|
|||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.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.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
|
@ -707,7 +700,6 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
|||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
|
@ -739,7 +731,6 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
|||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
|
@ -777,7 +768,6 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
||||
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
|
@ -785,7 +775,6 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
|
|||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
|
||||
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
@ -817,24 +806,24 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
|
|||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
|
||||
google.golang.org/api v0.194.0 h1:dztZKG9HgtIpbI35FhfuSNR/zmaMVdxNlntHj1sIS4s=
|
||||
google.golang.org/api v0.194.0/go.mod h1:AgvUFdojGANh3vI+P7EVnxj3AISHllxGCJSFmggmnd0=
|
||||
google.golang.org/api v0.195.0 h1:Ude4N8FvTKnnQJHU48RFI40jOBgIrL8Zqr3/QeST6yU=
|
||||
google.golang.org/api v0.195.0/go.mod h1:DOGRWuv3P8TU8Lnz7uQc4hyNqrBpMtD9ppW3wBJurgc=
|
||||
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/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240730163845-b1a4ccb954bf h1:GillM0Ef0pkZPIB+5iO6SDK+4T9pf6TpaYR6ICD5rVE=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240730163845-b1a4ccb954bf/go.mod h1:OFMYQFHJ4TM3JRlWDZhJbZfra2uqc3WLBZiaaqP4DtU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240823204242-4ba0660f739c h1:Kqjm4WpoWvwhMPcrAczoTyMySQmYa9Wy2iL6Con4zn8=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240823204242-4ba0660f739c/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
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.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
|
||||
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
|
||||
google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
|
||||
google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
|
||||
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=
|
||||
|
@ -866,7 +855,6 @@ gopkg.in/yaml.v2 v2.2.2/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=
|
||||
|
@ -896,8 +884,8 @@ k8s.io/cloud-provider-gcp/providers v0.28.2 h1:I65pFTLNMQSj7YuW3Mg3pZIXmw0naCmF6
|
|||
k8s.io/cloud-provider-gcp/providers v0.28.2/go.mod h1:P8dxRvvLtX7xUwVUzA/QOqv8taCzBaVsVMnjnpjmYXE=
|
||||
k8s.io/component-base v0.31.0 h1:/KIzGM5EvPNQcYgwq5NwoQBaOlVFrghoVGr8lG6vNRs=
|
||||
k8s.io/component-base v0.31.0/go.mod h1:TYVuzI1QmN4L5ItVdMSXKvH7/DtvIuas5/mm8YT3rTo=
|
||||
k8s.io/gengo v0.0.0-20240815230951-44b8d154562d h1:k9+VnMFK87/cliLr/mdSWNKKI7KXQEnk9bqZLgeMSIc=
|
||||
k8s.io/gengo v0.0.0-20240815230951-44b8d154562d/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/gengo v0.0.0-20240826214909-a7b603a56eb7 h1:HCbtr1pVu/ElMcTTs18KdMtH5y6f7PQvrjh1QZj3qCI=
|
||||
k8s.io/gengo v0.0.0-20240826214909-a7b603a56eb7/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
|
||||
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||
|
|
|
@ -152,7 +152,7 @@ require (
|
|||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/sourcegraph/go-diff v0.7.0 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/cast v1.7.0 // indirect
|
||||
github.com/spf13/cobra v1.8.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.19.0 // indirect
|
||||
|
|
|
@ -510,8 +510,8 @@ github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCp
|
|||
github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
|
||||
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
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=
|
||||
|
|
|
@ -27,10 +27,10 @@ require (
|
|||
cloud.google.com/go/auth v0.9.1 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.5.0 // indirect
|
||||
cloud.google.com/go/iam v1.1.12 // indirect
|
||||
cloud.google.com/go/iam v1.1.13 // indirect
|
||||
cloud.google.com/go/storage v1.43.0 // indirect
|
||||
cuelang.org/go v0.5.0 // indirect
|
||||
dario.cat/mergo v1.0.0 // indirect
|
||||
dario.cat/mergo v1.0.1 // indirect
|
||||
filippo.io/edwards25519 v1.0.0 // indirect
|
||||
github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
|
||||
|
@ -69,21 +69,21 @@ require (
|
|||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.30.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.30 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.29 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.31 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.30 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.176.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.177.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.15.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.12.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.18 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.60.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.61.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.30.5 // indirect
|
||||
|
@ -236,7 +236,7 @@ require (
|
|||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/cast v1.7.0 // indirect
|
||||
github.com/spf13/cobra v1.8.1 // indirect
|
||||
github.com/spf13/viper v1.19.0 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.1.6 // indirect
|
||||
|
@ -280,11 +280,11 @@ require (
|
|||
golang.org/x/time v0.6.0 // indirect
|
||||
golang.org/x/tools v0.24.0 // indirect
|
||||
golang.org/x/tools/go/vcs v0.1.0-deprecated // indirect
|
||||
google.golang.org/api v0.194.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240814211410-ddb44dafa142 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240730163845-b1a4ccb954bf // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
|
||||
google.golang.org/grpc v1.65.0 // indirect
|
||||
google.golang.org/api v0.195.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240823204242-4ba0660f739c // indirect
|
||||
google.golang.org/grpc v1.66.0 // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/gcfg.v1 v1.2.3 // indirect
|
||||
|
|
|
@ -19,12 +19,12 @@ cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJ
|
|||
cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
cloud.google.com/go/iam v1.1.12 h1:JixGLimRrNGcxvJEQ8+clfLxPlbeZA6MuRJ+qJNQ5Xw=
|
||||
cloud.google.com/go/iam v1.1.12/go.mod h1:9LDX8J7dN5YRyzVHxwQzrQs9opFFqn0Mxs9nAeB+Hhg=
|
||||
cloud.google.com/go/kms v1.18.4 h1:dYN3OCsQ6wJLLtOnI8DGUwQ5shMusXsWCCC+s09ATsk=
|
||||
cloud.google.com/go/kms v1.18.4/go.mod h1:SG1bgQ3UWW6/KdPo9uuJnzELXY5YTTMJtDYvajiQ22g=
|
||||
cloud.google.com/go/longrunning v0.5.11 h1:Havn1kGjz3whCfoD8dxMLP73Ph5w+ODyZB9RUsDxtGk=
|
||||
cloud.google.com/go/longrunning v0.5.11/go.mod h1:rDn7//lmlfWV1Dx6IB4RatCPenTwwmqXuiP0/RgoEO4=
|
||||
cloud.google.com/go/iam v1.1.13 h1:7zWBXG9ERbMLrzQBRhFliAV+kjcRToDTgQT3CTwYyv4=
|
||||
cloud.google.com/go/iam v1.1.13/go.mod h1:K8mY0uSXwEXS30KrnVb+j54LB/ntfZu1dr+4zFMNbus=
|
||||
cloud.google.com/go/kms v1.18.5 h1:75LSlVs60hyHK3ubs2OHd4sE63OAMcM2BdSJc2bkuM4=
|
||||
cloud.google.com/go/kms v1.18.5/go.mod h1:yXunGUGzabH8rjUPImp2ndHiGolHeWJJ0LODLedicIY=
|
||||
cloud.google.com/go/longrunning v0.5.12 h1:5LqSIdERr71CqfUsFlJdBpOkBH8FBCFD7P1nTWy3TYE=
|
||||
cloud.google.com/go/longrunning v0.5.12/go.mod h1:S5hMV8CDJ6r50t2ubVJSKQVv5u0rmik5//KgLO3k4lU=
|
||||
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/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
|
@ -33,8 +33,8 @@ cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyX
|
|||
cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0=
|
||||
cuelang.org/go v0.5.0 h1:D6N0UgTGJCOxFKU8RU+qYvavKNsVc/+ZobmifStVJzU=
|
||||
cuelang.org/go v0.5.0/go.mod h1:okjJBHFQFer+a41sAe2SaGm1glWS8oEb6CmJvn5Zdws=
|
||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
|
||||
filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
|
||||
|
@ -179,11 +179,11 @@ github.com/aws/aws-sdk-go-v2 v1.30.4/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6Wtu
|
|||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4 h1:70PVAiL15/aBMh5LThwgXdSQorVr91L127ttckI9QQU=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4/go.mod h1:/MQxMqci8tlqDH+pjmoLu1i0tbWCUP1hhyMRuFxpQCw=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.5.0/go.mod h1:RWlPOAW3E3tbtNAqTwvSW54Of/yP3oiZXMI0xfUdjyA=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.30 h1:AQF3/+rOgeJBQP3iI4vojlPib5X6eeOYoa/af7OxAYg=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.30/go.mod h1:yxqvuubha9Vw8stEgNiStO+yZpP68Wm9hLmcm+R/Qk4=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.31 h1:kxBoRsjhT3pq0cKthgj6RU6bXTm/2SgdoUMyrVw0rAI=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.31/go.mod h1:z04nZdSWFPaDwK3DdJOG2r+scLQzMYuJeW0CujEm9FM=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.3.1/go.mod h1:r0n73xwsIVagq8RsxmZbGSRQFj9As3je72C2WzUIToc=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.29 h1:CwGsupsXIlAFYuDVHv1nnK0wnxO0wZ/g1L8DSK/xiIw=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.29/go.mod h1:BPJ/yXV92ZVq6G8uYvbU0gSl8q94UB63nMT5ctNO38g=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.30 h1:aau/oYFtibVovr2rDt8FHlU17BTicFEMAi29V1U+L5Q=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.30/go.mod h1:BPJ/yXV92ZVq6G8uYvbU0gSl8q94UB63nMT5ctNO38g=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.3.0/go.mod h1:2LAuqPx1I6jNfaGDucWfA2zqQCYCOMCDHiCOciALyNw=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 h1:yjwoSyDZF8Jth+mUk5lSPJCkMC0lMy6FaCD51jm6ayE=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12/go.mod h1:fuR57fAgMk7ot3WcNQfb6rSEn+SUffl7ri+aa8uKysI=
|
||||
|
@ -198,8 +198,8 @@ github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvK
|
|||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.16 h1:mimdLQkIX1zr8GIPY1ZtALdBQGxcASiBd2MOp8m/dMc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.16/go.mod h1:YHk6owoSwrIsok+cAH9PENCOGoH5PU2EllX4vLtSrsY=
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.176.0 h1:fWhkSvaQqa5eWiRwBw10FUnk1YatAQ9We4GdGxKiCtg=
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.176.0/go.mod h1:ISODge3zgdwOEa4Ou6WM9PKbxJWJ15DYKnr2bfmCAIA=
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.177.0 h1:LAdDRIj5BEZM9fLDTUWUyPzWvv5A++nCEps/RGmZNOo=
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.177.0/go.mod h1:ISODge3zgdwOEa4Ou6WM9PKbxJWJ15DYKnr2bfmCAIA=
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.4.1/go.mod h1:FglZcyeiBqcbvyinl+n14aT/EWC7S1MIH+Gan2iizt0=
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.15.0 h1:lY2Z2sBP+zSbJ6CvvmnFgPcgknoQ0OJV88AwVetRRFk=
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.15.0/go.mod h1:4zYI85WiYDhFaU1jPFVfkD7HlBcdnITDE3QxDwy4Kus=
|
||||
|
@ -217,8 +217,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.16 h1:jg16PhLPUiHIj
|
|||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.16/go.mod h1:Uyk1zE1VVdsHSU7096h/rwnXDzOzYQVl+FNPhPw7ShY=
|
||||
github.com/aws/aws-sdk-go-v2/service/kms v1.35.5 h1:XUomV7SiclZl1QuXORdGcfFqHxEHET7rmNGtxTfNB+M=
|
||||
github.com/aws/aws-sdk-go-v2/service/kms v1.35.5/go.mod h1:A5CS0VRmxxj2YKYLCY08l/Zzbd01m6JZn0WzxgT1OCA=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.60.1 h1:mx2ucgtv+MWzJesJY9Ig/8AFHgoE5FwLXwUVgW/FGdI=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.60.1/go.mod h1:BSPI0EfnYUuNHPS0uqIo5VrRwzie+Fp+YhQOUs16sKI=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.61.0 h1:Wb544Wh+xfSXqJ/j3R4aX9wrKUoZsJNmilBYZb3mKQ4=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.61.0/go.mod h1:BSPI0EfnYUuNHPS0uqIo5VrRwzie+Fp+YhQOUs16sKI=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.3.1/go.mod h1:J3A3RGUvuCZjvSuZEcOpHDnzZP/sKbhDWV2T1EOzFIM=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 h1:zCsFCKvbj25i7p1u94imVoO447I/sFv8qq+lGJhRN0c=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.22.5/go.mod h1:ZeDX1SnKsVlejeuz41GiajjZpRSWR7/42q/EyA/QEiM=
|
||||
|
@ -928,8 +928,8 @@ github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
|||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
|
||||
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
|
@ -1338,8 +1338,8 @@ google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb
|
|||
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.194.0 h1:dztZKG9HgtIpbI35FhfuSNR/zmaMVdxNlntHj1sIS4s=
|
||||
google.golang.org/api v0.194.0/go.mod h1:AgvUFdojGANh3vI+P7EVnxj3AISHllxGCJSFmggmnd0=
|
||||
google.golang.org/api v0.195.0 h1:Ude4N8FvTKnnQJHU48RFI40jOBgIrL8Zqr3/QeST6yU=
|
||||
google.golang.org/api v0.195.0/go.mod h1:DOGRWuv3P8TU8Lnz7uQc4hyNqrBpMtD9ppW3wBJurgc=
|
||||
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=
|
||||
|
@ -1359,12 +1359,12 @@ google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvx
|
|||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20240814211410-ddb44dafa142 h1:oLiyxGgE+rt22duwci1+TG7bg2/L1LQsXwfjPlmuJA0=
|
||||
google.golang.org/genproto v0.0.0-20240814211410-ddb44dafa142/go.mod h1:G11eXq53iI5Q+kyNOmCvnzBaxEA2Q/Ik5Tj7nqBE8j4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240730163845-b1a4ccb954bf h1:GillM0Ef0pkZPIB+5iO6SDK+4T9pf6TpaYR6ICD5rVE=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240730163845-b1a4ccb954bf/go.mod h1:OFMYQFHJ4TM3JRlWDZhJbZfra2uqc3WLBZiaaqP4DtU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||
google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c h1:TYOEhrQMrNDTAd2rX9m+WgGr8Ku6YNuj1D7OX6rWSok=
|
||||
google.golang.org/genproto v0.0.0-20240823204242-4ba0660f739c/go.mod h1:2rC5OendXvZ8wGEo/cSLheztrZDZaSoHanUcd1xtZnw=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240823204242-4ba0660f739c h1:Kqjm4WpoWvwhMPcrAczoTyMySQmYa9Wy2iL6Con4zn8=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240823204242-4ba0660f739c/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||
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.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
|
@ -1375,8 +1375,8 @@ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
|
|||
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.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
|
||||
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
|
||||
google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
|
||||
google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
|
||||
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=
|
||||
|
|
|
@ -4,7 +4,7 @@ go 1.22.5
|
|||
|
||||
require (
|
||||
go.opentelemetry.io/proto/otlp v1.3.1
|
||||
google.golang.org/grpc v1.65.0
|
||||
google.golang.org/grpc v1.66.0
|
||||
google.golang.org/protobuf v1.34.2
|
||||
k8s.io/klog/v2 v2.130.1
|
||||
k8s.io/kops v1.28.0
|
||||
|
@ -44,9 +44,9 @@ require (
|
|||
golang.org/x/oauth2 v0.22.0 // indirect
|
||||
golang.org/x/sys v0.24.0 // indirect
|
||||
golang.org/x/text v0.17.0 // indirect
|
||||
google.golang.org/api v0.194.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240730163845-b1a4ccb954bf // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
|
||||
google.golang.org/api v0.195.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240823204242-4ba0660f739c // indirect
|
||||
k8s.io/apimachinery v0.31.0 // indirect
|
||||
k8s.io/client-go v0.31.0 // indirect
|
||||
k8s.io/utils v0.0.0-20240821151609-f90d01438635 // indirect
|
||||
|
|
|
@ -206,24 +206,24 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
|||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.194.0 h1:dztZKG9HgtIpbI35FhfuSNR/zmaMVdxNlntHj1sIS4s=
|
||||
google.golang.org/api v0.194.0/go.mod h1:AgvUFdojGANh3vI+P7EVnxj3AISHllxGCJSFmggmnd0=
|
||||
google.golang.org/api v0.195.0 h1:Ude4N8FvTKnnQJHU48RFI40jOBgIrL8Zqr3/QeST6yU=
|
||||
google.golang.org/api v0.195.0/go.mod h1:DOGRWuv3P8TU8Lnz7uQc4hyNqrBpMtD9ppW3wBJurgc=
|
||||
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/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240730163845-b1a4ccb954bf h1:GillM0Ef0pkZPIB+5iO6SDK+4T9pf6TpaYR6ICD5rVE=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240730163845-b1a4ccb954bf/go.mod h1:OFMYQFHJ4TM3JRlWDZhJbZfra2uqc3WLBZiaaqP4DtU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240823204242-4ba0660f739c h1:Kqjm4WpoWvwhMPcrAczoTyMySQmYa9Wy2iL6Con4zn8=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240823204242-4ba0660f739c/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
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.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
|
||||
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
|
||||
google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
|
||||
google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
|
||||
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=
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
version = 1
|
||||
|
||||
test_patterns = [
|
||||
"*_test.go"
|
||||
]
|
||||
|
||||
[[analyzers]]
|
||||
name = "go"
|
||||
enabled = true
|
||||
|
||||
[analyzers.meta]
|
||||
import_path = "dario.cat/mergo"
|
|
@ -0,0 +1,36 @@
|
|||
#### joe made this: http://goel.io/joe
|
||||
|
||||
#### go ####
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Golang/Intellij
|
||||
.idea
|
||||
|
||||
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
||||
.glide/
|
||||
|
||||
#### vim ####
|
||||
# Swap
|
||||
[._]*.s[a-v][a-z]
|
||||
[._]*.sw[a-p]
|
||||
[._]s[a-v][a-z]
|
||||
[._]sw[a-p]
|
||||
|
||||
# Session
|
||||
Session.vim
|
||||
|
||||
# Temporary
|
||||
.netrwhist
|
||||
*~
|
||||
# Auto-generated tag files
|
||||
tags
|
|
@ -0,0 +1,12 @@
|
|||
language: go
|
||||
arch:
|
||||
- amd64
|
||||
- ppc64le
|
||||
install:
|
||||
- go get -t
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
- go get github.com/mattn/goveralls
|
||||
script:
|
||||
- go test -race -v ./...
|
||||
after_script:
|
||||
- $HOME/gopath/bin/goveralls -service=travis-ci -repotoken $COVERALLS_TOKEN
|
|
@ -0,0 +1,46 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers 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, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at i@dario.im. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
|
@ -0,0 +1,112 @@
|
|||
<!-- omit in toc -->
|
||||
# Contributing to mergo
|
||||
|
||||
First off, thanks for taking the time to contribute! ❤️
|
||||
|
||||
All types of contributions are encouraged and valued. See the [Table of Contents](#table-of-contents) for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 🎉
|
||||
|
||||
> And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about:
|
||||
> - Star the project
|
||||
> - Tweet about it
|
||||
> - Refer this project in your project's readme
|
||||
> - Mention the project at local meetups and tell your friends/colleagues
|
||||
|
||||
<!-- omit in toc -->
|
||||
## Table of Contents
|
||||
|
||||
- [Code of Conduct](#code-of-conduct)
|
||||
- [I Have a Question](#i-have-a-question)
|
||||
- [I Want To Contribute](#i-want-to-contribute)
|
||||
- [Reporting Bugs](#reporting-bugs)
|
||||
- [Suggesting Enhancements](#suggesting-enhancements)
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project and everyone participating in it is governed by the
|
||||
[mergo Code of Conduct](https://github.com/imdario/mergoblob/master/CODE_OF_CONDUCT.md).
|
||||
By participating, you are expected to uphold this code. Please report unacceptable behavior
|
||||
to <>.
|
||||
|
||||
|
||||
## I Have a Question
|
||||
|
||||
> If you want to ask a question, we assume that you have read the available [Documentation](https://pkg.go.dev/github.com/imdario/mergo).
|
||||
|
||||
Before you ask a question, it is best to search for existing [Issues](https://github.com/imdario/mergo/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first.
|
||||
|
||||
If you then still feel the need to ask a question and need clarification, we recommend the following:
|
||||
|
||||
- Open an [Issue](https://github.com/imdario/mergo/issues/new).
|
||||
- Provide as much context as you can about what you're running into.
|
||||
- Provide project and platform versions (nodejs, npm, etc), depending on what seems relevant.
|
||||
|
||||
We will then take care of the issue as soon as possible.
|
||||
|
||||
## I Want To Contribute
|
||||
|
||||
> ### Legal Notice <!-- omit in toc -->
|
||||
> When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license.
|
||||
|
||||
### Reporting Bugs
|
||||
|
||||
<!-- omit in toc -->
|
||||
#### Before Submitting a Bug Report
|
||||
|
||||
A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible.
|
||||
|
||||
- Make sure that you are using the latest version.
|
||||
- Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the [documentation](). If you are looking for support, you might want to check [this section](#i-have-a-question)).
|
||||
- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker](https://github.com/imdario/mergoissues?q=label%3Abug).
|
||||
- Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue.
|
||||
- Collect information about the bug:
|
||||
- Stack trace (Traceback)
|
||||
- OS, Platform and Version (Windows, Linux, macOS, x86, ARM)
|
||||
- Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant.
|
||||
- Possibly your input and the output
|
||||
- Can you reliably reproduce the issue? And can you also reproduce it with older versions?
|
||||
|
||||
<!-- omit in toc -->
|
||||
#### How Do I Submit a Good Bug Report?
|
||||
|
||||
> You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to .
|
||||
<!-- You may add a PGP key to allow the messages to be sent encrypted as well. -->
|
||||
|
||||
We use GitHub issues to track bugs and errors. If you run into an issue with the project:
|
||||
|
||||
- Open an [Issue](https://github.com/imdario/mergo/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.)
|
||||
- Explain the behavior you would expect and the actual behavior.
|
||||
- Please provide as much context as possible and describe the *reproduction steps* that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case.
|
||||
- Provide the information you collected in the previous section.
|
||||
|
||||
Once it's filed:
|
||||
|
||||
- The project team will label the issue accordingly.
|
||||
- A team member will try to reproduce the issue with your provided steps. If there are no reproduction steps or no obvious way to reproduce the issue, the team will ask you for those steps and mark the issue as `needs-repro`. Bugs with the `needs-repro` tag will not be addressed until they are reproduced.
|
||||
- If the team is able to reproduce the issue, it will be marked `needs-fix`, as well as possibly other tags (such as `critical`), and the issue will be left to be implemented by someone.
|
||||
|
||||
### Suggesting Enhancements
|
||||
|
||||
This section guides you through submitting an enhancement suggestion for mergo, **including completely new features and minor improvements to existing functionality**. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions.
|
||||
|
||||
<!-- omit in toc -->
|
||||
#### Before Submitting an Enhancement
|
||||
|
||||
- Make sure that you are using the latest version.
|
||||
- Read the [documentation]() carefully and find out if the functionality is already covered, maybe by an individual configuration.
|
||||
- Perform a [search](https://github.com/imdario/mergo/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
|
||||
- Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library.
|
||||
|
||||
<!-- omit in toc -->
|
||||
#### How Do I Submit a Good Enhancement Suggestion?
|
||||
|
||||
Enhancement suggestions are tracked as [GitHub issues](https://github.com/imdario/mergo/issues).
|
||||
|
||||
- Use a **clear and descriptive title** for the issue to identify the suggestion.
|
||||
- Provide a **step-by-step description of the suggested enhancement** in as many details as possible.
|
||||
- **Describe the current behavior** and **explain which behavior you expected to see instead** and why. At this point you can also tell which alternatives do not work for you.
|
||||
- You may want to **include screenshots and animated GIFs** which help you demonstrate the steps or point out the part which the suggestion is related to. You can use [this tool](https://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [this tool](https://github.com/colinkeenan/silentcast) or [this tool](https://github.com/GNOME/byzanz) on Linux. <!-- this should only be included if the project has a GUI -->
|
||||
- **Explain why this enhancement would be useful** to most mergo users. You may also want to point out the other projects that solved it better and which could serve as inspiration.
|
||||
|
||||
<!-- omit in toc -->
|
||||
## Attribution
|
||||
This guide is based on the **contributing-gen**. [Make your own](https://github.com/bttger/contributing-gen)!
|
|
@ -0,0 +1,28 @@
|
|||
Copyright (c) 2013 Dario Castañé. All rights reserved.
|
||||
Copyright (c) 2012 The Go Authors. 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 Google Inc. 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
|
||||
OWNER 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.
|
|
@ -0,0 +1,258 @@
|
|||
# Mergo
|
||||
|
||||
[![GitHub release][5]][6]
|
||||
[![GoCard][7]][8]
|
||||
[![Test status][1]][2]
|
||||
[![OpenSSF Scorecard][21]][22]
|
||||
[![OpenSSF Best Practices][19]][20]
|
||||
[![Coverage status][9]][10]
|
||||
[![Sourcegraph][11]][12]
|
||||
[![FOSSA status][13]][14]
|
||||
|
||||
[![GoDoc][3]][4]
|
||||
[![Become my sponsor][15]][16]
|
||||
[![Tidelift][17]][18]
|
||||
|
||||
[1]: https://github.com/imdario/mergo/workflows/tests/badge.svg?branch=master
|
||||
[2]: https://github.com/imdario/mergo/actions/workflows/tests.yml
|
||||
[3]: https://godoc.org/github.com/imdario/mergo?status.svg
|
||||
[4]: https://godoc.org/github.com/imdario/mergo
|
||||
[5]: https://img.shields.io/github/release/imdario/mergo.svg
|
||||
[6]: https://github.com/imdario/mergo/releases
|
||||
[7]: https://goreportcard.com/badge/imdario/mergo
|
||||
[8]: https://goreportcard.com/report/github.com/imdario/mergo
|
||||
[9]: https://coveralls.io/repos/github/imdario/mergo/badge.svg?branch=master
|
||||
[10]: https://coveralls.io/github/imdario/mergo?branch=master
|
||||
[11]: https://sourcegraph.com/github.com/imdario/mergo/-/badge.svg
|
||||
[12]: https://sourcegraph.com/github.com/imdario/mergo?badge
|
||||
[13]: https://app.fossa.io/api/projects/git%2Bgithub.com%2Fimdario%2Fmergo.svg?type=shield
|
||||
[14]: https://app.fossa.io/projects/git%2Bgithub.com%2Fimdario%2Fmergo?ref=badge_shield
|
||||
[15]: https://img.shields.io/github/sponsors/imdario
|
||||
[16]: https://github.com/sponsors/imdario
|
||||
[17]: https://tidelift.com/badges/package/go/github.com%2Fimdario%2Fmergo
|
||||
[18]: https://tidelift.com/subscription/pkg/go-github.com-imdario-mergo
|
||||
[19]: https://bestpractices.coreinfrastructure.org/projects/7177/badge
|
||||
[20]: https://bestpractices.coreinfrastructure.org/projects/7177
|
||||
[21]: https://api.securityscorecards.dev/projects/github.com/imdario/mergo/badge
|
||||
[22]: https://api.securityscorecards.dev/projects/github.com/imdario/mergo
|
||||
|
||||
A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements.
|
||||
|
||||
Mergo merges same-type structs and maps by setting default values in zero-value fields. Mergo won't merge unexported (private) fields. It will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection).
|
||||
|
||||
Also a lovely [comune](http://en.wikipedia.org/wiki/Mergo) (municipality) in the Province of Ancona in the Italian region of Marche.
|
||||
|
||||
## Status
|
||||
|
||||
Mergo is stable and frozen, ready for production. Check a short list of the projects using at large scale it [here](https://github.com/imdario/mergo#mergo-in-the-wild).
|
||||
|
||||
No new features are accepted. They will be considered for a future v2 that improves the implementation and fixes bugs for corner cases.
|
||||
|
||||
### Important notes
|
||||
|
||||
#### 1.0.0
|
||||
|
||||
In [1.0.0](//github.com/imdario/mergo/releases/tag/1.0.0) Mergo moves to a vanity URL `dario.cat/mergo`. No more v1 versions will be released.
|
||||
|
||||
If the vanity URL is causing issues in your project due to a dependency pulling Mergo - it isn't a direct dependency in your project - it is recommended to use [replace](https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive) to pin the version to the last one with the old import URL:
|
||||
|
||||
```
|
||||
replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.16
|
||||
```
|
||||
|
||||
#### 0.3.9
|
||||
|
||||
Please keep in mind that a problematic PR broke [0.3.9](//github.com/imdario/mergo/releases/tag/0.3.9). I reverted it in [0.3.10](//github.com/imdario/mergo/releases/tag/0.3.10), and I consider it stable but not bug-free. Also, this version adds support for go modules.
|
||||
|
||||
Keep in mind that in [0.3.2](//github.com/imdario/mergo/releases/tag/0.3.2), Mergo changed `Merge()`and `Map()` signatures to support [transformers](#transformers). I added an optional/variadic argument so that it won't break the existing code.
|
||||
|
||||
If you were using Mergo before April 6th, 2015, please check your project works as intended after updating your local copy with ```go get -u dario.cat/mergo```. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause in existing projects after the change (release 0.2.0).
|
||||
|
||||
### Donations
|
||||
|
||||
If Mergo is useful to you, consider buying me a coffee, a beer, or making a monthly donation to allow me to keep building great free software. :heart_eyes:
|
||||
|
||||
<a href="https://liberapay.com/dario/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a>
|
||||
<a href='https://github.com/sponsors/imdario' target='_blank'><img alt="Become my sponsor" src="https://img.shields.io/github/sponsors/imdario?style=for-the-badge" /></a>
|
||||
|
||||
### Mergo in the wild
|
||||
|
||||
Mergo is used by [thousands](https://deps.dev/go/dario.cat%2Fmergo/v1.0.0/dependents) [of](https://deps.dev/go/github.com%2Fimdario%2Fmergo/v0.3.16/dependents) [projects](https://deps.dev/go/github.com%2Fimdario%2Fmergo/v0.3.12), including:
|
||||
|
||||
* [containerd/containerd](https://github.com/containerd/containerd)
|
||||
* [datadog/datadog-agent](https://github.com/datadog/datadog-agent)
|
||||
* [docker/cli/](https://github.com/docker/cli/)
|
||||
* [goreleaser/goreleaser](https://github.com/goreleaser/goreleaser)
|
||||
* [go-micro/go-micro](https://github.com/go-micro/go-micro)
|
||||
* [grafana/loki](https://github.com/grafana/loki)
|
||||
* [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes)
|
||||
* [masterminds/sprig](github.com/Masterminds/sprig)
|
||||
* [moby/moby](https://github.com/moby/moby)
|
||||
* [slackhq/nebula](https://github.com/slackhq/nebula)
|
||||
* [volcano-sh/volcano](https://github.com/volcano-sh/volcano)
|
||||
|
||||
## Install
|
||||
|
||||
go get dario.cat/mergo
|
||||
|
||||
// use in your .go code
|
||||
import (
|
||||
"dario.cat/mergo"
|
||||
)
|
||||
|
||||
## Usage
|
||||
|
||||
You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. It won't merge empty structs value as [they are zero values](https://golang.org/ref/spec#The_zero_value) too. Also, maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection).
|
||||
|
||||
```go
|
||||
if err := mergo.Merge(&dst, src); err != nil {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Also, you can merge overwriting values using the transformer `WithOverride`.
|
||||
|
||||
```go
|
||||
if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
If you need to override pointers, so the source pointer's value is assigned to the destination's pointer, you must use `WithoutDereference`:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"dario.cat/mergo"
|
||||
)
|
||||
|
||||
type Foo struct {
|
||||
A *string
|
||||
B int64
|
||||
}
|
||||
|
||||
func main() {
|
||||
first := "first"
|
||||
second := "second"
|
||||
src := Foo{
|
||||
A: &first,
|
||||
B: 2,
|
||||
}
|
||||
|
||||
dest := Foo{
|
||||
A: &second,
|
||||
B: 1,
|
||||
}
|
||||
|
||||
mergo.Merge(&dest, src, mergo.WithOverride, mergo.WithoutDereference)
|
||||
}
|
||||
```
|
||||
|
||||
Additionally, you can map a `map[string]interface{}` to a struct (and otherwise, from struct to map), following the same restrictions as in `Merge()`. Keys are capitalized to find each corresponding exported field.
|
||||
|
||||
```go
|
||||
if err := mergo.Map(&dst, srcMap); err != nil {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Warning: if you map a struct to map, it won't do it recursively. Don't expect Mergo to map struct members of your struct as `map[string]interface{}`. They will be just assigned as values.
|
||||
|
||||
Here is a nice example:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"dario.cat/mergo"
|
||||
)
|
||||
|
||||
type Foo struct {
|
||||
A string
|
||||
B int64
|
||||
}
|
||||
|
||||
func main() {
|
||||
src := Foo{
|
||||
A: "one",
|
||||
B: 2,
|
||||
}
|
||||
dest := Foo{
|
||||
A: "two",
|
||||
}
|
||||
mergo.Merge(&dest, src)
|
||||
fmt.Println(dest)
|
||||
// Will print
|
||||
// {two 2}
|
||||
}
|
||||
```
|
||||
|
||||
Note: if test are failing due missing package, please execute:
|
||||
|
||||
go get gopkg.in/yaml.v3
|
||||
|
||||
### Transformers
|
||||
|
||||
Transformers allow to merge specific types differently than in the default behavior. In other words, now you can customize how some types are merged. For example, `time.Time` is a struct; it doesn't have zero value but IsZero can return true because it has fields with zero value. How can we merge a non-zero `time.Time`?
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"dario.cat/mergo"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
type timeTransformer struct {
|
||||
}
|
||||
|
||||
func (t timeTransformer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error {
|
||||
if typ == reflect.TypeOf(time.Time{}) {
|
||||
return func(dst, src reflect.Value) error {
|
||||
if dst.CanSet() {
|
||||
isZero := dst.MethodByName("IsZero")
|
||||
result := isZero.Call([]reflect.Value{})
|
||||
if result[0].Bool() {
|
||||
dst.Set(src)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Snapshot struct {
|
||||
Time time.Time
|
||||
// ...
|
||||
}
|
||||
|
||||
func main() {
|
||||
src := Snapshot{time.Now()}
|
||||
dest := Snapshot{}
|
||||
mergo.Merge(&dest, src, mergo.WithTransformers(timeTransformer{}))
|
||||
fmt.Println(dest)
|
||||
// Will print
|
||||
// { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 }
|
||||
}
|
||||
```
|
||||
|
||||
## Contact me
|
||||
|
||||
If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): [@im_dario](https://twitter.com/im_dario)
|
||||
|
||||
## About
|
||||
|
||||
Written by [Dario Castañé](http://dario.im).
|
||||
|
||||
## License
|
||||
|
||||
[BSD 3-Clause](http://opensource.org/licenses/BSD-3-Clause) license, as [Go language](http://golang.org/LICENSE).
|
||||
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fimdario%2Fmergo?ref=badge_large)
|
|
@ -0,0 +1,14 @@
|
|||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 0.3.x | :white_check_mark: |
|
||||
| < 0.3 | :x: |
|
||||
|
||||
## Security contact information
|
||||
|
||||
To report a security vulnerability, please use the
|
||||
[Tidelift security contact](https://tidelift.com/security).
|
||||
Tidelift will coordinate the fix and disclosure.
|
|
@ -0,0 +1,148 @@
|
|||
// Copyright 2013 Dario Castañé. All rights reserved.
|
||||
// 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.
|
||||
|
||||
/*
|
||||
A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements.
|
||||
|
||||
Mergo merges same-type structs and maps by setting default values in zero-value fields. Mergo won't merge unexported (private) fields. It will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection).
|
||||
|
||||
# Status
|
||||
|
||||
It is ready for production use. It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, etc.
|
||||
|
||||
# Important notes
|
||||
|
||||
1.0.0
|
||||
|
||||
In 1.0.0 Mergo moves to a vanity URL `dario.cat/mergo`.
|
||||
|
||||
0.3.9
|
||||
|
||||
Please keep in mind that a problematic PR broke 0.3.9. We reverted it in 0.3.10. We consider 0.3.10 as stable but not bug-free. . Also, this version adds suppot for go modules.
|
||||
|
||||
Keep in mind that in 0.3.2, Mergo changed Merge() and Map() signatures to support transformers. We added an optional/variadic argument so that it won't break the existing code.
|
||||
|
||||
If you were using Mergo before April 6th, 2015, please check your project works as intended after updating your local copy with go get -u dario.cat/mergo. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause in existing projects after the change (release 0.2.0).
|
||||
|
||||
# Install
|
||||
|
||||
Do your usual installation procedure:
|
||||
|
||||
go get dario.cat/mergo
|
||||
|
||||
// use in your .go code
|
||||
import (
|
||||
"dario.cat/mergo"
|
||||
)
|
||||
|
||||
# Usage
|
||||
|
||||
You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. It won't merge empty structs value as they are zero values too. Also, maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection).
|
||||
|
||||
if err := mergo.Merge(&dst, src); err != nil {
|
||||
// ...
|
||||
}
|
||||
|
||||
Also, you can merge overwriting values using the transformer WithOverride.
|
||||
|
||||
if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil {
|
||||
// ...
|
||||
}
|
||||
|
||||
Additionally, you can map a map[string]interface{} to a struct (and otherwise, from struct to map), following the same restrictions as in Merge(). Keys are capitalized to find each corresponding exported field.
|
||||
|
||||
if err := mergo.Map(&dst, srcMap); err != nil {
|
||||
// ...
|
||||
}
|
||||
|
||||
Warning: if you map a struct to map, it won't do it recursively. Don't expect Mergo to map struct members of your struct as map[string]interface{}. They will be just assigned as values.
|
||||
|
||||
Here is a nice example:
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"dario.cat/mergo"
|
||||
)
|
||||
|
||||
type Foo struct {
|
||||
A string
|
||||
B int64
|
||||
}
|
||||
|
||||
func main() {
|
||||
src := Foo{
|
||||
A: "one",
|
||||
B: 2,
|
||||
}
|
||||
dest := Foo{
|
||||
A: "two",
|
||||
}
|
||||
mergo.Merge(&dest, src)
|
||||
fmt.Println(dest)
|
||||
// Will print
|
||||
// {two 2}
|
||||
}
|
||||
|
||||
# Transformers
|
||||
|
||||
Transformers allow to merge specific types differently than in the default behavior. In other words, now you can customize how some types are merged. For example, time.Time is a struct; it doesn't have zero value but IsZero can return true because it has fields with zero value. How can we merge a non-zero time.Time?
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"dario.cat/mergo"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
type timeTransformer struct {
|
||||
}
|
||||
|
||||
func (t timeTransformer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error {
|
||||
if typ == reflect.TypeOf(time.Time{}) {
|
||||
return func(dst, src reflect.Value) error {
|
||||
if dst.CanSet() {
|
||||
isZero := dst.MethodByName("IsZero")
|
||||
result := isZero.Call([]reflect.Value{})
|
||||
if result[0].Bool() {
|
||||
dst.Set(src)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Snapshot struct {
|
||||
Time time.Time
|
||||
// ...
|
||||
}
|
||||
|
||||
func main() {
|
||||
src := Snapshot{time.Now()}
|
||||
dest := Snapshot{}
|
||||
mergo.Merge(&dest, src, mergo.WithTransformers(timeTransformer{}))
|
||||
fmt.Println(dest)
|
||||
// Will print
|
||||
// { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 }
|
||||
}
|
||||
|
||||
# Contact me
|
||||
|
||||
If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): https://twitter.com/im_dario
|
||||
|
||||
# About
|
||||
|
||||
Written by Dario Castañé: https://da.rio.hn
|
||||
|
||||
# License
|
||||
|
||||
BSD 3-Clause license, as Go language.
|
||||
*/
|
||||
package mergo
|
|
@ -0,0 +1,178 @@
|
|||
// Copyright 2014 Dario Castañé. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Based on src/pkg/reflect/deepequal.go from official
|
||||
// golang's stdlib.
|
||||
|
||||
package mergo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
func changeInitialCase(s string, mapper func(rune) rune) string {
|
||||
if s == "" {
|
||||
return s
|
||||
}
|
||||
r, n := utf8.DecodeRuneInString(s)
|
||||
return string(mapper(r)) + s[n:]
|
||||
}
|
||||
|
||||
func isExported(field reflect.StructField) bool {
|
||||
r, _ := utf8.DecodeRuneInString(field.Name)
|
||||
return r >= 'A' && r <= 'Z'
|
||||
}
|
||||
|
||||
// Traverses recursively both values, assigning src's fields values to dst.
|
||||
// The map argument tracks comparisons that have already been seen, which allows
|
||||
// short circuiting on recursive types.
|
||||
func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) {
|
||||
overwrite := config.Overwrite
|
||||
if dst.CanAddr() {
|
||||
addr := dst.UnsafeAddr()
|
||||
h := 17 * addr
|
||||
seen := visited[h]
|
||||
typ := dst.Type()
|
||||
for p := seen; p != nil; p = p.next {
|
||||
if p.ptr == addr && p.typ == typ {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
// Remember, remember...
|
||||
visited[h] = &visit{typ, seen, addr}
|
||||
}
|
||||
zeroValue := reflect.Value{}
|
||||
switch dst.Kind() {
|
||||
case reflect.Map:
|
||||
dstMap := dst.Interface().(map[string]interface{})
|
||||
for i, n := 0, src.NumField(); i < n; i++ {
|
||||
srcType := src.Type()
|
||||
field := srcType.Field(i)
|
||||
if !isExported(field) {
|
||||
continue
|
||||
}
|
||||
fieldName := field.Name
|
||||
fieldName = changeInitialCase(fieldName, unicode.ToLower)
|
||||
if _, ok := dstMap[fieldName]; !ok || (!isEmptyValue(reflect.ValueOf(src.Field(i).Interface()), !config.ShouldNotDereference) && overwrite) || config.overwriteWithEmptyValue {
|
||||
dstMap[fieldName] = src.Field(i).Interface()
|
||||
}
|
||||
}
|
||||
case reflect.Ptr:
|
||||
if dst.IsNil() {
|
||||
v := reflect.New(dst.Type().Elem())
|
||||
dst.Set(v)
|
||||
}
|
||||
dst = dst.Elem()
|
||||
fallthrough
|
||||
case reflect.Struct:
|
||||
srcMap := src.Interface().(map[string]interface{})
|
||||
for key := range srcMap {
|
||||
config.overwriteWithEmptyValue = true
|
||||
srcValue := srcMap[key]
|
||||
fieldName := changeInitialCase(key, unicode.ToUpper)
|
||||
dstElement := dst.FieldByName(fieldName)
|
||||
if dstElement == zeroValue {
|
||||
// We discard it because the field doesn't exist.
|
||||
continue
|
||||
}
|
||||
srcElement := reflect.ValueOf(srcValue)
|
||||
dstKind := dstElement.Kind()
|
||||
srcKind := srcElement.Kind()
|
||||
if srcKind == reflect.Ptr && dstKind != reflect.Ptr {
|
||||
srcElement = srcElement.Elem()
|
||||
srcKind = reflect.TypeOf(srcElement.Interface()).Kind()
|
||||
} else if dstKind == reflect.Ptr {
|
||||
// Can this work? I guess it can't.
|
||||
if srcKind != reflect.Ptr && srcElement.CanAddr() {
|
||||
srcPtr := srcElement.Addr()
|
||||
srcElement = reflect.ValueOf(srcPtr)
|
||||
srcKind = reflect.Ptr
|
||||
}
|
||||
}
|
||||
|
||||
if !srcElement.IsValid() {
|
||||
continue
|
||||
}
|
||||
if srcKind == dstKind {
|
||||
if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
|
||||
return
|
||||
}
|
||||
} else if dstKind == reflect.Interface && dstElement.Kind() == reflect.Interface {
|
||||
if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
|
||||
return
|
||||
}
|
||||
} else if srcKind == reflect.Map {
|
||||
if err = deepMap(dstElement, srcElement, visited, depth+1, config); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("type mismatch on %s field: found %v, expected %v", fieldName, srcKind, dstKind)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Map sets fields' values in dst from src.
|
||||
// src can be a map with string keys or a struct. dst must be the opposite:
|
||||
// if src is a map, dst must be a valid pointer to struct. If src is a struct,
|
||||
// dst must be map[string]interface{}.
|
||||
// It won't merge unexported (private) fields and will do recursively
|
||||
// any exported field.
|
||||
// If dst is a map, keys will be src fields' names in lower camel case.
|
||||
// Missing key in src that doesn't match a field in dst will be skipped. This
|
||||
// doesn't apply if dst is a map.
|
||||
// This is separated method from Merge because it is cleaner and it keeps sane
|
||||
// semantics: merging equal types, mapping different (restricted) types.
|
||||
func Map(dst, src interface{}, opts ...func(*Config)) error {
|
||||
return _map(dst, src, opts...)
|
||||
}
|
||||
|
||||
// MapWithOverwrite will do the same as Map except that non-empty dst attributes will be overridden by
|
||||
// non-empty src attribute values.
|
||||
// Deprecated: Use Map(…) with WithOverride
|
||||
func MapWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
|
||||
return _map(dst, src, append(opts, WithOverride)...)
|
||||
}
|
||||
|
||||
func _map(dst, src interface{}, opts ...func(*Config)) error {
|
||||
if dst != nil && reflect.ValueOf(dst).Kind() != reflect.Ptr {
|
||||
return ErrNonPointerArgument
|
||||
}
|
||||
var (
|
||||
vDst, vSrc reflect.Value
|
||||
err error
|
||||
)
|
||||
config := &Config{}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(config)
|
||||
}
|
||||
|
||||
if vDst, vSrc, err = resolveValues(dst, src); err != nil {
|
||||
return err
|
||||
}
|
||||
// To be friction-less, we redirect equal-type arguments
|
||||
// to deepMerge. Only because arguments can be anything.
|
||||
if vSrc.Kind() == vDst.Kind() {
|
||||
return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
|
||||
}
|
||||
switch vSrc.Kind() {
|
||||
case reflect.Struct:
|
||||
if vDst.Kind() != reflect.Map {
|
||||
return ErrExpectedMapAsDestination
|
||||
}
|
||||
case reflect.Map:
|
||||
if vDst.Kind() != reflect.Struct {
|
||||
return ErrExpectedStructAsDestination
|
||||
}
|
||||
default:
|
||||
return ErrNotSupported
|
||||
}
|
||||
return deepMap(vDst, vSrc, make(map[uintptr]*visit), 0, config)
|
||||
}
|
|
@ -0,0 +1,409 @@
|
|||
// Copyright 2013 Dario Castañé. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Based on src/pkg/reflect/deepequal.go from official
|
||||
// golang's stdlib.
|
||||
|
||||
package mergo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func hasMergeableFields(dst reflect.Value) (exported bool) {
|
||||
for i, n := 0, dst.NumField(); i < n; i++ {
|
||||
field := dst.Type().Field(i)
|
||||
if field.Anonymous && dst.Field(i).Kind() == reflect.Struct {
|
||||
exported = exported || hasMergeableFields(dst.Field(i))
|
||||
} else if isExportedComponent(&field) {
|
||||
exported = exported || len(field.PkgPath) == 0
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func isExportedComponent(field *reflect.StructField) bool {
|
||||
pkgPath := field.PkgPath
|
||||
if len(pkgPath) > 0 {
|
||||
return false
|
||||
}
|
||||
c := field.Name[0]
|
||||
if 'a' <= c && c <= 'z' || c == '_' {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Transformers Transformers
|
||||
Overwrite bool
|
||||
ShouldNotDereference bool
|
||||
AppendSlice bool
|
||||
TypeCheck bool
|
||||
overwriteWithEmptyValue bool
|
||||
overwriteSliceWithEmptyValue bool
|
||||
sliceDeepCopy bool
|
||||
debug bool
|
||||
}
|
||||
|
||||
type Transformers interface {
|
||||
Transformer(reflect.Type) func(dst, src reflect.Value) error
|
||||
}
|
||||
|
||||
// Traverses recursively both values, assigning src's fields values to dst.
|
||||
// The map argument tracks comparisons that have already been seen, which allows
|
||||
// short circuiting on recursive types.
|
||||
func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) {
|
||||
overwrite := config.Overwrite
|
||||
typeCheck := config.TypeCheck
|
||||
overwriteWithEmptySrc := config.overwriteWithEmptyValue
|
||||
overwriteSliceWithEmptySrc := config.overwriteSliceWithEmptyValue
|
||||
sliceDeepCopy := config.sliceDeepCopy
|
||||
|
||||
if !src.IsValid() {
|
||||
return
|
||||
}
|
||||
if dst.CanAddr() {
|
||||
addr := dst.UnsafeAddr()
|
||||
h := 17 * addr
|
||||
seen := visited[h]
|
||||
typ := dst.Type()
|
||||
for p := seen; p != nil; p = p.next {
|
||||
if p.ptr == addr && p.typ == typ {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
// Remember, remember...
|
||||
visited[h] = &visit{typ, seen, addr}
|
||||
}
|
||||
|
||||
if config.Transformers != nil && !isReflectNil(dst) && dst.IsValid() {
|
||||
if fn := config.Transformers.Transformer(dst.Type()); fn != nil {
|
||||
err = fn(dst, src)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
switch dst.Kind() {
|
||||
case reflect.Struct:
|
||||
if hasMergeableFields(dst) {
|
||||
for i, n := 0, dst.NumField(); i < n; i++ {
|
||||
if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, config); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if dst.CanSet() && (isReflectNil(dst) || overwrite) && (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc) {
|
||||
dst.Set(src)
|
||||
}
|
||||
}
|
||||
case reflect.Map:
|
||||
if dst.IsNil() && !src.IsNil() {
|
||||
if dst.CanSet() {
|
||||
dst.Set(reflect.MakeMap(dst.Type()))
|
||||
} else {
|
||||
dst = src
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if src.Kind() != reflect.Map {
|
||||
if overwrite && dst.CanSet() {
|
||||
dst.Set(src)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for _, key := range src.MapKeys() {
|
||||
srcElement := src.MapIndex(key)
|
||||
if !srcElement.IsValid() {
|
||||
continue
|
||||
}
|
||||
dstElement := dst.MapIndex(key)
|
||||
switch srcElement.Kind() {
|
||||
case reflect.Chan, reflect.Func, reflect.Map, reflect.Interface, reflect.Slice:
|
||||
if srcElement.IsNil() {
|
||||
if overwrite {
|
||||
dst.SetMapIndex(key, srcElement)
|
||||
}
|
||||
continue
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
if !srcElement.CanInterface() {
|
||||
continue
|
||||
}
|
||||
switch reflect.TypeOf(srcElement.Interface()).Kind() {
|
||||
case reflect.Struct:
|
||||
fallthrough
|
||||
case reflect.Ptr:
|
||||
fallthrough
|
||||
case reflect.Map:
|
||||
srcMapElm := srcElement
|
||||
dstMapElm := dstElement
|
||||
if srcMapElm.CanInterface() {
|
||||
srcMapElm = reflect.ValueOf(srcMapElm.Interface())
|
||||
if dstMapElm.IsValid() {
|
||||
dstMapElm = reflect.ValueOf(dstMapElm.Interface())
|
||||
}
|
||||
}
|
||||
if err = deepMerge(dstMapElm, srcMapElm, visited, depth+1, config); err != nil {
|
||||
return
|
||||
}
|
||||
case reflect.Slice:
|
||||
srcSlice := reflect.ValueOf(srcElement.Interface())
|
||||
|
||||
var dstSlice reflect.Value
|
||||
if !dstElement.IsValid() || dstElement.IsNil() {
|
||||
dstSlice = reflect.MakeSlice(srcSlice.Type(), 0, srcSlice.Len())
|
||||
} else {
|
||||
dstSlice = reflect.ValueOf(dstElement.Interface())
|
||||
}
|
||||
|
||||
if (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) && !config.AppendSlice && !sliceDeepCopy {
|
||||
if typeCheck && srcSlice.Type() != dstSlice.Type() {
|
||||
return fmt.Errorf("cannot override two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
|
||||
}
|
||||
dstSlice = srcSlice
|
||||
} else if config.AppendSlice {
|
||||
if srcSlice.Type() != dstSlice.Type() {
|
||||
return fmt.Errorf("cannot append two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
|
||||
}
|
||||
dstSlice = reflect.AppendSlice(dstSlice, srcSlice)
|
||||
} else if sliceDeepCopy {
|
||||
i := 0
|
||||
for ; i < srcSlice.Len() && i < dstSlice.Len(); i++ {
|
||||
srcElement := srcSlice.Index(i)
|
||||
dstElement := dstSlice.Index(i)
|
||||
|
||||
if srcElement.CanInterface() {
|
||||
srcElement = reflect.ValueOf(srcElement.Interface())
|
||||
}
|
||||
if dstElement.CanInterface() {
|
||||
dstElement = reflect.ValueOf(dstElement.Interface())
|
||||
}
|
||||
|
||||
if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
dst.SetMapIndex(key, dstSlice)
|
||||
}
|
||||
}
|
||||
|
||||
if dstElement.IsValid() && !isEmptyValue(dstElement, !config.ShouldNotDereference) {
|
||||
if reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Slice {
|
||||
continue
|
||||
}
|
||||
if reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Map && reflect.TypeOf(dstElement.Interface()).Kind() == reflect.Map {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if srcElement.IsValid() && ((srcElement.Kind() != reflect.Ptr && overwrite) || !dstElement.IsValid() || isEmptyValue(dstElement, !config.ShouldNotDereference)) {
|
||||
if dst.IsNil() {
|
||||
dst.Set(reflect.MakeMap(dst.Type()))
|
||||
}
|
||||
dst.SetMapIndex(key, srcElement)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that all keys in dst are deleted if they are not in src.
|
||||
if overwriteWithEmptySrc {
|
||||
for _, key := range dst.MapKeys() {
|
||||
srcElement := src.MapIndex(key)
|
||||
if !srcElement.IsValid() {
|
||||
dst.SetMapIndex(key, reflect.Value{})
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Slice:
|
||||
if !dst.CanSet() {
|
||||
break
|
||||
}
|
||||
if (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) && !config.AppendSlice && !sliceDeepCopy {
|
||||
dst.Set(src)
|
||||
} else if config.AppendSlice {
|
||||
if src.Type() != dst.Type() {
|
||||
return fmt.Errorf("cannot append two slice with different type (%s, %s)", src.Type(), dst.Type())
|
||||
}
|
||||
dst.Set(reflect.AppendSlice(dst, src))
|
||||
} else if sliceDeepCopy {
|
||||
for i := 0; i < src.Len() && i < dst.Len(); i++ {
|
||||
srcElement := src.Index(i)
|
||||
dstElement := dst.Index(i)
|
||||
if srcElement.CanInterface() {
|
||||
srcElement = reflect.ValueOf(srcElement.Interface())
|
||||
}
|
||||
if dstElement.CanInterface() {
|
||||
dstElement = reflect.ValueOf(dstElement.Interface())
|
||||
}
|
||||
|
||||
if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Ptr:
|
||||
fallthrough
|
||||
case reflect.Interface:
|
||||
if isReflectNil(src) {
|
||||
if overwriteWithEmptySrc && dst.CanSet() && src.Type().AssignableTo(dst.Type()) {
|
||||
dst.Set(src)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if src.Kind() != reflect.Interface {
|
||||
if dst.IsNil() || (src.Kind() != reflect.Ptr && overwrite) {
|
||||
if dst.CanSet() && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) {
|
||||
dst.Set(src)
|
||||
}
|
||||
} else if src.Kind() == reflect.Ptr {
|
||||
if !config.ShouldNotDereference {
|
||||
if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
|
||||
return
|
||||
}
|
||||
} else if src.Elem().Kind() != reflect.Struct {
|
||||
if overwriteWithEmptySrc || (overwrite && !src.IsNil()) || dst.IsNil() {
|
||||
dst.Set(src)
|
||||
}
|
||||
}
|
||||
} else if dst.Elem().Type() == src.Type() {
|
||||
if err = deepMerge(dst.Elem(), src, visited, depth+1, config); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
return ErrDifferentArgumentsTypes
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if dst.IsNil() || overwrite {
|
||||
if dst.CanSet() && (overwrite || isEmptyValue(dst, !config.ShouldNotDereference)) {
|
||||
dst.Set(src)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if dst.Elem().Kind() == src.Elem().Kind() {
|
||||
if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
|
||||
return
|
||||
}
|
||||
break
|
||||
}
|
||||
default:
|
||||
mustSet := (isEmptyValue(dst, !config.ShouldNotDereference) || overwrite) && (!isEmptyValue(src, !config.ShouldNotDereference) || overwriteWithEmptySrc)
|
||||
if mustSet {
|
||||
if dst.CanSet() {
|
||||
dst.Set(src)
|
||||
} else {
|
||||
dst = src
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Merge will fill any empty for value type attributes on the dst struct using corresponding
|
||||
// src attributes if they themselves are not empty. dst and src must be valid same-type structs
|
||||
// and dst must be a pointer to struct.
|
||||
// It won't merge unexported (private) fields and will do recursively any exported field.
|
||||
func Merge(dst, src interface{}, opts ...func(*Config)) error {
|
||||
return merge(dst, src, opts...)
|
||||
}
|
||||
|
||||
// MergeWithOverwrite will do the same as Merge except that non-empty dst attributes will be overridden by
|
||||
// non-empty src attribute values.
|
||||
// Deprecated: use Merge(…) with WithOverride
|
||||
func MergeWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
|
||||
return merge(dst, src, append(opts, WithOverride)...)
|
||||
}
|
||||
|
||||
// WithTransformers adds transformers to merge, allowing to customize the merging of some types.
|
||||
func WithTransformers(transformers Transformers) func(*Config) {
|
||||
return func(config *Config) {
|
||||
config.Transformers = transformers
|
||||
}
|
||||
}
|
||||
|
||||
// WithOverride will make merge override non-empty dst attributes with non-empty src attributes values.
|
||||
func WithOverride(config *Config) {
|
||||
config.Overwrite = true
|
||||
}
|
||||
|
||||
// WithOverwriteWithEmptyValue will make merge override non empty dst attributes with empty src attributes values.
|
||||
func WithOverwriteWithEmptyValue(config *Config) {
|
||||
config.Overwrite = true
|
||||
config.overwriteWithEmptyValue = true
|
||||
}
|
||||
|
||||
// WithOverrideEmptySlice will make merge override empty dst slice with empty src slice.
|
||||
func WithOverrideEmptySlice(config *Config) {
|
||||
config.overwriteSliceWithEmptyValue = true
|
||||
}
|
||||
|
||||
// WithoutDereference prevents dereferencing pointers when evaluating whether they are empty
|
||||
// (i.e. a non-nil pointer is never considered empty).
|
||||
func WithoutDereference(config *Config) {
|
||||
config.ShouldNotDereference = true
|
||||
}
|
||||
|
||||
// WithAppendSlice will make merge append slices instead of overwriting it.
|
||||
func WithAppendSlice(config *Config) {
|
||||
config.AppendSlice = true
|
||||
}
|
||||
|
||||
// WithTypeCheck will make merge check types while overwriting it (must be used with WithOverride).
|
||||
func WithTypeCheck(config *Config) {
|
||||
config.TypeCheck = true
|
||||
}
|
||||
|
||||
// WithSliceDeepCopy will merge slice element one by one with Overwrite flag.
|
||||
func WithSliceDeepCopy(config *Config) {
|
||||
config.sliceDeepCopy = true
|
||||
config.Overwrite = true
|
||||
}
|
||||
|
||||
func merge(dst, src interface{}, opts ...func(*Config)) error {
|
||||
if dst != nil && reflect.ValueOf(dst).Kind() != reflect.Ptr {
|
||||
return ErrNonPointerArgument
|
||||
}
|
||||
var (
|
||||
vDst, vSrc reflect.Value
|
||||
err error
|
||||
)
|
||||
|
||||
config := &Config{}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(config)
|
||||
}
|
||||
|
||||
if vDst, vSrc, err = resolveValues(dst, src); err != nil {
|
||||
return err
|
||||
}
|
||||
if vDst.Type() != vSrc.Type() {
|
||||
return ErrDifferentArgumentsTypes
|
||||
}
|
||||
return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
|
||||
}
|
||||
|
||||
// IsReflectNil is the reflect value provided nil
|
||||
func isReflectNil(v reflect.Value) bool {
|
||||
k := v.Kind()
|
||||
switch k {
|
||||
case reflect.Interface, reflect.Slice, reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr:
|
||||
// Both interface and slice are nil if first word is 0.
|
||||
// Both are always bigger than a word; assume flagIndir.
|
||||
return v.IsNil()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
// Copyright 2013 Dario Castañé. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Based on src/pkg/reflect/deepequal.go from official
|
||||
// golang's stdlib.
|
||||
|
||||
package mergo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Errors reported by Mergo when it finds invalid arguments.
|
||||
var (
|
||||
ErrNilArguments = errors.New("src and dst must not be nil")
|
||||
ErrDifferentArgumentsTypes = errors.New("src and dst must be of same type")
|
||||
ErrNotSupported = errors.New("only structs, maps, and slices are supported")
|
||||
ErrExpectedMapAsDestination = errors.New("dst was expected to be a map")
|
||||
ErrExpectedStructAsDestination = errors.New("dst was expected to be a struct")
|
||||
ErrNonPointerArgument = errors.New("dst must be a pointer")
|
||||
)
|
||||
|
||||
// During deepMerge, must keep track of checks that are
|
||||
// in progress. The comparison algorithm assumes that all
|
||||
// checks in progress are true when it reencounters them.
|
||||
// Visited are stored in a map indexed by 17 * a1 + a2;
|
||||
type visit struct {
|
||||
typ reflect.Type
|
||||
next *visit
|
||||
ptr uintptr
|
||||
}
|
||||
|
||||
// From src/pkg/encoding/json/encode.go.
|
||||
func isEmptyValue(v reflect.Value, shouldDereference bool) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
||||
return v.Len() == 0
|
||||
case reflect.Bool:
|
||||
return !v.Bool()
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return v.Int() == 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return v.Uint() == 0
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return v.Float() == 0
|
||||
case reflect.Interface, reflect.Ptr:
|
||||
if v.IsNil() {
|
||||
return true
|
||||
}
|
||||
if shouldDereference {
|
||||
return isEmptyValue(v.Elem(), shouldDereference)
|
||||
}
|
||||
return false
|
||||
case reflect.Func:
|
||||
return v.IsNil()
|
||||
case reflect.Invalid:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func resolveValues(dst, src interface{}) (vDst, vSrc reflect.Value, err error) {
|
||||
if dst == nil || src == nil {
|
||||
err = ErrNilArguments
|
||||
return
|
||||
}
|
||||
vDst = reflect.ValueOf(dst).Elem()
|
||||
if vDst.Kind() != reflect.Struct && vDst.Kind() != reflect.Map && vDst.Kind() != reflect.Slice {
|
||||
err = ErrNotSupported
|
||||
return
|
||||
}
|
||||
vSrc = reflect.ValueOf(src)
|
||||
// We check if vSrc is a pointer to dereference it.
|
||||
if vSrc.Kind() == reflect.Ptr {
|
||||
vSrc = vSrc.Elem()
|
||||
}
|
||||
return
|
||||
}
|
|
@ -1,5 +1,33 @@
|
|||
# Changelog
|
||||
|
||||
## 3.3.0 (2024-08-27)
|
||||
|
||||
### Added
|
||||
|
||||
- #238: Add LessThanEqual and GreaterThanEqual functions (thanks @grosser)
|
||||
- #213: nil version equality checking (thanks @KnutZuidema)
|
||||
|
||||
### Changed
|
||||
|
||||
- #241: Simplify StrictNewVersion parsing (thanks @grosser)
|
||||
- Testing support up through Go 1.23
|
||||
- Minimum version set to 1.21 as this is what's tested now
|
||||
- Fuzz testing now supports caching
|
||||
|
||||
## 3.2.1 (2023-04-10)
|
||||
|
||||
### Changed
|
||||
|
||||
- #198: Improved testing around pre-release names
|
||||
- #200: Improved code scanning with addition of CodeQL
|
||||
- #201: Testing now includes Go 1.20. Go 1.17 has been dropped
|
||||
- #202: Migrated Fuzz testing to Go built-in Fuzzing. CI runs daily
|
||||
- #203: Docs updated for security details
|
||||
|
||||
### Fixed
|
||||
|
||||
- #199: Fixed issue with range transformations
|
||||
|
||||
## 3.2.0 (2022-11-28)
|
||||
|
||||
### Added
|
||||
|
|
|
@ -19,6 +19,7 @@ test-cover:
|
|||
.PHONY: fuzz
|
||||
fuzz:
|
||||
@echo "==> Running Fuzz Tests"
|
||||
go env GOCACHE
|
||||
go test -fuzz=FuzzNewVersion -fuzztime=15s .
|
||||
go test -fuzz=FuzzStrictNewVersion -fuzztime=15s .
|
||||
go test -fuzz=FuzzNewConstraint -fuzztime=15s .
|
||||
|
@ -27,4 +28,4 @@ $(GOLANGCI_LINT):
|
|||
# Install golangci-lint. The configuration for it is in the .golangci.yml
|
||||
# file in the root of the repository
|
||||
echo ${GOPATH}
|
||||
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin v1.17.1
|
||||
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin v1.56.2
|
||||
|
|
|
@ -13,12 +13,9 @@ Active](https://masterminds.github.io/stability/active.svg)](https://masterminds
|
|||
[](https://pkg.go.dev/github.com/Masterminds/semver/v3)
|
||||
[](https://goreportcard.com/report/github.com/Masterminds/semver)
|
||||
|
||||
If you are looking for a command line tool for version comparisons please see
|
||||
[vert](https://github.com/Masterminds/vert) which uses this library.
|
||||
|
||||
## Package Versions
|
||||
|
||||
Note, import `github.com/github.com/Masterminds/semver/v3` to use the latest version.
|
||||
Note, import `github.com/Masterminds/semver/v3` to use the latest version.
|
||||
|
||||
There are three major versions fo the `semver` package.
|
||||
|
||||
|
@ -80,12 +77,12 @@ There are two methods for comparing versions. One uses comparison methods on
|
|||
differences to notes between these two methods of comparison.
|
||||
|
||||
1. When two versions are compared using functions such as `Compare`, `LessThan`,
|
||||
and others it will follow the specification and always include prereleases
|
||||
and others it will follow the specification and always include pre-releases
|
||||
within the comparison. It will provide an answer that is valid with the
|
||||
comparison section of the spec at https://semver.org/#spec-item-11
|
||||
2. When constraint checking is used for checks or validation it will follow a
|
||||
different set of rules that are common for ranges with tools like npm/js
|
||||
and Rust/Cargo. This includes considering prereleases to be invalid if the
|
||||
and Rust/Cargo. This includes considering pre-releases to be invalid if the
|
||||
ranges does not include one. If you want to have it include pre-releases a
|
||||
simple solution is to include `-0` in your range.
|
||||
3. Constraint ranges can have some complex rules including the shorthand use of
|
||||
|
@ -113,7 +110,7 @@ v, err := semver.NewVersion("1.3")
|
|||
if err != nil {
|
||||
// Handle version not being parsable.
|
||||
}
|
||||
// Check if the version meets the constraints. The a variable will be true.
|
||||
// Check if the version meets the constraints. The variable a will be true.
|
||||
a := c.Check(v)
|
||||
```
|
||||
|
||||
|
@ -137,20 +134,20 @@ The basic comparisons are:
|
|||
### Working With Prerelease Versions
|
||||
|
||||
Pre-releases, for those not familiar with them, are used for software releases
|
||||
prior to stable or generally available releases. Examples of prereleases include
|
||||
development, alpha, beta, and release candidate releases. A prerelease may be
|
||||
prior to stable or generally available releases. Examples of pre-releases include
|
||||
development, alpha, beta, and release candidate releases. A pre-release may be
|
||||
a version such as `1.2.3-beta.1` while the stable release would be `1.2.3`. In the
|
||||
order of precedence, prereleases come before their associated releases. In this
|
||||
order of precedence, pre-releases come before their associated releases. In this
|
||||
example `1.2.3-beta.1 < 1.2.3`.
|
||||
|
||||
According to the Semantic Version specification prereleases may not be
|
||||
According to the Semantic Version specification, pre-releases may not be
|
||||
API compliant with their release counterpart. It says,
|
||||
|
||||
> A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version.
|
||||
|
||||
SemVer comparisons using constraints without a prerelease comparator will skip
|
||||
prerelease versions. For example, `>=1.2.3` will skip prereleases when looking
|
||||
at a list of releases while `>=1.2.3-0` will evaluate and find prereleases.
|
||||
SemVer's comparisons using constraints without a pre-release comparator will skip
|
||||
pre-release versions. For example, `>=1.2.3` will skip pre-releases when looking
|
||||
at a list of releases while `>=1.2.3-0` will evaluate and find pre-releases.
|
||||
|
||||
The reason for the `0` as a pre-release version in the example comparison is
|
||||
because pre-releases can only contain ASCII alphanumerics and hyphens (along with
|
||||
|
@ -171,6 +168,9 @@ These look like:
|
|||
* `1.2 - 1.4.5` which is equivalent to `>= 1.2 <= 1.4.5`
|
||||
* `2.3.4 - 4.5` which is equivalent to `>= 2.3.4 <= 4.5`
|
||||
|
||||
Note that `1.2-1.4.5` without whitespace is parsed completely differently; it's
|
||||
parsed as a single constraint `1.2.0` with _prerelease_ `1.4.5`.
|
||||
|
||||
### Wildcards In Comparisons
|
||||
|
||||
The `x`, `X`, and `*` characters can be used as a wildcard character. This works
|
||||
|
|
|
@ -83,22 +83,23 @@ func StrictNewVersion(v string) (*Version, error) {
|
|||
original: v,
|
||||
}
|
||||
|
||||
// check for prerelease or build metadata
|
||||
var extra []string
|
||||
if strings.ContainsAny(parts[2], "-+") {
|
||||
// Start with the build metadata first as it needs to be on the right
|
||||
extra = strings.SplitN(parts[2], "+", 2)
|
||||
if len(extra) > 1 {
|
||||
// build metadata found
|
||||
sv.metadata = extra[1]
|
||||
parts[2] = extra[0]
|
||||
// Extract build metadata
|
||||
if strings.Contains(parts[2], "+") {
|
||||
extra := strings.SplitN(parts[2], "+", 2)
|
||||
sv.metadata = extra[1]
|
||||
parts[2] = extra[0]
|
||||
if err := validateMetadata(sv.metadata); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
extra = strings.SplitN(parts[2], "-", 2)
|
||||
if len(extra) > 1 {
|
||||
// prerelease found
|
||||
sv.pre = extra[1]
|
||||
parts[2] = extra[0]
|
||||
// Extract build prerelease
|
||||
if strings.Contains(parts[2], "-") {
|
||||
extra := strings.SplitN(parts[2], "-", 2)
|
||||
sv.pre = extra[1]
|
||||
parts[2] = extra[0]
|
||||
if err := validatePrerelease(sv.pre); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,7 +115,7 @@ func StrictNewVersion(v string) (*Version, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// Extract the major, minor, and patch elements onto the returned Version
|
||||
// Extract major, minor, and patch
|
||||
var err error
|
||||
sv.major, err = strconv.ParseUint(parts[0], 10, 64)
|
||||
if err != nil {
|
||||
|
@ -131,23 +132,6 @@ func StrictNewVersion(v string) (*Version, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// No prerelease or build metadata found so returning now as a fastpath.
|
||||
if sv.pre == "" && sv.metadata == "" {
|
||||
return sv, nil
|
||||
}
|
||||
|
||||
if sv.pre != "" {
|
||||
if err = validatePrerelease(sv.pre); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if sv.metadata != "" {
|
||||
if err = validateMetadata(sv.metadata); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return sv, nil
|
||||
}
|
||||
|
||||
|
@ -381,15 +365,31 @@ func (v *Version) LessThan(o *Version) bool {
|
|||
return v.Compare(o) < 0
|
||||
}
|
||||
|
||||
// LessThanEqual tests if one version is less or equal than another one.
|
||||
func (v *Version) LessThanEqual(o *Version) bool {
|
||||
return v.Compare(o) <= 0
|
||||
}
|
||||
|
||||
// GreaterThan tests if one version is greater than another one.
|
||||
func (v *Version) GreaterThan(o *Version) bool {
|
||||
return v.Compare(o) > 0
|
||||
}
|
||||
|
||||
// GreaterThanEqual tests if one version is greater or equal than another one.
|
||||
func (v *Version) GreaterThanEqual(o *Version) bool {
|
||||
return v.Compare(o) >= 0
|
||||
}
|
||||
|
||||
// Equal tests if two versions are equal to each other.
|
||||
// Note, versions can be equal with different metadata since metadata
|
||||
// is not considered part of the comparable version.
|
||||
func (v *Version) Equal(o *Version) bool {
|
||||
if v == o {
|
||||
return true
|
||||
}
|
||||
if v == nil || o == nil {
|
||||
return false
|
||||
}
|
||||
return v.Compare(o) == 0
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,23 @@
|
|||
# Changelog
|
||||
|
||||
## Release 3.3.0 (2024-08-29)
|
||||
|
||||
### Added
|
||||
|
||||
- #400: added sha512sum function (thanks @itzik-elayev)
|
||||
|
||||
### Changed
|
||||
|
||||
- #407: Removed duplicate documentation (functions were documentated in 2 places)
|
||||
- #290: Corrected copy/paster oops in math documentation (thanks @zzhu41)
|
||||
- #369: Corrected template reference in docs (thanks @chey)
|
||||
- #375: Added link to URL documenation (thanks @carlpett)
|
||||
- #406: Updated the mergo dependency which had a breaking change (which was accounted for)
|
||||
- #376: Fixed documentation error (thanks @jheyduk)
|
||||
- #404: Updated dependency tree
|
||||
- #391: Fixed misspelling (thanks @chrishalbert)
|
||||
- #405: Updated Go versions used in testing
|
||||
|
||||
## Release 3.2.3 (2022-11-29)
|
||||
|
||||
### Changed
|
||||
|
@ -307,7 +325,7 @@ This release adds new functions, including:
|
|||
- Added `semver` and `semverCompare` for Semantic Versions
|
||||
- `list` replaces `tuple`
|
||||
- Fixed issue with `join`
|
||||
- Added `first`, `last`, `intial`, `rest`, `prepend`, `append`, `toString`, `toStrings`, `sortAlpha`, `reverse`, `coalesce`, `pluck`, `pick`, `compact`, `keys`, `omit`, `uniq`, `has`, `without`
|
||||
- Added `first`, `last`, `initial`, `rest`, `prepend`, `append`, `toString`, `toStrings`, `sortAlpha`, `reverse`, `coalesce`, `pluck`, `pick`, `compact`, `keys`, `omit`, `uniq`, `has`, `without`
|
||||
|
||||
## Release 2.9.0 (2017-02-23)
|
||||
|
||||
|
@ -361,7 +379,7 @@ Because we switched from `int` to `int64` as the return value for all integer ma
|
|||
- `min` complements `max` (formerly `biggest`)
|
||||
- `empty` indicates that a value is the empty value for its type
|
||||
- `tuple` creates a tuple inside of a template: `{{$t := tuple "a", "b" "c"}}`
|
||||
- `dict` creates a dictionary inside of a template `{{$d := dict "key1" "val1" "key2" "val2"}}`
|
||||
- `dict` creates a dictionary inside of a template `{{$d := dict "key1" "val1" "key2" "val2"}}`
|
||||
- Date formatters have been added for HTML dates (as used in `date` input fields)
|
||||
- Integer math functions can convert from a number of types, including `string` (via `strconv.ParseInt`).
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
|
@ -36,6 +37,11 @@ import (
|
|||
"golang.org/x/crypto/scrypt"
|
||||
)
|
||||
|
||||
func sha512sum(input string) string {
|
||||
hash := sha512.Sum512([]byte(input))
|
||||
return hex.EncodeToString(hash[:])
|
||||
}
|
||||
|
||||
func sha256sum(input string) string {
|
||||
hash := sha256.Sum256([]byte(input))
|
||||
return hex.EncodeToString(hash[:])
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package sprig
|
||||
|
||||
import (
|
||||
"github.com/imdario/mergo"
|
||||
"dario.cat/mergo"
|
||||
"github.com/mitchellh/copystructure"
|
||||
)
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ inside of Go `html/template` and `text/template` files.
|
|||
|
||||
To add these functions, use the `template.Funcs()` method:
|
||||
|
||||
t := templates.New("foo").Funcs(sprig.FuncMap())
|
||||
t := template.New("foo").Funcs(sprig.FuncMap())
|
||||
|
||||
Note that you should add the function map before you parse any template files.
|
||||
|
||||
|
|
|
@ -22,8 +22,7 @@ import (
|
|||
//
|
||||
// Use this to pass the functions into the template engine:
|
||||
//
|
||||
// tpl := template.New("foo").Funcs(sprig.FuncMap()))
|
||||
//
|
||||
// tpl := template.New("foo").Funcs(sprig.FuncMap()))
|
||||
func FuncMap() template.FuncMap {
|
||||
return HtmlFuncMap()
|
||||
}
|
||||
|
@ -142,10 +141,13 @@ var genericMap = map[string]interface{}{
|
|||
"swapcase": util.SwapCase,
|
||||
"shuffle": xstrings.Shuffle,
|
||||
"snakecase": xstrings.ToSnakeCase,
|
||||
"camelcase": xstrings.ToCamelCase,
|
||||
"kebabcase": xstrings.ToKebabCase,
|
||||
"wrap": func(l int, s string) string { return util.Wrap(s, l) },
|
||||
"wrapWith": func(l int, sep, str string) string { return util.WrapCustom(str, l, sep, true) },
|
||||
// camelcase used to call xstrings.ToCamelCase, but that function had a breaking change in version
|
||||
// 1.5 that moved it from upper camel case to lower camel case. This is a breaking change for sprig.
|
||||
// A new xstrings.ToPascalCase function was added that provided upper camel case.
|
||||
"camelcase": xstrings.ToPascalCase,
|
||||
"kebabcase": xstrings.ToKebabCase,
|
||||
"wrap": func(l int, s string) string { return util.Wrap(s, l) },
|
||||
"wrapWith": func(l int, sep, str string) string { return util.WrapCustom(str, l, sep, true) },
|
||||
// Switch order so that "foobar" | contains "foo"
|
||||
"contains": func(substr string, str string) bool { return strings.Contains(str, substr) },
|
||||
"hasPrefix": func(substr string, str string) bool { return strings.HasPrefix(str, substr) },
|
||||
|
@ -159,6 +161,7 @@ var genericMap = map[string]interface{}{
|
|||
"plural": plural,
|
||||
"sha1sum": sha1sum,
|
||||
"sha256sum": sha256sum,
|
||||
"sha512sum": sha512sum,
|
||||
"adler32sum": adler32sum,
|
||||
"toString": strval,
|
||||
|
||||
|
@ -336,20 +339,20 @@ var genericMap = map[string]interface{}{
|
|||
"mustChunk": mustChunk,
|
||||
|
||||
// Crypto:
|
||||
"bcrypt": bcrypt,
|
||||
"htpasswd": htpasswd,
|
||||
"genPrivateKey": generatePrivateKey,
|
||||
"derivePassword": derivePassword,
|
||||
"buildCustomCert": buildCustomCertificate,
|
||||
"genCA": generateCertificateAuthority,
|
||||
"genCAWithKey": generateCertificateAuthorityWithPEMKey,
|
||||
"genSelfSignedCert": generateSelfSignedCertificate,
|
||||
"bcrypt": bcrypt,
|
||||
"htpasswd": htpasswd,
|
||||
"genPrivateKey": generatePrivateKey,
|
||||
"derivePassword": derivePassword,
|
||||
"buildCustomCert": buildCustomCertificate,
|
||||
"genCA": generateCertificateAuthority,
|
||||
"genCAWithKey": generateCertificateAuthorityWithPEMKey,
|
||||
"genSelfSignedCert": generateSelfSignedCertificate,
|
||||
"genSelfSignedCertWithKey": generateSelfSignedCertificateWithPEMKey,
|
||||
"genSignedCert": generateSignedCertificate,
|
||||
"genSignedCertWithKey": generateSignedCertificateWithPEMKey,
|
||||
"encryptAES": encryptAES,
|
||||
"decryptAES": decryptAES,
|
||||
"randBytes": randBytes,
|
||||
"genSignedCert": generateSignedCertificate,
|
||||
"genSignedCertWithKey": generateSignedCertificateWithPEMKey,
|
||||
"encryptAES": encryptAES,
|
||||
"decryptAES": decryptAES,
|
||||
"randBytes": randBytes,
|
||||
|
||||
// UUIDs:
|
||||
"uuidv4": uuidv4,
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
# v1.27.31 (2024-08-26)
|
||||
|
||||
* **Dependency Update**: Updated to the latest SDK module versions
|
||||
|
||||
# v1.27.30 (2024-08-23)
|
||||
|
||||
* **Bug Fix**: Don't fail credentials unit tests if credentials are found on a file
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
package config
|
||||
|
||||
// goModuleVersion is the tagged release for this module
|
||||
const goModuleVersion = "1.27.30"
|
||||
const goModuleVersion = "1.27.31"
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
# v1.17.30 (2024-08-26)
|
||||
|
||||
* **Bug Fix**: Save SSO cached token expiry in UTC to ensure cross-SDK compatibility.
|
||||
|
||||
# v1.17.29 (2024-08-22)
|
||||
|
||||
* **Dependency Update**: Updated to the latest SDK module versions
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
package credentials
|
||||
|
||||
// goModuleVersion is the tagged release for this module
|
||||
const goModuleVersion = "1.17.29"
|
||||
const goModuleVersion = "1.17.30"
|
||||
|
|
|
@ -225,7 +225,7 @@ func (r *rfc3339) UnmarshalJSON(bytes []byte) (err error) {
|
|||
}
|
||||
|
||||
func (r *rfc3339) MarshalJSON() ([]byte, error) {
|
||||
value := time.Time(*r).Format(time.RFC3339)
|
||||
value := time.Time(*r).UTC().Format(time.RFC3339)
|
||||
|
||||
// Use JSON unmarshal to unescape the quoted value making use of JSON's
|
||||
// quoting rules.
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
# v1.177.0 (2024-08-28)
|
||||
|
||||
* **Feature**: Amazon VPC IP Address Manager (IPAM) now allows customers to provision IPv4 CIDR blocks and allocate Elastic IP Addresses directly from IPAM pools with public IPv4 space
|
||||
|
||||
# v1.176.0 (2024-08-21)
|
||||
|
||||
* **Feature**: DescribeInstanceStatus now returns health information on EBS volumes attached to Nitro instances
|
||||
|
|
|
@ -69,6 +69,9 @@ type AllocateAddressInput struct {
|
|||
// UnauthorizedOperation .
|
||||
DryRun *bool
|
||||
|
||||
// The ID of an IPAM pool.
|
||||
IpamPoolId *string
|
||||
|
||||
// A unique set of Availability Zones, Local Zones, or Wavelength Zones from
|
||||
// which Amazon Web Services advertises IP addresses. Use this parameter to limit
|
||||
// the IP address to this location. IP addresses cannot move between network border
|
||||
|
|
|
@ -13,8 +13,7 @@ import (
|
|||
|
||||
// Registers an AMI. When you're creating an instance-store backed AMI,
|
||||
// registering the AMI is the final step in the creation process. For more
|
||||
// information about creating AMIs, see [Create your own AMI]in the Amazon Elastic Compute Cloud User
|
||||
// Guide.
|
||||
// information about creating AMIs, see [Create an AMI from a snapshot]and [Create an instance-store backed AMI] in the Amazon EC2 User Guide.
|
||||
//
|
||||
// For Amazon EBS-backed instances, CreateImage creates and registers the AMI in a single
|
||||
// request, so you don't have to register the AMI yourself. We recommend that you
|
||||
|
@ -33,25 +32,24 @@ import (
|
|||
// mapping. If the snapshot is encrypted, or encryption by default is enabled, the
|
||||
// root volume of an instance launched from the AMI is encrypted.
|
||||
//
|
||||
// For more information, see [Create a Linux AMI from a snapshot] and [Use encryption with Amazon EBS-backed AMIs] in the Amazon Elastic Compute Cloud User Guide.
|
||||
// For more information, see [Create an AMI from a snapshot] and [Use encryption with Amazon EBS-backed AMIs] in the Amazon EC2 User Guide.
|
||||
//
|
||||
// # Amazon Web Services Marketplace product codes
|
||||
//
|
||||
// If any snapshots have Amazon Web Services Marketplace product codes, they are
|
||||
// copied to the new AMI.
|
||||
//
|
||||
// Windows and some Linux distributions, such as Red Hat Enterprise Linux (RHEL)
|
||||
// and SUSE Linux Enterprise Server (SLES), use the Amazon EC2 billing product code
|
||||
// associated with an AMI to verify the subscription status for package updates. To
|
||||
// create a new AMI for operating systems that require a billing product code,
|
||||
// instead of registering the AMI, do the following to preserve the billing product
|
||||
// code association:
|
||||
//
|
||||
// - Launch an instance from an existing AMI with that billing product code.
|
||||
//
|
||||
// - Customize the instance.
|
||||
//
|
||||
// - Create an AMI from the instance using CreateImage.
|
||||
// In most cases, AMIs for Windows, RedHat, SUSE, and SQL Server require correct
|
||||
// licensing information to be present on the AMI. For more information, see [Understand AMI billing information]in
|
||||
// the Amazon EC2 User Guide. When creating an AMI from a snapshot, the
|
||||
// RegisterImage operation derives the correct billing information from the
|
||||
// snapshot's metadata, but this requires the appropriate metadata to be present.
|
||||
// To verify if the correct billing information was applied, check the
|
||||
// PlatformDetails field on the new AMI. If the field is empty or doesn't match the
|
||||
// expected operating system code (for example, Windows, RedHat, SUSE, or SQL), the
|
||||
// AMI creation was unsuccessful, and you should discard the AMI and instead create
|
||||
// the AMI from an instance using CreateImage. For more information, see [Create an AMI from an instance] in the Amazon EC2
|
||||
// User Guide.
|
||||
//
|
||||
// If you purchase a Reserved Instance to apply to an On-Demand Instance that was
|
||||
// launched from an AMI with a billing product code, make sure that the Reserved
|
||||
|
@ -62,9 +60,10 @@ import (
|
|||
// User Guide.
|
||||
//
|
||||
// [Understand AMI billing information]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ami-billing-info.html
|
||||
// [Create a Linux AMI from a snapshot]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/creating-an-ami-ebs.html#creating-launching-ami-from-snapshot
|
||||
// [Create an instance-store backed AMI]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/creating-an-ami-instance-store.html
|
||||
// [Create an AMI from an instance]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/creating-an-ami-ebs.html#how-to-create-ebs-ami
|
||||
// [Create an AMI from a snapshot]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/creating-an-ami-ebs.html#creating-launching-ami-from-snapshot
|
||||
// [Use encryption with Amazon EBS-backed AMIs]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIEncryption.html
|
||||
// [Create your own AMI]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/creating-an-ami.html
|
||||
func (c *Client) RegisterImage(ctx context.Context, params *RegisterImageInput, optFns ...func(*Options)) (*RegisterImageOutput, error) {
|
||||
if params == nil {
|
||||
params = &RegisterImageInput{}
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
package ec2
|
||||
|
||||
// goModuleVersion is the tagged release for this module
|
||||
const goModuleVersion = "1.176.0"
|
||||
const goModuleVersion = "1.177.0"
|
||||
|
|
|
@ -50221,6 +50221,11 @@ func awsEc2query_serializeOpDocumentAllocateAddressInput(v *AllocateAddressInput
|
|||
objectKey.Boolean(*v.DryRun)
|
||||
}
|
||||
|
||||
if v.IpamPoolId != nil {
|
||||
objectKey := object.Key("IpamPoolId")
|
||||
objectKey.String(*v.IpamPoolId)
|
||||
}
|
||||
|
||||
if v.NetworkBorderGroup != nil {
|
||||
objectKey := object.Key("NetworkBorderGroup")
|
||||
objectKey.String(*v.NetworkBorderGroup)
|
||||
|
|
|
@ -5061,6 +5061,7 @@ const (
|
|||
IpamPoolAllocationResourceTypeEc2PublicIpv4Pool IpamPoolAllocationResourceType = "ec2-public-ipv4-pool"
|
||||
IpamPoolAllocationResourceTypeCustom IpamPoolAllocationResourceType = "custom"
|
||||
IpamPoolAllocationResourceTypeSubnet IpamPoolAllocationResourceType = "subnet"
|
||||
IpamPoolAllocationResourceTypeEip IpamPoolAllocationResourceType = "eip"
|
||||
)
|
||||
|
||||
// Values returns all known values for IpamPoolAllocationResourceType. Note that
|
||||
|
@ -5075,6 +5076,7 @@ func (IpamPoolAllocationResourceType) Values() []IpamPoolAllocationResourceType
|
|||
"ec2-public-ipv4-pool",
|
||||
"custom",
|
||||
"subnet",
|
||||
"eip",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5280,6 +5282,7 @@ const (
|
|||
IpamPublicAddressTypeServiceManagedIp IpamPublicAddressType = "service-managed-ip"
|
||||
IpamPublicAddressTypeServiceManagedByoip IpamPublicAddressType = "service-managed-byoip"
|
||||
IpamPublicAddressTypeAmazonOwnedEip IpamPublicAddressType = "amazon-owned-eip"
|
||||
IpamPublicAddressTypeAmazonOwnedContig IpamPublicAddressType = "amazon-owned-contig"
|
||||
IpamPublicAddressTypeByoip IpamPublicAddressType = "byoip"
|
||||
IpamPublicAddressTypeEc2PublicIp IpamPublicAddressType = "ec2-public-ip"
|
||||
)
|
||||
|
@ -5293,6 +5296,7 @@ func (IpamPublicAddressType) Values() []IpamPublicAddressType {
|
|||
"service-managed-ip",
|
||||
"service-managed-byoip",
|
||||
"amazon-owned-eip",
|
||||
"amazon-owned-contig",
|
||||
"byoip",
|
||||
"ec2-public-ip",
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
# v1.61.0 (2024-08-28)
|
||||
|
||||
* **Feature**: Add presignPost for s3 PutObject
|
||||
|
||||
# v1.60.1 (2024-08-22)
|
||||
|
||||
* No change notes available for this release.
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
package s3
|
||||
|
||||
// goModuleVersion is the tagged release for this module
|
||||
const goModuleVersion = "1.60.1"
|
||||
const goModuleVersion = "1.61.0"
|
||||
|
|
|
@ -0,0 +1,433 @@
|
|||
package s3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware"
|
||||
"github.com/aws/aws-sdk-go-v2/aws/retry"
|
||||
v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
|
||||
awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http"
|
||||
internalcontext "github.com/aws/aws-sdk-go-v2/internal/context"
|
||||
"github.com/aws/aws-sdk-go-v2/internal/sdk"
|
||||
acceptencodingcust "github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding"
|
||||
presignedurlcust "github.com/aws/aws-sdk-go-v2/service/internal/presigned-url"
|
||||
"github.com/aws/smithy-go/middleware"
|
||||
smithyhttp "github.com/aws/smithy-go/transport/http"
|
||||
)
|
||||
|
||||
const (
|
||||
algorithmHeader = "X-Amz-Algorithm"
|
||||
credentialHeader = "X-Amz-Credential"
|
||||
dateHeader = "X-Amz-Date"
|
||||
tokenHeader = "X-Amz-Security-Token"
|
||||
signatureHeader = "X-Amz-Signature"
|
||||
|
||||
algorithm = "AWS4-HMAC-SHA256"
|
||||
aws4Request = "aws4_request"
|
||||
bucketHeader = "bucket"
|
||||
defaultExpiresIn = 15 * time.Minute
|
||||
shortDateLayout = "20060102"
|
||||
)
|
||||
|
||||
// PresignPostObject is a special kind of [presigned request] used to send a request using
|
||||
// form data, likely from an HTML form on a browser.
|
||||
// Unlike other presigned operations, the return values of this function are not meant to be used directly
|
||||
// to make an HTTP request but rather to be used as inputs to a form. See [the docs] for more information
|
||||
// on how to use these values
|
||||
//
|
||||
// [presigned request] https://docs.aws.amazon.com/AmazonS3/latest/userguide/ShareObjectPreSignedURL.html
|
||||
// [the docs] https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html
|
||||
func (c *PresignClient) PresignPostObject(ctx context.Context, params *PutObjectInput, optFns ...func(*PresignPostOptions)) (*PresignedPostRequest, error) {
|
||||
if params == nil {
|
||||
params = &PutObjectInput{}
|
||||
}
|
||||
clientOptions := c.options.copy()
|
||||
options := PresignPostOptions{
|
||||
Expires: clientOptions.Expires,
|
||||
PostPresigner: &postSignAdapter{},
|
||||
}
|
||||
for _, fn := range optFns {
|
||||
fn(&options)
|
||||
}
|
||||
clientOptFns := append(clientOptions.ClientOptions, withNopHTTPClientAPIOption)
|
||||
cvt := presignPostConverter(options)
|
||||
result, _, err := c.client.invokeOperation(ctx, "$type:L", params, clientOptFns,
|
||||
c.client.addOperationPutObjectMiddlewares,
|
||||
cvt.ConvertToPresignMiddleware,
|
||||
func(stack *middleware.Stack, options Options) error {
|
||||
return awshttp.RemoveContentTypeHeader(stack)
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out := result.(*PresignedPostRequest)
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// PresignedPostRequest represents a presigned request to be sent using HTTP verb POST and FormData
|
||||
type PresignedPostRequest struct {
|
||||
// Represents the Base URL to make a request to
|
||||
URL string
|
||||
// Values is a key-value map of values to be sent as FormData
|
||||
// these values are not encoded
|
||||
Values map[string]string
|
||||
}
|
||||
|
||||
// postSignAdapter adapter to implement the presignPost interface
|
||||
type postSignAdapter struct{}
|
||||
|
||||
// PresignPost creates a special kind of [presigned request]
|
||||
// to be used with HTTP verb POST.
|
||||
// It differs from PUT request mostly on
|
||||
// 1. It accepts a new set of parameters, `Conditions[]`, that are used to create a policy doc to limit where an object can be posted to
|
||||
// 2. The return value needs to have more processing since it's meant to be sent via a form and not stand on its own
|
||||
// 3. There's no body to be signed, since that will be attached when the actual request is made
|
||||
// 4. The signature is made based on the policy document, not the whole request
|
||||
// More information can be found at https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html
|
||||
//
|
||||
// [presigned request] https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html
|
||||
func (s *postSignAdapter) PresignPost(
|
||||
credentials aws.Credentials,
|
||||
bucket string, key string,
|
||||
region string, service string, signingTime time.Time, conditions []interface{}, expirationTime time.Time, optFns ...func(*v4.SignerOptions),
|
||||
) (fields map[string]string, err error) {
|
||||
credentialScope := buildCredentialScope(signingTime, region, service)
|
||||
credentialStr := credentials.AccessKeyID + "/" + credentialScope
|
||||
|
||||
policyDoc, err := createPolicyDocument(expirationTime, signingTime, bucket, key, credentialStr, &credentials.SessionToken, conditions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
signature := buildSignature(policyDoc, credentials.SecretAccessKey, service, region, signingTime)
|
||||
|
||||
fields = getPostSignRequiredFields(signingTime, credentialStr, credentials)
|
||||
fields[signatureHeader] = signature
|
||||
fields["key"] = key
|
||||
fields["policy"] = policyDoc
|
||||
|
||||
return fields, nil
|
||||
}
|
||||
|
||||
func getPostSignRequiredFields(t time.Time, credentialStr string, awsCredentials aws.Credentials) map[string]string {
|
||||
fields := map[string]string{
|
||||
algorithmHeader: algorithm,
|
||||
dateHeader: t.UTC().Format("20060102T150405Z"),
|
||||
credentialHeader: credentialStr,
|
||||
}
|
||||
|
||||
sessionToken := awsCredentials.SessionToken
|
||||
if len(sessionToken) > 0 {
|
||||
fields[tokenHeader] = sessionToken
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
// PresignPost defines the interface to presign a POST request
|
||||
type PresignPost interface {
|
||||
PresignPost(
|
||||
credentials aws.Credentials,
|
||||
bucket string, key string,
|
||||
region string, service string, signingTime time.Time, conditions []interface{}, expirationTime time.Time,
|
||||
optFns ...func(*v4.SignerOptions),
|
||||
) (fields map[string]string, err error)
|
||||
}
|
||||
|
||||
// PresignPostOptions represent the options to be passed to a PresignPost sign request
|
||||
type PresignPostOptions struct {
|
||||
|
||||
// ClientOptions are list of functional options to mutate client options used by
|
||||
// the presign client.
|
||||
ClientOptions []func(*Options)
|
||||
|
||||
// PostPresigner to use. One will be created if none is provided
|
||||
PostPresigner PresignPost
|
||||
|
||||
// Expires sets the expiration duration for the generated presign url. This should
|
||||
// be the duration in seconds the presigned URL should be considered valid for. If
|
||||
// not set or set to zero, presign url would default to expire after 900 seconds.
|
||||
Expires time.Duration
|
||||
|
||||
// Conditions a list of extra conditions to pass to the policy document
|
||||
// Available conditions can be found [here]
|
||||
//
|
||||
// [here]https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html#sigv4-PolicyConditions
|
||||
Conditions []interface{}
|
||||
}
|
||||
|
||||
type presignPostConverter PresignPostOptions
|
||||
|
||||
// presignPostRequestMiddlewareOptions is the options for the presignPostRequestMiddleware middleware.
|
||||
type presignPostRequestMiddlewareOptions struct {
|
||||
CredentialsProvider aws.CredentialsProvider
|
||||
Presigner PresignPost
|
||||
LogSigning bool
|
||||
ExpiresIn time.Duration
|
||||
Conditions []interface{}
|
||||
}
|
||||
|
||||
type presignPostRequestMiddleware struct {
|
||||
credentialsProvider aws.CredentialsProvider
|
||||
presigner PresignPost
|
||||
logSigning bool
|
||||
expiresIn time.Duration
|
||||
conditions []interface{}
|
||||
}
|
||||
|
||||
// newPresignPostRequestMiddleware returns a new presignPostRequestMiddleware
|
||||
// initialized with the presigner.
|
||||
func newPresignPostRequestMiddleware(options presignPostRequestMiddlewareOptions) *presignPostRequestMiddleware {
|
||||
return &presignPostRequestMiddleware{
|
||||
credentialsProvider: options.CredentialsProvider,
|
||||
presigner: options.Presigner,
|
||||
logSigning: options.LogSigning,
|
||||
expiresIn: options.ExpiresIn,
|
||||
conditions: options.Conditions,
|
||||
}
|
||||
}
|
||||
|
||||
// ID provides the middleware ID.
|
||||
func (*presignPostRequestMiddleware) ID() string { return "PresignPostRequestMiddleware" }
|
||||
|
||||
// HandleFinalize will take the provided input and create a presigned url for
|
||||
// the http request using the SigV4 presign authentication scheme.
|
||||
//
|
||||
// Since the signed request is not a valid HTTP request
|
||||
func (s *presignPostRequestMiddleware) HandleFinalize(
|
||||
ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler,
|
||||
) (
|
||||
out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
|
||||
) {
|
||||
req, ok := in.Request.(*smithyhttp.Request)
|
||||
if !ok {
|
||||
return out, metadata, fmt.Errorf("unexpected request middleware type %T", in.Request)
|
||||
}
|
||||
|
||||
input := getOperationInput(ctx)
|
||||
asS3Put, ok := input.(*PutObjectInput)
|
||||
if !ok {
|
||||
return out, metadata, fmt.Errorf("expected PutObjectInput")
|
||||
}
|
||||
bucketName, ok := asS3Put.bucket()
|
||||
if !ok {
|
||||
return out, metadata, fmt.Errorf("requested input bucketName not found on request")
|
||||
}
|
||||
uploadKey := asS3Put.Key
|
||||
if uploadKey == nil {
|
||||
return out, metadata, fmt.Errorf("PutObject input does not have a key input")
|
||||
}
|
||||
|
||||
httpReq := req.Build(ctx)
|
||||
u := httpReq.URL.String()
|
||||
|
||||
signingName := awsmiddleware.GetSigningName(ctx)
|
||||
signingRegion := awsmiddleware.GetSigningRegion(ctx)
|
||||
|
||||
credentials, err := s.credentialsProvider.Retrieve(ctx)
|
||||
if err != nil {
|
||||
return out, metadata, &v4.SigningError{
|
||||
Err: fmt.Errorf("failed to retrieve credentials: %w", err),
|
||||
}
|
||||
}
|
||||
skew := internalcontext.GetAttemptSkewContext(ctx)
|
||||
signingTime := sdk.NowTime().Add(skew)
|
||||
expirationTime := signingTime.Add(s.expiresIn).UTC()
|
||||
|
||||
fields, err := s.presigner.PresignPost(
|
||||
credentials,
|
||||
bucketName,
|
||||
*uploadKey,
|
||||
signingRegion,
|
||||
signingName,
|
||||
signingTime,
|
||||
s.conditions,
|
||||
expirationTime,
|
||||
func(o *v4.SignerOptions) {
|
||||
o.Logger = middleware.GetLogger(ctx)
|
||||
o.LogSigning = s.logSigning
|
||||
})
|
||||
if err != nil {
|
||||
return out, metadata, &v4.SigningError{
|
||||
Err: fmt.Errorf("failed to sign http request, %w", err),
|
||||
}
|
||||
}
|
||||
|
||||
// Other middlewares may set default values on the URL on the path or as query params. Remove them
|
||||
baseURL := toBaseURL(u)
|
||||
|
||||
out.Result = &PresignedPostRequest{
|
||||
URL: baseURL,
|
||||
Values: fields,
|
||||
}
|
||||
|
||||
return out, metadata, nil
|
||||
}
|
||||
|
||||
func toBaseURL(fullURL string) string {
|
||||
a, _ := url.Parse(fullURL)
|
||||
return a.Scheme + "://" + a.Host
|
||||
}
|
||||
|
||||
// Adapted from existing PresignConverter middleware
|
||||
func (c presignPostConverter) ConvertToPresignMiddleware(stack *middleware.Stack, options Options) (err error) {
|
||||
stack.Build.Remove("UserAgent")
|
||||
stack.Finalize.Remove((*acceptencodingcust.DisableGzip)(nil).ID())
|
||||
stack.Finalize.Remove((*retry.Attempt)(nil).ID())
|
||||
stack.Finalize.Remove((*retry.MetricsHeader)(nil).ID())
|
||||
stack.Deserialize.Clear()
|
||||
|
||||
if err := stack.Finalize.Insert(&presignContextPolyfillMiddleware{}, "Signing", middleware.Before); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if no expiration is set, set one
|
||||
expiresIn := c.Expires
|
||||
if expiresIn == 0 {
|
||||
expiresIn = defaultExpiresIn
|
||||
}
|
||||
|
||||
pmw := newPresignPostRequestMiddleware(presignPostRequestMiddlewareOptions{
|
||||
CredentialsProvider: options.Credentials,
|
||||
Presigner: c.PostPresigner,
|
||||
LogSigning: options.ClientLogMode.IsSigning(),
|
||||
ExpiresIn: expiresIn,
|
||||
Conditions: c.Conditions,
|
||||
})
|
||||
if _, err := stack.Finalize.Swap("Signing", pmw); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = smithyhttp.AddNoPayloadDefaultContentTypeRemover(stack); err != nil {
|
||||
return err
|
||||
}
|
||||
err = presignedurlcust.AddAsIsPresigningMiddleware(stack)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func createPolicyDocument(expirationTime time.Time, signingTime time.Time, bucket string, key string, credentialString string, securityToken *string, extraConditions []interface{}) (string, error) {
|
||||
initialConditions := []interface{}{
|
||||
map[string]string{
|
||||
algorithmHeader: algorithm,
|
||||
},
|
||||
map[string]string{
|
||||
bucketHeader: bucket,
|
||||
},
|
||||
map[string]string{
|
||||
credentialHeader: credentialString,
|
||||
},
|
||||
map[string]string{
|
||||
dateHeader: signingTime.UTC().Format("20060102T150405Z"),
|
||||
},
|
||||
}
|
||||
|
||||
var conditions []interface{}
|
||||
for _, v := range initialConditions {
|
||||
conditions = append(conditions, v)
|
||||
}
|
||||
|
||||
if securityToken != nil && *securityToken != "" {
|
||||
conditions = append(conditions, map[string]string{
|
||||
tokenHeader: *securityToken,
|
||||
})
|
||||
}
|
||||
|
||||
// append user-defined conditions at the end
|
||||
conditions = append(conditions, extraConditions...)
|
||||
|
||||
// The policy allows you to set a "key" value to specify what's the name of the
|
||||
// key to add. Customers can add one by specifying one in their conditions,
|
||||
// so we're checking if one has already been set.
|
||||
// If none is found, restrict this to just the key name passed on the request
|
||||
// This can be disabled by adding a condition that explicitly allows
|
||||
// everything
|
||||
if !isAlreadyCheckingForKey(conditions) {
|
||||
conditions = append(conditions, map[string]string{"key": key})
|
||||
}
|
||||
|
||||
policyDoc := map[string]interface{}{
|
||||
"conditions": conditions,
|
||||
"expiration": expirationTime.Format(time.RFC3339),
|
||||
}
|
||||
|
||||
jsonBytes, err := json.Marshal(policyDoc)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return base64.StdEncoding.EncodeToString(jsonBytes), nil
|
||||
}
|
||||
|
||||
func isAlreadyCheckingForKey(conditions []interface{}) bool {
|
||||
// Need to check for two conditions:
|
||||
// 1. A condition of the form ["starts-with", "$key", "mykey"]
|
||||
// 2. A condition of the form {"key": "mykey"}
|
||||
for _, c := range conditions {
|
||||
slice, ok := c.([]interface{})
|
||||
if ok && len(slice) > 1 {
|
||||
if slice[0] == "starts-with" && slice[1] == "$key" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
m, ok := c.(map[string]interface{})
|
||||
if ok && len(m) > 0 {
|
||||
for k := range m {
|
||||
if k == "key" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
// Repeat this but for map[string]string due to type constrains
|
||||
ms, ok := c.(map[string]string)
|
||||
if ok && len(ms) > 0 {
|
||||
for k := range ms {
|
||||
if k == "key" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// these methods have been copied from v4 implementation since they are not exported for public use
|
||||
func hmacsha256(key []byte, data []byte) []byte {
|
||||
hash := hmac.New(sha256.New, key)
|
||||
hash.Write(data)
|
||||
return hash.Sum(nil)
|
||||
}
|
||||
|
||||
func buildSignature(strToSign, secret, service, region string, t time.Time) string {
|
||||
key := deriveKey(secret, service, region, t)
|
||||
return hex.EncodeToString(hmacsha256(key, []byte(strToSign)))
|
||||
}
|
||||
|
||||
func deriveKey(secret, service, region string, t time.Time) []byte {
|
||||
hmacDate := hmacsha256([]byte("AWS4"+secret), []byte(t.UTC().Format(shortDateLayout)))
|
||||
hmacRegion := hmacsha256(hmacDate, []byte(region))
|
||||
hmacService := hmacsha256(hmacRegion, []byte(service))
|
||||
return hmacsha256(hmacService, []byte(aws4Request))
|
||||
}
|
||||
|
||||
func buildCredentialScope(signingTime time.Time, region, service string) string {
|
||||
return strings.Join([]string{
|
||||
signingTime.UTC().Format(shortDateLayout),
|
||||
region,
|
||||
service,
|
||||
aws4Request,
|
||||
}, "/")
|
||||
}
|
|
@ -1,5 +1,12 @@
|
|||
# Change Log
|
||||
|
||||
## [v1.121.0] - 2024-08-20
|
||||
|
||||
- #715 - @danaelhe - Databases: Bring back Logsink Support
|
||||
- #710 - @bhardwajRahul - Update GODO to include new Openseach index crud changes
|
||||
- #712 - @danaelhe - Database: Namespace logsink
|
||||
- #711 - @danaelhe - Databases: Add Logsinks CRUD support
|
||||
|
||||
## [v1.120.0] - 2024-08-08
|
||||
|
||||
- #708 - @markusthoemmes - APPS-9201 Add `UpdateAllSourceVersions` parameter to update app calls
|
||||
|
|
|
@ -36,6 +36,10 @@ const (
|
|||
databaseTopicsPath = databaseBasePath + "/%s/topics"
|
||||
databaseMetricsCredentialsPath = databaseBasePath + "/metrics/credentials"
|
||||
databaseEvents = databaseBasePath + "/%s/events"
|
||||
databaseIndexesPath = databaseBasePath + "/%s/indexes"
|
||||
databaseIndexPath = databaseBasePath + "/%s/indexes/%s"
|
||||
databaseLogsinkPath = databaseBasePath + "/%s/logsink/%s"
|
||||
databaseLogsinksPath = databaseBasePath + "/%s/logsink"
|
||||
)
|
||||
|
||||
// SQL Mode constants allow for MySQL-specific SQL flavor configuration.
|
||||
|
@ -159,6 +163,13 @@ type DatabasesService interface {
|
|||
GetMetricsCredentials(context.Context) (*DatabaseMetricsCredentials, *Response, error)
|
||||
UpdateMetricsCredentials(context.Context, *DatabaseUpdateMetricsCredentialsRequest) (*Response, error)
|
||||
ListDatabaseEvents(context.Context, string, *ListOptions) ([]DatabaseEvent, *Response, error)
|
||||
ListIndexes(context.Context, string, *ListOptions) ([]DatabaseIndex, *Response, error)
|
||||
DeleteIndex(context.Context, string, string) (*Response, error)
|
||||
CreateLogsink(ctx context.Context, databaseID string, createLogsink *DatabaseCreateLogsinkRequest) (*DatabaseLogsink, *Response, error)
|
||||
GetLogsink(ctx context.Context, databaseID string, logsinkID string) (*DatabaseLogsink, *Response, error)
|
||||
ListLogsinks(ctx context.Context, databaseID string, opts *ListOptions) ([]DatabaseLogsink, *Response, error)
|
||||
UpdateLogsink(ctx context.Context, databaseID string, logsinkID string, updateLogsink *DatabaseUpdateLogsinkRequest) (*Response, error)
|
||||
DeleteLogsink(ctx context.Context, databaseID, logsinkID string) (*Response, error)
|
||||
}
|
||||
|
||||
// DatabasesServiceOp handles communication with the Databases related methods
|
||||
|
@ -323,6 +334,14 @@ type DatabaseTopic struct {
|
|||
Config *TopicConfig `json:"config,omitempty"`
|
||||
}
|
||||
|
||||
// DatabaseLogsink represents a logsink
|
||||
type DatabaseLogsink struct {
|
||||
ID string `json:"sink_id"`
|
||||
Name string `json:"sink_name,omitempty"`
|
||||
Type string `json:"sink_type,omitempty"`
|
||||
Config *DatabaseLogsinkConfig `json:"config,omitempty"`
|
||||
}
|
||||
|
||||
// TopicPartition represents the state of a Kafka topic partition
|
||||
type TopicPartition struct {
|
||||
EarliestOffset uint64 `json:"earliest_offset,omitempty"`
|
||||
|
@ -472,6 +491,35 @@ type DatabaseFirewallRule struct {
|
|||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// DatabaseCreateLogsinkRequest is used to create logsink for a database cluster
|
||||
type DatabaseCreateLogsinkRequest struct {
|
||||
Name string `json:"sink_name"`
|
||||
Type string `json:"sink_type"`
|
||||
Config *DatabaseLogsinkConfig `json:"config"`
|
||||
}
|
||||
|
||||
// DatabaseUpdateLogsinkRequest is used to update logsink for a database cluster
|
||||
type DatabaseUpdateLogsinkRequest struct {
|
||||
Config *DatabaseLogsinkConfig `json:"config"`
|
||||
}
|
||||
|
||||
// DatabaseLogsinkConfig represents one of the configurable options (rsyslog_logsink, elasticsearch_logsink, or opensearch_logsink) for a logsink.
|
||||
type DatabaseLogsinkConfig struct {
|
||||
URL string `json:"url,omitempty"`
|
||||
IndexPrefix string `json:"index_prefix,omitempty"`
|
||||
IndexDaysMax string `json:"index_days_max,omitempty"`
|
||||
Timeout string `json:"timeout,omitempty"`
|
||||
Server string `json:"server,omitempty"`
|
||||
Port int `json:"port,omitempty"`
|
||||
TLS bool `json:"tls,omitempty"`
|
||||
Format string `json:"format,omitempty"`
|
||||
Logline string `json:"logline,omitempty"`
|
||||
SD string `json:"sd,omitempty"`
|
||||
CA string `json:"ca,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
Cert string `json:"cert,omitempty"`
|
||||
}
|
||||
|
||||
// PostgreSQLConfig holds advanced configurations for PostgreSQL database clusters.
|
||||
type PostgreSQLConfig struct {
|
||||
AutovacuumFreezeMaxAge *int `json:"autovacuum_freeze_max_age,omitempty"`
|
||||
|
@ -680,6 +728,10 @@ type databaseTopicsRoot struct {
|
|||
Topics []DatabaseTopic `json:"topics"`
|
||||
}
|
||||
|
||||
type databaseLogsinksRoot struct {
|
||||
Sinks []DatabaseLogsink `json:"sinks"`
|
||||
}
|
||||
|
||||
type databaseMetricsCredentialsRoot struct {
|
||||
Credentials *DatabaseMetricsCredentials `json:"credentials"`
|
||||
}
|
||||
|
@ -733,6 +785,28 @@ type ListDatabaseEventsRoot struct {
|
|||
Events []DatabaseEvent `json:"events"`
|
||||
}
|
||||
|
||||
type DatabaseIndex struct {
|
||||
IndexName string `json:"index_name"`
|
||||
NumberofShards uint64 `json:"number_of_shards"`
|
||||
NumberofReplicas uint64 `json:"number_of_replicas"`
|
||||
Size int64 `json:"size,omitempty"`
|
||||
Health string `json:"health,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Docs int64 `json:"docs,omitempty"`
|
||||
CreateTime string `json:"create_time"`
|
||||
Replication *IndexReplication `json:"replication,omitempty"`
|
||||
}
|
||||
|
||||
type IndexReplication struct {
|
||||
LeaderIndex string `json:"leader_index,omitempty"`
|
||||
LeaderProject string `json:"leader_project,omitempty"`
|
||||
LeaderService string `json:"leader_service,omitempty"`
|
||||
}
|
||||
|
||||
type databaseIndexesRoot struct {
|
||||
Indexes []DatabaseIndex `json:"indexes"`
|
||||
}
|
||||
|
||||
// URN returns a URN identifier for the database
|
||||
func (d Database) URN() string {
|
||||
return ToURN("dbaas", d.ID)
|
||||
|
@ -1560,3 +1634,116 @@ func (svc *DatabasesServiceOp) ListDatabaseEvents(ctx context.Context, databaseI
|
|||
|
||||
return root.Events, resp, nil
|
||||
}
|
||||
|
||||
// ListIndexes returns all indexes for a given opensearch cluster
|
||||
func (svc *DatabasesServiceOp) ListIndexes(ctx context.Context, databaseID string, opts *ListOptions) ([]DatabaseIndex, *Response, error) {
|
||||
path := fmt.Sprintf(databaseIndexesPath, databaseID)
|
||||
path, err := addOptions(path, opts)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(databaseIndexesRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Indexes, resp, nil
|
||||
}
|
||||
|
||||
// DeleteIndex will delete an existing opensearch index
|
||||
func (svc *DatabasesServiceOp) DeleteIndex(ctx context.Context, databaseID, name string) (*Response, error) {
|
||||
path := fmt.Sprintf(databaseIndexPath, databaseID, name)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodDelete, path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := svc.client.Do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// CreateLogsink creates a new logsink for a database
|
||||
func (svc *DatabasesServiceOp) CreateLogsink(ctx context.Context, databaseID string, createLogsink *DatabaseCreateLogsinkRequest) (*DatabaseLogsink, *Response, error) {
|
||||
path := fmt.Sprintf(databaseLogsinksPath, databaseID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodPost, path, createLogsink)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
root := new(DatabaseLogsink)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root, resp, nil
|
||||
}
|
||||
|
||||
// GetLogsink gets a logsink for a database
|
||||
func (svc *DatabasesServiceOp) GetLogsink(ctx context.Context, databaseID string, logsinkID string) (*DatabaseLogsink, *Response, error) {
|
||||
path := fmt.Sprintf(databaseLogsinkPath, databaseID, logsinkID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
root := new(DatabaseLogsink)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root, resp, nil
|
||||
}
|
||||
|
||||
// ListTopics returns all topics for a given kafka cluster
|
||||
func (svc *DatabasesServiceOp) ListLogsinks(ctx context.Context, databaseID string, opts *ListOptions) ([]DatabaseLogsink, *Response, error) {
|
||||
path := fmt.Sprintf(databaseLogsinksPath, databaseID)
|
||||
path, err := addOptions(path, opts)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root := new(databaseLogsinksRoot)
|
||||
resp, err := svc.client.Do(ctx, req, root)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
return root.Sinks, resp, nil
|
||||
}
|
||||
|
||||
// UpdateLogsink updates a logsink for a database cluster
|
||||
func (svc *DatabasesServiceOp) UpdateLogsink(ctx context.Context, databaseID string, logsinkID string, updateLogsink *DatabaseUpdateLogsinkRequest) (*Response, error) {
|
||||
path := fmt.Sprintf(databaseLogsinkPath, databaseID, logsinkID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodPut, path, updateLogsink)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := svc.client.Do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// DeleteLogsink deletes a logsink for a database cluster
|
||||
func (svc *DatabasesServiceOp) DeleteLogsink(ctx context.Context, databaseID, logsinkID string) (*Response, error) {
|
||||
path := fmt.Sprintf(databaseLogsinkPath, databaseID, logsinkID)
|
||||
req, err := svc.client.NewRequest(ctx, http.MethodDelete, path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := svc.client.Do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
libraryVersion = "1.120.0"
|
||||
libraryVersion = "1.121.0"
|
||||
defaultBaseURL = "https://api.digitalocean.com/"
|
||||
userAgent = "godo/" + libraryVersion
|
||||
mediaType = "application/json"
|
||||
|
|
|
@ -39,8 +39,8 @@ _Keep this table sorted by Function in ascending order._
|
|||
| [Count](https://godoc.org/github.com/huandu/xstrings#Count) | `String#count` in Ruby | [#16](https://github.com/huandu/xstrings/issues/16) |
|
||||
| [Delete](https://godoc.org/github.com/huandu/xstrings#Delete) | `String#delete` in Ruby | [#17](https://github.com/huandu/xstrings/issues/17) |
|
||||
| [ExpandTabs](https://godoc.org/github.com/huandu/xstrings#ExpandTabs) | `str.expandtabs` in Python | [#27](https://github.com/huandu/xstrings/issues/27) |
|
||||
| [FirstRuneToLower](https://godoc.org/github.com/huandu/xstrings#FirstRuneToLower) | `lcfirst` in PHP or Perl | [#15](https://github.com/huandu/xstrings/issues/15) |
|
||||
| [FirstRuneToUpper](https://godoc.org/github.com/huandu/xstrings#FirstRuneToUpper) | `String#capitalize` in Ruby; `ucfirst` in PHP or Perl | [#15](https://github.com/huandu/xstrings/issues/15) |
|
||||
| [FirstRuneToLower](https://godoc.org/github.com/huandu/xstrings#FirstRuneToLower) | `lcfirst` in PHP or Perl | [#15](https://github.com/huandu/xstrings/issues/15) |
|
||||
| [FirstRuneToUpper](https://godoc.org/github.com/huandu/xstrings#FirstRuneToUpper) | `String#capitalize` in Ruby; `ucfirst` in PHP or Perl | [#15](https://github.com/huandu/xstrings/issues/15) |
|
||||
| [Insert](https://godoc.org/github.com/huandu/xstrings#Insert) | `String#insert` in Ruby | [#18](https://github.com/huandu/xstrings/issues/18) |
|
||||
| [LastPartition](https://godoc.org/github.com/huandu/xstrings#LastPartition) | `str.rpartition` in Python; `String#rpartition` in Ruby | [#19](https://github.com/huandu/xstrings/issues/19) |
|
||||
| [LeftJustify](https://godoc.org/github.com/huandu/xstrings#LeftJustify) | `str.ljust` in Python; `String#ljust` in Ruby | [#28](https://github.com/huandu/xstrings/issues/28) |
|
||||
|
@ -50,14 +50,15 @@ _Keep this table sorted by Function in ascending order._
|
|||
| [RightJustify](https://godoc.org/github.com/huandu/xstrings#RightJustify) | `str.rjust` in Python; `String#rjust` in Ruby | [#29](https://github.com/huandu/xstrings/issues/29) |
|
||||
| [RuneWidth](https://godoc.org/github.com/huandu/xstrings#RuneWidth) | - | [#27](https://github.com/huandu/xstrings/issues/27) |
|
||||
| [Scrub](https://godoc.org/github.com/huandu/xstrings#Scrub) | `String#scrub` in Ruby | [#20](https://github.com/huandu/xstrings/issues/20) |
|
||||
| [Shuffle](https://godoc.org/github.com/huandu/xstrings#Shuffle) | `str_shuffle` in PHP | [#13](https://github.com/huandu/xstrings/issues/13) |
|
||||
| [ShuffleSource](https://godoc.org/github.com/huandu/xstrings#ShuffleSource) | `str_shuffle` in PHP | [#13](https://github.com/huandu/xstrings/issues/13) |
|
||||
| [Shuffle](https://godoc.org/github.com/huandu/xstrings#Shuffle) | `str_shuffle` in PHP | [#13](https://github.com/huandu/xstrings/issues/13) |
|
||||
| [ShuffleSource](https://godoc.org/github.com/huandu/xstrings#ShuffleSource) | `str_shuffle` in PHP | [#13](https://github.com/huandu/xstrings/issues/13) |
|
||||
| [Slice](https://godoc.org/github.com/huandu/xstrings#Slice) | `mb_substr` in PHP | [#9](https://github.com/huandu/xstrings/issues/9) |
|
||||
| [Squeeze](https://godoc.org/github.com/huandu/xstrings#Squeeze) | `String#squeeze` in Ruby | [#11](https://github.com/huandu/xstrings/issues/11) |
|
||||
| [Successor](https://godoc.org/github.com/huandu/xstrings#Successor) | `String#succ` or `String#next` in Ruby | [#22](https://github.com/huandu/xstrings/issues/22) |
|
||||
| [SwapCase](https://godoc.org/github.com/huandu/xstrings#SwapCase) | `str.swapcase` in Python; `String#swapcase` in Ruby | [#12](https://github.com/huandu/xstrings/issues/12) |
|
||||
| [ToCamelCase](https://godoc.org/github.com/huandu/xstrings#ToCamelCase) | `String#camelize` in RoR | [#1](https://github.com/huandu/xstrings/issues/1) |
|
||||
| [ToKebab](https://godoc.org/github.com/huandu/xstrings#ToKebabCase) | - | [#41](https://github.com/huandu/xstrings/issues/41) |
|
||||
| [ToPascalCase](https://godoc.org/github.com/huandu/xstrings#ToPascalCase) | - | [#1](https://github.com/huandu/xstrings/issues/1) |
|
||||
| [ToSnakeCase](https://godoc.org/github.com/huandu/xstrings#ToSnakeCase) | `String#underscore` in RoR | [#1](https://github.com/huandu/xstrings/issues/1) |
|
||||
| [Translate](https://godoc.org/github.com/huandu/xstrings#Translate) | `str.translate` in Python; `String#tr` in Ruby; `strtr` in PHP; `tr///` in Perl | [#21](https://github.com/huandu/xstrings/issues/21) |
|
||||
| [Width](https://godoc.org/github.com/huandu/xstrings#Width) | `mb_strwidth` in PHP | [#26](https://github.com/huandu/xstrings/issues/26) |
|
||||
|
|
|
@ -13,17 +13,37 @@ import (
|
|||
//
|
||||
// Some samples.
|
||||
//
|
||||
// "some_words" => "someWords"
|
||||
// "http_server" => "httpServer"
|
||||
// "no_https" => "noHttps"
|
||||
// "_complex__case_" => "_complex_Case_"
|
||||
// "some words" => "someWords"
|
||||
// "GOLANG_IS_GREAT" => "golangIsGreat"
|
||||
func ToCamelCase(str string) string {
|
||||
return toCamelCase(str, false)
|
||||
}
|
||||
|
||||
// ToPascalCase is to convert words separated by space, underscore and hyphen to pascal case.
|
||||
//
|
||||
// Some samples.
|
||||
//
|
||||
// "some_words" => "SomeWords"
|
||||
// "http_server" => "HttpServer"
|
||||
// "no_https" => "NoHttps"
|
||||
// "_complex__case_" => "_Complex_Case_"
|
||||
// "some words" => "SomeWords"
|
||||
func ToCamelCase(str string) string {
|
||||
// "GOLANG_IS_GREAT" => "GolangIsGreat"
|
||||
func ToPascalCase(str string) string {
|
||||
return toCamelCase(str, true)
|
||||
}
|
||||
|
||||
func toCamelCase(str string, isBig bool) string {
|
||||
if len(str) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
buf := &stringBuilder{}
|
||||
var isFirstRuneUpper bool
|
||||
var r0, r1 rune
|
||||
var size int
|
||||
|
||||
|
@ -33,7 +53,14 @@ func ToCamelCase(str string) string {
|
|||
str = str[size:]
|
||||
|
||||
if !isConnector(r0) {
|
||||
r0 = unicode.ToUpper(r0)
|
||||
isFirstRuneUpper = unicode.IsUpper(r0)
|
||||
|
||||
if isBig {
|
||||
r0 = unicode.ToUpper(r0)
|
||||
} else {
|
||||
r0 = unicode.ToLower(r0)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
|
@ -60,12 +87,25 @@ func ToCamelCase(str string) string {
|
|||
}
|
||||
|
||||
if isConnector(r1) {
|
||||
isFirstRuneUpper = unicode.IsUpper(r0)
|
||||
r0 = unicode.ToUpper(r0)
|
||||
} else {
|
||||
if isFirstRuneUpper {
|
||||
if unicode.IsUpper(r0) {
|
||||
r0 = unicode.ToLower(r0)
|
||||
} else {
|
||||
isFirstRuneUpper = false
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteRune(r1)
|
||||
}
|
||||
}
|
||||
|
||||
if isFirstRuneUpper && !isBig {
|
||||
r0 = unicode.ToLower(r0)
|
||||
}
|
||||
|
||||
buf.WriteRune(r0)
|
||||
return buf.String()
|
||||
}
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
language: go
|
||||
|
||||
arch:
|
||||
- amd64
|
||||
- ppc64le
|
||||
|
||||
go:
|
||||
- 1.7.x
|
||||
- 1.14.x
|
||||
- 1.15.x
|
||||
- 1.16.x
|
||||
- 1.17.x
|
||||
- tip
|
||||
|
||||
install:
|
||||
- go build .
|
||||
|
||||
script:
|
||||
- go test -v
|
|
@ -1,3 +1,30 @@
|
|||
## Decimal v1.4.0
|
||||
#### BREAKING
|
||||
- Drop support for Go version older than 1.10 [#361](https://github.com/shopspring/decimal/pull/361)
|
||||
|
||||
#### FEATURES
|
||||
- Add implementation of natural logarithm [#339](https://github.com/shopspring/decimal/pull/339) [#357](https://github.com/shopspring/decimal/pull/357)
|
||||
- Add improved implementation of power operation [#358](https://github.com/shopspring/decimal/pull/358)
|
||||
- Add Compare method which forwards calls to Cmp [#346](https://github.com/shopspring/decimal/pull/346)
|
||||
- Add NewFromBigRat constructor [#288](https://github.com/shopspring/decimal/pull/288)
|
||||
- Add NewFromUint64 constructor [#352](https://github.com/shopspring/decimal/pull/352)
|
||||
|
||||
#### ENHANCEMENTS
|
||||
- Migrate to Github Actions [#245](https://github.com/shopspring/decimal/pull/245) [#340](https://github.com/shopspring/decimal/pull/340)
|
||||
- Fix examples for RoundDown, RoundFloor, RoundUp, and RoundCeil [#285](https://github.com/shopspring/decimal/pull/285) [#328](https://github.com/shopspring/decimal/pull/328) [#341](https://github.com/shopspring/decimal/pull/341)
|
||||
- Use Godoc standard to mark deprecated Equals and StringScaled methods [#342](https://github.com/shopspring/decimal/pull/342)
|
||||
- Removed unnecessary min function for RescalePair method [#265](https://github.com/shopspring/decimal/pull/265)
|
||||
- Avoid reallocation of initial slice in MarshalBinary (GobEncode) [#355](https://github.com/shopspring/decimal/pull/355)
|
||||
- Optimize NumDigits method [#301](https://github.com/shopspring/decimal/pull/301) [#356](https://github.com/shopspring/decimal/pull/356)
|
||||
- Optimize BigInt method [#359](https://github.com/shopspring/decimal/pull/359)
|
||||
- Support scanning uint64 [#131](https://github.com/shopspring/decimal/pull/131) [#364](https://github.com/shopspring/decimal/pull/364)
|
||||
- Add docs section with alternative libraries [#363](https://github.com/shopspring/decimal/pull/363)
|
||||
|
||||
#### BUGFIXES
|
||||
- Fix incorrect calculation of decimal modulo [#258](https://github.com/shopspring/decimal/pull/258) [#317](https://github.com/shopspring/decimal/pull/317)
|
||||
- Allocate new(big.Int) in Copy method to deeply clone it [#278](https://github.com/shopspring/decimal/pull/278)
|
||||
- Fix overflow edge case in QuoRem method [#322](https://github.com/shopspring/decimal/pull/322)
|
||||
|
||||
## Decimal v1.3.1
|
||||
|
||||
#### ENHANCEMENTS
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
# decimal
|
||||
|
||||
[](https://app.travis-ci.com/shopspring/decimal) [](https://godoc.org/github.com/shopspring/decimal) [](https://goreportcard.com/report/github.com/shopspring/decimal)
|
||||
[](https://github.com/shopspring/decimal/actions/workflows/ci.yml)
|
||||
[](https://godoc.org/github.com/shopspring/decimal)
|
||||
[](https://goreportcard.com/report/github.com/shopspring/decimal)
|
||||
|
||||
Arbitrary-precision fixed-point decimal numbers in go.
|
||||
|
||||
|
@ -20,7 +22,12 @@ Run `go get github.com/shopspring/decimal`
|
|||
|
||||
## Requirements
|
||||
|
||||
Decimal library requires Go version `>=1.7`
|
||||
Decimal library requires Go version `>=1.10`
|
||||
|
||||
## Documentation
|
||||
|
||||
http://godoc.org/github.com/shopspring/decimal
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
|
@ -57,14 +64,16 @@ func main() {
|
|||
}
|
||||
```
|
||||
|
||||
## Documentation
|
||||
## Alternative libraries
|
||||
|
||||
http://godoc.org/github.com/shopspring/decimal
|
||||
When working with decimal numbers, you might face problems this library is not perfectly suited for.
|
||||
Fortunately, thanks to the wonderful community we have a dozen other libraries that you can choose from.
|
||||
Explore other alternatives to find the one that best fits your needs :)
|
||||
|
||||
## Production Usage
|
||||
|
||||
* [Spring](https://shopspring.com/), since August 14, 2014.
|
||||
* If you are using this in production, please let us know!
|
||||
* [cockroachdb/apd](https://github.com/cockroachdb/apd) - arbitrary precision, mutable and rich API similar to `big.Int`, more performant than this library
|
||||
* [alpacahq/alpacadecimal](https://github.com/alpacahq/alpacadecimal) - high performance, low precision (12 digits), fully compatible API with this library
|
||||
* [govalues/decimal](https://github.com/govalues/decimal) - high performance, zero-allocation, low precision (19 digits)
|
||||
* [greatcloak/decimal](https://github.com/greatcloak/decimal) - fork focusing on billing and e-commerce web application related use cases, includes out-of-the-box BSON marshaling support
|
||||
|
||||
## FAQ
|
||||
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
package decimal
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
strLn10 = "2.302585092994045684017991454684364207601101488628772976033327900967572609677352480235997205089598298341967784042286248633409525465082806756666287369098781689482907208325554680843799894826233198528393505308965377732628846163366222287698219886746543667474404243274365155048934314939391479619404400222105101714174800368808401264708068556774321622835522011480466371565912137345074785694768346361679210180644507064800027750268491674655058685693567342067058113642922455440575892572420824131469568901675894025677631135691929203337658714166023010570308963457207544037084746994016826928280848118428931484852494864487192780967627127577539702766860595249671667418348570442250719796500471495105049221477656763693866297697952211071826454973477266242570942932258279850258550978526538320760672631716430950599508780752371033310119785754733154142180842754386359177811705430982748238504564801909561029929182431823752535770975053956518769751037497088869218020518933950723853920514463419726528728696511086257149219884997874887377134568620916705849807828059751193854445009978131146915934666241071846692310107598438319191292230792503747298650929009880391941702654416816335727555703151596113564846546190897042819763365836983716328982174407366009162177850541779276367731145041782137660111010731042397832521894898817597921798666394319523936855916447118246753245630912528778330963604262982153040874560927760726641354787576616262926568298704957954913954918049209069438580790032763017941503117866862092408537949861264933479354871737451675809537088281067452440105892444976479686075120275724181874989395971643105518848195288330746699317814634930000321200327765654130472621883970596794457943468343218395304414844803701305753674262153675579814770458031413637793236291560128185336498466942261465206459942072917119370602444929358037007718981097362533224548366988505528285966192805098447175198503666680874970496982273220244823343097169111136813588418696549323714996941979687803008850408979618598756579894836445212043698216415292987811742973332588607915912510967187510929248475023930572665446276200923068791518135803477701295593646298412366497023355174586195564772461857717369368404676577047874319780573853271810933883496338813069945569399346101090745616033312247949360455361849123333063704751724871276379140924398331810164737823379692265637682071706935846394531616949411701841938119405416449466111274712819705817783293841742231409930022911502362192186723337268385688273533371925103412930705632544426611429765388301822384091026198582888433587455960453004548370789052578473166283701953392231047527564998119228742789713715713228319641003422124210082180679525276689858180956119208391760721080919923461516952599099473782780648128058792731993893453415320185969711021407542282796298237068941764740642225757212455392526179373652434440560595336591539160312524480149313234572453879524389036839236450507881731359711238145323701508413491122324390927681724749607955799151363982881058285740538000653371655553014196332241918087621018204919492651483892"
|
||||
)
|
||||
|
||||
var (
|
||||
ln10 = newConstApproximation(strLn10)
|
||||
)
|
||||
|
||||
type constApproximation struct {
|
||||
exact Decimal
|
||||
approximations []Decimal
|
||||
}
|
||||
|
||||
func newConstApproximation(value string) constApproximation {
|
||||
parts := strings.Split(value, ".")
|
||||
coeff, fractional := parts[0], parts[1]
|
||||
|
||||
coeffLen := len(coeff)
|
||||
maxPrecision := len(fractional)
|
||||
|
||||
var approximations []Decimal
|
||||
for p := 1; p < maxPrecision; p *= 2 {
|
||||
r := RequireFromString(value[:coeffLen+p])
|
||||
approximations = append(approximations, r)
|
||||
}
|
||||
|
||||
return constApproximation{
|
||||
RequireFromString(value),
|
||||
approximations,
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the smallest approximation available that's at least as precise
|
||||
// as the passed precision (places after decimal point), i.e. Floor[ log2(precision) ] + 1
|
||||
func (c constApproximation) withPrecision(precision int32) Decimal {
|
||||
i := 0
|
||||
|
||||
if precision >= 1 {
|
||||
i++
|
||||
}
|
||||
|
||||
for precision >= 16 {
|
||||
precision /= 16
|
||||
i += 4
|
||||
}
|
||||
|
||||
for precision >= 2 {
|
||||
precision /= 2
|
||||
i++
|
||||
}
|
||||
|
||||
if i >= len(c.approximations) {
|
||||
return c.exact
|
||||
}
|
||||
|
||||
return c.approximations[i]
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -18,6 +18,14 @@ import (
|
|||
|
||||
var errNegativeNotAllowed = errors.New("unable to cast negative value")
|
||||
|
||||
type float64EProvider interface {
|
||||
Float64() (float64, error)
|
||||
}
|
||||
|
||||
type float64Provider interface {
|
||||
Float64() float64
|
||||
}
|
||||
|
||||
// ToTimeE casts an interface to a time.Time type.
|
||||
func ToTimeE(i interface{}) (tim time.Time, err error) {
|
||||
return ToTimeInDefaultLocationE(i, time.UTC)
|
||||
|
@ -77,11 +85,14 @@ func ToDurationE(i interface{}) (d time.Duration, err error) {
|
|||
d, err = time.ParseDuration(s + "ns")
|
||||
}
|
||||
return
|
||||
case json.Number:
|
||||
case float64EProvider:
|
||||
var v float64
|
||||
v, err = s.Float64()
|
||||
d = time.Duration(v)
|
||||
return
|
||||
case float64Provider:
|
||||
d = time.Duration(s.Float64())
|
||||
return
|
||||
default:
|
||||
err = fmt.Errorf("unable to cast %#v of type %T to Duration", i, i)
|
||||
return
|
||||
|
@ -174,12 +185,14 @@ func ToFloat64E(i interface{}) (float64, error) {
|
|||
return v, nil
|
||||
}
|
||||
return 0, fmt.Errorf("unable to cast %#v of type %T to float64", i, i)
|
||||
case json.Number:
|
||||
case float64EProvider:
|
||||
v, err := s.Float64()
|
||||
if err == nil {
|
||||
return v, nil
|
||||
}
|
||||
return 0, fmt.Errorf("unable to cast %#v of type %T to float64", i, i)
|
||||
case float64Provider:
|
||||
return s.Float64(), nil
|
||||
case bool:
|
||||
if s {
|
||||
return 1, nil
|
||||
|
@ -230,12 +243,14 @@ func ToFloat32E(i interface{}) (float32, error) {
|
|||
return float32(v), nil
|
||||
}
|
||||
return 0, fmt.Errorf("unable to cast %#v of type %T to float32", i, i)
|
||||
case json.Number:
|
||||
case float64EProvider:
|
||||
v, err := s.Float64()
|
||||
if err == nil {
|
||||
return float32(v), nil
|
||||
}
|
||||
return 0, fmt.Errorf("unable to cast %#v of type %T to float32", i, i)
|
||||
case float64Provider:
|
||||
return float32(s.Float64()), nil
|
||||
case bool:
|
||||
if s {
|
||||
return 1, nil
|
||||
|
@ -917,8 +932,8 @@ func indirectToStringerOrError(a interface{}) interface{} {
|
|||
return nil
|
||||
}
|
||||
|
||||
var errorType = reflect.TypeOf((*error)(nil)).Elem()
|
||||
var fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
|
||||
errorType := reflect.TypeOf((*error)(nil)).Elem()
|
||||
fmtStringerType := reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
|
||||
|
||||
v := reflect.ValueOf(a)
|
||||
for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() {
|
||||
|
@ -987,7 +1002,7 @@ func ToStringE(i interface{}) (string, error) {
|
|||
|
||||
// ToStringMapStringE casts an interface to a map[string]string type.
|
||||
func ToStringMapStringE(i interface{}) (map[string]string, error) {
|
||||
var m = map[string]string{}
|
||||
m := map[string]string{}
|
||||
|
||||
switch v := i.(type) {
|
||||
case map[string]string:
|
||||
|
@ -1017,7 +1032,7 @@ func ToStringMapStringE(i interface{}) (map[string]string, error) {
|
|||
|
||||
// ToStringMapStringSliceE casts an interface to a map[string][]string type.
|
||||
func ToStringMapStringSliceE(i interface{}) (map[string][]string, error) {
|
||||
var m = map[string][]string{}
|
||||
m := map[string][]string{}
|
||||
|
||||
switch v := i.(type) {
|
||||
case map[string][]string:
|
||||
|
@ -1081,7 +1096,7 @@ func ToStringMapStringSliceE(i interface{}) (map[string][]string, error) {
|
|||
|
||||
// ToStringMapBoolE casts an interface to a map[string]bool type.
|
||||
func ToStringMapBoolE(i interface{}) (map[string]bool, error) {
|
||||
var m = map[string]bool{}
|
||||
m := map[string]bool{}
|
||||
|
||||
switch v := i.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
|
@ -1106,7 +1121,7 @@ func ToStringMapBoolE(i interface{}) (map[string]bool, error) {
|
|||
|
||||
// ToStringMapE casts an interface to a map[string]interface{} type.
|
||||
func ToStringMapE(i interface{}) (map[string]interface{}, error) {
|
||||
var m = map[string]interface{}{}
|
||||
m := map[string]interface{}{}
|
||||
|
||||
switch v := i.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
|
@ -1126,7 +1141,7 @@ func ToStringMapE(i interface{}) (map[string]interface{}, error) {
|
|||
|
||||
// ToStringMapIntE casts an interface to a map[string]int{} type.
|
||||
func ToStringMapIntE(i interface{}) (map[string]int, error) {
|
||||
var m = map[string]int{}
|
||||
m := map[string]int{}
|
||||
if i == nil {
|
||||
return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int", i, i)
|
||||
}
|
||||
|
@ -1167,7 +1182,7 @@ func ToStringMapIntE(i interface{}) (map[string]int, error) {
|
|||
|
||||
// ToStringMapInt64E casts an interface to a map[string]int64{} type.
|
||||
func ToStringMapInt64E(i interface{}) (map[string]int64, error) {
|
||||
var m = map[string]int64{}
|
||||
m := map[string]int64{}
|
||||
if i == nil {
|
||||
return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int64", i, i)
|
||||
}
|
||||
|
@ -1404,38 +1419,35 @@ func (f timeFormat) hasTimezone() bool {
|
|||
return f.typ >= timeFormatNumericTimezone && f.typ <= timeFormatNumericAndNamedTimezone
|
||||
}
|
||||
|
||||
var (
|
||||
timeFormats = []timeFormat{
|
||||
// Keep common formats at the top.
|
||||
{"2006-01-02", timeFormatNoTimezone},
|
||||
{time.RFC3339, timeFormatNumericTimezone},
|
||||
{"2006-01-02T15:04:05", timeFormatNoTimezone}, // iso8601 without timezone
|
||||
{time.RFC1123Z, timeFormatNumericTimezone},
|
||||
{time.RFC1123, timeFormatNamedTimezone},
|
||||
{time.RFC822Z, timeFormatNumericTimezone},
|
||||
{time.RFC822, timeFormatNamedTimezone},
|
||||
{time.RFC850, timeFormatNamedTimezone},
|
||||
{"2006-01-02 15:04:05.999999999 -0700 MST", timeFormatNumericAndNamedTimezone}, // Time.String()
|
||||
{"2006-01-02T15:04:05-0700", timeFormatNumericTimezone}, // RFC3339 without timezone hh:mm colon
|
||||
{"2006-01-02 15:04:05Z0700", timeFormatNumericTimezone}, // RFC3339 without T or timezone hh:mm colon
|
||||
{"2006-01-02 15:04:05", timeFormatNoTimezone},
|
||||
{time.ANSIC, timeFormatNoTimezone},
|
||||
{time.UnixDate, timeFormatNamedTimezone},
|
||||
{time.RubyDate, timeFormatNumericTimezone},
|
||||
{"2006-01-02 15:04:05Z07:00", timeFormatNumericTimezone},
|
||||
{"02 Jan 2006", timeFormatNoTimezone},
|
||||
{"2006-01-02 15:04:05 -07:00", timeFormatNumericTimezone},
|
||||
{"2006-01-02 15:04:05 -0700", timeFormatNumericTimezone},
|
||||
{time.Kitchen, timeFormatTimeOnly},
|
||||
{time.Stamp, timeFormatTimeOnly},
|
||||
{time.StampMilli, timeFormatTimeOnly},
|
||||
{time.StampMicro, timeFormatTimeOnly},
|
||||
{time.StampNano, timeFormatTimeOnly},
|
||||
}
|
||||
)
|
||||
var timeFormats = []timeFormat{
|
||||
// Keep common formats at the top.
|
||||
{"2006-01-02", timeFormatNoTimezone},
|
||||
{time.RFC3339, timeFormatNumericTimezone},
|
||||
{"2006-01-02T15:04:05", timeFormatNoTimezone}, // iso8601 without timezone
|
||||
{time.RFC1123Z, timeFormatNumericTimezone},
|
||||
{time.RFC1123, timeFormatNamedTimezone},
|
||||
{time.RFC822Z, timeFormatNumericTimezone},
|
||||
{time.RFC822, timeFormatNamedTimezone},
|
||||
{time.RFC850, timeFormatNamedTimezone},
|
||||
{"2006-01-02 15:04:05.999999999 -0700 MST", timeFormatNumericAndNamedTimezone}, // Time.String()
|
||||
{"2006-01-02T15:04:05-0700", timeFormatNumericTimezone}, // RFC3339 without timezone hh:mm colon
|
||||
{"2006-01-02 15:04:05Z0700", timeFormatNumericTimezone}, // RFC3339 without T or timezone hh:mm colon
|
||||
{"2006-01-02 15:04:05", timeFormatNoTimezone},
|
||||
{time.ANSIC, timeFormatNoTimezone},
|
||||
{time.UnixDate, timeFormatNamedTimezone},
|
||||
{time.RubyDate, timeFormatNumericTimezone},
|
||||
{"2006-01-02 15:04:05Z07:00", timeFormatNumericTimezone},
|
||||
{"02 Jan 2006", timeFormatNoTimezone},
|
||||
{"2006-01-02 15:04:05 -07:00", timeFormatNumericTimezone},
|
||||
{"2006-01-02 15:04:05 -0700", timeFormatNumericTimezone},
|
||||
{time.Kitchen, timeFormatTimeOnly},
|
||||
{time.Stamp, timeFormatTimeOnly},
|
||||
{time.StampMilli, timeFormatTimeOnly},
|
||||
{time.StampMicro, timeFormatTimeOnly},
|
||||
{time.StampNano, timeFormatTimeOnly},
|
||||
}
|
||||
|
||||
func parseDateWith(s string, location *time.Location, formats []timeFormat) (d time.Time, e error) {
|
||||
|
||||
for _, format := range formats {
|
||||
if d, e = time.Parse(format.format, s); e == nil {
|
||||
|
||||
|
|
|
@ -2540,7 +2540,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"revision": "20240730",
|
||||
"revision": "20240806",
|
||||
"rootUrl": "https://container.googleapis.com/",
|
||||
"schemas": {
|
||||
"AcceleratorConfig": {
|
||||
|
@ -3369,6 +3369,10 @@
|
|||
"$ref": "PrivateClusterConfig",
|
||||
"description": "Configuration for private cluster."
|
||||
},
|
||||
"rbacBindingConfig": {
|
||||
"$ref": "RBACBindingConfig",
|
||||
"description": "RBACBindingConfig allows user to restrict ClusterRoleBindings an RoleBindings that can be created."
|
||||
},
|
||||
"releaseChannel": {
|
||||
"$ref": "ReleaseChannel",
|
||||
"description": "Release channel configuration. If left unspecified on cluster creation and a version is specified, the cluster is enrolled in the most mature release channel where the version is available (first checking STABLE, then REGULAR, and finally RAPID). Otherwise, if no release channel configuration and no version is specified, the cluster is enrolled in the REGULAR channel with its default version."
|
||||
|
@ -3756,6 +3760,10 @@
|
|||
],
|
||||
"type": "string"
|
||||
},
|
||||
"desiredRbacBindingConfig": {
|
||||
"$ref": "RBACBindingConfig",
|
||||
"description": "RBACBindingConfig allows user to restrict ClusterRoleBindings an RoleBindings that can be created."
|
||||
},
|
||||
"desiredReleaseChannel": {
|
||||
"$ref": "ReleaseChannel",
|
||||
"description": "The desired release channel configuration."
|
||||
|
@ -4960,7 +4968,7 @@
|
|||
"id": "MasterAuth",
|
||||
"properties": {
|
||||
"clientCertificate": {
|
||||
"description": "Output only. Base64-encoded public certificate used by clients to authenticate to the cluster endpoint.",
|
||||
"description": "Output only. Base64-encoded public certificate used by clients to authenticate to the cluster endpoint. Issued only if client_certificate_config is set.",
|
||||
"readOnly": true,
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -6316,6 +6324,21 @@
|
|||
},
|
||||
"type": "object"
|
||||
},
|
||||
"RBACBindingConfig": {
|
||||
"description": "RBACBindingConfig allows user to restrict ClusterRoleBindings an RoleBindings that can be created.",
|
||||
"id": "RBACBindingConfig",
|
||||
"properties": {
|
||||
"enableInsecureBindingSystemAuthenticated": {
|
||||
"description": "Setting this to true will allow any ClusterRoleBinding and RoleBinding with subjects system:authenticated.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"enableInsecureBindingSystemUnauthenticated": {
|
||||
"description": "Setting this to true will allow any ClusterRoleBinding and RoleBinding with subjets system:anonymous or system:unauthenticated.",
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"RangeInfo": {
|
||||
"description": "RangeInfo contains the range name and the range utilization by this cluster.",
|
||||
"id": "RangeInfo",
|
||||
|
|
|
@ -1260,6 +1260,9 @@ type Cluster struct {
|
|||
ParentProductConfig *ParentProductConfig `json:"parentProductConfig,omitempty"`
|
||||
// PrivateClusterConfig: Configuration for private cluster.
|
||||
PrivateClusterConfig *PrivateClusterConfig `json:"privateClusterConfig,omitempty"`
|
||||
// RbacBindingConfig: RBACBindingConfig allows user to restrict
|
||||
// ClusterRoleBindings an RoleBindings that can be created.
|
||||
RbacBindingConfig *RBACBindingConfig `json:"rbacBindingConfig,omitempty"`
|
||||
// ReleaseChannel: Release channel configuration. If left unspecified on
|
||||
// cluster creation and a version is specified, the cluster is enrolled in the
|
||||
// most mature release channel where the version is available (first checking
|
||||
|
@ -1608,6 +1611,9 @@ type ClusterUpdate struct {
|
|||
// "PRIVATE_IPV6_GOOGLE_ACCESS_BIDIRECTIONAL" - Enables private IPv6 access
|
||||
// to and from Google Services
|
||||
DesiredPrivateIpv6GoogleAccess string `json:"desiredPrivateIpv6GoogleAccess,omitempty"`
|
||||
// DesiredRbacBindingConfig: RBACBindingConfig allows user to restrict
|
||||
// ClusterRoleBindings an RoleBindings that can be created.
|
||||
DesiredRbacBindingConfig *RBACBindingConfig `json:"desiredRbacBindingConfig,omitempty"`
|
||||
// DesiredReleaseChannel: The desired release channel configuration.
|
||||
DesiredReleaseChannel *ReleaseChannel `json:"desiredReleaseChannel,omitempty"`
|
||||
// DesiredResourceUsageExportConfig: The desired configuration for exporting
|
||||
|
@ -3358,7 +3364,8 @@ func (s ManagedPrometheusConfig) MarshalJSON() ([]byte, error) {
|
|||
// certificates.
|
||||
type MasterAuth struct {
|
||||
// ClientCertificate: Output only. Base64-encoded public certificate used by
|
||||
// clients to authenticate to the cluster endpoint.
|
||||
// clients to authenticate to the cluster endpoint. Issued only if
|
||||
// client_certificate_config is set.
|
||||
ClientCertificate string `json:"clientCertificate,omitempty"`
|
||||
// ClientCertificateConfig: Configuration for client certificate authentication
|
||||
// on the cluster. For clusters before v1.12, if no configuration is specified,
|
||||
|
@ -5010,6 +5017,36 @@ func (s QueuedProvisioning) MarshalJSON() ([]byte, error) {
|
|||
return gensupport.MarshalJSON(NoMethod(s), s.ForceSendFields, s.NullFields)
|
||||
}
|
||||
|
||||
// RBACBindingConfig: RBACBindingConfig allows user to restrict
|
||||
// ClusterRoleBindings an RoleBindings that can be created.
|
||||
type RBACBindingConfig struct {
|
||||
// EnableInsecureBindingSystemAuthenticated: Setting this to true will allow
|
||||
// any ClusterRoleBinding and RoleBinding with subjects system:authenticated.
|
||||
EnableInsecureBindingSystemAuthenticated bool `json:"enableInsecureBindingSystemAuthenticated,omitempty"`
|
||||
// EnableInsecureBindingSystemUnauthenticated: Setting this to true will allow
|
||||
// any ClusterRoleBinding and RoleBinding with subjets system:anonymous or
|
||||
// system:unauthenticated.
|
||||
EnableInsecureBindingSystemUnauthenticated bool `json:"enableInsecureBindingSystemUnauthenticated,omitempty"`
|
||||
// ForceSendFields is a list of field names (e.g.
|
||||
// "EnableInsecureBindingSystemAuthenticated") to unconditionally include in
|
||||
// API requests. By default, fields with empty or default values are omitted
|
||||
// from API requests. See
|
||||
// https://pkg.go.dev/google.golang.org/api#hdr-ForceSendFields for more
|
||||
// details.
|
||||
ForceSendFields []string `json:"-"`
|
||||
// NullFields is a list of field names (e.g.
|
||||
// "EnableInsecureBindingSystemAuthenticated") to include in API requests with
|
||||
// the JSON null value. By default, fields with empty values are omitted from
|
||||
// API requests. See https://pkg.go.dev/google.golang.org/api#hdr-NullFields
|
||||
// for more details.
|
||||
NullFields []string `json:"-"`
|
||||
}
|
||||
|
||||
func (s RBACBindingConfig) MarshalJSON() ([]byte, error) {
|
||||
type NoMethod RBACBindingConfig
|
||||
return gensupport.MarshalJSON(NoMethod(s), s.ForceSendFields, s.NullFields)
|
||||
}
|
||||
|
||||
// RangeInfo: RangeInfo contains the range name and the range utilization by
|
||||
// this cluster.
|
||||
type RangeInfo struct {
|
||||
|
|
|
@ -5,4 +5,4 @@
|
|||
package internal
|
||||
|
||||
// Version is the current tagged release of the library.
|
||||
const Version = "0.194.0"
|
||||
const Version = "0.195.0"
|
||||
|
|
|
@ -2408,7 +2408,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"revision": "20240721",
|
||||
"revision": "20240818",
|
||||
"rootUrl": "https://networkservices.googleapis.com/",
|
||||
"schemas": {
|
||||
"AuditConfig": {
|
||||
|
@ -2814,6 +2814,18 @@
|
|||
},
|
||||
"type": "array"
|
||||
},
|
||||
"routingMode": {
|
||||
"description": "Optional. The routing mode of the Gateway. This field is configurable only for gateways of type SECURE_WEB_GATEWAY. This field is required for gateways of type SECURE_WEB_GATEWAY.",
|
||||
"enum": [
|
||||
"EXPLICIT_ROUTING_MODE",
|
||||
"NEXT_HOP_ROUTING_MODE"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"The routing mode is explicit; clients are configured to send traffic through the gateway. This is the default routing mode.",
|
||||
"The routing mode is next-hop. Clients are unaware of the gateway, and a route (advanced route or other route type) can be configured to direct traffic from client to gateway. The gateway then acts as a next-hop to the destination."
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"scope": {
|
||||
"description": "Optional. Scope determines how configuration across multiple Gateway instances are merged. The configuration for multiple Gateway instances with the same scope will be merged as presented as a single coniguration to the proxy/load balancer. Max length 64 characters. Scope should start with a letter and can only have letters, numbers, hyphens.",
|
||||
"type": "string"
|
||||
|
@ -3049,7 +3061,7 @@
|
|||
"type": "object"
|
||||
},
|
||||
"GrpcRouteRetryPolicy": {
|
||||
"description": "The specifications for retries.",
|
||||
"description": "The specifications for retries. Specifies one or more conditions for which this retry rule applies. Valid values are:",
|
||||
"id": "GrpcRouteRetryPolicy",
|
||||
"properties": {
|
||||
"numRetries": {
|
||||
|
|
|
@ -967,6 +967,19 @@ type Gateway struct {
|
|||
// 'OPEN_MESH' listen on 0.0.0.0 for IPv4 and :: for IPv6 and support multiple
|
||||
// ports.
|
||||
Ports []int64 `json:"ports,omitempty"`
|
||||
// RoutingMode: Optional. The routing mode of the Gateway. This field is
|
||||
// configurable only for gateways of type SECURE_WEB_GATEWAY. This field is
|
||||
// required for gateways of type SECURE_WEB_GATEWAY.
|
||||
//
|
||||
// Possible values:
|
||||
// "EXPLICIT_ROUTING_MODE" - The routing mode is explicit; clients are
|
||||
// configured to send traffic through the gateway. This is the default routing
|
||||
// mode.
|
||||
// "NEXT_HOP_ROUTING_MODE" - The routing mode is next-hop. Clients are
|
||||
// unaware of the gateway, and a route (advanced route or other route type) can
|
||||
// be configured to direct traffic from client to gateway. The gateway then
|
||||
// acts as a next-hop to the destination.
|
||||
RoutingMode string `json:"routingMode,omitempty"`
|
||||
// Scope: Optional. Scope determines how configuration across multiple Gateway
|
||||
// instances are merged. The configuration for multiple Gateway instances with
|
||||
// the same scope will be merged as presented as a single coniguration to the
|
||||
|
@ -1278,7 +1291,8 @@ func (s GrpcRouteMethodMatch) MarshalJSON() ([]byte, error) {
|
|||
return gensupport.MarshalJSON(NoMethod(s), s.ForceSendFields, s.NullFields)
|
||||
}
|
||||
|
||||
// GrpcRouteRetryPolicy: The specifications for retries.
|
||||
// GrpcRouteRetryPolicy: The specifications for retries. Specifies one or more
|
||||
// conditions for which this retry rule applies. Valid values are:
|
||||
type GrpcRouteRetryPolicy struct {
|
||||
// NumRetries: Specifies the allowed number of retries. This number must be >
|
||||
// 0. If not specified, default to 1.
|
||||
|
|
|
@ -2317,7 +2317,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"revision": "20240721",
|
||||
"revision": "20240818",
|
||||
"rootUrl": "https://networkservices.googleapis.com/",
|
||||
"schemas": {
|
||||
"AuditConfig": {
|
||||
|
@ -2772,6 +2772,18 @@
|
|||
},
|
||||
"type": "array"
|
||||
},
|
||||
"routingMode": {
|
||||
"description": "Optional. The routing mode of the Gateway. This field is configurable only for gateways of type SECURE_WEB_GATEWAY. This field is required for gateways of type SECURE_WEB_GATEWAY.",
|
||||
"enum": [
|
||||
"EXPLICIT_ROUTING_MODE",
|
||||
"NEXT_HOP_ROUTING_MODE"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"The routing mode is explicit; clients are configured to send traffic through the gateway. This is the default routing mode.",
|
||||
"The routing mode is next-hop. Clients are unaware of the gateway, and a route (advanced route or other route type) can be configured to direct traffic from client to gateway. The gateway then acts as a next-hop to the destination."
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"scope": {
|
||||
"description": "Optional. Scope determines how configuration across multiple Gateway instances are merged. The configuration for multiple Gateway instances with the same scope will be merged as presented as a single coniguration to the proxy/load balancer. Max length 64 characters. Scope should start with a letter and can only have letters, numbers, hyphens.",
|
||||
"type": "string"
|
||||
|
@ -3007,7 +3019,7 @@
|
|||
"type": "object"
|
||||
},
|
||||
"GrpcRouteRetryPolicy": {
|
||||
"description": "The specifications for retries.",
|
||||
"description": "The specifications for retries. Specifies one or more conditions for which this retry rule applies. Valid values are:",
|
||||
"id": "GrpcRouteRetryPolicy",
|
||||
"properties": {
|
||||
"numRetries": {
|
||||
|
|
|
@ -967,6 +967,19 @@ type Gateway struct {
|
|||
// 'OPEN_MESH' listen on 0.0.0.0 for IPv4 and :: for IPv6 and support multiple
|
||||
// ports.
|
||||
Ports []int64 `json:"ports,omitempty"`
|
||||
// RoutingMode: Optional. The routing mode of the Gateway. This field is
|
||||
// configurable only for gateways of type SECURE_WEB_GATEWAY. This field is
|
||||
// required for gateways of type SECURE_WEB_GATEWAY.
|
||||
//
|
||||
// Possible values:
|
||||
// "EXPLICIT_ROUTING_MODE" - The routing mode is explicit; clients are
|
||||
// configured to send traffic through the gateway. This is the default routing
|
||||
// mode.
|
||||
// "NEXT_HOP_ROUTING_MODE" - The routing mode is next-hop. Clients are
|
||||
// unaware of the gateway, and a route (advanced route or other route type) can
|
||||
// be configured to direct traffic from client to gateway. The gateway then
|
||||
// acts as a next-hop to the destination.
|
||||
RoutingMode string `json:"routingMode,omitempty"`
|
||||
// Scope: Optional. Scope determines how configuration across multiple Gateway
|
||||
// instances are merged. The configuration for multiple Gateway instances with
|
||||
// the same scope will be merged as presented as a single coniguration to the
|
||||
|
@ -1278,7 +1291,8 @@ func (s GrpcRouteMethodMatch) MarshalJSON() ([]byte, error) {
|
|||
return gensupport.MarshalJSON(NoMethod(s), s.ForceSendFields, s.NullFields)
|
||||
}
|
||||
|
||||
// GrpcRouteRetryPolicy: The specifications for retries.
|
||||
// GrpcRouteRetryPolicy: The specifications for retries. Specifies one or more
|
||||
// conditions for which this retry rule applies. Valid values are:
|
||||
type GrpcRouteRetryPolicy struct {
|
||||
// NumRetries: Specifies the allowed number of retries. This number must be >
|
||||
// 0. If not specified, default to 1.
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
"location": "me-central2"
|
||||
}
|
||||
],
|
||||
"etag": "\"34373939373134303235393739323331393435\"",
|
||||
"etag": "\"38363036373236373330353534313035333932\"",
|
||||
"icons": {
|
||||
"x16": "https://www.google.com/images/icons/product/cloud_storage-16.png",
|
||||
"x32": "https://www.google.com/images/icons/product/cloud_storage-32.png"
|
||||
|
@ -4136,7 +4136,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"revision": "20240809",
|
||||
"revision": "20240819",
|
||||
"rootUrl": "https://storage.googleapis.com/",
|
||||
"schemas": {
|
||||
"AnywhereCache": {
|
||||
|
@ -4349,6 +4349,11 @@
|
|||
"format": "int64",
|
||||
"type": "string"
|
||||
},
|
||||
"hardDeleteTime": {
|
||||
"description": "The hard delete time of the bucket in RFC 3339 format.",
|
||||
"format": "date-time",
|
||||
"type": "string"
|
||||
},
|
||||
"hierarchicalNamespace": {
|
||||
"description": "The bucket's hierarchical namespace configuration.",
|
||||
"properties": {
|
||||
|
@ -4675,6 +4680,11 @@
|
|||
},
|
||||
"type": "object"
|
||||
},
|
||||
"softDeleteTime": {
|
||||
"description": "The soft delete time of the bucket in RFC 3339 format.",
|
||||
"format": "date-time",
|
||||
"type": "string"
|
||||
},
|
||||
"storageClass": {
|
||||
"description": "The bucket's default storage class, used whenever no storageClass is specified for a newly-created object. This defines how objects in the bucket are stored and determines the SLA and the cost of storage. Values include MULTI_REGIONAL, REGIONAL, STANDARD, NEARLINE, COLDLINE, ARCHIVE, and DURABLE_REDUCED_AVAILABILITY. If this value is not specified when the bucket is created, it will default to STANDARD. For more information, see [Storage Classes](https://cloud.google.com/storage/docs/storage-classes).",
|
||||
"type": "string"
|
||||
|
|
|
@ -463,6 +463,8 @@ type Bucket struct {
|
|||
Etag string `json:"etag,omitempty"`
|
||||
// Generation: The generation of this bucket.
|
||||
Generation int64 `json:"generation,omitempty,string"`
|
||||
// HardDeleteTime: The hard delete time of the bucket in RFC 3339 format.
|
||||
HardDeleteTime string `json:"hardDeleteTime,omitempty"`
|
||||
// HierarchicalNamespace: The bucket's hierarchical namespace configuration.
|
||||
HierarchicalNamespace *BucketHierarchicalNamespace `json:"hierarchicalNamespace,omitempty"`
|
||||
// IamConfiguration: The bucket's IAM configuration.
|
||||
|
@ -525,6 +527,8 @@ type Bucket struct {
|
|||
// of time that soft-deleted objects will be retained, and cannot be
|
||||
// permanently deleted.
|
||||
SoftDeletePolicy *BucketSoftDeletePolicy `json:"softDeletePolicy,omitempty"`
|
||||
// SoftDeleteTime: The soft delete time of the bucket in RFC 3339 format.
|
||||
SoftDeleteTime string `json:"softDeleteTime,omitempty"`
|
||||
// StorageClass: The bucket's default storage class, used whenever no
|
||||
// storageClass is specified for a newly-created object. This defines how
|
||||
// objects in the bucket are stored and determines the SLA and the cost of
|
||||
|
|
|
@ -9,21 +9,28 @@ for general contribution guidelines.
|
|||
|
||||
## Maintainers (in alphabetical order)
|
||||
|
||||
- [aranjans](https://github.com/aranjans), Google LLC
|
||||
- [arjan-bal](https://github.com/arjan-bal), Google LLC
|
||||
- [arvindbr8](https://github.com/arvindbr8), Google LLC
|
||||
- [atollena](https://github.com/atollena), Datadog, Inc.
|
||||
- [cesarghali](https://github.com/cesarghali), Google LLC
|
||||
- [dfawley](https://github.com/dfawley), Google LLC
|
||||
- [easwars](https://github.com/easwars), Google LLC
|
||||
- [menghanl](https://github.com/menghanl), Google LLC
|
||||
- [srini100](https://github.com/srini100), Google LLC
|
||||
- [erm-g](https://github.com/erm-g), Google LLC
|
||||
- [gtcooke94](https://github.com/gtcooke94), Google LLC
|
||||
- [purnesh42h](https://github.com/purnesh42h), Google LLC
|
||||
- [zasweq](https://github.com/zasweq), Google LLC
|
||||
|
||||
## Emeritus Maintainers (in alphabetical order)
|
||||
- [adelez](https://github.com/adelez), Google LLC
|
||||
- [canguler](https://github.com/canguler), Google LLC
|
||||
- [iamqizhao](https://github.com/iamqizhao), Google LLC
|
||||
- [jadekler](https://github.com/jadekler), Google LLC
|
||||
- [jtattermusch](https://github.com/jtattermusch), Google LLC
|
||||
- [lyuxuan](https://github.com/lyuxuan), Google LLC
|
||||
- [makmukhi](https://github.com/makmukhi), Google LLC
|
||||
- [matt-kwong](https://github.com/matt-kwong), Google LLC
|
||||
- [nicolasnoble](https://github.com/nicolasnoble), Google LLC
|
||||
- [yongni](https://github.com/yongni), Google LLC
|
||||
- [adelez](https://github.com/adelez)
|
||||
- [canguler](https://github.com/canguler)
|
||||
- [cesarghali](https://github.com/cesarghali)
|
||||
- [iamqizhao](https://github.com/iamqizhao)
|
||||
- [jeanbza](https://github.com/jeanbza)
|
||||
- [jtattermusch](https://github.com/jtattermusch)
|
||||
- [lyuxuan](https://github.com/lyuxuan)
|
||||
- [makmukhi](https://github.com/makmukhi)
|
||||
- [matt-kwong](https://github.com/matt-kwong)
|
||||
- [menghanl](https://github.com/menghanl)
|
||||
- [nicolasnoble](https://github.com/nicolasnoble)
|
||||
- [srini100](https://github.com/srini100)
|
||||
- [yongni](https://github.com/yongni)
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# Security Policy
|
||||
|
||||
For information on gRPC Security Policy and reporting potentional security issues, please see [gRPC CVE Process](https://github.com/grpc/proposal/blob/master/P4-grpc-cve-process.md).
|
||||
For information on gRPC Security Policy and reporting potential security issues, please see [gRPC CVE Process](https://github.com/grpc/proposal/blob/master/P4-grpc-cve-process.md).
|
||||
|
|
|
@ -39,7 +39,7 @@ type Config struct {
|
|||
MaxDelay time.Duration
|
||||
}
|
||||
|
||||
// DefaultConfig is a backoff configuration with the default values specfied
|
||||
// DefaultConfig is a backoff configuration with the default values specified
|
||||
// at https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md.
|
||||
//
|
||||
// This should be useful for callers who want to configure backoff with
|
||||
|
|
|
@ -30,6 +30,7 @@ import (
|
|||
"google.golang.org/grpc/channelz"
|
||||
"google.golang.org/grpc/connectivity"
|
||||
"google.golang.org/grpc/credentials"
|
||||
estats "google.golang.org/grpc/experimental/stats"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
"google.golang.org/grpc/internal"
|
||||
"google.golang.org/grpc/metadata"
|
||||
|
@ -72,8 +73,21 @@ func unregisterForTesting(name string) {
|
|||
delete(m, name)
|
||||
}
|
||||
|
||||
// connectedAddress returns the connected address for a SubConnState. The
|
||||
// address is only valid if the state is READY.
|
||||
func connectedAddress(scs SubConnState) resolver.Address {
|
||||
return scs.connectedAddress
|
||||
}
|
||||
|
||||
// setConnectedAddress sets the connected address for a SubConnState.
|
||||
func setConnectedAddress(scs *SubConnState, addr resolver.Address) {
|
||||
scs.connectedAddress = addr
|
||||
}
|
||||
|
||||
func init() {
|
||||
internal.BalancerUnregister = unregisterForTesting
|
||||
internal.ConnectedAddress = connectedAddress
|
||||
internal.SetConnectedAddress = setConnectedAddress
|
||||
}
|
||||
|
||||
// Get returns the resolver builder registered with the given name.
|
||||
|
@ -243,6 +257,10 @@ type BuildOptions struct {
|
|||
// same resolver.Target as passed to the resolver. See the documentation for
|
||||
// the resolver.Target type for details about what it contains.
|
||||
Target resolver.Target
|
||||
// MetricsRecorder is the metrics recorder that balancers can use to record
|
||||
// metrics. Balancer implementations which do not register metrics on
|
||||
// metrics registry and record on them can ignore this field.
|
||||
MetricsRecorder estats.MetricsRecorder
|
||||
}
|
||||
|
||||
// Builder creates a balancer.
|
||||
|
@ -410,6 +428,9 @@ type SubConnState struct {
|
|||
// ConnectionError is set if the ConnectivityState is TransientFailure,
|
||||
// describing the reason the SubConn failed. Otherwise, it is nil.
|
||||
ConnectionError error
|
||||
// connectedAddr contains the connected address when ConnectivityState is
|
||||
// Ready. Otherwise, it is indeterminate.
|
||||
connectedAddress resolver.Address
|
||||
}
|
||||
|
||||
// ClientConnState describes the state of a ClientConn relevant to the
|
||||
|
|
|
@ -155,7 +155,7 @@ func (b *pickfirstBalancer) UpdateClientConnState(state balancer.ClientConnState
|
|||
// Endpoints not set, process addresses until we migrate resolver
|
||||
// emissions fully to Endpoints. The top channel does wrap emitted
|
||||
// addresses with endpoints, however some balancers such as weighted
|
||||
// target do not forwarrd the corresponding correct endpoints down/split
|
||||
// target do not forward the corresponding correct endpoints down/split
|
||||
// endpoints properly. Once all balancers correctly forward endpoints
|
||||
// down, can delete this else conditional.
|
||||
addrs = state.ResolverState.Addresses
|
||||
|
|
|
@ -25,12 +25,15 @@ import (
|
|||
|
||||
"google.golang.org/grpc/balancer"
|
||||
"google.golang.org/grpc/connectivity"
|
||||
"google.golang.org/grpc/internal"
|
||||
"google.golang.org/grpc/internal/balancer/gracefulswitch"
|
||||
"google.golang.org/grpc/internal/channelz"
|
||||
"google.golang.org/grpc/internal/grpcsync"
|
||||
"google.golang.org/grpc/resolver"
|
||||
)
|
||||
|
||||
var setConnectedAddress = internal.SetConnectedAddress.(func(*balancer.SubConnState, resolver.Address))
|
||||
|
||||
// ccBalancerWrapper sits between the ClientConn and the Balancer.
|
||||
//
|
||||
// ccBalancerWrapper implements methods corresponding to the ones on the
|
||||
|
@ -79,6 +82,7 @@ func newCCBalancerWrapper(cc *ClientConn) *ccBalancerWrapper {
|
|||
CustomUserAgent: cc.dopts.copts.UserAgent,
|
||||
ChannelzParent: cc.channelz,
|
||||
Target: cc.parsedTarget,
|
||||
MetricsRecorder: cc.metricsRecorderList,
|
||||
},
|
||||
serializer: grpcsync.NewCallbackSerializer(ctx),
|
||||
serializerCancel: cancel,
|
||||
|
@ -92,7 +96,7 @@ func newCCBalancerWrapper(cc *ClientConn) *ccBalancerWrapper {
|
|||
// it is safe to call into the balancer here.
|
||||
func (ccb *ccBalancerWrapper) updateClientConnState(ccs *balancer.ClientConnState) error {
|
||||
errCh := make(chan error)
|
||||
ok := ccb.serializer.Schedule(func(ctx context.Context) {
|
||||
uccs := func(ctx context.Context) {
|
||||
defer close(errCh)
|
||||
if ctx.Err() != nil || ccb.balancer == nil {
|
||||
return
|
||||
|
@ -107,17 +111,23 @@ func (ccb *ccBalancerWrapper) updateClientConnState(ccs *balancer.ClientConnStat
|
|||
logger.Infof("error from balancer.UpdateClientConnState: %v", err)
|
||||
}
|
||||
errCh <- err
|
||||
})
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
onFailure := func() { close(errCh) }
|
||||
|
||||
// UpdateClientConnState can race with Close, and when the latter wins, the
|
||||
// serializer is closed, and the attempt to schedule the callback will fail.
|
||||
// It is acceptable to ignore this failure. But since we want to handle the
|
||||
// state update in a blocking fashion (when we successfully schedule the
|
||||
// callback), we have to use the ScheduleOr method and not the MaybeSchedule
|
||||
// method on the serializer.
|
||||
ccb.serializer.ScheduleOr(uccs, onFailure)
|
||||
return <-errCh
|
||||
}
|
||||
|
||||
// resolverError is invoked by grpc to push a resolver error to the underlying
|
||||
// balancer. The call to the balancer is executed from the serializer.
|
||||
func (ccb *ccBalancerWrapper) resolverError(err error) {
|
||||
ccb.serializer.Schedule(func(ctx context.Context) {
|
||||
ccb.serializer.TrySchedule(func(ctx context.Context) {
|
||||
if ctx.Err() != nil || ccb.balancer == nil {
|
||||
return
|
||||
}
|
||||
|
@ -133,7 +143,7 @@ func (ccb *ccBalancerWrapper) close() {
|
|||
ccb.closed = true
|
||||
ccb.mu.Unlock()
|
||||
channelz.Info(logger, ccb.cc.channelz, "ccBalancerWrapper: closing")
|
||||
ccb.serializer.Schedule(func(context.Context) {
|
||||
ccb.serializer.TrySchedule(func(context.Context) {
|
||||
if ccb.balancer == nil {
|
||||
return
|
||||
}
|
||||
|
@ -145,7 +155,7 @@ func (ccb *ccBalancerWrapper) close() {
|
|||
|
||||
// exitIdle invokes the balancer's exitIdle method in the serializer.
|
||||
func (ccb *ccBalancerWrapper) exitIdle() {
|
||||
ccb.serializer.Schedule(func(ctx context.Context) {
|
||||
ccb.serializer.TrySchedule(func(ctx context.Context) {
|
||||
if ctx.Err() != nil || ccb.balancer == nil {
|
||||
return
|
||||
}
|
||||
|
@ -252,15 +262,29 @@ type acBalancerWrapper struct {
|
|||
|
||||
// updateState is invoked by grpc to push a subConn state update to the
|
||||
// underlying balancer.
|
||||
func (acbw *acBalancerWrapper) updateState(s connectivity.State, err error) {
|
||||
acbw.ccb.serializer.Schedule(func(ctx context.Context) {
|
||||
func (acbw *acBalancerWrapper) updateState(s connectivity.State, curAddr resolver.Address, err error) {
|
||||
acbw.ccb.serializer.TrySchedule(func(ctx context.Context) {
|
||||
if ctx.Err() != nil || acbw.ccb.balancer == nil {
|
||||
return
|
||||
}
|
||||
// Even though it is optional for balancers, gracefulswitch ensures
|
||||
// opts.StateListener is set, so this cannot ever be nil.
|
||||
// TODO: delete this comment when UpdateSubConnState is removed.
|
||||
acbw.stateListener(balancer.SubConnState{ConnectivityState: s, ConnectionError: err})
|
||||
scs := balancer.SubConnState{ConnectivityState: s, ConnectionError: err}
|
||||
if s == connectivity.Ready {
|
||||
setConnectedAddress(&scs, curAddr)
|
||||
}
|
||||
acbw.stateListener(scs)
|
||||
acbw.ac.mu.Lock()
|
||||
defer acbw.ac.mu.Unlock()
|
||||
if s == connectivity.Ready {
|
||||
// When changing states to READY, reset stateReadyChan. Wait until
|
||||
// after we notify the LB policy's listener(s) in order to prevent
|
||||
// ac.getTransport() from unblocking before the LB policy starts
|
||||
// tracking the subchannel as READY.
|
||||
close(acbw.ac.stateReadyChan)
|
||||
acbw.ac.stateReadyChan = make(chan struct{})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.34.1
|
||||
// protoc v4.25.2
|
||||
// protoc v5.27.1
|
||||
// source: grpc/binlog/v1/binarylog.proto
|
||||
|
||||
package grpc_binarylog_v1
|
||||
|
|
|
@ -24,6 +24,7 @@ import (
|
|||
"fmt"
|
||||
"math"
|
||||
"net/url"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
@ -39,6 +40,7 @@ import (
|
|||
"google.golang.org/grpc/internal/grpcsync"
|
||||
"google.golang.org/grpc/internal/idle"
|
||||
iresolver "google.golang.org/grpc/internal/resolver"
|
||||
"google.golang.org/grpc/internal/stats"
|
||||
"google.golang.org/grpc/internal/transport"
|
||||
"google.golang.org/grpc/keepalive"
|
||||
"google.golang.org/grpc/resolver"
|
||||
|
@ -194,8 +196,11 @@ func NewClient(target string, opts ...DialOption) (conn *ClientConn, err error)
|
|||
cc.csMgr = newConnectivityStateManager(cc.ctx, cc.channelz)
|
||||
cc.pickerWrapper = newPickerWrapper(cc.dopts.copts.StatsHandlers)
|
||||
|
||||
cc.metricsRecorderList = stats.NewMetricsRecorderList(cc.dopts.copts.StatsHandlers)
|
||||
|
||||
cc.initIdleStateLocked() // Safe to call without the lock, since nothing else has a reference to cc.
|
||||
cc.idlenessMgr = idle.NewManager((*idler)(cc), cc.dopts.idleTimeout)
|
||||
|
||||
return cc, nil
|
||||
}
|
||||
|
||||
|
@ -590,13 +595,14 @@ type ClientConn struct {
|
|||
cancel context.CancelFunc // Cancelled on close.
|
||||
|
||||
// The following are initialized at dial time, and are read-only after that.
|
||||
target string // User's dial target.
|
||||
parsedTarget resolver.Target // See initParsedTargetAndResolverBuilder().
|
||||
authority string // See initAuthority().
|
||||
dopts dialOptions // Default and user specified dial options.
|
||||
channelz *channelz.Channel // Channelz object.
|
||||
resolverBuilder resolver.Builder // See initParsedTargetAndResolverBuilder().
|
||||
idlenessMgr *idle.Manager
|
||||
target string // User's dial target.
|
||||
parsedTarget resolver.Target // See initParsedTargetAndResolverBuilder().
|
||||
authority string // See initAuthority().
|
||||
dopts dialOptions // Default and user specified dial options.
|
||||
channelz *channelz.Channel // Channelz object.
|
||||
resolverBuilder resolver.Builder // See initParsedTargetAndResolverBuilder().
|
||||
idlenessMgr *idle.Manager
|
||||
metricsRecorderList *stats.MetricsRecorderList
|
||||
|
||||
// The following provide their own synchronization, and therefore don't
|
||||
// require cc.mu to be held to access them.
|
||||
|
@ -626,11 +632,6 @@ type ClientConn struct {
|
|||
|
||||
// WaitForStateChange waits until the connectivity.State of ClientConn changes from sourceState or
|
||||
// ctx expires. A true value is returned in former case and false in latter.
|
||||
//
|
||||
// # Experimental
|
||||
//
|
||||
// Notice: This API is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
func (cc *ClientConn) WaitForStateChange(ctx context.Context, sourceState connectivity.State) bool {
|
||||
ch := cc.csMgr.getNotifyChan()
|
||||
if cc.csMgr.getState() != sourceState {
|
||||
|
@ -645,11 +646,6 @@ func (cc *ClientConn) WaitForStateChange(ctx context.Context, sourceState connec
|
|||
}
|
||||
|
||||
// GetState returns the connectivity.State of ClientConn.
|
||||
//
|
||||
// # Experimental
|
||||
//
|
||||
// Notice: This API is EXPERIMENTAL and may be changed or removed in a later
|
||||
// release.
|
||||
func (cc *ClientConn) GetState() connectivity.State {
|
||||
return cc.csMgr.getState()
|
||||
}
|
||||
|
@ -812,17 +808,11 @@ func (cc *ClientConn) applyFailingLBLocked(sc *serviceconfig.ParseResult) {
|
|||
cc.csMgr.updateState(connectivity.TransientFailure)
|
||||
}
|
||||
|
||||
// Makes a copy of the input addresses slice and clears out the balancer
|
||||
// attributes field. Addresses are passed during subconn creation and address
|
||||
// update operations. In both cases, we will clear the balancer attributes by
|
||||
// calling this function, and therefore we will be able to use the Equal method
|
||||
// provided by the resolver.Address type for comparison.
|
||||
func copyAddressesWithoutBalancerAttributes(in []resolver.Address) []resolver.Address {
|
||||
// Makes a copy of the input addresses slice. Addresses are passed during
|
||||
// subconn creation and address update operations.
|
||||
func copyAddresses(in []resolver.Address) []resolver.Address {
|
||||
out := make([]resolver.Address, len(in))
|
||||
for i := range in {
|
||||
out[i] = in[i]
|
||||
out[i].BalancerAttributes = nil
|
||||
}
|
||||
copy(out, in)
|
||||
return out
|
||||
}
|
||||
|
||||
|
@ -835,14 +825,14 @@ func (cc *ClientConn) newAddrConnLocked(addrs []resolver.Address, opts balancer.
|
|||
}
|
||||
|
||||
ac := &addrConn{
|
||||
state: connectivity.Idle,
|
||||
cc: cc,
|
||||
addrs: copyAddressesWithoutBalancerAttributes(addrs),
|
||||
scopts: opts,
|
||||
dopts: cc.dopts,
|
||||
channelz: channelz.RegisterSubChannel(cc.channelz, ""),
|
||||
resetBackoff: make(chan struct{}),
|
||||
stateChan: make(chan struct{}),
|
||||
state: connectivity.Idle,
|
||||
cc: cc,
|
||||
addrs: copyAddresses(addrs),
|
||||
scopts: opts,
|
||||
dopts: cc.dopts,
|
||||
channelz: channelz.RegisterSubChannel(cc.channelz, ""),
|
||||
resetBackoff: make(chan struct{}),
|
||||
stateReadyChan: make(chan struct{}),
|
||||
}
|
||||
ac.ctx, ac.cancel = context.WithCancel(cc.ctx)
|
||||
// Start with our address set to the first address; this may be updated if
|
||||
|
@ -918,28 +908,29 @@ func (ac *addrConn) connect() error {
|
|||
ac.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
ac.mu.Unlock()
|
||||
|
||||
ac.resetTransport()
|
||||
ac.resetTransportAndUnlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func equalAddresses(a, b []resolver.Address) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i, v := range a {
|
||||
if !v.Equal(b[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
// equalAddressIgnoringBalAttributes returns true is a and b are considered equal.
|
||||
// This is different from the Equal method on the resolver.Address type which
|
||||
// considers all fields to determine equality. Here, we only consider fields
|
||||
// that are meaningful to the subConn.
|
||||
func equalAddressIgnoringBalAttributes(a, b *resolver.Address) bool {
|
||||
return a.Addr == b.Addr && a.ServerName == b.ServerName &&
|
||||
a.Attributes.Equal(b.Attributes) &&
|
||||
a.Metadata == b.Metadata
|
||||
}
|
||||
|
||||
func equalAddressesIgnoringBalAttributes(a, b []resolver.Address) bool {
|
||||
return slices.EqualFunc(a, b, func(a, b resolver.Address) bool { return equalAddressIgnoringBalAttributes(&a, &b) })
|
||||
}
|
||||
|
||||
// updateAddrs updates ac.addrs with the new addresses list and handles active
|
||||
// connections or connection attempts.
|
||||
func (ac *addrConn) updateAddrs(addrs []resolver.Address) {
|
||||
addrs = copyAddressesWithoutBalancerAttributes(addrs)
|
||||
addrs = copyAddresses(addrs)
|
||||
limit := len(addrs)
|
||||
if limit > 5 {
|
||||
limit = 5
|
||||
|
@ -947,7 +938,7 @@ func (ac *addrConn) updateAddrs(addrs []resolver.Address) {
|
|||
channelz.Infof(logger, ac.channelz, "addrConn: updateAddrs addrs (%d of %d): %v", limit, len(addrs), addrs[:limit])
|
||||
|
||||
ac.mu.Lock()
|
||||
if equalAddresses(ac.addrs, addrs) {
|
||||
if equalAddressesIgnoringBalAttributes(ac.addrs, addrs) {
|
||||
ac.mu.Unlock()
|
||||
return
|
||||
}
|
||||
|
@ -966,7 +957,7 @@ func (ac *addrConn) updateAddrs(addrs []resolver.Address) {
|
|||
// Try to find the connected address.
|
||||
for _, a := range addrs {
|
||||
a.ServerName = ac.cc.getServerName(a)
|
||||
if a.Equal(ac.curAddr) {
|
||||
if equalAddressIgnoringBalAttributes(&a, &ac.curAddr) {
|
||||
// We are connected to a valid address, so do nothing but
|
||||
// update the addresses.
|
||||
ac.mu.Unlock()
|
||||
|
@ -992,11 +983,9 @@ func (ac *addrConn) updateAddrs(addrs []resolver.Address) {
|
|||
ac.updateConnectivityState(connectivity.Idle, nil)
|
||||
}
|
||||
|
||||
ac.mu.Unlock()
|
||||
|
||||
// Since we were connecting/connected, we should start a new connection
|
||||
// attempt.
|
||||
go ac.resetTransport()
|
||||
go ac.resetTransportAndUnlock()
|
||||
}
|
||||
|
||||
// getServerName determines the serverName to be used in the connection
|
||||
|
@ -1190,8 +1179,8 @@ type addrConn struct {
|
|||
addrs []resolver.Address // All addresses that the resolver resolved to.
|
||||
|
||||
// Use updateConnectivityState for updating addrConn's connectivity state.
|
||||
state connectivity.State
|
||||
stateChan chan struct{} // closed and recreated on every state change.
|
||||
state connectivity.State
|
||||
stateReadyChan chan struct{} // closed and recreated on every READY state change.
|
||||
|
||||
backoffIdx int // Needs to be stateful for resetConnectBackoff.
|
||||
resetBackoff chan struct{}
|
||||
|
@ -1204,9 +1193,6 @@ func (ac *addrConn) updateConnectivityState(s connectivity.State, lastErr error)
|
|||
if ac.state == s {
|
||||
return
|
||||
}
|
||||
// When changing states, reset the state change channel.
|
||||
close(ac.stateChan)
|
||||
ac.stateChan = make(chan struct{})
|
||||
ac.state = s
|
||||
ac.channelz.ChannelMetrics.State.Store(&s)
|
||||
if lastErr == nil {
|
||||
|
@ -1214,7 +1200,7 @@ func (ac *addrConn) updateConnectivityState(s connectivity.State, lastErr error)
|
|||
} else {
|
||||
channelz.Infof(logger, ac.channelz, "Subchannel Connectivity change to %v, last error: %s", s, lastErr)
|
||||
}
|
||||
ac.acbw.updateState(s, lastErr)
|
||||
ac.acbw.updateState(s, ac.curAddr, lastErr)
|
||||
}
|
||||
|
||||
// adjustParams updates parameters used to create transports upon
|
||||
|
@ -1231,8 +1217,10 @@ func (ac *addrConn) adjustParams(r transport.GoAwayReason) {
|
|||
}
|
||||
}
|
||||
|
||||
func (ac *addrConn) resetTransport() {
|
||||
ac.mu.Lock()
|
||||
// resetTransportAndUnlock unconditionally connects the addrConn.
|
||||
//
|
||||
// ac.mu must be held by the caller, and this function will guarantee it is released.
|
||||
func (ac *addrConn) resetTransportAndUnlock() {
|
||||
acCtx := ac.ctx
|
||||
if acCtx.Err() != nil {
|
||||
ac.mu.Unlock()
|
||||
|
@ -1522,7 +1510,7 @@ func (ac *addrConn) getReadyTransport() transport.ClientTransport {
|
|||
func (ac *addrConn) getTransport(ctx context.Context) (transport.ClientTransport, error) {
|
||||
for ctx.Err() == nil {
|
||||
ac.mu.Lock()
|
||||
t, state, sc := ac.transport, ac.state, ac.stateChan
|
||||
t, state, sc := ac.transport, ac.state, ac.stateReadyChan
|
||||
ac.mu.Unlock()
|
||||
if state == connectivity.Ready {
|
||||
return t, nil
|
||||
|
@ -1585,7 +1573,7 @@ func (ac *addrConn) tearDown(err error) {
|
|||
} else {
|
||||
// Hard close the transport when the channel is entering idle or is
|
||||
// being shutdown. In the case where the channel is being shutdown,
|
||||
// closing of transports is also taken care of by cancelation of cc.ctx.
|
||||
// closing of transports is also taken care of by cancellation of cc.ctx.
|
||||
// But in the case where the channel is entering idle, we need to
|
||||
// explicitly close the transports here. Instead of distinguishing
|
||||
// between these two cases, it is simpler to close the transport
|
||||
|
|
|
@ -21,18 +21,73 @@ package grpc
|
|||
import (
|
||||
"google.golang.org/grpc/encoding"
|
||||
_ "google.golang.org/grpc/encoding/proto" // to register the Codec for "proto"
|
||||
"google.golang.org/grpc/mem"
|
||||
)
|
||||
|
||||
// baseCodec contains the functionality of both Codec and encoding.Codec, but
|
||||
// omits the name/string, which vary between the two and are not needed for
|
||||
// anything besides the registry in the encoding package.
|
||||
// baseCodec captures the new encoding.CodecV2 interface without the Name
|
||||
// function, allowing it to be implemented by older Codec and encoding.Codec
|
||||
// implementations. The omitted Name function is only needed for the register in
|
||||
// the encoding package and is not part of the core functionality.
|
||||
type baseCodec interface {
|
||||
Marshal(v any) ([]byte, error)
|
||||
Unmarshal(data []byte, v any) error
|
||||
Marshal(v any) (mem.BufferSlice, error)
|
||||
Unmarshal(data mem.BufferSlice, v any) error
|
||||
}
|
||||
|
||||
var _ baseCodec = Codec(nil)
|
||||
var _ baseCodec = encoding.Codec(nil)
|
||||
// getCodec returns an encoding.CodecV2 for the codec of the given name (if
|
||||
// registered). Initially checks the V2 registry with encoding.GetCodecV2 and
|
||||
// returns the V2 codec if it is registered. Otherwise, it checks the V1 registry
|
||||
// with encoding.GetCodec and if it is registered wraps it with newCodecV1Bridge
|
||||
// to turn it into an encoding.CodecV2. Returns nil otherwise.
|
||||
func getCodec(name string) encoding.CodecV2 {
|
||||
if codecV1 := encoding.GetCodec(name); codecV1 != nil {
|
||||
return newCodecV1Bridge(codecV1)
|
||||
}
|
||||
|
||||
return encoding.GetCodecV2(name)
|
||||
}
|
||||
|
||||
func newCodecV0Bridge(c Codec) baseCodec {
|
||||
return codecV0Bridge{codec: c}
|
||||
}
|
||||
|
||||
func newCodecV1Bridge(c encoding.Codec) encoding.CodecV2 {
|
||||
return codecV1Bridge{
|
||||
codecV0Bridge: codecV0Bridge{codec: c},
|
||||
name: c.Name(),
|
||||
}
|
||||
}
|
||||
|
||||
var _ baseCodec = codecV0Bridge{}
|
||||
|
||||
type codecV0Bridge struct {
|
||||
codec interface {
|
||||
Marshal(v any) ([]byte, error)
|
||||
Unmarshal(data []byte, v any) error
|
||||
}
|
||||
}
|
||||
|
||||
func (c codecV0Bridge) Marshal(v any) (mem.BufferSlice, error) {
|
||||
data, err := c.codec.Marshal(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mem.BufferSlice{mem.NewBuffer(&data, nil)}, nil
|
||||
}
|
||||
|
||||
func (c codecV0Bridge) Unmarshal(data mem.BufferSlice, v any) (err error) {
|
||||
return c.codec.Unmarshal(data.Materialize(), v)
|
||||
}
|
||||
|
||||
var _ encoding.CodecV2 = codecV1Bridge{}
|
||||
|
||||
type codecV1Bridge struct {
|
||||
codecV0Bridge
|
||||
name string
|
||||
}
|
||||
|
||||
func (c codecV1Bridge) Name() string {
|
||||
return c.name
|
||||
}
|
||||
|
||||
// Codec defines the interface gRPC uses to encode and decode messages.
|
||||
// Note that implementations of this interface must be thread safe;
|
||||
|
|
|
@ -33,6 +33,7 @@ import (
|
|||
"google.golang.org/grpc/internal/binarylog"
|
||||
"google.golang.org/grpc/internal/transport"
|
||||
"google.golang.org/grpc/keepalive"
|
||||
"google.golang.org/grpc/mem"
|
||||
"google.golang.org/grpc/resolver"
|
||||
"google.golang.org/grpc/stats"
|
||||
)
|
||||
|
@ -60,7 +61,7 @@ func init() {
|
|||
internal.WithBinaryLogger = withBinaryLogger
|
||||
internal.JoinDialOptions = newJoinDialOption
|
||||
internal.DisableGlobalDialOptions = newDisableGlobalDialOptions
|
||||
internal.WithRecvBufferPool = withRecvBufferPool
|
||||
internal.WithBufferPool = withBufferPool
|
||||
}
|
||||
|
||||
// dialOptions configure a Dial call. dialOptions are set by the DialOption
|
||||
|
@ -92,7 +93,6 @@ type dialOptions struct {
|
|||
defaultServiceConfigRawJSON *string
|
||||
resolvers []resolver.Builder
|
||||
idleTimeout time.Duration
|
||||
recvBufferPool SharedBufferPool
|
||||
defaultScheme string
|
||||
maxCallAttempts int
|
||||
}
|
||||
|
@ -677,11 +677,11 @@ func defaultDialOptions() dialOptions {
|
|||
WriteBufferSize: defaultWriteBufSize,
|
||||
UseProxy: true,
|
||||
UserAgent: grpcUA,
|
||||
BufferPool: mem.DefaultBufferPool(),
|
||||
},
|
||||
bs: internalbackoff.DefaultExponential,
|
||||
healthCheckFunc: internal.HealthCheckFunc,
|
||||
idleTimeout: 30 * time.Minute,
|
||||
recvBufferPool: nopBufferPool{},
|
||||
defaultScheme: "dns",
|
||||
maxCallAttempts: defaultMaxCallAttempts,
|
||||
}
|
||||
|
@ -758,25 +758,8 @@ func WithMaxCallAttempts(n int) DialOption {
|
|||
})
|
||||
}
|
||||
|
||||
// WithRecvBufferPool returns a DialOption that configures the ClientConn
|
||||
// to use the provided shared buffer pool for parsing incoming messages. Depending
|
||||
// on the application's workload, this could result in reduced memory allocation.
|
||||
//
|
||||
// If you are unsure about how to implement a memory pool but want to utilize one,
|
||||
// begin with grpc.NewSharedBufferPool.
|
||||
//
|
||||
// Note: The shared buffer pool feature will not be active if any of the following
|
||||
// options are used: WithStatsHandler, EnableTracing, or binary logging. In such
|
||||
// cases, the shared buffer pool will be ignored.
|
||||
//
|
||||
// Deprecated: use experimental.WithRecvBufferPool instead. Will be deleted in
|
||||
// v1.60.0 or later.
|
||||
func WithRecvBufferPool(bufferPool SharedBufferPool) DialOption {
|
||||
return withRecvBufferPool(bufferPool)
|
||||
}
|
||||
|
||||
func withRecvBufferPool(bufferPool SharedBufferPool) DialOption {
|
||||
func withBufferPool(bufferPool mem.BufferPool) DialOption {
|
||||
return newFuncDialOption(func(o *dialOptions) {
|
||||
o.recvBufferPool = bufferPool
|
||||
o.copts.BufferPool = bufferPool
|
||||
})
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
//go:generate ./regenerate.sh
|
||||
//go:generate ./scripts/regenerate.sh
|
||||
|
||||
/*
|
||||
Package grpc implements an RPC system called gRPC.
|
||||
|
|
|
@ -94,7 +94,7 @@ type Codec interface {
|
|||
Name() string
|
||||
}
|
||||
|
||||
var registeredCodecs = make(map[string]Codec)
|
||||
var registeredCodecs = make(map[string]any)
|
||||
|
||||
// RegisterCodec registers the provided Codec for use with all gRPC clients and
|
||||
// servers.
|
||||
|
@ -126,5 +126,6 @@ func RegisterCodec(codec Codec) {
|
|||
//
|
||||
// The content-subtype is expected to be lowercase.
|
||||
func GetCodec(contentSubtype string) Codec {
|
||||
return registeredCodecs[contentSubtype]
|
||||
c, _ := registeredCodecs[contentSubtype].(Codec)
|
||||
return c
|
||||
}
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
*
|
||||
* Copyright 2024 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package encoding
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"google.golang.org/grpc/mem"
|
||||
)
|
||||
|
||||
// CodecV2 defines the interface gRPC uses to encode and decode messages. Note
|
||||
// that implementations of this interface must be thread safe; a CodecV2's
|
||||
// methods can be called from concurrent goroutines.
|
||||
type CodecV2 interface {
|
||||
// Marshal returns the wire format of v. The buffers in the returned
|
||||
// [mem.BufferSlice] must have at least one reference each, which will be freed
|
||||
// by gRPC when they are no longer needed.
|
||||
Marshal(v any) (out mem.BufferSlice, err error)
|
||||
// Unmarshal parses the wire format into v. Note that data will be freed as soon
|
||||
// as this function returns. If the codec wishes to guarantee access to the data
|
||||
// after this function, it must take its own reference that it frees when it is
|
||||
// no longer needed.
|
||||
Unmarshal(data mem.BufferSlice, v any) error
|
||||
// Name returns the name of the Codec implementation. The returned string
|
||||
// will be used as part of content type in transmission. The result must be
|
||||
// static; the result cannot change between calls.
|
||||
Name() string
|
||||
}
|
||||
|
||||
// RegisterCodecV2 registers the provided CodecV2 for use with all gRPC clients and
|
||||
// servers.
|
||||
//
|
||||
// The CodecV2 will be stored and looked up by result of its Name() method, which
|
||||
// should match the content-subtype of the encoding handled by the CodecV2. This
|
||||
// is case-insensitive, and is stored and looked up as lowercase. If the
|
||||
// result of calling Name() is an empty string, RegisterCodecV2 will panic. See
|
||||
// Content-Type on
|
||||
// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests for
|
||||
// more details.
|
||||
//
|
||||
// If both a Codec and CodecV2 are registered with the same name, the CodecV2
|
||||
// will be used.
|
||||
//
|
||||
// NOTE: this function must only be called during initialization time (i.e. in
|
||||
// an init() function), and is not thread-safe. If multiple Codecs are
|
||||
// registered with the same name, the one registered last will take effect.
|
||||
func RegisterCodecV2(codec CodecV2) {
|
||||
if codec == nil {
|
||||
panic("cannot register a nil CodecV2")
|
||||
}
|
||||
if codec.Name() == "" {
|
||||
panic("cannot register CodecV2 with empty string result for Name()")
|
||||
}
|
||||
contentSubtype := strings.ToLower(codec.Name())
|
||||
registeredCodecs[contentSubtype] = codec
|
||||
}
|
||||
|
||||
// GetCodecV2 gets a registered CodecV2 by content-subtype, or nil if no CodecV2 is
|
||||
// registered for the content-subtype.
|
||||
//
|
||||
// The content-subtype is expected to be lowercase.
|
||||
func GetCodecV2(contentSubtype string) CodecV2 {
|
||||
c, _ := registeredCodecs[contentSubtype].(CodecV2)
|
||||
return c
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
*
|
||||
* Copyright 2018 gRPC authors.
|
||||
* Copyright 2024 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -24,6 +24,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"google.golang.org/grpc/encoding"
|
||||
"google.golang.org/grpc/mem"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/protoadapt"
|
||||
)
|
||||
|
@ -32,28 +33,51 @@ import (
|
|||
const Name = "proto"
|
||||
|
||||
func init() {
|
||||
encoding.RegisterCodec(codec{})
|
||||
encoding.RegisterCodecV2(&codecV2{})
|
||||
}
|
||||
|
||||
// codec is a Codec implementation with protobuf. It is the default codec for gRPC.
|
||||
type codec struct{}
|
||||
// codec is a CodecV2 implementation with protobuf. It is the default codec for
|
||||
// gRPC.
|
||||
type codecV2 struct{}
|
||||
|
||||
func (codec) Marshal(v any) ([]byte, error) {
|
||||
func (c *codecV2) Marshal(v any) (data mem.BufferSlice, err error) {
|
||||
vv := messageV2Of(v)
|
||||
if vv == nil {
|
||||
return nil, fmt.Errorf("failed to marshal, message is %T, want proto.Message", v)
|
||||
return nil, fmt.Errorf("proto: failed to marshal, message is %T, want proto.Message", v)
|
||||
}
|
||||
|
||||
return proto.Marshal(vv)
|
||||
size := proto.Size(vv)
|
||||
if mem.IsBelowBufferPoolingThreshold(size) {
|
||||
buf, err := proto.Marshal(vv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data = append(data, mem.SliceBuffer(buf))
|
||||
} else {
|
||||
pool := mem.DefaultBufferPool()
|
||||
buf := pool.Get(size)
|
||||
if _, err := (proto.MarshalOptions{}).MarshalAppend((*buf)[:0], vv); err != nil {
|
||||
pool.Put(buf)
|
||||
return nil, err
|
||||
}
|
||||
data = append(data, mem.NewBuffer(buf, pool))
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (codec) Unmarshal(data []byte, v any) error {
|
||||
func (c *codecV2) Unmarshal(data mem.BufferSlice, v any) (err error) {
|
||||
vv := messageV2Of(v)
|
||||
if vv == nil {
|
||||
return fmt.Errorf("failed to unmarshal, message is %T, want proto.Message", v)
|
||||
}
|
||||
|
||||
return proto.Unmarshal(data, vv)
|
||||
buf := data.MaterializeToBuffer(mem.DefaultBufferPool())
|
||||
defer buf.Free()
|
||||
// TODO: Upgrade proto.Unmarshal to support mem.BufferSlice. Right now, it's not
|
||||
// really possible without a major overhaul of the proto package, but the
|
||||
// vtprotobuf library may be able to support this.
|
||||
return proto.Unmarshal(buf.ReadOnlyData(), vv)
|
||||
}
|
||||
|
||||
func messageV2Of(v any) proto.Message {
|
||||
|
@ -67,6 +91,6 @@ func messageV2Of(v any) proto.Message {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (codec) Name() string {
|
||||
func (c *codecV2) Name() string {
|
||||
return Name
|
||||
}
|
||||
|
|
270
vendor/google.golang.org/grpc/experimental/stats/metricregistry.go
generated
vendored
Normal file
270
vendor/google.golang.org/grpc/experimental/stats/metricregistry.go
generated
vendored
Normal file
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
*
|
||||
* Copyright 2024 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package stats
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"testing"
|
||||
|
||||
"google.golang.org/grpc/grpclog"
|
||||
"google.golang.org/grpc/internal"
|
||||
)
|
||||
|
||||
func init() {
|
||||
internal.SnapshotMetricRegistryForTesting = snapshotMetricsRegistryForTesting
|
||||
}
|
||||
|
||||
var logger = grpclog.Component("metrics-registry")
|
||||
|
||||
// DefaultMetrics are the default metrics registered through global metrics
|
||||
// registry. This is written to at initialization time only, and is read only
|
||||
// after initialization.
|
||||
var DefaultMetrics = NewMetrics()
|
||||
|
||||
// MetricDescriptor is the data for a registered metric.
|
||||
type MetricDescriptor struct {
|
||||
// The name of this metric. This name must be unique across the whole binary
|
||||
// (including any per call metrics). See
|
||||
// https://github.com/grpc/proposal/blob/master/A79-non-per-call-metrics-architecture.md#metric-instrument-naming-conventions
|
||||
// for metric naming conventions.
|
||||
Name Metric
|
||||
// The description of this metric.
|
||||
Description string
|
||||
// The unit (e.g. entries, seconds) of this metric.
|
||||
Unit string
|
||||
// The required label keys for this metric. These are intended to
|
||||
// metrics emitted from a stats handler.
|
||||
Labels []string
|
||||
// The optional label keys for this metric. These are intended to attached
|
||||
// to metrics emitted from a stats handler if configured.
|
||||
OptionalLabels []string
|
||||
// Whether this metric is on by default.
|
||||
Default bool
|
||||
// The type of metric. This is set by the metric registry, and not intended
|
||||
// to be set by a component registering a metric.
|
||||
Type MetricType
|
||||
// Bounds are the bounds of this metric. This only applies to histogram
|
||||
// metrics. If unset or set with length 0, stats handlers will fall back to
|
||||
// default bounds.
|
||||
Bounds []float64
|
||||
}
|
||||
|
||||
// MetricType is the type of metric.
|
||||
type MetricType int
|
||||
|
||||
// Type of metric supported by this instrument registry.
|
||||
const (
|
||||
MetricTypeIntCount MetricType = iota
|
||||
MetricTypeFloatCount
|
||||
MetricTypeIntHisto
|
||||
MetricTypeFloatHisto
|
||||
MetricTypeIntGauge
|
||||
)
|
||||
|
||||
// Int64CountHandle is a typed handle for a int count metric. This handle
|
||||
// is passed at the recording point in order to know which metric to record
|
||||
// on.
|
||||
type Int64CountHandle MetricDescriptor
|
||||
|
||||
// Descriptor returns the int64 count handle typecast to a pointer to a
|
||||
// MetricDescriptor.
|
||||
func (h *Int64CountHandle) Descriptor() *MetricDescriptor {
|
||||
return (*MetricDescriptor)(h)
|
||||
}
|
||||
|
||||
// Record records the int64 count value on the metrics recorder provided.
|
||||
func (h *Int64CountHandle) Record(recorder MetricsRecorder, incr int64, labels ...string) {
|
||||
recorder.RecordInt64Count(h, incr, labels...)
|
||||
}
|
||||
|
||||
// Float64CountHandle is a typed handle for a float count metric. This handle is
|
||||
// passed at the recording point in order to know which metric to record on.
|
||||
type Float64CountHandle MetricDescriptor
|
||||
|
||||
// Descriptor returns the float64 count handle typecast to a pointer to a
|
||||
// MetricDescriptor.
|
||||
func (h *Float64CountHandle) Descriptor() *MetricDescriptor {
|
||||
return (*MetricDescriptor)(h)
|
||||
}
|
||||
|
||||
// Record records the float64 count value on the metrics recorder provided.
|
||||
func (h *Float64CountHandle) Record(recorder MetricsRecorder, incr float64, labels ...string) {
|
||||
recorder.RecordFloat64Count(h, incr, labels...)
|
||||
}
|
||||
|
||||
// Int64HistoHandle is a typed handle for an int histogram metric. This handle
|
||||
// is passed at the recording point in order to know which metric to record on.
|
||||
type Int64HistoHandle MetricDescriptor
|
||||
|
||||
// Descriptor returns the int64 histo handle typecast to a pointer to a
|
||||
// MetricDescriptor.
|
||||
func (h *Int64HistoHandle) Descriptor() *MetricDescriptor {
|
||||
return (*MetricDescriptor)(h)
|
||||
}
|
||||
|
||||
// Record records the int64 histo value on the metrics recorder provided.
|
||||
func (h *Int64HistoHandle) Record(recorder MetricsRecorder, incr int64, labels ...string) {
|
||||
recorder.RecordInt64Histo(h, incr, labels...)
|
||||
}
|
||||
|
||||
// Float64HistoHandle is a typed handle for a float histogram metric. This
|
||||
// handle is passed at the recording point in order to know which metric to
|
||||
// record on.
|
||||
type Float64HistoHandle MetricDescriptor
|
||||
|
||||
// Descriptor returns the float64 histo handle typecast to a pointer to a
|
||||
// MetricDescriptor.
|
||||
func (h *Float64HistoHandle) Descriptor() *MetricDescriptor {
|
||||
return (*MetricDescriptor)(h)
|
||||
}
|
||||
|
||||
// Record records the float64 histo value on the metrics recorder provided.
|
||||
func (h *Float64HistoHandle) Record(recorder MetricsRecorder, incr float64, labels ...string) {
|
||||
recorder.RecordFloat64Histo(h, incr, labels...)
|
||||
}
|
||||
|
||||
// Int64GaugeHandle is a typed handle for an int gauge metric. This handle is
|
||||
// passed at the recording point in order to know which metric to record on.
|
||||
type Int64GaugeHandle MetricDescriptor
|
||||
|
||||
// Descriptor returns the int64 gauge handle typecast to a pointer to a
|
||||
// MetricDescriptor.
|
||||
func (h *Int64GaugeHandle) Descriptor() *MetricDescriptor {
|
||||
return (*MetricDescriptor)(h)
|
||||
}
|
||||
|
||||
// Record records the int64 histo value on the metrics recorder provided.
|
||||
func (h *Int64GaugeHandle) Record(recorder MetricsRecorder, incr int64, labels ...string) {
|
||||
recorder.RecordInt64Gauge(h, incr, labels...)
|
||||
}
|
||||
|
||||
// registeredMetrics are the registered metric descriptor names.
|
||||
var registeredMetrics = make(map[Metric]bool)
|
||||
|
||||
// metricsRegistry contains all of the registered metrics.
|
||||
//
|
||||
// This is written to only at init time, and read only after that.
|
||||
var metricsRegistry = make(map[Metric]*MetricDescriptor)
|
||||
|
||||
// DescriptorForMetric returns the MetricDescriptor from the global registry.
|
||||
//
|
||||
// Returns nil if MetricDescriptor not present.
|
||||
func DescriptorForMetric(metric Metric) *MetricDescriptor {
|
||||
return metricsRegistry[metric]
|
||||
}
|
||||
|
||||
func registerMetric(name Metric, def bool) {
|
||||
if registeredMetrics[name] {
|
||||
logger.Fatalf("metric %v already registered", name)
|
||||
}
|
||||
registeredMetrics[name] = true
|
||||
if def {
|
||||
DefaultMetrics = DefaultMetrics.Add(name)
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterInt64Count registers the metric description onto the global registry.
|
||||
// It returns a typed handle to use to recording data.
|
||||
//
|
||||
// NOTE: this function must only be called during initialization time (i.e. in
|
||||
// an init() function), and is not thread-safe. If multiple metrics are
|
||||
// registered with the same name, this function will panic.
|
||||
func RegisterInt64Count(descriptor MetricDescriptor) *Int64CountHandle {
|
||||
registerMetric(descriptor.Name, descriptor.Default)
|
||||
descriptor.Type = MetricTypeIntCount
|
||||
descPtr := &descriptor
|
||||
metricsRegistry[descriptor.Name] = descPtr
|
||||
return (*Int64CountHandle)(descPtr)
|
||||
}
|
||||
|
||||
// RegisterFloat64Count registers the metric description onto the global
|
||||
// registry. It returns a typed handle to use to recording data.
|
||||
//
|
||||
// NOTE: this function must only be called during initialization time (i.e. in
|
||||
// an init() function), and is not thread-safe. If multiple metrics are
|
||||
// registered with the same name, this function will panic.
|
||||
func RegisterFloat64Count(descriptor MetricDescriptor) *Float64CountHandle {
|
||||
registerMetric(descriptor.Name, descriptor.Default)
|
||||
descriptor.Type = MetricTypeFloatCount
|
||||
descPtr := &descriptor
|
||||
metricsRegistry[descriptor.Name] = descPtr
|
||||
return (*Float64CountHandle)(descPtr)
|
||||
}
|
||||
|
||||
// RegisterInt64Histo registers the metric description onto the global registry.
|
||||
// It returns a typed handle to use to recording data.
|
||||
//
|
||||
// NOTE: this function must only be called during initialization time (i.e. in
|
||||
// an init() function), and is not thread-safe. If multiple metrics are
|
||||
// registered with the same name, this function will panic.
|
||||
func RegisterInt64Histo(descriptor MetricDescriptor) *Int64HistoHandle {
|
||||
registerMetric(descriptor.Name, descriptor.Default)
|
||||
descriptor.Type = MetricTypeIntHisto
|
||||
descPtr := &descriptor
|
||||
metricsRegistry[descriptor.Name] = descPtr
|
||||
return (*Int64HistoHandle)(descPtr)
|
||||
}
|
||||
|
||||
// RegisterFloat64Histo registers the metric description onto the global
|
||||
// registry. It returns a typed handle to use to recording data.
|
||||
//
|
||||
// NOTE: this function must only be called during initialization time (i.e. in
|
||||
// an init() function), and is not thread-safe. If multiple metrics are
|
||||
// registered with the same name, this function will panic.
|
||||
func RegisterFloat64Histo(descriptor MetricDescriptor) *Float64HistoHandle {
|
||||
registerMetric(descriptor.Name, descriptor.Default)
|
||||
descriptor.Type = MetricTypeFloatHisto
|
||||
descPtr := &descriptor
|
||||
metricsRegistry[descriptor.Name] = descPtr
|
||||
return (*Float64HistoHandle)(descPtr)
|
||||
}
|
||||
|
||||
// RegisterInt64Gauge registers the metric description onto the global registry.
|
||||
// It returns a typed handle to use to recording data.
|
||||
//
|
||||
// NOTE: this function must only be called during initialization time (i.e. in
|
||||
// an init() function), and is not thread-safe. If multiple metrics are
|
||||
// registered with the same name, this function will panic.
|
||||
func RegisterInt64Gauge(descriptor MetricDescriptor) *Int64GaugeHandle {
|
||||
registerMetric(descriptor.Name, descriptor.Default)
|
||||
descriptor.Type = MetricTypeIntGauge
|
||||
descPtr := &descriptor
|
||||
metricsRegistry[descriptor.Name] = descPtr
|
||||
return (*Int64GaugeHandle)(descPtr)
|
||||
}
|
||||
|
||||
// snapshotMetricsRegistryForTesting snapshots the global data of the metrics
|
||||
// registry. Registers a cleanup function on the provided testing.T that sets
|
||||
// the metrics registry to its original state. Only called in testing functions.
|
||||
func snapshotMetricsRegistryForTesting(t *testing.T) {
|
||||
oldDefaultMetrics := DefaultMetrics
|
||||
oldRegisteredMetrics := registeredMetrics
|
||||
oldMetricsRegistry := metricsRegistry
|
||||
|
||||
registeredMetrics = make(map[Metric]bool)
|
||||
metricsRegistry = make(map[Metric]*MetricDescriptor)
|
||||
maps.Copy(registeredMetrics, registeredMetrics)
|
||||
maps.Copy(metricsRegistry, metricsRegistry)
|
||||
|
||||
t.Cleanup(func() {
|
||||
DefaultMetrics = oldDefaultMetrics
|
||||
registeredMetrics = oldRegisteredMetrics
|
||||
metricsRegistry = oldMetricsRegistry
|
||||
})
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
*
|
||||
* Copyright 2024 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
// Package stats contains experimental metrics/stats API's.
|
||||
package stats
|
||||
|
||||
import "maps"
|
||||
|
||||
// MetricsRecorder records on metrics derived from metric registry.
|
||||
type MetricsRecorder interface {
|
||||
// RecordInt64Count records the measurement alongside labels on the int
|
||||
// count associated with the provided handle.
|
||||
RecordInt64Count(handle *Int64CountHandle, incr int64, labels ...string)
|
||||
// RecordFloat64Count records the measurement alongside labels on the float
|
||||
// count associated with the provided handle.
|
||||
RecordFloat64Count(handle *Float64CountHandle, incr float64, labels ...string)
|
||||
// RecordInt64Histo records the measurement alongside labels on the int
|
||||
// histo associated with the provided handle.
|
||||
RecordInt64Histo(handle *Int64HistoHandle, incr int64, labels ...string)
|
||||
// RecordFloat64Histo records the measurement alongside labels on the float
|
||||
// histo associated with the provided handle.
|
||||
RecordFloat64Histo(handle *Float64HistoHandle, incr float64, labels ...string)
|
||||
// RecordInt64Gauge records the measurement alongside labels on the int
|
||||
// gauge associated with the provided handle.
|
||||
RecordInt64Gauge(handle *Int64GaugeHandle, incr int64, labels ...string)
|
||||
}
|
||||
|
||||
// Metric is an identifier for a metric.
|
||||
type Metric string
|
||||
|
||||
// Metrics is a set of metrics to record. Once created, Metrics is immutable,
|
||||
// however Add and Remove can make copies with specific metrics added or
|
||||
// removed, respectively.
|
||||
//
|
||||
// Do not construct directly; use NewMetrics instead.
|
||||
type Metrics struct {
|
||||
// metrics are the set of metrics to initialize.
|
||||
metrics map[Metric]bool
|
||||
}
|
||||
|
||||
// NewMetrics returns a Metrics containing Metrics.
|
||||
func NewMetrics(metrics ...Metric) *Metrics {
|
||||
newMetrics := make(map[Metric]bool)
|
||||
for _, metric := range metrics {
|
||||
newMetrics[metric] = true
|
||||
}
|
||||
return &Metrics{
|
||||
metrics: newMetrics,
|
||||
}
|
||||
}
|
||||
|
||||
// Metrics returns the metrics set. The returned map is read-only and must not
|
||||
// be modified.
|
||||
func (m *Metrics) Metrics() map[Metric]bool {
|
||||
return m.metrics
|
||||
}
|
||||
|
||||
// Add adds the metrics to the metrics set and returns a new copy with the
|
||||
// additional metrics.
|
||||
func (m *Metrics) Add(metrics ...Metric) *Metrics {
|
||||
newMetrics := make(map[Metric]bool)
|
||||
for metric := range m.metrics {
|
||||
newMetrics[metric] = true
|
||||
}
|
||||
|
||||
for _, metric := range metrics {
|
||||
newMetrics[metric] = true
|
||||
}
|
||||
return &Metrics{
|
||||
metrics: newMetrics,
|
||||
}
|
||||
}
|
||||
|
||||
// Join joins the metrics passed in with the metrics set, and returns a new copy
|
||||
// with the merged metrics.
|
||||
func (m *Metrics) Join(metrics *Metrics) *Metrics {
|
||||
newMetrics := make(map[Metric]bool)
|
||||
maps.Copy(newMetrics, m.metrics)
|
||||
maps.Copy(newMetrics, metrics.metrics)
|
||||
return &Metrics{
|
||||
metrics: newMetrics,
|
||||
}
|
||||
}
|
||||
|
||||
// Remove removes the metrics from the metrics set and returns a new copy with
|
||||
// the metrics removed.
|
||||
func (m *Metrics) Remove(metrics ...Metric) *Metrics {
|
||||
newMetrics := make(map[Metric]bool)
|
||||
for metric := range m.metrics {
|
||||
newMetrics[metric] = true
|
||||
}
|
||||
|
||||
for _, metric := range metrics {
|
||||
delete(newMetrics, metric)
|
||||
}
|
||||
return &Metrics{
|
||||
metrics: newMetrics,
|
||||
}
|
||||
}
|
|
@ -20,8 +20,6 @@ package grpclog
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/grpc/internal/grpclog"
|
||||
)
|
||||
|
||||
// componentData records the settings for a component.
|
||||
|
@ -33,22 +31,22 @@ var cache = map[string]*componentData{}
|
|||
|
||||
func (c *componentData) InfoDepth(depth int, args ...any) {
|
||||
args = append([]any{"[" + string(c.name) + "]"}, args...)
|
||||
grpclog.InfoDepth(depth+1, args...)
|
||||
InfoDepth(depth+1, args...)
|
||||
}
|
||||
|
||||
func (c *componentData) WarningDepth(depth int, args ...any) {
|
||||
args = append([]any{"[" + string(c.name) + "]"}, args...)
|
||||
grpclog.WarningDepth(depth+1, args...)
|
||||
WarningDepth(depth+1, args...)
|
||||
}
|
||||
|
||||
func (c *componentData) ErrorDepth(depth int, args ...any) {
|
||||
args = append([]any{"[" + string(c.name) + "]"}, args...)
|
||||
grpclog.ErrorDepth(depth+1, args...)
|
||||
ErrorDepth(depth+1, args...)
|
||||
}
|
||||
|
||||
func (c *componentData) FatalDepth(depth int, args ...any) {
|
||||
args = append([]any{"[" + string(c.name) + "]"}, args...)
|
||||
grpclog.FatalDepth(depth+1, args...)
|
||||
FatalDepth(depth+1, args...)
|
||||
}
|
||||
|
||||
func (c *componentData) Info(args ...any) {
|
||||
|
|
|
@ -18,18 +18,15 @@
|
|||
|
||||
// Package grpclog defines logging for grpc.
|
||||
//
|
||||
// All logs in transport and grpclb packages only go to verbose level 2.
|
||||
// All logs in other packages in grpc are logged in spite of the verbosity level.
|
||||
//
|
||||
// In the default logger,
|
||||
// severity level can be set by environment variable GRPC_GO_LOG_SEVERITY_LEVEL,
|
||||
// verbosity level can be set by GRPC_GO_LOG_VERBOSITY_LEVEL.
|
||||
package grpclog // import "google.golang.org/grpc/grpclog"
|
||||
// In the default logger, severity level can be set by environment variable
|
||||
// GRPC_GO_LOG_SEVERITY_LEVEL, verbosity level can be set by
|
||||
// GRPC_GO_LOG_VERBOSITY_LEVEL.
|
||||
package grpclog
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"google.golang.org/grpc/internal/grpclog"
|
||||
"google.golang.org/grpc/grpclog/internal"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -38,58 +35,58 @@ func init() {
|
|||
|
||||
// V reports whether verbosity level l is at least the requested verbose level.
|
||||
func V(l int) bool {
|
||||
return grpclog.Logger.V(l)
|
||||
return internal.LoggerV2Impl.V(l)
|
||||
}
|
||||
|
||||
// Info logs to the INFO log.
|
||||
func Info(args ...any) {
|
||||
grpclog.Logger.Info(args...)
|
||||
internal.LoggerV2Impl.Info(args...)
|
||||
}
|
||||
|
||||
// Infof logs to the INFO log. Arguments are handled in the manner of fmt.Printf.
|
||||
func Infof(format string, args ...any) {
|
||||
grpclog.Logger.Infof(format, args...)
|
||||
internal.LoggerV2Impl.Infof(format, args...)
|
||||
}
|
||||
|
||||
// Infoln logs to the INFO log. Arguments are handled in the manner of fmt.Println.
|
||||
func Infoln(args ...any) {
|
||||
grpclog.Logger.Infoln(args...)
|
||||
internal.LoggerV2Impl.Infoln(args...)
|
||||
}
|
||||
|
||||
// Warning logs to the WARNING log.
|
||||
func Warning(args ...any) {
|
||||
grpclog.Logger.Warning(args...)
|
||||
internal.LoggerV2Impl.Warning(args...)
|
||||
}
|
||||
|
||||
// Warningf logs to the WARNING log. Arguments are handled in the manner of fmt.Printf.
|
||||
func Warningf(format string, args ...any) {
|
||||
grpclog.Logger.Warningf(format, args...)
|
||||
internal.LoggerV2Impl.Warningf(format, args...)
|
||||
}
|
||||
|
||||
// Warningln logs to the WARNING log. Arguments are handled in the manner of fmt.Println.
|
||||
func Warningln(args ...any) {
|
||||
grpclog.Logger.Warningln(args...)
|
||||
internal.LoggerV2Impl.Warningln(args...)
|
||||
}
|
||||
|
||||
// Error logs to the ERROR log.
|
||||
func Error(args ...any) {
|
||||
grpclog.Logger.Error(args...)
|
||||
internal.LoggerV2Impl.Error(args...)
|
||||
}
|
||||
|
||||
// Errorf logs to the ERROR log. Arguments are handled in the manner of fmt.Printf.
|
||||
func Errorf(format string, args ...any) {
|
||||
grpclog.Logger.Errorf(format, args...)
|
||||
internal.LoggerV2Impl.Errorf(format, args...)
|
||||
}
|
||||
|
||||
// Errorln logs to the ERROR log. Arguments are handled in the manner of fmt.Println.
|
||||
func Errorln(args ...any) {
|
||||
grpclog.Logger.Errorln(args...)
|
||||
internal.LoggerV2Impl.Errorln(args...)
|
||||
}
|
||||
|
||||
// Fatal logs to the FATAL log. Arguments are handled in the manner of fmt.Print.
|
||||
// It calls os.Exit() with exit code 1.
|
||||
func Fatal(args ...any) {
|
||||
grpclog.Logger.Fatal(args...)
|
||||
internal.LoggerV2Impl.Fatal(args...)
|
||||
// Make sure fatal logs will exit.
|
||||
os.Exit(1)
|
||||
}
|
||||
|
@ -97,15 +94,15 @@ func Fatal(args ...any) {
|
|||
// Fatalf logs to the FATAL log. Arguments are handled in the manner of fmt.Printf.
|
||||
// It calls os.Exit() with exit code 1.
|
||||
func Fatalf(format string, args ...any) {
|
||||
grpclog.Logger.Fatalf(format, args...)
|
||||
internal.LoggerV2Impl.Fatalf(format, args...)
|
||||
// Make sure fatal logs will exit.
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Fatalln logs to the FATAL log. Arguments are handled in the manner of fmt.Println.
|
||||
// It calle os.Exit()) with exit code 1.
|
||||
// It calls os.Exit() with exit code 1.
|
||||
func Fatalln(args ...any) {
|
||||
grpclog.Logger.Fatalln(args...)
|
||||
internal.LoggerV2Impl.Fatalln(args...)
|
||||
// Make sure fatal logs will exit.
|
||||
os.Exit(1)
|
||||
}
|
||||
|
@ -114,19 +111,76 @@ func Fatalln(args ...any) {
|
|||
//
|
||||
// Deprecated: use Info.
|
||||
func Print(args ...any) {
|
||||
grpclog.Logger.Info(args...)
|
||||
internal.LoggerV2Impl.Info(args...)
|
||||
}
|
||||
|
||||
// Printf prints to the logger. Arguments are handled in the manner of fmt.Printf.
|
||||
//
|
||||
// Deprecated: use Infof.
|
||||
func Printf(format string, args ...any) {
|
||||
grpclog.Logger.Infof(format, args...)
|
||||
internal.LoggerV2Impl.Infof(format, args...)
|
||||
}
|
||||
|
||||
// Println prints to the logger. Arguments are handled in the manner of fmt.Println.
|
||||
//
|
||||
// Deprecated: use Infoln.
|
||||
func Println(args ...any) {
|
||||
grpclog.Logger.Infoln(args...)
|
||||
internal.LoggerV2Impl.Infoln(args...)
|
||||
}
|
||||
|
||||
// InfoDepth logs to the INFO log at the specified depth.
|
||||
//
|
||||
// # Experimental
|
||||
//
|
||||
// Notice: This API is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
func InfoDepth(depth int, args ...any) {
|
||||
if internal.DepthLoggerV2Impl != nil {
|
||||
internal.DepthLoggerV2Impl.InfoDepth(depth, args...)
|
||||
} else {
|
||||
internal.LoggerV2Impl.Infoln(args...)
|
||||
}
|
||||
}
|
||||
|
||||
// WarningDepth logs to the WARNING log at the specified depth.
|
||||
//
|
||||
// # Experimental
|
||||
//
|
||||
// Notice: This API is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
func WarningDepth(depth int, args ...any) {
|
||||
if internal.DepthLoggerV2Impl != nil {
|
||||
internal.DepthLoggerV2Impl.WarningDepth(depth, args...)
|
||||
} else {
|
||||
internal.LoggerV2Impl.Warningln(args...)
|
||||
}
|
||||
}
|
||||
|
||||
// ErrorDepth logs to the ERROR log at the specified depth.
|
||||
//
|
||||
// # Experimental
|
||||
//
|
||||
// Notice: This API is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
func ErrorDepth(depth int, args ...any) {
|
||||
if internal.DepthLoggerV2Impl != nil {
|
||||
internal.DepthLoggerV2Impl.ErrorDepth(depth, args...)
|
||||
} else {
|
||||
internal.LoggerV2Impl.Errorln(args...)
|
||||
}
|
||||
}
|
||||
|
||||
// FatalDepth logs to the FATAL log at the specified depth.
|
||||
//
|
||||
// # Experimental
|
||||
//
|
||||
// Notice: This API is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
func FatalDepth(depth int, args ...any) {
|
||||
if internal.DepthLoggerV2Impl != nil {
|
||||
internal.DepthLoggerV2Impl.FatalDepth(depth, args...)
|
||||
} else {
|
||||
internal.LoggerV2Impl.Fatalln(args...)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
*
|
||||
* Copyright 2024 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
// Package internal contains functionality internal to the grpclog package.
|
||||
package internal
|
||||
|
||||
// LoggerV2Impl is the logger used for the non-depth log functions.
|
||||
var LoggerV2Impl LoggerV2
|
||||
|
||||
// DepthLoggerV2Impl is the logger used for the depth log functions.
|
||||
var DepthLoggerV2Impl DepthLoggerV2
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
*
|
||||
* Copyright 2024 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
// Logger mimics golang's standard Logger as an interface.
|
||||
//
|
||||
// Deprecated: use LoggerV2.
|
||||
type Logger interface {
|
||||
Fatal(args ...any)
|
||||
Fatalf(format string, args ...any)
|
||||
Fatalln(args ...any)
|
||||
Print(args ...any)
|
||||
Printf(format string, args ...any)
|
||||
Println(args ...any)
|
||||
}
|
||||
|
||||
// LoggerWrapper wraps Logger into a LoggerV2.
|
||||
type LoggerWrapper struct {
|
||||
Logger
|
||||
}
|
||||
|
||||
// Info logs to INFO log. Arguments are handled in the manner of fmt.Print.
|
||||
func (l *LoggerWrapper) Info(args ...any) {
|
||||
l.Logger.Print(args...)
|
||||
}
|
||||
|
||||
// Infoln logs to INFO log. Arguments are handled in the manner of fmt.Println.
|
||||
func (l *LoggerWrapper) Infoln(args ...any) {
|
||||
l.Logger.Println(args...)
|
||||
}
|
||||
|
||||
// Infof logs to INFO log. Arguments are handled in the manner of fmt.Printf.
|
||||
func (l *LoggerWrapper) Infof(format string, args ...any) {
|
||||
l.Logger.Printf(format, args...)
|
||||
}
|
||||
|
||||
// Warning logs to WARNING log. Arguments are handled in the manner of fmt.Print.
|
||||
func (l *LoggerWrapper) Warning(args ...any) {
|
||||
l.Logger.Print(args...)
|
||||
}
|
||||
|
||||
// Warningln logs to WARNING log. Arguments are handled in the manner of fmt.Println.
|
||||
func (l *LoggerWrapper) Warningln(args ...any) {
|
||||
l.Logger.Println(args...)
|
||||
}
|
||||
|
||||
// Warningf logs to WARNING log. Arguments are handled in the manner of fmt.Printf.
|
||||
func (l *LoggerWrapper) Warningf(format string, args ...any) {
|
||||
l.Logger.Printf(format, args...)
|
||||
}
|
||||
|
||||
// Error logs to ERROR log. Arguments are handled in the manner of fmt.Print.
|
||||
func (l *LoggerWrapper) Error(args ...any) {
|
||||
l.Logger.Print(args...)
|
||||
}
|
||||
|
||||
// Errorln logs to ERROR log. Arguments are handled in the manner of fmt.Println.
|
||||
func (l *LoggerWrapper) Errorln(args ...any) {
|
||||
l.Logger.Println(args...)
|
||||
}
|
||||
|
||||
// Errorf logs to ERROR log. Arguments are handled in the manner of fmt.Printf.
|
||||
func (l *LoggerWrapper) Errorf(format string, args ...any) {
|
||||
l.Logger.Printf(format, args...)
|
||||
}
|
||||
|
||||
// V reports whether verbosity level l is at least the requested verbose level.
|
||||
func (*LoggerWrapper) V(l int) bool {
|
||||
// Returns true for all verbose level.
|
||||
return true
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
*
|
||||
* Copyright 2020 gRPC authors.
|
||||
* Copyright 2024 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,59 +16,17 @@
|
|||
*
|
||||
*/
|
||||
|
||||
// Package grpclog (internal) defines depth logging for grpc.
|
||||
package grpclog
|
||||
package internal
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Logger is the logger used for the non-depth log functions.
|
||||
var Logger LoggerV2
|
||||
|
||||
// DepthLogger is the logger used for the depth log functions.
|
||||
var DepthLogger DepthLoggerV2
|
||||
|
||||
// InfoDepth logs to the INFO log at the specified depth.
|
||||
func InfoDepth(depth int, args ...any) {
|
||||
if DepthLogger != nil {
|
||||
DepthLogger.InfoDepth(depth, args...)
|
||||
} else {
|
||||
Logger.Infoln(args...)
|
||||
}
|
||||
}
|
||||
|
||||
// WarningDepth logs to the WARNING log at the specified depth.
|
||||
func WarningDepth(depth int, args ...any) {
|
||||
if DepthLogger != nil {
|
||||
DepthLogger.WarningDepth(depth, args...)
|
||||
} else {
|
||||
Logger.Warningln(args...)
|
||||
}
|
||||
}
|
||||
|
||||
// ErrorDepth logs to the ERROR log at the specified depth.
|
||||
func ErrorDepth(depth int, args ...any) {
|
||||
if DepthLogger != nil {
|
||||
DepthLogger.ErrorDepth(depth, args...)
|
||||
} else {
|
||||
Logger.Errorln(args...)
|
||||
}
|
||||
}
|
||||
|
||||
// FatalDepth logs to the FATAL log at the specified depth.
|
||||
func FatalDepth(depth int, args ...any) {
|
||||
if DepthLogger != nil {
|
||||
DepthLogger.FatalDepth(depth, args...)
|
||||
} else {
|
||||
Logger.Fatalln(args...)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// LoggerV2 does underlying logging work for grpclog.
|
||||
// This is a copy of the LoggerV2 defined in the external grpclog package. It
|
||||
// is defined here to avoid a circular dependency.
|
||||
type LoggerV2 interface {
|
||||
// Info logs to INFO log. Arguments are handled in the manner of fmt.Print.
|
||||
Info(args ...any)
|
||||
|
@ -107,14 +65,13 @@ type LoggerV2 interface {
|
|||
// DepthLoggerV2 logs at a specified call frame. If a LoggerV2 also implements
|
||||
// DepthLoggerV2, the below functions will be called with the appropriate stack
|
||||
// depth set for trivial functions the logger may ignore.
|
||||
// This is a copy of the DepthLoggerV2 defined in the external grpclog package.
|
||||
// It is defined here to avoid a circular dependency.
|
||||
//
|
||||
// # Experimental
|
||||
//
|
||||
// Notice: This type is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
type DepthLoggerV2 interface {
|
||||
LoggerV2
|
||||
// InfoDepth logs to INFO log at the specified depth. Arguments are handled in the manner of fmt.Println.
|
||||
InfoDepth(depth int, args ...any)
|
||||
// WarningDepth logs to WARNING log at the specified depth. Arguments are handled in the manner of fmt.Println.
|
||||
|
@ -124,3 +81,124 @@ type DepthLoggerV2 interface {
|
|||
// FatalDepth logs to FATAL log at the specified depth. Arguments are handled in the manner of fmt.Println.
|
||||
FatalDepth(depth int, args ...any)
|
||||
}
|
||||
|
||||
const (
|
||||
// infoLog indicates Info severity.
|
||||
infoLog int = iota
|
||||
// warningLog indicates Warning severity.
|
||||
warningLog
|
||||
// errorLog indicates Error severity.
|
||||
errorLog
|
||||
// fatalLog indicates Fatal severity.
|
||||
fatalLog
|
||||
)
|
||||
|
||||
// severityName contains the string representation of each severity.
|
||||
var severityName = []string{
|
||||
infoLog: "INFO",
|
||||
warningLog: "WARNING",
|
||||
errorLog: "ERROR",
|
||||
fatalLog: "FATAL",
|
||||
}
|
||||
|
||||
// loggerT is the default logger used by grpclog.
|
||||
type loggerT struct {
|
||||
m []*log.Logger
|
||||
v int
|
||||
jsonFormat bool
|
||||
}
|
||||
|
||||
func (g *loggerT) output(severity int, s string) {
|
||||
sevStr := severityName[severity]
|
||||
if !g.jsonFormat {
|
||||
g.m[severity].Output(2, fmt.Sprintf("%v: %v", sevStr, s))
|
||||
return
|
||||
}
|
||||
// TODO: we can also include the logging component, but that needs more
|
||||
// (API) changes.
|
||||
b, _ := json.Marshal(map[string]string{
|
||||
"severity": sevStr,
|
||||
"message": s,
|
||||
})
|
||||
g.m[severity].Output(2, string(b))
|
||||
}
|
||||
|
||||
func (g *loggerT) Info(args ...any) {
|
||||
g.output(infoLog, fmt.Sprint(args...))
|
||||
}
|
||||
|
||||
func (g *loggerT) Infoln(args ...any) {
|
||||
g.output(infoLog, fmt.Sprintln(args...))
|
||||
}
|
||||
|
||||
func (g *loggerT) Infof(format string, args ...any) {
|
||||
g.output(infoLog, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func (g *loggerT) Warning(args ...any) {
|
||||
g.output(warningLog, fmt.Sprint(args...))
|
||||
}
|
||||
|
||||
func (g *loggerT) Warningln(args ...any) {
|
||||
g.output(warningLog, fmt.Sprintln(args...))
|
||||
}
|
||||
|
||||
func (g *loggerT) Warningf(format string, args ...any) {
|
||||
g.output(warningLog, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func (g *loggerT) Error(args ...any) {
|
||||
g.output(errorLog, fmt.Sprint(args...))
|
||||
}
|
||||
|
||||
func (g *loggerT) Errorln(args ...any) {
|
||||
g.output(errorLog, fmt.Sprintln(args...))
|
||||
}
|
||||
|
||||
func (g *loggerT) Errorf(format string, args ...any) {
|
||||
g.output(errorLog, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func (g *loggerT) Fatal(args ...any) {
|
||||
g.output(fatalLog, fmt.Sprint(args...))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (g *loggerT) Fatalln(args ...any) {
|
||||
g.output(fatalLog, fmt.Sprintln(args...))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (g *loggerT) Fatalf(format string, args ...any) {
|
||||
g.output(fatalLog, fmt.Sprintf(format, args...))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (g *loggerT) V(l int) bool {
|
||||
return l <= g.v
|
||||
}
|
||||
|
||||
// LoggerV2Config configures the LoggerV2 implementation.
|
||||
type LoggerV2Config struct {
|
||||
// Verbosity sets the verbosity level of the logger.
|
||||
Verbosity int
|
||||
// FormatJSON controls whether the logger should output logs in JSON format.
|
||||
FormatJSON bool
|
||||
}
|
||||
|
||||
// NewLoggerV2 creates a new LoggerV2 instance with the provided configuration.
|
||||
// The infoW, warningW, and errorW writers are used to write log messages of
|
||||
// different severity levels.
|
||||
func NewLoggerV2(infoW, warningW, errorW io.Writer, c LoggerV2Config) LoggerV2 {
|
||||
var m []*log.Logger
|
||||
flag := log.LstdFlags
|
||||
if c.FormatJSON {
|
||||
flag = 0
|
||||
}
|
||||
m = append(m, log.New(infoW, "", flag))
|
||||
m = append(m, log.New(io.MultiWriter(infoW, warningW), "", flag))
|
||||
ew := io.MultiWriter(infoW, warningW, errorW) // ew will be used for error and fatal.
|
||||
m = append(m, log.New(ew, "", flag))
|
||||
m = append(m, log.New(ew, "", flag))
|
||||
return &loggerT{m: m, v: c.Verbosity, jsonFormat: c.FormatJSON}
|
||||
}
|
|
@ -18,70 +18,17 @@
|
|||
|
||||
package grpclog
|
||||
|
||||
import "google.golang.org/grpc/internal/grpclog"
|
||||
import "google.golang.org/grpc/grpclog/internal"
|
||||
|
||||
// Logger mimics golang's standard Logger as an interface.
|
||||
//
|
||||
// Deprecated: use LoggerV2.
|
||||
type Logger interface {
|
||||
Fatal(args ...any)
|
||||
Fatalf(format string, args ...any)
|
||||
Fatalln(args ...any)
|
||||
Print(args ...any)
|
||||
Printf(format string, args ...any)
|
||||
Println(args ...any)
|
||||
}
|
||||
type Logger internal.Logger
|
||||
|
||||
// SetLogger sets the logger that is used in grpc. Call only from
|
||||
// init() functions.
|
||||
//
|
||||
// Deprecated: use SetLoggerV2.
|
||||
func SetLogger(l Logger) {
|
||||
grpclog.Logger = &loggerWrapper{Logger: l}
|
||||
}
|
||||
|
||||
// loggerWrapper wraps Logger into a LoggerV2.
|
||||
type loggerWrapper struct {
|
||||
Logger
|
||||
}
|
||||
|
||||
func (g *loggerWrapper) Info(args ...any) {
|
||||
g.Logger.Print(args...)
|
||||
}
|
||||
|
||||
func (g *loggerWrapper) Infoln(args ...any) {
|
||||
g.Logger.Println(args...)
|
||||
}
|
||||
|
||||
func (g *loggerWrapper) Infof(format string, args ...any) {
|
||||
g.Logger.Printf(format, args...)
|
||||
}
|
||||
|
||||
func (g *loggerWrapper) Warning(args ...any) {
|
||||
g.Logger.Print(args...)
|
||||
}
|
||||
|
||||
func (g *loggerWrapper) Warningln(args ...any) {
|
||||
g.Logger.Println(args...)
|
||||
}
|
||||
|
||||
func (g *loggerWrapper) Warningf(format string, args ...any) {
|
||||
g.Logger.Printf(format, args...)
|
||||
}
|
||||
|
||||
func (g *loggerWrapper) Error(args ...any) {
|
||||
g.Logger.Print(args...)
|
||||
}
|
||||
|
||||
func (g *loggerWrapper) Errorln(args ...any) {
|
||||
g.Logger.Println(args...)
|
||||
}
|
||||
|
||||
func (g *loggerWrapper) Errorf(format string, args ...any) {
|
||||
g.Logger.Printf(format, args...)
|
||||
}
|
||||
|
||||
func (g *loggerWrapper) V(l int) bool {
|
||||
// Returns true for all verbose level.
|
||||
return true
|
||||
internal.LoggerV2Impl = &internal.LoggerWrapper{Logger: l}
|
||||
}
|
||||
|
|
|
@ -19,52 +19,16 @@
|
|||
package grpclog
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/grpc/internal/grpclog"
|
||||
"google.golang.org/grpc/grpclog/internal"
|
||||
)
|
||||
|
||||
// LoggerV2 does underlying logging work for grpclog.
|
||||
type LoggerV2 interface {
|
||||
// Info logs to INFO log. Arguments are handled in the manner of fmt.Print.
|
||||
Info(args ...any)
|
||||
// Infoln logs to INFO log. Arguments are handled in the manner of fmt.Println.
|
||||
Infoln(args ...any)
|
||||
// Infof logs to INFO log. Arguments are handled in the manner of fmt.Printf.
|
||||
Infof(format string, args ...any)
|
||||
// Warning logs to WARNING log. Arguments are handled in the manner of fmt.Print.
|
||||
Warning(args ...any)
|
||||
// Warningln logs to WARNING log. Arguments are handled in the manner of fmt.Println.
|
||||
Warningln(args ...any)
|
||||
// Warningf logs to WARNING log. Arguments are handled in the manner of fmt.Printf.
|
||||
Warningf(format string, args ...any)
|
||||
// Error logs to ERROR log. Arguments are handled in the manner of fmt.Print.
|
||||
Error(args ...any)
|
||||
// Errorln logs to ERROR log. Arguments are handled in the manner of fmt.Println.
|
||||
Errorln(args ...any)
|
||||
// Errorf logs to ERROR log. Arguments are handled in the manner of fmt.Printf.
|
||||
Errorf(format string, args ...any)
|
||||
// Fatal logs to ERROR log. Arguments are handled in the manner of fmt.Print.
|
||||
// gRPC ensures that all Fatal logs will exit with os.Exit(1).
|
||||
// Implementations may also call os.Exit() with a non-zero exit code.
|
||||
Fatal(args ...any)
|
||||
// Fatalln logs to ERROR log. Arguments are handled in the manner of fmt.Println.
|
||||
// gRPC ensures that all Fatal logs will exit with os.Exit(1).
|
||||
// Implementations may also call os.Exit() with a non-zero exit code.
|
||||
Fatalln(args ...any)
|
||||
// Fatalf logs to ERROR log. Arguments are handled in the manner of fmt.Printf.
|
||||
// gRPC ensures that all Fatal logs will exit with os.Exit(1).
|
||||
// Implementations may also call os.Exit() with a non-zero exit code.
|
||||
Fatalf(format string, args ...any)
|
||||
// V reports whether verbosity level l is at least the requested verbose level.
|
||||
V(l int) bool
|
||||
}
|
||||
type LoggerV2 internal.LoggerV2
|
||||
|
||||
// SetLoggerV2 sets logger that is used in grpc to a V2 logger.
|
||||
// Not mutex-protected, should be called before any gRPC functions.
|
||||
|
@ -72,34 +36,8 @@ func SetLoggerV2(l LoggerV2) {
|
|||
if _, ok := l.(*componentData); ok {
|
||||
panic("cannot use component logger as grpclog logger")
|
||||
}
|
||||
grpclog.Logger = l
|
||||
grpclog.DepthLogger, _ = l.(grpclog.DepthLoggerV2)
|
||||
}
|
||||
|
||||
const (
|
||||
// infoLog indicates Info severity.
|
||||
infoLog int = iota
|
||||
// warningLog indicates Warning severity.
|
||||
warningLog
|
||||
// errorLog indicates Error severity.
|
||||
errorLog
|
||||
// fatalLog indicates Fatal severity.
|
||||
fatalLog
|
||||
)
|
||||
|
||||
// severityName contains the string representation of each severity.
|
||||
var severityName = []string{
|
||||
infoLog: "INFO",
|
||||
warningLog: "WARNING",
|
||||
errorLog: "ERROR",
|
||||
fatalLog: "FATAL",
|
||||
}
|
||||
|
||||
// loggerT is the default logger used by grpclog.
|
||||
type loggerT struct {
|
||||
m []*log.Logger
|
||||
v int
|
||||
jsonFormat bool
|
||||
internal.LoggerV2Impl = l
|
||||
internal.DepthLoggerV2Impl, _ = l.(internal.DepthLoggerV2)
|
||||
}
|
||||
|
||||
// NewLoggerV2 creates a loggerV2 with the provided writers.
|
||||
|
@ -108,32 +46,13 @@ type loggerT struct {
|
|||
// Warning logs will be written to warningW and infoW.
|
||||
// Info logs will be written to infoW.
|
||||
func NewLoggerV2(infoW, warningW, errorW io.Writer) LoggerV2 {
|
||||
return newLoggerV2WithConfig(infoW, warningW, errorW, loggerV2Config{})
|
||||
return internal.NewLoggerV2(infoW, warningW, errorW, internal.LoggerV2Config{})
|
||||
}
|
||||
|
||||
// NewLoggerV2WithVerbosity creates a loggerV2 with the provided writers and
|
||||
// verbosity level.
|
||||
func NewLoggerV2WithVerbosity(infoW, warningW, errorW io.Writer, v int) LoggerV2 {
|
||||
return newLoggerV2WithConfig(infoW, warningW, errorW, loggerV2Config{verbose: v})
|
||||
}
|
||||
|
||||
type loggerV2Config struct {
|
||||
verbose int
|
||||
jsonFormat bool
|
||||
}
|
||||
|
||||
func newLoggerV2WithConfig(infoW, warningW, errorW io.Writer, c loggerV2Config) LoggerV2 {
|
||||
var m []*log.Logger
|
||||
flag := log.LstdFlags
|
||||
if c.jsonFormat {
|
||||
flag = 0
|
||||
}
|
||||
m = append(m, log.New(infoW, "", flag))
|
||||
m = append(m, log.New(io.MultiWriter(infoW, warningW), "", flag))
|
||||
ew := io.MultiWriter(infoW, warningW, errorW) // ew will be used for error and fatal.
|
||||
m = append(m, log.New(ew, "", flag))
|
||||
m = append(m, log.New(ew, "", flag))
|
||||
return &loggerT{m: m, v: c.verbose, jsonFormat: c.jsonFormat}
|
||||
return internal.NewLoggerV2(infoW, warningW, errorW, internal.LoggerV2Config{Verbosity: v})
|
||||
}
|
||||
|
||||
// newLoggerV2 creates a loggerV2 to be used as default logger.
|
||||
|
@ -161,82 +80,12 @@ func newLoggerV2() LoggerV2 {
|
|||
|
||||
jsonFormat := strings.EqualFold(os.Getenv("GRPC_GO_LOG_FORMATTER"), "json")
|
||||
|
||||
return newLoggerV2WithConfig(infoW, warningW, errorW, loggerV2Config{
|
||||
verbose: v,
|
||||
jsonFormat: jsonFormat,
|
||||
return internal.NewLoggerV2(infoW, warningW, errorW, internal.LoggerV2Config{
|
||||
Verbosity: v,
|
||||
FormatJSON: jsonFormat,
|
||||
})
|
||||
}
|
||||
|
||||
func (g *loggerT) output(severity int, s string) {
|
||||
sevStr := severityName[severity]
|
||||
if !g.jsonFormat {
|
||||
g.m[severity].Output(2, fmt.Sprintf("%v: %v", sevStr, s))
|
||||
return
|
||||
}
|
||||
// TODO: we can also include the logging component, but that needs more
|
||||
// (API) changes.
|
||||
b, _ := json.Marshal(map[string]string{
|
||||
"severity": sevStr,
|
||||
"message": s,
|
||||
})
|
||||
g.m[severity].Output(2, string(b))
|
||||
}
|
||||
|
||||
func (g *loggerT) Info(args ...any) {
|
||||
g.output(infoLog, fmt.Sprint(args...))
|
||||
}
|
||||
|
||||
func (g *loggerT) Infoln(args ...any) {
|
||||
g.output(infoLog, fmt.Sprintln(args...))
|
||||
}
|
||||
|
||||
func (g *loggerT) Infof(format string, args ...any) {
|
||||
g.output(infoLog, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func (g *loggerT) Warning(args ...any) {
|
||||
g.output(warningLog, fmt.Sprint(args...))
|
||||
}
|
||||
|
||||
func (g *loggerT) Warningln(args ...any) {
|
||||
g.output(warningLog, fmt.Sprintln(args...))
|
||||
}
|
||||
|
||||
func (g *loggerT) Warningf(format string, args ...any) {
|
||||
g.output(warningLog, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func (g *loggerT) Error(args ...any) {
|
||||
g.output(errorLog, fmt.Sprint(args...))
|
||||
}
|
||||
|
||||
func (g *loggerT) Errorln(args ...any) {
|
||||
g.output(errorLog, fmt.Sprintln(args...))
|
||||
}
|
||||
|
||||
func (g *loggerT) Errorf(format string, args ...any) {
|
||||
g.output(errorLog, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func (g *loggerT) Fatal(args ...any) {
|
||||
g.output(fatalLog, fmt.Sprint(args...))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (g *loggerT) Fatalln(args ...any) {
|
||||
g.output(fatalLog, fmt.Sprintln(args...))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (g *loggerT) Fatalf(format string, args ...any) {
|
||||
g.output(fatalLog, fmt.Sprintf(format, args...))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (g *loggerT) V(l int) bool {
|
||||
return l <= g.v
|
||||
}
|
||||
|
||||
// DepthLoggerV2 logs at a specified call frame. If a LoggerV2 also implements
|
||||
// DepthLoggerV2, the below functions will be called with the appropriate stack
|
||||
// depth set for trivial functions the logger may ignore.
|
||||
|
@ -245,14 +94,4 @@ func (g *loggerT) V(l int) bool {
|
|||
//
|
||||
// Notice: This type is EXPERIMENTAL and may be changed or removed in a
|
||||
// later release.
|
||||
type DepthLoggerV2 interface {
|
||||
LoggerV2
|
||||
// InfoDepth logs to INFO log at the specified depth. Arguments are handled in the manner of fmt.Println.
|
||||
InfoDepth(depth int, args ...any)
|
||||
// WarningDepth logs to WARNING log at the specified depth. Arguments are handled in the manner of fmt.Println.
|
||||
WarningDepth(depth int, args ...any)
|
||||
// ErrorDepth logs to ERROR log at the specified depth. Arguments are handled in the manner of fmt.Println.
|
||||
ErrorDepth(depth int, args ...any)
|
||||
// FatalDepth logs to FATAL log at the specified depth. Arguments are handled in the manner of fmt.Println.
|
||||
FatalDepth(depth int, args ...any)
|
||||
}
|
||||
type DepthLoggerV2 internal.DepthLoggerV2
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.34.1
|
||||
// protoc v4.25.2
|
||||
// protoc v5.27.1
|
||||
// source: grpc/health/v1/health.proto
|
||||
|
||||
package grpc_health_v1
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.4.0
|
||||
// - protoc v4.25.2
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc v5.27.1
|
||||
// source: grpc/health/v1/health.proto
|
||||
|
||||
package grpc_health_v1
|
||||
|
@ -32,8 +32,8 @@ import (
|
|||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.62.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion8
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
Health_Check_FullMethodName = "/grpc.health.v1.Health/Check"
|
||||
|
@ -73,7 +73,7 @@ type HealthClient interface {
|
|||
// should assume this method is not supported and should not retry the
|
||||
// call. If the call terminates with any other status (including OK),
|
||||
// clients should retry the call with appropriate exponential backoff.
|
||||
Watch(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (Health_WatchClient, error)
|
||||
Watch(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[HealthCheckResponse], error)
|
||||
}
|
||||
|
||||
type healthClient struct {
|
||||
|
@ -94,13 +94,13 @@ func (c *healthClient) Check(ctx context.Context, in *HealthCheckRequest, opts .
|
|||
return out, nil
|
||||
}
|
||||
|
||||
func (c *healthClient) Watch(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (Health_WatchClient, error) {
|
||||
func (c *healthClient) Watch(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[HealthCheckResponse], error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &Health_ServiceDesc.Streams[0], Health_Watch_FullMethodName, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &healthWatchClient{ClientStream: stream}
|
||||
x := &grpc.GenericClientStream[HealthCheckRequest, HealthCheckResponse]{ClientStream: stream}
|
||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -110,26 +110,12 @@ func (c *healthClient) Watch(ctx context.Context, in *HealthCheckRequest, opts .
|
|||
return x, nil
|
||||
}
|
||||
|
||||
type Health_WatchClient interface {
|
||||
Recv() (*HealthCheckResponse, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
type healthWatchClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *healthWatchClient) Recv() (*HealthCheckResponse, error) {
|
||||
m := new(HealthCheckResponse)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type Health_WatchClient = grpc.ServerStreamingClient[HealthCheckResponse]
|
||||
|
||||
// HealthServer is the server API for Health service.
|
||||
// All implementations should embed UnimplementedHealthServer
|
||||
// for forward compatibility
|
||||
// for forward compatibility.
|
||||
//
|
||||
// Health is gRPC's mechanism for checking whether a server is able to handle
|
||||
// RPCs. Its semantics are documented in
|
||||
|
@ -160,19 +146,23 @@ type HealthServer interface {
|
|||
// should assume this method is not supported and should not retry the
|
||||
// call. If the call terminates with any other status (including OK),
|
||||
// clients should retry the call with appropriate exponential backoff.
|
||||
Watch(*HealthCheckRequest, Health_WatchServer) error
|
||||
Watch(*HealthCheckRequest, grpc.ServerStreamingServer[HealthCheckResponse]) error
|
||||
}
|
||||
|
||||
// UnimplementedHealthServer should be embedded to have forward compatible implementations.
|
||||
type UnimplementedHealthServer struct {
|
||||
}
|
||||
// UnimplementedHealthServer should be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedHealthServer struct{}
|
||||
|
||||
func (UnimplementedHealthServer) Check(context.Context, *HealthCheckRequest) (*HealthCheckResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Check not implemented")
|
||||
}
|
||||
func (UnimplementedHealthServer) Watch(*HealthCheckRequest, Health_WatchServer) error {
|
||||
func (UnimplementedHealthServer) Watch(*HealthCheckRequest, grpc.ServerStreamingServer[HealthCheckResponse]) error {
|
||||
return status.Errorf(codes.Unimplemented, "method Watch not implemented")
|
||||
}
|
||||
func (UnimplementedHealthServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeHealthServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to HealthServer will
|
||||
|
@ -182,6 +172,13 @@ type UnsafeHealthServer interface {
|
|||
}
|
||||
|
||||
func RegisterHealthServer(s grpc.ServiceRegistrar, srv HealthServer) {
|
||||
// If the following call panics, it indicates UnimplementedHealthServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&Health_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
|
@ -208,21 +205,11 @@ func _Health_Watch_Handler(srv interface{}, stream grpc.ServerStream) error {
|
|||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(HealthServer).Watch(m, &healthWatchServer{ServerStream: stream})
|
||||
return srv.(HealthServer).Watch(m, &grpc.GenericServerStream[HealthCheckRequest, HealthCheckResponse]{ServerStream: stream})
|
||||
}
|
||||
|
||||
type Health_WatchServer interface {
|
||||
Send(*HealthCheckResponse) error
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type healthWatchServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *healthWatchServer) Send(m *HealthCheckResponse) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type Health_WatchServer = grpc.ServerStreamingServer[HealthCheckResponse]
|
||||
|
||||
// Health_ServiceDesc is the grpc.ServiceDesc for Health service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
|
|
|
@ -46,7 +46,7 @@ type entry interface {
|
|||
|
||||
// channelMap is the storage data structure for channelz.
|
||||
//
|
||||
// Methods of channelMap can be divided in two two categories with respect to
|
||||
// Methods of channelMap can be divided into two categories with respect to
|
||||
// locking.
|
||||
//
|
||||
// 1. Methods acquire the global lock.
|
||||
|
|
|
@ -46,6 +46,10 @@ var (
|
|||
// by setting the environment variable "GRPC_ENFORCE_ALPN_ENABLED" to "true"
|
||||
// or "false".
|
||||
EnforceALPNEnabled = boolFromEnv("GRPC_ENFORCE_ALPN_ENABLED", false)
|
||||
// XDSFallbackSupport is the env variable that controls whether support for
|
||||
// xDS fallback is turned on. If this is unset or is false, only the first
|
||||
// xDS server in the list of server configs will be used.
|
||||
XDSFallbackSupport = boolFromEnv("GRPC_EXPERIMENTAL_XDS_FALLBACK", false)
|
||||
)
|
||||
|
||||
func boolFromEnv(envVar string, def bool) bool {
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
package internal
|
||||
|
||||
var (
|
||||
// WithRecvBufferPool is implemented by the grpc package and returns a dial
|
||||
// WithBufferPool is implemented by the grpc package and returns a dial
|
||||
// option to configure a shared buffer pool for a grpc.ClientConn.
|
||||
WithRecvBufferPool any // func (grpc.SharedBufferPool) grpc.DialOption
|
||||
WithBufferPool any // func (grpc.SharedBufferPool) grpc.DialOption
|
||||
|
||||
// RecvBufferPool is implemented by the grpc package and returns a server
|
||||
// BufferPool is implemented by the grpc package and returns a server
|
||||
// option to configure a shared buffer pool for a grpc.Server.
|
||||
RecvBufferPool any // func (grpc.SharedBufferPool) grpc.ServerOption
|
||||
BufferPool any // func (grpc.SharedBufferPool) grpc.ServerOption
|
||||
)
|
||||
|
|
|
@ -16,17 +16,21 @@
|
|||
*
|
||||
*/
|
||||
|
||||
// Package grpclog provides logging functionality for internal gRPC packages,
|
||||
// outside of the functionality provided by the external `grpclog` package.
|
||||
package grpclog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/grpc/grpclog"
|
||||
)
|
||||
|
||||
// PrefixLogger does logging with a prefix.
|
||||
//
|
||||
// Logging method on a nil logs without any prefix.
|
||||
type PrefixLogger struct {
|
||||
logger DepthLoggerV2
|
||||
logger grpclog.DepthLoggerV2
|
||||
prefix string
|
||||
}
|
||||
|
||||
|
@ -38,7 +42,7 @@ func (pl *PrefixLogger) Infof(format string, args ...any) {
|
|||
pl.logger.InfoDepth(1, fmt.Sprintf(format, args...))
|
||||
return
|
||||
}
|
||||
InfoDepth(1, fmt.Sprintf(format, args...))
|
||||
grpclog.InfoDepth(1, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// Warningf does warning logging.
|
||||
|
@ -48,7 +52,7 @@ func (pl *PrefixLogger) Warningf(format string, args ...any) {
|
|||
pl.logger.WarningDepth(1, fmt.Sprintf(format, args...))
|
||||
return
|
||||
}
|
||||
WarningDepth(1, fmt.Sprintf(format, args...))
|
||||
grpclog.WarningDepth(1, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// Errorf does error logging.
|
||||
|
@ -58,36 +62,18 @@ func (pl *PrefixLogger) Errorf(format string, args ...any) {
|
|||
pl.logger.ErrorDepth(1, fmt.Sprintf(format, args...))
|
||||
return
|
||||
}
|
||||
ErrorDepth(1, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// Debugf does info logging at verbose level 2.
|
||||
func (pl *PrefixLogger) Debugf(format string, args ...any) {
|
||||
// TODO(6044): Refactor interfaces LoggerV2 and DepthLogger, and maybe
|
||||
// rewrite PrefixLogger a little to ensure that we don't use the global
|
||||
// `Logger` here, and instead use the `logger` field.
|
||||
if !Logger.V(2) {
|
||||
return
|
||||
}
|
||||
if pl != nil {
|
||||
// Handle nil, so the tests can pass in a nil logger.
|
||||
format = pl.prefix + format
|
||||
pl.logger.InfoDepth(1, fmt.Sprintf(format, args...))
|
||||
return
|
||||
}
|
||||
InfoDepth(1, fmt.Sprintf(format, args...))
|
||||
|
||||
grpclog.ErrorDepth(1, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// V reports whether verbosity level l is at least the requested verbose level.
|
||||
func (pl *PrefixLogger) V(l int) bool {
|
||||
// TODO(6044): Refactor interfaces LoggerV2 and DepthLogger, and maybe
|
||||
// rewrite PrefixLogger a little to ensure that we don't use the global
|
||||
// `Logger` here, and instead use the `logger` field.
|
||||
return Logger.V(l)
|
||||
if pl != nil {
|
||||
return pl.logger.V(l)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// NewPrefixLogger creates a prefix logger with the given prefix.
|
||||
func NewPrefixLogger(logger DepthLoggerV2, prefix string) *PrefixLogger {
|
||||
func NewPrefixLogger(logger grpclog.DepthLoggerV2, prefix string) *PrefixLogger {
|
||||
return &PrefixLogger{logger: logger, prefix: prefix}
|
||||
}
|
|
@ -53,16 +53,28 @@ func NewCallbackSerializer(ctx context.Context) *CallbackSerializer {
|
|||
return cs
|
||||
}
|
||||
|
||||
// Schedule adds a callback to be scheduled after existing callbacks are run.
|
||||
// TrySchedule tries to schedules the provided callback function f to be
|
||||
// executed in the order it was added. This is a best-effort operation. If the
|
||||
// context passed to NewCallbackSerializer was canceled before this method is
|
||||
// called, the callback will not be scheduled.
|
||||
//
|
||||
// Callbacks are expected to honor the context when performing any blocking
|
||||
// operations, and should return early when the context is canceled.
|
||||
func (cs *CallbackSerializer) TrySchedule(f func(ctx context.Context)) {
|
||||
cs.callbacks.Put(f)
|
||||
}
|
||||
|
||||
// ScheduleOr schedules the provided callback function f to be executed in the
|
||||
// order it was added. If the context passed to NewCallbackSerializer has been
|
||||
// canceled before this method is called, the onFailure callback will be
|
||||
// executed inline instead.
|
||||
//
|
||||
// Return value indicates if the callback was successfully added to the list of
|
||||
// callbacks to be executed by the serializer. It is not possible to add
|
||||
// callbacks once the context passed to NewCallbackSerializer is cancelled.
|
||||
func (cs *CallbackSerializer) Schedule(f func(ctx context.Context)) bool {
|
||||
return cs.callbacks.Put(f) == nil
|
||||
// Callbacks are expected to honor the context when performing any blocking
|
||||
// operations, and should return early when the context is canceled.
|
||||
func (cs *CallbackSerializer) ScheduleOr(f func(ctx context.Context), onFailure func()) {
|
||||
if cs.callbacks.Put(f) != nil {
|
||||
onFailure()
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *CallbackSerializer) run(ctx context.Context) {
|
||||
|
|
|
@ -77,7 +77,7 @@ func (ps *PubSub) Subscribe(sub Subscriber) (cancel func()) {
|
|||
|
||||
if ps.msg != nil {
|
||||
msg := ps.msg
|
||||
ps.cs.Schedule(func(context.Context) {
|
||||
ps.cs.TrySchedule(func(context.Context) {
|
||||
ps.mu.Lock()
|
||||
defer ps.mu.Unlock()
|
||||
if !ps.subscribers[sub] {
|
||||
|
@ -103,7 +103,7 @@ func (ps *PubSub) Publish(msg any) {
|
|||
ps.msg = msg
|
||||
for sub := range ps.subscribers {
|
||||
s := sub
|
||||
ps.cs.Schedule(func(context.Context) {
|
||||
ps.cs.TrySchedule(func(context.Context) {
|
||||
ps.mu.Lock()
|
||||
defer ps.mu.Unlock()
|
||||
if !ps.subscribers[s] {
|
||||
|
|
|
@ -208,6 +208,27 @@ var (
|
|||
// ShuffleAddressListForTesting pseudo-randomizes the order of addresses. n
|
||||
// is the number of elements. swap swaps the elements with indexes i and j.
|
||||
ShuffleAddressListForTesting any // func(n int, swap func(i, j int))
|
||||
|
||||
// ConnectedAddress returns the connected address for a SubConnState. The
|
||||
// address is only valid if the state is READY.
|
||||
ConnectedAddress any // func (scs SubConnState) resolver.Address
|
||||
|
||||
// SetConnectedAddress sets the connected address for a SubConnState.
|
||||
SetConnectedAddress any // func(scs *SubConnState, addr resolver.Address)
|
||||
|
||||
// SnapshotMetricRegistryForTesting snapshots the global data of the metric
|
||||
// registry. Registers a cleanup function on the provided testing.T that
|
||||
// sets the metric registry to its original state. Only called in testing
|
||||
// functions.
|
||||
SnapshotMetricRegistryForTesting any // func(t *testing.T)
|
||||
|
||||
// SetDefaultBufferPoolForTesting updates the default buffer pool, for
|
||||
// testing purposes.
|
||||
SetDefaultBufferPoolForTesting any // func(mem.BufferPool)
|
||||
|
||||
// SetBufferPoolingThresholdForTesting updates the buffer pooling threshold, for
|
||||
// testing purposes.
|
||||
SetBufferPoolingThresholdForTesting any // func(int)
|
||||
)
|
||||
|
||||
// HealthChecker defines the signature of the client-side LB channel health
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
*
|
||||
* Copyright 2024 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
// Package stats provides internal stats related functionality.
|
||||
package stats
|
||||
|
||||
import "context"
|
||||
|
||||
// Labels are the labels for metrics.
|
||||
type Labels struct {
|
||||
// TelemetryLabels are the telemetry labels to record.
|
||||
TelemetryLabels map[string]string
|
||||
}
|
||||
|
||||
type labelsKey struct{}
|
||||
|
||||
// GetLabels returns the Labels stored in the context, or nil if there is one.
|
||||
func GetLabels(ctx context.Context) *Labels {
|
||||
labels, _ := ctx.Value(labelsKey{}).(*Labels)
|
||||
return labels
|
||||
}
|
||||
|
||||
// SetLabels sets the Labels in the context.
|
||||
func SetLabels(ctx context.Context, labels *Labels) context.Context {
|
||||
// could also append
|
||||
return context.WithValue(ctx, labelsKey{}, labels)
|
||||
}
|
95
vendor/google.golang.org/grpc/internal/stats/metrics_recorder_list.go
generated
vendored
Normal file
95
vendor/google.golang.org/grpc/internal/stats/metrics_recorder_list.go
generated
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright 2024 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package stats
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
estats "google.golang.org/grpc/experimental/stats"
|
||||
"google.golang.org/grpc/stats"
|
||||
)
|
||||
|
||||
// MetricsRecorderList forwards Record calls to all of its metricsRecorders.
|
||||
//
|
||||
// It eats any record calls where the label values provided do not match the
|
||||
// number of label keys.
|
||||
type MetricsRecorderList struct {
|
||||
// metricsRecorders are the metrics recorders this list will forward to.
|
||||
metricsRecorders []estats.MetricsRecorder
|
||||
}
|
||||
|
||||
// NewMetricsRecorderList creates a new metric recorder list with all the stats
|
||||
// handlers provided which implement the MetricsRecorder interface.
|
||||
// If no stats handlers provided implement the MetricsRecorder interface,
|
||||
// the MetricsRecorder list returned is a no-op.
|
||||
func NewMetricsRecorderList(shs []stats.Handler) *MetricsRecorderList {
|
||||
var mrs []estats.MetricsRecorder
|
||||
for _, sh := range shs {
|
||||
if mr, ok := sh.(estats.MetricsRecorder); ok {
|
||||
mrs = append(mrs, mr)
|
||||
}
|
||||
}
|
||||
return &MetricsRecorderList{
|
||||
metricsRecorders: mrs,
|
||||
}
|
||||
}
|
||||
|
||||
func verifyLabels(desc *estats.MetricDescriptor, labelsRecv ...string) {
|
||||
if got, want := len(labelsRecv), len(desc.Labels)+len(desc.OptionalLabels); got != want {
|
||||
panic(fmt.Sprintf("Received %d labels in call to record metric %q, but expected %d.", got, desc.Name, want))
|
||||
}
|
||||
}
|
||||
|
||||
func (l *MetricsRecorderList) RecordInt64Count(handle *estats.Int64CountHandle, incr int64, labels ...string) {
|
||||
verifyLabels(handle.Descriptor(), labels...)
|
||||
|
||||
for _, metricRecorder := range l.metricsRecorders {
|
||||
metricRecorder.RecordInt64Count(handle, incr, labels...)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *MetricsRecorderList) RecordFloat64Count(handle *estats.Float64CountHandle, incr float64, labels ...string) {
|
||||
verifyLabels(handle.Descriptor(), labels...)
|
||||
|
||||
for _, metricRecorder := range l.metricsRecorders {
|
||||
metricRecorder.RecordFloat64Count(handle, incr, labels...)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *MetricsRecorderList) RecordInt64Histo(handle *estats.Int64HistoHandle, incr int64, labels ...string) {
|
||||
verifyLabels(handle.Descriptor(), labels...)
|
||||
|
||||
for _, metricRecorder := range l.metricsRecorders {
|
||||
metricRecorder.RecordInt64Histo(handle, incr, labels...)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *MetricsRecorderList) RecordFloat64Histo(handle *estats.Float64HistoHandle, incr float64, labels ...string) {
|
||||
verifyLabels(handle.Descriptor(), labels...)
|
||||
|
||||
for _, metricRecorder := range l.metricsRecorders {
|
||||
metricRecorder.RecordFloat64Histo(handle, incr, labels...)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *MetricsRecorderList) RecordInt64Gauge(handle *estats.Int64GaugeHandle, incr int64, labels ...string) {
|
||||
verifyLabels(handle.Descriptor(), labels...)
|
||||
|
||||
for _, metricRecorder := range l.metricsRecorders {
|
||||
metricRecorder.RecordInt64Gauge(handle, incr, labels...)
|
||||
}
|
||||
}
|
|
@ -44,7 +44,7 @@ func NetDialerWithTCPKeepalive() *net.Dialer {
|
|||
// combination of unconditionally enabling TCP keepalives here, and
|
||||
// disabling the overriding of TCP keepalive parameters by setting the
|
||||
// KeepAlive field to a negative value above, results in OS defaults for
|
||||
// the TCP keealive interval and time parameters.
|
||||
// the TCP keepalive interval and time parameters.
|
||||
Control: func(_, _ string, c syscall.RawConn) error {
|
||||
return c.Control(func(fd uintptr) {
|
||||
unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_KEEPALIVE, 1)
|
||||
|
|
|
@ -44,7 +44,7 @@ func NetDialerWithTCPKeepalive() *net.Dialer {
|
|||
// combination of unconditionally enabling TCP keepalives here, and
|
||||
// disabling the overriding of TCP keepalive parameters by setting the
|
||||
// KeepAlive field to a negative value above, results in OS defaults for
|
||||
// the TCP keealive interval and time parameters.
|
||||
// the TCP keepalive interval and time parameters.
|
||||
Control: func(_, _ string, c syscall.RawConn) error {
|
||||
return c.Control(func(fd uintptr) {
|
||||
windows.SetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_KEEPALIVE, 1)
|
||||
|
|
|
@ -32,6 +32,7 @@ import (
|
|||
"golang.org/x/net/http2/hpack"
|
||||
"google.golang.org/grpc/internal/grpclog"
|
||||
"google.golang.org/grpc/internal/grpcutil"
|
||||
"google.golang.org/grpc/mem"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
|
@ -148,9 +149,9 @@ type dataFrame struct {
|
|||
streamID uint32
|
||||
endStream bool
|
||||
h []byte
|
||||
d []byte
|
||||
reader mem.Reader
|
||||
// onEachWrite is called every time
|
||||
// a part of d is written out.
|
||||
// a part of data is written out.
|
||||
onEachWrite func()
|
||||
}
|
||||
|
||||
|
@ -289,18 +290,22 @@ func (l *outStreamList) dequeue() *outStream {
|
|||
}
|
||||
|
||||
// controlBuffer is a way to pass information to loopy.
|
||||
// Information is passed as specific struct types called control frames.
|
||||
// A control frame not only represents data, messages or headers to be sent out
|
||||
// but can also be used to instruct loopy to update its internal state.
|
||||
// It shouldn't be confused with an HTTP2 frame, although some of the control frames
|
||||
// like dataFrame and headerFrame do go out on wire as HTTP2 frames.
|
||||
//
|
||||
// Information is passed as specific struct types called control frames. A
|
||||
// control frame not only represents data, messages or headers to be sent out
|
||||
// but can also be used to instruct loopy to update its internal state. It
|
||||
// shouldn't be confused with an HTTP2 frame, although some of the control
|
||||
// frames like dataFrame and headerFrame do go out on wire as HTTP2 frames.
|
||||
type controlBuffer struct {
|
||||
ch chan struct{}
|
||||
done <-chan struct{}
|
||||
wakeupCh chan struct{} // Unblocks readers waiting for something to read.
|
||||
done <-chan struct{} // Closed when the transport is done.
|
||||
|
||||
// Mutex guards all the fields below, except trfChan which can be read
|
||||
// atomically without holding mu.
|
||||
mu sync.Mutex
|
||||
consumerWaiting bool
|
||||
list *itemList
|
||||
err error
|
||||
consumerWaiting bool // True when readers are blocked waiting for new data.
|
||||
closed bool // True when the controlbuf is finished.
|
||||
list *itemList // List of queued control frames.
|
||||
|
||||
// transportResponseFrames counts the number of queued items that represent
|
||||
// the response of an action initiated by the peer. trfChan is created
|
||||
|
@ -308,47 +313,59 @@ type controlBuffer struct {
|
|||
// closed and nilled when transportResponseFrames drops below the
|
||||
// threshold. Both fields are protected by mu.
|
||||
transportResponseFrames int
|
||||
trfChan atomic.Value // chan struct{}
|
||||
trfChan atomic.Pointer[chan struct{}]
|
||||
}
|
||||
|
||||
func newControlBuffer(done <-chan struct{}) *controlBuffer {
|
||||
return &controlBuffer{
|
||||
ch: make(chan struct{}, 1),
|
||||
list: &itemList{},
|
||||
done: done,
|
||||
wakeupCh: make(chan struct{}, 1),
|
||||
list: &itemList{},
|
||||
done: done,
|
||||
}
|
||||
}
|
||||
|
||||
// throttle blocks if there are too many incomingSettings/cleanupStreams in the
|
||||
// controlbuf.
|
||||
// throttle blocks if there are too many frames in the control buf that
|
||||
// represent the response of an action initiated by the peer, like
|
||||
// incomingSettings cleanupStreams etc.
|
||||
func (c *controlBuffer) throttle() {
|
||||
ch, _ := c.trfChan.Load().(chan struct{})
|
||||
if ch != nil {
|
||||
if ch := c.trfChan.Load(); ch != nil {
|
||||
select {
|
||||
case <-ch:
|
||||
case <-(*ch):
|
||||
case <-c.done:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// put adds an item to the controlbuf.
|
||||
func (c *controlBuffer) put(it cbItem) error {
|
||||
_, err := c.executeAndPut(nil, it)
|
||||
return err
|
||||
}
|
||||
|
||||
// executeAndPut runs f, and if the return value is true, adds the given item to
|
||||
// the controlbuf. The item could be nil, in which case, this method simply
|
||||
// executes f and does not add the item to the controlbuf.
|
||||
//
|
||||
// The first return value indicates whether the item was successfully added to
|
||||
// the control buffer. A non-nil error, specifically ErrConnClosing, is returned
|
||||
// if the control buffer is already closed.
|
||||
func (c *controlBuffer) executeAndPut(f func() bool, it cbItem) (bool, error) {
|
||||
var wakeUp bool
|
||||
c.mu.Lock()
|
||||
if c.err != nil {
|
||||
c.mu.Unlock()
|
||||
return false, c.err
|
||||
defer c.mu.Unlock()
|
||||
|
||||
if c.closed {
|
||||
return false, ErrConnClosing
|
||||
}
|
||||
if f != nil {
|
||||
if !f() { // f wasn't successful
|
||||
c.mu.Unlock()
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
if it == nil {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
var wakeUp bool
|
||||
if c.consumerWaiting {
|
||||
wakeUp = true
|
||||
c.consumerWaiting = false
|
||||
|
@ -359,98 +376,102 @@ func (c *controlBuffer) executeAndPut(f func() bool, it cbItem) (bool, error) {
|
|||
if c.transportResponseFrames == maxQueuedTransportResponseFrames {
|
||||
// We are adding the frame that puts us over the threshold; create
|
||||
// a throttling channel.
|
||||
c.trfChan.Store(make(chan struct{}))
|
||||
ch := make(chan struct{})
|
||||
c.trfChan.Store(&ch)
|
||||
}
|
||||
}
|
||||
c.mu.Unlock()
|
||||
if wakeUp {
|
||||
select {
|
||||
case c.ch <- struct{}{}:
|
||||
case c.wakeupCh <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Note argument f should never be nil.
|
||||
func (c *controlBuffer) execute(f func(it any) bool, it any) (bool, error) {
|
||||
c.mu.Lock()
|
||||
if c.err != nil {
|
||||
c.mu.Unlock()
|
||||
return false, c.err
|
||||
}
|
||||
if !f(it) { // f wasn't successful
|
||||
c.mu.Unlock()
|
||||
return false, nil
|
||||
}
|
||||
c.mu.Unlock()
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// get returns the next control frame from the control buffer. If block is true
|
||||
// **and** there are no control frames in the control buffer, the call blocks
|
||||
// until one of the conditions is met: there is a frame to return or the
|
||||
// transport is closed.
|
||||
func (c *controlBuffer) get(block bool) (any, error) {
|
||||
for {
|
||||
c.mu.Lock()
|
||||
if c.err != nil {
|
||||
frame, err := c.getOnceLocked()
|
||||
if frame != nil || err != nil || !block {
|
||||
// If we read a frame or an error, we can return to the caller. The
|
||||
// call to getOnceLocked() returns a nil frame and a nil error if
|
||||
// there is nothing to read, and in that case, if the caller asked
|
||||
// us not to block, we can return now as well.
|
||||
c.mu.Unlock()
|
||||
return nil, c.err
|
||||
}
|
||||
if !c.list.isEmpty() {
|
||||
h := c.list.dequeue().(cbItem)
|
||||
if h.isTransportResponseFrame() {
|
||||
if c.transportResponseFrames == maxQueuedTransportResponseFrames {
|
||||
// We are removing the frame that put us over the
|
||||
// threshold; close and clear the throttling channel.
|
||||
ch := c.trfChan.Load().(chan struct{})
|
||||
close(ch)
|
||||
c.trfChan.Store((chan struct{})(nil))
|
||||
}
|
||||
c.transportResponseFrames--
|
||||
}
|
||||
c.mu.Unlock()
|
||||
return h, nil
|
||||
}
|
||||
if !block {
|
||||
c.mu.Unlock()
|
||||
return nil, nil
|
||||
return frame, err
|
||||
}
|
||||
c.consumerWaiting = true
|
||||
c.mu.Unlock()
|
||||
|
||||
// Release the lock above and wait to be woken up.
|
||||
select {
|
||||
case <-c.ch:
|
||||
case <-c.wakeupCh:
|
||||
case <-c.done:
|
||||
return nil, errors.New("transport closed by client")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Callers must not use this method, but should instead use get().
|
||||
//
|
||||
// Caller must hold c.mu.
|
||||
func (c *controlBuffer) getOnceLocked() (any, error) {
|
||||
if c.closed {
|
||||
return false, ErrConnClosing
|
||||
}
|
||||
if c.list.isEmpty() {
|
||||
return nil, nil
|
||||
}
|
||||
h := c.list.dequeue().(cbItem)
|
||||
if h.isTransportResponseFrame() {
|
||||
if c.transportResponseFrames == maxQueuedTransportResponseFrames {
|
||||
// We are removing the frame that put us over the
|
||||
// threshold; close and clear the throttling channel.
|
||||
ch := c.trfChan.Swap(nil)
|
||||
close(*ch)
|
||||
}
|
||||
c.transportResponseFrames--
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
|
||||
// finish closes the control buffer, cleaning up any streams that have queued
|
||||
// header frames. Once this method returns, no more frames can be added to the
|
||||
// control buffer, and attempts to do so will return ErrConnClosing.
|
||||
func (c *controlBuffer) finish() {
|
||||
c.mu.Lock()
|
||||
if c.err != nil {
|
||||
c.mu.Unlock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
if c.closed {
|
||||
return
|
||||
}
|
||||
c.err = ErrConnClosing
|
||||
c.closed = true
|
||||
// There may be headers for streams in the control buffer.
|
||||
// These streams need to be cleaned out since the transport
|
||||
// is still not aware of these yet.
|
||||
for head := c.list.dequeueAll(); head != nil; head = head.next {
|
||||
hdr, ok := head.it.(*headerFrame)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if hdr.onOrphaned != nil { // It will be nil on the server-side.
|
||||
hdr.onOrphaned(ErrConnClosing)
|
||||
switch v := head.it.(type) {
|
||||
case *headerFrame:
|
||||
if v.onOrphaned != nil { // It will be nil on the server-side.
|
||||
v.onOrphaned(ErrConnClosing)
|
||||
}
|
||||
case *dataFrame:
|
||||
_ = v.reader.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// In case throttle() is currently in flight, it needs to be unblocked.
|
||||
// Otherwise, the transport may not close, since the transport is closed by
|
||||
// the reader encountering the connection error.
|
||||
ch, _ := c.trfChan.Load().(chan struct{})
|
||||
ch := c.trfChan.Swap(nil)
|
||||
if ch != nil {
|
||||
close(ch)
|
||||
close(*ch)
|
||||
}
|
||||
c.trfChan.Store((chan struct{})(nil))
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
type side int
|
||||
|
@ -466,7 +487,7 @@ const (
|
|||
// stream maintains a queue of data frames; as loopy receives data frames
|
||||
// it gets added to the queue of the relevant stream.
|
||||
// Loopy goes over this list of active streams by processing one node every iteration,
|
||||
// thereby closely resemebling to a round-robin scheduling over all streams. While
|
||||
// thereby closely resembling a round-robin scheduling over all streams. While
|
||||
// processing a stream, loopy writes out data bytes from this stream capped by the min
|
||||
// of http2MaxFrameLen, connection-level flow control and stream-level flow control.
|
||||
type loopyWriter struct {
|
||||
|
@ -490,12 +511,13 @@ type loopyWriter struct {
|
|||
draining bool
|
||||
conn net.Conn
|
||||
logger *grpclog.PrefixLogger
|
||||
bufferPool mem.BufferPool
|
||||
|
||||
// Side-specific handlers
|
||||
ssGoAwayHandler func(*goAway) (bool, error)
|
||||
}
|
||||
|
||||
func newLoopyWriter(s side, fr *framer, cbuf *controlBuffer, bdpEst *bdpEstimator, conn net.Conn, logger *grpclog.PrefixLogger, goAwayHandler func(*goAway) (bool, error)) *loopyWriter {
|
||||
func newLoopyWriter(s side, fr *framer, cbuf *controlBuffer, bdpEst *bdpEstimator, conn net.Conn, logger *grpclog.PrefixLogger, goAwayHandler func(*goAway) (bool, error), bufferPool mem.BufferPool) *loopyWriter {
|
||||
var buf bytes.Buffer
|
||||
l := &loopyWriter{
|
||||
side: s,
|
||||
|
@ -511,6 +533,7 @@ func newLoopyWriter(s side, fr *framer, cbuf *controlBuffer, bdpEst *bdpEstimato
|
|||
conn: conn,
|
||||
logger: logger,
|
||||
ssGoAwayHandler: goAwayHandler,
|
||||
bufferPool: bufferPool,
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
@ -768,6 +791,11 @@ func (l *loopyWriter) cleanupStreamHandler(c *cleanupStream) error {
|
|||
// not be established yet.
|
||||
delete(l.estdStreams, c.streamID)
|
||||
str.deleteSelf()
|
||||
for head := str.itl.dequeueAll(); head != nil; head = head.next {
|
||||
if df, ok := head.it.(*dataFrame); ok {
|
||||
_ = df.reader.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
if c.rst { // If RST_STREAM needs to be sent.
|
||||
if err := l.framer.fr.WriteRSTStream(c.streamID, c.rstCode); err != nil {
|
||||
|
@ -903,16 +931,18 @@ func (l *loopyWriter) processData() (bool, error) {
|
|||
dataItem := str.itl.peek().(*dataFrame) // Peek at the first data item this stream.
|
||||
// A data item is represented by a dataFrame, since it later translates into
|
||||
// multiple HTTP2 data frames.
|
||||
// Every dataFrame has two buffers; h that keeps grpc-message header and d that is actual data.
|
||||
// As an optimization to keep wire traffic low, data from d is copied to h to make as big as the
|
||||
// maximum possible HTTP2 frame size.
|
||||
// Every dataFrame has two buffers; h that keeps grpc-message header and data
|
||||
// that is the actual message. As an optimization to keep wire traffic low, data
|
||||
// from data is copied to h to make as big as the maximum possible HTTP2 frame
|
||||
// size.
|
||||
|
||||
if len(dataItem.h) == 0 && len(dataItem.d) == 0 { // Empty data frame
|
||||
if len(dataItem.h) == 0 && dataItem.reader.Remaining() == 0 { // Empty data frame
|
||||
// Client sends out empty data frame with endStream = true
|
||||
if err := l.framer.fr.WriteData(dataItem.streamID, dataItem.endStream, nil); err != nil {
|
||||
return false, err
|
||||
}
|
||||
str.itl.dequeue() // remove the empty data item from stream
|
||||
_ = dataItem.reader.Close()
|
||||
if str.itl.isEmpty() {
|
||||
str.state = empty
|
||||
} else if trailer, ok := str.itl.peek().(*headerFrame); ok { // the next item is trailers.
|
||||
|
@ -927,9 +957,7 @@ func (l *loopyWriter) processData() (bool, error) {
|
|||
}
|
||||
return false, nil
|
||||
}
|
||||
var (
|
||||
buf []byte
|
||||
)
|
||||
|
||||
// Figure out the maximum size we can send
|
||||
maxSize := http2MaxFrameLen
|
||||
if strQuota := int(l.oiws) - str.bytesOutStanding; strQuota <= 0 { // stream-level flow control.
|
||||
|
@ -943,43 +971,50 @@ func (l *loopyWriter) processData() (bool, error) {
|
|||
}
|
||||
// Compute how much of the header and data we can send within quota and max frame length
|
||||
hSize := min(maxSize, len(dataItem.h))
|
||||
dSize := min(maxSize-hSize, len(dataItem.d))
|
||||
if hSize != 0 {
|
||||
if dSize == 0 {
|
||||
buf = dataItem.h
|
||||
} else {
|
||||
// We can add some data to grpc message header to distribute bytes more equally across frames.
|
||||
// Copy on the stack to avoid generating garbage
|
||||
var localBuf [http2MaxFrameLen]byte
|
||||
copy(localBuf[:hSize], dataItem.h)
|
||||
copy(localBuf[hSize:], dataItem.d[:dSize])
|
||||
buf = localBuf[:hSize+dSize]
|
||||
}
|
||||
} else {
|
||||
buf = dataItem.d
|
||||
}
|
||||
|
||||
dSize := min(maxSize-hSize, dataItem.reader.Remaining())
|
||||
remainingBytes := len(dataItem.h) + dataItem.reader.Remaining() - hSize - dSize
|
||||
size := hSize + dSize
|
||||
|
||||
var buf *[]byte
|
||||
|
||||
if hSize != 0 && dSize == 0 {
|
||||
buf = &dataItem.h
|
||||
} else {
|
||||
// Note: this is only necessary because the http2.Framer does not support
|
||||
// partially writing a frame, so the sequence must be materialized into a buffer.
|
||||
// TODO: Revisit once https://github.com/golang/go/issues/66655 is addressed.
|
||||
pool := l.bufferPool
|
||||
if pool == nil {
|
||||
// Note that this is only supposed to be nil in tests. Otherwise, stream is
|
||||
// always initialized with a BufferPool.
|
||||
pool = mem.DefaultBufferPool()
|
||||
}
|
||||
buf = pool.Get(size)
|
||||
defer pool.Put(buf)
|
||||
|
||||
copy((*buf)[:hSize], dataItem.h)
|
||||
_, _ = dataItem.reader.Read((*buf)[hSize:])
|
||||
}
|
||||
|
||||
// Now that outgoing flow controls are checked we can replenish str's write quota
|
||||
str.wq.replenish(size)
|
||||
var endStream bool
|
||||
// If this is the last data message on this stream and all of it can be written in this iteration.
|
||||
if dataItem.endStream && len(dataItem.h)+len(dataItem.d) <= size {
|
||||
if dataItem.endStream && remainingBytes == 0 {
|
||||
endStream = true
|
||||
}
|
||||
if dataItem.onEachWrite != nil {
|
||||
dataItem.onEachWrite()
|
||||
}
|
||||
if err := l.framer.fr.WriteData(dataItem.streamID, endStream, buf[:size]); err != nil {
|
||||
if err := l.framer.fr.WriteData(dataItem.streamID, endStream, (*buf)[:size]); err != nil {
|
||||
return false, err
|
||||
}
|
||||
str.bytesOutStanding += size
|
||||
l.sendQuota -= uint32(size)
|
||||
dataItem.h = dataItem.h[hSize:]
|
||||
dataItem.d = dataItem.d[dSize:]
|
||||
|
||||
if len(dataItem.h) == 0 && len(dataItem.d) == 0 { // All the data from that message was written out.
|
||||
if remainingBytes == 0 { // All the data from that message was written out.
|
||||
_ = dataItem.reader.Close()
|
||||
str.itl.dequeue()
|
||||
}
|
||||
if str.itl.isEmpty() {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue