diff --git a/cmd/ingress-operator/start.go b/cmd/ingress-operator/start.go
index d9053f862a..ace92620d9 100644
--- a/cmd/ingress-operator/start.go
+++ b/cmd/ingress-operator/start.go
@@ -36,7 +36,7 @@ const (
defaultGatewayAPIOperatorCatalog = "redhat-operators"
defaultGatewayAPIOperatorChannel = "stable"
defaultGatewayAPIOperatorVersion = "servicemeshoperator3.v3.2.0"
- defaultIstioVersion = "v1.27.3"
+ defaultIstioVersion = "v1.27.5"
)
type StartOptions struct {
diff --git a/go.mod b/go.mod
index 651a8f3885..54bd964896 100644
--- a/go.mod
+++ b/go.mod
@@ -19,8 +19,8 @@ require (
github.com/go-logr/zapr v1.3.0
github.com/google/go-cmp v0.7.0
github.com/google/gopacket v1.1.19
- github.com/istio-ecosystem/sail-operator v0.0.0-20250513111011-30be83268d6b
- github.com/openshift/api v0.0.0-20251214014457-bfa868a22401
+ github.com/istio-ecosystem/sail-operator v0.0.0-20260212113734-df7c3ff58926
+ github.com/openshift/api v0.0.0-20260223154456-de86ee3bf481
github.com/openshift/client-go v0.0.0-20251205093018-96a6cbc1420c
github.com/openshift/library-go v0.0.0-20251021141706-f489e811f030
github.com/operator-framework/api v0.30.0
@@ -32,9 +32,9 @@ require (
github.com/summerwind/h2spec v0.0.0-20200804131034-70ac22940108
github.com/tcnksm/go-httpstat v0.2.1-0.20191008022543-e866bb274419
go.uber.org/zap v1.27.0
- golang.org/x/time v0.12.0
+ golang.org/x/time v0.14.0
google.golang.org/api v0.126.0
- google.golang.org/grpc v1.75.1
+ google.golang.org/grpc v1.78.0
gopkg.in/fsnotify.v1 v1.4.7
gopkg.in/yaml.v2 v2.4.0
k8s.io/api v0.35.0
@@ -42,113 +42,177 @@ require (
k8s.io/apimachinery v0.35.0
k8s.io/apiserver v0.35.0
k8s.io/client-go v0.35.0
- k8s.io/utils v0.0.0-20251002143259-bc988d571ff4
+ k8s.io/utils v0.0.0-20251219084037-98d557b7f1e7
sigs.k8s.io/controller-runtime v0.23.1
sigs.k8s.io/gateway-api v1.4.1
)
require (
- cloud.google.com/go/compute/metadata v0.7.0 // indirect
+ cloud.google.com/go/compute/metadata v0.9.0 // indirect
+ dario.cat/mergo v1.0.2 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.3.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1 // indirect
+ github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.20 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 // indirect
+ github.com/BurntSushi/toml v1.5.0 // indirect
+ github.com/MakeNowJust/heredoc v1.0.0 // indirect
+ github.com/Masterminds/goutils v1.1.1 // indirect
+ github.com/Masterminds/semver/v3 v3.4.0 // indirect
+ github.com/Masterminds/sprig/v3 v3.3.0 // indirect
+ github.com/Masterminds/squirrel v1.5.4 // indirect
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
- github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect
+ github.com/chai2010/gettext-go v1.0.3 // indirect
+ github.com/cncf/xds/go v0.0.0-20251110193048-8bfbf64dc13e // indirect
+ github.com/containerd/containerd v1.7.29 // indirect
+ github.com/containerd/errdefs v0.3.0 // indirect
+ github.com/containerd/log v0.1.0 // indirect
+ github.com/containerd/platforms v0.2.1 // indirect
+ github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
- github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
+ github.com/envoyproxy/protoc-gen-validate v1.3.0 // indirect
+ github.com/evanphx/json-patch v5.9.11+incompatible // indirect
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
+ github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
+ github.com/go-errors/errors v1.5.1 // indirect
+ github.com/go-gorp/gorp/v3 v3.1.0 // indirect
github.com/go-openapi/errors v0.21.0 // indirect
- github.com/go-openapi/jsonpointer v0.21.2 // indirect
- github.com/go-openapi/jsonreference v0.21.0 // indirect
+ github.com/go-openapi/jsonpointer v0.22.4 // indirect
+ github.com/go-openapi/jsonreference v0.21.4 // indirect
github.com/go-openapi/strfmt v0.22.1 // indirect
- github.com/go-openapi/swag v0.23.1 // indirect
+ github.com/go-openapi/swag v0.25.4 // indirect
+ github.com/go-openapi/swag/cmdutils v0.25.4 // indirect
+ github.com/go-openapi/swag/conv v0.25.4 // indirect
+ github.com/go-openapi/swag/fileutils v0.25.4 // indirect
+ github.com/go-openapi/swag/jsonname v0.25.4 // indirect
+ github.com/go-openapi/swag/jsonutils v0.25.4 // indirect
+ github.com/go-openapi/swag/loading v0.25.4 // indirect
+ github.com/go-openapi/swag/mangling v0.25.4 // indirect
+ github.com/go-openapi/swag/netutils v0.25.4 // indirect
+ github.com/go-openapi/swag/stringutils v0.25.4 // indirect
+ github.com/go-openapi/swag/typeutils v0.25.4 // indirect
+ github.com/go-openapi/swag/yamlutils v0.25.4 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.19.0 // indirect
+ github.com/gobwas/glob v0.2.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/btree v1.1.3 // indirect
- github.com/google/gnostic-models v0.7.0 // indirect
+ github.com/google/gnostic-models v0.7.1 // indirect
github.com/google/s2a-go v0.1.4 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
github.com/googleapis/gax-go/v2 v2.10.0 // indirect
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
+ github.com/gosuri/uitable v0.0.4 // indirect
+ github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
+ github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
+ github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
+ github.com/huandu/xstrings v1.5.0 // indirect
github.com/imdario/mergo v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
- github.com/josharian/intern v1.0.0 // indirect
+ github.com/jmoiron/sqlx v1.4.0 // indirect
github.com/josharian/native v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
+ github.com/klauspost/compress v1.18.0 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
+ github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
+ github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
- github.com/mailru/easyjson v0.9.0 // indirect
+ github.com/lib/pq v1.10.9 // indirect
+ github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
+ github.com/magiconair/properties v1.8.9 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
+ github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mdlayher/netlink v1.6.0 // indirect
github.com/mdlayher/socket v0.1.1 // indirect
+ github.com/mitchellh/copystructure v1.2.0 // indirect
+ github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
+ github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/spdystream v0.5.0 // indirect
+ github.com/moby/term v0.5.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
+ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/oklog/ulid v1.3.1 // indirect
+ github.com/opencontainers/go-digest v1.0.0 // indirect
+ github.com/opencontainers/image-spec v1.1.1 // indirect
+ github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/procfs v0.17.0 // indirect
+ github.com/rivo/uniseg v0.4.7 // indirect
github.com/robfig/cron v1.2.0 // indirect
+ github.com/rubenv/sql-migrate v1.8.0 // indirect
+ github.com/russross/blackfriday/v2 v2.1.0 // indirect
+ github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
+ github.com/shopspring/decimal v1.4.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
- github.com/spf13/pflag v1.0.9 // indirect
+ github.com/spf13/cast v1.8.0 // indirect
+ github.com/spf13/pflag v1.0.10 // indirect
github.com/x448/float16 v0.8.4 // indirect
+ github.com/xlab/treeprint v1.2.0 // indirect
go.mongodb.org/mongo-driver v1.14.0 // indirect
go.opencensus.io v0.24.0 // indirect
- go.opentelemetry.io/otel v1.37.0 // indirect
- go.opentelemetry.io/otel/trace v1.37.0 // indirect
+ go.opentelemetry.io/otel v1.38.0 // indirect
+ go.opentelemetry.io/otel/trace v1.38.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
- golang.org/x/crypto v0.45.0 // indirect
- golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect
- golang.org/x/net v0.47.0 // indirect
- golang.org/x/oauth2 v0.30.0 // indirect
- golang.org/x/sync v0.18.0 // indirect
- golang.org/x/sys v0.38.0 // indirect
- golang.org/x/term v0.37.0 // indirect
- golang.org/x/text v0.31.0 // indirect
+ golang.org/x/crypto v0.46.0 // indirect
+ golang.org/x/exp v0.0.0-20251017212417-90e834f514db // indirect
+ golang.org/x/net v0.48.0 // indirect
+ golang.org/x/oauth2 v0.34.0 // indirect
+ golang.org/x/sync v0.19.0 // indirect
+ golang.org/x/sys v0.39.0 // indirect
+ golang.org/x/term v0.38.0 // indirect
+ golang.org/x/text v0.32.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1 // indirect
- google.golang.org/protobuf v1.36.8 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect
+ google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
+ gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
+ helm.sh/helm/v3 v3.18.6 // indirect
+ istio.io/istio v0.0.0-20260208024451-a30ad73344d7 // indirect
+ k8s.io/cli-runtime v0.35.0 // indirect
k8s.io/component-base v0.35.0 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
- k8s.io/kube-aggregator v0.35.0 // indirect
- k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect
+ k8s.io/kube-aggregator v0.34.1 // indirect
+ k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e // indirect
+ k8s.io/kubectl v0.35.0 // indirect
+ oras.land/oras-go/v2 v2.6.0 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96 // indirect
+ sigs.k8s.io/kustomize/api v0.20.1 // indirect
+ sigs.k8s.io/kustomize/kyaml v0.20.1 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 // indirect
sigs.k8s.io/yaml v1.6.0 // indirect
@@ -157,3 +221,6 @@ require (
// This replace stanza is necessary to import
// github.com/istio-ecosystem/sail-operator.
replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.5
+
+// Use the sail_library_2 branch from aslakknutsen's fork for Sail Library integration
+replace github.com/istio-ecosystem/sail-operator => github.com/aslakknutsen/sail-operator v0.0.0-20260223154431-ffebc5493a7f
diff --git a/go.sum b/go.sum
index 93efb94820..6f3561c42b 100644
--- a/go.sum
+++ b/go.sum
@@ -1,7 +1,13 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
-cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
+cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
+cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
+dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
+dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
+filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
+filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 h1:F0gBpfdPLGsw+nsgk6aqqkZS1jiixa5WwFe3fk/T3Ys=
@@ -22,6 +28,8 @@ github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.3.1 h1:mrkD
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.3.1/go.mod h1:hPv41DbqMmnxcGralanA/kVlfdH5jv3T4LxGku2E1BY=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1 h1:bFWuoEKg+gImo7pvkiQEFAc8ocibADgXeiLAxWhWmkI=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1/go.mod h1:Vih/3yc6yac2JzU4hzpaDupBJP0Flaia9rXXrU8xyww=
+github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
+github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.11.27 h1:F3R3q42aWytozkV8ihzcgMO4OA4cuqr3bNlsEuF6//A=
@@ -47,14 +55,25 @@ github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mo
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 h1:H5xDQaE3XowWfhZRUpnfC+rGZMEVoSiji+b+/HFAPU4=
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
+github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
+github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
+github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
github.com/IBM/go-sdk-core/v5 v5.8.0/go.mod h1:+YbdhrjCHC84ls4MeBp+Hj4NZCni+tDAc0XQUqRO9Jc=
github.com/IBM/go-sdk-core/v5 v5.17.4 h1:VGb9+mRrnS2HpHZFM5hy4J6ppIWnwNrw0G+tLSgcJLc=
github.com/IBM/go-sdk-core/v5 v5.17.4/go.mod h1:KsAAI7eStAWwQa4F96MLy+whYSh39JzNjklZRbN/8ns=
github.com/IBM/networking-go-sdk v0.26.0 h1:K/geWMCgg5P0pbaVQ0eZLhim2G6yOZc8rjszbv2Kmzc=
github.com/IBM/networking-go-sdk v0.26.0/go.mod h1:tVxXclpQs8nQJYPTr9ZPNC1voaPNQLy8iy/72oVfFtM=
-github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
+github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
+github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
+github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
+github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
github.com/Masterminds/semver/v3 v3.4.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/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM=
+github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
@@ -63,6 +82,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
+github.com/aslakknutsen/sail-operator v0.0.0-20260223154431-ffebc5493a7f h1:/wY2qCfgvOQhcr0GK+J8lkvajwseOrITgyrlHyIQWo0=
+github.com/aslakknutsen/sail-operator v0.0.0-20260223154431-ffebc5493a7f/go.mod h1:rR8cFIg6t7uYqAb03oMQSQ/vYnXR1WJN7zbnm+3VTDI=
github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
github.com/aws/aws-sdk-go v1.38.49 h1:E31vxjCe6a5I+mJLmUGaZobiWmg9KdWaud9IfceYeYQ=
github.com/aws/aws-sdk-go v1.38.49/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
@@ -70,10 +91,18 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
+github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70=
+github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
+github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
+github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
+github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8=
+github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chai2010/gettext-go v1.0.3 h1:9liNh8t+u26xl5ddmWLmsOsdNLwkdRTg5AG+JnTiM80=
+github.com/chai2010/gettext-go v1.0.3/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
@@ -81,16 +110,42 @@ github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XP
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls=
-github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
+github.com/cncf/xds/go v0.0.0-20251110193048-8bfbf64dc13e h1:gt7U1Igw0xbJdyaCM5H2CnlAlPSkzrhsebQB6WQWjLA=
+github.com/cncf/xds/go v0.0.0-20251110193048-8bfbf64dc13e/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI=
+github.com/containerd/containerd v1.7.29 h1:90fWABQsaN9mJhGkoVnuzEY+o1XDPbg9BTC9QTAHnuE=
+github.com/containerd/containerd v1.7.29/go.mod h1:azUkWcOvHrWvaiUjSQH0fjzuHIwSPg1WL5PshGP4Szs=
+github.com/containerd/errdefs v0.3.0 h1:FSZgGOeK4yuT/+DnF07/Olde/q4KBoMsaamhXxIMDp4=
+github.com/containerd/errdefs v0.3.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
+github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
+github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
+github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
+github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
+github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
+github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
+github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
+github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
+github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.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/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
+github.com/distribution/distribution/v3 v3.0.0 h1:q4R8wemdRQDClzoNNStftB2ZAfqOiN6UX90KJc4HjyM=
+github.com/distribution/distribution/v3 v3.0.0/go.mod h1:tRNuFoZsUdyRVegq8xGNeds4KLjwLCRin/tTo6i1DhU=
+github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
+github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
+github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
+github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
+github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
+github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
+github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
+github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
+github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
+github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -99,17 +154,25 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
-github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
-github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls=
-github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/envoyproxy/protoc-gen-validate v1.3.0 h1:TvGH1wof4H33rezVKWSpqKz5NXWg5VPuZ0uONDT6eb4=
+github.com/envoyproxy/protoc-gen-validate v1.3.0/go.mod h1:HvYl7zwPa5mffgyeTUHA9zHIH36nmrm7oCbo4YKoSWA=
+github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8=
+github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU=
github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=
+github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4=
+github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc=
github.com/fatih/color v0.0.0-20161025120501-bf82308e8c85/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
+github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
+github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/florianl/go-nfqueue v1.3.2 h1:8DPzhKJHywpHJAE/4ktgcqveCL7qmMLsEsVD68C4x4I=
github.com/florianl/go-nfqueue v1.3.2/go.mod h1:eSnAor2YCfMCVYrVNEhkLGN/r1L+J4uDjc0EUy0tfq4=
+github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI=
+github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk=
+github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
+github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
@@ -119,6 +182,10 @@ github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj2
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
+github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
+github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs=
+github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
@@ -128,15 +195,43 @@ github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR
github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
github.com/go-openapi/errors v0.21.0 h1:FhChC/duCnfoLj1gZ0BgaBmzhJC2SL/sJr8a2vAobSY=
github.com/go-openapi/errors v0.21.0/go.mod h1:jxNTMUxRCKj65yb/okJGEtahVd7uvWnuWfj53bse4ho=
-github.com/go-openapi/jsonpointer v0.21.2 h1:AqQaNADVwq/VnkCmQg6ogE+M3FOsKTytwges0JdwVuA=
-github.com/go-openapi/jsonpointer v0.21.2/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk=
-github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
-github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
+github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4=
+github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80=
+github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8=
+github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4=
github.com/go-openapi/strfmt v0.20.2/go.mod h1:43urheQI9dNtE5lTZQfuFJvjYJKPrxicATpEfZwHUNk=
github.com/go-openapi/strfmt v0.22.1 h1:5Ky8cybT4576C6Ffc+8gYji/wRXCo6Ozm8RaWjPI6jc=
github.com/go-openapi/strfmt v0.22.1/go.mod h1:OfVoytIXJasDkkGvkb1Cceb3BPyMOwk1FgmyyEw7NYg=
-github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU=
-github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
+github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU=
+github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ=
+github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4=
+github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0=
+github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4=
+github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU=
+github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y=
+github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk=
+github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI=
+github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag=
+github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA=
+github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY=
+github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo=
+github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM=
+github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s=
+github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE=
+github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48=
+github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg=
+github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0=
+github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg=
+github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8=
+github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0=
+github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw=
+github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE=
+github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw=
+github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc=
+github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4=
+github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg=
+github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls=
+github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
@@ -148,6 +243,8 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91
github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4=
github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
+github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
@@ -176,6 +273,8 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe
github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
+github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
+github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
@@ -207,8 +306,8 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
-github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
-github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
+github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c=
+github.com/google/gnostic-models v0.7.1/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@@ -226,8 +325,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
-github.com/google/pprof v0.0.0-20250501235452-c0086092b71a h1:rDA3FfmxwXR+BVKKdz55WwMJ1pD2hJQNW31d+l3mPk4=
-github.com/google/pprof v0.0.0-20250501235452-c0086092b71a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
+github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a h1://KbezygeMJZCSHH+HgUZiTeSoiuFspbMg1ge+eFj18=
+github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc=
github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -238,40 +337,65 @@ github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9
github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
github.com/googleapis/gax-go/v2 v2.10.0 h1:ebSgKfMxynOdxw8QQuFOKMgomqeLGPqNLQox2bo42zg=
github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw=
+github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
+github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
+github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
+github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
+github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY=
+github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
+github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248=
+github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk=
+github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
+github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
+github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
+github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
+github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
+github.com/hashicorp/golang-lru/arc/v2 v2.0.5 h1:l2zaLDubNhW4XO3LnliVj0GXO3+/CGNJAg1dcN2Fpfw=
+github.com/hashicorp/golang-lru/arc/v2 v2.0.5/go.mod h1:ny6zBSQZi2JxIeYcv7kt2sH2PXJtirBN7RDhRpxPkxU=
+github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
+github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+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.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
-github.com/istio-ecosystem/sail-operator v0.0.0-20250513111011-30be83268d6b h1:jQokaEG8FFjsl7DQ6sb/pEMemZonFQ6Uu1puaCyXzF0=
-github.com/istio-ecosystem/sail-operator v0.0.0-20250513111011-30be83268d6b/go.mod h1:Es2YI34zqMGgV0gpf+KM5SaXMNcJ+9BnFMUSE32atcM=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
+github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
+github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
-github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
-github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/josharian/native v1.0.0 h1:Ts/E8zCSEsG17dUqv7joXJFybuMLjQfWE04tsBODTxk=
github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.4.0 h1:VzM3TYHDgqPkettiP6I6q2jOeQFL4nrJM+UcAc4f6Fs=
+github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.4.0/go.mod h1:nqCI7aelBJU61wiBeeZWJ6oi4bJy5nrjkM6lWIMA4j0=
github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs=
@@ -292,11 +416,19 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
+github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
+github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
+github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
+github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
-github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
-github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
+github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
+github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
+github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
+github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
+github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
@@ -305,21 +437,37 @@ github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stg
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
+github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
+github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mdlayher/netlink v1.6.0 h1:rOHX5yl7qnlpiVkFWoqccueppMtXzeziFjWAjLg6sz0=
github.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWCdcZk8/vA=
github.com/mdlayher/socket v0.1.1 h1:q3uOGirUPfAV2MUoaC7BavjQ154J7+JOkTWyiV+intI=
github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs=
+github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA=
+github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
+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-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
+github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
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.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
+github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
+github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
+github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
+github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
@@ -345,8 +493,12 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48=
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
-github.com/openshift/api v0.0.0-20251214014457-bfa868a22401 h1:goMf6pBtRFSQaVElFk6K+GIAqnv7O84p7PJHH6pDz/E=
-github.com/openshift/api v0.0.0-20251214014457-bfa868a22401/go.mod h1:d5uzF0YN2nQQFA0jIEWzzOZ+edmo6wzlGLvx5Fhz4uY=
+github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
+github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
+github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
+github.com/openshift/api v0.0.0-20260223154456-de86ee3bf481 h1:vzJFg36EK0uI3ODv9cgC1dgnYxwxFv4+kgJFXQ5kojM=
+github.com/openshift/api v0.0.0-20260223154456-de86ee3bf481/go.mod h1:ZYAxo9t1AALeEotN07tNzIvqqqWSxcZIqMUKnY/xCeQ=
github.com/openshift/client-go v0.0.0-20251205093018-96a6cbc1420c h1:TBE0Gl+oCo/SNEhLKZQNNH/SWHXrpGyhAw7P0lAqdHg=
github.com/openshift/client-go v0.0.0-20251205093018-96a6cbc1420c/go.mod h1:IsynOWZAfdH+BgWimcFQRtI41Id9sgdhsCEjIk8ACLw=
github.com/openshift/library-go v0.0.0-20251021141706-f489e811f030 h1:dbv8ZYDWIl22A5WBjQJTKeENM08f8HwMBuv8glDXO/0=
@@ -354,6 +506,10 @@ github.com/openshift/library-go v0.0.0-20251021141706-f489e811f030/go.mod h1:OlF
github.com/operator-framework/api v0.30.0 h1:44hCmGnEnZk/Miol5o44dhSldNH0EToQUG7vZTl29kk=
github.com/operator-framework/api v0.30.0/go.mod h1:FYxAPhjtlXSAty/fbn5YJnFagt6SpJZJgFNNbvDe5W0=
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
+github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
+github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
+github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
+github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -363,6 +519,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY=
+github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg=
github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.74.0 h1:AHzMWDxNiAVscJL6+4wkvFRTpMnJqiaZFEKA/osaBXE=
github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.74.0/go.mod h1:wAR5JopumPtAZnu0Cjv2PSqV4p4QB09LMhc6fZZTXuA=
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
@@ -372,10 +530,19 @@ github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNw
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
+github.com/prometheus/otlptranslator v0.0.0-20250717125610-8549f4ab4f8f h1:QQB6SuvGZjK8kdc2YaLJpYhV8fxauOsjE6jgcL6YJ8Q=
+github.com/prometheus/otlptranslator v0.0.0-20250717125610-8549f4ab4f8f/go.mod h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI=
github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
-github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
-github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
+github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5 h1:EaDatTxkdHG+U3Bk4EUr+DZ7fOGwTfezUiUJMaIcaho=
+github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5/go.mod h1:fyalQWdtzDBECAQFBJuQe5bzQ02jGd5Qcbgb97Flm7U=
+github.com/redis/go-redis/extra/redisotel/v9 v9.0.5 h1:EfpWLLCyXw8PSM2/XNJLjI3Pb27yVE+gIAfeqp8LUCc=
+github.com/redis/go-redis/extra/redisotel/v9 v9.0.5/go.mod h1:WZjPDy7VNzn77AAfnAfVjZNvfJTYfPetfZk5yoSTLaQ=
+github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
+github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
+github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
@@ -384,20 +551,31 @@ github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
+github.com/rubenv/sql-migrate v1.8.0 h1:dXnYiJk9k3wetp7GfQbKJcPHjVJL6YK19tKj8t2Ns0o=
+github.com/rubenv/sql-migrate v1.8.0/go.mod h1:F2bGFBwCU+pnmbtNYDeKvSuvL6lBVtXDXUUv5t+u1qw=
+github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
+github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
+github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
+github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
+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.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/spf13/cast v1.8.0 h1:gEN9K4b8Xws4EX0+a0reLmhq8moKn7ntRlQYgjPeCDk=
+github.com/spf13/cast v1.8.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v0.0.0-20170118185516-dc208f4211e7/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v1.10.0 h1:a5/WeUlSDCvV5a45ljW2ZFtV0bTDpkfSAj3uqB6Sc+0=
github.com/spf13/cobra v1.10.0/go.mod h1:9dhySC7dnTtEiqzmqfkLj47BslqLCUPMXjG2lj/NgoE=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.8/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
-github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
+github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
@@ -425,6 +603,8 @@ github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcY
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
+github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
+github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -434,19 +614,55 @@ go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd
go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
-go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
-go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
-go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
-go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
-go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
-go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
-go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
-go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
-go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
-go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
-go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
-go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
+go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
+go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
+go.opentelemetry.io/contrib/bridges/prometheus v0.57.0 h1:UW0+QyeyBVhn+COBec3nGhfnFe5lwB0ic1JBVjzhk0w=
+go.opentelemetry.io/contrib/bridges/prometheus v0.57.0/go.mod h1:ppciCHRLsyCio54qbzQv0E4Jyth/fLWDTJYfvWpcSVk=
+go.opentelemetry.io/contrib/exporters/autoexport v0.57.0 h1:jmTVJ86dP60C01K3slFQa2NQ/Aoi7zA+wy7vMOKD9H4=
+go.opentelemetry.io/contrib/exporters/autoexport v0.57.0/go.mod h1:EJBheUMttD/lABFyLXhce47Wr6DPWYReCzaZiXadH7g=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
+go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
+go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
+go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0 h1:WzNab7hOOLzdDF/EoWCt4glhrbMPVMOO5JYTmpz36Ls=
+go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0/go.mod h1:hKvJwTzJdp90Vh7p6q/9PAOd55dI6WA6sWj62a/JvSs=
+go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0 h1:S+LdBGiQXtJdowoJoQPEtI52syEP/JYBUpjO49EQhV8=
+go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0/go.mod h1:5KXybFvPGds3QinJWQT7pmXf+TN5YIa7CNYObWRkj50=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0 h1:j7ZSD+5yn+lo3sGV69nW04rRR0jhYnBwjuX3r0HvnK0=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0/go.mod h1:WXbYJTUaZXAbYd8lbgGuvih0yuCfOFC5RJoYnoLcGz8=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0 h1:t/Qur3vKSkUCcDVaSumWF2PKHt85pc7fRvFuoVT8qFU=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0/go.mod h1:Rl61tySSdcOJWoEgYZVtmnKdA0GeKrSqkHC1t+91CH8=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 h1:bDMKF3RUSxshZ5OjOTi8rsHGaPKsAt76FaqgvIUySLc=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0/go.mod h1:dDT67G/IkA46Mr2l9Uj7HsQVwsjASyV9SjGofsiUZDA=
+go.opentelemetry.io/otel/exporters/prometheus v0.59.1 h1:HcpSkTkJbggT8bjYP+BjyqPWlD17BH9C5CYNKeDzmcA=
+go.opentelemetry.io/otel/exporters/prometheus v0.59.1/go.mod h1:0FJL+gjuUoM07xzik3KPBaN+nz/CoB15kV6WLMiXZag=
+go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.8.0 h1:CHXNXwfKWfzS65yrlB2PVds1IBZcdsX8Vepy9of0iRU=
+go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.8.0/go.mod h1:zKU4zUgKiaRxrdovSS2amdM5gOc59slmo/zJwGX+YBg=
+go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.32.0 h1:SZmDnHcgp3zwlPBS2JX2urGYe/jBKEIT6ZedHRUyCz8=
+go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.32.0/go.mod h1:fdWW0HtZJ7+jNpTKUR0GpMEDP69nR8YBJQxNiVCE3jk=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.32.0 h1:cC2yDI3IQd0Udsux7Qmq8ToKAx1XCilTQECZ0KDZyTw=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.32.0/go.mod h1:2PD5Ex6z8CFzDbTdOlwyNIUywRr1DN0ospafJM1wJ+s=
+go.opentelemetry.io/otel/log v0.8.0 h1:egZ8vV5atrUWUbnSsHn6vB8R21G2wrKqNiDt3iWertk=
+go.opentelemetry.io/otel/log v0.8.0/go.mod h1:M9qvDdUTRCopJcGRKg57+JSQ9LgLBrwwfC32epk5NX8=
+go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
+go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
+go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
+go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
+go.opentelemetry.io/otel/sdk/log v0.8.0 h1:zg7GUYXqxk1jnGF/dTdLPrK06xJdrXgqgFLnI4Crxvs=
+go.opentelemetry.io/otel/sdk/log v0.8.0/go.mod h1:50iXr0UVwQrYS45KbruFrEt4LvAdCaWWgIrsN3ZQggo=
+go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
+go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
+go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
+go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
+go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
+go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
+go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
+go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
@@ -466,11 +682,11 @@ 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-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
-golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
+golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
+golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI=
-golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
+golang.org/x/exp v0.0.0-20251017212417-90e834f514db h1:by6IehL4BH5k3e3SJmcoNbOobMey2SLpAF79iPOEBvw=
+golang.org/x/exp v0.0.0-20251017212417-90e834f514db/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@@ -479,8 +695,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
-golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
+golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
+golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
golang.org/x/net v0.0.0-20161104230106-55a3084c9119/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -502,12 +718,12 @@ golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
-golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
+golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
+golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
-golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
+golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
+golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -518,8 +734,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
-golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
+golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
+golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -539,6 +755,7 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -547,12 +764,12 @@ 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.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
-golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
+golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
-golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
+golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
+golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -560,10 +777,10 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
-golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
-golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
-golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
-golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
+golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
+golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
+golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
+golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -578,8 +795,8 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
-golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
+golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
+golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -598,11 +815,11 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao=
-google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 h1:FiusG7LWj+4byqhbvmB+Q93B/mOxJLN2DTozDuZm4EU=
-google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:kXqgZtrWaf6qS3jZOCnCH7WYfrvFjkC51bM8fz3RsCA=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1 h1:pmJpJEvT846VzausCQ5d7KreSROcDqmO388w5YbnltA=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
+google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3 h1:1hfbdAfFbkmpg41000wDVqr7jUpK/Yo+LPnIxxGzmkg=
+google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU=
+google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
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=
@@ -611,8 +828,8 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
-google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
-google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
+google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
+google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
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=
@@ -624,8 +841,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
-google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
+google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
+google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -640,6 +857,8 @@ gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8
gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
+gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -653,8 +872,16 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+helm.sh/helm/v3 v3.18.6 h1:S/2CqcYnNfLckkHLI0VgQbxgcDaU3N4A/46E3n9wSNY=
+helm.sh/helm/v3 v3.18.6/go.mod h1:L/dXDR2r539oPlFP1PJqKAC1CUgqHJDLkxKpDGrWnyg=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+istio.io/api v1.29.0-alpha.0.0.20260205010447-d2bc7d18a337 h1:fTa0j3yQhp5RohEaAaGB+DiXWX6EEq4CGcrcvU+9Sao=
+istio.io/api v1.29.0-alpha.0.0.20260205010447-d2bc7d18a337/go.mod h1:+brQWcBHoROuyA6fv8rbgg8Kfn0RCGuqoY0duCMuSLA=
+istio.io/client-go v1.29.0-alpha.0.0.20260205011149-b3a6b2e28b06 h1:S3ger4fZHVuV61d9HKwUksc2y1vQhtyu4zgVr0lD03M=
+istio.io/client-go v1.29.0-alpha.0.0.20260205011149-b3a6b2e28b06/go.mod h1:NHEtxuW56GL/RuXXE6NLdzrBURs++EyIp2WSsL9Fpe8=
+istio.io/istio v0.0.0-20260208024451-a30ad73344d7 h1:QjIjbK46AhUscVomrrEFiiFq1roN+/3I2hqCauHGO7M=
+istio.io/istio v0.0.0-20260208024451-a30ad73344d7/go.mod h1:cVTeU6zOpccSZOT3xFeSPn7G0ySPG/vaP9T0kqgk0Wg=
k8s.io/api v0.35.0 h1:iBAU5LTyBI9vw3L5glmat1njFK34srdLmktWwLTprlY=
k8s.io/api v0.35.0/go.mod h1:AQ0SNTzm4ZAczM03QH42c7l3bih1TbAXYo0DkF8ktnA=
k8s.io/apiextensions-apiserver v0.35.0 h1:3xHk2rTOdWXXJM+RDQZJvdx0yEOgC0FgQ1PlJatA5T4=
@@ -663,18 +890,24 @@ k8s.io/apimachinery v0.35.0 h1:Z2L3IHvPVv/MJ7xRxHEtk6GoJElaAqDCCU0S6ncYok8=
k8s.io/apimachinery v0.35.0/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns=
k8s.io/apiserver v0.35.0 h1:CUGo5o+7hW9GcAEF3x3usT3fX4f9r8xmgQeCBDaOgX4=
k8s.io/apiserver v0.35.0/go.mod h1:QUy1U4+PrzbJaM3XGu2tQ7U9A4udRRo5cyxkFX0GEds=
+k8s.io/cli-runtime v0.35.0 h1:PEJtYS/Zr4p20PfZSLCbY6YvaoLrfByd6THQzPworUE=
+k8s.io/cli-runtime v0.35.0/go.mod h1:VBRvHzosVAoVdP3XwUQn1Oqkvaa8facnokNkD7jOTMY=
k8s.io/client-go v0.35.0 h1:IAW0ifFbfQQwQmga0UdoH0yvdqrbwMdq9vIFEhRpxBE=
k8s.io/client-go v0.35.0/go.mod h1:q2E5AAyqcbeLGPdoRB+Nxe3KYTfPce1Dnu1myQdqz9o=
k8s.io/component-base v0.35.0 h1:+yBrOhzri2S1BVqyVSvcM3PtPyx5GUxCK2tinZz1G94=
k8s.io/component-base v0.35.0/go.mod h1:85SCX4UCa6SCFt6p3IKAPej7jSnF3L8EbfSyMZayJR0=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
-k8s.io/kube-aggregator v0.35.0 h1:FBtbuRFA7Ohe2QKirFZcJf8rgimC8oSaNiCi4pdU5xw=
-k8s.io/kube-aggregator v0.35.0/go.mod h1:vKBRpQUfDryb7udwUwF3eCSvv3AJNgHtL4PGl6PqAg8=
-k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE=
-k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
-k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck=
-k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+k8s.io/kube-aggregator v0.34.1 h1:WNLV0dVNoFKmuyvdWLd92iDSyD/TSTjqwaPj0U9XAEU=
+k8s.io/kube-aggregator v0.34.1/go.mod h1:RU8j+5ERfp0h+gIvWtxRPfsa5nK7rboDm8RST8BJfYQ=
+k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ=
+k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
+k8s.io/kubectl v0.35.0 h1:cL/wJKHDe8E8+rP3G7avnymcMg6bH6JEcR5w5uo06wc=
+k8s.io/kubectl v0.35.0/go.mod h1:VR5/TSkYyxZwrRwY5I5dDq6l5KXmiCb+9w8IKplk3Qo=
+k8s.io/utils v0.0.0-20251219084037-98d557b7f1e7 h1:H6xtwB5tC+KFSHoEhA1o7DnOtHDEo+n9OBSHjlajVKc=
+k8s.io/utils v0.0.0-20251219084037-98d557b7f1e7/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
+oras.land/oras-go/v2 v2.6.0 h1:X4ELRsiGkrbeox69+9tzTu492FMUu7zJQW6eJU+I2oc=
+oras.land/oras-go/v2 v2.6.0/go.mod h1:magiQDfG6H1O9APp+rOsvCPcW1GD2MM7vgnKY0Y+u1o=
sigs.k8s.io/controller-runtime v0.23.1 h1:TjJSM80Nf43Mg21+RCy3J70aj/W6KyvDtOlpKf+PupE=
sigs.k8s.io/controller-runtime v0.23.1/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0=
sigs.k8s.io/gateway-api v1.4.1 h1:NPxFutNkKNa8UfLd2CMlEuhIPMQgDQ6DXNKG9sHbJU8=
@@ -683,6 +916,10 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96 h1:PFWFSkpArPNJxFX4ZKWAk9NSeRoZaXschn+ULa4xVek=
sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96/go.mod h1:EOBQyBowOUsd7U4CJnMHNE0ri+zCXyouGdLwC/jZU+I=
+sigs.k8s.io/kustomize/api v0.20.1 h1:iWP1Ydh3/lmldBnH/S5RXgT98vWYMaTUL1ADcr+Sv7I=
+sigs.k8s.io/kustomize/api v0.20.1/go.mod h1:t6hUFxO+Ph0VxIk1sKp1WS0dOjbPCtLJ4p8aADLwqjM=
+sigs.k8s.io/kustomize/kyaml v0.20.1 h1:PCMnA2mrVbRP3NIB6v9kYCAc38uvFLVs8j/CD567A78=
+sigs.k8s.io/kustomize/kyaml v0.20.1/go.mod h1:0EmkQHRUsJxY8Ug9Niig1pUMSCGHxQ5RklbpV/Ri6po=
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 h1:2WOzJpHUBVrrkDjU4KBT8n5LDcj824eX0I5UKcgeRUs=
diff --git a/manifests/00-cluster-role.yaml b/manifests/00-cluster-role.yaml
index e29ed4bd76..1f06f50573 100644
--- a/manifests/00-cluster-role.yaml
+++ b/manifests/00-cluster-role.yaml
@@ -37,13 +37,31 @@ rules:
resources:
- nodes
verbs:
+ - get
- list
+ - watch
+
+- apiGroups:
+ - ""
+ resources:
+ - services/status
+ - replicationcontrollers
+ verbs:
+ - "*"
- apiGroups:
- apps
resources:
- deployments
- daemonsets
+ - replicasets
+ verbs:
+ - "*"
+
+- apiGroups:
+ - autoscaling
+ resources:
+ - horizontalpodautoscalers
verbs:
- "*"
@@ -71,11 +89,7 @@ rules:
- roles
- rolebindings
verbs:
- - create
- - get
- - list
- - watch
- - update
+ - "*"
- apiGroups:
- operator.openshift.io
@@ -158,16 +172,6 @@ rules:
verbs:
- '*'
-- apiGroups:
- - gateway.networking.k8s.io
- resources:
- - gatewayclasses
- - gateways
- - httproutes
- - grpcroutes
- verbs:
- - '*'
-
- apiGroups:
- apiextensions.k8s.io
resources:
@@ -187,6 +191,7 @@ rules:
- sailoperator.io
resources:
- istios
+ - istiorevisions
verbs:
- '*'
@@ -249,5 +254,95 @@ rules:
resources:
- endpointslices
verbs:
+ - get
+ - list
+ - watch
+
+# Required for Istio installation via Helm
+- apiGroups:
+ - admissionregistration.k8s.io
+ resources:
+ - mutatingwebhookconfigurations
+ - validatingwebhookconfigurations
+ verbs:
+ - "*"
+
+- apiGroups:
+ - coordination.k8s.io
+ resources:
+ - leases
+ verbs:
+ - get
+ - list
+ - watch
+ - create
+ - update
+ - patch
+
+- apiGroups:
+ - networking.k8s.io
+ resources:
+ - ingresses
+ - ingresses/status
+ verbs:
+ - "*"
+
+- apiGroups:
+ - authentication.istio.io
+ - config.istio.io
+ - extensions.istio.io
+ - networking.istio.io
+ - rbac.istio.io
+ - security.istio.io
+ - telemetry.istio.io
+ resources:
+ - "*"
+ verbs:
+ - "*"
+
+- apiGroups:
+ - gateway.networking.k8s.io
+ resources:
+ - "*"
+ verbs:
+ - "*"
+
+- apiGroups:
+ - gateway.networking.x-k8s.io
+ resources:
+ - "*"
+ verbs:
+ - "*"
+
+- apiGroups:
+ - networking.x-k8s.io
+ resources:
+ - gateways
+ verbs:
+ - get
- list
- watch
+
+- apiGroups:
+ - multicluster.x-k8s.io
+ resources:
+ - serviceexports
+ - serviceimports
+ verbs:
+ - get
+ - list
+ - watch
+ - create
+ - delete
+
+- apiGroups:
+ - inference.networking.x-k8s.io
+ resources:
+ - inferencepools
+ - inferencepools/status
+ verbs:
+ - get
+ - list
+ - watch
+ - update
+ - patch
diff --git a/manifests/00-custom-resource-definition.yaml b/manifests/00-custom-resource-definition.yaml
index d37991c458..fd7ecdeba2 100644
--- a/manifests/00-custom-resource-definition.yaml
+++ b/manifests/00-custom-resource-definition.yaml
@@ -1994,27 +1994,25 @@ spec:
profile as invalid configurations can be catastrophic. An example custom profile
looks like this:
+ minTLSVersion: VersionTLS11
ciphers:
-
- ECDHE-ECDSA-CHACHA20-POLY1305
-
- ECDHE-RSA-CHACHA20-POLY1305
-
- ECDHE-RSA-AES128-GCM-SHA256
-
- ECDHE-ECDSA-AES128-GCM-SHA256
-
- minTLSVersion: VersionTLS11
nullable: true
properties:
ciphers:
description: |-
ciphers is used to specify the cipher algorithms that are negotiated
- during the TLS handshake. Operators may remove entries their operands
- do not support. For example, to use DES-CBC3-SHA (yaml):
+ during the TLS handshake. Operators may remove entries that their operands
+ do not support. For example, to use only ECDHE-RSA-AES128-GCM-SHA256 (yaml):
ciphers:
- - DES-CBC3-SHA
+ - ECDHE-RSA-AES128-GCM-SHA256
+
+ TLS 1.3 cipher suites (e.g. TLS_AES_128_GCM_SHA256) are not configurable
+ and are always enabled when TLS 1.3 is negotiated.
items:
type: string
type: array
@@ -2026,8 +2024,6 @@ spec:
versions 1.1, 1.2 and 1.3 (yaml):
minTLSVersion: VersionTLS11
-
- NOTE: currently the highest minTLSVersion allowed is VersionTLS12
enum:
- VersionTLS10
- VersionTLS11
@@ -2037,143 +2033,81 @@ spec:
type: object
intermediate:
description: |-
- intermediate is a TLS security profile based on:
-
- https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28recommended.29
-
- and looks like this (yaml):
+ intermediate is a TLS profile for use when you do not need compatibility with
+ legacy clients and want to remain highly secure while being compatible with
+ most clients currently in use.
+ This profile is equivalent to a Custom profile specified as:
+ minTLSVersion: VersionTLS12
ciphers:
-
- TLS_AES_128_GCM_SHA256
-
- TLS_AES_256_GCM_SHA384
-
- TLS_CHACHA20_POLY1305_SHA256
-
- ECDHE-ECDSA-AES128-GCM-SHA256
-
- ECDHE-RSA-AES128-GCM-SHA256
-
- ECDHE-ECDSA-AES256-GCM-SHA384
-
- ECDHE-RSA-AES256-GCM-SHA384
-
- ECDHE-ECDSA-CHACHA20-POLY1305
-
- ECDHE-RSA-CHACHA20-POLY1305
-
- - DHE-RSA-AES128-GCM-SHA256
-
- - DHE-RSA-AES256-GCM-SHA384
-
- minTLSVersion: VersionTLS12
nullable: true
type: object
modern:
description: |-
- modern is a TLS security profile based on:
-
- https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
-
- and looks like this (yaml):
+ modern is a TLS security profile for use with clients that support TLS 1.3 and
+ do not need backward compatibility for older clients.
+ This profile is equivalent to a Custom profile specified as:
+ minTLSVersion: VersionTLS13
ciphers:
-
- TLS_AES_128_GCM_SHA256
-
- TLS_AES_256_GCM_SHA384
-
- TLS_CHACHA20_POLY1305_SHA256
-
- minTLSVersion: VersionTLS13
nullable: true
type: object
old:
description: |-
- old is a TLS security profile based on:
-
- https://wiki.mozilla.org/Security/Server_Side_TLS#Old_backward_compatibility
-
- and looks like this (yaml):
+ old is a TLS profile for use when services need to be accessed by very old
+ clients or libraries and should be used only as a last resort.
+ This profile is equivalent to a Custom profile specified as:
+ minTLSVersion: VersionTLS10
ciphers:
-
- TLS_AES_128_GCM_SHA256
-
- TLS_AES_256_GCM_SHA384
-
- TLS_CHACHA20_POLY1305_SHA256
-
- ECDHE-ECDSA-AES128-GCM-SHA256
-
- ECDHE-RSA-AES128-GCM-SHA256
-
- ECDHE-ECDSA-AES256-GCM-SHA384
-
- ECDHE-RSA-AES256-GCM-SHA384
-
- ECDHE-ECDSA-CHACHA20-POLY1305
-
- ECDHE-RSA-CHACHA20-POLY1305
-
- - DHE-RSA-AES128-GCM-SHA256
-
- - DHE-RSA-AES256-GCM-SHA384
-
- - DHE-RSA-CHACHA20-POLY1305
-
- ECDHE-ECDSA-AES128-SHA256
-
- ECDHE-RSA-AES128-SHA256
-
- ECDHE-ECDSA-AES128-SHA
-
- ECDHE-RSA-AES128-SHA
-
- - ECDHE-ECDSA-AES256-SHA384
-
- - ECDHE-RSA-AES256-SHA384
-
- ECDHE-ECDSA-AES256-SHA
-
- ECDHE-RSA-AES256-SHA
-
- - DHE-RSA-AES128-SHA256
-
- - DHE-RSA-AES256-SHA256
-
- AES128-GCM-SHA256
-
- AES256-GCM-SHA384
-
- AES128-SHA256
-
- - AES256-SHA256
-
- AES128-SHA
-
- AES256-SHA
-
- DES-CBC3-SHA
-
- minTLSVersion: VersionTLS10
nullable: true
type: object
type:
description: |-
- type is one of Old, Intermediate, Modern or Custom. Custom provides
- the ability to specify individual TLS security profile parameters.
- Old, Intermediate and Modern are TLS security profiles based on:
-
- https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations
+ type is one of Old, Intermediate, Modern or Custom. Custom provides the
+ ability to specify individual TLS security profile parameters.
- The profiles are intent based, so they may change over time as new ciphers are developed and existing ciphers
- are found to be insecure. Depending on precisely which ciphers are available to a process, the list may be
- reduced.
+ The profiles are based on version 5.7 of the Mozilla Server Side TLS
+ configuration guidelines. The cipher lists consist of the configuration's
+ "ciphersuites" followed by the Go-specific "ciphers" from the guidelines.
+ See: https://ssl-config.mozilla.org/guidelines/5.7.json
- Note that the Modern profile is currently not supported because it is not
- yet well adopted by common software libraries.
+ The profiles are intent based, so they may change over time as new ciphers are
+ developed and existing ciphers are found to be insecure. Depending on
+ precisely which ciphers are available to a process, the list may be reduced.
enum:
- Old
- Intermediate
@@ -3307,11 +3241,14 @@ spec:
ciphers:
description: |-
ciphers is used to specify the cipher algorithms that are negotiated
- during the TLS handshake. Operators may remove entries their operands
- do not support. For example, to use DES-CBC3-SHA (yaml):
+ during the TLS handshake. Operators may remove entries that their operands
+ do not support. For example, to use only ECDHE-RSA-AES128-GCM-SHA256 (yaml):
ciphers:
- - DES-CBC3-SHA
+ - ECDHE-RSA-AES128-GCM-SHA256
+
+ TLS 1.3 cipher suites (e.g. TLS_AES_128_GCM_SHA256) are not configurable
+ and are always enabled when TLS 1.3 is negotiated.
items:
type: string
type: array
@@ -3323,8 +3260,6 @@ spec:
versions 1.1, 1.2 and 1.3 (yaml):
minTLSVersion: VersionTLS11
-
- NOTE: currently the highest minTLSVersion allowed is VersionTLS12
enum:
- VersionTLS10
- VersionTLS11
diff --git a/pkg/operator/controller/gatewayclass/controller.go b/pkg/operator/controller/gatewayclass/controller.go
index f409d3c4e9..5ae9b45b17 100644
--- a/pkg/operator/controller/gatewayclass/controller.go
+++ b/pkg/operator/controller/gatewayclass/controller.go
@@ -3,19 +3,27 @@ package gatewayclass
import (
"context"
"fmt"
+ "slices"
+ "strings"
"sync"
+ "time"
logf "github.com/openshift/cluster-ingress-operator/pkg/log"
operatorcontroller "github.com/openshift/cluster-ingress-operator/pkg/operator/controller"
- sailv1 "github.com/istio-ecosystem/sail-operator/api/v1"
operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
+ "k8s.io/client-go/rest"
"k8s.io/client-go/tools/record"
+ "k8s.io/client-go/util/workqueue"
gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1"
+ sailv1 "github.com/istio-ecosystem/sail-operator/api/v1"
+ "github.com/istio-ecosystem/sail-operator/pkg/install"
+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
+ "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
@@ -23,6 +31,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
+ "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/predicate"
@@ -71,6 +80,14 @@ const (
// can be specified. This annotation is only intended for use by
// OpenShift developers.
istioVersionOverrideAnnotationKey = "unsupported.do-not-use.openshift.io/istio-version"
+ // sailLibraryFinalizer is a finalizer key added to GatewayClasses that
+ // at some moment were reconciled by sail-library.
+ // They signal two things:
+ // 1 - For sail-library, if there is no other gatewayclass using it, the reconciliation
+ // can be stopped
+ // 2 - For olm-install - In case it is called, it means the installation was rolled
+ // back and the finalizer must be removed
+ sailLibraryFinalizer = "openshift.io/ingress-operator-sail-finalizer"
)
var log = logf.Logger.WithName(controllerName)
@@ -81,11 +98,13 @@ var gatewayClassController controller.Controller
// that the manager does not start it.
func NewUnmanaged(mgr manager.Manager, config Config) (controller.Controller, error) {
operatorCache := mgr.GetCache()
+
reconciler := &reconciler{
- config: config,
- client: mgr.GetClient(),
- cache: operatorCache,
- recorder: mgr.GetEventRecorderFor(controllerName),
+ config: config,
+ client: mgr.GetClient(),
+ cache: operatorCache,
+ kubeConfig: config.KubeConfig,
+ recorder: mgr.GetEventRecorderFor(controllerName),
}
options := controller.Options{Reconciler: reconciler}
options.DefaultFromConfig(mgr.GetControllerOptions())
@@ -104,21 +123,11 @@ func NewUnmanaged(mgr manager.Manager, config Config) (controller.Controller, er
return nil, err
}
- isServiceMeshSubscription := predicate.NewPredicateFuncs(func(o client.Object) bool {
- return o.GetName() == operatorcontroller.ServiceMeshOperatorSubscriptionName().Name
- })
- if err = c.Watch(source.Kind[client.Object](operatorCache, &operatorsv1alpha1.Subscription{},
- reconciler.enqueueRequestForSomeGatewayClass(), isServiceMeshSubscription)); err != nil {
- return nil, err
- }
-
isOurInstallPlan := predicate.NewPredicateFuncs(func(o client.Object) bool {
installPlan := o.(*operatorsv1alpha1.InstallPlan)
if len(installPlan.Spec.ClusterServiceVersionNames) > 0 {
- for _, csv := range installPlan.Spec.ClusterServiceVersionNames {
- if csv == config.GatewayAPIOperatorVersion {
- return true
- }
+ if slices.Contains(installPlan.Spec.ClusterServiceVersionNames, config.GatewayAPIOperatorVersion) {
+ return true
}
}
return false
@@ -130,9 +139,6 @@ func NewUnmanaged(mgr manager.Manager, config Config) (controller.Controller, er
installPlan := o.(*operatorsv1alpha1.InstallPlan)
return !installPlan.Spec.Approved && installPlan.Status.Phase == operatorsv1alpha1.InstallPlanPhaseRequiresApproval
})
- if err := c.Watch(source.Kind[client.Object](operatorCache, &operatorsv1alpha1.InstallPlan{}, reconciler.enqueueRequestForSomeGatewayClass(), isOurInstallPlan, isInstallPlanReadyForApproval)); err != nil {
- return nil, err
- }
// Watch for the InferencePool CRD to determine whether to enable
// Gateway API Inference Extension (GIE) on the Istio control-plane.
@@ -144,8 +150,54 @@ func NewUnmanaged(mgr manager.Manager, config Config) (controller.Controller, er
return false
}
})
- if err := c.Watch(source.Kind[client.Object](operatorCache, &apiextensionsv1.CustomResourceDefinition{}, reconciler.enqueueRequestForSomeGatewayClass(), isInferencepoolCrd)); err != nil {
- return nil, err
+
+ if !config.GatewayAPIWithoutOLMEnabled {
+ isServiceMeshSubscription := predicate.NewPredicateFuncs(func(o client.Object) bool {
+ return o.GetName() == operatorcontroller.ServiceMeshOperatorSubscriptionName().Name
+ })
+ if err = c.Watch(source.Kind[client.Object](operatorCache, &operatorsv1alpha1.Subscription{},
+ reconciler.enqueueRequestForSomeGatewayClass(), isServiceMeshSubscription)); err != nil {
+ return nil, err
+ }
+ if err := c.Watch(source.Kind[client.Object](operatorCache, &operatorsv1alpha1.InstallPlan{}, reconciler.enqueueRequestForSomeGatewayClass(), isOurInstallPlan, isInstallPlanReadyForApproval)); err != nil {
+ return nil, err
+ }
+ if err := c.Watch(source.Kind[client.Object](operatorCache, &apiextensionsv1.CustomResourceDefinition{}, reconciler.enqueueRequestForSomeGatewayClass(), isInferencepoolCrd)); err != nil {
+ return nil, err
+ }
+ } else {
+ // On OLM we need to watch Subscriptions, InstallPlans and CRDs differently.
+ // Any change on any subscription, installplan (if ours) or CRD (if Istio or GIE) must:
+ // - Trigger a new installer enqueue (part of enqueueRequestForSubscriptionChange)
+ // - Trigger a reconciliation for ALL (and not SOME) classes we manage to add status
+ isIstioCRD := predicate.NewPredicateFuncs(func(o client.Object) bool {
+ return strings.Contains(o.GetName(), "istio.io")
+ })
+
+ if err = c.Watch(source.Kind[client.Object](operatorCache, &operatorsv1alpha1.Subscription{},
+ reconciler.enqueueRequestForSubscriptionChange())); err != nil {
+ return nil, err
+ }
+ if err := c.Watch(source.Kind[client.Object](operatorCache, &operatorsv1alpha1.InstallPlan{}, reconciler.enqueueRequestForSubscriptionChange(), isOurInstallPlan)); err != nil {
+ return nil, err
+ }
+ if err := c.Watch(source.Kind[client.Object](operatorCache, &apiextensionsv1.CustomResourceDefinition{}, reconciler.enqueueRequestForSubscriptionChange(), predicate.Or(isInferencepoolCrd, isIstioCRD))); err != nil {
+ return nil, err
+ }
+
+ // For Non-OLM install, we start the sail-operator library that
+ // does the reconciliation of CRDs and resources.
+ // The channel here receives notification from the previously started sail-operator library
+ // and triggers new reconciliations
+ if config.SailOperatorReconciler != nil && config.SailOperatorReconciler.NotifyCh != nil {
+ sailOperatorSource := &SailOperatorSource[client.Object]{
+ NotifyCh: config.SailOperatorReconciler.NotifyCh,
+ RequestsFunc: reconciler.allManagedGatewayClasses,
+ }
+ if err := c.Watch(sailOperatorSource); err != nil {
+ return nil, err
+ }
+ }
}
gatewayClassController = c
@@ -155,8 +207,9 @@ func NewUnmanaged(mgr manager.Manager, config Config) (controller.Controller, er
// Config holds all the configuration that must be provided when creating the
// controller.
type Config struct {
- // OperatorNamespace is the namespace in which the operator should
- // create the Istio CR.
+ // KubeConfig is the Kubernetes client configuration used by the Sail Library.
+ KubeConfig *rest.Config
+ // OperatorNamespace is the namespace in which the operator is deployed.
OperatorNamespace string
// OperandNamespace is the namespace in which Istio should be deployed.
OperandNamespace string
@@ -166,75 +219,182 @@ type Config struct {
GatewayAPIOperatorChannel string
// GatewayAPIOperatorVersion is the name and release of the Gateway API implementation to install.
GatewayAPIOperatorVersion string
- // IstioVersion is the version of Istio to configure on the Istio CR.
+ // GatewayAPIWithoutOLMEnabled indicates whether the GatewayAPIWithoutOLM feature gate is enabled.
+ GatewayAPIWithoutOLMEnabled bool
+ // IstioVersion is the version of Istio to install.
IstioVersion string
+ // SailOperatorReconciler contains the instance and the notification channel for the reconciler of Istio resources
+ SailOperatorReconciler *SailOperatorReconciler
+}
+
+// SailLibraryInstaller implements the methods of sail library but in a way we can
+// also mock and test
+type SailLibraryInstaller interface {
+ Start(ctx context.Context) <-chan struct{}
+ Apply(opts install.Options)
+ Uninstall(ctx context.Context, namespace, revision string) error
+ Status() install.Status
+ Enqueue()
+}
+
+type SailOperatorReconciler struct {
+ Installer SailLibraryInstaller
+ NotifyCh <-chan struct{}
}
// reconciler reconciles gatewayclasses.
type reconciler struct {
config Config
- client client.Client
- cache cache.Cache
- recorder record.EventRecorder
+ client client.Client
+ cache cache.Cache
+ kubeConfig *rest.Config
+ recorder record.EventRecorder
startIstioWatch sync.Once
}
+func (r *reconciler) enqueueRequestForSubscriptionChange() handler.EventHandler {
+ return handler.EnqueueRequestsFromMapFunc(
+ func(ctx context.Context, obj client.Object) []reconcile.Request {
+ // If this is OLM and we detect the change of subscriptions, we must
+ // enforce that Sail Installer also enqueues a new reconciliation
+ if r.config.SailOperatorReconciler != nil && r.config.SailOperatorReconciler.Installer != nil {
+ // We can call Enqueue as many times as we want, as sail-library should enqueue and filter
+ // and not make concurrent operations
+ r.config.SailOperatorReconciler.Installer.Enqueue()
+ }
+ return r.allManagedGatewayClasses(ctx, obj)
+ })
+}
+
// enqueueRequestForSomeGatewayClass enqueues a reconciliation request for the
// gatewayclass that has the earliest creation timestamp and that specifies our
// controller name.
func (r *reconciler) enqueueRequestForSomeGatewayClass() handler.EventHandler {
return handler.EnqueueRequestsFromMapFunc(
- func(ctx context.Context, _ client.Object) []reconcile.Request {
- requests := []reconcile.Request{}
+ func(ctx context.Context, obj client.Object) []reconcile.Request {
+ if r.config.GatewayAPIWithoutOLMEnabled {
+ return r.allManagedGatewayClasses(ctx, obj)
+ }
+ return r.requestsForSomeGatewayClass(ctx, obj)
+ },
+ )
+}
- var gatewayClasses gatewayapiv1.GatewayClassList
- if err := r.cache.List(context.Background(), &gatewayClasses); err != nil {
- log.Error(err, "Failed to list gatewayclasses")
+func (r *reconciler) requestsForSomeGatewayClass(ctx context.Context, _ client.Object) []reconcile.Request {
+ requests := []reconcile.Request{}
+ var gatewayClasses gatewayapiv1.GatewayClassList
+ if err := r.cache.List(ctx, &gatewayClasses); err != nil {
+ log.Error(err, "Failed to list gatewayclasses")
- return requests
- }
+ return requests
+ }
- var (
- found bool
- oldest metav1.Time
- name string
- )
- for i := range gatewayClasses.Items {
- if gatewayClasses.Items[i].Spec.ControllerName != operatorcontroller.OpenShiftGatewayClassControllerName {
- continue
- }
+ var (
+ found bool
+ oldest metav1.Time
+ name string
+ )
+ for i := range gatewayClasses.Items {
+ if gatewayClasses.Items[i].Spec.ControllerName != operatorcontroller.OpenShiftGatewayClassControllerName {
+ continue
+ }
- ctime := gatewayClasses.Items[i].CreationTimestamp
- if !found || ctime.Before(&oldest) {
- found, oldest, name = true, ctime, gatewayClasses.Items[i].Name
- }
+ // If we ever added the sail library finalizer, this means this is a rollback so
+ // we need to be sure that the OLM process removes the finalizer and the status
+ if controllerutil.ContainsFinalizer(&gatewayClasses.Items[i], sailLibraryFinalizer) {
+ request := reconcile.Request{
+ NamespacedName: types.NamespacedName{
+ Namespace: "",
+ Name: gatewayClasses.Items[i].Name,
+ },
}
+ requests = append(requests, request)
+ continue
+ }
- if found {
- request := reconcile.Request{
- NamespacedName: types.NamespacedName{
- Namespace: "", // GatewayClass is cluster-scoped.
- Name: name,
- },
- }
- requests = append(requests, request)
- }
+ ctime := gatewayClasses.Items[i].CreationTimestamp
+ if !found || ctime.Before(&oldest) {
+ found, oldest, name = true, ctime, gatewayClasses.Items[i].Name
+ }
+ }
- return requests
- },
- )
+ if found {
+ request := reconcile.Request{
+ NamespacedName: types.NamespacedName{
+ Namespace: "", // GatewayClass is cluster-scoped.
+ Name: name,
+ },
+ }
+ requests = append(requests, request)
+ }
+
+ return requests
+}
+
+func (r *reconciler) allManagedGatewayClasses(ctx context.Context, _ client.Object) []reconcile.Request {
+ requests := []reconcile.Request{}
+ var gatewayClasses gatewayapiv1.GatewayClassList
+ if err := r.cache.List(ctx, &gatewayClasses, client.MatchingFields{
+ operatorcontroller.GatewayClassIndexFieldName: operatorcontroller.OpenShiftGatewayClassControllerName,
+ }); err != nil {
+ log.Error(err, "Failed to list gatewayclasses")
+ return requests
+ }
+
+ for _, class := range gatewayClasses.Items {
+ request := reconcile.Request{
+ NamespacedName: types.NamespacedName{
+ Namespace: "", // GatewayClass is cluster-scoped.
+ Name: class.Name,
+ },
+ }
+ requests = append(requests, request)
+ }
+
+ return requests
}
// Reconcile expects request to refer to a GatewayClass and creates or
// reconciles an Istio deployment.
func (r *reconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
+ if r.config.GatewayAPIWithoutOLMEnabled && r.config.SailOperatorReconciler != nil && r.config.SailOperatorReconciler.Installer != nil {
+ return r.reconcileWithSailLibrary(ctx, request)
+ }
+ return r.reconcileWithOLM(ctx, request)
+}
+
+// reconcileWithOLM reconciles a GatewayClass using OLM to install OSSM,
+// which then manages an Istio CR for the Istio installation.
+func (r *reconciler) reconcileWithOLM(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
log.Info("reconciling", "request", request)
- var gatewayclass gatewayapiv1.GatewayClass
- if err := r.cache.Get(ctx, request.NamespacedName, &gatewayclass); err != nil {
- return reconcile.Result{}, err
+ sourceGatewayClass := &gatewayapiv1.GatewayClass{}
+ if err := r.cache.Get(ctx, request.NamespacedName, sourceGatewayClass); err != nil {
+ if !errors.IsNotFound(err) {
+ return reconcile.Result{}, fmt.Errorf("error getting gatewayclass: %w", err)
+ }
+ return reconcile.Result{}, nil
+ }
+
+ gatewayclass := sourceGatewayClass.DeepCopy()
+ // This is not SailOperator class, so remove any finalizer and any status from it
+ if controllerutil.RemoveFinalizer(gatewayclass, sailLibraryFinalizer) {
+ var errs []error
+ err := r.client.Patch(ctx, gatewayclass, client.MergeFrom(sourceGatewayClass))
+ if err != nil {
+ log.Error(err, "error patching the gatewayclass status")
+ errs = append(errs, err)
+ }
+ removeSailOperatorConditions(&gatewayclass.Status.Conditions)
+ if err := r.client.Status().Patch(ctx, gatewayclass, client.MergeFrom(sourceGatewayClass)); err != nil {
+ log.Error(err, "error patching the gatewayclass status")
+ errs = append(errs, err)
+
+ }
+
+ return reconcile.Result{}, utilerrors.NewAggregate(errs) // Removing the finalizer should kick a new reconciliation
}
var errs []error
@@ -260,7 +420,7 @@ func (r *reconciler) Reconcile(ctx context.Context, request reconcile.Request) (
if v, ok := gatewayclass.Annotations[istioVersionOverrideAnnotationKey]; ok {
istioVersion = v
}
- if _, _, err := r.ensureIstio(ctx, &gatewayclass, istioVersion); err != nil {
+ if _, _, err := r.ensureIstioOLM(ctx, gatewayclass, istioVersion); err != nil {
errs = append(errs, err)
} else {
// The OSSM operator installs the istios.sailoperator.io CRD.
@@ -280,3 +440,114 @@ func (r *reconciler) Reconcile(ctx context.Context, request reconcile.Request) (
return reconcile.Result{}, utilerrors.NewAggregate(errs)
}
+
+// reconcileWithSailLibrary reconciles a GatewayClass using the Sail Library
+// for direct Helm-based installation of Istio.
+func (r *reconciler) reconcileWithSailLibrary(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
+ log.Info("reconciling", "request", request)
+
+ sourceGatewayClass := &gatewayapiv1.GatewayClass{}
+ if err := r.cache.Get(ctx, request.NamespacedName, sourceGatewayClass); err != nil {
+ if !errors.IsNotFound(err) {
+ return reconcile.Result{}, fmt.Errorf("error getting gatewayclass: %w", err)
+ }
+ return reconcile.Result{}, nil
+ }
+
+ gatewayclass := sourceGatewayClass.DeepCopy()
+
+ if !gatewayclass.DeletionTimestamp.IsZero() {
+ // Check if this is the last remaining GatewayClass. If so:
+ // 1 - Stop the library in case this is the last GatewayClass
+ // 2 - Delete the finalizer (always, regardless of being the last)
+ // 3 - We must always return from here when deletion is in progress
+ gatewayClassList := gatewayapiv1.GatewayClassList{}
+ if err := r.cache.List(ctx, &gatewayClassList, client.MatchingFields{
+ operatorcontroller.GatewayClassIndexFieldName: operatorcontroller.OpenShiftGatewayClassControllerName,
+ }); err != nil {
+ return reconcile.Result{}, fmt.Errorf("failed to list gateway classes: %w", err)
+ }
+
+ if len(gatewayClassList.Items) < 2 {
+ if err := r.config.SailOperatorReconciler.Installer.Uninstall(ctx, operatorcontroller.DefaultOperandNamespace, operatorcontroller.IstioName("").Name); err != nil {
+ return reconcile.Result{}, fmt.Errorf("failed to uninstall the operator: %w", err)
+ }
+ }
+ // This is not SailOperator class, so remove any finalizer
+ if controllerutil.RemoveFinalizer(gatewayclass, sailLibraryFinalizer) {
+ err := r.client.Patch(ctx, gatewayclass, client.MergeFrom(sourceGatewayClass))
+ if err != nil {
+ log.Error(err, "error patching the gatewayclass status")
+ }
+ return reconcile.Result{}, err // Removing the finalizer should kick a new reconciliation
+ }
+ // Finalizer already absent; nothing else to do during deletion.
+ return reconcile.Result{}, nil
+ }
+
+ if controllerutil.AddFinalizer(gatewayclass, sailLibraryFinalizer) {
+ err := r.client.Patch(ctx, gatewayclass, client.MergeFrom(sourceGatewayClass))
+ if err != nil {
+ log.Error(err, "error patching the gatewayclass status")
+ }
+ return reconcile.Result{}, err // Return if we added the finalizer, to kick reconciliation again
+ }
+
+ // Ensure migration from 4.21 to 4.22 Sail Library.
+ if migrationComplete, err := r.ensureOSSMtoSailLibraryMigration(ctx); err != nil {
+ return reconcile.Result{}, fmt.Errorf("error validating sail library migration: %w", err)
+ } else if !migrationComplete {
+ // Migration isn't complete - give OSSM time to clean up.
+ return reconcile.Result{RequeueAfter: 5 * time.Second}, nil
+ }
+
+ var errs []error
+
+ istioVersion := r.config.IstioVersion
+ if v, ok := gatewayclass.Annotations[istioVersionOverrideAnnotationKey]; ok {
+ istioVersion = v
+ }
+
+ if err := r.ensureIstio(ctx, gatewayclass, istioVersion); err != nil {
+ log.Error(err, "error ensuring Istio")
+ errs = append(errs, err)
+ }
+
+ if err := r.client.Status().Patch(ctx, gatewayclass, client.MergeFrom(sourceGatewayClass)); err != nil {
+ log.Error(err, "error patching the gatewayclass status")
+ errs = append(errs, err)
+ }
+
+ return reconcile.Result{}, utilerrors.NewAggregate(errs)
+}
+
+// SailOperatorSource bridges a sail operator channel to a MapFunc logic.
+// the Sail operator contains a source channel where notification for changes (like drifts)
+// can be sent back to our controller, so we trigger a reconciliation of our GatewayClass and its status
+type SailOperatorSource[T client.Object] struct {
+ NotifyCh <-chan struct{}
+ RequestsFunc func(context.Context, client.Object) []reconcile.Request
+}
+
+func (s *SailOperatorSource[T]) Start(ctx context.Context, queue workqueue.TypedRateLimitingInterface[reconcile.Request]) error {
+ go func() {
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ case _, ok := <-s.NotifyCh:
+ if !ok {
+ log.Info("sail operator notification channel closed, stopping watch")
+ return
+ }
+ var empty T
+ requests := s.RequestsFunc(ctx, empty)
+ log.Info("got notification from sail library")
+ for _, req := range requests {
+ queue.Add(req)
+ }
+ }
+ }
+ }()
+ return nil
+}
diff --git a/pkg/operator/controller/gatewayclass/controller_test.go b/pkg/operator/controller/gatewayclass/controller_test.go
index f3c193c2ee..a1f8ec37a0 100644
--- a/pkg/operator/controller/gatewayclass/controller_test.go
+++ b/pkg/operator/controller/gatewayclass/controller_test.go
@@ -3,6 +3,7 @@ package gatewayclass
import (
"context"
"testing"
+ "time"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
@@ -10,6 +11,7 @@ import (
configv1 "github.com/openshift/api/config/v1"
operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -51,6 +53,14 @@ func Test_Reconcile(t *testing.T) {
}
}
+ istioCRD := func() *apiextensionsv1.CustomResourceDefinition {
+ return &apiextensionsv1.CustomResourceDefinition{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "istios.sailoperator.io",
+ },
+ }
+ }
+
istio := func(version string, gieEnabled bool) *sailv1.Istio {
ret := &sailv1.Istio{
ObjectMeta: metav1.ObjectMeta{
@@ -126,27 +136,31 @@ func Test_Reconcile(t *testing.T) {
}
tests := []struct {
- name string
- request reconcile.Request
- existingObjects []runtime.Object
- expectCreate []client.Object
- expectUpdate []client.Object
- expectDelete []client.Object
- expectError string
+ name string
+ request reconcile.Request
+ expectedResult reconcile.Result
+ fakeHelmInstaller SailLibraryInstaller
+ existingObjects []client.Object
+ expectCreate []client.Object
+ expectUpdate []client.Object
+ expectPatched []client.Object
+ expectDelete []client.Object
+ expectedStatusPatched []client.Object
+ expectError string
}{
{
name: "Nonexistent gatewayclass",
request: req("openshift-default"),
- existingObjects: []runtime.Object{},
+ existingObjects: []client.Object{},
expectCreate: []client.Object{},
expectUpdate: []client.Object{},
expectDelete: []client.Object{},
- expectError: `"openshift-default" not found`,
+ //expectError: `"openshift-default" not found`, // We should not expect an error when a class is not found
},
{
name: "Minimal gatewayclass",
request: req("openshift-default"),
- existingObjects: []runtime.Object{
+ existingObjects: []client.Object{
&gatewayapiv1.GatewayClass{
ObjectMeta: metav1.ObjectMeta{
Name: "openshift-default",
@@ -166,7 +180,7 @@ func Test_Reconcile(t *testing.T) {
{
name: "Minimal gatewayclass with experimental InferencePool CRD",
request: req("openshift-default"),
- existingObjects: []runtime.Object{
+ existingObjects: []client.Object{
&gatewayapiv1.GatewayClass{
ObjectMeta: metav1.ObjectMeta{
Name: "openshift-default",
@@ -191,7 +205,7 @@ func Test_Reconcile(t *testing.T) {
{
name: "Minimal gatewayclass with stable InferencePool CRD",
request: req("openshift-default"),
- existingObjects: []runtime.Object{
+ existingObjects: []client.Object{
&gatewayapiv1.GatewayClass{
ObjectMeta: metav1.ObjectMeta{
Name: "openshift-default",
@@ -216,7 +230,7 @@ func Test_Reconcile(t *testing.T) {
{
name: "Gatewayclass with Istio version override",
request: req("openshift-default"),
- existingObjects: []runtime.Object{
+ existingObjects: []client.Object{
&gatewayapiv1.GatewayClass{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
@@ -239,7 +253,7 @@ func Test_Reconcile(t *testing.T) {
{
name: "Gatewayclass with OSSM and Istio overrides",
request: req("openshift-default"),
- existingObjects: []runtime.Object{
+ existingObjects: []client.Object{
&gatewayapiv1.GatewayClass{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
@@ -262,6 +276,164 @@ func Test_Reconcile(t *testing.T) {
expectUpdate: []client.Object{},
expectDelete: []client.Object{},
},
+ {
+ name: "Gatewayclass when has sail finalizer but helm fg is disabled should remove the finalizer and status",
+ request: req("openshift-default"),
+ existingObjects: []client.Object{
+ &gatewayapiv1.GatewayClass{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "openshift-default",
+ Finalizers: []string{"openshift.io/ingress-operator-sail-finalizer"},
+ },
+ Spec: gatewayapiv1.GatewayClassSpec{
+ ControllerName: gatewayapiv1.GatewayController("openshift.io/gateway-controller/v1"),
+ },
+ Status: gatewayapiv1.GatewayClassStatus{
+ Conditions: []metav1.Condition{
+ {
+ Type: ControllerInstalledConditionType,
+ Reason: "Something",
+ Status: metav1.ConditionUnknown,
+ },
+ {
+ Type: CRDsReadyConditionType,
+ Reason: "Otherthing",
+ Status: metav1.ConditionTrue,
+ },
+ },
+ },
+ },
+ },
+ expectPatched: []client.Object{
+ &gatewayapiv1.GatewayClass{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "openshift-default",
+ },
+ Spec: gatewayapiv1.GatewayClassSpec{
+ ControllerName: gatewayapiv1.GatewayController("openshift.io/gateway-controller/v1"),
+ },
+ Status: gatewayapiv1.GatewayClassStatus{
+ Conditions: []metav1.Condition{},
+ },
+ },
+ },
+ expectedStatusPatched: []client.Object{
+ &gatewayapiv1.GatewayClass{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "openshift-default",
+ },
+ Spec: gatewayapiv1.GatewayClassSpec{
+ ControllerName: gatewayapiv1.GatewayController("openshift.io/gateway-controller/v1"),
+ },
+ Status: gatewayapiv1.GatewayClassStatus{
+ Conditions: []metav1.Condition{},
+ },
+ },
+ },
+ },
+ {
+ name: "Gatewayclass when using helm installer should get finalizer",
+ fakeHelmInstaller: &fakeSailInstaller{},
+ request: req("openshift-default"),
+ existingObjects: []client.Object{
+ &gatewayapiv1.GatewayClass{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "openshift-default",
+ },
+ Spec: gatewayapiv1.GatewayClassSpec{
+ ControllerName: gatewayapiv1.GatewayController("openshift.io/gateway-controller/v1"),
+ },
+ },
+ },
+ expectPatched: []client.Object{
+ &gatewayapiv1.GatewayClass{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "openshift-default",
+ Finalizers: []string{"openshift.io/ingress-operator-sail-finalizer"},
+ },
+ Spec: gatewayapiv1.GatewayClassSpec{
+ ControllerName: gatewayapiv1.GatewayController("openshift.io/gateway-controller/v1"),
+ },
+ },
+ },
+ expectDelete: []client.Object{},
+ },
+ {
+ name: "Gatewayclass when using helm installer should migrate old Istio instances",
+ fakeHelmInstaller: &fakeSailInstaller{},
+ request: req("openshift-default"),
+ existingObjects: []client.Object{
+ &gatewayapiv1.GatewayClass{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "openshift-default",
+ Finalizers: []string{"openshift.io/ingress-operator-sail-finalizer"},
+ },
+ Spec: gatewayapiv1.GatewayClassSpec{
+ ControllerName: gatewayapiv1.GatewayController("openshift.io/gateway-controller/v1"),
+ },
+ },
+ istioCRD(),
+ istio("v1.24.4", true),
+ },
+ expectPatched: []client.Object{},
+ expectDelete: []client.Object{
+ istio("v1.24.4", true), // Expect this resource to be deleted
+ },
+ expectedResult: reconcile.Result{
+ RequeueAfter: 5 * time.Second,
+ },
+ },
+ {
+ name: "Gatewayclass when using helm installer and has no istio instance should install via helm",
+ fakeHelmInstaller: &fakeSailInstaller{},
+ request: req("openshift-default"),
+ existingObjects: []client.Object{
+ &gatewayapiv1.GatewayClass{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "openshift-default",
+ Finalizers: []string{"openshift.io/ingress-operator-sail-finalizer"},
+ },
+ Spec: gatewayapiv1.GatewayClassSpec{
+ ControllerName: gatewayapiv1.GatewayController("openshift.io/gateway-controller/v1"),
+ },
+ Status: gatewayapiv1.GatewayClassStatus{
+ Conditions: []metav1.Condition{},
+ },
+ },
+ },
+ expectedStatusPatched: []client.Object{
+ &gatewayapiv1.GatewayClass{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "openshift-default",
+ Finalizers: []string{"openshift.io/ingress-operator-sail-finalizer"},
+ },
+ Spec: gatewayapiv1.GatewayClassSpec{
+ ControllerName: gatewayapiv1.GatewayController("openshift.io/gateway-controller/v1"),
+ },
+ Status: gatewayapiv1.GatewayClassStatus{
+ Conditions: []metav1.Condition{
+ {
+ Type: "ControllerInstalled",
+ Status: metav1.ConditionTrue,
+ Reason: "Installed",
+ },
+ {
+ Type: "CRDsReady",
+ Status: metav1.ConditionUnknown,
+ Reason: "NoneExist",
+ },
+ },
+ },
+ },
+ },
+ },
+ /* TODO:
+ - Add tests for different conditions
+ - Verify if we can force some error on Istio removal
+ - Add a full "update/downgrade/update" test
+ - Add a test for GatewayClass removal when there are still classes (should not call Uninstall)
+ - Add a test for full removal
+ */
}
scheme := runtime.NewScheme()
@@ -275,14 +447,20 @@ func Test_Reconcile(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
fakeClient := fake.NewClientBuilder().
WithScheme(scheme).
- WithRuntimeObjects(tc.existingObjects...).
+ WithStatusSubresource(tc.existingObjects...).
+ WithObjects(tc.existingObjects...).
+ // TODO: add index
Build()
cl := &testutil.FakeClientRecorder{
- Client: fakeClient,
+ Client: fakeClient,
+ StatusWriter: &testutil.FakeStatusWriter{
+ StatusWriter: fakeClient.Status(),
+ },
T: t,
Added: []client.Object{},
Updated: []client.Object{},
Deleted: []client.Object{},
+ Patched: []client.Object{},
}
gatewayClassController = &testutil.FakeController{
T: t,
@@ -303,17 +481,27 @@ func Test_Reconcile(t *testing.T) {
IstioVersion: "v1.24.4",
},
}
+ if tc.fakeHelmInstaller != nil {
+ reconciler.config.GatewayAPIWithoutOLMEnabled = true
+ reconciler.config.SailOperatorReconciler = &SailOperatorReconciler{
+ Installer: tc.fakeHelmInstaller,
+ NotifyCh: tc.fakeHelmInstaller.Start(context.Background()),
+ }
+ }
res, err := reconciler.Reconcile(context.Background(), tc.request)
if tc.expectError != "" {
+ require.NotNil(t, err)
assert.Contains(t, err.Error(), tc.expectError)
} else {
assert.NoError(t, err)
}
- assert.Equal(t, reconcile.Result{}, res)
+
+ assert.Equal(t, tc.expectedResult, res)
cmpOpts := []cmp.Option{
cmpopts.EquateEmpty(),
cmpopts.IgnoreFields(metav1.ObjectMeta{}, "ResourceVersion", "OwnerReferences"),
cmpopts.IgnoreFields(metav1.TypeMeta{}, "Kind", "APIVersion"),
+ cmpopts.IgnoreFields(metav1.Condition{}, "LastTransitionTime", "Message"),
cmpopts.IgnoreFields(operatorsv1alpha1.SubscriptionSpec{}, "Config"),
cmpopts.IgnoreFields(apiextensionsv1.CustomResourceDefinition{}, "Spec"),
}
@@ -326,6 +514,12 @@ func Test_Reconcile(t *testing.T) {
if diff := cmp.Diff(tc.expectDelete, cl.Deleted, cmpOpts...); diff != "" {
t.Fatalf("found diff between expected and actual deletes: %s", diff)
}
+ if diff := cmp.Diff(tc.expectPatched, cl.Patched, cmpOpts...); diff != "" {
+ t.Fatalf("found diff between expected and actual patches: %s", diff)
+ }
+ if diff := cmp.Diff(tc.expectedStatusPatched, cl.StatusWriter.Patched, cmpOpts...); diff != "" {
+ t.Fatalf("found diff between expected and actual patches: %s", diff)
+ }
})
}
}
diff --git a/pkg/operator/controller/gatewayclass/istio.go b/pkg/operator/controller/gatewayclass/istio_olm.go
similarity index 86%
rename from pkg/operator/controller/gatewayclass/istio.go
rename to pkg/operator/controller/gatewayclass/istio_olm.go
index 4e1a1c2b40..05587bf571 100644
--- a/pkg/operator/controller/gatewayclass/istio.go
+++ b/pkg/operator/controller/gatewayclass/istio_olm.go
@@ -9,7 +9,6 @@ import (
gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1"
sailv1 "github.com/istio-ecosystem/sail-operator/api/v1"
-
"github.com/openshift/cluster-ingress-operator/pkg/operator/controller"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
@@ -23,10 +22,10 @@ import (
// cluster-critical priority class in a pod's spec.priorityClassName.
const systemClusterCriticalPriorityClassName = "system-cluster-critical"
-// ensureIstio attempts to ensure that an Istio CR is present and returns a
+// ensureIstioOLM attempts to ensure that an Istio CR is present and returns a
// Boolean indicating whether it exists, the CR if it exists, and an error
// value.
-func (r *reconciler) ensureIstio(ctx context.Context, gatewayclass *gatewayapiv1.GatewayClass, istioVersion string) (bool, *sailv1.Istio, error) {
+func (r *reconciler) ensureIstioOLM(ctx context.Context, gatewayclass *gatewayapiv1.GatewayClass, istioVersion string) (bool, *sailv1.Istio, error) {
name := controller.IstioName(r.config.OperandNamespace)
have, current, err := r.currentIstio(ctx, name)
if err != nil {
@@ -95,9 +94,10 @@ func (r *reconciler) crdExists(ctx context.Context, crdName string) (bool, error
return true, nil
}
-// desiredIstio returns the desired Istio CR.
-func desiredIstio(name types.NamespacedName, ownerRef metav1.OwnerReference, istioVersion string, enableInferenceExtension bool) *sailv1.Istio {
- pilotContainerEnv := map[string]string{
+// gatewayAPIPilotEnv returns the pilot environment variables for configuring
+// Istio's Gateway API controller with OpenShift-specific settings.
+func gatewayAPIPilotEnv(enableInferenceExtension bool) map[string]string {
+ env := map[string]string{
// Enable Gateway API.
"PILOT_ENABLE_GATEWAY_API": "true",
// Do not enable experimental Gateway API features.
@@ -146,8 +146,14 @@ func desiredIstio(name types.NamespacedName, ownerRef metav1.OwnerReference, ist
"PILOT_ENABLE_GATEWAY_API_COPY_LABELS_ANNOTATIONS": "false",
}
if enableInferenceExtension {
- pilotContainerEnv["ENABLE_GATEWAY_API_INFERENCE_EXTENSION"] = "true"
+ env["ENABLE_GATEWAY_API_INFERENCE_EXTENSION"] = "true"
}
+ return env
+}
+
+// desiredIstio returns the desired Istio CR.
+func desiredIstio(name types.NamespacedName, ownerRef metav1.OwnerReference, istioVersion string, enableInferenceExtension bool) *sailv1.Istio {
+ pilotContainerEnv := gatewayAPIPilotEnv(enableInferenceExtension)
return &sailv1.Istio{
ObjectMeta: metav1.ObjectMeta{
Namespace: name.Namespace,
@@ -278,3 +284,29 @@ func istioChanged(current, expected *sailv1.Istio) (bool, *sailv1.Istio) {
return true, updated
}
+
+// openshiftValues returns the OpenShift-specific value overrides for Istio.
+// These values are merged on top of the gateway-api preset defaults.
+func openshiftValues(enableInferenceExtension bool) *sailv1.Values {
+ pilotEnv := gatewayAPIPilotEnv(enableInferenceExtension)
+
+ return &sailv1.Values{
+ Global: &sailv1.GlobalConfig{
+ DefaultPodDisruptionBudget: &sailv1.DefaultPodDisruptionBudgetConfig{
+ Enabled: ptr.To(false),
+ },
+ IstioNamespace: ptr.To(controller.DefaultOperandNamespace),
+ // Use system-cluster-critical priority for OpenShift system workloads
+ PriorityClassName: ptr.To(systemClusterCriticalPriorityClassName),
+ // OpenShift-specific CA trust bundle
+ TrustBundleName: ptr.To(controller.OpenShiftGatewayCARootCertName),
+ },
+ Pilot: &sailv1.PilotConfig{
+ Env: pilotEnv,
+ // Workload partitioning for OpenShift management workloads
+ PodAnnotations: map[string]string{
+ WorkloadPartitioningManagementAnnotationKey: WorkloadPartitioningManagementPreferredScheduling,
+ },
+ },
+ }
+}
diff --git a/pkg/operator/controller/gatewayclass/istio_sail_installer.go b/pkg/operator/controller/gatewayclass/istio_sail_installer.go
new file mode 100644
index 0000000000..58f4960389
--- /dev/null
+++ b/pkg/operator/controller/gatewayclass/istio_sail_installer.go
@@ -0,0 +1,227 @@
+package gatewayclass
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "strings"
+
+ "github.com/istio-ecosystem/sail-operator/pkg/install"
+ "github.com/openshift/cluster-ingress-operator/pkg/operator/controller"
+ operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
+ apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
+ "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/utils/ptr"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1"
+)
+
+const (
+ ControllerInstalledConditionType = "ControllerInstalled"
+ CRDsReadyConditionType = "CRDsReady"
+
+ subscriptionPrefix = "operators.coreos.com/"
+)
+
+// SubscriptionExists is used as a predicate function to allow the library to
+// query CIO if a subscription exists before taking an action over a CRD
+func (r *reconciler) overwriteOLMManagedCRDFunc(ctx context.Context, crd *apiextensionsv1.CustomResourceDefinition) bool {
+ // defensive measure
+ if ctx == nil || crd == nil {
+ return false
+ }
+
+ logOverwrite := log.WithValues("crd", crd.GetName())
+
+ labels := crd.GetLabels()
+ if labels == nil {
+ // no labels, we can override
+ return true
+ }
+
+ // This is not a OLM managed CRD
+ if val, ok := labels["olm.managed"]; !ok || val != "true" {
+ return true
+ }
+
+ var subscriptionName, subscriptionNamespace, foundLabel string
+ // we just care about the label name
+ for label := range labels {
+ if after, ok := strings.CutPrefix(label, subscriptionPrefix); ok {
+ // Check if label is on the format we want
+ nameNamespace := strings.SplitN(after, ".", 2)
+ if len(nameNamespace) != 2 {
+ logOverwrite.Info("ignoring invalid OLM label", "label", label)
+ continue
+ }
+ foundLabel = label
+ subscriptionName, subscriptionNamespace = nameNamespace[0], nameNamespace[1]
+ break
+ }
+ }
+
+ if foundLabel == "" || subscriptionName == "" || subscriptionNamespace == "" {
+ logOverwrite.Info("no subscription label found")
+ return true
+ }
+
+ // Check for InstallPlan, which effectively installs CRDs. Even if invalid it
+ // may become valid at some point and overwrite CRDs
+ installPlanList := operatorsv1alpha1.InstallPlanList{}
+ if err := r.cache.List(ctx, &installPlanList, client.HasLabels([]string{foundLabel})); err != nil {
+ log.Error(err, "error trying to find install plans")
+ return false
+ }
+ if len(installPlanList.Items) > 0 {
+ logOverwrite.Info("CRD has valid installPlans, not overwriting")
+ return false
+ }
+
+ // Next check for subscriptions.
+ subscription := operatorsv1alpha1.Subscription{}
+ subscription.SetNamespace(subscriptionNamespace)
+ subscription.SetName(subscriptionName)
+ err := r.cache.Get(ctx, client.ObjectKeyFromObject(&subscription), &subscription)
+ if err != nil {
+ if !errors.IsNotFound(err) {
+ log.Error(err, "error trying to find subscription")
+ return false
+ }
+ // No subscription was found, the CRD can be overwritten
+ return true
+ }
+ // If we are here means we don't have installplans, but we do have subscriptions
+ // which means we may be on an intermediate state
+ return false
+}
+
+// ensureIstio installs or updates Istio using the Sail Library.
+// It returns an error if the installation fails.
+func (r *reconciler) ensureIstio(ctx context.Context, gatewayclass *gatewayapiv1.GatewayClass, istioVersion string) error {
+ if r.config.SailOperatorReconciler == nil || r.config.SailOperatorReconciler.Installer == nil {
+ return fmt.Errorf("internal error: sail operator is null")
+ }
+ sailInstaller := r.config.SailOperatorReconciler.Installer
+
+ enableInferenceExtension, err := r.inferencepoolCrdExists(ctx)
+ if err != nil {
+ return fmt.Errorf("failed to check for InferencePool CRD: %w", err)
+ }
+
+ // Build options from current state
+ opts, err := r.buildInstallerOptions(enableInferenceExtension, istioVersion)
+ if err != nil {
+ return err
+ }
+
+ opts.OverwriteOLMManagedCRD = r.overwriteOLMManagedCRDFunc
+ // Enqueue the request to reconcile. This does not return
+ // any error or status. We validate the status again next, and set
+ // the right conditions on the GatewayClass for it
+ sailInstaller.Apply(opts)
+
+ status := sailInstaller.Status()
+ log.V(1).Info("CRD management result", "status", status.CRDs)
+
+ mapStatusToConditions(status, gatewayclass.Generation, &gatewayclass.Status.Conditions)
+
+ return nil
+}
+
+func (r *reconciler) buildInstallerOptions(enableInferenceExtension bool, istioVersion string) (install.Options, error) {
+ // Start with Gateway API defaults
+ values := install.GatewayAPIDefaults()
+
+ // Apply OpenShift-specific overrides
+ openshiftOverrides := openshiftValues(enableInferenceExtension)
+ values = install.MergeValues(values, openshiftOverrides)
+
+ return install.Options{
+ Namespace: controller.DefaultOperandNamespace,
+ Revision: controller.IstioName("").Name,
+ Values: values,
+ Version: istioVersion,
+ ManageCRDs: ptr.To(true),
+ IncludeAllCRDs: ptr.To(true),
+ }, nil
+}
+
+// mapStatusToConditions translates the library Status into GatewayClass conditions.
+func mapStatusToConditions(status install.Status, generation int64, conditions *[]metav1.Condition) {
+ installed := metav1.Condition{
+ Type: ControllerInstalledConditionType,
+ ObservedGeneration: generation,
+ LastTransitionTime: metav1.Now(),
+ }
+ if status.Installed {
+ installed.Status = metav1.ConditionTrue
+ installed.Reason = "Installed"
+ if status.Error != nil {
+ installed.Message = fmt.Sprintf("istiod %s installed (with warning: %v)", status.Version, status.Error)
+ } else {
+ installed.Message = fmt.Sprintf("istiod %s installed", status.Version)
+ }
+ } else if status.Error != nil {
+ installed.Status = metav1.ConditionFalse
+ installed.Reason = "InstallFailed"
+ installed.Message = status.Error.Error()
+ } else {
+ installed.Status = metav1.ConditionUnknown
+ installed.Reason = "Pending"
+ installed.Message = "waiting for first reconciliation"
+ }
+
+ meta.SetStatusCondition(conditions, installed)
+
+ // CRD condition: reflects CRD ownership state.
+ crd := metav1.Condition{
+ Type: CRDsReadyConditionType,
+ ObservedGeneration: generation,
+ LastTransitionTime: metav1.Now(),
+ }
+ switch status.CRDState {
+ case install.CRDManagedByCIO:
+ crd.Status = metav1.ConditionTrue
+ crd.Reason = "ManagedByCIO"
+ crd.Message = status.CRDMessage
+ case install.CRDManagedByOLM:
+ crd.Status = metav1.ConditionTrue
+ crd.Reason = "ManagedByOLM"
+ crd.Message = status.CRDMessage
+ case install.CRDNoneExist:
+ crd.Status = metav1.ConditionUnknown
+ crd.Reason = "NoneExist"
+ crd.Message = "CRDs not yet installed"
+ case install.CRDMixedOwnership:
+ crd.Status = metav1.ConditionFalse
+ crd.Reason = "MixedOwnership"
+ crd.Message = getCRDStatusMessage(status)
+ default:
+ crd.Status = metav1.ConditionFalse
+ crd.Reason = "UnknownManagement"
+ crd.Message = getCRDStatusMessage(status)
+ }
+ meta.SetStatusCondition(conditions, crd)
+}
+
+func removeSailOperatorConditions(conditions *[]metav1.Condition) {
+ meta.RemoveStatusCondition(conditions, ControllerInstalledConditionType)
+ meta.RemoveStatusCondition(conditions, CRDsReadyConditionType)
+}
+
+func getCRDStatusMessage(status install.Status) string {
+ var message bytes.Buffer
+ if _, err := message.WriteString(status.CRDMessage); err != nil {
+ log.Error(err, "error writing CRD status", "status", status.CRDMessage)
+ }
+ for _, info := range status.CRDs {
+ crdMsg := fmt.Sprintf("\n- %s: %s", info.Name, info.State)
+ _, err := message.WriteString(crdMsg)
+ if err != nil {
+ log.Error(err, "error writing CRD message", "crd", info.Name)
+ }
+ }
+ return message.String()
+}
diff --git a/pkg/operator/controller/gatewayclass/istio_sail_installer_test.go b/pkg/operator/controller/gatewayclass/istio_sail_installer_test.go
new file mode 100644
index 0000000000..c8c6255dac
--- /dev/null
+++ b/pkg/operator/controller/gatewayclass/istio_sail_installer_test.go
@@ -0,0 +1,55 @@
+package gatewayclass
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/istio-ecosystem/sail-operator/pkg/install"
+)
+
+// fakeSailInstaller implements the Istio methods for installation
+// We care for now just about Apply, Uninstall and Status for the reconciliation tests
+type fakeSailInstaller struct {
+ notifyCh chan struct{}
+ internalOpts install.Options
+ status install.Status
+}
+
+// Test if implementation adheres the interface
+var _ SailLibraryInstaller = &fakeSailInstaller{}
+
+func (i *fakeSailInstaller) Start(ctx context.Context) <-chan struct{} {
+ i.notifyCh = make(chan struct{})
+ return i.notifyCh
+}
+
+func (i *fakeSailInstaller) Apply(opts install.Options) {
+ // This is where we fake behavior
+ switch opts.Version {
+ case "ok-helm":
+ i.status.Installed = true
+ i.status.CRDState = install.CRDManagedByCIO
+ case "ok-olm":
+ i.status.Installed = true
+ i.status.CRDState = install.CRDManagedByOLM
+ case "ok-mixed":
+ i.status.Installed = true
+ i.status.CRDState = install.CRDMixedOwnership
+ case "broken":
+ i.status.Error = fmt.Errorf("broken installation")
+ i.status.CRDState = install.CRDUnknownManagement
+ default:
+ i.status.Installed = true
+ i.status.CRDState = install.CRDNoneExist
+ }
+}
+
+func (i *fakeSailInstaller) Uninstall(ctx context.Context, namespace, revision string) error {
+ return nil
+}
+
+func (i *fakeSailInstaller) Status() install.Status {
+ return i.status
+}
+
+func (i *fakeSailInstaller) Enqueue() {}
diff --git a/pkg/operator/controller/gatewayclass/migration.go b/pkg/operator/controller/gatewayclass/migration.go
new file mode 100644
index 0000000000..77dadb1216
--- /dev/null
+++ b/pkg/operator/controller/gatewayclass/migration.go
@@ -0,0 +1,104 @@
+package gatewayclass
+
+import (
+ "context"
+ "fmt"
+
+ sailv1 "github.com/istio-ecosystem/sail-operator/api/v1"
+
+ "github.com/openshift/cluster-ingress-operator/pkg/operator/controller"
+
+ "k8s.io/apimachinery/pkg/api/errors"
+)
+
+// ensureOSSMtoSailLibraryMigration handles the upgrade migration from OLM-based
+// Istio installation (4.21) to Helm-based installation via Sail Library (4.22).
+//
+// Steps:
+// 1. Check if old Istio CR exists and delete it if present
+// 2. Wait for Sail Operator to clean up IstioRevision and Helm resources
+// 3. Return nil when cleanup is complete to proceed with Helm-based installation
+//
+// Returns a bool whether the migration is complete and an error.
+//
+// This migration logic can be removed in 4.23+ when 4.21 is no longer supported.
+func (r *reconciler) ensureOSSMtoSailLibraryMigration(ctx context.Context) (bool, error) {
+ // Check if migration is needed.
+ needsMigration, istio, err := r.needsOSSMtoSailLibraryMigration(ctx)
+ if err != nil {
+ return false, fmt.Errorf("failed to check migration status: %w", err)
+ }
+ if !needsMigration {
+ // No Istio CR found, check if we're waiting for IstioRevision cleanup.
+ istioRevisionExists, err := r.istioRevisionExists(ctx)
+ if err != nil {
+ return false, fmt.Errorf("failed to check for IstioRevision: %w", err)
+ }
+ if istioRevisionExists {
+ log.Info("IstioRevision still exists, requeueing to wait for cleanup", "name", controller.IstioName("").Name)
+ return false, nil
+ }
+ return true, nil
+ }
+
+ // Istio CR exists - delete it to trigger Sail Operator cleanup.
+ log.Info("Migrating from OSSM to Sail Library: deleting Istio CR", "name", controller.IstioName(""))
+
+ if err := r.client.Delete(ctx, istio); err != nil {
+ if errors.IsNotFound(err) {
+ // Already deleted between Get and Delete, that's fine.
+ log.Info("Istio CR already deleted during migration", "name", controller.IstioName(""))
+ return false, nil
+ }
+ return false, fmt.Errorf("failed to delete Istio CR: %w", err)
+ }
+
+ // Waiting for istio revision cleanup.
+ return false, nil
+}
+
+func (r *reconciler) needsOSSMtoSailLibraryMigration(ctx context.Context) (bool, *sailv1.Istio, error) {
+ // First check if the Istio CRD exists.
+ istioCrdExists, err := r.crdExists(ctx, "istios.sailoperator.io")
+ if err != nil {
+ return false, nil, fmt.Errorf("failed to check for Istio CRD: %w", err)
+ }
+ if !istioCrdExists {
+ return false, nil, nil
+ }
+
+ // Check if the specific Istio CR "openshift-gateway" exists.
+ name := controller.IstioName(r.config.OperandNamespace)
+ exists, istio, err := r.currentIstio(ctx, name)
+ if err != nil {
+ return false, nil, fmt.Errorf("failed to check for Istio CR: %w", err)
+ }
+ if !exists {
+ return false, nil, nil
+ }
+
+ return true, istio, nil
+}
+
+// istioRevisionExists checks if an IstioRevision resource exists with the expected name.
+func (r *reconciler) istioRevisionExists(ctx context.Context) (bool, error) {
+ istioRevisionCrdExists, err := r.crdExists(ctx, "istiorevisions.sailoperator.io")
+ if err != nil {
+ return false, fmt.Errorf("failed to check for IstioRevision CRD: %w", err)
+ }
+ if !istioRevisionCrdExists {
+ return false, nil
+ }
+
+ // Check if the IstioRevision resource exists.
+ istioRevisionName := controller.IstioName("")
+ istioRevision := &sailv1.IstioRevision{}
+ err = r.client.Get(ctx, istioRevisionName, istioRevision)
+ if err != nil {
+ if errors.IsNotFound(err) {
+ return false, nil
+ }
+ return false, fmt.Errorf("failed to get IstioRevision: %w", err)
+ }
+ return true, nil
+}
diff --git a/pkg/operator/controller/test/util/fake.go b/pkg/operator/controller/test/util/fake.go
index f49acd5af8..026dde81d9 100644
--- a/pkg/operator/controller/test/util/fake.go
+++ b/pkg/operator/controller/test/util/fake.go
@@ -29,6 +29,7 @@ type FakeClientRecorder struct {
Added []client.Object
Updated []client.Object
Deleted []client.Object
+ Patched []client.Object
StatusWriter *FakeStatusWriter
}
@@ -69,6 +70,7 @@ func (c *FakeClientRecorder) Update(ctx context.Context, obj client.Object, opts
}
func (c *FakeClientRecorder) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
+ c.Patched = append(c.Patched, obj)
return c.Client.Patch(ctx, obj, patch, opts...)
}
@@ -84,6 +86,7 @@ type FakeStatusWriter struct {
Added []client.Object
Updated []client.Object
+ Patched []client.Object
}
func (w *FakeStatusWriter) Create(ctx context.Context, obj client.Object, subResource client.Object, opts ...client.SubResourceCreateOption) error {
@@ -97,6 +100,7 @@ func (w *FakeStatusWriter) Update(ctx context.Context, obj client.Object, opts .
}
func (w *FakeStatusWriter) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.SubResourcePatchOption) error {
+ w.Patched = append(w.Patched, obj)
return w.StatusWriter.Patch(ctx, obj, patch, opts...)
}
diff --git a/pkg/operator/operator.go b/pkg/operator/operator.go
index ff5457f84b..e9f19095c3 100644
--- a/pkg/operator/operator.go
+++ b/pkg/operator/operator.go
@@ -3,8 +3,12 @@ package operator
import (
"context"
"fmt"
+ "os"
+ "strconv"
"time"
+ "github.com/istio-ecosystem/sail-operator/pkg/install"
+ "github.com/istio-ecosystem/sail-operator/resources"
configclient "github.com/openshift/client-go/config/clientset/versioned"
configinformers "github.com/openshift/client-go/config/informers/externalversions"
"github.com/openshift/library-go/pkg/operator/configobserver/featuregates"
@@ -136,6 +140,18 @@ func New(config operatorconfig.Config, kubeConfig *rest.Config) (*Operator, erro
azureWorkloadIdentityEnabled := featureGates.Enabled(features.FeatureGateAzureWorkloadIdentity)
gatewayAPIEnabled := featureGates.Enabled(features.FeatureGateGatewayAPI)
gatewayAPIControllerEnabled := featureGates.Enabled(features.FeatureGateGatewayAPIController)
+ //gatewayAPIWithoutOLMEnabled := featureGates.Enabled(features.FeatureGateGatewayAPIWithoutOLM)
+
+ gatewayAPIWithoutOLMEnabledBool, ok := os.LookupEnv("GATEWAY_HELM")
+ if !ok {
+ gatewayAPIWithoutOLMEnabledBool = "false"
+ }
+
+ gatewayAPIWithoutOLMEnabled, err := strconv.ParseBool(gatewayAPIWithoutOLMEnabledBool)
+ if err != nil {
+ return nil, err
+ }
+
routeExternalCertificateEnabled := featureGates.Enabled(features.FeatureGateRouteExternalCertificate)
ingressControllerDCMEnabled := featureGates.Enabled(features.FeatureGateIngressControllerDynamicConfigurationManager)
@@ -313,14 +329,36 @@ func New(config operatorconfig.Config, kubeConfig *rest.Config) (*Operator, erro
// Set up the gatewayclass controller. This controller is unmanaged by
// the manager; the gatewayapi controller starts it after it creates the
// Gateway API CRDs.
- gatewayClassController, err := gatewayclasscontroller.NewUnmanaged(mgr, gatewayclasscontroller.Config{
- OperatorNamespace: config.Namespace,
- OperandNamespace: operatorcontroller.DefaultOperandNamespace,
- GatewayAPIOperatorCatalog: config.GatewayAPIOperatorCatalog,
- GatewayAPIOperatorChannel: config.GatewayAPIOperatorChannel,
- GatewayAPIOperatorVersion: config.GatewayAPIOperatorVersion,
- IstioVersion: config.IstioVersion,
- })
+ //
+ gatewayclassControllerConfig := gatewayclasscontroller.Config{
+ KubeConfig: kubeConfig,
+ OperatorNamespace: config.Namespace,
+ OperandNamespace: operatorcontroller.DefaultOperandNamespace,
+ GatewayAPIOperatorCatalog: config.GatewayAPIOperatorCatalog,
+ GatewayAPIOperatorChannel: config.GatewayAPIOperatorChannel,
+ GatewayAPIOperatorVersion: config.GatewayAPIOperatorVersion,
+ GatewayAPIWithoutOLMEnabled: gatewayAPIWithoutOLMEnabled,
+ IstioVersion: config.IstioVersion,
+ }
+
+ // Gated Feature - For Non-OLM install, we start the sail-operator library that
+ // does the reconciliation of CRDs and resources.
+ // Starting this library returns a channel, that can be used by the reconciliation
+ // process to receive notifications from the library informer and kick a new GatewayClass
+ // reconciliation.
+ if gatewayAPIWithoutOLMEnabled {
+ installer, err := install.New(mgr.GetConfig(), resources.FS)
+ if err != nil {
+ return nil, fmt.Errorf("failed to initialize sail-operator installation library: %w", err)
+ }
+ notifyCh := installer.Start(ctx)
+ gatewayclassControllerConfig.SailOperatorReconciler = &gatewayclasscontroller.SailOperatorReconciler{
+ NotifyCh: notifyCh,
+ Installer: installer,
+ }
+ }
+
+ gatewayClassController, err := gatewayclasscontroller.NewUnmanaged(mgr, gatewayclassControllerConfig)
if err != nil {
return nil, fmt.Errorf("failed to create gatewayclass controller: %w", err)
}
diff --git a/vendor/cloud.google.com/go/compute/metadata/CHANGES.md b/vendor/cloud.google.com/go/compute/metadata/CHANGES.md
index 1f848ce0b3..e384683c50 100644
--- a/vendor/cloud.google.com/go/compute/metadata/CHANGES.md
+++ b/vendor/cloud.google.com/go/compute/metadata/CHANGES.md
@@ -1,5 +1,47 @@
# Changes
+## [0.9.0](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.8.4...compute/metadata/v0.9.0) (2025-09-24)
+
+
+### Features
+
+* **compute/metadata:** Retry on HTTP 429 ([#12932](https://github.com/googleapis/google-cloud-go/issues/12932)) ([1e91f5c](https://github.com/googleapis/google-cloud-go/commit/1e91f5c07acacd38ecdd4ff3e83e092b745e0bc2))
+
+## [0.8.4](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.8.3...compute/metadata/v0.8.4) (2025-09-18)
+
+
+### Bug Fixes
+
+* **compute/metadata:** Set subClient for UseDefaultClient case ([#12911](https://github.com/googleapis/google-cloud-go/issues/12911)) ([9e2646b](https://github.com/googleapis/google-cloud-go/commit/9e2646b1821231183fd775bb107c062865eeaccd))
+
+## [0.8.3](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.8.2...compute/metadata/v0.8.3) (2025-09-17)
+
+
+### Bug Fixes
+
+* **compute/metadata:** Disable Client timeouts for subscription client ([#12910](https://github.com/googleapis/google-cloud-go/issues/12910)) ([187a58a](https://github.com/googleapis/google-cloud-go/commit/187a58a540494e1e8562b046325b8cad8cf7af4a))
+
+## [0.8.2](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.8.1...compute/metadata/v0.8.2) (2025-09-17)
+
+
+### Bug Fixes
+
+* **compute/metadata:** Racy test and uninitialized subClient ([#12892](https://github.com/googleapis/google-cloud-go/issues/12892)) ([4943ca2](https://github.com/googleapis/google-cloud-go/commit/4943ca2bf83908a23806247bc4252dfb440d09cc)), refs [#12888](https://github.com/googleapis/google-cloud-go/issues/12888)
+
+## [0.8.1](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.8.0...compute/metadata/v0.8.1) (2025-09-16)
+
+
+### Bug Fixes
+
+* **compute/metadata:** Use separate client for subscribe methods ([#12885](https://github.com/googleapis/google-cloud-go/issues/12885)) ([76b80f8](https://github.com/googleapis/google-cloud-go/commit/76b80f8df9bf9339d175407e8c15936fe1ac1c9c))
+
+## [0.8.0](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.7.0...compute/metadata/v0.8.0) (2025-08-06)
+
+
+### Features
+
+* **compute/metadata:** Add Options.UseDefaultClient ([#12657](https://github.com/googleapis/google-cloud-go/issues/12657)) ([1a88209](https://github.com/googleapis/google-cloud-go/commit/1a8820900f20e038291c4bb2c5284a449196e81f)), refs [#11078](https://github.com/googleapis/google-cloud-go/issues/11078)
+
## [0.7.0](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.6.0...compute/metadata/v0.7.0) (2025-05-13)
diff --git a/vendor/cloud.google.com/go/compute/metadata/metadata.go b/vendor/cloud.google.com/go/compute/metadata/metadata.go
index 322be8032d..6bd1891660 100644
--- a/vendor/cloud.google.com/go/compute/metadata/metadata.go
+++ b/vendor/cloud.google.com/go/compute/metadata/metadata.go
@@ -22,6 +22,7 @@ package metadata // import "cloud.google.com/go/compute/metadata"
import (
"context"
"encoding/json"
+ "errors"
"fmt"
"io"
"log/slog"
@@ -62,21 +63,26 @@ var (
)
var defaultClient = &Client{
- hc: newDefaultHTTPClient(),
- logger: slog.New(noOpHandler{}),
+ hc: newDefaultHTTPClient(true),
+ subClient: newDefaultHTTPClient(false),
+ logger: slog.New(noOpHandler{}),
}
-func newDefaultHTTPClient() *http.Client {
- return &http.Client{
- Transport: &http.Transport{
- Dial: (&net.Dialer{
- Timeout: 2 * time.Second,
- KeepAlive: 30 * time.Second,
- }).Dial,
- IdleConnTimeout: 60 * time.Second,
- },
- Timeout: 5 * time.Second,
+func newDefaultHTTPClient(enableTimeouts bool) *http.Client {
+ transport := &http.Transport{
+ Dial: (&net.Dialer{
+ Timeout: 2 * time.Second,
+ KeepAlive: 30 * time.Second,
+ }).Dial,
}
+ c := &http.Client{
+ Transport: transport,
+ }
+ if enableTimeouts {
+ transport.IdleConnTimeout = 60 * time.Second
+ c.Timeout = 5 * time.Second
+ }
+ return c
}
// NotDefinedError is returned when requested metadata is not defined.
@@ -350,42 +356,74 @@ func strsContains(ss []string, s string) bool {
// A Client provides metadata.
type Client struct {
- hc *http.Client
- logger *slog.Logger
+ hc *http.Client
+ // subClient by default is a HTTP Client that is only used for subscribe
+ // methods that should not specify a timeout. If the user specifies a client
+ // this with be the same as 'hc'.
+ subClient *http.Client
+ logger *slog.Logger
}
// Options for configuring a [Client].
type Options struct {
// Client is the HTTP client used to make requests. Optional.
+ // If UseDefaultClient is true, this field is ignored.
+ // If this field is nil, a new default http.Client will be created.
Client *http.Client
// Logger is used to log information about HTTP request and responses.
// If not provided, nothing will be logged. Optional.
Logger *slog.Logger
+ // UseDefaultClient specifies that the client should use the same default
+ // internal http.Client that is used in functions such as GetWithContext.
+ // This is useful for sharing a single TCP connection pool across requests.
+ // The difference vs GetWithContext is the ability to use this struct
+ // to provide a custom logger. If this field is true, the Client
+ // field is ignored.
+ UseDefaultClient bool
}
// NewClient returns a Client that can be used to fetch metadata.
// Returns the client that uses the specified http.Client for HTTP requests.
-// If nil is specified, returns the default client.
+// If nil is specified, returns the default internal Client that is
+// also used in functions such as GetWithContext. This is useful for sharing
+// a single TCP connection pool across requests.
func NewClient(c *http.Client) *Client {
- return NewWithOptions(&Options{
- Client: c,
- })
+ if c == nil {
+ // Preserve original behavior for nil argument.
+ return defaultClient
+ }
+ // Return a new client with a no-op logger for backward compatibility.
+ return &Client{hc: c, subClient: c, logger: slog.New(noOpHandler{})}
}
// NewWithOptions returns a Client that is configured with the provided Options.
func NewWithOptions(opts *Options) *Client {
+ // Preserve original behavior for nil opts.
if opts == nil {
return defaultClient
}
+
+ // Handle explicit request for the internal default http.Client.
+ if opts.UseDefaultClient {
+ logger := opts.Logger
+ if logger == nil {
+ logger = slog.New(noOpHandler{})
+ }
+ return &Client{hc: defaultClient.hc, subClient: defaultClient.subClient, logger: logger}
+ }
+
+ // Handle isolated client creation.
client := opts.Client
+ subClient := opts.Client
if client == nil {
- client = newDefaultHTTPClient()
+ client = newDefaultHTTPClient(true)
+ subClient = newDefaultHTTPClient(false)
}
logger := opts.Logger
if logger == nil {
logger = slog.New(noOpHandler{})
}
- return &Client{hc: client, logger: logger}
+ return &Client{hc: client, subClient: subClient, logger: logger}
}
// NOTE: metadataRequestStrategy is assigned to a variable for test stubbing purposes.
@@ -469,6 +507,10 @@ func (c *Client) OnGCEWithContext(ctx context.Context) bool {
// getETag returns a value from the metadata service as well as the associated ETag.
// This func is otherwise equivalent to Get.
func (c *Client) getETag(ctx context.Context, suffix string) (value, etag string, err error) {
+ return c.getETagWithSubClient(ctx, suffix, false)
+}
+
+func (c *Client) getETagWithSubClient(ctx context.Context, suffix string, enableSubClient bool) (value, etag string, err error) {
// Using a fixed IP makes it very difficult to spoof the metadata service in
// a container, which is an important use-case for local testing of cloud
// deployments. To enable spoofing of the metadata service, the environment
@@ -495,9 +537,13 @@ func (c *Client) getETag(ctx context.Context, suffix string) (value, etag string
var reqErr error
var body []byte
retryer := newRetryer()
+ hc := c.hc
+ if enableSubClient {
+ hc = c.subClient
+ }
for {
c.logger.DebugContext(ctx, "metadata request", "request", httpRequest(req, nil))
- res, reqErr = c.hc.Do(req)
+ res, reqErr = hc.Do(req)
var code int
if res != nil {
code = res.StatusCode
@@ -843,7 +889,7 @@ func (c *Client) SubscribeWithContext(ctx context.Context, suffix string, fn fun
const failedSubscribeSleep = time.Second * 5
// First check to see if the metadata value exists at all.
- val, lastETag, err := c.getETag(ctx, suffix)
+ val, lastETag, err := c.getETagWithSubClient(ctx, suffix, true)
if err != nil {
return err
}
@@ -859,8 +905,11 @@ func (c *Client) SubscribeWithContext(ctx context.Context, suffix string, fn fun
suffix += "?wait_for_change=true&last_etag="
}
for {
- val, etag, err := c.getETag(ctx, suffix+url.QueryEscape(lastETag))
+ val, etag, err := c.getETagWithSubClient(ctx, suffix+url.QueryEscape(lastETag), true)
if err != nil {
+ if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
+ return err
+ }
if _, deleted := err.(NotDefinedError); !deleted {
time.Sleep(failedSubscribeSleep)
continue // Retry on other errors.
diff --git a/vendor/cloud.google.com/go/compute/metadata/retry.go b/vendor/cloud.google.com/go/compute/metadata/retry.go
index 3d4bc75ddf..d516f30f80 100644
--- a/vendor/cloud.google.com/go/compute/metadata/retry.go
+++ b/vendor/cloud.google.com/go/compute/metadata/retry.go
@@ -95,6 +95,9 @@ func shouldRetry(status int, err error) bool {
if 500 <= status && status <= 599 {
return true
}
+ if status == http.StatusTooManyRequests {
+ return true
+ }
if err == io.ErrUnexpectedEOF {
return true
}
diff --git a/vendor/dario.cat/mergo/.deepsource.toml b/vendor/dario.cat/mergo/.deepsource.toml
new file mode 100644
index 0000000000..a8bc979e02
--- /dev/null
+++ b/vendor/dario.cat/mergo/.deepsource.toml
@@ -0,0 +1,12 @@
+version = 1
+
+test_patterns = [
+ "*_test.go"
+]
+
+[[analyzers]]
+name = "go"
+enabled = true
+
+ [analyzers.meta]
+ import_path = "dario.cat/mergo"
\ No newline at end of file
diff --git a/vendor/dario.cat/mergo/.gitignore b/vendor/dario.cat/mergo/.gitignore
new file mode 100644
index 0000000000..45ad0f1ae3
--- /dev/null
+++ b/vendor/dario.cat/mergo/.gitignore
@@ -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
diff --git a/vendor/dario.cat/mergo/.travis.yml b/vendor/dario.cat/mergo/.travis.yml
new file mode 100644
index 0000000000..d324c43ba4
--- /dev/null
+++ b/vendor/dario.cat/mergo/.travis.yml
@@ -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
diff --git a/vendor/dario.cat/mergo/CODE_OF_CONDUCT.md b/vendor/dario.cat/mergo/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000000..469b44907a
--- /dev/null
+++ b/vendor/dario.cat/mergo/CODE_OF_CONDUCT.md
@@ -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/
diff --git a/vendor/dario.cat/mergo/CONTRIBUTING.md b/vendor/dario.cat/mergo/CONTRIBUTING.md
new file mode 100644
index 0000000000..0a1ff9f94d
--- /dev/null
+++ b/vendor/dario.cat/mergo/CONTRIBUTING.md
@@ -0,0 +1,112 @@
+
+# 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
+
+
+## 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
+> 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
+
+
+#### 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?
+
+
+#### 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 .
+
+
+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.
+
+
+#### 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.
+
+
+#### 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.
+- **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.
+
+
+## Attribution
+This guide is based on the **contributing-gen**. [Make your own](https://github.com/bttger/contributing-gen)!
diff --git a/vendor/dario.cat/mergo/FUNDING.json b/vendor/dario.cat/mergo/FUNDING.json
new file mode 100644
index 0000000000..0585e1fe13
--- /dev/null
+++ b/vendor/dario.cat/mergo/FUNDING.json
@@ -0,0 +1,7 @@
+{
+ "drips": {
+ "ethereum": {
+ "ownedBy": "0x6160020e7102237aC41bdb156e94401692D76930"
+ }
+ }
+}
diff --git a/vendor/dario.cat/mergo/LICENSE b/vendor/dario.cat/mergo/LICENSE
new file mode 100644
index 0000000000..686680298d
--- /dev/null
+++ b/vendor/dario.cat/mergo/LICENSE
@@ -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.
diff --git a/vendor/dario.cat/mergo/README.md b/vendor/dario.cat/mergo/README.md
new file mode 100644
index 0000000000..0e4a59afd9
--- /dev/null
+++ b/vendor/dario.cat/mergo/README.md
@@ -0,0 +1,253 @@
+# 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:
+
+
+
+
+### 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)
+* [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}
+}
+```
+
+### 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)
diff --git a/vendor/dario.cat/mergo/SECURITY.md b/vendor/dario.cat/mergo/SECURITY.md
new file mode 100644
index 0000000000..3788fcc1c2
--- /dev/null
+++ b/vendor/dario.cat/mergo/SECURITY.md
@@ -0,0 +1,14 @@
+# Security Policy
+
+## Supported Versions
+
+| Version | Supported |
+| ------- | ------------------ |
+| 1.x.x | :white_check_mark: |
+| < 1.0 | :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.
diff --git a/vendor/dario.cat/mergo/doc.go b/vendor/dario.cat/mergo/doc.go
new file mode 100644
index 0000000000..7d96ec0546
--- /dev/null
+++ b/vendor/dario.cat/mergo/doc.go
@@ -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
diff --git a/vendor/dario.cat/mergo/map.go b/vendor/dario.cat/mergo/map.go
new file mode 100644
index 0000000000..759b4f74fd
--- /dev/null
+++ b/vendor/dario.cat/mergo/map.go
@@ -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)
+}
diff --git a/vendor/dario.cat/mergo/merge.go b/vendor/dario.cat/mergo/merge.go
new file mode 100644
index 0000000000..fd47c95b2b
--- /dev/null
+++ b/vendor/dario.cat/mergo/merge.go
@@ -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
+ }
+}
diff --git a/vendor/dario.cat/mergo/mergo.go b/vendor/dario.cat/mergo/mergo.go
new file mode 100644
index 0000000000..0a721e2d85
--- /dev/null
+++ b/vendor/dario.cat/mergo/mergo.go
@@ -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
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/LICENSE b/vendor/github.com/Azure/go-ansiterm/LICENSE
new file mode 100644
index 0000000000..e3d9a64d1d
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Microsoft Corporation
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/github.com/Azure/go-ansiterm/README.md b/vendor/github.com/Azure/go-ansiterm/README.md
new file mode 100644
index 0000000000..261c041e7a
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/README.md
@@ -0,0 +1,12 @@
+# go-ansiterm
+
+This is a cross platform Ansi Terminal Emulation library. It reads a stream of Ansi characters and produces the appropriate function calls. The results of the function calls are platform dependent.
+
+For example the parser might receive "ESC, [, A" as a stream of three characters. This is the code for Cursor Up (http://www.vt100.net/docs/vt510-rm/CUU). The parser then calls the cursor up function (CUU()) on an event handler. The event handler determines what platform specific work must be done to cause the cursor to move up one position.
+
+The parser (parser.go) is a partial implementation of this state machine (http://vt100.net/emu/vt500_parser.png). There are also two event handler implementations, one for tests (test_event_handler.go) to validate that the expected events are being produced and called, the other is a Windows implementation (winterm/win_event_handler.go).
+
+See parser_test.go for examples exercising the state machine and generating appropriate function calls.
+
+-----
+This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
diff --git a/vendor/github.com/Azure/go-ansiterm/SECURITY.md b/vendor/github.com/Azure/go-ansiterm/SECURITY.md
new file mode 100644
index 0000000000..e138ec5d6a
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/SECURITY.md
@@ -0,0 +1,41 @@
+
+
+## Security
+
+Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
+
+If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
+
+## Reporting Security Issues
+
+**Please do not report security vulnerabilities through public GitHub issues.**
+
+Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
+
+If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
+
+You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
+
+Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
+
+ * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
+ * Full paths of source file(s) related to the manifestation of the issue
+ * The location of the affected source code (tag/branch/commit or direct URL)
+ * Any special configuration required to reproduce the issue
+ * Step-by-step instructions to reproduce the issue
+ * Proof-of-concept or exploit code (if possible)
+ * Impact of the issue, including how an attacker might exploit the issue
+
+This information will help us triage your report more quickly.
+
+If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
+
+## Preferred Languages
+
+We prefer all communications to be in English.
+
+## Policy
+
+Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
+
+
diff --git a/vendor/github.com/Azure/go-ansiterm/constants.go b/vendor/github.com/Azure/go-ansiterm/constants.go
new file mode 100644
index 0000000000..96504a33bc
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/constants.go
@@ -0,0 +1,188 @@
+package ansiterm
+
+const LogEnv = "DEBUG_TERMINAL"
+
+// ANSI constants
+// References:
+// -- http://www.ecma-international.org/publications/standards/Ecma-048.htm
+// -- http://man7.org/linux/man-pages/man4/console_codes.4.html
+// -- http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html
+// -- http://en.wikipedia.org/wiki/ANSI_escape_code
+// -- http://vt100.net/emu/dec_ansi_parser
+// -- http://vt100.net/emu/vt500_parser.svg
+// -- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+// -- http://www.inwap.com/pdp10/ansicode.txt
+const (
+ // ECMA-48 Set Graphics Rendition
+ // Note:
+ // -- Constants leading with an underscore (e.g., _ANSI_xxx) are unsupported or reserved
+ // -- Fonts could possibly be supported via SetCurrentConsoleFontEx
+ // -- Windows does not expose the per-window cursor (i.e., caret) blink times
+ ANSI_SGR_RESET = 0
+ ANSI_SGR_BOLD = 1
+ ANSI_SGR_DIM = 2
+ _ANSI_SGR_ITALIC = 3
+ ANSI_SGR_UNDERLINE = 4
+ _ANSI_SGR_BLINKSLOW = 5
+ _ANSI_SGR_BLINKFAST = 6
+ ANSI_SGR_REVERSE = 7
+ _ANSI_SGR_INVISIBLE = 8
+ _ANSI_SGR_LINETHROUGH = 9
+ _ANSI_SGR_FONT_00 = 10
+ _ANSI_SGR_FONT_01 = 11
+ _ANSI_SGR_FONT_02 = 12
+ _ANSI_SGR_FONT_03 = 13
+ _ANSI_SGR_FONT_04 = 14
+ _ANSI_SGR_FONT_05 = 15
+ _ANSI_SGR_FONT_06 = 16
+ _ANSI_SGR_FONT_07 = 17
+ _ANSI_SGR_FONT_08 = 18
+ _ANSI_SGR_FONT_09 = 19
+ _ANSI_SGR_FONT_10 = 20
+ _ANSI_SGR_DOUBLEUNDERLINE = 21
+ ANSI_SGR_BOLD_DIM_OFF = 22
+ _ANSI_SGR_ITALIC_OFF = 23
+ ANSI_SGR_UNDERLINE_OFF = 24
+ _ANSI_SGR_BLINK_OFF = 25
+ _ANSI_SGR_RESERVED_00 = 26
+ ANSI_SGR_REVERSE_OFF = 27
+ _ANSI_SGR_INVISIBLE_OFF = 28
+ _ANSI_SGR_LINETHROUGH_OFF = 29
+ ANSI_SGR_FOREGROUND_BLACK = 30
+ ANSI_SGR_FOREGROUND_RED = 31
+ ANSI_SGR_FOREGROUND_GREEN = 32
+ ANSI_SGR_FOREGROUND_YELLOW = 33
+ ANSI_SGR_FOREGROUND_BLUE = 34
+ ANSI_SGR_FOREGROUND_MAGENTA = 35
+ ANSI_SGR_FOREGROUND_CYAN = 36
+ ANSI_SGR_FOREGROUND_WHITE = 37
+ _ANSI_SGR_RESERVED_01 = 38
+ ANSI_SGR_FOREGROUND_DEFAULT = 39
+ ANSI_SGR_BACKGROUND_BLACK = 40
+ ANSI_SGR_BACKGROUND_RED = 41
+ ANSI_SGR_BACKGROUND_GREEN = 42
+ ANSI_SGR_BACKGROUND_YELLOW = 43
+ ANSI_SGR_BACKGROUND_BLUE = 44
+ ANSI_SGR_BACKGROUND_MAGENTA = 45
+ ANSI_SGR_BACKGROUND_CYAN = 46
+ ANSI_SGR_BACKGROUND_WHITE = 47
+ _ANSI_SGR_RESERVED_02 = 48
+ ANSI_SGR_BACKGROUND_DEFAULT = 49
+ // 50 - 65: Unsupported
+
+ ANSI_MAX_CMD_LENGTH = 4096
+
+ MAX_INPUT_EVENTS = 128
+ DEFAULT_WIDTH = 80
+ DEFAULT_HEIGHT = 24
+
+ ANSI_BEL = 0x07
+ ANSI_BACKSPACE = 0x08
+ ANSI_TAB = 0x09
+ ANSI_LINE_FEED = 0x0A
+ ANSI_VERTICAL_TAB = 0x0B
+ ANSI_FORM_FEED = 0x0C
+ ANSI_CARRIAGE_RETURN = 0x0D
+ ANSI_ESCAPE_PRIMARY = 0x1B
+ ANSI_ESCAPE_SECONDARY = 0x5B
+ ANSI_OSC_STRING_ENTRY = 0x5D
+ ANSI_COMMAND_FIRST = 0x40
+ ANSI_COMMAND_LAST = 0x7E
+ DCS_ENTRY = 0x90
+ CSI_ENTRY = 0x9B
+ OSC_STRING = 0x9D
+ ANSI_PARAMETER_SEP = ";"
+ ANSI_CMD_G0 = '('
+ ANSI_CMD_G1 = ')'
+ ANSI_CMD_G2 = '*'
+ ANSI_CMD_G3 = '+'
+ ANSI_CMD_DECPNM = '>'
+ ANSI_CMD_DECPAM = '='
+ ANSI_CMD_OSC = ']'
+ ANSI_CMD_STR_TERM = '\\'
+
+ KEY_CONTROL_PARAM_2 = ";2"
+ KEY_CONTROL_PARAM_3 = ";3"
+ KEY_CONTROL_PARAM_4 = ";4"
+ KEY_CONTROL_PARAM_5 = ";5"
+ KEY_CONTROL_PARAM_6 = ";6"
+ KEY_CONTROL_PARAM_7 = ";7"
+ KEY_CONTROL_PARAM_8 = ";8"
+ KEY_ESC_CSI = "\x1B["
+ KEY_ESC_N = "\x1BN"
+ KEY_ESC_O = "\x1BO"
+
+ FILL_CHARACTER = ' '
+)
+
+func getByteRange(start byte, end byte) []byte {
+ bytes := make([]byte, 0, 32)
+ for i := start; i <= end; i++ {
+ bytes = append(bytes, byte(i))
+ }
+
+ return bytes
+}
+
+var toGroundBytes = getToGroundBytes()
+var executors = getExecuteBytes()
+
+// SPACE 20+A0 hex Always and everywhere a blank space
+// Intermediate 20-2F hex !"#$%&'()*+,-./
+var intermeds = getByteRange(0x20, 0x2F)
+
+// Parameters 30-3F hex 0123456789:;<=>?
+// CSI Parameters 30-39, 3B hex 0123456789;
+var csiParams = getByteRange(0x30, 0x3F)
+
+var csiCollectables = append(getByteRange(0x30, 0x39), getByteRange(0x3B, 0x3F)...)
+
+// Uppercase 40-5F hex @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
+var upperCase = getByteRange(0x40, 0x5F)
+
+// Lowercase 60-7E hex `abcdefghijlkmnopqrstuvwxyz{|}~
+var lowerCase = getByteRange(0x60, 0x7E)
+
+// Alphabetics 40-7E hex (all of upper and lower case)
+var alphabetics = append(upperCase, lowerCase...)
+
+var printables = getByteRange(0x20, 0x7F)
+
+var escapeIntermediateToGroundBytes = getByteRange(0x30, 0x7E)
+var escapeToGroundBytes = getEscapeToGroundBytes()
+
+// See http://www.vt100.net/emu/vt500_parser.png for description of the complex
+// byte ranges below
+
+func getEscapeToGroundBytes() []byte {
+ escapeToGroundBytes := getByteRange(0x30, 0x4F)
+ escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x51, 0x57)...)
+ escapeToGroundBytes = append(escapeToGroundBytes, 0x59)
+ escapeToGroundBytes = append(escapeToGroundBytes, 0x5A)
+ escapeToGroundBytes = append(escapeToGroundBytes, 0x5C)
+ escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x60, 0x7E)...)
+ return escapeToGroundBytes
+}
+
+func getExecuteBytes() []byte {
+ executeBytes := getByteRange(0x00, 0x17)
+ executeBytes = append(executeBytes, 0x19)
+ executeBytes = append(executeBytes, getByteRange(0x1C, 0x1F)...)
+ return executeBytes
+}
+
+func getToGroundBytes() []byte {
+ groundBytes := []byte{0x18}
+ groundBytes = append(groundBytes, 0x1A)
+ groundBytes = append(groundBytes, getByteRange(0x80, 0x8F)...)
+ groundBytes = append(groundBytes, getByteRange(0x91, 0x97)...)
+ groundBytes = append(groundBytes, 0x99)
+ groundBytes = append(groundBytes, 0x9A)
+ groundBytes = append(groundBytes, 0x9C)
+ return groundBytes
+}
+
+// Delete 7F hex Always and everywhere ignored
+// C1 Control 80-9F hex 32 additional control characters
+// G1 Displayable A1-FE hex 94 additional displayable characters
+// Special A0+FF hex Same as SPACE and DELETE
diff --git a/vendor/github.com/Azure/go-ansiterm/context.go b/vendor/github.com/Azure/go-ansiterm/context.go
new file mode 100644
index 0000000000..8d66e777c0
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/context.go
@@ -0,0 +1,7 @@
+package ansiterm
+
+type ansiContext struct {
+ currentChar byte
+ paramBuffer []byte
+ interBuffer []byte
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go b/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go
new file mode 100644
index 0000000000..bcbe00d0c5
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/csi_entry_state.go
@@ -0,0 +1,49 @@
+package ansiterm
+
+type csiEntryState struct {
+ baseState
+}
+
+func (csiState csiEntryState) Handle(b byte) (s state, e error) {
+ csiState.parser.logf("CsiEntry::Handle %#x", b)
+
+ nextState, err := csiState.baseState.Handle(b)
+ if nextState != nil || err != nil {
+ return nextState, err
+ }
+
+ switch {
+ case sliceContains(alphabetics, b):
+ return csiState.parser.ground, nil
+ case sliceContains(csiCollectables, b):
+ return csiState.parser.csiParam, nil
+ case sliceContains(executors, b):
+ return csiState, csiState.parser.execute()
+ }
+
+ return csiState, nil
+}
+
+func (csiState csiEntryState) Transition(s state) error {
+ csiState.parser.logf("CsiEntry::Transition %s --> %s", csiState.Name(), s.Name())
+ csiState.baseState.Transition(s)
+
+ switch s {
+ case csiState.parser.ground:
+ return csiState.parser.csiDispatch()
+ case csiState.parser.csiParam:
+ switch {
+ case sliceContains(csiParams, csiState.parser.context.currentChar):
+ csiState.parser.collectParam()
+ case sliceContains(intermeds, csiState.parser.context.currentChar):
+ csiState.parser.collectInter()
+ }
+ }
+
+ return nil
+}
+
+func (csiState csiEntryState) Enter() error {
+ csiState.parser.clear()
+ return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/csi_param_state.go b/vendor/github.com/Azure/go-ansiterm/csi_param_state.go
new file mode 100644
index 0000000000..7ed5e01c34
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/csi_param_state.go
@@ -0,0 +1,38 @@
+package ansiterm
+
+type csiParamState struct {
+ baseState
+}
+
+func (csiState csiParamState) Handle(b byte) (s state, e error) {
+ csiState.parser.logf("CsiParam::Handle %#x", b)
+
+ nextState, err := csiState.baseState.Handle(b)
+ if nextState != nil || err != nil {
+ return nextState, err
+ }
+
+ switch {
+ case sliceContains(alphabetics, b):
+ return csiState.parser.ground, nil
+ case sliceContains(csiCollectables, b):
+ csiState.parser.collectParam()
+ return csiState, nil
+ case sliceContains(executors, b):
+ return csiState, csiState.parser.execute()
+ }
+
+ return csiState, nil
+}
+
+func (csiState csiParamState) Transition(s state) error {
+ csiState.parser.logf("CsiParam::Transition %s --> %s", csiState.Name(), s.Name())
+ csiState.baseState.Transition(s)
+
+ switch s {
+ case csiState.parser.ground:
+ return csiState.parser.csiDispatch()
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go b/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go
new file mode 100644
index 0000000000..1c719db9e4
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go
@@ -0,0 +1,36 @@
+package ansiterm
+
+type escapeIntermediateState struct {
+ baseState
+}
+
+func (escState escapeIntermediateState) Handle(b byte) (s state, e error) {
+ escState.parser.logf("escapeIntermediateState::Handle %#x", b)
+ nextState, err := escState.baseState.Handle(b)
+ if nextState != nil || err != nil {
+ return nextState, err
+ }
+
+ switch {
+ case sliceContains(intermeds, b):
+ return escState, escState.parser.collectInter()
+ case sliceContains(executors, b):
+ return escState, escState.parser.execute()
+ case sliceContains(escapeIntermediateToGroundBytes, b):
+ return escState.parser.ground, nil
+ }
+
+ return escState, nil
+}
+
+func (escState escapeIntermediateState) Transition(s state) error {
+ escState.parser.logf("escapeIntermediateState::Transition %s --> %s", escState.Name(), s.Name())
+ escState.baseState.Transition(s)
+
+ switch s {
+ case escState.parser.ground:
+ return escState.parser.escDispatch()
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/escape_state.go b/vendor/github.com/Azure/go-ansiterm/escape_state.go
new file mode 100644
index 0000000000..6390abd231
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/escape_state.go
@@ -0,0 +1,47 @@
+package ansiterm
+
+type escapeState struct {
+ baseState
+}
+
+func (escState escapeState) Handle(b byte) (s state, e error) {
+ escState.parser.logf("escapeState::Handle %#x", b)
+ nextState, err := escState.baseState.Handle(b)
+ if nextState != nil || err != nil {
+ return nextState, err
+ }
+
+ switch {
+ case b == ANSI_ESCAPE_SECONDARY:
+ return escState.parser.csiEntry, nil
+ case b == ANSI_OSC_STRING_ENTRY:
+ return escState.parser.oscString, nil
+ case sliceContains(executors, b):
+ return escState, escState.parser.execute()
+ case sliceContains(escapeToGroundBytes, b):
+ return escState.parser.ground, nil
+ case sliceContains(intermeds, b):
+ return escState.parser.escapeIntermediate, nil
+ }
+
+ return escState, nil
+}
+
+func (escState escapeState) Transition(s state) error {
+ escState.parser.logf("Escape::Transition %s --> %s", escState.Name(), s.Name())
+ escState.baseState.Transition(s)
+
+ switch s {
+ case escState.parser.ground:
+ return escState.parser.escDispatch()
+ case escState.parser.escapeIntermediate:
+ return escState.parser.collectInter()
+ }
+
+ return nil
+}
+
+func (escState escapeState) Enter() error {
+ escState.parser.clear()
+ return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/event_handler.go b/vendor/github.com/Azure/go-ansiterm/event_handler.go
new file mode 100644
index 0000000000..98087b38c2
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/event_handler.go
@@ -0,0 +1,90 @@
+package ansiterm
+
+type AnsiEventHandler interface {
+ // Print
+ Print(b byte) error
+
+ // Execute C0 commands
+ Execute(b byte) error
+
+ // CUrsor Up
+ CUU(int) error
+
+ // CUrsor Down
+ CUD(int) error
+
+ // CUrsor Forward
+ CUF(int) error
+
+ // CUrsor Backward
+ CUB(int) error
+
+ // Cursor to Next Line
+ CNL(int) error
+
+ // Cursor to Previous Line
+ CPL(int) error
+
+ // Cursor Horizontal position Absolute
+ CHA(int) error
+
+ // Vertical line Position Absolute
+ VPA(int) error
+
+ // CUrsor Position
+ CUP(int, int) error
+
+ // Horizontal and Vertical Position (depends on PUM)
+ HVP(int, int) error
+
+ // Text Cursor Enable Mode
+ DECTCEM(bool) error
+
+ // Origin Mode
+ DECOM(bool) error
+
+ // 132 Column Mode
+ DECCOLM(bool) error
+
+ // Erase in Display
+ ED(int) error
+
+ // Erase in Line
+ EL(int) error
+
+ // Insert Line
+ IL(int) error
+
+ // Delete Line
+ DL(int) error
+
+ // Insert Character
+ ICH(int) error
+
+ // Delete Character
+ DCH(int) error
+
+ // Set Graphics Rendition
+ SGR([]int) error
+
+ // Pan Down
+ SU(int) error
+
+ // Pan Up
+ SD(int) error
+
+ // Device Attributes
+ DA([]string) error
+
+ // Set Top and Bottom Margins
+ DECSTBM(int, int) error
+
+ // Index
+ IND() error
+
+ // Reverse Index
+ RI() error
+
+ // Flush updates from previous commands
+ Flush() error
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/ground_state.go b/vendor/github.com/Azure/go-ansiterm/ground_state.go
new file mode 100644
index 0000000000..52451e9469
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/ground_state.go
@@ -0,0 +1,24 @@
+package ansiterm
+
+type groundState struct {
+ baseState
+}
+
+func (gs groundState) Handle(b byte) (s state, e error) {
+ gs.parser.context.currentChar = b
+
+ nextState, err := gs.baseState.Handle(b)
+ if nextState != nil || err != nil {
+ return nextState, err
+ }
+
+ switch {
+ case sliceContains(printables, b):
+ return gs, gs.parser.print()
+
+ case sliceContains(executors, b):
+ return gs, gs.parser.execute()
+ }
+
+ return gs, nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/osc_string_state.go b/vendor/github.com/Azure/go-ansiterm/osc_string_state.go
new file mode 100644
index 0000000000..194d5e9c94
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/osc_string_state.go
@@ -0,0 +1,23 @@
+package ansiterm
+
+type oscStringState struct {
+ baseState
+}
+
+func (oscState oscStringState) Handle(b byte) (s state, e error) {
+ oscState.parser.logf("OscString::Handle %#x", b)
+ nextState, err := oscState.baseState.Handle(b)
+ if nextState != nil || err != nil {
+ return nextState, err
+ }
+
+ // There are several control characters and sequences which can
+ // terminate an OSC string. Most of them are handled by the baseState
+ // handler. The ANSI_BEL character is a special case which behaves as a
+ // terminator only for an OSC string.
+ if b == ANSI_BEL {
+ return oscState.parser.ground, nil
+ }
+
+ return oscState, nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/parser.go b/vendor/github.com/Azure/go-ansiterm/parser.go
new file mode 100644
index 0000000000..03cec7ada6
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/parser.go
@@ -0,0 +1,151 @@
+package ansiterm
+
+import (
+ "errors"
+ "log"
+ "os"
+)
+
+type AnsiParser struct {
+ currState state
+ eventHandler AnsiEventHandler
+ context *ansiContext
+ csiEntry state
+ csiParam state
+ dcsEntry state
+ escape state
+ escapeIntermediate state
+ error state
+ ground state
+ oscString state
+ stateMap []state
+
+ logf func(string, ...interface{})
+}
+
+type Option func(*AnsiParser)
+
+func WithLogf(f func(string, ...interface{})) Option {
+ return func(ap *AnsiParser) {
+ ap.logf = f
+ }
+}
+
+func CreateParser(initialState string, evtHandler AnsiEventHandler, opts ...Option) *AnsiParser {
+ ap := &AnsiParser{
+ eventHandler: evtHandler,
+ context: &ansiContext{},
+ }
+ for _, o := range opts {
+ o(ap)
+ }
+
+ if isDebugEnv := os.Getenv(LogEnv); isDebugEnv == "1" {
+ logFile, _ := os.Create("ansiParser.log")
+ logger := log.New(logFile, "", log.LstdFlags)
+ if ap.logf != nil {
+ l := ap.logf
+ ap.logf = func(s string, v ...interface{}) {
+ l(s, v...)
+ logger.Printf(s, v...)
+ }
+ } else {
+ ap.logf = logger.Printf
+ }
+ }
+
+ if ap.logf == nil {
+ ap.logf = func(string, ...interface{}) {}
+ }
+
+ ap.csiEntry = csiEntryState{baseState{name: "CsiEntry", parser: ap}}
+ ap.csiParam = csiParamState{baseState{name: "CsiParam", parser: ap}}
+ ap.dcsEntry = dcsEntryState{baseState{name: "DcsEntry", parser: ap}}
+ ap.escape = escapeState{baseState{name: "Escape", parser: ap}}
+ ap.escapeIntermediate = escapeIntermediateState{baseState{name: "EscapeIntermediate", parser: ap}}
+ ap.error = errorState{baseState{name: "Error", parser: ap}}
+ ap.ground = groundState{baseState{name: "Ground", parser: ap}}
+ ap.oscString = oscStringState{baseState{name: "OscString", parser: ap}}
+
+ ap.stateMap = []state{
+ ap.csiEntry,
+ ap.csiParam,
+ ap.dcsEntry,
+ ap.escape,
+ ap.escapeIntermediate,
+ ap.error,
+ ap.ground,
+ ap.oscString,
+ }
+
+ ap.currState = getState(initialState, ap.stateMap)
+
+ ap.logf("CreateParser: parser %p", ap)
+ return ap
+}
+
+func getState(name string, states []state) state {
+ for _, el := range states {
+ if el.Name() == name {
+ return el
+ }
+ }
+
+ return nil
+}
+
+func (ap *AnsiParser) Parse(bytes []byte) (int, error) {
+ for i, b := range bytes {
+ if err := ap.handle(b); err != nil {
+ return i, err
+ }
+ }
+
+ return len(bytes), ap.eventHandler.Flush()
+}
+
+func (ap *AnsiParser) handle(b byte) error {
+ ap.context.currentChar = b
+ newState, err := ap.currState.Handle(b)
+ if err != nil {
+ return err
+ }
+
+ if newState == nil {
+ ap.logf("WARNING: newState is nil")
+ return errors.New("New state of 'nil' is invalid.")
+ }
+
+ if newState != ap.currState {
+ if err := ap.changeState(newState); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (ap *AnsiParser) changeState(newState state) error {
+ ap.logf("ChangeState %s --> %s", ap.currState.Name(), newState.Name())
+
+ // Exit old state
+ if err := ap.currState.Exit(); err != nil {
+ ap.logf("Exit state '%s' failed with : '%v'", ap.currState.Name(), err)
+ return err
+ }
+
+ // Perform transition action
+ if err := ap.currState.Transition(newState); err != nil {
+ ap.logf("Transition from '%s' to '%s' failed with: '%v'", ap.currState.Name(), newState.Name, err)
+ return err
+ }
+
+ // Enter new state
+ if err := newState.Enter(); err != nil {
+ ap.logf("Enter state '%s' failed with: '%v'", newState.Name(), err)
+ return err
+ }
+
+ ap.currState = newState
+ return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go b/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go
new file mode 100644
index 0000000000..de0a1f9cde
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go
@@ -0,0 +1,99 @@
+package ansiterm
+
+import (
+ "strconv"
+)
+
+func parseParams(bytes []byte) ([]string, error) {
+ paramBuff := make([]byte, 0, 0)
+ params := []string{}
+
+ for _, v := range bytes {
+ if v == ';' {
+ if len(paramBuff) > 0 {
+ // Completed parameter, append it to the list
+ s := string(paramBuff)
+ params = append(params, s)
+ paramBuff = make([]byte, 0, 0)
+ }
+ } else {
+ paramBuff = append(paramBuff, v)
+ }
+ }
+
+ // Last parameter may not be terminated with ';'
+ if len(paramBuff) > 0 {
+ s := string(paramBuff)
+ params = append(params, s)
+ }
+
+ return params, nil
+}
+
+func parseCmd(context ansiContext) (string, error) {
+ return string(context.currentChar), nil
+}
+
+func getInt(params []string, dflt int) int {
+ i := getInts(params, 1, dflt)[0]
+ return i
+}
+
+func getInts(params []string, minCount int, dflt int) []int {
+ ints := []int{}
+
+ for _, v := range params {
+ i, _ := strconv.Atoi(v)
+ // Zero is mapped to the default value in VT100.
+ if i == 0 {
+ i = dflt
+ }
+ ints = append(ints, i)
+ }
+
+ if len(ints) < minCount {
+ remaining := minCount - len(ints)
+ for i := 0; i < remaining; i++ {
+ ints = append(ints, dflt)
+ }
+ }
+
+ return ints
+}
+
+func (ap *AnsiParser) modeDispatch(param string, set bool) error {
+ switch param {
+ case "?3":
+ return ap.eventHandler.DECCOLM(set)
+ case "?6":
+ return ap.eventHandler.DECOM(set)
+ case "?25":
+ return ap.eventHandler.DECTCEM(set)
+ }
+ return nil
+}
+
+func (ap *AnsiParser) hDispatch(params []string) error {
+ if len(params) == 1 {
+ return ap.modeDispatch(params[0], true)
+ }
+
+ return nil
+}
+
+func (ap *AnsiParser) lDispatch(params []string) error {
+ if len(params) == 1 {
+ return ap.modeDispatch(params[0], false)
+ }
+
+ return nil
+}
+
+func getEraseParam(params []string) int {
+ param := getInt(params, 0)
+ if param < 0 || 3 < param {
+ param = 0
+ }
+
+ return param
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/parser_actions.go b/vendor/github.com/Azure/go-ansiterm/parser_actions.go
new file mode 100644
index 0000000000..0bb5e51e9a
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/parser_actions.go
@@ -0,0 +1,119 @@
+package ansiterm
+
+func (ap *AnsiParser) collectParam() error {
+ currChar := ap.context.currentChar
+ ap.logf("collectParam %#x", currChar)
+ ap.context.paramBuffer = append(ap.context.paramBuffer, currChar)
+ return nil
+}
+
+func (ap *AnsiParser) collectInter() error {
+ currChar := ap.context.currentChar
+ ap.logf("collectInter %#x", currChar)
+ ap.context.paramBuffer = append(ap.context.interBuffer, currChar)
+ return nil
+}
+
+func (ap *AnsiParser) escDispatch() error {
+ cmd, _ := parseCmd(*ap.context)
+ intermeds := ap.context.interBuffer
+ ap.logf("escDispatch currentChar: %#x", ap.context.currentChar)
+ ap.logf("escDispatch: %v(%v)", cmd, intermeds)
+
+ switch cmd {
+ case "D": // IND
+ return ap.eventHandler.IND()
+ case "E": // NEL, equivalent to CRLF
+ err := ap.eventHandler.Execute(ANSI_CARRIAGE_RETURN)
+ if err == nil {
+ err = ap.eventHandler.Execute(ANSI_LINE_FEED)
+ }
+ return err
+ case "M": // RI
+ return ap.eventHandler.RI()
+ }
+
+ return nil
+}
+
+func (ap *AnsiParser) csiDispatch() error {
+ cmd, _ := parseCmd(*ap.context)
+ params, _ := parseParams(ap.context.paramBuffer)
+ ap.logf("Parsed params: %v with length: %d", params, len(params))
+
+ ap.logf("csiDispatch: %v(%v)", cmd, params)
+
+ switch cmd {
+ case "@":
+ return ap.eventHandler.ICH(getInt(params, 1))
+ case "A":
+ return ap.eventHandler.CUU(getInt(params, 1))
+ case "B":
+ return ap.eventHandler.CUD(getInt(params, 1))
+ case "C":
+ return ap.eventHandler.CUF(getInt(params, 1))
+ case "D":
+ return ap.eventHandler.CUB(getInt(params, 1))
+ case "E":
+ return ap.eventHandler.CNL(getInt(params, 1))
+ case "F":
+ return ap.eventHandler.CPL(getInt(params, 1))
+ case "G":
+ return ap.eventHandler.CHA(getInt(params, 1))
+ case "H":
+ ints := getInts(params, 2, 1)
+ x, y := ints[0], ints[1]
+ return ap.eventHandler.CUP(x, y)
+ case "J":
+ param := getEraseParam(params)
+ return ap.eventHandler.ED(param)
+ case "K":
+ param := getEraseParam(params)
+ return ap.eventHandler.EL(param)
+ case "L":
+ return ap.eventHandler.IL(getInt(params, 1))
+ case "M":
+ return ap.eventHandler.DL(getInt(params, 1))
+ case "P":
+ return ap.eventHandler.DCH(getInt(params, 1))
+ case "S":
+ return ap.eventHandler.SU(getInt(params, 1))
+ case "T":
+ return ap.eventHandler.SD(getInt(params, 1))
+ case "c":
+ return ap.eventHandler.DA(params)
+ case "d":
+ return ap.eventHandler.VPA(getInt(params, 1))
+ case "f":
+ ints := getInts(params, 2, 1)
+ x, y := ints[0], ints[1]
+ return ap.eventHandler.HVP(x, y)
+ case "h":
+ return ap.hDispatch(params)
+ case "l":
+ return ap.lDispatch(params)
+ case "m":
+ return ap.eventHandler.SGR(getInts(params, 1, 0))
+ case "r":
+ ints := getInts(params, 2, 1)
+ top, bottom := ints[0], ints[1]
+ return ap.eventHandler.DECSTBM(top, bottom)
+ default:
+ ap.logf("ERROR: Unsupported CSI command: '%s', with full context: %v", cmd, ap.context)
+ return nil
+ }
+
+}
+
+func (ap *AnsiParser) print() error {
+ return ap.eventHandler.Print(ap.context.currentChar)
+}
+
+func (ap *AnsiParser) clear() error {
+ ap.context = &ansiContext{}
+ return nil
+}
+
+func (ap *AnsiParser) execute() error {
+ return ap.eventHandler.Execute(ap.context.currentChar)
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/states.go b/vendor/github.com/Azure/go-ansiterm/states.go
new file mode 100644
index 0000000000..f2ea1fcd12
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/states.go
@@ -0,0 +1,71 @@
+package ansiterm
+
+type stateID int
+
+type state interface {
+ Enter() error
+ Exit() error
+ Handle(byte) (state, error)
+ Name() string
+ Transition(state) error
+}
+
+type baseState struct {
+ name string
+ parser *AnsiParser
+}
+
+func (base baseState) Enter() error {
+ return nil
+}
+
+func (base baseState) Exit() error {
+ return nil
+}
+
+func (base baseState) Handle(b byte) (s state, e error) {
+
+ switch {
+ case b == CSI_ENTRY:
+ return base.parser.csiEntry, nil
+ case b == DCS_ENTRY:
+ return base.parser.dcsEntry, nil
+ case b == ANSI_ESCAPE_PRIMARY:
+ return base.parser.escape, nil
+ case b == OSC_STRING:
+ return base.parser.oscString, nil
+ case sliceContains(toGroundBytes, b):
+ return base.parser.ground, nil
+ }
+
+ return nil, nil
+}
+
+func (base baseState) Name() string {
+ return base.name
+}
+
+func (base baseState) Transition(s state) error {
+ if s == base.parser.ground {
+ execBytes := []byte{0x18}
+ execBytes = append(execBytes, 0x1A)
+ execBytes = append(execBytes, getByteRange(0x80, 0x8F)...)
+ execBytes = append(execBytes, getByteRange(0x91, 0x97)...)
+ execBytes = append(execBytes, 0x99)
+ execBytes = append(execBytes, 0x9A)
+
+ if sliceContains(execBytes, base.parser.context.currentChar) {
+ return base.parser.execute()
+ }
+ }
+
+ return nil
+}
+
+type dcsEntryState struct {
+ baseState
+}
+
+type errorState struct {
+ baseState
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/utilities.go b/vendor/github.com/Azure/go-ansiterm/utilities.go
new file mode 100644
index 0000000000..392114493a
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/utilities.go
@@ -0,0 +1,21 @@
+package ansiterm
+
+import (
+ "strconv"
+)
+
+func sliceContains(bytes []byte, b byte) bool {
+ for _, v := range bytes {
+ if v == b {
+ return true
+ }
+ }
+
+ return false
+}
+
+func convertBytesToInteger(bytes []byte) int {
+ s := string(bytes)
+ i, _ := strconv.Atoi(s)
+ return i
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go b/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go
new file mode 100644
index 0000000000..5599082ae9
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/ansi.go
@@ -0,0 +1,196 @@
+// +build windows
+
+package winterm
+
+import (
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+ "syscall"
+
+ "github.com/Azure/go-ansiterm"
+ windows "golang.org/x/sys/windows"
+)
+
+// Windows keyboard constants
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx.
+const (
+ VK_PRIOR = 0x21 // PAGE UP key
+ VK_NEXT = 0x22 // PAGE DOWN key
+ VK_END = 0x23 // END key
+ VK_HOME = 0x24 // HOME key
+ VK_LEFT = 0x25 // LEFT ARROW key
+ VK_UP = 0x26 // UP ARROW key
+ VK_RIGHT = 0x27 // RIGHT ARROW key
+ VK_DOWN = 0x28 // DOWN ARROW key
+ VK_SELECT = 0x29 // SELECT key
+ VK_PRINT = 0x2A // PRINT key
+ VK_EXECUTE = 0x2B // EXECUTE key
+ VK_SNAPSHOT = 0x2C // PRINT SCREEN key
+ VK_INSERT = 0x2D // INS key
+ VK_DELETE = 0x2E // DEL key
+ VK_HELP = 0x2F // HELP key
+ VK_F1 = 0x70 // F1 key
+ VK_F2 = 0x71 // F2 key
+ VK_F3 = 0x72 // F3 key
+ VK_F4 = 0x73 // F4 key
+ VK_F5 = 0x74 // F5 key
+ VK_F6 = 0x75 // F6 key
+ VK_F7 = 0x76 // F7 key
+ VK_F8 = 0x77 // F8 key
+ VK_F9 = 0x78 // F9 key
+ VK_F10 = 0x79 // F10 key
+ VK_F11 = 0x7A // F11 key
+ VK_F12 = 0x7B // F12 key
+
+ RIGHT_ALT_PRESSED = 0x0001
+ LEFT_ALT_PRESSED = 0x0002
+ RIGHT_CTRL_PRESSED = 0x0004
+ LEFT_CTRL_PRESSED = 0x0008
+ SHIFT_PRESSED = 0x0010
+ NUMLOCK_ON = 0x0020
+ SCROLLLOCK_ON = 0x0040
+ CAPSLOCK_ON = 0x0080
+ ENHANCED_KEY = 0x0100
+)
+
+type ansiCommand struct {
+ CommandBytes []byte
+ Command string
+ Parameters []string
+ IsSpecial bool
+}
+
+func newAnsiCommand(command []byte) *ansiCommand {
+
+ if isCharacterSelectionCmdChar(command[1]) {
+ // Is Character Set Selection commands
+ return &ansiCommand{
+ CommandBytes: command,
+ Command: string(command),
+ IsSpecial: true,
+ }
+ }
+
+ // last char is command character
+ lastCharIndex := len(command) - 1
+
+ ac := &ansiCommand{
+ CommandBytes: command,
+ Command: string(command[lastCharIndex]),
+ IsSpecial: false,
+ }
+
+ // more than a single escape
+ if lastCharIndex != 0 {
+ start := 1
+ // skip if double char escape sequence
+ if command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_ESCAPE_SECONDARY {
+ start++
+ }
+ // convert this to GetNextParam method
+ ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ansiterm.ANSI_PARAMETER_SEP)
+ }
+
+ return ac
+}
+
+func (ac *ansiCommand) paramAsSHORT(index int, defaultValue int16) int16 {
+ if index < 0 || index >= len(ac.Parameters) {
+ return defaultValue
+ }
+
+ param, err := strconv.ParseInt(ac.Parameters[index], 10, 16)
+ if err != nil {
+ return defaultValue
+ }
+
+ return int16(param)
+}
+
+func (ac *ansiCommand) String() string {
+ return fmt.Sprintf("0x%v \"%v\" (\"%v\")",
+ bytesToHex(ac.CommandBytes),
+ ac.Command,
+ strings.Join(ac.Parameters, "\",\""))
+}
+
+// isAnsiCommandChar returns true if the passed byte falls within the range of ANSI commands.
+// See http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html.
+func isAnsiCommandChar(b byte) bool {
+ switch {
+ case ansiterm.ANSI_COMMAND_FIRST <= b && b <= ansiterm.ANSI_COMMAND_LAST && b != ansiterm.ANSI_ESCAPE_SECONDARY:
+ return true
+ case b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_OSC || b == ansiterm.ANSI_CMD_DECPAM || b == ansiterm.ANSI_CMD_DECPNM:
+ // non-CSI escape sequence terminator
+ return true
+ case b == ansiterm.ANSI_CMD_STR_TERM || b == ansiterm.ANSI_BEL:
+ // String escape sequence terminator
+ return true
+ }
+ return false
+}
+
+func isXtermOscSequence(command []byte, current byte) bool {
+ return (len(command) >= 2 && command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_CMD_OSC && current != ansiterm.ANSI_BEL)
+}
+
+func isCharacterSelectionCmdChar(b byte) bool {
+ return (b == ansiterm.ANSI_CMD_G0 || b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_G2 || b == ansiterm.ANSI_CMD_G3)
+}
+
+// bytesToHex converts a slice of bytes to a human-readable string.
+func bytesToHex(b []byte) string {
+ hex := make([]string, len(b))
+ for i, ch := range b {
+ hex[i] = fmt.Sprintf("%X", ch)
+ }
+ return strings.Join(hex, "")
+}
+
+// ensureInRange adjusts the passed value, if necessary, to ensure it is within
+// the passed min / max range.
+func ensureInRange(n int16, min int16, max int16) int16 {
+ if n < min {
+ return min
+ } else if n > max {
+ return max
+ } else {
+ return n
+ }
+}
+
+func GetStdFile(nFile int) (*os.File, uintptr) {
+ var file *os.File
+
+ // syscall uses negative numbers
+ // windows package uses very big uint32
+ // Keep these switches split so we don't have to convert ints too much.
+ switch uint32(nFile) {
+ case windows.STD_INPUT_HANDLE:
+ file = os.Stdin
+ case windows.STD_OUTPUT_HANDLE:
+ file = os.Stdout
+ case windows.STD_ERROR_HANDLE:
+ file = os.Stderr
+ default:
+ switch nFile {
+ case syscall.STD_INPUT_HANDLE:
+ file = os.Stdin
+ case syscall.STD_OUTPUT_HANDLE:
+ file = os.Stdout
+ case syscall.STD_ERROR_HANDLE:
+ file = os.Stderr
+ default:
+ panic(fmt.Errorf("Invalid standard handle identifier: %v", nFile))
+ }
+ }
+
+ fd, err := syscall.GetStdHandle(nFile)
+ if err != nil {
+ panic(fmt.Errorf("Invalid standard handle identifier: %v -- %v", nFile, err))
+ }
+
+ return file, uintptr(fd)
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/api.go b/vendor/github.com/Azure/go-ansiterm/winterm/api.go
new file mode 100644
index 0000000000..6055e33b91
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/api.go
@@ -0,0 +1,327 @@
+// +build windows
+
+package winterm
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+//===========================================================================================================
+// IMPORTANT NOTE:
+//
+// The methods below make extensive use of the "unsafe" package to obtain the required pointers.
+// Beginning in Go 1.3, the garbage collector may release local variables (e.g., incoming arguments, stack
+// variables) the pointers reference *before* the API completes.
+//
+// As a result, in those cases, the code must hint that the variables remain in active by invoking the
+// dummy method "use" (see below). Newer versions of Go are planned to change the mechanism to no longer
+// require unsafe pointers.
+//
+// If you add or modify methods, ENSURE protection of local variables through the "use" builtin to inform
+// the garbage collector the variables remain in use if:
+//
+// -- The value is not a pointer (e.g., int32, struct)
+// -- The value is not referenced by the method after passing the pointer to Windows
+//
+// See http://golang.org/doc/go1.3.
+//===========================================================================================================
+
+var (
+ kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
+
+ getConsoleCursorInfoProc = kernel32DLL.NewProc("GetConsoleCursorInfo")
+ setConsoleCursorInfoProc = kernel32DLL.NewProc("SetConsoleCursorInfo")
+ setConsoleCursorPositionProc = kernel32DLL.NewProc("SetConsoleCursorPosition")
+ setConsoleModeProc = kernel32DLL.NewProc("SetConsoleMode")
+ getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo")
+ setConsoleScreenBufferSizeProc = kernel32DLL.NewProc("SetConsoleScreenBufferSize")
+ scrollConsoleScreenBufferProc = kernel32DLL.NewProc("ScrollConsoleScreenBufferA")
+ setConsoleTextAttributeProc = kernel32DLL.NewProc("SetConsoleTextAttribute")
+ setConsoleWindowInfoProc = kernel32DLL.NewProc("SetConsoleWindowInfo")
+ writeConsoleOutputProc = kernel32DLL.NewProc("WriteConsoleOutputW")
+ readConsoleInputProc = kernel32DLL.NewProc("ReadConsoleInputW")
+ waitForSingleObjectProc = kernel32DLL.NewProc("WaitForSingleObject")
+)
+
+// Windows Console constants
+const (
+ // Console modes
+ // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
+ ENABLE_PROCESSED_INPUT = 0x0001
+ ENABLE_LINE_INPUT = 0x0002
+ ENABLE_ECHO_INPUT = 0x0004
+ ENABLE_WINDOW_INPUT = 0x0008
+ ENABLE_MOUSE_INPUT = 0x0010
+ ENABLE_INSERT_MODE = 0x0020
+ ENABLE_QUICK_EDIT_MODE = 0x0040
+ ENABLE_EXTENDED_FLAGS = 0x0080
+ ENABLE_AUTO_POSITION = 0x0100
+ ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200
+
+ ENABLE_PROCESSED_OUTPUT = 0x0001
+ ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
+ ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
+ DISABLE_NEWLINE_AUTO_RETURN = 0x0008
+ ENABLE_LVB_GRID_WORLDWIDE = 0x0010
+
+ // Character attributes
+ // Note:
+ // -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan).
+ // Clearing all foreground or background colors results in black; setting all creates white.
+ // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes.
+ FOREGROUND_BLUE uint16 = 0x0001
+ FOREGROUND_GREEN uint16 = 0x0002
+ FOREGROUND_RED uint16 = 0x0004
+ FOREGROUND_INTENSITY uint16 = 0x0008
+ FOREGROUND_MASK uint16 = 0x000F
+
+ BACKGROUND_BLUE uint16 = 0x0010
+ BACKGROUND_GREEN uint16 = 0x0020
+ BACKGROUND_RED uint16 = 0x0040
+ BACKGROUND_INTENSITY uint16 = 0x0080
+ BACKGROUND_MASK uint16 = 0x00F0
+
+ COMMON_LVB_MASK uint16 = 0xFF00
+ COMMON_LVB_REVERSE_VIDEO uint16 = 0x4000
+ COMMON_LVB_UNDERSCORE uint16 = 0x8000
+
+ // Input event types
+ // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
+ KEY_EVENT = 0x0001
+ MOUSE_EVENT = 0x0002
+ WINDOW_BUFFER_SIZE_EVENT = 0x0004
+ MENU_EVENT = 0x0008
+ FOCUS_EVENT = 0x0010
+
+ // WaitForSingleObject return codes
+ WAIT_ABANDONED = 0x00000080
+ WAIT_FAILED = 0xFFFFFFFF
+ WAIT_SIGNALED = 0x0000000
+ WAIT_TIMEOUT = 0x00000102
+
+ // WaitForSingleObject wait duration
+ WAIT_INFINITE = 0xFFFFFFFF
+ WAIT_ONE_SECOND = 1000
+ WAIT_HALF_SECOND = 500
+ WAIT_QUARTER_SECOND = 250
+)
+
+// Windows API Console types
+// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682101(v=vs.85).aspx for Console specific types (e.g., COORD)
+// -- See https://msdn.microsoft.com/en-us/library/aa296569(v=vs.60).aspx for comments on alignment
+type (
+ CHAR_INFO struct {
+ UnicodeChar uint16
+ Attributes uint16
+ }
+
+ CONSOLE_CURSOR_INFO struct {
+ Size uint32
+ Visible int32
+ }
+
+ CONSOLE_SCREEN_BUFFER_INFO struct {
+ Size COORD
+ CursorPosition COORD
+ Attributes uint16
+ Window SMALL_RECT
+ MaximumWindowSize COORD
+ }
+
+ COORD struct {
+ X int16
+ Y int16
+ }
+
+ SMALL_RECT struct {
+ Left int16
+ Top int16
+ Right int16
+ Bottom int16
+ }
+
+ // INPUT_RECORD is a C/C++ union of which KEY_EVENT_RECORD is one case, it is also the largest
+ // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
+ INPUT_RECORD struct {
+ EventType uint16
+ KeyEvent KEY_EVENT_RECORD
+ }
+
+ KEY_EVENT_RECORD struct {
+ KeyDown int32
+ RepeatCount uint16
+ VirtualKeyCode uint16
+ VirtualScanCode uint16
+ UnicodeChar uint16
+ ControlKeyState uint32
+ }
+
+ WINDOW_BUFFER_SIZE struct {
+ Size COORD
+ }
+)
+
+// boolToBOOL converts a Go bool into a Windows int32.
+func boolToBOOL(f bool) int32 {
+ if f {
+ return int32(1)
+ } else {
+ return int32(0)
+ }
+}
+
+// GetConsoleCursorInfo retrieves information about the size and visiblity of the console cursor.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683163(v=vs.85).aspx.
+func GetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
+ r1, r2, err := getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
+ return checkError(r1, r2, err)
+}
+
+// SetConsoleCursorInfo sets the size and visiblity of the console cursor.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686019(v=vs.85).aspx.
+func SetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
+ r1, r2, err := setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
+ return checkError(r1, r2, err)
+}
+
+// SetConsoleCursorPosition location of the console cursor.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx.
+func SetConsoleCursorPosition(handle uintptr, coord COORD) error {
+ r1, r2, err := setConsoleCursorPositionProc.Call(handle, coordToPointer(coord))
+ use(coord)
+ return checkError(r1, r2, err)
+}
+
+// GetConsoleMode gets the console mode for given file descriptor
+// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx.
+func GetConsoleMode(handle uintptr) (mode uint32, err error) {
+ err = syscall.GetConsoleMode(syscall.Handle(handle), &mode)
+ return mode, err
+}
+
+// SetConsoleMode sets the console mode for given file descriptor
+// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
+func SetConsoleMode(handle uintptr, mode uint32) error {
+ r1, r2, err := setConsoleModeProc.Call(handle, uintptr(mode), 0)
+ use(mode)
+ return checkError(r1, r2, err)
+}
+
+// GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer.
+// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx.
+func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) {
+ info := CONSOLE_SCREEN_BUFFER_INFO{}
+ err := checkError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0))
+ if err != nil {
+ return nil, err
+ }
+ return &info, nil
+}
+
+func ScrollConsoleScreenBuffer(handle uintptr, scrollRect SMALL_RECT, clipRect SMALL_RECT, destOrigin COORD, char CHAR_INFO) error {
+ r1, r2, err := scrollConsoleScreenBufferProc.Call(handle, uintptr(unsafe.Pointer(&scrollRect)), uintptr(unsafe.Pointer(&clipRect)), coordToPointer(destOrigin), uintptr(unsafe.Pointer(&char)))
+ use(scrollRect)
+ use(clipRect)
+ use(destOrigin)
+ use(char)
+ return checkError(r1, r2, err)
+}
+
+// SetConsoleScreenBufferSize sets the size of the console screen buffer.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686044(v=vs.85).aspx.
+func SetConsoleScreenBufferSize(handle uintptr, coord COORD) error {
+ r1, r2, err := setConsoleScreenBufferSizeProc.Call(handle, coordToPointer(coord))
+ use(coord)
+ return checkError(r1, r2, err)
+}
+
+// SetConsoleTextAttribute sets the attributes of characters written to the
+// console screen buffer by the WriteFile or WriteConsole function.
+// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx.
+func SetConsoleTextAttribute(handle uintptr, attribute uint16) error {
+ r1, r2, err := setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0)
+ use(attribute)
+ return checkError(r1, r2, err)
+}
+
+// SetConsoleWindowInfo sets the size and position of the console screen buffer's window.
+// Note that the size and location must be within and no larger than the backing console screen buffer.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686125(v=vs.85).aspx.
+func SetConsoleWindowInfo(handle uintptr, isAbsolute bool, rect SMALL_RECT) error {
+ r1, r2, err := setConsoleWindowInfoProc.Call(handle, uintptr(boolToBOOL(isAbsolute)), uintptr(unsafe.Pointer(&rect)))
+ use(isAbsolute)
+ use(rect)
+ return checkError(r1, r2, err)
+}
+
+// WriteConsoleOutput writes the CHAR_INFOs from the provided buffer to the active console buffer.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687404(v=vs.85).aspx.
+func WriteConsoleOutput(handle uintptr, buffer []CHAR_INFO, bufferSize COORD, bufferCoord COORD, writeRegion *SMALL_RECT) error {
+ r1, r2, err := writeConsoleOutputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), coordToPointer(bufferSize), coordToPointer(bufferCoord), uintptr(unsafe.Pointer(writeRegion)))
+ use(buffer)
+ use(bufferSize)
+ use(bufferCoord)
+ return checkError(r1, r2, err)
+}
+
+// ReadConsoleInput reads (and removes) data from the console input buffer.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx.
+func ReadConsoleInput(handle uintptr, buffer []INPUT_RECORD, count *uint32) error {
+ r1, r2, err := readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), uintptr(len(buffer)), uintptr(unsafe.Pointer(count)))
+ use(buffer)
+ return checkError(r1, r2, err)
+}
+
+// WaitForSingleObject waits for the passed handle to be signaled.
+// It returns true if the handle was signaled; false otherwise.
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx.
+func WaitForSingleObject(handle uintptr, msWait uint32) (bool, error) {
+ r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(uint32(msWait)))
+ switch r1 {
+ case WAIT_ABANDONED, WAIT_TIMEOUT:
+ return false, nil
+ case WAIT_SIGNALED:
+ return true, nil
+ }
+ use(msWait)
+ return false, err
+}
+
+// String helpers
+func (info CONSOLE_SCREEN_BUFFER_INFO) String() string {
+ return fmt.Sprintf("Size(%v) Cursor(%v) Window(%v) Max(%v)", info.Size, info.CursorPosition, info.Window, info.MaximumWindowSize)
+}
+
+func (coord COORD) String() string {
+ return fmt.Sprintf("%v,%v", coord.X, coord.Y)
+}
+
+func (rect SMALL_RECT) String() string {
+ return fmt.Sprintf("(%v,%v),(%v,%v)", rect.Left, rect.Top, rect.Right, rect.Bottom)
+}
+
+// checkError evaluates the results of a Windows API call and returns the error if it failed.
+func checkError(r1, r2 uintptr, err error) error {
+ // Windows APIs return non-zero to indicate success
+ if r1 != 0 {
+ return nil
+ }
+
+ // Return the error if provided, otherwise default to EINVAL
+ if err != nil {
+ return err
+ }
+ return syscall.EINVAL
+}
+
+// coordToPointer converts a COORD into a uintptr (by fooling the type system).
+func coordToPointer(c COORD) uintptr {
+ // Note: This code assumes the two SHORTs are correctly laid out; the "cast" to uint32 is just to get a pointer to pass.
+ return uintptr(*((*uint32)(unsafe.Pointer(&c))))
+}
+
+// use is a no-op, but the compiler cannot see that it is.
+// Calling use(p) ensures that p is kept live until that point.
+func use(p interface{}) {}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go b/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go
new file mode 100644
index 0000000000..cbec8f728f
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go
@@ -0,0 +1,100 @@
+// +build windows
+
+package winterm
+
+import "github.com/Azure/go-ansiterm"
+
+const (
+ FOREGROUND_COLOR_MASK = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
+ BACKGROUND_COLOR_MASK = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
+)
+
+// collectAnsiIntoWindowsAttributes modifies the passed Windows text mode flags to reflect the
+// request represented by the passed ANSI mode.
+func collectAnsiIntoWindowsAttributes(windowsMode uint16, inverted bool, baseMode uint16, ansiMode int16) (uint16, bool) {
+ switch ansiMode {
+
+ // Mode styles
+ case ansiterm.ANSI_SGR_BOLD:
+ windowsMode = windowsMode | FOREGROUND_INTENSITY
+
+ case ansiterm.ANSI_SGR_DIM, ansiterm.ANSI_SGR_BOLD_DIM_OFF:
+ windowsMode &^= FOREGROUND_INTENSITY
+
+ case ansiterm.ANSI_SGR_UNDERLINE:
+ windowsMode = windowsMode | COMMON_LVB_UNDERSCORE
+
+ case ansiterm.ANSI_SGR_REVERSE:
+ inverted = true
+
+ case ansiterm.ANSI_SGR_REVERSE_OFF:
+ inverted = false
+
+ case ansiterm.ANSI_SGR_UNDERLINE_OFF:
+ windowsMode &^= COMMON_LVB_UNDERSCORE
+
+ // Foreground colors
+ case ansiterm.ANSI_SGR_FOREGROUND_DEFAULT:
+ windowsMode = (windowsMode &^ FOREGROUND_MASK) | (baseMode & FOREGROUND_MASK)
+
+ case ansiterm.ANSI_SGR_FOREGROUND_BLACK:
+ windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK)
+
+ case ansiterm.ANSI_SGR_FOREGROUND_RED:
+ windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED
+
+ case ansiterm.ANSI_SGR_FOREGROUND_GREEN:
+ windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN
+
+ case ansiterm.ANSI_SGR_FOREGROUND_YELLOW:
+ windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN
+
+ case ansiterm.ANSI_SGR_FOREGROUND_BLUE:
+ windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_BLUE
+
+ case ansiterm.ANSI_SGR_FOREGROUND_MAGENTA:
+ windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_BLUE
+
+ case ansiterm.ANSI_SGR_FOREGROUND_CYAN:
+ windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE
+
+ case ansiterm.ANSI_SGR_FOREGROUND_WHITE:
+ windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
+
+ // Background colors
+ case ansiterm.ANSI_SGR_BACKGROUND_DEFAULT:
+ // Black with no intensity
+ windowsMode = (windowsMode &^ BACKGROUND_MASK) | (baseMode & BACKGROUND_MASK)
+
+ case ansiterm.ANSI_SGR_BACKGROUND_BLACK:
+ windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK)
+
+ case ansiterm.ANSI_SGR_BACKGROUND_RED:
+ windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED
+
+ case ansiterm.ANSI_SGR_BACKGROUND_GREEN:
+ windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN
+
+ case ansiterm.ANSI_SGR_BACKGROUND_YELLOW:
+ windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN
+
+ case ansiterm.ANSI_SGR_BACKGROUND_BLUE:
+ windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_BLUE
+
+ case ansiterm.ANSI_SGR_BACKGROUND_MAGENTA:
+ windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_BLUE
+
+ case ansiterm.ANSI_SGR_BACKGROUND_CYAN:
+ windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE
+
+ case ansiterm.ANSI_SGR_BACKGROUND_WHITE:
+ windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
+ }
+
+ return windowsMode, inverted
+}
+
+// invertAttributes inverts the foreground and background colors of a Windows attributes value
+func invertAttributes(windowsMode uint16) uint16 {
+ return (COMMON_LVB_MASK & windowsMode) | ((FOREGROUND_MASK & windowsMode) << 4) | ((BACKGROUND_MASK & windowsMode) >> 4)
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go b/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go
new file mode 100644
index 0000000000..3ee06ea728
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go
@@ -0,0 +1,101 @@
+// +build windows
+
+package winterm
+
+const (
+ horizontal = iota
+ vertical
+)
+
+func (h *windowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_INFO) SMALL_RECT {
+ if h.originMode {
+ sr := h.effectiveSr(info.Window)
+ return SMALL_RECT{
+ Top: sr.top,
+ Bottom: sr.bottom,
+ Left: 0,
+ Right: info.Size.X - 1,
+ }
+ } else {
+ return SMALL_RECT{
+ Top: info.Window.Top,
+ Bottom: info.Window.Bottom,
+ Left: 0,
+ Right: info.Size.X - 1,
+ }
+ }
+}
+
+// setCursorPosition sets the cursor to the specified position, bounded to the screen size
+func (h *windowsAnsiEventHandler) setCursorPosition(position COORD, window SMALL_RECT) error {
+ position.X = ensureInRange(position.X, window.Left, window.Right)
+ position.Y = ensureInRange(position.Y, window.Top, window.Bottom)
+ err := SetConsoleCursorPosition(h.fd, position)
+ if err != nil {
+ return err
+ }
+ h.logf("Cursor position set: (%d, %d)", position.X, position.Y)
+ return err
+}
+
+func (h *windowsAnsiEventHandler) moveCursorVertical(param int) error {
+ return h.moveCursor(vertical, param)
+}
+
+func (h *windowsAnsiEventHandler) moveCursorHorizontal(param int) error {
+ return h.moveCursor(horizontal, param)
+}
+
+func (h *windowsAnsiEventHandler) moveCursor(moveMode int, param int) error {
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+
+ position := info.CursorPosition
+ switch moveMode {
+ case horizontal:
+ position.X += int16(param)
+ case vertical:
+ position.Y += int16(param)
+ }
+
+ if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (h *windowsAnsiEventHandler) moveCursorLine(param int) error {
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+
+ position := info.CursorPosition
+ position.X = 0
+ position.Y += int16(param)
+
+ if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (h *windowsAnsiEventHandler) moveCursorColumn(param int) error {
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+
+ position := info.CursorPosition
+ position.X = int16(param) - 1
+
+ if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go b/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go
new file mode 100644
index 0000000000..244b5fa25e
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go
@@ -0,0 +1,84 @@
+// +build windows
+
+package winterm
+
+import "github.com/Azure/go-ansiterm"
+
+func (h *windowsAnsiEventHandler) clearRange(attributes uint16, fromCoord COORD, toCoord COORD) error {
+ // Ignore an invalid (negative area) request
+ if toCoord.Y < fromCoord.Y {
+ return nil
+ }
+
+ var err error
+
+ var coordStart = COORD{}
+ var coordEnd = COORD{}
+
+ xCurrent, yCurrent := fromCoord.X, fromCoord.Y
+ xEnd, yEnd := toCoord.X, toCoord.Y
+
+ // Clear any partial initial line
+ if xCurrent > 0 {
+ coordStart.X, coordStart.Y = xCurrent, yCurrent
+ coordEnd.X, coordEnd.Y = xEnd, yCurrent
+
+ err = h.clearRect(attributes, coordStart, coordEnd)
+ if err != nil {
+ return err
+ }
+
+ xCurrent = 0
+ yCurrent += 1
+ }
+
+ // Clear intervening rectangular section
+ if yCurrent < yEnd {
+ coordStart.X, coordStart.Y = xCurrent, yCurrent
+ coordEnd.X, coordEnd.Y = xEnd, yEnd-1
+
+ err = h.clearRect(attributes, coordStart, coordEnd)
+ if err != nil {
+ return err
+ }
+
+ xCurrent = 0
+ yCurrent = yEnd
+ }
+
+ // Clear remaining partial ending line
+ coordStart.X, coordStart.Y = xCurrent, yCurrent
+ coordEnd.X, coordEnd.Y = xEnd, yEnd
+
+ err = h.clearRect(attributes, coordStart, coordEnd)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (h *windowsAnsiEventHandler) clearRect(attributes uint16, fromCoord COORD, toCoord COORD) error {
+ region := SMALL_RECT{Top: fromCoord.Y, Left: fromCoord.X, Bottom: toCoord.Y, Right: toCoord.X}
+ width := toCoord.X - fromCoord.X + 1
+ height := toCoord.Y - fromCoord.Y + 1
+ size := uint32(width) * uint32(height)
+
+ if size <= 0 {
+ return nil
+ }
+
+ buffer := make([]CHAR_INFO, size)
+
+ char := CHAR_INFO{ansiterm.FILL_CHARACTER, attributes}
+ for i := 0; i < int(size); i++ {
+ buffer[i] = char
+ }
+
+ err := WriteConsoleOutput(h.fd, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, ®ion)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go b/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go
new file mode 100644
index 0000000000..2d27fa1d02
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go
@@ -0,0 +1,118 @@
+// +build windows
+
+package winterm
+
+// effectiveSr gets the current effective scroll region in buffer coordinates
+func (h *windowsAnsiEventHandler) effectiveSr(window SMALL_RECT) scrollRegion {
+ top := addInRange(window.Top, h.sr.top, window.Top, window.Bottom)
+ bottom := addInRange(window.Top, h.sr.bottom, window.Top, window.Bottom)
+ if top >= bottom {
+ top = window.Top
+ bottom = window.Bottom
+ }
+ return scrollRegion{top: top, bottom: bottom}
+}
+
+func (h *windowsAnsiEventHandler) scrollUp(param int) error {
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+
+ sr := h.effectiveSr(info.Window)
+ return h.scroll(param, sr, info)
+}
+
+func (h *windowsAnsiEventHandler) scrollDown(param int) error {
+ return h.scrollUp(-param)
+}
+
+func (h *windowsAnsiEventHandler) deleteLines(param int) error {
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+
+ start := info.CursorPosition.Y
+ sr := h.effectiveSr(info.Window)
+ // Lines cannot be inserted or deleted outside the scrolling region.
+ if start >= sr.top && start <= sr.bottom {
+ sr.top = start
+ return h.scroll(param, sr, info)
+ } else {
+ return nil
+ }
+}
+
+func (h *windowsAnsiEventHandler) insertLines(param int) error {
+ return h.deleteLines(-param)
+}
+
+// scroll scrolls the provided scroll region by param lines. The scroll region is in buffer coordinates.
+func (h *windowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSOLE_SCREEN_BUFFER_INFO) error {
+ h.logf("scroll: scrollTop: %d, scrollBottom: %d", sr.top, sr.bottom)
+ h.logf("scroll: windowTop: %d, windowBottom: %d", info.Window.Top, info.Window.Bottom)
+
+ // Copy from and clip to the scroll region (full buffer width)
+ scrollRect := SMALL_RECT{
+ Top: sr.top,
+ Bottom: sr.bottom,
+ Left: 0,
+ Right: info.Size.X - 1,
+ }
+
+ // Origin to which area should be copied
+ destOrigin := COORD{
+ X: 0,
+ Y: sr.top - int16(param),
+ }
+
+ char := CHAR_INFO{
+ UnicodeChar: ' ',
+ Attributes: h.attributes,
+ }
+
+ if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (h *windowsAnsiEventHandler) deleteCharacters(param int) error {
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+ return h.scrollLine(param, info.CursorPosition, info)
+}
+
+func (h *windowsAnsiEventHandler) insertCharacters(param int) error {
+ return h.deleteCharacters(-param)
+}
+
+// scrollLine scrolls a line horizontally starting at the provided position by a number of columns.
+func (h *windowsAnsiEventHandler) scrollLine(columns int, position COORD, info *CONSOLE_SCREEN_BUFFER_INFO) error {
+ // Copy from and clip to the scroll region (full buffer width)
+ scrollRect := SMALL_RECT{
+ Top: position.Y,
+ Bottom: position.Y,
+ Left: position.X,
+ Right: info.Size.X - 1,
+ }
+
+ // Origin to which area should be copied
+ destOrigin := COORD{
+ X: position.X - int16(columns),
+ Y: position.Y,
+ }
+
+ char := CHAR_INFO{
+ UnicodeChar: ' ',
+ Attributes: h.attributes,
+ }
+
+ if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go b/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go
new file mode 100644
index 0000000000..afa7635d77
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/utilities.go
@@ -0,0 +1,9 @@
+// +build windows
+
+package winterm
+
+// AddInRange increments a value by the passed quantity while ensuring the values
+// always remain within the supplied min / max range.
+func addInRange(n int16, increment int16, min int16, max int16) int16 {
+ return ensureInRange(n+increment, min, max)
+}
diff --git a/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go b/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go
new file mode 100644
index 0000000000..2d40fb75ad
--- /dev/null
+++ b/vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go
@@ -0,0 +1,743 @@
+// +build windows
+
+package winterm
+
+import (
+ "bytes"
+ "log"
+ "os"
+ "strconv"
+
+ "github.com/Azure/go-ansiterm"
+)
+
+type windowsAnsiEventHandler struct {
+ fd uintptr
+ file *os.File
+ infoReset *CONSOLE_SCREEN_BUFFER_INFO
+ sr scrollRegion
+ buffer bytes.Buffer
+ attributes uint16
+ inverted bool
+ wrapNext bool
+ drewMarginByte bool
+ originMode bool
+ marginByte byte
+ curInfo *CONSOLE_SCREEN_BUFFER_INFO
+ curPos COORD
+ logf func(string, ...interface{})
+}
+
+type Option func(*windowsAnsiEventHandler)
+
+func WithLogf(f func(string, ...interface{})) Option {
+ return func(w *windowsAnsiEventHandler) {
+ w.logf = f
+ }
+}
+
+func CreateWinEventHandler(fd uintptr, file *os.File, opts ...Option) ansiterm.AnsiEventHandler {
+ infoReset, err := GetConsoleScreenBufferInfo(fd)
+ if err != nil {
+ return nil
+ }
+
+ h := &windowsAnsiEventHandler{
+ fd: fd,
+ file: file,
+ infoReset: infoReset,
+ attributes: infoReset.Attributes,
+ }
+ for _, o := range opts {
+ o(h)
+ }
+
+ if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" {
+ logFile, _ := os.Create("winEventHandler.log")
+ logger := log.New(logFile, "", log.LstdFlags)
+ if h.logf != nil {
+ l := h.logf
+ h.logf = func(s string, v ...interface{}) {
+ l(s, v...)
+ logger.Printf(s, v...)
+ }
+ } else {
+ h.logf = logger.Printf
+ }
+ }
+
+ if h.logf == nil {
+ h.logf = func(string, ...interface{}) {}
+ }
+
+ return h
+}
+
+type scrollRegion struct {
+ top int16
+ bottom int16
+}
+
+// simulateLF simulates a LF or CR+LF by scrolling if necessary to handle the
+// current cursor position and scroll region settings, in which case it returns
+// true. If no special handling is necessary, then it does nothing and returns
+// false.
+//
+// In the false case, the caller should ensure that a carriage return
+// and line feed are inserted or that the text is otherwise wrapped.
+func (h *windowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) {
+ if h.wrapNext {
+ if err := h.Flush(); err != nil {
+ return false, err
+ }
+ h.clearWrap()
+ }
+ pos, info, err := h.getCurrentInfo()
+ if err != nil {
+ return false, err
+ }
+ sr := h.effectiveSr(info.Window)
+ if pos.Y == sr.bottom {
+ // Scrolling is necessary. Let Windows automatically scroll if the scrolling region
+ // is the full window.
+ if sr.top == info.Window.Top && sr.bottom == info.Window.Bottom {
+ if includeCR {
+ pos.X = 0
+ h.updatePos(pos)
+ }
+ return false, nil
+ }
+
+ // A custom scroll region is active. Scroll the window manually to simulate
+ // the LF.
+ if err := h.Flush(); err != nil {
+ return false, err
+ }
+ h.logf("Simulating LF inside scroll region")
+ if err := h.scrollUp(1); err != nil {
+ return false, err
+ }
+ if includeCR {
+ pos.X = 0
+ if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
+ return false, err
+ }
+ }
+ return true, nil
+
+ } else if pos.Y < info.Window.Bottom {
+ // Let Windows handle the LF.
+ pos.Y++
+ if includeCR {
+ pos.X = 0
+ }
+ h.updatePos(pos)
+ return false, nil
+ } else {
+ // The cursor is at the bottom of the screen but outside the scroll
+ // region. Skip the LF.
+ h.logf("Simulating LF outside scroll region")
+ if includeCR {
+ if err := h.Flush(); err != nil {
+ return false, err
+ }
+ pos.X = 0
+ if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
+ return false, err
+ }
+ }
+ return true, nil
+ }
+}
+
+// executeLF executes a LF without a CR.
+func (h *windowsAnsiEventHandler) executeLF() error {
+ handled, err := h.simulateLF(false)
+ if err != nil {
+ return err
+ }
+ if !handled {
+ // Windows LF will reset the cursor column position. Write the LF
+ // and restore the cursor position.
+ pos, _, err := h.getCurrentInfo()
+ if err != nil {
+ return err
+ }
+ h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED)
+ if pos.X != 0 {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("Resetting cursor position for LF without CR")
+ if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func (h *windowsAnsiEventHandler) Print(b byte) error {
+ if h.wrapNext {
+ h.buffer.WriteByte(h.marginByte)
+ h.clearWrap()
+ if _, err := h.simulateLF(true); err != nil {
+ return err
+ }
+ }
+ pos, info, err := h.getCurrentInfo()
+ if err != nil {
+ return err
+ }
+ if pos.X == info.Size.X-1 {
+ h.wrapNext = true
+ h.marginByte = b
+ } else {
+ pos.X++
+ h.updatePos(pos)
+ h.buffer.WriteByte(b)
+ }
+ return nil
+}
+
+func (h *windowsAnsiEventHandler) Execute(b byte) error {
+ switch b {
+ case ansiterm.ANSI_TAB:
+ h.logf("Execute(TAB)")
+ // Move to the next tab stop, but preserve auto-wrap if already set.
+ if !h.wrapNext {
+ pos, info, err := h.getCurrentInfo()
+ if err != nil {
+ return err
+ }
+ pos.X = (pos.X + 8) - pos.X%8
+ if pos.X >= info.Size.X {
+ pos.X = info.Size.X - 1
+ }
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case ansiterm.ANSI_BEL:
+ h.buffer.WriteByte(ansiterm.ANSI_BEL)
+ return nil
+
+ case ansiterm.ANSI_BACKSPACE:
+ if h.wrapNext {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.clearWrap()
+ }
+ pos, _, err := h.getCurrentInfo()
+ if err != nil {
+ return err
+ }
+ if pos.X > 0 {
+ pos.X--
+ h.updatePos(pos)
+ h.buffer.WriteByte(ansiterm.ANSI_BACKSPACE)
+ }
+ return nil
+
+ case ansiterm.ANSI_VERTICAL_TAB, ansiterm.ANSI_FORM_FEED:
+ // Treat as true LF.
+ return h.executeLF()
+
+ case ansiterm.ANSI_LINE_FEED:
+ // Simulate a CR and LF for now since there is no way in go-ansiterm
+ // to tell if the LF should include CR (and more things break when it's
+ // missing than when it's incorrectly added).
+ handled, err := h.simulateLF(true)
+ if handled || err != nil {
+ return err
+ }
+ return h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED)
+
+ case ansiterm.ANSI_CARRIAGE_RETURN:
+ if h.wrapNext {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.clearWrap()
+ }
+ pos, _, err := h.getCurrentInfo()
+ if err != nil {
+ return err
+ }
+ if pos.X != 0 {
+ pos.X = 0
+ h.updatePos(pos)
+ h.buffer.WriteByte(ansiterm.ANSI_CARRIAGE_RETURN)
+ }
+ return nil
+
+ default:
+ return nil
+ }
+}
+
+func (h *windowsAnsiEventHandler) CUU(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("CUU: [%v]", []string{strconv.Itoa(param)})
+ h.clearWrap()
+ return h.moveCursorVertical(-param)
+}
+
+func (h *windowsAnsiEventHandler) CUD(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("CUD: [%v]", []string{strconv.Itoa(param)})
+ h.clearWrap()
+ return h.moveCursorVertical(param)
+}
+
+func (h *windowsAnsiEventHandler) CUF(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("CUF: [%v]", []string{strconv.Itoa(param)})
+ h.clearWrap()
+ return h.moveCursorHorizontal(param)
+}
+
+func (h *windowsAnsiEventHandler) CUB(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("CUB: [%v]", []string{strconv.Itoa(param)})
+ h.clearWrap()
+ return h.moveCursorHorizontal(-param)
+}
+
+func (h *windowsAnsiEventHandler) CNL(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("CNL: [%v]", []string{strconv.Itoa(param)})
+ h.clearWrap()
+ return h.moveCursorLine(param)
+}
+
+func (h *windowsAnsiEventHandler) CPL(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("CPL: [%v]", []string{strconv.Itoa(param)})
+ h.clearWrap()
+ return h.moveCursorLine(-param)
+}
+
+func (h *windowsAnsiEventHandler) CHA(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("CHA: [%v]", []string{strconv.Itoa(param)})
+ h.clearWrap()
+ return h.moveCursorColumn(param)
+}
+
+func (h *windowsAnsiEventHandler) VPA(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("VPA: [[%d]]", param)
+ h.clearWrap()
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+ window := h.getCursorWindow(info)
+ position := info.CursorPosition
+ position.Y = window.Top + int16(param) - 1
+ return h.setCursorPosition(position, window)
+}
+
+func (h *windowsAnsiEventHandler) CUP(row int, col int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("CUP: [[%d %d]]", row, col)
+ h.clearWrap()
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+
+ window := h.getCursorWindow(info)
+ position := COORD{window.Left + int16(col) - 1, window.Top + int16(row) - 1}
+ return h.setCursorPosition(position, window)
+}
+
+func (h *windowsAnsiEventHandler) HVP(row int, col int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("HVP: [[%d %d]]", row, col)
+ h.clearWrap()
+ return h.CUP(row, col)
+}
+
+func (h *windowsAnsiEventHandler) DECTCEM(visible bool) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("DECTCEM: [%v]", []string{strconv.FormatBool(visible)})
+ h.clearWrap()
+ return nil
+}
+
+func (h *windowsAnsiEventHandler) DECOM(enable bool) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("DECOM: [%v]", []string{strconv.FormatBool(enable)})
+ h.clearWrap()
+ h.originMode = enable
+ return h.CUP(1, 1)
+}
+
+func (h *windowsAnsiEventHandler) DECCOLM(use132 bool) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("DECCOLM: [%v]", []string{strconv.FormatBool(use132)})
+ h.clearWrap()
+ if err := h.ED(2); err != nil {
+ return err
+ }
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+ targetWidth := int16(80)
+ if use132 {
+ targetWidth = 132
+ }
+ if info.Size.X < targetWidth {
+ if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
+ h.logf("set buffer failed: %v", err)
+ return err
+ }
+ }
+ window := info.Window
+ window.Left = 0
+ window.Right = targetWidth - 1
+ if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
+ h.logf("set window failed: %v", err)
+ return err
+ }
+ if info.Size.X > targetWidth {
+ if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
+ h.logf("set buffer failed: %v", err)
+ return err
+ }
+ }
+ return SetConsoleCursorPosition(h.fd, COORD{0, 0})
+}
+
+func (h *windowsAnsiEventHandler) ED(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("ED: [%v]", []string{strconv.Itoa(param)})
+ h.clearWrap()
+
+ // [J -- Erases from the cursor to the end of the screen, including the cursor position.
+ // [1J -- Erases from the beginning of the screen to the cursor, including the cursor position.
+ // [2J -- Erases the complete display. The cursor does not move.
+ // Notes:
+ // -- Clearing the entire buffer, versus just the Window, works best for Windows Consoles
+
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+
+ var start COORD
+ var end COORD
+
+ switch param {
+ case 0:
+ start = info.CursorPosition
+ end = COORD{info.Size.X - 1, info.Size.Y - 1}
+
+ case 1:
+ start = COORD{0, 0}
+ end = info.CursorPosition
+
+ case 2:
+ start = COORD{0, 0}
+ end = COORD{info.Size.X - 1, info.Size.Y - 1}
+ }
+
+ err = h.clearRange(h.attributes, start, end)
+ if err != nil {
+ return err
+ }
+
+ // If the whole buffer was cleared, move the window to the top while preserving
+ // the window-relative cursor position.
+ if param == 2 {
+ pos := info.CursorPosition
+ window := info.Window
+ pos.Y -= window.Top
+ window.Bottom -= window.Top
+ window.Top = 0
+ if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
+ return err
+ }
+ if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (h *windowsAnsiEventHandler) EL(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("EL: [%v]", strconv.Itoa(param))
+ h.clearWrap()
+
+ // [K -- Erases from the cursor to the end of the line, including the cursor position.
+ // [1K -- Erases from the beginning of the line to the cursor, including the cursor position.
+ // [2K -- Erases the complete line.
+
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+
+ var start COORD
+ var end COORD
+
+ switch param {
+ case 0:
+ start = info.CursorPosition
+ end = COORD{info.Size.X, info.CursorPosition.Y}
+
+ case 1:
+ start = COORD{0, info.CursorPosition.Y}
+ end = info.CursorPosition
+
+ case 2:
+ start = COORD{0, info.CursorPosition.Y}
+ end = COORD{info.Size.X, info.CursorPosition.Y}
+ }
+
+ err = h.clearRange(h.attributes, start, end)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (h *windowsAnsiEventHandler) IL(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("IL: [%v]", strconv.Itoa(param))
+ h.clearWrap()
+ return h.insertLines(param)
+}
+
+func (h *windowsAnsiEventHandler) DL(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("DL: [%v]", strconv.Itoa(param))
+ h.clearWrap()
+ return h.deleteLines(param)
+}
+
+func (h *windowsAnsiEventHandler) ICH(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("ICH: [%v]", strconv.Itoa(param))
+ h.clearWrap()
+ return h.insertCharacters(param)
+}
+
+func (h *windowsAnsiEventHandler) DCH(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("DCH: [%v]", strconv.Itoa(param))
+ h.clearWrap()
+ return h.deleteCharacters(param)
+}
+
+func (h *windowsAnsiEventHandler) SGR(params []int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ strings := []string{}
+ for _, v := range params {
+ strings = append(strings, strconv.Itoa(v))
+ }
+
+ h.logf("SGR: [%v]", strings)
+
+ if len(params) <= 0 {
+ h.attributes = h.infoReset.Attributes
+ h.inverted = false
+ } else {
+ for _, attr := range params {
+
+ if attr == ansiterm.ANSI_SGR_RESET {
+ h.attributes = h.infoReset.Attributes
+ h.inverted = false
+ continue
+ }
+
+ h.attributes, h.inverted = collectAnsiIntoWindowsAttributes(h.attributes, h.inverted, h.infoReset.Attributes, int16(attr))
+ }
+ }
+
+ attributes := h.attributes
+ if h.inverted {
+ attributes = invertAttributes(attributes)
+ }
+ err := SetConsoleTextAttribute(h.fd, attributes)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (h *windowsAnsiEventHandler) SU(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("SU: [%v]", []string{strconv.Itoa(param)})
+ h.clearWrap()
+ return h.scrollUp(param)
+}
+
+func (h *windowsAnsiEventHandler) SD(param int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("SD: [%v]", []string{strconv.Itoa(param)})
+ h.clearWrap()
+ return h.scrollDown(param)
+}
+
+func (h *windowsAnsiEventHandler) DA(params []string) error {
+ h.logf("DA: [%v]", params)
+ // DA cannot be implemented because it must send data on the VT100 input stream,
+ // which is not available to go-ansiterm.
+ return nil
+}
+
+func (h *windowsAnsiEventHandler) DECSTBM(top int, bottom int) error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("DECSTBM: [%d, %d]", top, bottom)
+
+ // Windows is 0 indexed, Linux is 1 indexed
+ h.sr.top = int16(top - 1)
+ h.sr.bottom = int16(bottom - 1)
+
+ // This command also moves the cursor to the origin.
+ h.clearWrap()
+ return h.CUP(1, 1)
+}
+
+func (h *windowsAnsiEventHandler) RI() error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ h.logf("RI: []")
+ h.clearWrap()
+
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+
+ sr := h.effectiveSr(info.Window)
+ if info.CursorPosition.Y == sr.top {
+ return h.scrollDown(1)
+ }
+
+ return h.moveCursorVertical(-1)
+}
+
+func (h *windowsAnsiEventHandler) IND() error {
+ h.logf("IND: []")
+ return h.executeLF()
+}
+
+func (h *windowsAnsiEventHandler) Flush() error {
+ h.curInfo = nil
+ if h.buffer.Len() > 0 {
+ h.logf("Flush: [%s]", h.buffer.Bytes())
+ if _, err := h.buffer.WriteTo(h.file); err != nil {
+ return err
+ }
+ }
+
+ if h.wrapNext && !h.drewMarginByte {
+ h.logf("Flush: drawing margin byte '%c'", h.marginByte)
+
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return err
+ }
+
+ charInfo := []CHAR_INFO{{UnicodeChar: uint16(h.marginByte), Attributes: info.Attributes}}
+ size := COORD{1, 1}
+ position := COORD{0, 0}
+ region := SMALL_RECT{Left: info.CursorPosition.X, Top: info.CursorPosition.Y, Right: info.CursorPosition.X, Bottom: info.CursorPosition.Y}
+ if err := WriteConsoleOutput(h.fd, charInfo, size, position, ®ion); err != nil {
+ return err
+ }
+ h.drewMarginByte = true
+ }
+ return nil
+}
+
+// cacheConsoleInfo ensures that the current console screen information has been queried
+// since the last call to Flush(). It must be called before accessing h.curInfo or h.curPos.
+func (h *windowsAnsiEventHandler) getCurrentInfo() (COORD, *CONSOLE_SCREEN_BUFFER_INFO, error) {
+ if h.curInfo == nil {
+ info, err := GetConsoleScreenBufferInfo(h.fd)
+ if err != nil {
+ return COORD{}, nil, err
+ }
+ h.curInfo = info
+ h.curPos = info.CursorPosition
+ }
+ return h.curPos, h.curInfo, nil
+}
+
+func (h *windowsAnsiEventHandler) updatePos(pos COORD) {
+ if h.curInfo == nil {
+ panic("failed to call getCurrentInfo before calling updatePos")
+ }
+ h.curPos = pos
+}
+
+// clearWrap clears the state where the cursor is in the margin
+// waiting for the next character before wrapping the line. This must
+// be done before most operations that act on the cursor.
+func (h *windowsAnsiEventHandler) clearWrap() {
+ h.wrapNext = false
+ h.drewMarginByte = false
+}
diff --git a/vendor/github.com/BurntSushi/toml/.gitignore b/vendor/github.com/BurntSushi/toml/.gitignore
new file mode 100644
index 0000000000..fe79e3adda
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/.gitignore
@@ -0,0 +1,2 @@
+/toml.test
+/toml-test
diff --git a/vendor/github.com/BurntSushi/toml/COPYING b/vendor/github.com/BurntSushi/toml/COPYING
new file mode 100644
index 0000000000..01b5743200
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/COPYING
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 TOML authors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/github.com/BurntSushi/toml/README.md b/vendor/github.com/BurntSushi/toml/README.md
new file mode 100644
index 0000000000..235496eeb2
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/README.md
@@ -0,0 +1,120 @@
+TOML stands for Tom's Obvious, Minimal Language. This Go package provides a
+reflection interface similar to Go's standard library `json` and `xml` packages.
+
+Compatible with TOML version [v1.0.0](https://toml.io/en/v1.0.0).
+
+Documentation: https://pkg.go.dev/github.com/BurntSushi/toml
+
+See the [releases page](https://github.com/BurntSushi/toml/releases) for a
+changelog; this information is also in the git tag annotations (e.g. `git show
+v0.4.0`).
+
+This library requires Go 1.18 or newer; add it to your go.mod with:
+
+ % go get github.com/BurntSushi/toml@latest
+
+It also comes with a TOML validator CLI tool:
+
+ % go install github.com/BurntSushi/toml/cmd/tomlv@latest
+ % tomlv some-toml-file.toml
+
+### Examples
+For the simplest example, consider some TOML file as just a list of keys and
+values:
+
+```toml
+Age = 25
+Cats = [ "Cauchy", "Plato" ]
+Pi = 3.14
+Perfection = [ 6, 28, 496, 8128 ]
+DOB = 1987-07-05T05:45:00Z
+```
+
+Which can be decoded with:
+
+```go
+type Config struct {
+ Age int
+ Cats []string
+ Pi float64
+ Perfection []int
+ DOB time.Time
+}
+
+var conf Config
+_, err := toml.Decode(tomlData, &conf)
+```
+
+You can also use struct tags if your struct field name doesn't map to a TOML key
+value directly:
+
+```toml
+some_key_NAME = "wat"
+```
+
+```go
+type TOML struct {
+ ObscureKey string `toml:"some_key_NAME"`
+}
+```
+
+Beware that like other decoders **only exported fields** are considered when
+encoding and decoding; private fields are silently ignored.
+
+### Using the `Marshaler` and `encoding.TextUnmarshaler` interfaces
+Here's an example that automatically parses values in a `mail.Address`:
+
+```toml
+contacts = [
+ "Donald Duck ",
+ "Scrooge McDuck ",
+]
+```
+
+Can be decoded with:
+
+```go
+// Create address type which satisfies the encoding.TextUnmarshaler interface.
+type address struct {
+ *mail.Address
+}
+
+func (a *address) UnmarshalText(text []byte) error {
+ var err error
+ a.Address, err = mail.ParseAddress(string(text))
+ return err
+}
+
+// Decode it.
+func decode() {
+ blob := `
+ contacts = [
+ "Donald Duck ",
+ "Scrooge McDuck ",
+ ]
+ `
+
+ var contacts struct {
+ Contacts []address
+ }
+
+ _, err := toml.Decode(blob, &contacts)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ for _, c := range contacts.Contacts {
+ fmt.Printf("%#v\n", c.Address)
+ }
+
+ // Output:
+ // &mail.Address{Name:"Donald Duck", Address:"donald@duckburg.com"}
+ // &mail.Address{Name:"Scrooge McDuck", Address:"scrooge@duckburg.com"}
+}
+```
+
+To target TOML specifically you can implement `UnmarshalTOML` TOML interface in
+a similar way.
+
+### More complex usage
+See the [`_example/`](/_example) directory for a more complex example.
diff --git a/vendor/github.com/BurntSushi/toml/decode.go b/vendor/github.com/BurntSushi/toml/decode.go
new file mode 100644
index 0000000000..3fa516caa2
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/decode.go
@@ -0,0 +1,638 @@
+package toml
+
+import (
+ "bytes"
+ "encoding"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/fs"
+ "math"
+ "os"
+ "reflect"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// Unmarshaler is the interface implemented by objects that can unmarshal a
+// TOML description of themselves.
+type Unmarshaler interface {
+ UnmarshalTOML(any) error
+}
+
+// Unmarshal decodes the contents of data in TOML format into a pointer v.
+//
+// See [Decoder] for a description of the decoding process.
+func Unmarshal(data []byte, v any) error {
+ _, err := NewDecoder(bytes.NewReader(data)).Decode(v)
+ return err
+}
+
+// Decode the TOML data in to the pointer v.
+//
+// See [Decoder] for a description of the decoding process.
+func Decode(data string, v any) (MetaData, error) {
+ return NewDecoder(strings.NewReader(data)).Decode(v)
+}
+
+// DecodeFile reads the contents of a file and decodes it with [Decode].
+func DecodeFile(path string, v any) (MetaData, error) {
+ fp, err := os.Open(path)
+ if err != nil {
+ return MetaData{}, err
+ }
+ defer fp.Close()
+ return NewDecoder(fp).Decode(v)
+}
+
+// DecodeFS reads the contents of a file from [fs.FS] and decodes it with
+// [Decode].
+func DecodeFS(fsys fs.FS, path string, v any) (MetaData, error) {
+ fp, err := fsys.Open(path)
+ if err != nil {
+ return MetaData{}, err
+ }
+ defer fp.Close()
+ return NewDecoder(fp).Decode(v)
+}
+
+// Primitive is a TOML value that hasn't been decoded into a Go value.
+//
+// This type can be used for any value, which will cause decoding to be delayed.
+// You can use [PrimitiveDecode] to "manually" decode these values.
+//
+// NOTE: The underlying representation of a `Primitive` value is subject to
+// change. Do not rely on it.
+//
+// NOTE: Primitive values are still parsed, so using them will only avoid the
+// overhead of reflection. They can be useful when you don't know the exact type
+// of TOML data until runtime.
+type Primitive struct {
+ undecoded any
+ context Key
+}
+
+// The significand precision for float32 and float64 is 24 and 53 bits; this is
+// the range a natural number can be stored in a float without loss of data.
+const (
+ maxSafeFloat32Int = 16777215 // 2^24-1
+ maxSafeFloat64Int = int64(9007199254740991) // 2^53-1
+)
+
+// Decoder decodes TOML data.
+//
+// TOML tables correspond to Go structs or maps; they can be used
+// interchangeably, but structs offer better type safety.
+//
+// TOML table arrays correspond to either a slice of structs or a slice of maps.
+//
+// TOML datetimes correspond to [time.Time]. Local datetimes are parsed in the
+// local timezone.
+//
+// [time.Duration] types are treated as nanoseconds if the TOML value is an
+// integer, or they're parsed with time.ParseDuration() if they're strings.
+//
+// All other TOML types (float, string, int, bool and array) correspond to the
+// obvious Go types.
+//
+// An exception to the above rules is if a type implements the TextUnmarshaler
+// interface, in which case any primitive TOML value (floats, strings, integers,
+// booleans, datetimes) will be converted to a []byte and given to the value's
+// UnmarshalText method. See the Unmarshaler example for a demonstration with
+// email addresses.
+//
+// # Key mapping
+//
+// TOML keys can map to either keys in a Go map or field names in a Go struct.
+// The special `toml` struct tag can be used to map TOML keys to struct fields
+// that don't match the key name exactly (see the example). A case insensitive
+// match to struct names will be tried if an exact match can't be found.
+//
+// The mapping between TOML values and Go values is loose. That is, there may
+// exist TOML values that cannot be placed into your representation, and there
+// may be parts of your representation that do not correspond to TOML values.
+// This loose mapping can be made stricter by using the IsDefined and/or
+// Undecoded methods on the MetaData returned.
+//
+// This decoder does not handle cyclic types. Decode will not terminate if a
+// cyclic type is passed.
+type Decoder struct {
+ r io.Reader
+}
+
+// NewDecoder creates a new Decoder.
+func NewDecoder(r io.Reader) *Decoder {
+ return &Decoder{r: r}
+}
+
+var (
+ unmarshalToml = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
+ unmarshalText = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
+ primitiveType = reflect.TypeOf((*Primitive)(nil)).Elem()
+)
+
+// Decode TOML data in to the pointer `v`.
+func (dec *Decoder) Decode(v any) (MetaData, error) {
+ rv := reflect.ValueOf(v)
+ if rv.Kind() != reflect.Ptr {
+ s := "%q"
+ if reflect.TypeOf(v) == nil {
+ s = "%v"
+ }
+
+ return MetaData{}, fmt.Errorf("toml: cannot decode to non-pointer "+s, reflect.TypeOf(v))
+ }
+ if rv.IsNil() {
+ return MetaData{}, fmt.Errorf("toml: cannot decode to nil value of %q", reflect.TypeOf(v))
+ }
+
+ // Check if this is a supported type: struct, map, any, or something that
+ // implements UnmarshalTOML or UnmarshalText.
+ rv = indirect(rv)
+ rt := rv.Type()
+ if rv.Kind() != reflect.Struct && rv.Kind() != reflect.Map &&
+ !(rv.Kind() == reflect.Interface && rv.NumMethod() == 0) &&
+ !rt.Implements(unmarshalToml) && !rt.Implements(unmarshalText) {
+ return MetaData{}, fmt.Errorf("toml: cannot decode to type %s", rt)
+ }
+
+ // TODO: parser should read from io.Reader? Or at the very least, make it
+ // read from []byte rather than string
+ data, err := io.ReadAll(dec.r)
+ if err != nil {
+ return MetaData{}, err
+ }
+
+ p, err := parse(string(data))
+ if err != nil {
+ return MetaData{}, err
+ }
+
+ md := MetaData{
+ mapping: p.mapping,
+ keyInfo: p.keyInfo,
+ keys: p.ordered,
+ decoded: make(map[string]struct{}, len(p.ordered)),
+ context: nil,
+ data: data,
+ }
+ return md, md.unify(p.mapping, rv)
+}
+
+// PrimitiveDecode is just like the other Decode* functions, except it decodes a
+// TOML value that has already been parsed. Valid primitive values can *only* be
+// obtained from values filled by the decoder functions, including this method.
+// (i.e., v may contain more [Primitive] values.)
+//
+// Meta data for primitive values is included in the meta data returned by the
+// Decode* functions with one exception: keys returned by the Undecoded method
+// will only reflect keys that were decoded. Namely, any keys hidden behind a
+// Primitive will be considered undecoded. Executing this method will update the
+// undecoded keys in the meta data. (See the example.)
+func (md *MetaData) PrimitiveDecode(primValue Primitive, v any) error {
+ md.context = primValue.context
+ defer func() { md.context = nil }()
+ return md.unify(primValue.undecoded, rvalue(v))
+}
+
+// markDecodedRecursive is a helper to mark any key under the given tmap as
+// decoded, recursing as needed
+func markDecodedRecursive(md *MetaData, tmap map[string]any) {
+ for key := range tmap {
+ md.decoded[md.context.add(key).String()] = struct{}{}
+ if tmap, ok := tmap[key].(map[string]any); ok {
+ md.context = append(md.context, key)
+ markDecodedRecursive(md, tmap)
+ md.context = md.context[0 : len(md.context)-1]
+ }
+ }
+}
+
+// unify performs a sort of type unification based on the structure of `rv`,
+// which is the client representation.
+//
+// Any type mismatch produces an error. Finding a type that we don't know
+// how to handle produces an unsupported type error.
+func (md *MetaData) unify(data any, rv reflect.Value) error {
+ // Special case. Look for a `Primitive` value.
+ // TODO: #76 would make this superfluous after implemented.
+ if rv.Type() == primitiveType {
+ // Save the undecoded data and the key context into the primitive
+ // value.
+ context := make(Key, len(md.context))
+ copy(context, md.context)
+ rv.Set(reflect.ValueOf(Primitive{
+ undecoded: data,
+ context: context,
+ }))
+ return nil
+ }
+
+ rvi := rv.Interface()
+ if v, ok := rvi.(Unmarshaler); ok {
+ err := v.UnmarshalTOML(data)
+ if err != nil {
+ return md.parseErr(err)
+ }
+ // Assume the Unmarshaler decoded everything, so mark all keys under
+ // this table as decoded.
+ if tmap, ok := data.(map[string]any); ok {
+ markDecodedRecursive(md, tmap)
+ }
+ if aot, ok := data.([]map[string]any); ok {
+ for _, tmap := range aot {
+ markDecodedRecursive(md, tmap)
+ }
+ }
+ return nil
+ }
+ if v, ok := rvi.(encoding.TextUnmarshaler); ok {
+ return md.unifyText(data, v)
+ }
+
+ // TODO:
+ // The behavior here is incorrect whenever a Go type satisfies the
+ // encoding.TextUnmarshaler interface but also corresponds to a TOML hash or
+ // array. In particular, the unmarshaler should only be applied to primitive
+ // TOML values. But at this point, it will be applied to all kinds of values
+ // and produce an incorrect error whenever those values are hashes or arrays
+ // (including arrays of tables).
+
+ k := rv.Kind()
+
+ if k >= reflect.Int && k <= reflect.Uint64 {
+ return md.unifyInt(data, rv)
+ }
+ switch k {
+ case reflect.Struct:
+ return md.unifyStruct(data, rv)
+ case reflect.Map:
+ return md.unifyMap(data, rv)
+ case reflect.Array:
+ return md.unifyArray(data, rv)
+ case reflect.Slice:
+ return md.unifySlice(data, rv)
+ case reflect.String:
+ return md.unifyString(data, rv)
+ case reflect.Bool:
+ return md.unifyBool(data, rv)
+ case reflect.Interface:
+ if rv.NumMethod() > 0 { /// Only empty interfaces are supported.
+ return md.e("unsupported type %s", rv.Type())
+ }
+ return md.unifyAnything(data, rv)
+ case reflect.Float32, reflect.Float64:
+ return md.unifyFloat64(data, rv)
+ }
+ return md.e("unsupported type %s", rv.Kind())
+}
+
+func (md *MetaData) unifyStruct(mapping any, rv reflect.Value) error {
+ tmap, ok := mapping.(map[string]any)
+ if !ok {
+ if mapping == nil {
+ return nil
+ }
+ return md.e("type mismatch for %s: expected table but found %s", rv.Type().String(), fmtType(mapping))
+ }
+
+ for key, datum := range tmap {
+ var f *field
+ fields := cachedTypeFields(rv.Type())
+ for i := range fields {
+ ff := &fields[i]
+ if ff.name == key {
+ f = ff
+ break
+ }
+ if f == nil && strings.EqualFold(ff.name, key) {
+ f = ff
+ }
+ }
+ if f != nil {
+ subv := rv
+ for _, i := range f.index {
+ subv = indirect(subv.Field(i))
+ }
+
+ if isUnifiable(subv) {
+ md.decoded[md.context.add(key).String()] = struct{}{}
+ md.context = append(md.context, key)
+
+ err := md.unify(datum, subv)
+ if err != nil {
+ return err
+ }
+ md.context = md.context[0 : len(md.context)-1]
+ } else if f.name != "" {
+ return md.e("cannot write unexported field %s.%s", rv.Type().String(), f.name)
+ }
+ }
+ }
+ return nil
+}
+
+func (md *MetaData) unifyMap(mapping any, rv reflect.Value) error {
+ keyType := rv.Type().Key().Kind()
+ if keyType != reflect.String && keyType != reflect.Interface {
+ return fmt.Errorf("toml: cannot decode to a map with non-string key type (%s in %q)",
+ keyType, rv.Type())
+ }
+
+ tmap, ok := mapping.(map[string]any)
+ if !ok {
+ if tmap == nil {
+ return nil
+ }
+ return md.badtype("map", mapping)
+ }
+ if rv.IsNil() {
+ rv.Set(reflect.MakeMap(rv.Type()))
+ }
+ for k, v := range tmap {
+ md.decoded[md.context.add(k).String()] = struct{}{}
+ md.context = append(md.context, k)
+
+ rvval := reflect.Indirect(reflect.New(rv.Type().Elem()))
+
+ err := md.unify(v, indirect(rvval))
+ if err != nil {
+ return err
+ }
+ md.context = md.context[0 : len(md.context)-1]
+
+ rvkey := indirect(reflect.New(rv.Type().Key()))
+
+ switch keyType {
+ case reflect.Interface:
+ rvkey.Set(reflect.ValueOf(k))
+ case reflect.String:
+ rvkey.SetString(k)
+ }
+
+ rv.SetMapIndex(rvkey, rvval)
+ }
+ return nil
+}
+
+func (md *MetaData) unifyArray(data any, rv reflect.Value) error {
+ datav := reflect.ValueOf(data)
+ if datav.Kind() != reflect.Slice {
+ if !datav.IsValid() {
+ return nil
+ }
+ return md.badtype("slice", data)
+ }
+ if l := datav.Len(); l != rv.Len() {
+ return md.e("expected array length %d; got TOML array of length %d", rv.Len(), l)
+ }
+ return md.unifySliceArray(datav, rv)
+}
+
+func (md *MetaData) unifySlice(data any, rv reflect.Value) error {
+ datav := reflect.ValueOf(data)
+ if datav.Kind() != reflect.Slice {
+ if !datav.IsValid() {
+ return nil
+ }
+ return md.badtype("slice", data)
+ }
+ n := datav.Len()
+ if rv.IsNil() || rv.Cap() < n {
+ rv.Set(reflect.MakeSlice(rv.Type(), n, n))
+ }
+ rv.SetLen(n)
+ return md.unifySliceArray(datav, rv)
+}
+
+func (md *MetaData) unifySliceArray(data, rv reflect.Value) error {
+ l := data.Len()
+ for i := 0; i < l; i++ {
+ err := md.unify(data.Index(i).Interface(), indirect(rv.Index(i)))
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (md *MetaData) unifyString(data any, rv reflect.Value) error {
+ _, ok := rv.Interface().(json.Number)
+ if ok {
+ if i, ok := data.(int64); ok {
+ rv.SetString(strconv.FormatInt(i, 10))
+ } else if f, ok := data.(float64); ok {
+ rv.SetString(strconv.FormatFloat(f, 'f', -1, 64))
+ } else {
+ return md.badtype("string", data)
+ }
+ return nil
+ }
+
+ if s, ok := data.(string); ok {
+ rv.SetString(s)
+ return nil
+ }
+ return md.badtype("string", data)
+}
+
+func (md *MetaData) unifyFloat64(data any, rv reflect.Value) error {
+ rvk := rv.Kind()
+
+ if num, ok := data.(float64); ok {
+ switch rvk {
+ case reflect.Float32:
+ if num < -math.MaxFloat32 || num > math.MaxFloat32 {
+ return md.parseErr(errParseRange{i: num, size: rvk.String()})
+ }
+ fallthrough
+ case reflect.Float64:
+ rv.SetFloat(num)
+ default:
+ panic("bug")
+ }
+ return nil
+ }
+
+ if num, ok := data.(int64); ok {
+ if (rvk == reflect.Float32 && (num < -maxSafeFloat32Int || num > maxSafeFloat32Int)) ||
+ (rvk == reflect.Float64 && (num < -maxSafeFloat64Int || num > maxSafeFloat64Int)) {
+ return md.parseErr(errUnsafeFloat{i: num, size: rvk.String()})
+ }
+ rv.SetFloat(float64(num))
+ return nil
+ }
+
+ return md.badtype("float", data)
+}
+
+func (md *MetaData) unifyInt(data any, rv reflect.Value) error {
+ _, ok := rv.Interface().(time.Duration)
+ if ok {
+ // Parse as string duration, and fall back to regular integer parsing
+ // (as nanosecond) if this is not a string.
+ if s, ok := data.(string); ok {
+ dur, err := time.ParseDuration(s)
+ if err != nil {
+ return md.parseErr(errParseDuration{s})
+ }
+ rv.SetInt(int64(dur))
+ return nil
+ }
+ }
+
+ num, ok := data.(int64)
+ if !ok {
+ return md.badtype("integer", data)
+ }
+
+ rvk := rv.Kind()
+ switch {
+ case rvk >= reflect.Int && rvk <= reflect.Int64:
+ if (rvk == reflect.Int8 && (num < math.MinInt8 || num > math.MaxInt8)) ||
+ (rvk == reflect.Int16 && (num < math.MinInt16 || num > math.MaxInt16)) ||
+ (rvk == reflect.Int32 && (num < math.MinInt32 || num > math.MaxInt32)) {
+ return md.parseErr(errParseRange{i: num, size: rvk.String()})
+ }
+ rv.SetInt(num)
+ case rvk >= reflect.Uint && rvk <= reflect.Uint64:
+ unum := uint64(num)
+ if rvk == reflect.Uint8 && (num < 0 || unum > math.MaxUint8) ||
+ rvk == reflect.Uint16 && (num < 0 || unum > math.MaxUint16) ||
+ rvk == reflect.Uint32 && (num < 0 || unum > math.MaxUint32) {
+ return md.parseErr(errParseRange{i: num, size: rvk.String()})
+ }
+ rv.SetUint(unum)
+ default:
+ panic("unreachable")
+ }
+ return nil
+}
+
+func (md *MetaData) unifyBool(data any, rv reflect.Value) error {
+ if b, ok := data.(bool); ok {
+ rv.SetBool(b)
+ return nil
+ }
+ return md.badtype("boolean", data)
+}
+
+func (md *MetaData) unifyAnything(data any, rv reflect.Value) error {
+ rv.Set(reflect.ValueOf(data))
+ return nil
+}
+
+func (md *MetaData) unifyText(data any, v encoding.TextUnmarshaler) error {
+ var s string
+ switch sdata := data.(type) {
+ case Marshaler:
+ text, err := sdata.MarshalTOML()
+ if err != nil {
+ return err
+ }
+ s = string(text)
+ case encoding.TextMarshaler:
+ text, err := sdata.MarshalText()
+ if err != nil {
+ return err
+ }
+ s = string(text)
+ case fmt.Stringer:
+ s = sdata.String()
+ case string:
+ s = sdata
+ case bool:
+ s = fmt.Sprintf("%v", sdata)
+ case int64:
+ s = fmt.Sprintf("%d", sdata)
+ case float64:
+ s = fmt.Sprintf("%f", sdata)
+ default:
+ return md.badtype("primitive (string-like)", data)
+ }
+ if err := v.UnmarshalText([]byte(s)); err != nil {
+ return md.parseErr(err)
+ }
+ return nil
+}
+
+func (md *MetaData) badtype(dst string, data any) error {
+ return md.e("incompatible types: TOML value has type %s; destination has type %s", fmtType(data), dst)
+}
+
+func (md *MetaData) parseErr(err error) error {
+ k := md.context.String()
+ d := string(md.data)
+ return ParseError{
+ Message: err.Error(),
+ err: err,
+ LastKey: k,
+ Position: md.keyInfo[k].pos.withCol(d),
+ Line: md.keyInfo[k].pos.Line,
+ input: d,
+ }
+}
+
+func (md *MetaData) e(format string, args ...any) error {
+ f := "toml: "
+ if len(md.context) > 0 {
+ f = fmt.Sprintf("toml: (last key %q): ", md.context)
+ p := md.keyInfo[md.context.String()].pos
+ if p.Line > 0 {
+ f = fmt.Sprintf("toml: line %d (last key %q): ", p.Line, md.context)
+ }
+ }
+ return fmt.Errorf(f+format, args...)
+}
+
+// rvalue returns a reflect.Value of `v`. All pointers are resolved.
+func rvalue(v any) reflect.Value {
+ return indirect(reflect.ValueOf(v))
+}
+
+// indirect returns the value pointed to by a pointer.
+//
+// Pointers are followed until the value is not a pointer. New values are
+// allocated for each nil pointer.
+//
+// An exception to this rule is if the value satisfies an interface of interest
+// to us (like encoding.TextUnmarshaler).
+func indirect(v reflect.Value) reflect.Value {
+ if v.Kind() != reflect.Ptr {
+ if v.CanSet() {
+ pv := v.Addr()
+ pvi := pv.Interface()
+ if _, ok := pvi.(encoding.TextUnmarshaler); ok {
+ return pv
+ }
+ if _, ok := pvi.(Unmarshaler); ok {
+ return pv
+ }
+ }
+ return v
+ }
+ if v.IsNil() {
+ v.Set(reflect.New(v.Type().Elem()))
+ }
+ return indirect(reflect.Indirect(v))
+}
+
+func isUnifiable(rv reflect.Value) bool {
+ if rv.CanSet() {
+ return true
+ }
+ rvi := rv.Interface()
+ if _, ok := rvi.(encoding.TextUnmarshaler); ok {
+ return true
+ }
+ if _, ok := rvi.(Unmarshaler); ok {
+ return true
+ }
+ return false
+}
+
+// fmt %T with "interface {}" replaced with "any", which is far more readable.
+func fmtType(t any) string {
+ return strings.ReplaceAll(fmt.Sprintf("%T", t), "interface {}", "any")
+}
diff --git a/vendor/github.com/BurntSushi/toml/deprecated.go b/vendor/github.com/BurntSushi/toml/deprecated.go
new file mode 100644
index 0000000000..155709a80b
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/deprecated.go
@@ -0,0 +1,29 @@
+package toml
+
+import (
+ "encoding"
+ "io"
+)
+
+// TextMarshaler is an alias for encoding.TextMarshaler.
+//
+// Deprecated: use encoding.TextMarshaler
+type TextMarshaler encoding.TextMarshaler
+
+// TextUnmarshaler is an alias for encoding.TextUnmarshaler.
+//
+// Deprecated: use encoding.TextUnmarshaler
+type TextUnmarshaler encoding.TextUnmarshaler
+
+// DecodeReader is an alias for NewDecoder(r).Decode(v).
+//
+// Deprecated: use NewDecoder(reader).Decode(&value).
+func DecodeReader(r io.Reader, v any) (MetaData, error) { return NewDecoder(r).Decode(v) }
+
+// PrimitiveDecode is an alias for MetaData.PrimitiveDecode().
+//
+// Deprecated: use MetaData.PrimitiveDecode.
+func PrimitiveDecode(primValue Primitive, v any) error {
+ md := MetaData{decoded: make(map[string]struct{})}
+ return md.unify(primValue.undecoded, rvalue(v))
+}
diff --git a/vendor/github.com/BurntSushi/toml/doc.go b/vendor/github.com/BurntSushi/toml/doc.go
new file mode 100644
index 0000000000..82c90a9057
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/doc.go
@@ -0,0 +1,8 @@
+// Package toml implements decoding and encoding of TOML files.
+//
+// This package supports TOML v1.0.0, as specified at https://toml.io
+//
+// The github.com/BurntSushi/toml/cmd/tomlv package implements a TOML validator,
+// and can be used to verify if TOML document is valid. It can also be used to
+// print the type of each key.
+package toml
diff --git a/vendor/github.com/BurntSushi/toml/encode.go b/vendor/github.com/BurntSushi/toml/encode.go
new file mode 100644
index 0000000000..ac196e7df8
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/encode.go
@@ -0,0 +1,776 @@
+package toml
+
+import (
+ "bufio"
+ "bytes"
+ "encoding"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "math"
+ "reflect"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/BurntSushi/toml/internal"
+)
+
+type tomlEncodeError struct{ error }
+
+var (
+ errArrayNilElement = errors.New("toml: cannot encode array with nil element")
+ errNonString = errors.New("toml: cannot encode a map with non-string key type")
+ errNoKey = errors.New("toml: top-level values must be Go maps or structs")
+ errAnything = errors.New("") // used in testing
+)
+
+var dblQuotedReplacer = strings.NewReplacer(
+ "\"", "\\\"",
+ "\\", "\\\\",
+ "\x00", `\u0000`,
+ "\x01", `\u0001`,
+ "\x02", `\u0002`,
+ "\x03", `\u0003`,
+ "\x04", `\u0004`,
+ "\x05", `\u0005`,
+ "\x06", `\u0006`,
+ "\x07", `\u0007`,
+ "\b", `\b`,
+ "\t", `\t`,
+ "\n", `\n`,
+ "\x0b", `\u000b`,
+ "\f", `\f`,
+ "\r", `\r`,
+ "\x0e", `\u000e`,
+ "\x0f", `\u000f`,
+ "\x10", `\u0010`,
+ "\x11", `\u0011`,
+ "\x12", `\u0012`,
+ "\x13", `\u0013`,
+ "\x14", `\u0014`,
+ "\x15", `\u0015`,
+ "\x16", `\u0016`,
+ "\x17", `\u0017`,
+ "\x18", `\u0018`,
+ "\x19", `\u0019`,
+ "\x1a", `\u001a`,
+ "\x1b", `\u001b`,
+ "\x1c", `\u001c`,
+ "\x1d", `\u001d`,
+ "\x1e", `\u001e`,
+ "\x1f", `\u001f`,
+ "\x7f", `\u007f`,
+)
+
+var (
+ marshalToml = reflect.TypeOf((*Marshaler)(nil)).Elem()
+ marshalText = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
+ timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
+)
+
+// Marshaler is the interface implemented by types that can marshal themselves
+// into valid TOML.
+type Marshaler interface {
+ MarshalTOML() ([]byte, error)
+}
+
+// Marshal returns a TOML representation of the Go value.
+//
+// See [Encoder] for a description of the encoding process.
+func Marshal(v any) ([]byte, error) {
+ buff := new(bytes.Buffer)
+ if err := NewEncoder(buff).Encode(v); err != nil {
+ return nil, err
+ }
+ return buff.Bytes(), nil
+}
+
+// Encoder encodes a Go to a TOML document.
+//
+// The mapping between Go values and TOML values should be precisely the same as
+// for [Decode].
+//
+// time.Time is encoded as a RFC 3339 string, and time.Duration as its string
+// representation.
+//
+// The [Marshaler] and [encoding.TextMarshaler] interfaces are supported to
+// encoding the value as custom TOML.
+//
+// If you want to write arbitrary binary data then you will need to use
+// something like base64 since TOML does not have any binary types.
+//
+// When encoding TOML hashes (Go maps or structs), keys without any sub-hashes
+// are encoded first.
+//
+// Go maps will be sorted alphabetically by key for deterministic output.
+//
+// The toml struct tag can be used to provide the key name; if omitted the
+// struct field name will be used. If the "omitempty" option is present the
+// following value will be skipped:
+//
+// - arrays, slices, maps, and string with len of 0
+// - struct with all zero values
+// - bool false
+//
+// If omitzero is given all int and float types with a value of 0 will be
+// skipped.
+//
+// Encoding Go values without a corresponding TOML representation will return an
+// error. Examples of this includes maps with non-string keys, slices with nil
+// elements, embedded non-struct types, and nested slices containing maps or
+// structs. (e.g. [][]map[string]string is not allowed but []map[string]string
+// is okay, as is []map[string][]string).
+//
+// NOTE: only exported keys are encoded due to the use of reflection. Unexported
+// keys are silently discarded.
+type Encoder struct {
+ Indent string // string for a single indentation level; default is two spaces.
+ hasWritten bool // written any output to w yet?
+ w *bufio.Writer
+}
+
+// NewEncoder create a new Encoder.
+func NewEncoder(w io.Writer) *Encoder {
+ return &Encoder{w: bufio.NewWriter(w), Indent: " "}
+}
+
+// Encode writes a TOML representation of the Go value to the [Encoder]'s writer.
+//
+// An error is returned if the value given cannot be encoded to a valid TOML
+// document.
+func (enc *Encoder) Encode(v any) error {
+ rv := eindirect(reflect.ValueOf(v))
+ err := enc.safeEncode(Key([]string{}), rv)
+ if err != nil {
+ return err
+ }
+ return enc.w.Flush()
+}
+
+func (enc *Encoder) safeEncode(key Key, rv reflect.Value) (err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ if terr, ok := r.(tomlEncodeError); ok {
+ err = terr.error
+ return
+ }
+ panic(r)
+ }
+ }()
+ enc.encode(key, rv)
+ return nil
+}
+
+func (enc *Encoder) encode(key Key, rv reflect.Value) {
+ // If we can marshal the type to text, then we use that. This prevents the
+ // encoder for handling these types as generic structs (or whatever the
+ // underlying type of a TextMarshaler is).
+ switch {
+ case isMarshaler(rv):
+ enc.writeKeyValue(key, rv, false)
+ return
+ case rv.Type() == primitiveType: // TODO: #76 would make this superfluous after implemented.
+ enc.encode(key, reflect.ValueOf(rv.Interface().(Primitive).undecoded))
+ return
+ }
+
+ k := rv.Kind()
+ switch k {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
+ reflect.Int64,
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
+ reflect.Uint64,
+ reflect.Float32, reflect.Float64, reflect.String, reflect.Bool:
+ enc.writeKeyValue(key, rv, false)
+ case reflect.Array, reflect.Slice:
+ if typeEqual(tomlArrayHash, tomlTypeOfGo(rv)) {
+ enc.eArrayOfTables(key, rv)
+ } else {
+ enc.writeKeyValue(key, rv, false)
+ }
+ case reflect.Interface:
+ if rv.IsNil() {
+ return
+ }
+ enc.encode(key, rv.Elem())
+ case reflect.Map:
+ if rv.IsNil() {
+ return
+ }
+ enc.eTable(key, rv)
+ case reflect.Ptr:
+ if rv.IsNil() {
+ return
+ }
+ enc.encode(key, rv.Elem())
+ case reflect.Struct:
+ enc.eTable(key, rv)
+ default:
+ encPanic(fmt.Errorf("unsupported type for key '%s': %s", key, k))
+ }
+}
+
+// eElement encodes any value that can be an array element.
+func (enc *Encoder) eElement(rv reflect.Value) {
+ switch v := rv.Interface().(type) {
+ case time.Time: // Using TextMarshaler adds extra quotes, which we don't want.
+ format := time.RFC3339Nano
+ switch v.Location() {
+ case internal.LocalDatetime:
+ format = "2006-01-02T15:04:05.999999999"
+ case internal.LocalDate:
+ format = "2006-01-02"
+ case internal.LocalTime:
+ format = "15:04:05.999999999"
+ }
+ switch v.Location() {
+ default:
+ enc.wf(v.Format(format))
+ case internal.LocalDatetime, internal.LocalDate, internal.LocalTime:
+ enc.wf(v.In(time.UTC).Format(format))
+ }
+ return
+ case Marshaler:
+ s, err := v.MarshalTOML()
+ if err != nil {
+ encPanic(err)
+ }
+ if s == nil {
+ encPanic(errors.New("MarshalTOML returned nil and no error"))
+ }
+ enc.w.Write(s)
+ return
+ case encoding.TextMarshaler:
+ s, err := v.MarshalText()
+ if err != nil {
+ encPanic(err)
+ }
+ if s == nil {
+ encPanic(errors.New("MarshalText returned nil and no error"))
+ }
+ enc.writeQuoted(string(s))
+ return
+ case time.Duration:
+ enc.writeQuoted(v.String())
+ return
+ case json.Number:
+ n, _ := rv.Interface().(json.Number)
+
+ if n == "" { /// Useful zero value.
+ enc.w.WriteByte('0')
+ return
+ } else if v, err := n.Int64(); err == nil {
+ enc.eElement(reflect.ValueOf(v))
+ return
+ } else if v, err := n.Float64(); err == nil {
+ enc.eElement(reflect.ValueOf(v))
+ return
+ }
+ encPanic(fmt.Errorf("unable to convert %q to int64 or float64", n))
+ }
+
+ switch rv.Kind() {
+ case reflect.Ptr:
+ enc.eElement(rv.Elem())
+ return
+ case reflect.String:
+ enc.writeQuoted(rv.String())
+ case reflect.Bool:
+ enc.wf(strconv.FormatBool(rv.Bool()))
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ enc.wf(strconv.FormatInt(rv.Int(), 10))
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ enc.wf(strconv.FormatUint(rv.Uint(), 10))
+ case reflect.Float32:
+ f := rv.Float()
+ if math.IsNaN(f) {
+ if math.Signbit(f) {
+ enc.wf("-")
+ }
+ enc.wf("nan")
+ } else if math.IsInf(f, 0) {
+ if math.Signbit(f) {
+ enc.wf("-")
+ }
+ enc.wf("inf")
+ } else {
+ enc.wf(floatAddDecimal(strconv.FormatFloat(f, 'f', -1, 32)))
+ }
+ case reflect.Float64:
+ f := rv.Float()
+ if math.IsNaN(f) {
+ if math.Signbit(f) {
+ enc.wf("-")
+ }
+ enc.wf("nan")
+ } else if math.IsInf(f, 0) {
+ if math.Signbit(f) {
+ enc.wf("-")
+ }
+ enc.wf("inf")
+ } else {
+ enc.wf(floatAddDecimal(strconv.FormatFloat(f, 'f', -1, 64)))
+ }
+ case reflect.Array, reflect.Slice:
+ enc.eArrayOrSliceElement(rv)
+ case reflect.Struct:
+ enc.eStruct(nil, rv, true)
+ case reflect.Map:
+ enc.eMap(nil, rv, true)
+ case reflect.Interface:
+ enc.eElement(rv.Elem())
+ default:
+ encPanic(fmt.Errorf("unexpected type: %s", fmtType(rv.Interface())))
+ }
+}
+
+// By the TOML spec, all floats must have a decimal with at least one number on
+// either side.
+func floatAddDecimal(fstr string) string {
+ if !strings.Contains(fstr, ".") {
+ return fstr + ".0"
+ }
+ return fstr
+}
+
+func (enc *Encoder) writeQuoted(s string) {
+ enc.wf("\"%s\"", dblQuotedReplacer.Replace(s))
+}
+
+func (enc *Encoder) eArrayOrSliceElement(rv reflect.Value) {
+ length := rv.Len()
+ enc.wf("[")
+ for i := 0; i < length; i++ {
+ elem := eindirect(rv.Index(i))
+ enc.eElement(elem)
+ if i != length-1 {
+ enc.wf(", ")
+ }
+ }
+ enc.wf("]")
+}
+
+func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) {
+ if len(key) == 0 {
+ encPanic(errNoKey)
+ }
+ for i := 0; i < rv.Len(); i++ {
+ trv := eindirect(rv.Index(i))
+ if isNil(trv) {
+ continue
+ }
+ enc.newline()
+ enc.wf("%s[[%s]]", enc.indentStr(key), key)
+ enc.newline()
+ enc.eMapOrStruct(key, trv, false)
+ }
+}
+
+func (enc *Encoder) eTable(key Key, rv reflect.Value) {
+ if len(key) == 1 {
+ // Output an extra newline between top-level tables.
+ // (The newline isn't written if nothing else has been written though.)
+ enc.newline()
+ }
+ if len(key) > 0 {
+ enc.wf("%s[%s]", enc.indentStr(key), key)
+ enc.newline()
+ }
+ enc.eMapOrStruct(key, rv, false)
+}
+
+func (enc *Encoder) eMapOrStruct(key Key, rv reflect.Value, inline bool) {
+ switch rv.Kind() {
+ case reflect.Map:
+ enc.eMap(key, rv, inline)
+ case reflect.Struct:
+ enc.eStruct(key, rv, inline)
+ default:
+ // Should never happen?
+ panic("eTable: unhandled reflect.Value Kind: " + rv.Kind().String())
+ }
+}
+
+func (enc *Encoder) eMap(key Key, rv reflect.Value, inline bool) {
+ rt := rv.Type()
+ if rt.Key().Kind() != reflect.String {
+ encPanic(errNonString)
+ }
+
+ // Sort keys so that we have deterministic output. And write keys directly
+ // underneath this key first, before writing sub-structs or sub-maps.
+ var mapKeysDirect, mapKeysSub []reflect.Value
+ for _, mapKey := range rv.MapKeys() {
+ if typeIsTable(tomlTypeOfGo(eindirect(rv.MapIndex(mapKey)))) {
+ mapKeysSub = append(mapKeysSub, mapKey)
+ } else {
+ mapKeysDirect = append(mapKeysDirect, mapKey)
+ }
+ }
+
+ writeMapKeys := func(mapKeys []reflect.Value, trailC bool) {
+ sort.Slice(mapKeys, func(i, j int) bool { return mapKeys[i].String() < mapKeys[j].String() })
+ for i, mapKey := range mapKeys {
+ val := eindirect(rv.MapIndex(mapKey))
+ if isNil(val) {
+ continue
+ }
+
+ if inline {
+ enc.writeKeyValue(Key{mapKey.String()}, val, true)
+ if trailC || i != len(mapKeys)-1 {
+ enc.wf(", ")
+ }
+ } else {
+ enc.encode(key.add(mapKey.String()), val)
+ }
+ }
+ }
+
+ if inline {
+ enc.wf("{")
+ }
+ writeMapKeys(mapKeysDirect, len(mapKeysSub) > 0)
+ writeMapKeys(mapKeysSub, false)
+ if inline {
+ enc.wf("}")
+ }
+}
+
+func pointerTo(t reflect.Type) reflect.Type {
+ if t.Kind() == reflect.Ptr {
+ return pointerTo(t.Elem())
+ }
+ return t
+}
+
+func (enc *Encoder) eStruct(key Key, rv reflect.Value, inline bool) {
+ // Write keys for fields directly under this key first, because if we write
+ // a field that creates a new table then all keys under it will be in that
+ // table (not the one we're writing here).
+ //
+ // Fields is a [][]int: for fieldsDirect this always has one entry (the
+ // struct index). For fieldsSub it contains two entries: the parent field
+ // index from tv, and the field indexes for the fields of the sub.
+ var (
+ rt = rv.Type()
+ fieldsDirect, fieldsSub [][]int
+ addFields func(rt reflect.Type, rv reflect.Value, start []int)
+ )
+ addFields = func(rt reflect.Type, rv reflect.Value, start []int) {
+ for i := 0; i < rt.NumField(); i++ {
+ f := rt.Field(i)
+ isEmbed := f.Anonymous && pointerTo(f.Type).Kind() == reflect.Struct
+ if f.PkgPath != "" && !isEmbed { /// Skip unexported fields.
+ continue
+ }
+ opts := getOptions(f.Tag)
+ if opts.skip {
+ continue
+ }
+
+ frv := eindirect(rv.Field(i))
+
+ // Need to make a copy because ... ehm, I don't know why... I guess
+ // allocating a new array can cause it to fail(?)
+ //
+ // Done for: https://github.com/BurntSushi/toml/issues/430
+ // Previously only on 32bit for: https://github.com/BurntSushi/toml/issues/314
+ copyStart := make([]int, len(start))
+ copy(copyStart, start)
+ start = copyStart
+
+ // Treat anonymous struct fields with tag names as though they are
+ // not anonymous, like encoding/json does.
+ //
+ // Non-struct anonymous fields use the normal encoding logic.
+ if isEmbed {
+ if getOptions(f.Tag).name == "" && frv.Kind() == reflect.Struct {
+ addFields(frv.Type(), frv, append(start, f.Index...))
+ continue
+ }
+ }
+
+ if typeIsTable(tomlTypeOfGo(frv)) {
+ fieldsSub = append(fieldsSub, append(start, f.Index...))
+ } else {
+ fieldsDirect = append(fieldsDirect, append(start, f.Index...))
+ }
+ }
+ }
+ addFields(rt, rv, nil)
+
+ writeFields := func(fields [][]int, totalFields int) {
+ for _, fieldIndex := range fields {
+ fieldType := rt.FieldByIndex(fieldIndex)
+ fieldVal := rv.FieldByIndex(fieldIndex)
+
+ opts := getOptions(fieldType.Tag)
+ if opts.skip {
+ continue
+ }
+ if opts.omitempty && isEmpty(fieldVal) {
+ continue
+ }
+
+ fieldVal = eindirect(fieldVal)
+
+ if isNil(fieldVal) { /// Don't write anything for nil fields.
+ continue
+ }
+
+ keyName := fieldType.Name
+ if opts.name != "" {
+ keyName = opts.name
+ }
+
+ if opts.omitzero && isZero(fieldVal) {
+ continue
+ }
+
+ if inline {
+ enc.writeKeyValue(Key{keyName}, fieldVal, true)
+ if fieldIndex[0] != totalFields-1 {
+ enc.wf(", ")
+ }
+ } else {
+ enc.encode(key.add(keyName), fieldVal)
+ }
+ }
+ }
+
+ if inline {
+ enc.wf("{")
+ }
+
+ l := len(fieldsDirect) + len(fieldsSub)
+ writeFields(fieldsDirect, l)
+ writeFields(fieldsSub, l)
+ if inline {
+ enc.wf("}")
+ }
+}
+
+// tomlTypeOfGo returns the TOML type name of the Go value's type.
+//
+// It is used to determine whether the types of array elements are mixed (which
+// is forbidden). If the Go value is nil, then it is illegal for it to be an
+// array element, and valueIsNil is returned as true.
+//
+// The type may be `nil`, which means no concrete TOML type could be found.
+func tomlTypeOfGo(rv reflect.Value) tomlType {
+ if isNil(rv) || !rv.IsValid() {
+ return nil
+ }
+
+ if rv.Kind() == reflect.Struct {
+ if rv.Type() == timeType {
+ return tomlDatetime
+ }
+ if isMarshaler(rv) {
+ return tomlString
+ }
+ return tomlHash
+ }
+
+ if isMarshaler(rv) {
+ return tomlString
+ }
+
+ switch rv.Kind() {
+ case reflect.Bool:
+ return tomlBool
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
+ reflect.Int64,
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
+ reflect.Uint64:
+ return tomlInteger
+ case reflect.Float32, reflect.Float64:
+ return tomlFloat
+ case reflect.Array, reflect.Slice:
+ if isTableArray(rv) {
+ return tomlArrayHash
+ }
+ return tomlArray
+ case reflect.Ptr, reflect.Interface:
+ return tomlTypeOfGo(rv.Elem())
+ case reflect.String:
+ return tomlString
+ case reflect.Map:
+ return tomlHash
+ default:
+ encPanic(errors.New("unsupported type: " + rv.Kind().String()))
+ panic("unreachable")
+ }
+}
+
+func isMarshaler(rv reflect.Value) bool {
+ return rv.Type().Implements(marshalText) || rv.Type().Implements(marshalToml)
+}
+
+// isTableArray reports if all entries in the array or slice are a table.
+func isTableArray(arr reflect.Value) bool {
+ if isNil(arr) || !arr.IsValid() || arr.Len() == 0 {
+ return false
+ }
+
+ ret := true
+ for i := 0; i < arr.Len(); i++ {
+ tt := tomlTypeOfGo(eindirect(arr.Index(i)))
+ // Don't allow nil.
+ if tt == nil {
+ encPanic(errArrayNilElement)
+ }
+
+ if ret && !typeEqual(tomlHash, tt) {
+ ret = false
+ }
+ }
+ return ret
+}
+
+type tagOptions struct {
+ skip bool // "-"
+ name string
+ omitempty bool
+ omitzero bool
+}
+
+func getOptions(tag reflect.StructTag) tagOptions {
+ t := tag.Get("toml")
+ if t == "-" {
+ return tagOptions{skip: true}
+ }
+ var opts tagOptions
+ parts := strings.Split(t, ",")
+ opts.name = parts[0]
+ for _, s := range parts[1:] {
+ switch s {
+ case "omitempty":
+ opts.omitempty = true
+ case "omitzero":
+ opts.omitzero = true
+ }
+ }
+ return opts
+}
+
+func isZero(rv reflect.Value) bool {
+ switch rv.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return rv.Int() == 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ return rv.Uint() == 0
+ case reflect.Float32, reflect.Float64:
+ return rv.Float() == 0.0
+ }
+ return false
+}
+
+func isEmpty(rv reflect.Value) bool {
+ switch rv.Kind() {
+ case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
+ return rv.Len() == 0
+ case reflect.Struct:
+ if rv.Type().Comparable() {
+ return reflect.Zero(rv.Type()).Interface() == rv.Interface()
+ }
+ // Need to also check if all the fields are empty, otherwise something
+ // like this with uncomparable types will always return true:
+ //
+ // type a struct{ field b }
+ // type b struct{ s []string }
+ // s := a{field: b{s: []string{"AAA"}}}
+ for i := 0; i < rv.NumField(); i++ {
+ if !isEmpty(rv.Field(i)) {
+ return false
+ }
+ }
+ return true
+ case reflect.Bool:
+ return !rv.Bool()
+ case reflect.Ptr:
+ return rv.IsNil()
+ }
+ return false
+}
+
+func (enc *Encoder) newline() {
+ if enc.hasWritten {
+ enc.wf("\n")
+ }
+}
+
+// Write a key/value pair:
+//
+// key =
+//
+// This is also used for "k = v" in inline tables; so something like this will
+// be written in three calls:
+//
+// ┌───────────────────â”
+// │ ┌───┠┌────â”│
+// v v v v vv
+// key = {k = 1, k2 = 2}
+func (enc *Encoder) writeKeyValue(key Key, val reflect.Value, inline bool) {
+ /// Marshaler used on top-level document; call eElement() to just call
+ /// Marshal{TOML,Text}.
+ if len(key) == 0 {
+ enc.eElement(val)
+ return
+ }
+ enc.wf("%s%s = ", enc.indentStr(key), key.maybeQuoted(len(key)-1))
+ enc.eElement(val)
+ if !inline {
+ enc.newline()
+ }
+}
+
+func (enc *Encoder) wf(format string, v ...any) {
+ _, err := fmt.Fprintf(enc.w, format, v...)
+ if err != nil {
+ encPanic(err)
+ }
+ enc.hasWritten = true
+}
+
+func (enc *Encoder) indentStr(key Key) string {
+ return strings.Repeat(enc.Indent, len(key)-1)
+}
+
+func encPanic(err error) {
+ panic(tomlEncodeError{err})
+}
+
+// Resolve any level of pointers to the actual value (e.g. **string → string).
+func eindirect(v reflect.Value) reflect.Value {
+ if v.Kind() != reflect.Ptr && v.Kind() != reflect.Interface {
+ if isMarshaler(v) {
+ return v
+ }
+ if v.CanAddr() { /// Special case for marshalers; see #358.
+ if pv := v.Addr(); isMarshaler(pv) {
+ return pv
+ }
+ }
+ return v
+ }
+
+ if v.IsNil() {
+ return v
+ }
+
+ return eindirect(v.Elem())
+}
+
+func isNil(rv reflect.Value) bool {
+ switch rv.Kind() {
+ case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
+ return rv.IsNil()
+ default:
+ return false
+ }
+}
diff --git a/vendor/github.com/BurntSushi/toml/error.go b/vendor/github.com/BurntSushi/toml/error.go
new file mode 100644
index 0000000000..b7077d3ae3
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/error.go
@@ -0,0 +1,347 @@
+package toml
+
+import (
+ "fmt"
+ "strings"
+)
+
+// ParseError is returned when there is an error parsing the TOML syntax such as
+// invalid syntax, duplicate keys, etc.
+//
+// In addition to the error message itself, you can also print detailed location
+// information with context by using [ErrorWithPosition]:
+//
+// toml: error: Key 'fruit' was already created and cannot be used as an array.
+//
+// At line 4, column 2-7:
+//
+// 2 | fruit = []
+// 3 |
+// 4 | [[fruit]] # Not allowed
+// ^^^^^
+//
+// [ErrorWithUsage] can be used to print the above with some more detailed usage
+// guidance:
+//
+// toml: error: newlines not allowed within inline tables
+//
+// At line 1, column 18:
+//
+// 1 | x = [{ key = 42 #
+// ^
+//
+// Error help:
+//
+// Inline tables must always be on a single line:
+//
+// table = {key = 42, second = 43}
+//
+// It is invalid to split them over multiple lines like so:
+//
+// # INVALID
+// table = {
+// key = 42,
+// second = 43
+// }
+//
+// Use regular for this:
+//
+// [table]
+// key = 42
+// second = 43
+type ParseError struct {
+ Message string // Short technical message.
+ Usage string // Longer message with usage guidance; may be blank.
+ Position Position // Position of the error
+ LastKey string // Last parsed key, may be blank.
+
+ // Line the error occurred.
+ //
+ // Deprecated: use [Position].
+ Line int
+
+ err error
+ input string
+}
+
+// Position of an error.
+type Position struct {
+ Line int // Line number, starting at 1.
+ Col int // Error column, starting at 1.
+ Start int // Start of error, as byte offset starting at 0.
+ Len int // Length of the error in bytes.
+}
+
+func (p Position) withCol(tomlFile string) Position {
+ var (
+ pos int
+ lines = strings.Split(tomlFile, "\n")
+ )
+ for i := range lines {
+ ll := len(lines[i]) + 1 // +1 for the removed newline
+ if pos+ll >= p.Start {
+ p.Col = p.Start - pos + 1
+ if p.Col < 1 { // Should never happen, but just in case.
+ p.Col = 1
+ }
+ break
+ }
+ pos += ll
+ }
+ return p
+}
+
+func (pe ParseError) Error() string {
+ if pe.LastKey == "" {
+ return fmt.Sprintf("toml: line %d: %s", pe.Position.Line, pe.Message)
+ }
+ return fmt.Sprintf("toml: line %d (last key %q): %s",
+ pe.Position.Line, pe.LastKey, pe.Message)
+}
+
+// ErrorWithPosition returns the error with detailed location context.
+//
+// See the documentation on [ParseError].
+func (pe ParseError) ErrorWithPosition() string {
+ if pe.input == "" { // Should never happen, but just in case.
+ return pe.Error()
+ }
+
+ // TODO: don't show control characters as literals? This may not show up
+ // well everywhere.
+
+ var (
+ lines = strings.Split(pe.input, "\n")
+ b = new(strings.Builder)
+ )
+ if pe.Position.Len == 1 {
+ fmt.Fprintf(b, "toml: error: %s\n\nAt line %d, column %d:\n\n",
+ pe.Message, pe.Position.Line, pe.Position.Col)
+ } else {
+ fmt.Fprintf(b, "toml: error: %s\n\nAt line %d, column %d-%d:\n\n",
+ pe.Message, pe.Position.Line, pe.Position.Col, pe.Position.Col+pe.Position.Len-1)
+ }
+ if pe.Position.Line > 2 {
+ fmt.Fprintf(b, "% 7d | %s\n", pe.Position.Line-2, expandTab(lines[pe.Position.Line-3]))
+ }
+ if pe.Position.Line > 1 {
+ fmt.Fprintf(b, "% 7d | %s\n", pe.Position.Line-1, expandTab(lines[pe.Position.Line-2]))
+ }
+
+ /// Expand tabs, so that the ^^^s are at the correct position, but leave
+ /// "column 10-13" intact. Adjusting this to the visual column would be
+ /// better, but we don't know the tabsize of the user in their editor, which
+ /// can be 8, 4, 2, or something else. We can't know. So leaving it as the
+ /// character index is probably the "most correct".
+ expanded := expandTab(lines[pe.Position.Line-1])
+ diff := len(expanded) - len(lines[pe.Position.Line-1])
+
+ fmt.Fprintf(b, "% 7d | %s\n", pe.Position.Line, expanded)
+ fmt.Fprintf(b, "% 10s%s%s\n", "", strings.Repeat(" ", pe.Position.Col-1+diff), strings.Repeat("^", pe.Position.Len))
+ return b.String()
+}
+
+// ErrorWithUsage returns the error with detailed location context and usage
+// guidance.
+//
+// See the documentation on [ParseError].
+func (pe ParseError) ErrorWithUsage() string {
+ m := pe.ErrorWithPosition()
+ if u, ok := pe.err.(interface{ Usage() string }); ok && u.Usage() != "" {
+ lines := strings.Split(strings.TrimSpace(u.Usage()), "\n")
+ for i := range lines {
+ if lines[i] != "" {
+ lines[i] = " " + lines[i]
+ }
+ }
+ return m + "Error help:\n\n" + strings.Join(lines, "\n") + "\n"
+ }
+ return m
+}
+
+func expandTab(s string) string {
+ var (
+ b strings.Builder
+ l int
+ fill = func(n int) string {
+ b := make([]byte, n)
+ for i := range b {
+ b[i] = ' '
+ }
+ return string(b)
+ }
+ )
+ b.Grow(len(s))
+ for _, r := range s {
+ switch r {
+ case '\t':
+ tw := 8 - l%8
+ b.WriteString(fill(tw))
+ l += tw
+ default:
+ b.WriteRune(r)
+ l += 1
+ }
+ }
+ return b.String()
+}
+
+type (
+ errLexControl struct{ r rune }
+ errLexEscape struct{ r rune }
+ errLexUTF8 struct{ b byte }
+ errParseDate struct{ v string }
+ errLexInlineTableNL struct{}
+ errLexStringNL struct{}
+ errParseRange struct {
+ i any // int or float
+ size string // "int64", "uint16", etc.
+ }
+ errUnsafeFloat struct {
+ i interface{} // float32 or float64
+ size string // "float32" or "float64"
+ }
+ errParseDuration struct{ d string }
+)
+
+func (e errLexControl) Error() string {
+ return fmt.Sprintf("TOML files cannot contain control characters: '0x%02x'", e.r)
+}
+func (e errLexControl) Usage() string { return "" }
+
+func (e errLexEscape) Error() string { return fmt.Sprintf(`invalid escape in string '\%c'`, e.r) }
+func (e errLexEscape) Usage() string { return usageEscape }
+func (e errLexUTF8) Error() string { return fmt.Sprintf("invalid UTF-8 byte: 0x%02x", e.b) }
+func (e errLexUTF8) Usage() string { return "" }
+func (e errParseDate) Error() string { return fmt.Sprintf("invalid datetime: %q", e.v) }
+func (e errParseDate) Usage() string { return usageDate }
+func (e errLexInlineTableNL) Error() string { return "newlines not allowed within inline tables" }
+func (e errLexInlineTableNL) Usage() string { return usageInlineNewline }
+func (e errLexStringNL) Error() string { return "strings cannot contain newlines" }
+func (e errLexStringNL) Usage() string { return usageStringNewline }
+func (e errParseRange) Error() string { return fmt.Sprintf("%v is out of range for %s", e.i, e.size) }
+func (e errParseRange) Usage() string { return usageIntOverflow }
+func (e errUnsafeFloat) Error() string {
+ return fmt.Sprintf("%v is out of the safe %s range", e.i, e.size)
+}
+func (e errUnsafeFloat) Usage() string { return usageUnsafeFloat }
+func (e errParseDuration) Error() string { return fmt.Sprintf("invalid duration: %q", e.d) }
+func (e errParseDuration) Usage() string { return usageDuration }
+
+const usageEscape = `
+A '\' inside a "-delimited string is interpreted as an escape character.
+
+The following escape sequences are supported:
+\b, \t, \n, \f, \r, \", \\, \uXXXX, and \UXXXXXXXX
+
+To prevent a '\' from being recognized as an escape character, use either:
+
+- a ' or '''-delimited string; escape characters aren't processed in them; or
+- write two backslashes to get a single backslash: '\\'.
+
+If you're trying to add a Windows path (e.g. "C:\Users\martin") then using '/'
+instead of '\' will usually also work: "C:/Users/martin".
+`
+
+const usageInlineNewline = `
+Inline tables must always be on a single line:
+
+ table = {key = 42, second = 43}
+
+It is invalid to split them over multiple lines like so:
+
+ # INVALID
+ table = {
+ key = 42,
+ second = 43
+ }
+
+Use regular for this:
+
+ [table]
+ key = 42
+ second = 43
+`
+
+const usageStringNewline = `
+Strings must always be on a single line, and cannot span more than one line:
+
+ # INVALID
+ string = "Hello,
+ world!"
+
+Instead use """ or ''' to split strings over multiple lines:
+
+ string = """Hello,
+ world!"""
+`
+
+const usageIntOverflow = `
+This number is too large; this may be an error in the TOML, but it can also be a
+bug in the program that uses too small of an integer.
+
+The maximum and minimum values are:
+
+ size │ lowest │ highest
+ ───────┼────────────────┼──────────────
+ int8 │ -128 │ 127
+ int16 │ -32,768 │ 32,767
+ int32 │ -2,147,483,648 │ 2,147,483,647
+ int64 │ -9.2 × 10¹ⷠ│ 9.2 × 10¹â·
+ uint8 │ 0 │ 255
+ uint16 │ 0 │ 65,535
+ uint32 │ 0 │ 4,294,967,295
+ uint64 │ 0 │ 1.8 × 10¹â¸
+
+int refers to int32 on 32-bit systems and int64 on 64-bit systems.
+`
+
+const usageUnsafeFloat = `
+This number is outside of the "safe" range for floating point numbers; whole
+(non-fractional) numbers outside the below range can not always be represented
+accurately in a float, leading to some loss of accuracy.
+
+Explicitly mark a number as a fractional unit by adding ".0", which will incur
+some loss of accuracy; for example:
+
+ f = 2_000_000_000.0
+
+Accuracy ranges:
+
+ float32 = 16,777,215
+ float64 = 9,007,199,254,740,991
+`
+
+const usageDuration = `
+A duration must be as "number", without any spaces. Valid units are:
+
+ ns nanoseconds (billionth of a second)
+ us, µs microseconds (millionth of a second)
+ ms milliseconds (thousands of a second)
+ s seconds
+ m minutes
+ h hours
+
+You can combine multiple units; for example "5m10s" for 5 minutes and 10
+seconds.
+`
+
+const usageDate = `
+A TOML datetime must be in one of the following formats:
+
+ 2006-01-02T15:04:05Z07:00 Date and time, with timezone.
+ 2006-01-02T15:04:05 Date and time, but without timezone.
+ 2006-01-02 Date without a time or timezone.
+ 15:04:05 Just a time, without any timezone.
+
+Seconds may optionally have a fraction, up to nanosecond precision:
+
+ 15:04:05.123
+ 15:04:05.856018510
+`
+
+// TOML 1.1:
+// The seconds part in times is optional, and may be omitted:
+// 2006-01-02T15:04Z07:00
+// 2006-01-02T15:04
+// 15:04
diff --git a/vendor/github.com/BurntSushi/toml/internal/tz.go b/vendor/github.com/BurntSushi/toml/internal/tz.go
new file mode 100644
index 0000000000..022f15bc2b
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/internal/tz.go
@@ -0,0 +1,36 @@
+package internal
+
+import "time"
+
+// Timezones used for local datetime, date, and time TOML types.
+//
+// The exact way times and dates without a timezone should be interpreted is not
+// well-defined in the TOML specification and left to the implementation. These
+// defaults to current local timezone offset of the computer, but this can be
+// changed by changing these variables before decoding.
+//
+// TODO:
+// Ideally we'd like to offer people the ability to configure the used timezone
+// by setting Decoder.Timezone and Encoder.Timezone; however, this is a bit
+// tricky: the reason we use three different variables for this is to support
+// round-tripping – without these specific TZ names we wouldn't know which
+// format to use.
+//
+// There isn't a good way to encode this right now though, and passing this sort
+// of information also ties in to various related issues such as string format
+// encoding, encoding of comments, etc.
+//
+// So, for the time being, just put this in internal until we can write a good
+// comprehensive API for doing all of this.
+//
+// The reason they're exported is because they're referred from in e.g.
+// internal/tag.
+//
+// Note that this behaviour is valid according to the TOML spec as the exact
+// behaviour is left up to implementations.
+var (
+ localOffset = func() int { _, o := time.Now().Zone(); return o }()
+ LocalDatetime = time.FixedZone("datetime-local", localOffset)
+ LocalDate = time.FixedZone("date-local", localOffset)
+ LocalTime = time.FixedZone("time-local", localOffset)
+)
diff --git a/vendor/github.com/BurntSushi/toml/lex.go b/vendor/github.com/BurntSushi/toml/lex.go
new file mode 100644
index 0000000000..1c3b477029
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/lex.go
@@ -0,0 +1,1272 @@
+package toml
+
+import (
+ "fmt"
+ "reflect"
+ "runtime"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+type itemType int
+
+const (
+ itemError itemType = iota
+ itemNIL // used in the parser to indicate no type
+ itemEOF
+ itemText
+ itemString
+ itemStringEsc
+ itemRawString
+ itemMultilineString
+ itemRawMultilineString
+ itemBool
+ itemInteger
+ itemFloat
+ itemDatetime
+ itemArray // the start of an array
+ itemArrayEnd
+ itemTableStart
+ itemTableEnd
+ itemArrayTableStart
+ itemArrayTableEnd
+ itemKeyStart
+ itemKeyEnd
+ itemCommentStart
+ itemInlineTableStart
+ itemInlineTableEnd
+)
+
+const eof = 0
+
+type stateFn func(lx *lexer) stateFn
+
+func (p Position) String() string {
+ return fmt.Sprintf("at line %d; start %d; length %d", p.Line, p.Start, p.Len)
+}
+
+type lexer struct {
+ input string
+ start int
+ pos int
+ line int
+ state stateFn
+ items chan item
+ tomlNext bool
+ esc bool
+
+ // Allow for backing up up to 4 runes. This is necessary because TOML
+ // contains 3-rune tokens (""" and ''').
+ prevWidths [4]int
+ nprev int // how many of prevWidths are in use
+ atEOF bool // If we emit an eof, we can still back up, but it is not OK to call next again.
+
+ // A stack of state functions used to maintain context.
+ //
+ // The idea is to reuse parts of the state machine in various places. For
+ // example, values can appear at the top level or within arbitrarily nested
+ // arrays. The last state on the stack is used after a value has been lexed.
+ // Similarly for comments.
+ stack []stateFn
+}
+
+type item struct {
+ typ itemType
+ val string
+ err error
+ pos Position
+}
+
+func (lx *lexer) nextItem() item {
+ for {
+ select {
+ case item := <-lx.items:
+ return item
+ default:
+ lx.state = lx.state(lx)
+ //fmt.Printf(" STATE %-24s current: %-10s stack: %s\n", lx.state, lx.current(), lx.stack)
+ }
+ }
+}
+
+func lex(input string, tomlNext bool) *lexer {
+ lx := &lexer{
+ input: input,
+ state: lexTop,
+ items: make(chan item, 10),
+ stack: make([]stateFn, 0, 10),
+ line: 1,
+ tomlNext: tomlNext,
+ }
+ return lx
+}
+
+func (lx *lexer) push(state stateFn) {
+ lx.stack = append(lx.stack, state)
+}
+
+func (lx *lexer) pop() stateFn {
+ if len(lx.stack) == 0 {
+ return lx.errorf("BUG in lexer: no states to pop")
+ }
+ last := lx.stack[len(lx.stack)-1]
+ lx.stack = lx.stack[0 : len(lx.stack)-1]
+ return last
+}
+
+func (lx *lexer) current() string {
+ return lx.input[lx.start:lx.pos]
+}
+
+func (lx lexer) getPos() Position {
+ p := Position{
+ Line: lx.line,
+ Start: lx.start,
+ Len: lx.pos - lx.start,
+ }
+ if p.Len <= 0 {
+ p.Len = 1
+ }
+ return p
+}
+
+func (lx *lexer) emit(typ itemType) {
+ // Needed for multiline strings ending with an incomplete UTF-8 sequence.
+ if lx.start > lx.pos {
+ lx.error(errLexUTF8{lx.input[lx.pos]})
+ return
+ }
+ lx.items <- item{typ: typ, pos: lx.getPos(), val: lx.current()}
+ lx.start = lx.pos
+}
+
+func (lx *lexer) emitTrim(typ itemType) {
+ lx.items <- item{typ: typ, pos: lx.getPos(), val: strings.TrimSpace(lx.current())}
+ lx.start = lx.pos
+}
+
+func (lx *lexer) next() (r rune) {
+ if lx.atEOF {
+ panic("BUG in lexer: next called after EOF")
+ }
+ if lx.pos >= len(lx.input) {
+ lx.atEOF = true
+ return eof
+ }
+
+ if lx.input[lx.pos] == '\n' {
+ lx.line++
+ }
+ lx.prevWidths[3] = lx.prevWidths[2]
+ lx.prevWidths[2] = lx.prevWidths[1]
+ lx.prevWidths[1] = lx.prevWidths[0]
+ if lx.nprev < 4 {
+ lx.nprev++
+ }
+
+ r, w := utf8.DecodeRuneInString(lx.input[lx.pos:])
+ if r == utf8.RuneError && w == 1 {
+ lx.error(errLexUTF8{lx.input[lx.pos]})
+ return utf8.RuneError
+ }
+
+ // Note: don't use peek() here, as this calls next().
+ if isControl(r) || (r == '\r' && (len(lx.input)-1 == lx.pos || lx.input[lx.pos+1] != '\n')) {
+ lx.errorControlChar(r)
+ return utf8.RuneError
+ }
+
+ lx.prevWidths[0] = w
+ lx.pos += w
+ return r
+}
+
+// ignore skips over the pending input before this point.
+func (lx *lexer) ignore() {
+ lx.start = lx.pos
+}
+
+// backup steps back one rune. Can be called 4 times between calls to next.
+func (lx *lexer) backup() {
+ if lx.atEOF {
+ lx.atEOF = false
+ return
+ }
+ if lx.nprev < 1 {
+ panic("BUG in lexer: backed up too far")
+ }
+ w := lx.prevWidths[0]
+ lx.prevWidths[0] = lx.prevWidths[1]
+ lx.prevWidths[1] = lx.prevWidths[2]
+ lx.prevWidths[2] = lx.prevWidths[3]
+ lx.nprev--
+
+ lx.pos -= w
+ if lx.pos < len(lx.input) && lx.input[lx.pos] == '\n' {
+ lx.line--
+ }
+}
+
+// accept consumes the next rune if it's equal to `valid`.
+func (lx *lexer) accept(valid rune) bool {
+ if lx.next() == valid {
+ return true
+ }
+ lx.backup()
+ return false
+}
+
+// peek returns but does not consume the next rune in the input.
+func (lx *lexer) peek() rune {
+ r := lx.next()
+ lx.backup()
+ return r
+}
+
+// skip ignores all input that matches the given predicate.
+func (lx *lexer) skip(pred func(rune) bool) {
+ for {
+ r := lx.next()
+ if pred(r) {
+ continue
+ }
+ lx.backup()
+ lx.ignore()
+ return
+ }
+}
+
+// error stops all lexing by emitting an error and returning `nil`.
+//
+// Note that any value that is a character is escaped if it's a special
+// character (newlines, tabs, etc.).
+func (lx *lexer) error(err error) stateFn {
+ if lx.atEOF {
+ return lx.errorPrevLine(err)
+ }
+ lx.items <- item{typ: itemError, pos: lx.getPos(), err: err}
+ return nil
+}
+
+// errorfPrevline is like error(), but sets the position to the last column of
+// the previous line.
+//
+// This is so that unexpected EOF or NL errors don't show on a new blank line.
+func (lx *lexer) errorPrevLine(err error) stateFn {
+ pos := lx.getPos()
+ pos.Line--
+ pos.Len = 1
+ pos.Start = lx.pos - 1
+ lx.items <- item{typ: itemError, pos: pos, err: err}
+ return nil
+}
+
+// errorPos is like error(), but allows explicitly setting the position.
+func (lx *lexer) errorPos(start, length int, err error) stateFn {
+ pos := lx.getPos()
+ pos.Start = start
+ pos.Len = length
+ lx.items <- item{typ: itemError, pos: pos, err: err}
+ return nil
+}
+
+// errorf is like error, and creates a new error.
+func (lx *lexer) errorf(format string, values ...any) stateFn {
+ if lx.atEOF {
+ pos := lx.getPos()
+ if lx.pos >= 1 && lx.input[lx.pos-1] == '\n' {
+ pos.Line--
+ }
+ pos.Len = 1
+ pos.Start = lx.pos - 1
+ lx.items <- item{typ: itemError, pos: pos, err: fmt.Errorf(format, values...)}
+ return nil
+ }
+ lx.items <- item{typ: itemError, pos: lx.getPos(), err: fmt.Errorf(format, values...)}
+ return nil
+}
+
+func (lx *lexer) errorControlChar(cc rune) stateFn {
+ return lx.errorPos(lx.pos-1, 1, errLexControl{cc})
+}
+
+// lexTop consumes elements at the top level of TOML data.
+func lexTop(lx *lexer) stateFn {
+ r := lx.next()
+ if isWhitespace(r) || isNL(r) {
+ return lexSkip(lx, lexTop)
+ }
+ switch r {
+ case '#':
+ lx.push(lexTop)
+ return lexCommentStart
+ case '[':
+ return lexTableStart
+ case eof:
+ if lx.pos > lx.start {
+ return lx.errorf("unexpected EOF")
+ }
+ lx.emit(itemEOF)
+ return nil
+ }
+
+ // At this point, the only valid item can be a key, so we back up
+ // and let the key lexer do the rest.
+ lx.backup()
+ lx.push(lexTopEnd)
+ return lexKeyStart
+}
+
+// lexTopEnd is entered whenever a top-level item has been consumed. (A value
+// or a table.) It must see only whitespace, and will turn back to lexTop
+// upon a newline. If it sees EOF, it will quit the lexer successfully.
+func lexTopEnd(lx *lexer) stateFn {
+ r := lx.next()
+ switch {
+ case r == '#':
+ // a comment will read to a newline for us.
+ lx.push(lexTop)
+ return lexCommentStart
+ case isWhitespace(r):
+ return lexTopEnd
+ case isNL(r):
+ lx.ignore()
+ return lexTop
+ case r == eof:
+ lx.emit(itemEOF)
+ return nil
+ }
+ return lx.errorf("expected a top-level item to end with a newline, comment, or EOF, but got %q instead", r)
+}
+
+// lexTable lexes the beginning of a table. Namely, it makes sure that
+// it starts with a character other than '.' and ']'.
+// It assumes that '[' has already been consumed.
+// It also handles the case that this is an item in an array of tables.
+// e.g., '[[name]]'.
+func lexTableStart(lx *lexer) stateFn {
+ if lx.peek() == '[' {
+ lx.next()
+ lx.emit(itemArrayTableStart)
+ lx.push(lexArrayTableEnd)
+ } else {
+ lx.emit(itemTableStart)
+ lx.push(lexTableEnd)
+ }
+ return lexTableNameStart
+}
+
+func lexTableEnd(lx *lexer) stateFn {
+ lx.emit(itemTableEnd)
+ return lexTopEnd
+}
+
+func lexArrayTableEnd(lx *lexer) stateFn {
+ if r := lx.next(); r != ']' {
+ return lx.errorf("expected end of table array name delimiter ']', but got %q instead", r)
+ }
+ lx.emit(itemArrayTableEnd)
+ return lexTopEnd
+}
+
+func lexTableNameStart(lx *lexer) stateFn {
+ lx.skip(isWhitespace)
+ switch r := lx.peek(); {
+ case r == ']' || r == eof:
+ return lx.errorf("unexpected end of table name (table names cannot be empty)")
+ case r == '.':
+ return lx.errorf("unexpected table separator (table names cannot be empty)")
+ case r == '"' || r == '\'':
+ lx.ignore()
+ lx.push(lexTableNameEnd)
+ return lexQuotedName
+ default:
+ lx.push(lexTableNameEnd)
+ return lexBareName
+ }
+}
+
+// lexTableNameEnd reads the end of a piece of a table name, optionally
+// consuming whitespace.
+func lexTableNameEnd(lx *lexer) stateFn {
+ lx.skip(isWhitespace)
+ switch r := lx.next(); {
+ case isWhitespace(r):
+ return lexTableNameEnd
+ case r == '.':
+ lx.ignore()
+ return lexTableNameStart
+ case r == ']':
+ return lx.pop()
+ default:
+ return lx.errorf("expected '.' or ']' to end table name, but got %q instead", r)
+ }
+}
+
+// lexBareName lexes one part of a key or table.
+//
+// It assumes that at least one valid character for the table has already been
+// read.
+//
+// Lexes only one part, e.g. only 'a' inside 'a.b'.
+func lexBareName(lx *lexer) stateFn {
+ r := lx.next()
+ if isBareKeyChar(r, lx.tomlNext) {
+ return lexBareName
+ }
+ lx.backup()
+ lx.emit(itemText)
+ return lx.pop()
+}
+
+// lexBareName lexes one part of a key or table.
+//
+// It assumes that at least one valid character for the table has already been
+// read.
+//
+// Lexes only one part, e.g. only '"a"' inside '"a".b'.
+func lexQuotedName(lx *lexer) stateFn {
+ r := lx.next()
+ switch {
+ case isWhitespace(r):
+ return lexSkip(lx, lexValue)
+ case r == '"':
+ lx.ignore() // ignore the '"'
+ return lexString
+ case r == '\'':
+ lx.ignore() // ignore the "'"
+ return lexRawString
+ case r == eof:
+ return lx.errorf("unexpected EOF; expected value")
+ default:
+ return lx.errorf("expected value but found %q instead", r)
+ }
+}
+
+// lexKeyStart consumes all key parts until a '='.
+func lexKeyStart(lx *lexer) stateFn {
+ lx.skip(isWhitespace)
+ switch r := lx.peek(); {
+ case r == '=' || r == eof:
+ return lx.errorf("unexpected '=': key name appears blank")
+ case r == '.':
+ return lx.errorf("unexpected '.': keys cannot start with a '.'")
+ case r == '"' || r == '\'':
+ lx.ignore()
+ fallthrough
+ default: // Bare key
+ lx.emit(itemKeyStart)
+ return lexKeyNameStart
+ }
+}
+
+func lexKeyNameStart(lx *lexer) stateFn {
+ lx.skip(isWhitespace)
+ switch r := lx.peek(); {
+ case r == '=' || r == eof:
+ return lx.errorf("unexpected '='")
+ case r == '.':
+ return lx.errorf("unexpected '.'")
+ case r == '"' || r == '\'':
+ lx.ignore()
+ lx.push(lexKeyEnd)
+ return lexQuotedName
+ default:
+ lx.push(lexKeyEnd)
+ return lexBareName
+ }
+}
+
+// lexKeyEnd consumes the end of a key and trims whitespace (up to the key
+// separator).
+func lexKeyEnd(lx *lexer) stateFn {
+ lx.skip(isWhitespace)
+ switch r := lx.next(); {
+ case isWhitespace(r):
+ return lexSkip(lx, lexKeyEnd)
+ case r == eof:
+ return lx.errorf("unexpected EOF; expected key separator '='")
+ case r == '.':
+ lx.ignore()
+ return lexKeyNameStart
+ case r == '=':
+ lx.emit(itemKeyEnd)
+ return lexSkip(lx, lexValue)
+ default:
+ if r == '\n' {
+ return lx.errorPrevLine(fmt.Errorf("expected '.' or '=', but got %q instead", r))
+ }
+ return lx.errorf("expected '.' or '=', but got %q instead", r)
+ }
+}
+
+// lexValue starts the consumption of a value anywhere a value is expected.
+// lexValue will ignore whitespace.
+// After a value is lexed, the last state on the next is popped and returned.
+func lexValue(lx *lexer) stateFn {
+ // We allow whitespace to precede a value, but NOT newlines.
+ // In array syntax, the array states are responsible for ignoring newlines.
+ r := lx.next()
+ switch {
+ case isWhitespace(r):
+ return lexSkip(lx, lexValue)
+ case isDigit(r):
+ lx.backup() // avoid an extra state and use the same as above
+ return lexNumberOrDateStart
+ }
+ switch r {
+ case '[':
+ lx.ignore()
+ lx.emit(itemArray)
+ return lexArrayValue
+ case '{':
+ lx.ignore()
+ lx.emit(itemInlineTableStart)
+ return lexInlineTableValue
+ case '"':
+ if lx.accept('"') {
+ if lx.accept('"') {
+ lx.ignore() // Ignore """
+ return lexMultilineString
+ }
+ lx.backup()
+ }
+ lx.ignore() // ignore the '"'
+ return lexString
+ case '\'':
+ if lx.accept('\'') {
+ if lx.accept('\'') {
+ lx.ignore() // Ignore """
+ return lexMultilineRawString
+ }
+ lx.backup()
+ }
+ lx.ignore() // ignore the "'"
+ return lexRawString
+ case '.': // special error case, be kind to users
+ return lx.errorf("floats must start with a digit, not '.'")
+ case 'i', 'n':
+ if (lx.accept('n') && lx.accept('f')) || (lx.accept('a') && lx.accept('n')) {
+ lx.emit(itemFloat)
+ return lx.pop()
+ }
+ case '-', '+':
+ return lexDecimalNumberStart
+ }
+ if unicode.IsLetter(r) {
+ // Be permissive here; lexBool will give a nice error if the
+ // user wrote something like
+ // x = foo
+ // (i.e. not 'true' or 'false' but is something else word-like.)
+ lx.backup()
+ return lexBool
+ }
+ if r == eof {
+ return lx.errorf("unexpected EOF; expected value")
+ }
+ if r == '\n' {
+ return lx.errorPrevLine(fmt.Errorf("expected value but found %q instead", r))
+ }
+ return lx.errorf("expected value but found %q instead", r)
+}
+
+// lexArrayValue consumes one value in an array. It assumes that '[' or ','
+// have already been consumed. All whitespace and newlines are ignored.
+func lexArrayValue(lx *lexer) stateFn {
+ r := lx.next()
+ switch {
+ case isWhitespace(r) || isNL(r):
+ return lexSkip(lx, lexArrayValue)
+ case r == '#':
+ lx.push(lexArrayValue)
+ return lexCommentStart
+ case r == ',':
+ return lx.errorf("unexpected comma")
+ case r == ']':
+ return lexArrayEnd
+ }
+
+ lx.backup()
+ lx.push(lexArrayValueEnd)
+ return lexValue
+}
+
+// lexArrayValueEnd consumes everything between the end of an array value and
+// the next value (or the end of the array): it ignores whitespace and newlines
+// and expects either a ',' or a ']'.
+func lexArrayValueEnd(lx *lexer) stateFn {
+ switch r := lx.next(); {
+ case isWhitespace(r) || isNL(r):
+ return lexSkip(lx, lexArrayValueEnd)
+ case r == '#':
+ lx.push(lexArrayValueEnd)
+ return lexCommentStart
+ case r == ',':
+ lx.ignore()
+ return lexArrayValue // move on to the next value
+ case r == ']':
+ return lexArrayEnd
+ default:
+ return lx.errorf("expected a comma (',') or array terminator (']'), but got %s", runeOrEOF(r))
+ }
+}
+
+// lexArrayEnd finishes the lexing of an array.
+// It assumes that a ']' has just been consumed.
+func lexArrayEnd(lx *lexer) stateFn {
+ lx.ignore()
+ lx.emit(itemArrayEnd)
+ return lx.pop()
+}
+
+// lexInlineTableValue consumes one key/value pair in an inline table.
+// It assumes that '{' or ',' have already been consumed. Whitespace is ignored.
+func lexInlineTableValue(lx *lexer) stateFn {
+ r := lx.next()
+ switch {
+ case isWhitespace(r):
+ return lexSkip(lx, lexInlineTableValue)
+ case isNL(r):
+ if lx.tomlNext {
+ return lexSkip(lx, lexInlineTableValue)
+ }
+ return lx.errorPrevLine(errLexInlineTableNL{})
+ case r == '#':
+ lx.push(lexInlineTableValue)
+ return lexCommentStart
+ case r == ',':
+ return lx.errorf("unexpected comma")
+ case r == '}':
+ return lexInlineTableEnd
+ }
+ lx.backup()
+ lx.push(lexInlineTableValueEnd)
+ return lexKeyStart
+}
+
+// lexInlineTableValueEnd consumes everything between the end of an inline table
+// key/value pair and the next pair (or the end of the table):
+// it ignores whitespace and expects either a ',' or a '}'.
+func lexInlineTableValueEnd(lx *lexer) stateFn {
+ switch r := lx.next(); {
+ case isWhitespace(r):
+ return lexSkip(lx, lexInlineTableValueEnd)
+ case isNL(r):
+ if lx.tomlNext {
+ return lexSkip(lx, lexInlineTableValueEnd)
+ }
+ return lx.errorPrevLine(errLexInlineTableNL{})
+ case r == '#':
+ lx.push(lexInlineTableValueEnd)
+ return lexCommentStart
+ case r == ',':
+ lx.ignore()
+ lx.skip(isWhitespace)
+ if lx.peek() == '}' {
+ if lx.tomlNext {
+ return lexInlineTableValueEnd
+ }
+ return lx.errorf("trailing comma not allowed in inline tables")
+ }
+ return lexInlineTableValue
+ case r == '}':
+ return lexInlineTableEnd
+ default:
+ return lx.errorf("expected a comma or an inline table terminator '}', but got %s instead", runeOrEOF(r))
+ }
+}
+
+func runeOrEOF(r rune) string {
+ if r == eof {
+ return "end of file"
+ }
+ return "'" + string(r) + "'"
+}
+
+// lexInlineTableEnd finishes the lexing of an inline table.
+// It assumes that a '}' has just been consumed.
+func lexInlineTableEnd(lx *lexer) stateFn {
+ lx.ignore()
+ lx.emit(itemInlineTableEnd)
+ return lx.pop()
+}
+
+// lexString consumes the inner contents of a string. It assumes that the
+// beginning '"' has already been consumed and ignored.
+func lexString(lx *lexer) stateFn {
+ r := lx.next()
+ switch {
+ case r == eof:
+ return lx.errorf(`unexpected EOF; expected '"'`)
+ case isNL(r):
+ return lx.errorPrevLine(errLexStringNL{})
+ case r == '\\':
+ lx.push(lexString)
+ return lexStringEscape
+ case r == '"':
+ lx.backup()
+ if lx.esc {
+ lx.esc = false
+ lx.emit(itemStringEsc)
+ } else {
+ lx.emit(itemString)
+ }
+ lx.next()
+ lx.ignore()
+ return lx.pop()
+ }
+ return lexString
+}
+
+// lexMultilineString consumes the inner contents of a string. It assumes that
+// the beginning '"""' has already been consumed and ignored.
+func lexMultilineString(lx *lexer) stateFn {
+ r := lx.next()
+ switch r {
+ default:
+ return lexMultilineString
+ case eof:
+ return lx.errorf(`unexpected EOF; expected '"""'`)
+ case '\\':
+ return lexMultilineStringEscape
+ case '"':
+ /// Found " → try to read two more "".
+ if lx.accept('"') {
+ if lx.accept('"') {
+ /// Peek ahead: the string can contain " and "", including at the
+ /// end: """str"""""
+ /// 6 or more at the end, however, is an error.
+ if lx.peek() == '"' {
+ /// Check if we already lexed 5 's; if so we have 6 now, and
+ /// that's just too many man!
+ ///
+ /// Second check is for the edge case:
+ ///
+ /// two quotes allowed.
+ /// vv
+ /// """lol \""""""
+ /// ^^ ^^^---- closing three
+ /// escaped
+ ///
+ /// But ugly, but it works
+ if strings.HasSuffix(lx.current(), `"""""`) && !strings.HasSuffix(lx.current(), `\"""""`) {
+ return lx.errorf(`unexpected '""""""'`)
+ }
+ lx.backup()
+ lx.backup()
+ return lexMultilineString
+ }
+
+ lx.backup() /// backup: don't include the """ in the item.
+ lx.backup()
+ lx.backup()
+ lx.esc = false
+ lx.emit(itemMultilineString)
+ lx.next() /// Read over ''' again and discard it.
+ lx.next()
+ lx.next()
+ lx.ignore()
+ return lx.pop()
+ }
+ lx.backup()
+ }
+ return lexMultilineString
+ }
+}
+
+// lexRawString consumes a raw string. Nothing can be escaped in such a string.
+// It assumes that the beginning "'" has already been consumed and ignored.
+func lexRawString(lx *lexer) stateFn {
+ r := lx.next()
+ switch {
+ default:
+ return lexRawString
+ case r == eof:
+ return lx.errorf(`unexpected EOF; expected "'"`)
+ case isNL(r):
+ return lx.errorPrevLine(errLexStringNL{})
+ case r == '\'':
+ lx.backup()
+ lx.emit(itemRawString)
+ lx.next()
+ lx.ignore()
+ return lx.pop()
+ }
+}
+
+// lexMultilineRawString consumes a raw string. Nothing can be escaped in such a
+// string. It assumes that the beginning triple-' has already been consumed and
+// ignored.
+func lexMultilineRawString(lx *lexer) stateFn {
+ r := lx.next()
+ switch r {
+ default:
+ return lexMultilineRawString
+ case eof:
+ return lx.errorf(`unexpected EOF; expected "'''"`)
+ case '\'':
+ /// Found ' → try to read two more ''.
+ if lx.accept('\'') {
+ if lx.accept('\'') {
+ /// Peek ahead: the string can contain ' and '', including at the
+ /// end: '''str'''''
+ /// 6 or more at the end, however, is an error.
+ if lx.peek() == '\'' {
+ /// Check if we already lexed 5 's; if so we have 6 now, and
+ /// that's just too many man!
+ if strings.HasSuffix(lx.current(), "'''''") {
+ return lx.errorf(`unexpected "''''''"`)
+ }
+ lx.backup()
+ lx.backup()
+ return lexMultilineRawString
+ }
+
+ lx.backup() /// backup: don't include the ''' in the item.
+ lx.backup()
+ lx.backup()
+ lx.emit(itemRawMultilineString)
+ lx.next() /// Read over ''' again and discard it.
+ lx.next()
+ lx.next()
+ lx.ignore()
+ return lx.pop()
+ }
+ lx.backup()
+ }
+ return lexMultilineRawString
+ }
+}
+
+// lexMultilineStringEscape consumes an escaped character. It assumes that the
+// preceding '\\' has already been consumed.
+func lexMultilineStringEscape(lx *lexer) stateFn {
+ if isNL(lx.next()) { /// \ escaping newline.
+ return lexMultilineString
+ }
+ lx.backup()
+ lx.push(lexMultilineString)
+ return lexStringEscape(lx)
+}
+
+func lexStringEscape(lx *lexer) stateFn {
+ lx.esc = true
+ r := lx.next()
+ switch r {
+ case 'e':
+ if !lx.tomlNext {
+ return lx.error(errLexEscape{r})
+ }
+ fallthrough
+ case 'b':
+ fallthrough
+ case 't':
+ fallthrough
+ case 'n':
+ fallthrough
+ case 'f':
+ fallthrough
+ case 'r':
+ fallthrough
+ case '"':
+ fallthrough
+ case ' ', '\t':
+ // Inside """ .. """ strings you can use \ to escape newlines, and any
+ // amount of whitespace can be between the \ and \n.
+ fallthrough
+ case '\\':
+ return lx.pop()
+ case 'x':
+ if !lx.tomlNext {
+ return lx.error(errLexEscape{r})
+ }
+ return lexHexEscape
+ case 'u':
+ return lexShortUnicodeEscape
+ case 'U':
+ return lexLongUnicodeEscape
+ }
+ return lx.error(errLexEscape{r})
+}
+
+func lexHexEscape(lx *lexer) stateFn {
+ var r rune
+ for i := 0; i < 2; i++ {
+ r = lx.next()
+ if !isHex(r) {
+ return lx.errorf(`expected two hexadecimal digits after '\x', but got %q instead`, lx.current())
+ }
+ }
+ return lx.pop()
+}
+
+func lexShortUnicodeEscape(lx *lexer) stateFn {
+ var r rune
+ for i := 0; i < 4; i++ {
+ r = lx.next()
+ if !isHex(r) {
+ return lx.errorf(`expected four hexadecimal digits after '\u', but got %q instead`, lx.current())
+ }
+ }
+ return lx.pop()
+}
+
+func lexLongUnicodeEscape(lx *lexer) stateFn {
+ var r rune
+ for i := 0; i < 8; i++ {
+ r = lx.next()
+ if !isHex(r) {
+ return lx.errorf(`expected eight hexadecimal digits after '\U', but got %q instead`, lx.current())
+ }
+ }
+ return lx.pop()
+}
+
+// lexNumberOrDateStart processes the first character of a value which begins
+// with a digit. It exists to catch values starting with '0', so that
+// lexBaseNumberOrDate can differentiate base prefixed integers from other
+// types.
+func lexNumberOrDateStart(lx *lexer) stateFn {
+ r := lx.next()
+ switch r {
+ case '0':
+ return lexBaseNumberOrDate
+ }
+
+ if !isDigit(r) {
+ // The only way to reach this state is if the value starts
+ // with a digit, so specifically treat anything else as an
+ // error.
+ return lx.errorf("expected a digit but got %q", r)
+ }
+
+ return lexNumberOrDate
+}
+
+// lexNumberOrDate consumes either an integer, float or datetime.
+func lexNumberOrDate(lx *lexer) stateFn {
+ r := lx.next()
+ if isDigit(r) {
+ return lexNumberOrDate
+ }
+ switch r {
+ case '-', ':':
+ return lexDatetime
+ case '_':
+ return lexDecimalNumber
+ case '.', 'e', 'E':
+ return lexFloat
+ }
+
+ lx.backup()
+ lx.emit(itemInteger)
+ return lx.pop()
+}
+
+// lexDatetime consumes a Datetime, to a first approximation.
+// The parser validates that it matches one of the accepted formats.
+func lexDatetime(lx *lexer) stateFn {
+ r := lx.next()
+ if isDigit(r) {
+ return lexDatetime
+ }
+ switch r {
+ case '-', ':', 'T', 't', ' ', '.', 'Z', 'z', '+':
+ return lexDatetime
+ }
+
+ lx.backup()
+ lx.emitTrim(itemDatetime)
+ return lx.pop()
+}
+
+// lexHexInteger consumes a hexadecimal integer after seeing the '0x' prefix.
+func lexHexInteger(lx *lexer) stateFn {
+ r := lx.next()
+ if isHex(r) {
+ return lexHexInteger
+ }
+ switch r {
+ case '_':
+ return lexHexInteger
+ }
+
+ lx.backup()
+ lx.emit(itemInteger)
+ return lx.pop()
+}
+
+// lexOctalInteger consumes an octal integer after seeing the '0o' prefix.
+func lexOctalInteger(lx *lexer) stateFn {
+ r := lx.next()
+ if isOctal(r) {
+ return lexOctalInteger
+ }
+ switch r {
+ case '_':
+ return lexOctalInteger
+ }
+
+ lx.backup()
+ lx.emit(itemInteger)
+ return lx.pop()
+}
+
+// lexBinaryInteger consumes a binary integer after seeing the '0b' prefix.
+func lexBinaryInteger(lx *lexer) stateFn {
+ r := lx.next()
+ if isBinary(r) {
+ return lexBinaryInteger
+ }
+ switch r {
+ case '_':
+ return lexBinaryInteger
+ }
+
+ lx.backup()
+ lx.emit(itemInteger)
+ return lx.pop()
+}
+
+// lexDecimalNumber consumes a decimal float or integer.
+func lexDecimalNumber(lx *lexer) stateFn {
+ r := lx.next()
+ if isDigit(r) {
+ return lexDecimalNumber
+ }
+ switch r {
+ case '.', 'e', 'E':
+ return lexFloat
+ case '_':
+ return lexDecimalNumber
+ }
+
+ lx.backup()
+ lx.emit(itemInteger)
+ return lx.pop()
+}
+
+// lexDecimalNumber consumes the first digit of a number beginning with a sign.
+// It assumes the sign has already been consumed. Values which start with a sign
+// are only allowed to be decimal integers or floats.
+//
+// The special "nan" and "inf" values are also recognized.
+func lexDecimalNumberStart(lx *lexer) stateFn {
+ r := lx.next()
+
+ // Special error cases to give users better error messages
+ switch r {
+ case 'i':
+ if !lx.accept('n') || !lx.accept('f') {
+ return lx.errorf("invalid float: '%s'", lx.current())
+ }
+ lx.emit(itemFloat)
+ return lx.pop()
+ case 'n':
+ if !lx.accept('a') || !lx.accept('n') {
+ return lx.errorf("invalid float: '%s'", lx.current())
+ }
+ lx.emit(itemFloat)
+ return lx.pop()
+ case '0':
+ p := lx.peek()
+ switch p {
+ case 'b', 'o', 'x':
+ return lx.errorf("cannot use sign with non-decimal numbers: '%s%c'", lx.current(), p)
+ }
+ case '.':
+ return lx.errorf("floats must start with a digit, not '.'")
+ }
+
+ if isDigit(r) {
+ return lexDecimalNumber
+ }
+
+ return lx.errorf("expected a digit but got %q", r)
+}
+
+// lexBaseNumberOrDate differentiates between the possible values which
+// start with '0'. It assumes that before reaching this state, the initial '0'
+// has been consumed.
+func lexBaseNumberOrDate(lx *lexer) stateFn {
+ r := lx.next()
+ // Note: All datetimes start with at least two digits, so we don't
+ // handle date characters (':', '-', etc.) here.
+ if isDigit(r) {
+ return lexNumberOrDate
+ }
+ switch r {
+ case '_':
+ // Can only be decimal, because there can't be an underscore
+ // between the '0' and the base designator, and dates can't
+ // contain underscores.
+ return lexDecimalNumber
+ case '.', 'e', 'E':
+ return lexFloat
+ case 'b':
+ r = lx.peek()
+ if !isBinary(r) {
+ lx.errorf("not a binary number: '%s%c'", lx.current(), r)
+ }
+ return lexBinaryInteger
+ case 'o':
+ r = lx.peek()
+ if !isOctal(r) {
+ lx.errorf("not an octal number: '%s%c'", lx.current(), r)
+ }
+ return lexOctalInteger
+ case 'x':
+ r = lx.peek()
+ if !isHex(r) {
+ lx.errorf("not a hexadecimal number: '%s%c'", lx.current(), r)
+ }
+ return lexHexInteger
+ }
+
+ lx.backup()
+ lx.emit(itemInteger)
+ return lx.pop()
+}
+
+// lexFloat consumes the elements of a float. It allows any sequence of
+// float-like characters, so floats emitted by the lexer are only a first
+// approximation and must be validated by the parser.
+func lexFloat(lx *lexer) stateFn {
+ r := lx.next()
+ if isDigit(r) {
+ return lexFloat
+ }
+ switch r {
+ case '_', '.', '-', '+', 'e', 'E':
+ return lexFloat
+ }
+
+ lx.backup()
+ lx.emit(itemFloat)
+ return lx.pop()
+}
+
+// lexBool consumes a bool string: 'true' or 'false.
+func lexBool(lx *lexer) stateFn {
+ var rs []rune
+ for {
+ r := lx.next()
+ if !unicode.IsLetter(r) {
+ lx.backup()
+ break
+ }
+ rs = append(rs, r)
+ }
+ s := string(rs)
+ switch s {
+ case "true", "false":
+ lx.emit(itemBool)
+ return lx.pop()
+ }
+ return lx.errorf("expected value but found %q instead", s)
+}
+
+// lexCommentStart begins the lexing of a comment. It will emit
+// itemCommentStart and consume no characters, passing control to lexComment.
+func lexCommentStart(lx *lexer) stateFn {
+ lx.ignore()
+ lx.emit(itemCommentStart)
+ return lexComment
+}
+
+// lexComment lexes an entire comment. It assumes that '#' has been consumed.
+// It will consume *up to* the first newline character, and pass control
+// back to the last state on the stack.
+func lexComment(lx *lexer) stateFn {
+ switch r := lx.next(); {
+ case isNL(r) || r == eof:
+ lx.backup()
+ lx.emit(itemText)
+ return lx.pop()
+ default:
+ return lexComment
+ }
+}
+
+// lexSkip ignores all slurped input and moves on to the next state.
+func lexSkip(lx *lexer, nextState stateFn) stateFn {
+ lx.ignore()
+ return nextState
+}
+
+func (s stateFn) String() string {
+ name := runtime.FuncForPC(reflect.ValueOf(s).Pointer()).Name()
+ if i := strings.LastIndexByte(name, '.'); i > -1 {
+ name = name[i+1:]
+ }
+ if s == nil {
+ name = ""
+ }
+ return name + "()"
+}
+
+func (itype itemType) String() string {
+ switch itype {
+ case itemError:
+ return "Error"
+ case itemNIL:
+ return "NIL"
+ case itemEOF:
+ return "EOF"
+ case itemText:
+ return "Text"
+ case itemString, itemStringEsc, itemRawString, itemMultilineString, itemRawMultilineString:
+ return "String"
+ case itemBool:
+ return "Bool"
+ case itemInteger:
+ return "Integer"
+ case itemFloat:
+ return "Float"
+ case itemDatetime:
+ return "DateTime"
+ case itemTableStart:
+ return "TableStart"
+ case itemTableEnd:
+ return "TableEnd"
+ case itemKeyStart:
+ return "KeyStart"
+ case itemKeyEnd:
+ return "KeyEnd"
+ case itemArray:
+ return "Array"
+ case itemArrayEnd:
+ return "ArrayEnd"
+ case itemCommentStart:
+ return "CommentStart"
+ case itemInlineTableStart:
+ return "InlineTableStart"
+ case itemInlineTableEnd:
+ return "InlineTableEnd"
+ }
+ panic(fmt.Sprintf("BUG: Unknown type '%d'.", int(itype)))
+}
+
+func (item item) String() string {
+ return fmt.Sprintf("(%s, %s)", item.typ, item.val)
+}
+
+func isWhitespace(r rune) bool { return r == '\t' || r == ' ' }
+func isNL(r rune) bool { return r == '\n' || r == '\r' }
+func isControl(r rune) bool { // Control characters except \t, \r, \n
+ switch r {
+ case '\t', '\r', '\n':
+ return false
+ default:
+ return (r >= 0x00 && r <= 0x1f) || r == 0x7f
+ }
+}
+func isDigit(r rune) bool { return r >= '0' && r <= '9' }
+func isBinary(r rune) bool { return r == '0' || r == '1' }
+func isOctal(r rune) bool { return r >= '0' && r <= '7' }
+func isHex(r rune) bool { return (r >= '0' && r <= '9') || (r|0x20 >= 'a' && r|0x20 <= 'f') }
+func isBareKeyChar(r rune, tomlNext bool) bool {
+ return (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') ||
+ (r >= '0' && r <= '9') || r == '_' || r == '-'
+}
diff --git a/vendor/github.com/BurntSushi/toml/meta.go b/vendor/github.com/BurntSushi/toml/meta.go
new file mode 100644
index 0000000000..0d337026c1
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/meta.go
@@ -0,0 +1,145 @@
+package toml
+
+import (
+ "strings"
+)
+
+// MetaData allows access to meta information about TOML data that's not
+// accessible otherwise.
+//
+// It allows checking if a key is defined in the TOML data, whether any keys
+// were undecoded, and the TOML type of a key.
+type MetaData struct {
+ context Key // Used only during decoding.
+
+ keyInfo map[string]keyInfo
+ mapping map[string]any
+ keys []Key
+ decoded map[string]struct{}
+ data []byte // Input file; for errors.
+}
+
+// IsDefined reports if the key exists in the TOML data.
+//
+// The key should be specified hierarchically, for example to access the TOML
+// key "a.b.c" you would use IsDefined("a", "b", "c"). Keys are case sensitive.
+//
+// Returns false for an empty key.
+func (md *MetaData) IsDefined(key ...string) bool {
+ if len(key) == 0 {
+ return false
+ }
+
+ var (
+ hash map[string]any
+ ok bool
+ hashOrVal any = md.mapping
+ )
+ for _, k := range key {
+ if hash, ok = hashOrVal.(map[string]any); !ok {
+ return false
+ }
+ if hashOrVal, ok = hash[k]; !ok {
+ return false
+ }
+ }
+ return true
+}
+
+// Type returns a string representation of the type of the key specified.
+//
+// Type will return the empty string if given an empty key or a key that does
+// not exist. Keys are case sensitive.
+func (md *MetaData) Type(key ...string) string {
+ if ki, ok := md.keyInfo[Key(key).String()]; ok {
+ return ki.tomlType.typeString()
+ }
+ return ""
+}
+
+// Keys returns a slice of every key in the TOML data, including key groups.
+//
+// Each key is itself a slice, where the first element is the top of the
+// hierarchy and the last is the most specific. The list will have the same
+// order as the keys appeared in the TOML data.
+//
+// All keys returned are non-empty.
+func (md *MetaData) Keys() []Key {
+ return md.keys
+}
+
+// Undecoded returns all keys that have not been decoded in the order in which
+// they appear in the original TOML document.
+//
+// This includes keys that haven't been decoded because of a [Primitive] value.
+// Once the Primitive value is decoded, the keys will be considered decoded.
+//
+// Also note that decoding into an empty interface will result in no decoding,
+// and so no keys will be considered decoded.
+//
+// In this sense, the Undecoded keys correspond to keys in the TOML document
+// that do not have a concrete type in your representation.
+func (md *MetaData) Undecoded() []Key {
+ undecoded := make([]Key, 0, len(md.keys))
+ for _, key := range md.keys {
+ if _, ok := md.decoded[key.String()]; !ok {
+ undecoded = append(undecoded, key)
+ }
+ }
+ return undecoded
+}
+
+// Key represents any TOML key, including key groups. Use [MetaData.Keys] to get
+// values of this type.
+type Key []string
+
+func (k Key) String() string {
+ // This is called quite often, so it's a bit funky to make it faster.
+ var b strings.Builder
+ b.Grow(len(k) * 25)
+outer:
+ for i, kk := range k {
+ if i > 0 {
+ b.WriteByte('.')
+ }
+ if kk == "" {
+ b.WriteString(`""`)
+ } else {
+ for _, r := range kk {
+ // "Inline" isBareKeyChar
+ if !((r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '_' || r == '-') {
+ b.WriteByte('"')
+ b.WriteString(dblQuotedReplacer.Replace(kk))
+ b.WriteByte('"')
+ continue outer
+ }
+ }
+ b.WriteString(kk)
+ }
+ }
+ return b.String()
+}
+
+func (k Key) maybeQuoted(i int) string {
+ if k[i] == "" {
+ return `""`
+ }
+ for _, r := range k[i] {
+ if (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '_' || r == '-' {
+ continue
+ }
+ return `"` + dblQuotedReplacer.Replace(k[i]) + `"`
+ }
+ return k[i]
+}
+
+// Like append(), but only increase the cap by 1.
+func (k Key) add(piece string) Key {
+ newKey := make(Key, len(k)+1)
+ copy(newKey, k)
+ newKey[len(k)] = piece
+ return newKey
+}
+
+func (k Key) parent() Key { return k[:len(k)-1] } // all except the last piece.
+func (k Key) last() string { return k[len(k)-1] } // last piece of this key.
diff --git a/vendor/github.com/BurntSushi/toml/parse.go b/vendor/github.com/BurntSushi/toml/parse.go
new file mode 100644
index 0000000000..e3ea8a9a2d
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/parse.go
@@ -0,0 +1,845 @@
+package toml
+
+import (
+ "fmt"
+ "math"
+ "os"
+ "strconv"
+ "strings"
+ "time"
+ "unicode/utf8"
+
+ "github.com/BurntSushi/toml/internal"
+)
+
+type parser struct {
+ lx *lexer
+ context Key // Full key for the current hash in scope.
+ currentKey string // Base key name for everything except hashes.
+ pos Position // Current position in the TOML file.
+ tomlNext bool
+
+ ordered []Key // List of keys in the order that they appear in the TOML data.
+
+ keyInfo map[string]keyInfo // Map keyname → info about the TOML key.
+ mapping map[string]any // Map keyname → key value.
+ implicits map[string]struct{} // Record implicit keys (e.g. "key.group.names").
+}
+
+type keyInfo struct {
+ pos Position
+ tomlType tomlType
+}
+
+func parse(data string) (p *parser, err error) {
+ _, tomlNext := os.LookupEnv("BURNTSUSHI_TOML_110")
+
+ defer func() {
+ if r := recover(); r != nil {
+ if pErr, ok := r.(ParseError); ok {
+ pErr.input = data
+ err = pErr
+ return
+ }
+ panic(r)
+ }
+ }()
+
+ // Read over BOM; do this here as the lexer calls utf8.DecodeRuneInString()
+ // which mangles stuff. UTF-16 BOM isn't strictly valid, but some tools add
+ // it anyway.
+ if strings.HasPrefix(data, "\xff\xfe") || strings.HasPrefix(data, "\xfe\xff") { // UTF-16
+ data = data[2:]
+ } else if strings.HasPrefix(data, "\xef\xbb\xbf") { // UTF-8
+ data = data[3:]
+ }
+
+ // Examine first few bytes for NULL bytes; this probably means it's a UTF-16
+ // file (second byte in surrogate pair being NULL). Again, do this here to
+ // avoid having to deal with UTF-8/16 stuff in the lexer.
+ ex := 6
+ if len(data) < 6 {
+ ex = len(data)
+ }
+ if i := strings.IndexRune(data[:ex], 0); i > -1 {
+ return nil, ParseError{
+ Message: "files cannot contain NULL bytes; probably using UTF-16; TOML files must be UTF-8",
+ Position: Position{Line: 1, Col: 1, Start: i, Len: 1},
+ Line: 1,
+ input: data,
+ }
+ }
+
+ p = &parser{
+ keyInfo: make(map[string]keyInfo),
+ mapping: make(map[string]any),
+ lx: lex(data, tomlNext),
+ ordered: make([]Key, 0),
+ implicits: make(map[string]struct{}),
+ tomlNext: tomlNext,
+ }
+ for {
+ item := p.next()
+ if item.typ == itemEOF {
+ break
+ }
+ p.topLevel(item)
+ }
+
+ return p, nil
+}
+
+func (p *parser) panicErr(it item, err error) {
+ panic(ParseError{
+ Message: err.Error(),
+ err: err,
+ Position: it.pos.withCol(p.lx.input),
+ Line: it.pos.Len,
+ LastKey: p.current(),
+ })
+}
+
+func (p *parser) panicItemf(it item, format string, v ...any) {
+ panic(ParseError{
+ Message: fmt.Sprintf(format, v...),
+ Position: it.pos.withCol(p.lx.input),
+ Line: it.pos.Len,
+ LastKey: p.current(),
+ })
+}
+
+func (p *parser) panicf(format string, v ...any) {
+ panic(ParseError{
+ Message: fmt.Sprintf(format, v...),
+ Position: p.pos.withCol(p.lx.input),
+ Line: p.pos.Line,
+ LastKey: p.current(),
+ })
+}
+
+func (p *parser) next() item {
+ it := p.lx.nextItem()
+ //fmt.Printf("ITEM %-18s line %-3d │ %q\n", it.typ, it.pos.Line, it.val)
+ if it.typ == itemError {
+ if it.err != nil {
+ panic(ParseError{
+ Message: it.err.Error(),
+ err: it.err,
+ Position: it.pos.withCol(p.lx.input),
+ Line: it.pos.Line,
+ LastKey: p.current(),
+ })
+ }
+
+ p.panicItemf(it, "%s", it.val)
+ }
+ return it
+}
+
+func (p *parser) nextPos() item {
+ it := p.next()
+ p.pos = it.pos
+ return it
+}
+
+func (p *parser) bug(format string, v ...any) {
+ panic(fmt.Sprintf("BUG: "+format+"\n\n", v...))
+}
+
+func (p *parser) expect(typ itemType) item {
+ it := p.next()
+ p.assertEqual(typ, it.typ)
+ return it
+}
+
+func (p *parser) assertEqual(expected, got itemType) {
+ if expected != got {
+ p.bug("Expected '%s' but got '%s'.", expected, got)
+ }
+}
+
+func (p *parser) topLevel(item item) {
+ switch item.typ {
+ case itemCommentStart: // # ..
+ p.expect(itemText)
+ case itemTableStart: // [ .. ]
+ name := p.nextPos()
+
+ var key Key
+ for ; name.typ != itemTableEnd && name.typ != itemEOF; name = p.next() {
+ key = append(key, p.keyString(name))
+ }
+ p.assertEqual(itemTableEnd, name.typ)
+
+ p.addContext(key, false)
+ p.setType("", tomlHash, item.pos)
+ p.ordered = append(p.ordered, key)
+ case itemArrayTableStart: // [[ .. ]]
+ name := p.nextPos()
+
+ var key Key
+ for ; name.typ != itemArrayTableEnd && name.typ != itemEOF; name = p.next() {
+ key = append(key, p.keyString(name))
+ }
+ p.assertEqual(itemArrayTableEnd, name.typ)
+
+ p.addContext(key, true)
+ p.setType("", tomlArrayHash, item.pos)
+ p.ordered = append(p.ordered, key)
+ case itemKeyStart: // key = ..
+ outerContext := p.context
+ /// Read all the key parts (e.g. 'a' and 'b' in 'a.b')
+ k := p.nextPos()
+ var key Key
+ for ; k.typ != itemKeyEnd && k.typ != itemEOF; k = p.next() {
+ key = append(key, p.keyString(k))
+ }
+ p.assertEqual(itemKeyEnd, k.typ)
+
+ /// The current key is the last part.
+ p.currentKey = key.last()
+
+ /// All the other parts (if any) are the context; need to set each part
+ /// as implicit.
+ context := key.parent()
+ for i := range context {
+ p.addImplicitContext(append(p.context, context[i:i+1]...))
+ }
+ p.ordered = append(p.ordered, p.context.add(p.currentKey))
+
+ /// Set value.
+ vItem := p.next()
+ val, typ := p.value(vItem, false)
+ p.setValue(p.currentKey, val)
+ p.setType(p.currentKey, typ, vItem.pos)
+
+ /// Remove the context we added (preserving any context from [tbl] lines).
+ p.context = outerContext
+ p.currentKey = ""
+ default:
+ p.bug("Unexpected type at top level: %s", item.typ)
+ }
+}
+
+// Gets a string for a key (or part of a key in a table name).
+func (p *parser) keyString(it item) string {
+ switch it.typ {
+ case itemText:
+ return it.val
+ case itemString, itemStringEsc, itemMultilineString,
+ itemRawString, itemRawMultilineString:
+ s, _ := p.value(it, false)
+ return s.(string)
+ default:
+ p.bug("Unexpected key type: %s", it.typ)
+ }
+ panic("unreachable")
+}
+
+var datetimeRepl = strings.NewReplacer(
+ "z", "Z",
+ "t", "T",
+ " ", "T")
+
+// value translates an expected value from the lexer into a Go value wrapped
+// as an empty interface.
+func (p *parser) value(it item, parentIsArray bool) (any, tomlType) {
+ switch it.typ {
+ case itemString:
+ return it.val, p.typeOfPrimitive(it)
+ case itemStringEsc:
+ return p.replaceEscapes(it, it.val), p.typeOfPrimitive(it)
+ case itemMultilineString:
+ return p.replaceEscapes(it, p.stripEscapedNewlines(stripFirstNewline(it.val))), p.typeOfPrimitive(it)
+ case itemRawString:
+ return it.val, p.typeOfPrimitive(it)
+ case itemRawMultilineString:
+ return stripFirstNewline(it.val), p.typeOfPrimitive(it)
+ case itemInteger:
+ return p.valueInteger(it)
+ case itemFloat:
+ return p.valueFloat(it)
+ case itemBool:
+ switch it.val {
+ case "true":
+ return true, p.typeOfPrimitive(it)
+ case "false":
+ return false, p.typeOfPrimitive(it)
+ default:
+ p.bug("Expected boolean value, but got '%s'.", it.val)
+ }
+ case itemDatetime:
+ return p.valueDatetime(it)
+ case itemArray:
+ return p.valueArray(it)
+ case itemInlineTableStart:
+ return p.valueInlineTable(it, parentIsArray)
+ default:
+ p.bug("Unexpected value type: %s", it.typ)
+ }
+ panic("unreachable")
+}
+
+func (p *parser) valueInteger(it item) (any, tomlType) {
+ if !numUnderscoresOK(it.val) {
+ p.panicItemf(it, "Invalid integer %q: underscores must be surrounded by digits", it.val)
+ }
+ if numHasLeadingZero(it.val) {
+ p.panicItemf(it, "Invalid integer %q: cannot have leading zeroes", it.val)
+ }
+
+ num, err := strconv.ParseInt(it.val, 0, 64)
+ if err != nil {
+ // Distinguish integer values. Normally, it'd be a bug if the lexer
+ // provides an invalid integer, but it's possible that the number is
+ // out of range of valid values (which the lexer cannot determine).
+ // So mark the former as a bug but the latter as a legitimate user
+ // error.
+ if e, ok := err.(*strconv.NumError); ok && e.Err == strconv.ErrRange {
+ p.panicErr(it, errParseRange{i: it.val, size: "int64"})
+ } else {
+ p.bug("Expected integer value, but got '%s'.", it.val)
+ }
+ }
+ return num, p.typeOfPrimitive(it)
+}
+
+func (p *parser) valueFloat(it item) (any, tomlType) {
+ parts := strings.FieldsFunc(it.val, func(r rune) bool {
+ switch r {
+ case '.', 'e', 'E':
+ return true
+ }
+ return false
+ })
+ for _, part := range parts {
+ if !numUnderscoresOK(part) {
+ p.panicItemf(it, "Invalid float %q: underscores must be surrounded by digits", it.val)
+ }
+ }
+ if len(parts) > 0 && numHasLeadingZero(parts[0]) {
+ p.panicItemf(it, "Invalid float %q: cannot have leading zeroes", it.val)
+ }
+ if !numPeriodsOK(it.val) {
+ // As a special case, numbers like '123.' or '1.e2',
+ // which are valid as far as Go/strconv are concerned,
+ // must be rejected because TOML says that a fractional
+ // part consists of '.' followed by 1+ digits.
+ p.panicItemf(it, "Invalid float %q: '.' must be followed by one or more digits", it.val)
+ }
+ val := strings.Replace(it.val, "_", "", -1)
+ signbit := false
+ if val == "+nan" || val == "-nan" {
+ signbit = val == "-nan"
+ val = "nan"
+ }
+ num, err := strconv.ParseFloat(val, 64)
+ if err != nil {
+ if e, ok := err.(*strconv.NumError); ok && e.Err == strconv.ErrRange {
+ p.panicErr(it, errParseRange{i: it.val, size: "float64"})
+ } else {
+ p.panicItemf(it, "Invalid float value: %q", it.val)
+ }
+ }
+ if signbit {
+ num = math.Copysign(num, -1)
+ }
+ return num, p.typeOfPrimitive(it)
+}
+
+var dtTypes = []struct {
+ fmt string
+ zone *time.Location
+ next bool
+}{
+ {time.RFC3339Nano, time.Local, false},
+ {"2006-01-02T15:04:05.999999999", internal.LocalDatetime, false},
+ {"2006-01-02", internal.LocalDate, false},
+ {"15:04:05.999999999", internal.LocalTime, false},
+
+ // tomlNext
+ {"2006-01-02T15:04Z07:00", time.Local, true},
+ {"2006-01-02T15:04", internal.LocalDatetime, true},
+ {"15:04", internal.LocalTime, true},
+}
+
+func (p *parser) valueDatetime(it item) (any, tomlType) {
+ it.val = datetimeRepl.Replace(it.val)
+ var (
+ t time.Time
+ ok bool
+ err error
+ )
+ for _, dt := range dtTypes {
+ if dt.next && !p.tomlNext {
+ continue
+ }
+ t, err = time.ParseInLocation(dt.fmt, it.val, dt.zone)
+ if err == nil {
+ if missingLeadingZero(it.val, dt.fmt) {
+ p.panicErr(it, errParseDate{it.val})
+ }
+ ok = true
+ break
+ }
+ }
+ if !ok {
+ p.panicErr(it, errParseDate{it.val})
+ }
+ return t, p.typeOfPrimitive(it)
+}
+
+// Go's time.Parse() will accept numbers without a leading zero; there isn't any
+// way to require it. https://github.com/golang/go/issues/29911
+//
+// Depend on the fact that the separators (- and :) should always be at the same
+// location.
+func missingLeadingZero(d, l string) bool {
+ for i, c := range []byte(l) {
+ if c == '.' || c == 'Z' {
+ return false
+ }
+ if (c < '0' || c > '9') && d[i] != c {
+ return true
+ }
+ }
+ return false
+}
+
+func (p *parser) valueArray(it item) (any, tomlType) {
+ p.setType(p.currentKey, tomlArray, it.pos)
+
+ var (
+ // Initialize to a non-nil slice to make it consistent with how S = []
+ // decodes into a non-nil slice inside something like struct { S
+ // []string }. See #338
+ array = make([]any, 0, 2)
+ )
+ for it = p.next(); it.typ != itemArrayEnd; it = p.next() {
+ if it.typ == itemCommentStart {
+ p.expect(itemText)
+ continue
+ }
+
+ val, typ := p.value(it, true)
+ array = append(array, val)
+
+ // XXX: type isn't used here, we need it to record the accurate type
+ // information.
+ //
+ // Not entirely sure how to best store this; could use "key[0]",
+ // "key[1]" notation, or maybe store it on the Array type?
+ _ = typ
+ }
+ return array, tomlArray
+}
+
+func (p *parser) valueInlineTable(it item, parentIsArray bool) (any, tomlType) {
+ var (
+ topHash = make(map[string]any)
+ outerContext = p.context
+ outerKey = p.currentKey
+ )
+
+ p.context = append(p.context, p.currentKey)
+ prevContext := p.context
+ p.currentKey = ""
+
+ p.addImplicit(p.context)
+ p.addContext(p.context, parentIsArray)
+
+ /// Loop over all table key/value pairs.
+ for it := p.next(); it.typ != itemInlineTableEnd; it = p.next() {
+ if it.typ == itemCommentStart {
+ p.expect(itemText)
+ continue
+ }
+
+ /// Read all key parts.
+ k := p.nextPos()
+ var key Key
+ for ; k.typ != itemKeyEnd && k.typ != itemEOF; k = p.next() {
+ key = append(key, p.keyString(k))
+ }
+ p.assertEqual(itemKeyEnd, k.typ)
+
+ /// The current key is the last part.
+ p.currentKey = key.last()
+
+ /// All the other parts (if any) are the context; need to set each part
+ /// as implicit.
+ context := key.parent()
+ for i := range context {
+ p.addImplicitContext(append(p.context, context[i:i+1]...))
+ }
+ p.ordered = append(p.ordered, p.context.add(p.currentKey))
+
+ /// Set the value.
+ val, typ := p.value(p.next(), false)
+ p.setValue(p.currentKey, val)
+ p.setType(p.currentKey, typ, it.pos)
+
+ hash := topHash
+ for _, c := range context {
+ h, ok := hash[c]
+ if !ok {
+ h = make(map[string]any)
+ hash[c] = h
+ }
+ hash, ok = h.(map[string]any)
+ if !ok {
+ p.panicf("%q is not a table", p.context)
+ }
+ }
+ hash[p.currentKey] = val
+
+ /// Restore context.
+ p.context = prevContext
+ }
+ p.context = outerContext
+ p.currentKey = outerKey
+ return topHash, tomlHash
+}
+
+// numHasLeadingZero checks if this number has leading zeroes, allowing for '0',
+// +/- signs, and base prefixes.
+func numHasLeadingZero(s string) bool {
+ if len(s) > 1 && s[0] == '0' && !(s[1] == 'b' || s[1] == 'o' || s[1] == 'x') { // Allow 0b, 0o, 0x
+ return true
+ }
+ if len(s) > 2 && (s[0] == '-' || s[0] == '+') && s[1] == '0' {
+ return true
+ }
+ return false
+}
+
+// numUnderscoresOK checks whether each underscore in s is surrounded by
+// characters that are not underscores.
+func numUnderscoresOK(s string) bool {
+ switch s {
+ case "nan", "+nan", "-nan", "inf", "-inf", "+inf":
+ return true
+ }
+ accept := false
+ for _, r := range s {
+ if r == '_' {
+ if !accept {
+ return false
+ }
+ }
+
+ // isHex is a superset of all the permissible characters surrounding an
+ // underscore.
+ accept = isHex(r)
+ }
+ return accept
+}
+
+// numPeriodsOK checks whether every period in s is followed by a digit.
+func numPeriodsOK(s string) bool {
+ period := false
+ for _, r := range s {
+ if period && !isDigit(r) {
+ return false
+ }
+ period = r == '.'
+ }
+ return !period
+}
+
+// Set the current context of the parser, where the context is either a hash or
+// an array of hashes, depending on the value of the `array` parameter.
+//
+// Establishing the context also makes sure that the key isn't a duplicate, and
+// will create implicit hashes automatically.
+func (p *parser) addContext(key Key, array bool) {
+ /// Always start at the top level and drill down for our context.
+ hashContext := p.mapping
+ keyContext := make(Key, 0, len(key)-1)
+
+ /// We only need implicit hashes for the parents.
+ for _, k := range key.parent() {
+ _, ok := hashContext[k]
+ keyContext = append(keyContext, k)
+
+ // No key? Make an implicit hash and move on.
+ if !ok {
+ p.addImplicit(keyContext)
+ hashContext[k] = make(map[string]any)
+ }
+
+ // If the hash context is actually an array of tables, then set
+ // the hash context to the last element in that array.
+ //
+ // Otherwise, it better be a table, since this MUST be a key group (by
+ // virtue of it not being the last element in a key).
+ switch t := hashContext[k].(type) {
+ case []map[string]any:
+ hashContext = t[len(t)-1]
+ case map[string]any:
+ hashContext = t
+ default:
+ p.panicf("Key '%s' was already created as a hash.", keyContext)
+ }
+ }
+
+ p.context = keyContext
+ if array {
+ // If this is the first element for this array, then allocate a new
+ // list of tables for it.
+ k := key.last()
+ if _, ok := hashContext[k]; !ok {
+ hashContext[k] = make([]map[string]any, 0, 4)
+ }
+
+ // Add a new table. But make sure the key hasn't already been used
+ // for something else.
+ if hash, ok := hashContext[k].([]map[string]any); ok {
+ hashContext[k] = append(hash, make(map[string]any))
+ } else {
+ p.panicf("Key '%s' was already created and cannot be used as an array.", key)
+ }
+ } else {
+ p.setValue(key.last(), make(map[string]any))
+ }
+ p.context = append(p.context, key.last())
+}
+
+// setValue sets the given key to the given value in the current context.
+// It will make sure that the key hasn't already been defined, account for
+// implicit key groups.
+func (p *parser) setValue(key string, value any) {
+ var (
+ tmpHash any
+ ok bool
+ hash = p.mapping
+ keyContext = make(Key, 0, len(p.context)+1)
+ )
+ for _, k := range p.context {
+ keyContext = append(keyContext, k)
+ if tmpHash, ok = hash[k]; !ok {
+ p.bug("Context for key '%s' has not been established.", keyContext)
+ }
+ switch t := tmpHash.(type) {
+ case []map[string]any:
+ // The context is a table of hashes. Pick the most recent table
+ // defined as the current hash.
+ hash = t[len(t)-1]
+ case map[string]any:
+ hash = t
+ default:
+ p.panicf("Key '%s' has already been defined.", keyContext)
+ }
+ }
+ keyContext = append(keyContext, key)
+
+ if _, ok := hash[key]; ok {
+ // Normally redefining keys isn't allowed, but the key could have been
+ // defined implicitly and it's allowed to be redefined concretely. (See
+ // the `valid/implicit-and-explicit-after.toml` in toml-test)
+ //
+ // But we have to make sure to stop marking it as an implicit. (So that
+ // another redefinition provokes an error.)
+ //
+ // Note that since it has already been defined (as a hash), we don't
+ // want to overwrite it. So our business is done.
+ if p.isArray(keyContext) {
+ p.removeImplicit(keyContext)
+ hash[key] = value
+ return
+ }
+ if p.isImplicit(keyContext) {
+ p.removeImplicit(keyContext)
+ return
+ }
+ // Otherwise, we have a concrete key trying to override a previous key,
+ // which is *always* wrong.
+ p.panicf("Key '%s' has already been defined.", keyContext)
+ }
+
+ hash[key] = value
+}
+
+// setType sets the type of a particular value at a given key. It should be
+// called immediately AFTER setValue.
+//
+// Note that if `key` is empty, then the type given will be applied to the
+// current context (which is either a table or an array of tables).
+func (p *parser) setType(key string, typ tomlType, pos Position) {
+ keyContext := make(Key, 0, len(p.context)+1)
+ keyContext = append(keyContext, p.context...)
+ if len(key) > 0 { // allow type setting for hashes
+ keyContext = append(keyContext, key)
+ }
+ // Special case to make empty keys ("" = 1) work.
+ // Without it it will set "" rather than `""`.
+ // TODO: why is this needed? And why is this only needed here?
+ if len(keyContext) == 0 {
+ keyContext = Key{""}
+ }
+ p.keyInfo[keyContext.String()] = keyInfo{tomlType: typ, pos: pos}
+}
+
+// Implicit keys need to be created when tables are implied in "a.b.c.d = 1" and
+// "[a.b.c]" (the "a", "b", and "c" hashes are never created explicitly).
+func (p *parser) addImplicit(key Key) { p.implicits[key.String()] = struct{}{} }
+func (p *parser) removeImplicit(key Key) { delete(p.implicits, key.String()) }
+func (p *parser) isImplicit(key Key) bool { _, ok := p.implicits[key.String()]; return ok }
+func (p *parser) isArray(key Key) bool { return p.keyInfo[key.String()].tomlType == tomlArray }
+func (p *parser) addImplicitContext(key Key) { p.addImplicit(key); p.addContext(key, false) }
+
+// current returns the full key name of the current context.
+func (p *parser) current() string {
+ if len(p.currentKey) == 0 {
+ return p.context.String()
+ }
+ if len(p.context) == 0 {
+ return p.currentKey
+ }
+ return fmt.Sprintf("%s.%s", p.context, p.currentKey)
+}
+
+func stripFirstNewline(s string) string {
+ if len(s) > 0 && s[0] == '\n' {
+ return s[1:]
+ }
+ if len(s) > 1 && s[0] == '\r' && s[1] == '\n' {
+ return s[2:]
+ }
+ return s
+}
+
+// stripEscapedNewlines removes whitespace after line-ending backslashes in
+// multiline strings.
+//
+// A line-ending backslash is an unescaped \ followed only by whitespace until
+// the next newline. After a line-ending backslash, all whitespace is removed
+// until the next non-whitespace character.
+func (p *parser) stripEscapedNewlines(s string) string {
+ var (
+ b strings.Builder
+ i int
+ )
+ b.Grow(len(s))
+ for {
+ ix := strings.Index(s[i:], `\`)
+ if ix < 0 {
+ b.WriteString(s)
+ return b.String()
+ }
+ i += ix
+
+ if len(s) > i+1 && s[i+1] == '\\' {
+ // Escaped backslash.
+ i += 2
+ continue
+ }
+ // Scan until the next non-whitespace.
+ j := i + 1
+ whitespaceLoop:
+ for ; j < len(s); j++ {
+ switch s[j] {
+ case ' ', '\t', '\r', '\n':
+ default:
+ break whitespaceLoop
+ }
+ }
+ if j == i+1 {
+ // Not a whitespace escape.
+ i++
+ continue
+ }
+ if !strings.Contains(s[i:j], "\n") {
+ // This is not a line-ending backslash. (It's a bad escape sequence,
+ // but we can let replaceEscapes catch it.)
+ i++
+ continue
+ }
+ b.WriteString(s[:i])
+ s = s[j:]
+ i = 0
+ }
+}
+
+func (p *parser) replaceEscapes(it item, str string) string {
+ var (
+ b strings.Builder
+ skip = 0
+ )
+ b.Grow(len(str))
+ for i, c := range str {
+ if skip > 0 {
+ skip--
+ continue
+ }
+ if c != '\\' {
+ b.WriteRune(c)
+ continue
+ }
+
+ if i >= len(str) {
+ p.bug("Escape sequence at end of string.")
+ return ""
+ }
+ switch str[i+1] {
+ default:
+ p.bug("Expected valid escape code after \\, but got %q.", str[i+1])
+ case ' ', '\t':
+ p.panicItemf(it, "invalid escape: '\\%c'", str[i+1])
+ case 'b':
+ b.WriteByte(0x08)
+ skip = 1
+ case 't':
+ b.WriteByte(0x09)
+ skip = 1
+ case 'n':
+ b.WriteByte(0x0a)
+ skip = 1
+ case 'f':
+ b.WriteByte(0x0c)
+ skip = 1
+ case 'r':
+ b.WriteByte(0x0d)
+ skip = 1
+ case 'e':
+ if p.tomlNext {
+ b.WriteByte(0x1b)
+ skip = 1
+ }
+ case '"':
+ b.WriteByte(0x22)
+ skip = 1
+ case '\\':
+ b.WriteByte(0x5c)
+ skip = 1
+ // The lexer guarantees the correct number of characters are present;
+ // don't need to check here.
+ case 'x':
+ if p.tomlNext {
+ escaped := p.asciiEscapeToUnicode(it, str[i+2:i+4])
+ b.WriteRune(escaped)
+ skip = 3
+ }
+ case 'u':
+ escaped := p.asciiEscapeToUnicode(it, str[i+2:i+6])
+ b.WriteRune(escaped)
+ skip = 5
+ case 'U':
+ escaped := p.asciiEscapeToUnicode(it, str[i+2:i+10])
+ b.WriteRune(escaped)
+ skip = 9
+ }
+ }
+ return b.String()
+}
+
+func (p *parser) asciiEscapeToUnicode(it item, s string) rune {
+ hex, err := strconv.ParseUint(strings.ToLower(s), 16, 32)
+ if err != nil {
+ p.bug("Could not parse '%s' as a hexadecimal number, but the lexer claims it's OK: %s", s, err)
+ }
+ if !utf8.ValidRune(rune(hex)) {
+ p.panicItemf(it, "Escaped character '\\u%s' is not valid UTF-8.", s)
+ }
+ return rune(hex)
+}
diff --git a/vendor/github.com/BurntSushi/toml/type_fields.go b/vendor/github.com/BurntSushi/toml/type_fields.go
new file mode 100644
index 0000000000..10c51f7eeb
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/type_fields.go
@@ -0,0 +1,238 @@
+package toml
+
+// Struct field handling is adapted from code in encoding/json:
+//
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the Go distribution.
+
+import (
+ "reflect"
+ "sort"
+ "sync"
+)
+
+// A field represents a single field found in a struct.
+type field struct {
+ name string // the name of the field (`toml` tag included)
+ tag bool // whether field has a `toml` tag
+ index []int // represents the depth of an anonymous field
+ typ reflect.Type // the type of the field
+}
+
+// byName sorts field by name, breaking ties with depth,
+// then breaking ties with "name came from toml tag", then
+// breaking ties with index sequence.
+type byName []field
+
+func (x byName) Len() int { return len(x) }
+func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x byName) Less(i, j int) bool {
+ if x[i].name != x[j].name {
+ return x[i].name < x[j].name
+ }
+ if len(x[i].index) != len(x[j].index) {
+ return len(x[i].index) < len(x[j].index)
+ }
+ if x[i].tag != x[j].tag {
+ return x[i].tag
+ }
+ return byIndex(x).Less(i, j)
+}
+
+// byIndex sorts field by index sequence.
+type byIndex []field
+
+func (x byIndex) Len() int { return len(x) }
+func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x byIndex) Less(i, j int) bool {
+ for k, xik := range x[i].index {
+ if k >= len(x[j].index) {
+ return false
+ }
+ if xik != x[j].index[k] {
+ return xik < x[j].index[k]
+ }
+ }
+ return len(x[i].index) < len(x[j].index)
+}
+
+// typeFields returns a list of fields that TOML should recognize for the given
+// type. The algorithm is breadth-first search over the set of structs to
+// include - the top struct and then any reachable anonymous structs.
+func typeFields(t reflect.Type) []field {
+ // Anonymous fields to explore at the current level and the next.
+ current := []field{}
+ next := []field{{typ: t}}
+
+ // Count of queued names for current level and the next.
+ var count map[reflect.Type]int
+ var nextCount map[reflect.Type]int
+
+ // Types already visited at an earlier level.
+ visited := map[reflect.Type]bool{}
+
+ // Fields found.
+ var fields []field
+
+ for len(next) > 0 {
+ current, next = next, current[:0]
+ count, nextCount = nextCount, map[reflect.Type]int{}
+
+ for _, f := range current {
+ if visited[f.typ] {
+ continue
+ }
+ visited[f.typ] = true
+
+ // Scan f.typ for fields to include.
+ for i := 0; i < f.typ.NumField(); i++ {
+ sf := f.typ.Field(i)
+ if sf.PkgPath != "" && !sf.Anonymous { // unexported
+ continue
+ }
+ opts := getOptions(sf.Tag)
+ if opts.skip {
+ continue
+ }
+ index := make([]int, len(f.index)+1)
+ copy(index, f.index)
+ index[len(f.index)] = i
+
+ ft := sf.Type
+ if ft.Name() == "" && ft.Kind() == reflect.Ptr {
+ // Follow pointer.
+ ft = ft.Elem()
+ }
+
+ // Record found field and index sequence.
+ if opts.name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
+ tagged := opts.name != ""
+ name := opts.name
+ if name == "" {
+ name = sf.Name
+ }
+ fields = append(fields, field{name, tagged, index, ft})
+ if count[f.typ] > 1 {
+ // If there were multiple instances, add a second,
+ // so that the annihilation code will see a duplicate.
+ // It only cares about the distinction between 1 or 2,
+ // so don't bother generating any more copies.
+ fields = append(fields, fields[len(fields)-1])
+ }
+ continue
+ }
+
+ // Record new anonymous struct to explore in next round.
+ nextCount[ft]++
+ if nextCount[ft] == 1 {
+ f := field{name: ft.Name(), index: index, typ: ft}
+ next = append(next, f)
+ }
+ }
+ }
+ }
+
+ sort.Sort(byName(fields))
+
+ // Delete all fields that are hidden by the Go rules for embedded fields,
+ // except that fields with TOML tags are promoted.
+
+ // The fields are sorted in primary order of name, secondary order
+ // of field index length. Loop over names; for each name, delete
+ // hidden fields by choosing the one dominant field that survives.
+ out := fields[:0]
+ for advance, i := 0, 0; i < len(fields); i += advance {
+ // One iteration per name.
+ // Find the sequence of fields with the name of this first field.
+ fi := fields[i]
+ name := fi.name
+ for advance = 1; i+advance < len(fields); advance++ {
+ fj := fields[i+advance]
+ if fj.name != name {
+ break
+ }
+ }
+ if advance == 1 { // Only one field with this name
+ out = append(out, fi)
+ continue
+ }
+ dominant, ok := dominantField(fields[i : i+advance])
+ if ok {
+ out = append(out, dominant)
+ }
+ }
+
+ fields = out
+ sort.Sort(byIndex(fields))
+
+ return fields
+}
+
+// dominantField looks through the fields, all of which are known to
+// have the same name, to find the single field that dominates the
+// others using Go's embedding rules, modified by the presence of
+// TOML tags. If there are multiple top-level fields, the boolean
+// will be false: This condition is an error in Go and we skip all
+// the fields.
+func dominantField(fields []field) (field, bool) {
+ // The fields are sorted in increasing index-length order. The winner
+ // must therefore be one with the shortest index length. Drop all
+ // longer entries, which is easy: just truncate the slice.
+ length := len(fields[0].index)
+ tagged := -1 // Index of first tagged field.
+ for i, f := range fields {
+ if len(f.index) > length {
+ fields = fields[:i]
+ break
+ }
+ if f.tag {
+ if tagged >= 0 {
+ // Multiple tagged fields at the same level: conflict.
+ // Return no field.
+ return field{}, false
+ }
+ tagged = i
+ }
+ }
+ if tagged >= 0 {
+ return fields[tagged], true
+ }
+ // All remaining fields have the same length. If there's more than one,
+ // we have a conflict (two fields named "X" at the same level) and we
+ // return no field.
+ if len(fields) > 1 {
+ return field{}, false
+ }
+ return fields[0], true
+}
+
+var fieldCache struct {
+ sync.RWMutex
+ m map[reflect.Type][]field
+}
+
+// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
+func cachedTypeFields(t reflect.Type) []field {
+ fieldCache.RLock()
+ f := fieldCache.m[t]
+ fieldCache.RUnlock()
+ if f != nil {
+ return f
+ }
+
+ // Compute fields without lock.
+ // Might duplicate effort but won't hold other computations back.
+ f = typeFields(t)
+ if f == nil {
+ f = []field{}
+ }
+
+ fieldCache.Lock()
+ if fieldCache.m == nil {
+ fieldCache.m = map[reflect.Type][]field{}
+ }
+ fieldCache.m[t] = f
+ fieldCache.Unlock()
+ return f
+}
diff --git a/vendor/github.com/BurntSushi/toml/type_toml.go b/vendor/github.com/BurntSushi/toml/type_toml.go
new file mode 100644
index 0000000000..1c090d331e
--- /dev/null
+++ b/vendor/github.com/BurntSushi/toml/type_toml.go
@@ -0,0 +1,65 @@
+package toml
+
+// tomlType represents any Go type that corresponds to a TOML type.
+// While the first draft of the TOML spec has a simplistic type system that
+// probably doesn't need this level of sophistication, we seem to be militating
+// toward adding real composite types.
+type tomlType interface {
+ typeString() string
+}
+
+// typeEqual accepts any two types and returns true if they are equal.
+func typeEqual(t1, t2 tomlType) bool {
+ if t1 == nil || t2 == nil {
+ return false
+ }
+ return t1.typeString() == t2.typeString()
+}
+
+func typeIsTable(t tomlType) bool {
+ return typeEqual(t, tomlHash) || typeEqual(t, tomlArrayHash)
+}
+
+type tomlBaseType string
+
+func (btype tomlBaseType) typeString() string { return string(btype) }
+func (btype tomlBaseType) String() string { return btype.typeString() }
+
+var (
+ tomlInteger tomlBaseType = "Integer"
+ tomlFloat tomlBaseType = "Float"
+ tomlDatetime tomlBaseType = "Datetime"
+ tomlString tomlBaseType = "String"
+ tomlBool tomlBaseType = "Bool"
+ tomlArray tomlBaseType = "Array"
+ tomlHash tomlBaseType = "Hash"
+ tomlArrayHash tomlBaseType = "ArrayHash"
+)
+
+// typeOfPrimitive returns a tomlType of any primitive value in TOML.
+// Primitive values are: Integer, Float, Datetime, String and Bool.
+//
+// Passing a lexer item other than the following will cause a BUG message
+// to occur: itemString, itemBool, itemInteger, itemFloat, itemDatetime.
+func (p *parser) typeOfPrimitive(lexItem item) tomlType {
+ switch lexItem.typ {
+ case itemInteger:
+ return tomlInteger
+ case itemFloat:
+ return tomlFloat
+ case itemDatetime:
+ return tomlDatetime
+ case itemString, itemStringEsc:
+ return tomlString
+ case itemMultilineString:
+ return tomlString
+ case itemRawString:
+ return tomlString
+ case itemRawMultilineString:
+ return tomlString
+ case itemBool:
+ return tomlBool
+ }
+ p.bug("Cannot infer primitive type of lex item '%s'.", lexItem)
+ panic("unreachable")
+}
diff --git a/vendor/github.com/MakeNowJust/heredoc/LICENSE b/vendor/github.com/MakeNowJust/heredoc/LICENSE
new file mode 100644
index 0000000000..6d0eb9d5d6
--- /dev/null
+++ b/vendor/github.com/MakeNowJust/heredoc/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014-2019 TSUYUSATO Kitsune
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/github.com/MakeNowJust/heredoc/README.md b/vendor/github.com/MakeNowJust/heredoc/README.md
new file mode 100644
index 0000000000..e9924d2974
--- /dev/null
+++ b/vendor/github.com/MakeNowJust/heredoc/README.md
@@ -0,0 +1,52 @@
+# heredoc
+
+[](https://circleci.com/gh/MakeNowJust/heredoc) [](https://godoc.org/github.com/MakeNowJust/heredoc)
+
+## About
+
+Package heredoc provides the here-document with keeping indent.
+
+## Install
+
+```console
+$ go get github.com/MakeNowJust/heredoc
+```
+
+## Import
+
+```go
+// usual
+import "github.com/MakeNowJust/heredoc"
+```
+
+## Example
+
+```go
+package main
+
+import (
+ "fmt"
+ "github.com/MakeNowJust/heredoc"
+)
+
+func main() {
+ fmt.Println(heredoc.Doc(`
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit,
+ sed do eiusmod tempor incididunt ut labore et dolore magna
+ aliqua. Ut enim ad minim veniam, ...
+ `))
+ // Output:
+ // Lorem ipsum dolor sit amet, consectetur adipisicing elit,
+ // sed do eiusmod tempor incididunt ut labore et dolore magna
+ // aliqua. Ut enim ad minim veniam, ...
+ //
+}
+```
+
+## API Document
+
+ - [heredoc - GoDoc](https://godoc.org/github.com/MakeNowJust/heredoc)
+
+## License
+
+This software is released under the MIT License, see LICENSE.
diff --git a/vendor/github.com/MakeNowJust/heredoc/heredoc.go b/vendor/github.com/MakeNowJust/heredoc/heredoc.go
new file mode 100644
index 0000000000..1fc0469555
--- /dev/null
+++ b/vendor/github.com/MakeNowJust/heredoc/heredoc.go
@@ -0,0 +1,105 @@
+// Copyright (c) 2014-2019 TSUYUSATO Kitsune
+// This software is released under the MIT License.
+// http://opensource.org/licenses/mit-license.php
+
+// Package heredoc provides creation of here-documents from raw strings.
+//
+// Golang supports raw-string syntax.
+//
+// doc := `
+// Foo
+// Bar
+// `
+//
+// But raw-string cannot recognize indentation. Thus such content is an indented string, equivalent to
+//
+// "\n\tFoo\n\tBar\n"
+//
+// I dont't want this!
+//
+// However this problem is solved by package heredoc.
+//
+// doc := heredoc.Doc(`
+// Foo
+// Bar
+// `)
+//
+// Is equivalent to
+//
+// "Foo\nBar\n"
+package heredoc
+
+import (
+ "fmt"
+ "strings"
+ "unicode"
+)
+
+const maxInt = int(^uint(0) >> 1)
+
+// Doc returns un-indented string as here-document.
+func Doc(raw string) string {
+ skipFirstLine := false
+ if len(raw) > 0 && raw[0] == '\n' {
+ raw = raw[1:]
+ } else {
+ skipFirstLine = true
+ }
+
+ lines := strings.Split(raw, "\n")
+
+ minIndentSize := getMinIndent(lines, skipFirstLine)
+ lines = removeIndentation(lines, minIndentSize, skipFirstLine)
+
+ return strings.Join(lines, "\n")
+}
+
+// getMinIndent calculates the minimum indentation in lines, excluding empty lines.
+func getMinIndent(lines []string, skipFirstLine bool) int {
+ minIndentSize := maxInt
+
+ for i, line := range lines {
+ if i == 0 && skipFirstLine {
+ continue
+ }
+
+ indentSize := 0
+ for _, r := range []rune(line) {
+ if unicode.IsSpace(r) {
+ indentSize += 1
+ } else {
+ break
+ }
+ }
+
+ if len(line) == indentSize {
+ if i == len(lines)-1 && indentSize < minIndentSize {
+ lines[i] = ""
+ }
+ } else if indentSize < minIndentSize {
+ minIndentSize = indentSize
+ }
+ }
+ return minIndentSize
+}
+
+// removeIndentation removes n characters from the front of each line in lines.
+// Skips first line if skipFirstLine is true, skips empty lines.
+func removeIndentation(lines []string, n int, skipFirstLine bool) []string {
+ for i, line := range lines {
+ if i == 0 && skipFirstLine {
+ continue
+ }
+
+ if len(lines[i]) >= n {
+ lines[i] = line[n:]
+ }
+ }
+ return lines
+}
+
+// Docf returns unindented and formatted string as here-document.
+// Formatting is done as for fmt.Printf().
+func Docf(raw string, args ...interface{}) string {
+ return fmt.Sprintf(Doc(raw), args...)
+}
diff --git a/vendor/github.com/Masterminds/goutils/.travis.yml b/vendor/github.com/Masterminds/goutils/.travis.yml
new file mode 100644
index 0000000000..4025e01ec4
--- /dev/null
+++ b/vendor/github.com/Masterminds/goutils/.travis.yml
@@ -0,0 +1,18 @@
+language: go
+
+go:
+ - 1.6
+ - 1.7
+ - 1.8
+ - tip
+
+script:
+ - go test -v
+
+notifications:
+ webhooks:
+ urls:
+ - https://webhooks.gitter.im/e/06e3328629952dabe3e0
+ on_success: change # options: [always|never|change] default: always
+ on_failure: always # options: [always|never|change] default: always
+ on_start: never # options: [always|never|change] default: always
diff --git a/vendor/github.com/Masterminds/goutils/CHANGELOG.md b/vendor/github.com/Masterminds/goutils/CHANGELOG.md
new file mode 100644
index 0000000000..d700ec47f2
--- /dev/null
+++ b/vendor/github.com/Masterminds/goutils/CHANGELOG.md
@@ -0,0 +1,8 @@
+# 1.0.1 (2017-05-31)
+
+## Fixed
+- #21: Fix generation of alphanumeric strings (thanks @dbarranco)
+
+# 1.0.0 (2014-04-30)
+
+- Initial release.
diff --git a/vendor/github.com/Masterminds/goutils/LICENSE.txt b/vendor/github.com/Masterminds/goutils/LICENSE.txt
new file mode 100644
index 0000000000..d645695673
--- /dev/null
+++ b/vendor/github.com/Masterminds/goutils/LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/vendor/github.com/Masterminds/goutils/README.md b/vendor/github.com/Masterminds/goutils/README.md
new file mode 100644
index 0000000000..163ffe72a8
--- /dev/null
+++ b/vendor/github.com/Masterminds/goutils/README.md
@@ -0,0 +1,70 @@
+GoUtils
+===========
+[](https://masterminds.github.io/stability/maintenance.html)
+[](https://godoc.org/github.com/Masterminds/goutils) [](https://travis-ci.org/Masterminds/goutils) [](https://ci.appveyor.com/project/mattfarina/goutils)
+
+
+GoUtils provides users with utility functions to manipulate strings in various ways. It is a Go implementation of some
+string manipulation libraries of Java Apache Commons. GoUtils includes the following Java Apache Commons classes:
+* WordUtils
+* RandomStringUtils
+* StringUtils (partial implementation)
+
+## Installation
+If you have Go set up on your system, from the GOPATH directory within the command line/terminal, enter this:
+
+ go get github.com/Masterminds/goutils
+
+If you do not have Go set up on your system, please follow the [Go installation directions from the documenation](http://golang.org/doc/install), and then follow the instructions above to install GoUtils.
+
+
+## Documentation
+GoUtils doc is available here: [](https://godoc.org/github.com/Masterminds/goutils)
+
+
+## Usage
+The code snippets below show examples of how to use GoUtils. Some functions return errors while others do not. The first instance below, which does not return an error, is the `Initials` function (located within the `wordutils.go` file).
+
+ package main
+
+ import (
+ "fmt"
+ "github.com/Masterminds/goutils"
+ )
+
+ func main() {
+
+ // EXAMPLE 1: A goutils function which returns no errors
+ fmt.Println (goutils.Initials("John Doe Foo")) // Prints out "JDF"
+
+ }
+Some functions return errors mainly due to illegal arguements used as parameters. The code example below illustrates how to deal with function that returns an error. In this instance, the function is the `Random` function (located within the `randomstringutils.go` file).
+
+ package main
+
+ import (
+ "fmt"
+ "github.com/Masterminds/goutils"
+ )
+
+ func main() {
+
+ // EXAMPLE 2: A goutils function which returns an error
+ rand1, err1 := goutils.Random (-1, 0, 0, true, true)
+
+ if err1 != nil {
+ fmt.Println(err1) // Prints out error message because -1 was entered as the first parameter in goutils.Random(...)
+ } else {
+ fmt.Println(rand1)
+ }
+
+ }
+
+## License
+GoUtils is licensed under the Apache License, Version 2.0. Please check the LICENSE.txt file or visit http://www.apache.org/licenses/LICENSE-2.0 for a copy of the license.
+
+## Issue Reporting
+Make suggestions or report issues using the Git issue tracker: https://github.com/Masterminds/goutils/issues
+
+## Website
+* [GoUtils webpage](http://Masterminds.github.io/goutils/)
diff --git a/vendor/github.com/Masterminds/goutils/appveyor.yml b/vendor/github.com/Masterminds/goutils/appveyor.yml
new file mode 100644
index 0000000000..657564a847
--- /dev/null
+++ b/vendor/github.com/Masterminds/goutils/appveyor.yml
@@ -0,0 +1,21 @@
+version: build-{build}.{branch}
+
+clone_folder: C:\gopath\src\github.com\Masterminds\goutils
+shallow_clone: true
+
+environment:
+ GOPATH: C:\gopath
+
+platform:
+ - x64
+
+build: off
+
+install:
+ - go version
+ - go env
+
+test_script:
+ - go test -v
+
+deploy: off
diff --git a/vendor/github.com/Masterminds/goutils/cryptorandomstringutils.go b/vendor/github.com/Masterminds/goutils/cryptorandomstringutils.go
new file mode 100644
index 0000000000..8dbd924858
--- /dev/null
+++ b/vendor/github.com/Masterminds/goutils/cryptorandomstringutils.go
@@ -0,0 +1,230 @@
+/*
+Copyright 2014 Alexander Okoli
+
+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 goutils
+
+import (
+ "crypto/rand"
+ "fmt"
+ "math"
+ "math/big"
+ "unicode"
+)
+
+/*
+CryptoRandomNonAlphaNumeric creates a random string whose length is the number of characters specified.
+Characters will be chosen from the set of all characters (ASCII/Unicode values between 0 to 2,147,483,647 (math.MaxInt32)).
+
+Parameter:
+ count - the length of random string to create
+
+Returns:
+ string - the random string
+ error - an error stemming from an invalid parameter within underlying function, CryptoRandom(...)
+*/
+func CryptoRandomNonAlphaNumeric(count int) (string, error) {
+ return CryptoRandomAlphaNumericCustom(count, false, false)
+}
+
+/*
+CryptoRandomAscii creates a random string whose length is the number of characters specified.
+Characters will be chosen from the set of characters whose ASCII value is between 32 and 126 (inclusive).
+
+Parameter:
+ count - the length of random string to create
+
+Returns:
+ string - the random string
+ error - an error stemming from an invalid parameter within underlying function, CryptoRandom(...)
+*/
+func CryptoRandomAscii(count int) (string, error) {
+ return CryptoRandom(count, 32, 127, false, false)
+}
+
+/*
+CryptoRandomNumeric creates a random string whose length is the number of characters specified.
+Characters will be chosen from the set of numeric characters.
+
+Parameter:
+ count - the length of random string to create
+
+Returns:
+ string - the random string
+ error - an error stemming from an invalid parameter within underlying function, CryptoRandom(...)
+*/
+func CryptoRandomNumeric(count int) (string, error) {
+ return CryptoRandom(count, 0, 0, false, true)
+}
+
+/*
+CryptoRandomAlphabetic creates a random string whose length is the number of characters specified.
+Characters will be chosen from the set of alpha-numeric characters as indicated by the arguments.
+
+Parameters:
+ count - the length of random string to create
+ letters - if true, generated string may include alphabetic characters
+ numbers - if true, generated string may include numeric characters
+
+Returns:
+ string - the random string
+ error - an error stemming from an invalid parameter within underlying function, CryptoRandom(...)
+*/
+func CryptoRandomAlphabetic(count int) (string, error) {
+ return CryptoRandom(count, 0, 0, true, false)
+}
+
+/*
+CryptoRandomAlphaNumeric creates a random string whose length is the number of characters specified.
+Characters will be chosen from the set of alpha-numeric characters.
+
+Parameter:
+ count - the length of random string to create
+
+Returns:
+ string - the random string
+ error - an error stemming from an invalid parameter within underlying function, CryptoRandom(...)
+*/
+func CryptoRandomAlphaNumeric(count int) (string, error) {
+ return CryptoRandom(count, 0, 0, true, true)
+}
+
+/*
+CryptoRandomAlphaNumericCustom creates a random string whose length is the number of characters specified.
+Characters will be chosen from the set of alpha-numeric characters as indicated by the arguments.
+
+Parameters:
+ count - the length of random string to create
+ letters - if true, generated string may include alphabetic characters
+ numbers - if true, generated string may include numeric characters
+
+Returns:
+ string - the random string
+ error - an error stemming from an invalid parameter within underlying function, CryptoRandom(...)
+*/
+func CryptoRandomAlphaNumericCustom(count int, letters bool, numbers bool) (string, error) {
+ return CryptoRandom(count, 0, 0, letters, numbers)
+}
+
+/*
+CryptoRandom creates a random string based on a variety of options, using using golang's crypto/rand source of randomness.
+If the parameters start and end are both 0, start and end are set to ' ' and 'z', the ASCII printable characters, will be used,
+unless letters and numbers are both false, in which case, start and end are set to 0 and math.MaxInt32, respectively.
+If chars is not nil, characters stored in chars that are between start and end are chosen.
+
+Parameters:
+ count - the length of random string to create
+ start - the position in set of chars (ASCII/Unicode int) to start at
+ end - the position in set of chars (ASCII/Unicode int) to end before
+ letters - if true, generated string may include alphabetic characters
+ numbers - if true, generated string may include numeric characters
+ chars - the set of chars to choose randoms from. If nil, then it will use the set of all chars.
+
+Returns:
+ string - the random string
+ error - an error stemming from invalid parameters: if count < 0; or the provided chars array is empty; or end <= start; or end > len(chars)
+*/
+func CryptoRandom(count int, start int, end int, letters bool, numbers bool, chars ...rune) (string, error) {
+ if count == 0 {
+ return "", nil
+ } else if count < 0 {
+ err := fmt.Errorf("randomstringutils illegal argument: Requested random string length %v is less than 0.", count) // equiv to err := errors.New("...")
+ return "", err
+ }
+ if chars != nil && len(chars) == 0 {
+ err := fmt.Errorf("randomstringutils illegal argument: The chars array must not be empty")
+ return "", err
+ }
+
+ if start == 0 && end == 0 {
+ if chars != nil {
+ end = len(chars)
+ } else {
+ if !letters && !numbers {
+ end = math.MaxInt32
+ } else {
+ end = 'z' + 1
+ start = ' '
+ }
+ }
+ } else {
+ if end <= start {
+ err := fmt.Errorf("randomstringutils illegal argument: Parameter end (%v) must be greater than start (%v)", end, start)
+ return "", err
+ }
+
+ if chars != nil && end > len(chars) {
+ err := fmt.Errorf("randomstringutils illegal argument: Parameter end (%v) cannot be greater than len(chars) (%v)", end, len(chars))
+ return "", err
+ }
+ }
+
+ buffer := make([]rune, count)
+ gap := end - start
+
+ // high-surrogates range, (\uD800-\uDBFF) = 55296 - 56319
+ // low-surrogates range, (\uDC00-\uDFFF) = 56320 - 57343
+
+ for count != 0 {
+ count--
+ var ch rune
+ if chars == nil {
+ ch = rune(getCryptoRandomInt(gap) + int64(start))
+ } else {
+ ch = chars[getCryptoRandomInt(gap)+int64(start)]
+ }
+
+ if letters && unicode.IsLetter(ch) || numbers && unicode.IsDigit(ch) || !letters && !numbers {
+ if ch >= 56320 && ch <= 57343 { // low surrogate range
+ if count == 0 {
+ count++
+ } else {
+ // Insert low surrogate
+ buffer[count] = ch
+ count--
+ // Insert high surrogate
+ buffer[count] = rune(55296 + getCryptoRandomInt(128))
+ }
+ } else if ch >= 55296 && ch <= 56191 { // High surrogates range (Partial)
+ if count == 0 {
+ count++
+ } else {
+ // Insert low surrogate
+ buffer[count] = rune(56320 + getCryptoRandomInt(128))
+ count--
+ // Insert high surrogate
+ buffer[count] = ch
+ }
+ } else if ch >= 56192 && ch <= 56319 {
+ // private high surrogate, skip it
+ count++
+ } else {
+ // not one of the surrogates*
+ buffer[count] = ch
+ }
+ } else {
+ count++
+ }
+ }
+ return string(buffer), nil
+}
+
+func getCryptoRandomInt(count int) int64 {
+ nBig, err := rand.Int(rand.Reader, big.NewInt(int64(count)))
+ if err != nil {
+ panic(err)
+ }
+ return nBig.Int64()
+}
diff --git a/vendor/github.com/Masterminds/goutils/randomstringutils.go b/vendor/github.com/Masterminds/goutils/randomstringutils.go
new file mode 100644
index 0000000000..272670231a
--- /dev/null
+++ b/vendor/github.com/Masterminds/goutils/randomstringutils.go
@@ -0,0 +1,248 @@
+/*
+Copyright 2014 Alexander Okoli
+
+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 goutils
+
+import (
+ "fmt"
+ "math"
+ "math/rand"
+ "time"
+ "unicode"
+)
+
+// RANDOM provides the time-based seed used to generate random numbers
+var RANDOM = rand.New(rand.NewSource(time.Now().UnixNano()))
+
+/*
+RandomNonAlphaNumeric creates a random string whose length is the number of characters specified.
+Characters will be chosen from the set of all characters (ASCII/Unicode values between 0 to 2,147,483,647 (math.MaxInt32)).
+
+Parameter:
+ count - the length of random string to create
+
+Returns:
+ string - the random string
+ error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
+*/
+func RandomNonAlphaNumeric(count int) (string, error) {
+ return RandomAlphaNumericCustom(count, false, false)
+}
+
+/*
+RandomAscii creates a random string whose length is the number of characters specified.
+Characters will be chosen from the set of characters whose ASCII value is between 32 and 126 (inclusive).
+
+Parameter:
+ count - the length of random string to create
+
+Returns:
+ string - the random string
+ error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
+*/
+func RandomAscii(count int) (string, error) {
+ return Random(count, 32, 127, false, false)
+}
+
+/*
+RandomNumeric creates a random string whose length is the number of characters specified.
+Characters will be chosen from the set of numeric characters.
+
+Parameter:
+ count - the length of random string to create
+
+Returns:
+ string - the random string
+ error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
+*/
+func RandomNumeric(count int) (string, error) {
+ return Random(count, 0, 0, false, true)
+}
+
+/*
+RandomAlphabetic creates a random string whose length is the number of characters specified.
+Characters will be chosen from the set of alphabetic characters.
+
+Parameters:
+ count - the length of random string to create
+
+Returns:
+ string - the random string
+ error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
+*/
+func RandomAlphabetic(count int) (string, error) {
+ return Random(count, 0, 0, true, false)
+}
+
+/*
+RandomAlphaNumeric creates a random string whose length is the number of characters specified.
+Characters will be chosen from the set of alpha-numeric characters.
+
+Parameter:
+ count - the length of random string to create
+
+Returns:
+ string - the random string
+ error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
+*/
+func RandomAlphaNumeric(count int) (string, error) {
+ return Random(count, 0, 0, true, true)
+}
+
+/*
+RandomAlphaNumericCustom creates a random string whose length is the number of characters specified.
+Characters will be chosen from the set of alpha-numeric characters as indicated by the arguments.
+
+Parameters:
+ count - the length of random string to create
+ letters - if true, generated string may include alphabetic characters
+ numbers - if true, generated string may include numeric characters
+
+Returns:
+ string - the random string
+ error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
+*/
+func RandomAlphaNumericCustom(count int, letters bool, numbers bool) (string, error) {
+ return Random(count, 0, 0, letters, numbers)
+}
+
+/*
+Random creates a random string based on a variety of options, using default source of randomness.
+This method has exactly the same semantics as RandomSeed(int, int, int, bool, bool, []char, *rand.Rand), but
+instead of using an externally supplied source of randomness, it uses the internal *rand.Rand instance.
+
+Parameters:
+ count - the length of random string to create
+ start - the position in set of chars (ASCII/Unicode int) to start at
+ end - the position in set of chars (ASCII/Unicode int) to end before
+ letters - if true, generated string may include alphabetic characters
+ numbers - if true, generated string may include numeric characters
+ chars - the set of chars to choose randoms from. If nil, then it will use the set of all chars.
+
+Returns:
+ string - the random string
+ error - an error stemming from an invalid parameter within underlying function, RandomSeed(...)
+*/
+func Random(count int, start int, end int, letters bool, numbers bool, chars ...rune) (string, error) {
+ return RandomSeed(count, start, end, letters, numbers, chars, RANDOM)
+}
+
+/*
+RandomSeed creates a random string based on a variety of options, using supplied source of randomness.
+If the parameters start and end are both 0, start and end are set to ' ' and 'z', the ASCII printable characters, will be used,
+unless letters and numbers are both false, in which case, start and end are set to 0 and math.MaxInt32, respectively.
+If chars is not nil, characters stored in chars that are between start and end are chosen.
+This method accepts a user-supplied *rand.Rand instance to use as a source of randomness. By seeding a single *rand.Rand instance
+with a fixed seed and using it for each call, the same random sequence of strings can be generated repeatedly and predictably.
+
+Parameters:
+ count - the length of random string to create
+ start - the position in set of chars (ASCII/Unicode decimals) to start at
+ end - the position in set of chars (ASCII/Unicode decimals) to end before
+ letters - if true, generated string may include alphabetic characters
+ numbers - if true, generated string may include numeric characters
+ chars - the set of chars to choose randoms from. If nil, then it will use the set of all chars.
+ random - a source of randomness.
+
+Returns:
+ string - the random string
+ error - an error stemming from invalid parameters: if count < 0; or the provided chars array is empty; or end <= start; or end > len(chars)
+*/
+func RandomSeed(count int, start int, end int, letters bool, numbers bool, chars []rune, random *rand.Rand) (string, error) {
+
+ if count == 0 {
+ return "", nil
+ } else if count < 0 {
+ err := fmt.Errorf("randomstringutils illegal argument: Requested random string length %v is less than 0.", count) // equiv to err := errors.New("...")
+ return "", err
+ }
+ if chars != nil && len(chars) == 0 {
+ err := fmt.Errorf("randomstringutils illegal argument: The chars array must not be empty")
+ return "", err
+ }
+
+ if start == 0 && end == 0 {
+ if chars != nil {
+ end = len(chars)
+ } else {
+ if !letters && !numbers {
+ end = math.MaxInt32
+ } else {
+ end = 'z' + 1
+ start = ' '
+ }
+ }
+ } else {
+ if end <= start {
+ err := fmt.Errorf("randomstringutils illegal argument: Parameter end (%v) must be greater than start (%v)", end, start)
+ return "", err
+ }
+
+ if chars != nil && end > len(chars) {
+ err := fmt.Errorf("randomstringutils illegal argument: Parameter end (%v) cannot be greater than len(chars) (%v)", end, len(chars))
+ return "", err
+ }
+ }
+
+ buffer := make([]rune, count)
+ gap := end - start
+
+ // high-surrogates range, (\uD800-\uDBFF) = 55296 - 56319
+ // low-surrogates range, (\uDC00-\uDFFF) = 56320 - 57343
+
+ for count != 0 {
+ count--
+ var ch rune
+ if chars == nil {
+ ch = rune(random.Intn(gap) + start)
+ } else {
+ ch = chars[random.Intn(gap)+start]
+ }
+
+ if letters && unicode.IsLetter(ch) || numbers && unicode.IsDigit(ch) || !letters && !numbers {
+ if ch >= 56320 && ch <= 57343 { // low surrogate range
+ if count == 0 {
+ count++
+ } else {
+ // Insert low surrogate
+ buffer[count] = ch
+ count--
+ // Insert high surrogate
+ buffer[count] = rune(55296 + random.Intn(128))
+ }
+ } else if ch >= 55296 && ch <= 56191 { // High surrogates range (Partial)
+ if count == 0 {
+ count++
+ } else {
+ // Insert low surrogate
+ buffer[count] = rune(56320 + random.Intn(128))
+ count--
+ // Insert high surrogate
+ buffer[count] = ch
+ }
+ } else if ch >= 56192 && ch <= 56319 {
+ // private high surrogate, skip it
+ count++
+ } else {
+ // not one of the surrogates*
+ buffer[count] = ch
+ }
+ } else {
+ count++
+ }
+ }
+ return string(buffer), nil
+}
diff --git a/vendor/github.com/Masterminds/goutils/stringutils.go b/vendor/github.com/Masterminds/goutils/stringutils.go
new file mode 100644
index 0000000000..741bb530e8
--- /dev/null
+++ b/vendor/github.com/Masterminds/goutils/stringutils.go
@@ -0,0 +1,240 @@
+/*
+Copyright 2014 Alexander Okoli
+
+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 goutils
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+ "unicode"
+)
+
+// Typically returned by functions where a searched item cannot be found
+const INDEX_NOT_FOUND = -1
+
+/*
+Abbreviate abbreviates a string using ellipses. This will turn the string "Now is the time for all good men" into "Now is the time for..."
+
+Specifically, the algorithm is as follows:
+
+ - If str is less than maxWidth characters long, return it.
+ - Else abbreviate it to (str[0:maxWidth - 3] + "...").
+ - If maxWidth is less than 4, return an illegal argument error.
+ - In no case will it return a string of length greater than maxWidth.
+
+Parameters:
+ str - the string to check
+ maxWidth - maximum length of result string, must be at least 4
+
+Returns:
+ string - abbreviated string
+ error - if the width is too small
+*/
+func Abbreviate(str string, maxWidth int) (string, error) {
+ return AbbreviateFull(str, 0, maxWidth)
+}
+
+/*
+AbbreviateFull abbreviates a string using ellipses. This will turn the string "Now is the time for all good men" into "...is the time for..."
+This function works like Abbreviate(string, int), but allows you to specify a "left edge" offset. Note that this left edge is not
+necessarily going to be the leftmost character in the result, or the first character following the ellipses, but it will appear
+somewhere in the result.
+In no case will it return a string of length greater than maxWidth.
+
+Parameters:
+ str - the string to check
+ offset - left edge of source string
+ maxWidth - maximum length of result string, must be at least 4
+
+Returns:
+ string - abbreviated string
+ error - if the width is too small
+*/
+func AbbreviateFull(str string, offset int, maxWidth int) (string, error) {
+ if str == "" {
+ return "", nil
+ }
+ if maxWidth < 4 {
+ err := fmt.Errorf("stringutils illegal argument: Minimum abbreviation width is 4")
+ return "", err
+ }
+ if len(str) <= maxWidth {
+ return str, nil
+ }
+ if offset > len(str) {
+ offset = len(str)
+ }
+ if len(str)-offset < (maxWidth - 3) { // 15 - 5 < 10 - 3 = 10 < 7
+ offset = len(str) - (maxWidth - 3)
+ }
+ abrevMarker := "..."
+ if offset <= 4 {
+ return str[0:maxWidth-3] + abrevMarker, nil // str.substring(0, maxWidth - 3) + abrevMarker;
+ }
+ if maxWidth < 7 {
+ err := fmt.Errorf("stringutils illegal argument: Minimum abbreviation width with offset is 7")
+ return "", err
+ }
+ if (offset + maxWidth - 3) < len(str) { // 5 + (10-3) < 15 = 12 < 15
+ abrevStr, _ := Abbreviate(str[offset:len(str)], (maxWidth - 3))
+ return abrevMarker + abrevStr, nil // abrevMarker + abbreviate(str.substring(offset), maxWidth - 3);
+ }
+ return abrevMarker + str[(len(str)-(maxWidth-3)):len(str)], nil // abrevMarker + str.substring(str.length() - (maxWidth - 3));
+}
+
+/*
+DeleteWhiteSpace deletes all whitespaces from a string as defined by unicode.IsSpace(rune).
+It returns the string without whitespaces.
+
+Parameter:
+ str - the string to delete whitespace from, may be nil
+
+Returns:
+ the string without whitespaces
+*/
+func DeleteWhiteSpace(str string) string {
+ if str == "" {
+ return str
+ }
+ sz := len(str)
+ var chs bytes.Buffer
+ count := 0
+ for i := 0; i < sz; i++ {
+ ch := rune(str[i])
+ if !unicode.IsSpace(ch) {
+ chs.WriteRune(ch)
+ count++
+ }
+ }
+ if count == sz {
+ return str
+ }
+ return chs.String()
+}
+
+/*
+IndexOfDifference compares two strings, and returns the index at which the strings begin to differ.
+
+Parameters:
+ str1 - the first string
+ str2 - the second string
+
+Returns:
+ the index where str1 and str2 begin to differ; -1 if they are equal
+*/
+func IndexOfDifference(str1 string, str2 string) int {
+ if str1 == str2 {
+ return INDEX_NOT_FOUND
+ }
+ if IsEmpty(str1) || IsEmpty(str2) {
+ return 0
+ }
+ var i int
+ for i = 0; i < len(str1) && i < len(str2); i++ {
+ if rune(str1[i]) != rune(str2[i]) {
+ break
+ }
+ }
+ if i < len(str2) || i < len(str1) {
+ return i
+ }
+ return INDEX_NOT_FOUND
+}
+
+/*
+IsBlank checks if a string is whitespace or empty (""). Observe the following behavior:
+
+ goutils.IsBlank("") = true
+ goutils.IsBlank(" ") = true
+ goutils.IsBlank("bob") = false
+ goutils.IsBlank(" bob ") = false
+
+Parameter:
+ str - the string to check
+
+Returns:
+ true - if the string is whitespace or empty ("")
+*/
+func IsBlank(str string) bool {
+ strLen := len(str)
+ if str == "" || strLen == 0 {
+ return true
+ }
+ for i := 0; i < strLen; i++ {
+ if unicode.IsSpace(rune(str[i])) == false {
+ return false
+ }
+ }
+ return true
+}
+
+/*
+IndexOf returns the index of the first instance of sub in str, with the search beginning from the
+index start point specified. -1 is returned if sub is not present in str.
+
+An empty string ("") will return -1 (INDEX_NOT_FOUND). A negative start position is treated as zero.
+A start position greater than the string length returns -1.
+
+Parameters:
+ str - the string to check
+ sub - the substring to find
+ start - the start position; negative treated as zero
+
+Returns:
+ the first index where the sub string was found (always >= start)
+*/
+func IndexOf(str string, sub string, start int) int {
+
+ if start < 0 {
+ start = 0
+ }
+
+ if len(str) < start {
+ return INDEX_NOT_FOUND
+ }
+
+ if IsEmpty(str) || IsEmpty(sub) {
+ return INDEX_NOT_FOUND
+ }
+
+ partialIndex := strings.Index(str[start:len(str)], sub)
+ if partialIndex == -1 {
+ return INDEX_NOT_FOUND
+ }
+ return partialIndex + start
+}
+
+// IsEmpty checks if a string is empty (""). Returns true if empty, and false otherwise.
+func IsEmpty(str string) bool {
+ return len(str) == 0
+}
+
+// Returns either the passed in string, or if the string is empty, the value of defaultStr.
+func DefaultString(str string, defaultStr string) string {
+ if IsEmpty(str) {
+ return defaultStr
+ }
+ return str
+}
+
+// Returns either the passed in string, or if the string is whitespace, empty (""), the value of defaultStr.
+func DefaultIfBlank(str string, defaultStr string) string {
+ if IsBlank(str) {
+ return defaultStr
+ }
+ return str
+}
diff --git a/vendor/github.com/Masterminds/goutils/wordutils.go b/vendor/github.com/Masterminds/goutils/wordutils.go
new file mode 100644
index 0000000000..034cad8e21
--- /dev/null
+++ b/vendor/github.com/Masterminds/goutils/wordutils.go
@@ -0,0 +1,357 @@
+/*
+Copyright 2014 Alexander Okoli
+
+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 goutils provides utility functions to manipulate strings in various ways.
+The code snippets below show examples of how to use goutils. Some functions return
+errors while others do not, so usage would vary as a result.
+
+Example:
+
+ package main
+
+ import (
+ "fmt"
+ "github.com/aokoli/goutils"
+ )
+
+ func main() {
+
+ // EXAMPLE 1: A goutils function which returns no errors
+ fmt.Println (goutils.Initials("John Doe Foo")) // Prints out "JDF"
+
+
+
+ // EXAMPLE 2: A goutils function which returns an error
+ rand1, err1 := goutils.Random (-1, 0, 0, true, true)
+
+ if err1 != nil {
+ fmt.Println(err1) // Prints out error message because -1 was entered as the first parameter in goutils.Random(...)
+ } else {
+ fmt.Println(rand1)
+ }
+ }
+*/
+package goutils
+
+import (
+ "bytes"
+ "strings"
+ "unicode"
+)
+
+// VERSION indicates the current version of goutils
+const VERSION = "1.0.0"
+
+/*
+Wrap wraps a single line of text, identifying words by ' '.
+New lines will be separated by '\n'. Very long words, such as URLs will not be wrapped.
+Leading spaces on a new line are stripped. Trailing spaces are not stripped.
+
+Parameters:
+ str - the string to be word wrapped
+ wrapLength - the column (a column can fit only one character) to wrap the words at, less than 1 is treated as 1
+
+Returns:
+ a line with newlines inserted
+*/
+func Wrap(str string, wrapLength int) string {
+ return WrapCustom(str, wrapLength, "", false)
+}
+
+/*
+WrapCustom wraps a single line of text, identifying words by ' '.
+Leading spaces on a new line are stripped. Trailing spaces are not stripped.
+
+Parameters:
+ str - the string to be word wrapped
+ wrapLength - the column number (a column can fit only one character) to wrap the words at, less than 1 is treated as 1
+ newLineStr - the string to insert for a new line, "" uses '\n'
+ wrapLongWords - true if long words (such as URLs) should be wrapped
+
+Returns:
+ a line with newlines inserted
+*/
+func WrapCustom(str string, wrapLength int, newLineStr string, wrapLongWords bool) string {
+
+ if str == "" {
+ return ""
+ }
+ if newLineStr == "" {
+ newLineStr = "\n" // TODO Assumes "\n" is seperator. Explore SystemUtils.LINE_SEPARATOR from Apache Commons
+ }
+ if wrapLength < 1 {
+ wrapLength = 1
+ }
+
+ inputLineLength := len(str)
+ offset := 0
+
+ var wrappedLine bytes.Buffer
+
+ for inputLineLength-offset > wrapLength {
+
+ if rune(str[offset]) == ' ' {
+ offset++
+ continue
+ }
+
+ end := wrapLength + offset + 1
+ spaceToWrapAt := strings.LastIndex(str[offset:end], " ") + offset
+
+ if spaceToWrapAt >= offset {
+ // normal word (not longer than wrapLength)
+ wrappedLine.WriteString(str[offset:spaceToWrapAt])
+ wrappedLine.WriteString(newLineStr)
+ offset = spaceToWrapAt + 1
+
+ } else {
+ // long word or URL
+ if wrapLongWords {
+ end := wrapLength + offset
+ // long words are wrapped one line at a time
+ wrappedLine.WriteString(str[offset:end])
+ wrappedLine.WriteString(newLineStr)
+ offset += wrapLength
+ } else {
+ // long words aren't wrapped, just extended beyond limit
+ end := wrapLength + offset
+ index := strings.IndexRune(str[end:len(str)], ' ')
+ if index == -1 {
+ wrappedLine.WriteString(str[offset:len(str)])
+ offset = inputLineLength
+ } else {
+ spaceToWrapAt = index + end
+ wrappedLine.WriteString(str[offset:spaceToWrapAt])
+ wrappedLine.WriteString(newLineStr)
+ offset = spaceToWrapAt + 1
+ }
+ }
+ }
+ }
+
+ wrappedLine.WriteString(str[offset:len(str)])
+
+ return wrappedLine.String()
+
+}
+
+/*
+Capitalize capitalizes all the delimiter separated words in a string. Only the first letter of each word is changed.
+To convert the rest of each word to lowercase at the same time, use CapitalizeFully(str string, delimiters ...rune).
+The delimiters represent a set of characters understood to separate words. The first string character
+and the first non-delimiter character after a delimiter will be capitalized. A "" input string returns "".
+Capitalization uses the Unicode title case, normally equivalent to upper case.
+
+Parameters:
+ str - the string to capitalize
+ delimiters - set of characters to determine capitalization, exclusion of this parameter means whitespace would be delimeter
+
+Returns:
+ capitalized string
+*/
+func Capitalize(str string, delimiters ...rune) string {
+
+ var delimLen int
+
+ if delimiters == nil {
+ delimLen = -1
+ } else {
+ delimLen = len(delimiters)
+ }
+
+ if str == "" || delimLen == 0 {
+ return str
+ }
+
+ buffer := []rune(str)
+ capitalizeNext := true
+ for i := 0; i < len(buffer); i++ {
+ ch := buffer[i]
+ if isDelimiter(ch, delimiters...) {
+ capitalizeNext = true
+ } else if capitalizeNext {
+ buffer[i] = unicode.ToTitle(ch)
+ capitalizeNext = false
+ }
+ }
+ return string(buffer)
+
+}
+
+/*
+CapitalizeFully converts all the delimiter separated words in a string into capitalized words, that is each word is made up of a
+titlecase character and then a series of lowercase characters. The delimiters represent a set of characters understood
+to separate words. The first string character and the first non-delimiter character after a delimiter will be capitalized.
+Capitalization uses the Unicode title case, normally equivalent to upper case.
+
+Parameters:
+ str - the string to capitalize fully
+ delimiters - set of characters to determine capitalization, exclusion of this parameter means whitespace would be delimeter
+
+Returns:
+ capitalized string
+*/
+func CapitalizeFully(str string, delimiters ...rune) string {
+
+ var delimLen int
+
+ if delimiters == nil {
+ delimLen = -1
+ } else {
+ delimLen = len(delimiters)
+ }
+
+ if str == "" || delimLen == 0 {
+ return str
+ }
+ str = strings.ToLower(str)
+ return Capitalize(str, delimiters...)
+}
+
+/*
+Uncapitalize uncapitalizes all the whitespace separated words in a string. Only the first letter of each word is changed.
+The delimiters represent a set of characters understood to separate words. The first string character and the first non-delimiter
+character after a delimiter will be uncapitalized. Whitespace is defined by unicode.IsSpace(char).
+
+Parameters:
+ str - the string to uncapitalize fully
+ delimiters - set of characters to determine capitalization, exclusion of this parameter means whitespace would be delimeter
+
+Returns:
+ uncapitalized string
+*/
+func Uncapitalize(str string, delimiters ...rune) string {
+
+ var delimLen int
+
+ if delimiters == nil {
+ delimLen = -1
+ } else {
+ delimLen = len(delimiters)
+ }
+
+ if str == "" || delimLen == 0 {
+ return str
+ }
+
+ buffer := []rune(str)
+ uncapitalizeNext := true // TODO Always makes capitalize/un apply to first char.
+ for i := 0; i < len(buffer); i++ {
+ ch := buffer[i]
+ if isDelimiter(ch, delimiters...) {
+ uncapitalizeNext = true
+ } else if uncapitalizeNext {
+ buffer[i] = unicode.ToLower(ch)
+ uncapitalizeNext = false
+ }
+ }
+ return string(buffer)
+}
+
+/*
+SwapCase swaps the case of a string using a word based algorithm.
+
+Conversion algorithm:
+
+ Upper case character converts to Lower case
+ Title case character converts to Lower case
+ Lower case character after Whitespace or at start converts to Title case
+ Other Lower case character converts to Upper case
+ Whitespace is defined by unicode.IsSpace(char).
+
+Parameters:
+ str - the string to swap case
+
+Returns:
+ the changed string
+*/
+func SwapCase(str string) string {
+ if str == "" {
+ return str
+ }
+ buffer := []rune(str)
+
+ whitespace := true
+
+ for i := 0; i < len(buffer); i++ {
+ ch := buffer[i]
+ if unicode.IsUpper(ch) {
+ buffer[i] = unicode.ToLower(ch)
+ whitespace = false
+ } else if unicode.IsTitle(ch) {
+ buffer[i] = unicode.ToLower(ch)
+ whitespace = false
+ } else if unicode.IsLower(ch) {
+ if whitespace {
+ buffer[i] = unicode.ToTitle(ch)
+ whitespace = false
+ } else {
+ buffer[i] = unicode.ToUpper(ch)
+ }
+ } else {
+ whitespace = unicode.IsSpace(ch)
+ }
+ }
+ return string(buffer)
+}
+
+/*
+Initials extracts the initial letters from each word in the string. The first letter of the string and all first
+letters after the defined delimiters are returned as a new string. Their case is not changed. If the delimiters
+parameter is excluded, then Whitespace is used. Whitespace is defined by unicode.IsSpacea(char). An empty delimiter array returns an empty string.
+
+Parameters:
+ str - the string to get initials from
+ delimiters - set of characters to determine words, exclusion of this parameter means whitespace would be delimeter
+Returns:
+ string of initial letters
+*/
+func Initials(str string, delimiters ...rune) string {
+ if str == "" {
+ return str
+ }
+ if delimiters != nil && len(delimiters) == 0 {
+ return ""
+ }
+ strLen := len(str)
+ var buf bytes.Buffer
+ lastWasGap := true
+ for i := 0; i < strLen; i++ {
+ ch := rune(str[i])
+
+ if isDelimiter(ch, delimiters...) {
+ lastWasGap = true
+ } else if lastWasGap {
+ buf.WriteRune(ch)
+ lastWasGap = false
+ }
+ }
+ return buf.String()
+}
+
+// private function (lower case func name)
+func isDelimiter(ch rune, delimiters ...rune) bool {
+ if delimiters == nil {
+ return unicode.IsSpace(ch)
+ }
+ for _, delimiter := range delimiters {
+ if ch == delimiter {
+ return true
+ }
+ }
+ return false
+}
diff --git a/vendor/github.com/Masterminds/semver/v3/.gitignore b/vendor/github.com/Masterminds/semver/v3/.gitignore
new file mode 100644
index 0000000000..6b061e6174
--- /dev/null
+++ b/vendor/github.com/Masterminds/semver/v3/.gitignore
@@ -0,0 +1 @@
+_fuzz/
\ No newline at end of file
diff --git a/vendor/github.com/Masterminds/semver/v3/.golangci.yml b/vendor/github.com/Masterminds/semver/v3/.golangci.yml
new file mode 100644
index 0000000000..fbc6332592
--- /dev/null
+++ b/vendor/github.com/Masterminds/semver/v3/.golangci.yml
@@ -0,0 +1,27 @@
+run:
+ deadline: 2m
+
+linters:
+ disable-all: true
+ enable:
+ - misspell
+ - govet
+ - staticcheck
+ - errcheck
+ - unparam
+ - ineffassign
+ - nakedret
+ - gocyclo
+ - dupl
+ - goimports
+ - revive
+ - gosec
+ - gosimple
+ - typecheck
+ - unused
+
+linters-settings:
+ gofmt:
+ simplify: true
+ dupl:
+ threshold: 600
diff --git a/vendor/github.com/Masterminds/semver/v3/CHANGELOG.md b/vendor/github.com/Masterminds/semver/v3/CHANGELOG.md
new file mode 100644
index 0000000000..fabe5e43dc
--- /dev/null
+++ b/vendor/github.com/Masterminds/semver/v3/CHANGELOG.md
@@ -0,0 +1,268 @@
+# Changelog
+
+## 3.4.0 (2025-06-27)
+
+### Added
+
+- #268: Added property to Constraints to include prereleases for Check and Validate
+
+### Changed
+
+- #263: Updated Go testing for 1.24, 1.23, and 1.22
+- #269: Updated the error message handling for message case and wrapping errors
+- #266: Restore the ability to have leading 0's when parsing with NewVersion.
+ Opt-out of this by setting CoerceNewVersion to false.
+
+### Fixed
+
+- #257: Fixed the CodeQL link (thanks @dmitris)
+- #262: Restored detailed errors when failed to parse with NewVersion. Opt-out
+ of this by setting DetailedNewVersionErrors to false for faster performance.
+- #267: Handle pre-releases for an "and" group if one constraint includes them
+
+## 3.3.1 (2024-11-19)
+
+### Fixed
+
+- #253: Fix for allowing some version that were invalid
+
+## 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
+
+- #190: Added text marshaling and unmarshaling
+- #167: Added JSON marshalling for constraints (thanks @SimonTheLeg)
+- #173: Implement encoding.TextMarshaler and encoding.TextUnmarshaler on Version (thanks @MarkRosemaker)
+- #179: Added New() version constructor (thanks @kazhuravlev)
+
+### Changed
+
+- #182/#183: Updated CI testing setup
+
+### Fixed
+
+- #186: Fixing issue where validation of constraint section gave false positives
+- #176: Fix constraints check with *-0 (thanks @mtt0)
+- #181: Fixed Caret operator (^) gives unexpected results when the minor version in constraint is 0 (thanks @arshchimni)
+- #161: Fixed godoc (thanks @afirth)
+
+## 3.1.1 (2020-11-23)
+
+### Fixed
+
+- #158: Fixed issue with generated regex operation order that could cause problem
+
+## 3.1.0 (2020-04-15)
+
+### Added
+
+- #131: Add support for serializing/deserializing SQL (thanks @ryancurrah)
+
+### Changed
+
+- #148: More accurate validation messages on constraints
+
+## 3.0.3 (2019-12-13)
+
+### Fixed
+
+- #141: Fixed issue with <= comparison
+
+## 3.0.2 (2019-11-14)
+
+### Fixed
+
+- #134: Fixed broken constraint checking with ^0.0 (thanks @krmichelos)
+
+## 3.0.1 (2019-09-13)
+
+### Fixed
+
+- #125: Fixes issue with module path for v3
+
+## 3.0.0 (2019-09-12)
+
+This is a major release of the semver package which includes API changes. The Go
+API is compatible with ^1. The Go API was not changed because many people are using
+`go get` without Go modules for their applications and API breaking changes cause
+errors which we have or would need to support.
+
+The changes in this release are the handling based on the data passed into the
+functions. These are described in the added and changed sections below.
+
+### Added
+
+- StrictNewVersion function. This is similar to NewVersion but will return an
+ error if the version passed in is not a strict semantic version. For example,
+ 1.2.3 would pass but v1.2.3 or 1.2 would fail because they are not strictly
+ speaking semantic versions. This function is faster, performs fewer operations,
+ and uses fewer allocations than NewVersion.
+- Fuzzing has been performed on NewVersion, StrictNewVersion, and NewConstraint.
+ The Makefile contains the operations used. For more information on you can start
+ on Wikipedia at https://en.wikipedia.org/wiki/Fuzzing
+- Now using Go modules
+
+### Changed
+
+- NewVersion has proper prerelease and metadata validation with error messages
+ to signal an issue with either of them
+- ^ now operates using a similar set of rules to npm/js and Rust/Cargo. If the
+ version is >=1 the ^ ranges works the same as v1. For major versions of 0 the
+ rules have changed. The minor version is treated as the stable version unless
+ a patch is specified and then it is equivalent to =. One difference from npm/js
+ is that prereleases there are only to a specific version (e.g. 1.2.3).
+ Prereleases here look over multiple versions and follow semantic version
+ ordering rules. This pattern now follows along with the expected and requested
+ handling of this packaged by numerous users.
+
+## 1.5.0 (2019-09-11)
+
+### Added
+
+- #103: Add basic fuzzing for `NewVersion()` (thanks @jesse-c)
+
+### Changed
+
+- #82: Clarify wildcard meaning in range constraints and update tests for it (thanks @greysteil)
+- #83: Clarify caret operator range for pre-1.0.0 dependencies (thanks @greysteil)
+- #72: Adding docs comment pointing to vert for a cli
+- #71: Update the docs on pre-release comparator handling
+- #89: Test with new go versions (thanks @thedevsaddam)
+- #87: Added $ to ValidPrerelease for better validation (thanks @jeremycarroll)
+
+### Fixed
+
+- #78: Fix unchecked error in example code (thanks @ravron)
+- #70: Fix the handling of pre-releases and the 0.0.0 release edge case
+- #97: Fixed copyright file for proper display on GitHub
+- #107: Fix handling prerelease when sorting alphanum and num
+- #109: Fixed where Validate sometimes returns wrong message on error
+
+## 1.4.2 (2018-04-10)
+
+### Changed
+
+- #72: Updated the docs to point to vert for a console appliaction
+- #71: Update the docs on pre-release comparator handling
+
+### Fixed
+
+- #70: Fix the handling of pre-releases and the 0.0.0 release edge case
+
+## 1.4.1 (2018-04-02)
+
+### Fixed
+
+- Fixed #64: Fix pre-release precedence issue (thanks @uudashr)
+
+## 1.4.0 (2017-10-04)
+
+### Changed
+
+- #61: Update NewVersion to parse ints with a 64bit int size (thanks @zknill)
+
+## 1.3.1 (2017-07-10)
+
+### Fixed
+
+- Fixed #57: number comparisons in prerelease sometimes inaccurate
+
+## 1.3.0 (2017-05-02)
+
+### Added
+
+- #45: Added json (un)marshaling support (thanks @mh-cbon)
+- Stability marker. See https://masterminds.github.io/stability/
+
+### Fixed
+
+- #51: Fix handling of single digit tilde constraint (thanks @dgodd)
+
+### Changed
+
+- #55: The godoc icon moved from png to svg
+
+## 1.2.3 (2017-04-03)
+
+### Fixed
+
+- #46: Fixed 0.x.x and 0.0.x in constraints being treated as *
+
+## Release 1.2.2 (2016-12-13)
+
+### Fixed
+
+- #34: Fixed issue where hyphen range was not working with pre-release parsing.
+
+## Release 1.2.1 (2016-11-28)
+
+### Fixed
+
+- #24: Fixed edge case issue where constraint "> 0" does not handle "0.0.1-alpha"
+ properly.
+
+## Release 1.2.0 (2016-11-04)
+
+### Added
+
+- #20: Added MustParse function for versions (thanks @adamreese)
+- #15: Added increment methods on versions (thanks @mh-cbon)
+
+### Fixed
+
+- Issue #21: Per the SemVer spec (section 9) a pre-release is unstable and
+ might not satisfy the intended compatibility. The change here ignores pre-releases
+ on constraint checks (e.g., ~ or ^) when a pre-release is not part of the
+ constraint. For example, `^1.2.3` will ignore pre-releases while
+ `^1.2.3-alpha` will include them.
+
+## Release 1.1.1 (2016-06-30)
+
+### Changed
+
+- Issue #9: Speed up version comparison performance (thanks @sdboyer)
+- Issue #8: Added benchmarks (thanks @sdboyer)
+- Updated Go Report Card URL to new location
+- Updated Readme to add code snippet formatting (thanks @mh-cbon)
+- Updating tagging to v[SemVer] structure for compatibility with other tools.
+
+## Release 1.1.0 (2016-03-11)
+
+- Issue #2: Implemented validation to provide reasons a versions failed a
+ constraint.
+
+## Release 1.0.1 (2015-12-31)
+
+- Fixed #1: * constraint failing on valid versions.
+
+## Release 1.0.0 (2015-10-20)
+
+- Initial release
diff --git a/vendor/github.com/Masterminds/semver/v3/LICENSE.txt b/vendor/github.com/Masterminds/semver/v3/LICENSE.txt
new file mode 100644
index 0000000000..9ff7da9c48
--- /dev/null
+++ b/vendor/github.com/Masterminds/semver/v3/LICENSE.txt
@@ -0,0 +1,19 @@
+Copyright (C) 2014-2019, Matt Butcher and Matt Farina
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/github.com/Masterminds/semver/v3/Makefile b/vendor/github.com/Masterminds/semver/v3/Makefile
new file mode 100644
index 0000000000..9ca87a2c79
--- /dev/null
+++ b/vendor/github.com/Masterminds/semver/v3/Makefile
@@ -0,0 +1,31 @@
+GOPATH=$(shell go env GOPATH)
+GOLANGCI_LINT=$(GOPATH)/bin/golangci-lint
+
+.PHONY: lint
+lint: $(GOLANGCI_LINT)
+ @echo "==> Linting codebase"
+ @$(GOLANGCI_LINT) run
+
+.PHONY: test
+test:
+ @echo "==> Running tests"
+ GO111MODULE=on go test -v
+
+.PHONY: test-cover
+test-cover:
+ @echo "==> Running Tests with coverage"
+ GO111MODULE=on go 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 .
+
+$(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.56.2
diff --git a/vendor/github.com/Masterminds/semver/v3/README.md b/vendor/github.com/Masterminds/semver/v3/README.md
new file mode 100644
index 0000000000..2f56c676a5
--- /dev/null
+++ b/vendor/github.com/Masterminds/semver/v3/README.md
@@ -0,0 +1,274 @@
+# SemVer
+
+The `semver` package provides the ability to work with [Semantic Versions](http://semver.org) in Go. Specifically it provides the ability to:
+
+* Parse semantic versions
+* Sort semantic versions
+* Check if a semantic version fits within a set of constraints
+* Optionally work with a `v` prefix
+
+[](https://masterminds.github.io/stability/active.html)
+[](https://github.com/Masterminds/semver/actions)
+[](https://pkg.go.dev/github.com/Masterminds/semver/v3)
+[](https://goreportcard.com/report/github.com/Masterminds/semver)
+
+## Package Versions
+
+Note, import `github.com/Masterminds/semver/v3` to use the latest version.
+
+There are three major versions fo the `semver` package.
+
+* 3.x.x is the stable and active version. This version is focused on constraint
+ compatibility for range handling in other tools from other languages. It has
+ a similar API to the v1 releases. The development of this version is on the master
+ branch. The documentation for this version is below.
+* 2.x was developed primarily for [dep](https://github.com/golang/dep). There are
+ no tagged releases and the development was performed by [@sdboyer](https://github.com/sdboyer).
+ There are API breaking changes from v1. This version lives on the [2.x branch](https://github.com/Masterminds/semver/tree/2.x).
+* 1.x.x is the original release. It is no longer maintained. You should use the
+ v3 release instead. You can read the documentation for the 1.x.x release
+ [here](https://github.com/Masterminds/semver/blob/release-1/README.md).
+
+## Parsing Semantic Versions
+
+There are two functions that can parse semantic versions. The `StrictNewVersion`
+function only parses valid version 2 semantic versions as outlined in the
+specification. The `NewVersion` function attempts to coerce a version into a
+semantic version and parse it. For example, if there is a leading v or a version
+listed without all 3 parts (e.g. `v1.2`) it will attempt to coerce it into a valid
+semantic version (e.g., 1.2.0). In both cases a `Version` object is returned
+that can be sorted, compared, and used in constraints.
+
+When parsing a version an error is returned if there is an issue parsing the
+version. For example,
+
+ v, err := semver.NewVersion("1.2.3-beta.1+build345")
+
+The version object has methods to get the parts of the version, compare it to
+other versions, convert the version back into a string, and get the original
+string. Getting the original string is useful if the semantic version was coerced
+into a valid form.
+
+There are package level variables that affect how `NewVersion` handles parsing.
+
+- `CoerceNewVersion` is `true` by default. When set to `true` it coerces non-compliant
+ versions into SemVer. For example, allowing a leading 0 in a major, minor, or patch
+ part. This enables the use of CalVer in versions even when not compliant with SemVer.
+ When set to `false` less coercion work is done.
+- `DetailedNewVersionErrors` provides more detailed errors. It only has an affect when
+ `CoerceNewVersion` is set to `false`. When `DetailedNewVersionErrors` is set to `true`
+ it can provide some more insight into why a version is invalid. Setting
+ `DetailedNewVersionErrors` to `false` is faster on performance but provides less
+ detailed error messages if a version fails to parse.
+
+## Sorting Semantic Versions
+
+A set of versions can be sorted using the `sort` package from the standard library.
+For example,
+
+```go
+raw := []string{"1.2.3", "1.0", "1.3", "2", "0.4.2",}
+vs := make([]*semver.Version, len(raw))
+for i, r := range raw {
+ v, err := semver.NewVersion(r)
+ if err != nil {
+ t.Errorf("Error parsing version: %s", err)
+ }
+
+ vs[i] = v
+}
+
+sort.Sort(semver.Collection(vs))
+```
+
+## Checking Version Constraints
+
+There are two methods for comparing versions. One uses comparison methods on
+`Version` instances and the other uses `Constraints`. There are some important
+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 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 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
+ ~ and ^. For more details on those see the options below.
+
+There are differences between the two methods or checking versions because the
+comparison methods on `Version` follow the specification while comparison ranges
+are not part of the specification. Different packages and tools have taken it
+upon themselves to come up with range rules. This has resulted in differences.
+For example, npm/js and Cargo/Rust follow similar patterns while PHP has a
+different pattern for ^. The comparison features in this package follow the
+npm/js and Cargo/Rust lead because applications using it have followed similar
+patters with their versions.
+
+Checking a version against version constraints is one of the most featureful
+parts of the package.
+
+```go
+c, err := semver.NewConstraint(">= 1.2.3")
+if err != nil {
+ // Handle constraint not being parsable.
+}
+
+v, err := semver.NewVersion("1.3")
+if err != nil {
+ // Handle version not being parsable.
+}
+// Check if the version meets the constraints. The variable a will be true.
+a := c.Check(v)
+```
+
+### Basic Comparisons
+
+There are two elements to the comparisons. First, a comparison string is a list
+of space or comma separated AND comparisons. These are then separated by || (OR)
+comparisons. For example, `">= 1.2 < 3.0.0 || >= 4.2.3"` is looking for a
+comparison that's greater than or equal to 1.2 and less than 3.0.0 or is
+greater than or equal to 4.2.3.
+
+The basic comparisons are:
+
+* `=`: equal (aliased to no operator)
+* `!=`: not equal
+* `>`: greater than
+* `<`: less than
+* `>=`: greater than or equal to
+* `<=`: less than or equal to
+
+### 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 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, pre-releases come before their associated releases. In this
+example `1.2.3-beta.1 < 1.2.3`.
+
+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'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
+`.` separators), per the spec. Sorting happens in ASCII sort order, again per the
+spec. The lowest character is a `0` in ASCII sort order
+(see an [ASCII Table](http://www.asciitable.com/))
+
+Understanding ASCII sort ordering is important because A-Z comes before a-z. That
+means `>=1.2.3-BETA` will return `1.2.3-alpha`. What you might expect from case
+sensitivity doesn't apply here. This is due to ASCII sort ordering which is what
+the spec specifies.
+
+The `Constraints` instance returned from `semver.NewConstraint()` has a property
+`IncludePrerelease` that, when set to true, will return prerelease versions when calls
+to `Check()` and `Validate()` are made.
+
+### Hyphen Range Comparisons
+
+There are multiple methods to handle ranges and the first is hyphens ranges.
+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
+for all comparison operators. When used on the `=` operator it falls
+back to the patch level comparison (see tilde below). For example,
+
+* `1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
+* `>= 1.2.x` is equivalent to `>= 1.2.0`
+* `<= 2.x` is equivalent to `< 3`
+* `*` is equivalent to `>= 0.0.0`
+
+### Tilde Range Comparisons (Patch)
+
+The tilde (`~`) comparison operator is for patch level ranges when a minor
+version is specified and major level changes when the minor number is missing.
+For example,
+
+* `~1.2.3` is equivalent to `>= 1.2.3, < 1.3.0`
+* `~1` is equivalent to `>= 1, < 2`
+* `~2.3` is equivalent to `>= 2.3, < 2.4`
+* `~1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
+* `~1.x` is equivalent to `>= 1, < 2`
+
+### Caret Range Comparisons (Major)
+
+The caret (`^`) comparison operator is for major level changes once a stable
+(1.0.0) release has occurred. Prior to a 1.0.0 release the minor versions acts
+as the API stability level. This is useful when comparisons of API versions as a
+major change is API breaking. For example,
+
+* `^1.2.3` is equivalent to `>= 1.2.3, < 2.0.0`
+* `^1.2.x` is equivalent to `>= 1.2.0, < 2.0.0`
+* `^2.3` is equivalent to `>= 2.3, < 3`
+* `^2.x` is equivalent to `>= 2.0.0, < 3`
+* `^0.2.3` is equivalent to `>=0.2.3 <0.3.0`
+* `^0.2` is equivalent to `>=0.2.0 <0.3.0`
+* `^0.0.3` is equivalent to `>=0.0.3 <0.0.4`
+* `^0.0` is equivalent to `>=0.0.0 <0.1.0`
+* `^0` is equivalent to `>=0.0.0 <1.0.0`
+
+## Validation
+
+In addition to testing a version against a constraint, a version can be validated
+against a constraint. When validation fails a slice of errors containing why a
+version didn't meet the constraint is returned. For example,
+
+```go
+c, err := semver.NewConstraint("<= 1.2.3, >= 1.4")
+if err != nil {
+ // Handle constraint not being parseable.
+}
+
+v, err := semver.NewVersion("1.3")
+if err != nil {
+ // Handle version not being parseable.
+}
+
+// Validate a version against a constraint.
+a, msgs := c.Validate(v)
+// a is false
+for _, m := range msgs {
+ fmt.Println(m)
+
+ // Loops over the errors which would read
+ // "1.3 is greater than 1.2.3"
+ // "1.3 is less than 1.4"
+}
+```
+
+## Contribute
+
+If you find an issue or want to contribute please file an [issue](https://github.com/Masterminds/semver/issues)
+or [create a pull request](https://github.com/Masterminds/semver/pulls).
+
+## Security
+
+Security is an important consideration for this project. The project currently
+uses the following tools to help discover security issues:
+
+* [CodeQL](https://codeql.github.com)
+* [gosec](https://github.com/securego/gosec)
+* Daily Fuzz testing
+
+If you believe you have found a security vulnerability you can privately disclose
+it through the [GitHub security page](https://github.com/Masterminds/semver/security).
diff --git a/vendor/github.com/Masterminds/semver/v3/SECURITY.md b/vendor/github.com/Masterminds/semver/v3/SECURITY.md
new file mode 100644
index 0000000000..a30a66b1f7
--- /dev/null
+++ b/vendor/github.com/Masterminds/semver/v3/SECURITY.md
@@ -0,0 +1,19 @@
+# Security Policy
+
+## Supported Versions
+
+The following versions of semver are currently supported:
+
+| Version | Supported |
+| ------- | ------------------ |
+| 3.x | :white_check_mark: |
+| 2.x | :x: |
+| 1.x | :x: |
+
+Fixes are only released for the latest minor version in the form of a patch release.
+
+## Reporting a Vulnerability
+
+You can privately disclose a vulnerability through GitHubs
+[private vulnerability reporting](https://github.com/Masterminds/semver/security/advisories)
+mechanism.
diff --git a/vendor/github.com/Masterminds/semver/v3/collection.go b/vendor/github.com/Masterminds/semver/v3/collection.go
new file mode 100644
index 0000000000..a78235895f
--- /dev/null
+++ b/vendor/github.com/Masterminds/semver/v3/collection.go
@@ -0,0 +1,24 @@
+package semver
+
+// Collection is a collection of Version instances and implements the sort
+// interface. See the sort package for more details.
+// https://golang.org/pkg/sort/
+type Collection []*Version
+
+// Len returns the length of a collection. The number of Version instances
+// on the slice.
+func (c Collection) Len() int {
+ return len(c)
+}
+
+// Less is needed for the sort interface to compare two Version objects on the
+// slice. If checks if one is less than the other.
+func (c Collection) Less(i, j int) bool {
+ return c[i].LessThan(c[j])
+}
+
+// Swap is needed for the sort interface to replace the Version objects
+// at two different positions in the slice.
+func (c Collection) Swap(i, j int) {
+ c[i], c[j] = c[j], c[i]
+}
diff --git a/vendor/github.com/Masterminds/semver/v3/constraints.go b/vendor/github.com/Masterminds/semver/v3/constraints.go
new file mode 100644
index 0000000000..8b7a10f836
--- /dev/null
+++ b/vendor/github.com/Masterminds/semver/v3/constraints.go
@@ -0,0 +1,601 @@
+package semver
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "regexp"
+ "strings"
+)
+
+// Constraints is one or more constraint that a semantic version can be
+// checked against.
+type Constraints struct {
+ constraints [][]*constraint
+ containsPre []bool
+
+ // IncludePrerelease specifies if pre-releases should be included in
+ // the results. Note, if a constraint range has a prerelease than
+ // prereleases will be included for that AND group even if this is
+ // set to false.
+ IncludePrerelease bool
+}
+
+// NewConstraint returns a Constraints instance that a Version instance can
+// be checked against. If there is a parse error it will be returned.
+func NewConstraint(c string) (*Constraints, error) {
+
+ // Rewrite - ranges into a comparison operation.
+ c = rewriteRange(c)
+
+ ors := strings.Split(c, "||")
+ lenors := len(ors)
+ or := make([][]*constraint, lenors)
+ hasPre := make([]bool, lenors)
+ for k, v := range ors {
+ // Validate the segment
+ if !validConstraintRegex.MatchString(v) {
+ return nil, fmt.Errorf("improper constraint: %s", v)
+ }
+
+ cs := findConstraintRegex.FindAllString(v, -1)
+ if cs == nil {
+ cs = append(cs, v)
+ }
+ result := make([]*constraint, len(cs))
+ for i, s := range cs {
+ pc, err := parseConstraint(s)
+ if err != nil {
+ return nil, err
+ }
+
+ // If one of the constraints has a prerelease record this.
+ // This information is used when checking all in an "and"
+ // group to ensure they all check for prereleases.
+ if pc.con.pre != "" {
+ hasPre[k] = true
+ }
+
+ result[i] = pc
+ }
+ or[k] = result
+ }
+
+ o := &Constraints{
+ constraints: or,
+ containsPre: hasPre,
+ }
+ return o, nil
+}
+
+// Check tests if a version satisfies the constraints.
+func (cs Constraints) Check(v *Version) bool {
+ // TODO(mattfarina): For v4 of this library consolidate the Check and Validate
+ // functions as the underlying functions make that possible now.
+ // loop over the ORs and check the inner ANDs
+ for i, o := range cs.constraints {
+ joy := true
+ for _, c := range o {
+ if check, _ := c.check(v, (cs.IncludePrerelease || cs.containsPre[i])); !check {
+ joy = false
+ break
+ }
+ }
+
+ if joy {
+ return true
+ }
+ }
+
+ return false
+}
+
+// Validate checks if a version satisfies a constraint. If not a slice of
+// reasons for the failure are returned in addition to a bool.
+func (cs Constraints) Validate(v *Version) (bool, []error) {
+ // loop over the ORs and check the inner ANDs
+ var e []error
+
+ // Capture the prerelease message only once. When it happens the first time
+ // this var is marked
+ var prerelesase bool
+ for i, o := range cs.constraints {
+ joy := true
+ for _, c := range o {
+ // Before running the check handle the case there the version is
+ // a prerelease and the check is not searching for prereleases.
+ if !(cs.IncludePrerelease || cs.containsPre[i]) && v.pre != "" {
+ if !prerelesase {
+ em := fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
+ e = append(e, em)
+ prerelesase = true
+ }
+ joy = false
+
+ } else {
+
+ if _, err := c.check(v, (cs.IncludePrerelease || cs.containsPre[i])); err != nil {
+ e = append(e, err)
+ joy = false
+ }
+ }
+ }
+
+ if joy {
+ return true, []error{}
+ }
+ }
+
+ return false, e
+}
+
+func (cs Constraints) String() string {
+ buf := make([]string, len(cs.constraints))
+ var tmp bytes.Buffer
+
+ for k, v := range cs.constraints {
+ tmp.Reset()
+ vlen := len(v)
+ for kk, c := range v {
+ tmp.WriteString(c.string())
+
+ // Space separate the AND conditions
+ if vlen > 1 && kk < vlen-1 {
+ tmp.WriteString(" ")
+ }
+ }
+ buf[k] = tmp.String()
+ }
+
+ return strings.Join(buf, " || ")
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+func (cs *Constraints) UnmarshalText(text []byte) error {
+ temp, err := NewConstraint(string(text))
+ if err != nil {
+ return err
+ }
+
+ *cs = *temp
+
+ return nil
+}
+
+// MarshalText implements the encoding.TextMarshaler interface.
+func (cs Constraints) MarshalText() ([]byte, error) {
+ return []byte(cs.String()), nil
+}
+
+var constraintOps map[string]cfunc
+var constraintRegex *regexp.Regexp
+var constraintRangeRegex *regexp.Regexp
+
+// Used to find individual constraints within a multi-constraint string
+var findConstraintRegex *regexp.Regexp
+
+// Used to validate an segment of ANDs is valid
+var validConstraintRegex *regexp.Regexp
+
+const cvRegex string = `v?([0-9|x|X|\*]+)(\.[0-9|x|X|\*]+)?(\.[0-9|x|X|\*]+)?` +
+ `(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` +
+ `(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?`
+
+func init() {
+ constraintOps = map[string]cfunc{
+ "": constraintTildeOrEqual,
+ "=": constraintTildeOrEqual,
+ "!=": constraintNotEqual,
+ ">": constraintGreaterThan,
+ "<": constraintLessThan,
+ ">=": constraintGreaterThanEqual,
+ "=>": constraintGreaterThanEqual,
+ "<=": constraintLessThanEqual,
+ "=<": constraintLessThanEqual,
+ "~": constraintTilde,
+ "~>": constraintTilde,
+ "^": constraintCaret,
+ }
+
+ ops := `=||!=|>|<|>=|=>|<=|=<|~|~>|\^`
+
+ constraintRegex = regexp.MustCompile(fmt.Sprintf(
+ `^\s*(%s)\s*(%s)\s*$`,
+ ops,
+ cvRegex))
+
+ constraintRangeRegex = regexp.MustCompile(fmt.Sprintf(
+ `\s*(%s)\s+-\s+(%s)\s*`,
+ cvRegex, cvRegex))
+
+ findConstraintRegex = regexp.MustCompile(fmt.Sprintf(
+ `(%s)\s*(%s)`,
+ ops,
+ cvRegex))
+
+ // The first time a constraint shows up will look slightly different from
+ // future times it shows up due to a leading space or comma in a given
+ // string.
+ validConstraintRegex = regexp.MustCompile(fmt.Sprintf(
+ `^(\s*(%s)\s*(%s)\s*)((?:\s+|,\s*)(%s)\s*(%s)\s*)*$`,
+ ops,
+ cvRegex,
+ ops,
+ cvRegex))
+}
+
+// An individual constraint
+type constraint struct {
+ // The version used in the constraint check. For example, if a constraint
+ // is '<= 2.0.0' the con a version instance representing 2.0.0.
+ con *Version
+
+ // The original parsed version (e.g., 4.x from != 4.x)
+ orig string
+
+ // The original operator for the constraint
+ origfunc string
+
+ // When an x is used as part of the version (e.g., 1.x)
+ minorDirty bool
+ dirty bool
+ patchDirty bool
+}
+
+// Check if a version meets the constraint
+func (c *constraint) check(v *Version, includePre bool) (bool, error) {
+ return constraintOps[c.origfunc](v, c, includePre)
+}
+
+// String prints an individual constraint into a string
+func (c *constraint) string() string {
+ return c.origfunc + c.orig
+}
+
+type cfunc func(v *Version, c *constraint, includePre bool) (bool, error)
+
+func parseConstraint(c string) (*constraint, error) {
+ if len(c) > 0 {
+ m := constraintRegex.FindStringSubmatch(c)
+ if m == nil {
+ return nil, fmt.Errorf("improper constraint: %s", c)
+ }
+
+ cs := &constraint{
+ orig: m[2],
+ origfunc: m[1],
+ }
+
+ ver := m[2]
+ minorDirty := false
+ patchDirty := false
+ dirty := false
+ if isX(m[3]) || m[3] == "" {
+ ver = fmt.Sprintf("0.0.0%s", m[6])
+ dirty = true
+ } else if isX(strings.TrimPrefix(m[4], ".")) || m[4] == "" {
+ minorDirty = true
+ dirty = true
+ ver = fmt.Sprintf("%s.0.0%s", m[3], m[6])
+ } else if isX(strings.TrimPrefix(m[5], ".")) || m[5] == "" {
+ dirty = true
+ patchDirty = true
+ ver = fmt.Sprintf("%s%s.0%s", m[3], m[4], m[6])
+ }
+
+ con, err := NewVersion(ver)
+ if err != nil {
+
+ // The constraintRegex should catch any regex parsing errors. So,
+ // we should never get here.
+ return nil, errors.New("constraint parser error")
+ }
+
+ cs.con = con
+ cs.minorDirty = minorDirty
+ cs.patchDirty = patchDirty
+ cs.dirty = dirty
+
+ return cs, nil
+ }
+
+ // The rest is the special case where an empty string was passed in which
+ // is equivalent to * or >=0.0.0
+ con, err := StrictNewVersion("0.0.0")
+ if err != nil {
+
+ // The constraintRegex should catch any regex parsing errors. So,
+ // we should never get here.
+ return nil, errors.New("constraint parser error")
+ }
+
+ cs := &constraint{
+ con: con,
+ orig: c,
+ origfunc: "",
+ minorDirty: false,
+ patchDirty: false,
+ dirty: true,
+ }
+ return cs, nil
+}
+
+// Constraint functions
+func constraintNotEqual(v *Version, c *constraint, includePre bool) (bool, error) {
+ // The existence of prereleases is checked at the group level and passed in.
+ // Exit early if the version has a prerelease but those are to be ignored.
+ if v.Prerelease() != "" && !includePre {
+ return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
+ }
+
+ if c.dirty {
+ if c.con.Major() != v.Major() {
+ return true, nil
+ }
+ if c.con.Minor() != v.Minor() && !c.minorDirty {
+ return true, nil
+ } else if c.minorDirty {
+ return false, fmt.Errorf("%s is equal to %s", v, c.orig)
+ } else if c.con.Patch() != v.Patch() && !c.patchDirty {
+ return true, nil
+ } else if c.patchDirty {
+ // Need to handle prereleases if present
+ if v.Prerelease() != "" || c.con.Prerelease() != "" {
+ eq := comparePrerelease(v.Prerelease(), c.con.Prerelease()) != 0
+ if eq {
+ return true, nil
+ }
+ return false, fmt.Errorf("%s is equal to %s", v, c.orig)
+ }
+ return false, fmt.Errorf("%s is equal to %s", v, c.orig)
+ }
+ }
+
+ eq := v.Equal(c.con)
+ if eq {
+ return false, fmt.Errorf("%s is equal to %s", v, c.orig)
+ }
+
+ return true, nil
+}
+
+func constraintGreaterThan(v *Version, c *constraint, includePre bool) (bool, error) {
+
+ // The existence of prereleases is checked at the group level and passed in.
+ // Exit early if the version has a prerelease but those are to be ignored.
+ if v.Prerelease() != "" && !includePre {
+ return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
+ }
+
+ var eq bool
+
+ if !c.dirty {
+ eq = v.Compare(c.con) == 1
+ if eq {
+ return true, nil
+ }
+ return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
+ }
+
+ if v.Major() > c.con.Major() {
+ return true, nil
+ } else if v.Major() < c.con.Major() {
+ return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
+ } else if c.minorDirty {
+ // This is a range case such as >11. When the version is something like
+ // 11.1.0 is it not > 11. For that we would need 12 or higher
+ return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
+ } else if c.patchDirty {
+ // This is for ranges such as >11.1. A version of 11.1.1 is not greater
+ // which one of 11.2.1 is greater
+ eq = v.Minor() > c.con.Minor()
+ if eq {
+ return true, nil
+ }
+ return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
+ }
+
+ // If we have gotten here we are not comparing pre-preleases and can use the
+ // Compare function to accomplish that.
+ eq = v.Compare(c.con) == 1
+ if eq {
+ return true, nil
+ }
+ return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig)
+}
+
+func constraintLessThan(v *Version, c *constraint, includePre bool) (bool, error) {
+ // The existence of prereleases is checked at the group level and passed in.
+ // Exit early if the version has a prerelease but those are to be ignored.
+ if v.Prerelease() != "" && !includePre {
+ return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
+ }
+
+ eq := v.Compare(c.con) < 0
+ if eq {
+ return true, nil
+ }
+ return false, fmt.Errorf("%s is greater than or equal to %s", v, c.orig)
+}
+
+func constraintGreaterThanEqual(v *Version, c *constraint, includePre bool) (bool, error) {
+
+ // The existence of prereleases is checked at the group level and passed in.
+ // Exit early if the version has a prerelease but those are to be ignored.
+ if v.Prerelease() != "" && !includePre {
+ return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
+ }
+
+ eq := v.Compare(c.con) >= 0
+ if eq {
+ return true, nil
+ }
+ return false, fmt.Errorf("%s is less than %s", v, c.orig)
+}
+
+func constraintLessThanEqual(v *Version, c *constraint, includePre bool) (bool, error) {
+ // The existence of prereleases is checked at the group level and passed in.
+ // Exit early if the version has a prerelease but those are to be ignored.
+ if v.Prerelease() != "" && !includePre {
+ return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
+ }
+
+ var eq bool
+
+ if !c.dirty {
+ eq = v.Compare(c.con) <= 0
+ if eq {
+ return true, nil
+ }
+ return false, fmt.Errorf("%s is greater than %s", v, c.orig)
+ }
+
+ if v.Major() > c.con.Major() {
+ return false, fmt.Errorf("%s is greater than %s", v, c.orig)
+ } else if v.Major() == c.con.Major() && v.Minor() > c.con.Minor() && !c.minorDirty {
+ return false, fmt.Errorf("%s is greater than %s", v, c.orig)
+ }
+
+ return true, nil
+}
+
+// ~*, ~>* --> >= 0.0.0 (any)
+// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0, <3.0.0
+// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0, <2.1.0
+// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0, <1.3.0
+// ~1.2.3, ~>1.2.3 --> >=1.2.3, <1.3.0
+// ~1.2.0, ~>1.2.0 --> >=1.2.0, <1.3.0
+func constraintTilde(v *Version, c *constraint, includePre bool) (bool, error) {
+ // The existence of prereleases is checked at the group level and passed in.
+ // Exit early if the version has a prerelease but those are to be ignored.
+ if v.Prerelease() != "" && !includePre {
+ return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
+ }
+
+ if v.LessThan(c.con) {
+ return false, fmt.Errorf("%s is less than %s", v, c.orig)
+ }
+
+ // ~0.0.0 is a special case where all constraints are accepted. It's
+ // equivalent to >= 0.0.0.
+ if c.con.Major() == 0 && c.con.Minor() == 0 && c.con.Patch() == 0 &&
+ !c.minorDirty && !c.patchDirty {
+ return true, nil
+ }
+
+ if v.Major() != c.con.Major() {
+ return false, fmt.Errorf("%s does not have same major version as %s", v, c.orig)
+ }
+
+ if v.Minor() != c.con.Minor() && !c.minorDirty {
+ return false, fmt.Errorf("%s does not have same major and minor version as %s", v, c.orig)
+ }
+
+ return true, nil
+}
+
+// When there is a .x (dirty) status it automatically opts in to ~. Otherwise
+// it's a straight =
+func constraintTildeOrEqual(v *Version, c *constraint, includePre bool) (bool, error) {
+ // The existence of prereleases is checked at the group level and passed in.
+ // Exit early if the version has a prerelease but those are to be ignored.
+ if v.Prerelease() != "" && !includePre {
+ return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
+ }
+
+ if c.dirty {
+ return constraintTilde(v, c, includePre)
+ }
+
+ eq := v.Equal(c.con)
+ if eq {
+ return true, nil
+ }
+
+ return false, fmt.Errorf("%s is not equal to %s", v, c.orig)
+}
+
+// ^* --> (any)
+// ^1.2.3 --> >=1.2.3 <2.0.0
+// ^1.2 --> >=1.2.0 <2.0.0
+// ^1 --> >=1.0.0 <2.0.0
+// ^0.2.3 --> >=0.2.3 <0.3.0
+// ^0.2 --> >=0.2.0 <0.3.0
+// ^0.0.3 --> >=0.0.3 <0.0.4
+// ^0.0 --> >=0.0.0 <0.1.0
+// ^0 --> >=0.0.0 <1.0.0
+func constraintCaret(v *Version, c *constraint, includePre bool) (bool, error) {
+ // The existence of prereleases is checked at the group level and passed in.
+ // Exit early if the version has a prerelease but those are to be ignored.
+ if v.Prerelease() != "" && !includePre {
+ return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v)
+ }
+
+ // This less than handles prereleases
+ if v.LessThan(c.con) {
+ return false, fmt.Errorf("%s is less than %s", v, c.orig)
+ }
+
+ var eq bool
+
+ // ^ when the major > 0 is >=x.y.z < x+1
+ if c.con.Major() > 0 || c.minorDirty {
+
+ // ^ has to be within a major range for > 0. Everything less than was
+ // filtered out with the LessThan call above. This filters out those
+ // that greater but not within the same major range.
+ eq = v.Major() == c.con.Major()
+ if eq {
+ return true, nil
+ }
+ return false, fmt.Errorf("%s does not have same major version as %s", v, c.orig)
+ }
+
+ // ^ when the major is 0 and minor > 0 is >=0.y.z < 0.y+1
+ if c.con.Major() == 0 && v.Major() > 0 {
+ return false, fmt.Errorf("%s does not have same major version as %s", v, c.orig)
+ }
+ // If the con Minor is > 0 it is not dirty
+ if c.con.Minor() > 0 || c.patchDirty {
+ eq = v.Minor() == c.con.Minor()
+ if eq {
+ return true, nil
+ }
+ return false, fmt.Errorf("%s does not have same minor version as %s. Expected minor versions to match when constraint major version is 0", v, c.orig)
+ }
+ // ^ when the minor is 0 and minor > 0 is =0.0.z
+ if c.con.Minor() == 0 && v.Minor() > 0 {
+ return false, fmt.Errorf("%s does not have same minor version as %s", v, c.orig)
+ }
+
+ // At this point the major is 0 and the minor is 0 and not dirty. The patch
+ // is not dirty so we need to check if they are equal. If they are not equal
+ eq = c.con.Patch() == v.Patch()
+ if eq {
+ return true, nil
+ }
+ return false, fmt.Errorf("%s does not equal %s. Expect version and constraint to equal when major and minor versions are 0", v, c.orig)
+}
+
+func isX(x string) bool {
+ switch x {
+ case "x", "*", "X":
+ return true
+ default:
+ return false
+ }
+}
+
+func rewriteRange(i string) string {
+ m := constraintRangeRegex.FindAllStringSubmatch(i, -1)
+ if m == nil {
+ return i
+ }
+ o := i
+ for _, v := range m {
+ t := fmt.Sprintf(">= %s, <= %s ", v[1], v[11])
+ o = strings.Replace(o, v[0], t, 1)
+ }
+
+ return o
+}
diff --git a/vendor/github.com/Masterminds/semver/v3/doc.go b/vendor/github.com/Masterminds/semver/v3/doc.go
new file mode 100644
index 0000000000..74f97caa57
--- /dev/null
+++ b/vendor/github.com/Masterminds/semver/v3/doc.go
@@ -0,0 +1,184 @@
+/*
+Package semver provides the ability to work with Semantic Versions (http://semver.org) in Go.
+
+Specifically it provides the ability to:
+
+ - Parse semantic versions
+ - Sort semantic versions
+ - Check if a semantic version fits within a set of constraints
+ - Optionally work with a `v` prefix
+
+# Parsing Semantic Versions
+
+There are two functions that can parse semantic versions. The `StrictNewVersion`
+function only parses valid version 2 semantic versions as outlined in the
+specification. The `NewVersion` function attempts to coerce a version into a
+semantic version and parse it. For example, if there is a leading v or a version
+listed without all 3 parts (e.g. 1.2) it will attempt to coerce it into a valid
+semantic version (e.g., 1.2.0). In both cases a `Version` object is returned
+that can be sorted, compared, and used in constraints.
+
+When parsing a version an optional error can be returned if there is an issue
+parsing the version. For example,
+
+ v, err := semver.NewVersion("1.2.3-beta.1+b345")
+
+The version object has methods to get the parts of the version, compare it to
+other versions, convert the version back into a string, and get the original
+string. For more details please see the documentation
+at https://godoc.org/github.com/Masterminds/semver.
+
+# Sorting Semantic Versions
+
+A set of versions can be sorted using the `sort` package from the standard library.
+For example,
+
+ raw := []string{"1.2.3", "1.0", "1.3", "2", "0.4.2",}
+ vs := make([]*semver.Version, len(raw))
+ for i, r := range raw {
+ v, err := semver.NewVersion(r)
+ if err != nil {
+ t.Errorf("Error parsing version: %s", err)
+ }
+
+ vs[i] = v
+ }
+
+ sort.Sort(semver.Collection(vs))
+
+# Checking Version Constraints and Comparing Versions
+
+There are two methods for comparing versions. One uses comparison methods on
+`Version` instances and the other is using Constraints. There are some important
+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
+ within the comparison. It will provide an answer valid with the comparison
+ spec section 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
+ ranges does not include on. 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 shorthard use of
+ ~ and ^. For more details on those see the options below.
+
+There are differences between the two methods or checking versions because the
+comparison methods on `Version` follow the specification while comparison ranges
+are not part of the specification. Different packages and tools have taken it
+upon themselves to come up with range rules. This has resulted in differences.
+For example, npm/js and Cargo/Rust follow similar patterns which PHP has a
+different pattern for ^. The comparison features in this package follow the
+npm/js and Cargo/Rust lead because applications using it have followed similar
+patters with their versions.
+
+Checking a version against version constraints is one of the most featureful
+parts of the package.
+
+ c, err := semver.NewConstraint(">= 1.2.3")
+ if err != nil {
+ // Handle constraint not being parsable.
+ }
+
+ 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.
+ a := c.Check(v)
+
+# Basic Comparisons
+
+There are two elements to the comparisons. First, a comparison string is a list
+of comma or space separated AND comparisons. These are then separated by || (OR)
+comparisons. For example, `">= 1.2 < 3.0.0 || >= 4.2.3"` is looking for a
+comparison that's greater than or equal to 1.2 and less than 3.0.0 or is
+greater than or equal to 4.2.3. This can also be written as
+`">= 1.2, < 3.0.0 || >= 4.2.3"`
+
+The basic comparisons are:
+
+ - `=`: equal (aliased to no operator)
+ - `!=`: not equal
+ - `>`: greater than
+ - `<`: less than
+ - `>=`: greater than or equal to
+ - `<=`: less than or equal to
+
+# Hyphen Range Comparisons
+
+There are multiple methods to handle ranges and the first is hyphens ranges.
+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`
+
+# Wildcards In Comparisons
+
+The `x`, `X`, and `*` characters can be used as a wildcard character. This works
+for all comparison operators. When used on the `=` operator it falls
+back to the tilde operation. For example,
+
+ - `1.2.x` is equivalent to `>= 1.2.0 < 1.3.0`
+ - `>= 1.2.x` is equivalent to `>= 1.2.0`
+ - `<= 2.x` is equivalent to `<= 3`
+ - `*` is equivalent to `>= 0.0.0`
+
+Tilde Range Comparisons (Patch)
+
+The tilde (`~`) comparison operator is for patch level ranges when a minor
+version is specified and major level changes when the minor number is missing.
+For example,
+
+ - `~1.2.3` is equivalent to `>= 1.2.3 < 1.3.0`
+ - `~1` is equivalent to `>= 1, < 2`
+ - `~2.3` is equivalent to `>= 2.3 < 2.4`
+ - `~1.2.x` is equivalent to `>= 1.2.0 < 1.3.0`
+ - `~1.x` is equivalent to `>= 1 < 2`
+
+Caret Range Comparisons (Major)
+
+The caret (`^`) comparison operator is for major level changes once a stable
+(1.0.0) release has occurred. Prior to a 1.0.0 release the minor versions acts
+as the API stability level. This is useful when comparisons of API versions as a
+major change is API breaking. For example,
+
+ - `^1.2.3` is equivalent to `>= 1.2.3, < 2.0.0`
+ - `^1.2.x` is equivalent to `>= 1.2.0, < 2.0.0`
+ - `^2.3` is equivalent to `>= 2.3, < 3`
+ - `^2.x` is equivalent to `>= 2.0.0, < 3`
+ - `^0.2.3` is equivalent to `>=0.2.3 <0.3.0`
+ - `^0.2` is equivalent to `>=0.2.0 <0.3.0`
+ - `^0.0.3` is equivalent to `>=0.0.3 <0.0.4`
+ - `^0.0` is equivalent to `>=0.0.0 <0.1.0`
+ - `^0` is equivalent to `>=0.0.0 <1.0.0`
+
+# Validation
+
+In addition to testing a version against a constraint, a version can be validated
+against a constraint. When validation fails a slice of errors containing why a
+version didn't meet the constraint is returned. For example,
+
+ c, err := semver.NewConstraint("<= 1.2.3, >= 1.4")
+ if err != nil {
+ // Handle constraint not being parseable.
+ }
+
+ v, _ := semver.NewVersion("1.3")
+ if err != nil {
+ // Handle version not being parseable.
+ }
+
+ // Validate a version against a constraint.
+ a, msgs := c.Validate(v)
+ // a is false
+ for _, m := range msgs {
+ fmt.Println(m)
+
+ // Loops over the errors which would read
+ // "1.3 is greater than 1.2.3"
+ // "1.3 is less than 1.4"
+ }
+*/
+package semver
diff --git a/vendor/github.com/Masterminds/semver/v3/version.go b/vendor/github.com/Masterminds/semver/v3/version.go
new file mode 100644
index 0000000000..7a3ba73887
--- /dev/null
+++ b/vendor/github.com/Masterminds/semver/v3/version.go
@@ -0,0 +1,788 @@
+package semver
+
+import (
+ "bytes"
+ "database/sql/driver"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+// The compiled version of the regex created at init() is cached here so it
+// only needs to be created once.
+var versionRegex *regexp.Regexp
+var looseVersionRegex *regexp.Regexp
+
+// CoerceNewVersion sets if leading 0's are allowd in the version part. Leading 0's are
+// not allowed in a valid semantic version. When set to true, NewVersion will coerce
+// leading 0's into a valid version.
+var CoerceNewVersion = true
+
+// DetailedNewVersionErrors specifies if detailed errors are returned from the NewVersion
+// function. This is used when CoerceNewVersion is set to false. If set to false
+// ErrInvalidSemVer is returned for an invalid version. This does not apply to
+// StrictNewVersion. Setting this function to false returns errors more quickly.
+var DetailedNewVersionErrors = true
+
+var (
+ // ErrInvalidSemVer is returned a version is found to be invalid when
+ // being parsed.
+ ErrInvalidSemVer = errors.New("invalid semantic version")
+
+ // ErrEmptyString is returned when an empty string is passed in for parsing.
+ ErrEmptyString = errors.New("version string empty")
+
+ // ErrInvalidCharacters is returned when invalid characters are found as
+ // part of a version
+ ErrInvalidCharacters = errors.New("invalid characters in version")
+
+ // ErrSegmentStartsZero is returned when a version segment starts with 0.
+ // This is invalid in SemVer.
+ ErrSegmentStartsZero = errors.New("version segment starts with 0")
+
+ // ErrInvalidMetadata is returned when the metadata is an invalid format
+ ErrInvalidMetadata = errors.New("invalid metadata string")
+
+ // ErrInvalidPrerelease is returned when the pre-release is an invalid format
+ ErrInvalidPrerelease = errors.New("invalid prerelease string")
+)
+
+// semVerRegex is the regular expression used to parse a semantic version.
+// This is not the official regex from the semver spec. It has been modified to allow for loose handling
+// where versions like 2.1 are detected.
+const semVerRegex string = `v?(0|[1-9]\d*)(?:\.(0|[1-9]\d*))?(?:\.(0|[1-9]\d*))?` +
+ `(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?` +
+ `(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?`
+
+// looseSemVerRegex is a regular expression that lets invalid semver expressions through
+// with enough detail that certain errors can be checked for.
+const looseSemVerRegex string = `v?([0-9]+)(\.[0-9]+)?(\.[0-9]+)?` +
+ `(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` +
+ `(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?`
+
+// Version represents a single semantic version.
+type Version struct {
+ major, minor, patch uint64
+ pre string
+ metadata string
+ original string
+}
+
+func init() {
+ versionRegex = regexp.MustCompile("^" + semVerRegex + "$")
+ looseVersionRegex = regexp.MustCompile("^" + looseSemVerRegex + "$")
+}
+
+const (
+ num string = "0123456789"
+ allowed string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-" + num
+)
+
+// StrictNewVersion parses a given version and returns an instance of Version or
+// an error if unable to parse the version. Only parses valid semantic versions.
+// Performs checking that can find errors within the version.
+// If you want to coerce a version such as 1 or 1.2 and parse it as the 1.x
+// releases of semver did, use the NewVersion() function.
+func StrictNewVersion(v string) (*Version, error) {
+ // Parsing here does not use RegEx in order to increase performance and reduce
+ // allocations.
+
+ if len(v) == 0 {
+ return nil, ErrEmptyString
+ }
+
+ // Split the parts into [0]major, [1]minor, and [2]patch,prerelease,build
+ parts := strings.SplitN(v, ".", 3)
+ if len(parts) != 3 {
+ return nil, ErrInvalidSemVer
+ }
+
+ sv := &Version{
+ original: v,
+ }
+
+ // 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
+ }
+ }
+
+ // 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
+ }
+ }
+
+ // Validate the number segments are valid. This includes only having positive
+ // numbers and no leading 0's.
+ for _, p := range parts {
+ if !containsOnly(p, num) {
+ return nil, ErrInvalidCharacters
+ }
+
+ if len(p) > 1 && p[0] == '0' {
+ return nil, ErrSegmentStartsZero
+ }
+ }
+
+ // Extract major, minor, and patch
+ var err error
+ sv.major, err = strconv.ParseUint(parts[0], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+
+ sv.minor, err = strconv.ParseUint(parts[1], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+
+ sv.patch, err = strconv.ParseUint(parts[2], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+
+ return sv, nil
+}
+
+// NewVersion parses a given version and returns an instance of Version or
+// an error if unable to parse the version. If the version is SemVer-ish it
+// attempts to convert it to SemVer. If you want to validate it was a strict
+// semantic version at parse time see StrictNewVersion().
+func NewVersion(v string) (*Version, error) {
+ if CoerceNewVersion {
+ return coerceNewVersion(v)
+ }
+ m := versionRegex.FindStringSubmatch(v)
+ if m == nil {
+
+ // Disabling detailed errors is first so that it is in the fast path.
+ if !DetailedNewVersionErrors {
+ return nil, ErrInvalidSemVer
+ }
+
+ // Check for specific errors with the semver string and return a more detailed
+ // error.
+ m = looseVersionRegex.FindStringSubmatch(v)
+ if m == nil {
+ return nil, ErrInvalidSemVer
+ }
+ err := validateVersion(m)
+ if err != nil {
+ return nil, err
+ }
+ return nil, ErrInvalidSemVer
+ }
+
+ sv := &Version{
+ metadata: m[5],
+ pre: m[4],
+ original: v,
+ }
+
+ var err error
+ sv.major, err = strconv.ParseUint(m[1], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("error parsing version segment: %w", err)
+ }
+
+ if m[2] != "" {
+ sv.minor, err = strconv.ParseUint(m[2], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("error parsing version segment: %w", err)
+ }
+ } else {
+ sv.minor = 0
+ }
+
+ if m[3] != "" {
+ sv.patch, err = strconv.ParseUint(m[3], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("error parsing version segment: %w", err)
+ }
+ } else {
+ sv.patch = 0
+ }
+
+ // Perform some basic due diligence on the extra parts to ensure they are
+ // valid.
+
+ 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
+}
+
+func coerceNewVersion(v string) (*Version, error) {
+ m := looseVersionRegex.FindStringSubmatch(v)
+ if m == nil {
+ return nil, ErrInvalidSemVer
+ }
+
+ sv := &Version{
+ metadata: m[8],
+ pre: m[5],
+ original: v,
+ }
+
+ var err error
+ sv.major, err = strconv.ParseUint(m[1], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("error parsing version segment: %w", err)
+ }
+
+ if m[2] != "" {
+ sv.minor, err = strconv.ParseUint(strings.TrimPrefix(m[2], "."), 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("error parsing version segment: %w", err)
+ }
+ } else {
+ sv.minor = 0
+ }
+
+ if m[3] != "" {
+ sv.patch, err = strconv.ParseUint(strings.TrimPrefix(m[3], "."), 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("error parsing version segment: %w", err)
+ }
+ } else {
+ sv.patch = 0
+ }
+
+ // Perform some basic due diligence on the extra parts to ensure they are
+ // valid.
+
+ 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
+}
+
+// New creates a new instance of Version with each of the parts passed in as
+// arguments instead of parsing a version string.
+func New(major, minor, patch uint64, pre, metadata string) *Version {
+ v := Version{
+ major: major,
+ minor: minor,
+ patch: patch,
+ pre: pre,
+ metadata: metadata,
+ original: "",
+ }
+
+ v.original = v.String()
+
+ return &v
+}
+
+// MustParse parses a given version and panics on error.
+func MustParse(v string) *Version {
+ sv, err := NewVersion(v)
+ if err != nil {
+ panic(err)
+ }
+ return sv
+}
+
+// String converts a Version object to a string.
+// Note, if the original version contained a leading v this version will not.
+// See the Original() method to retrieve the original value. Semantic Versions
+// don't contain a leading v per the spec. Instead it's optional on
+// implementation.
+func (v Version) String() string {
+ var buf bytes.Buffer
+
+ fmt.Fprintf(&buf, "%d.%d.%d", v.major, v.minor, v.patch)
+ if v.pre != "" {
+ fmt.Fprintf(&buf, "-%s", v.pre)
+ }
+ if v.metadata != "" {
+ fmt.Fprintf(&buf, "+%s", v.metadata)
+ }
+
+ return buf.String()
+}
+
+// Original returns the original value passed in to be parsed.
+func (v *Version) Original() string {
+ return v.original
+}
+
+// Major returns the major version.
+func (v Version) Major() uint64 {
+ return v.major
+}
+
+// Minor returns the minor version.
+func (v Version) Minor() uint64 {
+ return v.minor
+}
+
+// Patch returns the patch version.
+func (v Version) Patch() uint64 {
+ return v.patch
+}
+
+// Prerelease returns the pre-release version.
+func (v Version) Prerelease() string {
+ return v.pre
+}
+
+// Metadata returns the metadata on the version.
+func (v Version) Metadata() string {
+ return v.metadata
+}
+
+// originalVPrefix returns the original 'v' prefix if any.
+func (v Version) originalVPrefix() string {
+ // Note, only lowercase v is supported as a prefix by the parser.
+ if v.original != "" && v.original[:1] == "v" {
+ return v.original[:1]
+ }
+ return ""
+}
+
+// IncPatch produces the next patch version.
+// If the current version does not have prerelease/metadata information,
+// it unsets metadata and prerelease values, increments patch number.
+// If the current version has any of prerelease or metadata information,
+// it unsets both values and keeps current patch value
+func (v Version) IncPatch() Version {
+ vNext := v
+ // according to http://semver.org/#spec-item-9
+ // Pre-release versions have a lower precedence than the associated normal version.
+ // according to http://semver.org/#spec-item-10
+ // Build metadata SHOULD be ignored when determining version precedence.
+ if v.pre != "" {
+ vNext.metadata = ""
+ vNext.pre = ""
+ } else {
+ vNext.metadata = ""
+ vNext.pre = ""
+ vNext.patch = v.patch + 1
+ }
+ vNext.original = v.originalVPrefix() + "" + vNext.String()
+ return vNext
+}
+
+// IncMinor produces the next minor version.
+// Sets patch to 0.
+// Increments minor number.
+// Unsets metadata.
+// Unsets prerelease status.
+func (v Version) IncMinor() Version {
+ vNext := v
+ vNext.metadata = ""
+ vNext.pre = ""
+ vNext.patch = 0
+ vNext.minor = v.minor + 1
+ vNext.original = v.originalVPrefix() + "" + vNext.String()
+ return vNext
+}
+
+// IncMajor produces the next major version.
+// Sets patch to 0.
+// Sets minor to 0.
+// Increments major number.
+// Unsets metadata.
+// Unsets prerelease status.
+func (v Version) IncMajor() Version {
+ vNext := v
+ vNext.metadata = ""
+ vNext.pre = ""
+ vNext.patch = 0
+ vNext.minor = 0
+ vNext.major = v.major + 1
+ vNext.original = v.originalVPrefix() + "" + vNext.String()
+ return vNext
+}
+
+// SetPrerelease defines the prerelease value.
+// Value must not include the required 'hyphen' prefix.
+func (v Version) SetPrerelease(prerelease string) (Version, error) {
+ vNext := v
+ if len(prerelease) > 0 {
+ if err := validatePrerelease(prerelease); err != nil {
+ return vNext, err
+ }
+ }
+ vNext.pre = prerelease
+ vNext.original = v.originalVPrefix() + "" + vNext.String()
+ return vNext, nil
+}
+
+// SetMetadata defines metadata value.
+// Value must not include the required 'plus' prefix.
+func (v Version) SetMetadata(metadata string) (Version, error) {
+ vNext := v
+ if len(metadata) > 0 {
+ if err := validateMetadata(metadata); err != nil {
+ return vNext, err
+ }
+ }
+ vNext.metadata = metadata
+ vNext.original = v.originalVPrefix() + "" + vNext.String()
+ return vNext, nil
+}
+
+// LessThan tests if one version is less than another one.
+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
+}
+
+// Compare compares this version to another one. It returns -1, 0, or 1 if
+// the version smaller, equal, or larger than the other version.
+//
+// Versions are compared by X.Y.Z. Build metadata is ignored. Prerelease is
+// lower than the version without a prerelease. Compare always takes into account
+// prereleases. If you want to work with ranges using typical range syntaxes that
+// skip prereleases if the range is not looking for them use constraints.
+func (v *Version) Compare(o *Version) int {
+ // Compare the major, minor, and patch version for differences. If a
+ // difference is found return the comparison.
+ if d := compareSegment(v.Major(), o.Major()); d != 0 {
+ return d
+ }
+ if d := compareSegment(v.Minor(), o.Minor()); d != 0 {
+ return d
+ }
+ if d := compareSegment(v.Patch(), o.Patch()); d != 0 {
+ return d
+ }
+
+ // At this point the major, minor, and patch versions are the same.
+ ps := v.pre
+ po := o.Prerelease()
+
+ if ps == "" && po == "" {
+ return 0
+ }
+ if ps == "" {
+ return 1
+ }
+ if po == "" {
+ return -1
+ }
+
+ return comparePrerelease(ps, po)
+}
+
+// UnmarshalJSON implements JSON.Unmarshaler interface.
+func (v *Version) UnmarshalJSON(b []byte) error {
+ var s string
+ if err := json.Unmarshal(b, &s); err != nil {
+ return err
+ }
+ temp, err := NewVersion(s)
+ if err != nil {
+ return err
+ }
+ v.major = temp.major
+ v.minor = temp.minor
+ v.patch = temp.patch
+ v.pre = temp.pre
+ v.metadata = temp.metadata
+ v.original = temp.original
+ return nil
+}
+
+// MarshalJSON implements JSON.Marshaler interface.
+func (v Version) MarshalJSON() ([]byte, error) {
+ return json.Marshal(v.String())
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+func (v *Version) UnmarshalText(text []byte) error {
+ temp, err := NewVersion(string(text))
+ if err != nil {
+ return err
+ }
+
+ *v = *temp
+
+ return nil
+}
+
+// MarshalText implements the encoding.TextMarshaler interface.
+func (v Version) MarshalText() ([]byte, error) {
+ return []byte(v.String()), nil
+}
+
+// Scan implements the SQL.Scanner interface.
+func (v *Version) Scan(value interface{}) error {
+ var s string
+ s, _ = value.(string)
+ temp, err := NewVersion(s)
+ if err != nil {
+ return err
+ }
+ v.major = temp.major
+ v.minor = temp.minor
+ v.patch = temp.patch
+ v.pre = temp.pre
+ v.metadata = temp.metadata
+ v.original = temp.original
+ return nil
+}
+
+// Value implements the Driver.Valuer interface.
+func (v Version) Value() (driver.Value, error) {
+ return v.String(), nil
+}
+
+func compareSegment(v, o uint64) int {
+ if v < o {
+ return -1
+ }
+ if v > o {
+ return 1
+ }
+
+ return 0
+}
+
+func comparePrerelease(v, o string) int {
+ // split the prelease versions by their part. The separator, per the spec,
+ // is a .
+ sparts := strings.Split(v, ".")
+ oparts := strings.Split(o, ".")
+
+ // Find the longer length of the parts to know how many loop iterations to
+ // go through.
+ slen := len(sparts)
+ olen := len(oparts)
+
+ l := slen
+ if olen > slen {
+ l = olen
+ }
+
+ // Iterate over each part of the prereleases to compare the differences.
+ for i := 0; i < l; i++ {
+ // Since the lentgh of the parts can be different we need to create
+ // a placeholder. This is to avoid out of bounds issues.
+ stemp := ""
+ if i < slen {
+ stemp = sparts[i]
+ }
+
+ otemp := ""
+ if i < olen {
+ otemp = oparts[i]
+ }
+
+ d := comparePrePart(stemp, otemp)
+ if d != 0 {
+ return d
+ }
+ }
+
+ // Reaching here means two versions are of equal value but have different
+ // metadata (the part following a +). They are not identical in string form
+ // but the version comparison finds them to be equal.
+ return 0
+}
+
+func comparePrePart(s, o string) int {
+ // Fastpath if they are equal
+ if s == o {
+ return 0
+ }
+
+ // When s or o are empty we can use the other in an attempt to determine
+ // the response.
+ if s == "" {
+ if o != "" {
+ return -1
+ }
+ return 1
+ }
+
+ if o == "" {
+ if s != "" {
+ return 1
+ }
+ return -1
+ }
+
+ // When comparing strings "99" is greater than "103". To handle
+ // cases like this we need to detect numbers and compare them. According
+ // to the semver spec, numbers are always positive. If there is a - at the
+ // start like -99 this is to be evaluated as an alphanum. numbers always
+ // have precedence over alphanum. Parsing as Uints because negative numbers
+ // are ignored.
+
+ oi, n1 := strconv.ParseUint(o, 10, 64)
+ si, n2 := strconv.ParseUint(s, 10, 64)
+
+ // The case where both are strings compare the strings
+ if n1 != nil && n2 != nil {
+ if s > o {
+ return 1
+ }
+ return -1
+ } else if n1 != nil {
+ // o is a string and s is a number
+ return -1
+ } else if n2 != nil {
+ // s is a string and o is a number
+ return 1
+ }
+ // Both are numbers
+ if si > oi {
+ return 1
+ }
+ return -1
+}
+
+// Like strings.ContainsAny but does an only instead of any.
+func containsOnly(s string, comp string) bool {
+ return strings.IndexFunc(s, func(r rune) bool {
+ return !strings.ContainsRune(comp, r)
+ }) == -1
+}
+
+// From the spec, "Identifiers MUST comprise only
+// ASCII alphanumerics and hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty.
+// Numeric identifiers MUST NOT include leading zeroes.". These segments can
+// be dot separated.
+func validatePrerelease(p string) error {
+ eparts := strings.Split(p, ".")
+ for _, p := range eparts {
+ if p == "" {
+ return ErrInvalidPrerelease
+ } else if containsOnly(p, num) {
+ if len(p) > 1 && p[0] == '0' {
+ return ErrSegmentStartsZero
+ }
+ } else if !containsOnly(p, allowed) {
+ return ErrInvalidPrerelease
+ }
+ }
+
+ return nil
+}
+
+// From the spec, "Build metadata MAY be denoted by
+// appending a plus sign and a series of dot separated identifiers immediately
+// following the patch or pre-release version. Identifiers MUST comprise only
+// ASCII alphanumerics and hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty."
+func validateMetadata(m string) error {
+ eparts := strings.Split(m, ".")
+ for _, p := range eparts {
+ if p == "" {
+ return ErrInvalidMetadata
+ } else if !containsOnly(p, allowed) {
+ return ErrInvalidMetadata
+ }
+ }
+ return nil
+}
+
+// validateVersion checks for common validation issues but may not catch all errors
+func validateVersion(m []string) error {
+ var err error
+ var v string
+ if m[1] != "" {
+ if len(m[1]) > 1 && m[1][0] == '0' {
+ return ErrSegmentStartsZero
+ }
+ _, err = strconv.ParseUint(m[1], 10, 64)
+ if err != nil {
+ return fmt.Errorf("error parsing version segment: %w", err)
+ }
+ }
+
+ if m[2] != "" {
+ v = strings.TrimPrefix(m[2], ".")
+ if len(v) > 1 && v[0] == '0' {
+ return ErrSegmentStartsZero
+ }
+ _, err = strconv.ParseUint(v, 10, 64)
+ if err != nil {
+ return fmt.Errorf("error parsing version segment: %w", err)
+ }
+ }
+
+ if m[3] != "" {
+ v = strings.TrimPrefix(m[3], ".")
+ if len(v) > 1 && v[0] == '0' {
+ return ErrSegmentStartsZero
+ }
+ _, err = strconv.ParseUint(v, 10, 64)
+ if err != nil {
+ return fmt.Errorf("error parsing version segment: %w", err)
+ }
+ }
+
+ if m[5] != "" {
+ if err = validatePrerelease(m[5]); err != nil {
+ return err
+ }
+ }
+
+ if m[8] != "" {
+ if err = validateMetadata(m[8]); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/Masterminds/sprig/v3/.gitignore b/vendor/github.com/Masterminds/sprig/v3/.gitignore
new file mode 100644
index 0000000000..5e3002f88f
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/v3/.gitignore
@@ -0,0 +1,2 @@
+vendor/
+/.glide
diff --git a/vendor/github.com/Masterminds/sprig/v3/CHANGELOG.md b/vendor/github.com/Masterminds/sprig/v3/CHANGELOG.md
new file mode 100644
index 0000000000..b5ef766a7a
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/v3/CHANGELOG.md
@@ -0,0 +1,401 @@
+# 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
+
+- Updated docs (thanks @book987 @aJetHorn @neelayu @pellizzetti @apricote @SaigyoujiYuyuko233 @AlekSi)
+- #348: Updated huandu/xstrings which fixed a snake case bug (thanks @yxxhero)
+- #353: Updated masterminds/semver which included bug fixes
+- #354: Updated golang.org/x/crypto which included bug fixes
+
+## Release 3.2.2 (2021-02-04)
+
+This is a re-release of 3.2.1 to satisfy something with the Go module system.
+
+## Release 3.2.1 (2021-02-04)
+
+### Changed
+
+- Upgraded `Masterminds/goutils` to `v1.1.1`. see the [Security Advisory](https://github.com/Masterminds/goutils/security/advisories/GHSA-xg2h-wx96-xgxr)
+
+## Release 3.2.0 (2020-12-14)
+
+### Added
+
+- #211: Added randInt function (thanks @kochurovro)
+- #223: Added fromJson and mustFromJson functions (thanks @mholt)
+- #242: Added a bcrypt function (thanks @robbiet480)
+- #253: Added randBytes function (thanks @MikaelSmith)
+- #254: Added dig function for dicts (thanks @nyarly)
+- #257: Added regexQuoteMeta for quoting regex metadata (thanks @rheaton)
+- #261: Added filepath functions osBase, osDir, osExt, osClean, osIsAbs (thanks @zugl)
+- #268: Added and and all functions for testing conditions (thanks @phuslu)
+- #181: Added float64 arithmetic addf, add1f, subf, divf, mulf, maxf, and minf
+ (thanks @andrewmostello)
+- #265: Added chunk function to split array into smaller arrays (thanks @karelbilek)
+- #270: Extend certificate functions to handle non-RSA keys + add support for
+ ed25519 keys (thanks @misberner)
+
+### Changed
+
+- Removed testing and support for Go 1.12. ed25519 support requires Go 1.13 or newer
+- Using semver 3.1.1 and mergo 0.3.11
+
+### Fixed
+
+- #249: Fix htmlDateInZone example (thanks @spawnia)
+
+NOTE: The dependency github.com/imdario/mergo reverted the breaking change in
+0.3.9 via 0.3.10 release.
+
+## Release 3.1.0 (2020-04-16)
+
+NOTE: The dependency github.com/imdario/mergo made a behavior change in 0.3.9
+that impacts sprig functionality. Do not use sprig with a version newer than 0.3.8.
+
+### Added
+
+- #225: Added support for generating htpasswd hash (thanks @rustycl0ck)
+- #224: Added duration filter (thanks @frebib)
+- #205: Added `seq` function (thanks @thadc23)
+
+### Changed
+
+- #203: Unlambda functions with correct signature (thanks @muesli)
+- #236: Updated the license formatting for GitHub display purposes
+- #238: Updated package dependency versions. Note, mergo not updated to 0.3.9
+ as it causes a breaking change for sprig. That issue is tracked at
+ https://github.com/imdario/mergo/issues/139
+
+### Fixed
+
+- #229: Fix `seq` example in docs (thanks @kalmant)
+
+## Release 3.0.2 (2019-12-13)
+
+### Fixed
+
+- #220: Updating to semver v3.0.3 to fix issue with <= ranges
+- #218: fix typo elyptical->elliptic in ecdsa key description (thanks @laverya)
+
+## Release 3.0.1 (2019-12-08)
+
+### Fixed
+
+- #212: Updated semver fixing broken constraint checking with ^0.0
+
+## Release 3.0.0 (2019-10-02)
+
+### Added
+
+- #187: Added durationRound function (thanks @yjp20)
+- #189: Added numerous template functions that return errors rather than panic (thanks @nrvnrvn)
+- #193: Added toRawJson support (thanks @Dean-Coakley)
+- #197: Added get support to dicts (thanks @Dean-Coakley)
+
+### Changed
+
+- #186: Moving dependency management to Go modules
+- #186: Updated semver to v3. This has changes in the way ^ is handled
+- #194: Updated documentation on merging and how it copies. Added example using deepCopy
+- #196: trunc now supports negative values (thanks @Dean-Coakley)
+
+## Release 2.22.0 (2019-10-02)
+
+### Added
+
+- #173: Added getHostByName function to resolve dns names to ips (thanks @fcgravalos)
+- #195: Added deepCopy function for use with dicts
+
+### Changed
+
+- Updated merge and mergeOverwrite documentation to explain copying and how to
+ use deepCopy with it
+
+## Release 2.21.0 (2019-09-18)
+
+### Added
+
+- #122: Added encryptAES/decryptAES functions (thanks @n0madic)
+- #128: Added toDecimal support (thanks @Dean-Coakley)
+- #169: Added list contcat (thanks @astorath)
+- #174: Added deepEqual function (thanks @bonifaido)
+- #170: Added url parse and join functions (thanks @astorath)
+
+### Changed
+
+- #171: Updated glide config for Google UUID to v1 and to add ranges to semver and testify
+
+### Fixed
+
+- #172: Fix semver wildcard example (thanks @piepmatz)
+- #175: Fix dateInZone doc example (thanks @s3than)
+
+## Release 2.20.0 (2019-06-18)
+
+### Added
+
+- #164: Adding function to get unix epoch for a time (@mattfarina)
+- #166: Adding tests for date_in_zone (@mattfarina)
+
+### Changed
+
+- #144: Fix function comments based on best practices from Effective Go (@CodeLingoTeam)
+- #150: Handles pointer type for time.Time in "htmlDate" (@mapreal19)
+- #161, #157, #160, #153, #158, #156, #155, #159, #152 documentation updates (@badeadan)
+
+### Fixed
+
+## Release 2.19.0 (2019-03-02)
+
+IMPORTANT: This release reverts a change from 2.18.0
+
+In the previous release (2.18), we prematurely merged a partial change to the crypto functions that led to creating two sets of crypto functions (I blame @technosophos -- since that's me). This release rolls back that change, and does what was originally intended: It alters the existing crypto functions to use secure random.
+
+We debated whether this classifies as a change worthy of major revision, but given the proximity to the last release, we have decided that treating 2.18 as a faulty release is the correct course of action. We apologize for any inconvenience.
+
+### Changed
+
+- Fix substr panic 35fb796 (Alexey igrychev)
+- Remove extra period 1eb7729 (Matthew Lorimor)
+- Make random string functions use crypto by default 6ceff26 (Matthew Lorimor)
+- README edits/fixes/suggestions 08fe136 (Lauri Apple)
+
+
+## Release 2.18.0 (2019-02-12)
+
+### Added
+
+- Added mergeOverwrite function
+- cryptographic functions that use secure random (see fe1de12)
+
+### Changed
+
+- Improve documentation of regexMatch function, resolves #139 90b89ce (Jan Tagscherer)
+- Handle has for nil list 9c10885 (Daniel Cohen)
+- Document behaviour of mergeOverwrite fe0dbe9 (Lukas Rieder)
+- doc: adds missing documentation. 4b871e6 (Fernandez Ludovic)
+- Replace outdated goutils imports 01893d2 (Matthew Lorimor)
+- Surface crypto secure random strings from goutils fe1de12 (Matthew Lorimor)
+- Handle untyped nil values as paramters to string functions 2b2ec8f (Morten Torkildsen)
+
+### Fixed
+
+- Fix dict merge issue and provide mergeOverwrite .dst .src1 to overwrite from src -> dst 4c59c12 (Lukas Rieder)
+- Fix substr var names and comments d581f80 (Dean Coakley)
+- Fix substr documentation 2737203 (Dean Coakley)
+
+## Release 2.17.1 (2019-01-03)
+
+### Fixed
+
+The 2.17.0 release did not have a version pinned for xstrings, which caused compilation failures when xstrings < 1.2 was used. This adds the correct version string to glide.yaml.
+
+## Release 2.17.0 (2019-01-03)
+
+### Added
+
+- adds alder32sum function and test 6908fc2 (marshallford)
+- Added kebabcase function ca331a1 (Ilyes512)
+
+### Changed
+
+- Update goutils to 1.1.0 4e1125d (Matt Butcher)
+
+### Fixed
+
+- Fix 'has' documentation e3f2a85 (dean-coakley)
+- docs(dict): fix typo in pick example dc424f9 (Dustin Specker)
+- fixes spelling errors... not sure how that happened 4cf188a (marshallford)
+
+## Release 2.16.0 (2018-08-13)
+
+### Added
+
+- add splitn function fccb0b0 (Helgi Þorbjörnsson)
+- Add slice func df28ca7 (gongdo)
+- Generate serial number a3bdffd (Cody Coons)
+- Extract values of dict with values function df39312 (Lawrence Jones)
+
+### Changed
+
+- Modify panic message for list.slice ae38335 (gongdo)
+- Minor improvement in code quality - Removed an unreachable piece of code at defaults.go#L26:6 - Resolve formatting issues. 5834241 (Abhishek Kashyap)
+- Remove duplicated documentation 1d97af1 (Matthew Fisher)
+- Test on go 1.11 49df809 (Helgi Þormar Þorbjörnsson)
+
+### Fixed
+
+- Fix file permissions c5f40b5 (gongdo)
+- Fix example for buildCustomCert 7779e0d (Tin Lam)
+
+## Release 2.15.0 (2018-04-02)
+
+### Added
+
+- #68 and #69: Add json helpers to docs (thanks @arunvelsriram)
+- #66: Add ternary function (thanks @binoculars)
+- #67: Allow keys function to take multiple dicts (thanks @binoculars)
+- #89: Added sha1sum to crypto function (thanks @benkeil)
+- #81: Allow customizing Root CA that used by genSignedCert (thanks @chenzhiwei)
+- #92: Add travis testing for go 1.10
+- #93: Adding appveyor config for windows testing
+
+### Changed
+
+- #90: Updating to more recent dependencies
+- #73: replace satori/go.uuid with google/uuid (thanks @petterw)
+
+### Fixed
+
+- #76: Fixed documentation typos (thanks @Thiht)
+- Fixed rounding issue on the `ago` function. Note, the removes support for Go 1.8 and older
+
+## Release 2.14.1 (2017-12-01)
+
+### Fixed
+
+- #60: Fix typo in function name documentation (thanks @neil-ca-moore)
+- #61: Removing line with {{ due to blocking github pages genertion
+- #64: Update the list functions to handle int, string, and other slices for compatibility
+
+## Release 2.14.0 (2017-10-06)
+
+This new version of Sprig adds a set of functions for generating and working with SSL certificates.
+
+- `genCA` generates an SSL Certificate Authority
+- `genSelfSignedCert` generates an SSL self-signed certificate
+- `genSignedCert` generates an SSL certificate and key based on a given CA
+
+## Release 2.13.0 (2017-09-18)
+
+This release adds new functions, including:
+
+- `regexMatch`, `regexFindAll`, `regexFind`, `regexReplaceAll`, `regexReplaceAllLiteral`, and `regexSplit` to work with regular expressions
+- `floor`, `ceil`, and `round` math functions
+- `toDate` converts a string to a date
+- `nindent` is just like `indent` but also prepends a new line
+- `ago` returns the time from `time.Now`
+
+### Added
+
+- #40: Added basic regex functionality (thanks @alanquillin)
+- #41: Added ceil floor and round functions (thanks @alanquillin)
+- #48: Added toDate function (thanks @andreynering)
+- #50: Added nindent function (thanks @binoculars)
+- #46: Added ago function (thanks @slayer)
+
+### Changed
+
+- #51: Updated godocs to include new string functions (thanks @curtisallen)
+- #49: Added ability to merge multiple dicts (thanks @binoculars)
+
+## Release 2.12.0 (2017-05-17)
+
+- `snakecase`, `camelcase`, and `shuffle` are three new string functions
+- `fail` allows you to bail out of a template render when conditions are not met
+
+## Release 2.11.0 (2017-05-02)
+
+- Added `toJson` and `toPrettyJson`
+- Added `merge`
+- Refactored documentation
+
+## Release 2.10.0 (2017-03-15)
+
+- Added `semver` and `semverCompare` for Semantic Versions
+- `list` replaces `tuple`
+- Fixed issue with `join`
+- 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)
+
+- Added `splitList` to split a list
+- Added crypto functions of `genPrivateKey` and `derivePassword`
+
+## Release 2.8.0 (2016-12-21)
+
+- Added access to several path functions (`base`, `dir`, `clean`, `ext`, and `abs`)
+- Added functions for _mutating_ dictionaries (`set`, `unset`, `hasKey`)
+
+## Release 2.7.0 (2016-12-01)
+
+- Added `sha256sum` to generate a hash of an input
+- Added functions to convert a numeric or string to `int`, `int64`, `float64`
+
+## Release 2.6.0 (2016-10-03)
+
+- Added a `uuidv4` template function for generating UUIDs inside of a template.
+
+## Release 2.5.0 (2016-08-19)
+
+- New `trimSuffix`, `trimPrefix`, `hasSuffix`, and `hasPrefix` functions
+- New aliases have been added for a few functions that didn't follow the naming conventions (`trimAll` and `abbrevBoth`)
+- `trimall` and `abbrevboth` (notice the case) are deprecated and will be removed in 3.0.0
+
+## Release 2.4.0 (2016-08-16)
+
+- Adds two functions: `until` and `untilStep`
+
+## Release 2.3.0 (2016-06-21)
+
+- cat: Concatenate strings with whitespace separators.
+- replace: Replace parts of a string: `replace " " "-" "Me First"` renders "Me-First"
+- plural: Format plurals: `len "foo" | plural "one foo" "many foos"` renders "many foos"
+- indent: Indent blocks of text in a way that is sensitive to "\n" characters.
+
+## Release 2.2.0 (2016-04-21)
+
+- Added a `genPrivateKey` function (Thanks @bacongobbler)
+
+## Release 2.1.0 (2016-03-30)
+
+- `default` now prints the default value when it does not receive a value down the pipeline. It is much safer now to do `{{.Foo | default "bar"}}`.
+- Added accessors for "hermetic" functions. These return only functions that, when given the same input, produce the same output.
+
+## Release 2.0.0 (2016-03-29)
+
+Because we switched from `int` to `int64` as the return value for all integer math functions, the library's major version number has been incremented.
+
+- `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"}}`
+- 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`).
+
+## Release 1.2.0 (2016-02-01)
+
+- Added quote and squote
+- Added b32enc and b32dec
+- add now takes varargs
+- biggest now takes varargs
+
+## Release 1.1.0 (2015-12-29)
+
+- Added #4: Added contains function. strings.Contains, but with the arguments
+ switched to simplify common pipelines. (thanks krancour)
+- Added Travis-CI testing support
+
+## Release 1.0.0 (2015-12-23)
+
+- Initial release
diff --git a/vendor/github.com/Masterminds/sprig/v3/LICENSE.txt b/vendor/github.com/Masterminds/sprig/v3/LICENSE.txt
new file mode 100644
index 0000000000..f311b1eaaa
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/v3/LICENSE.txt
@@ -0,0 +1,19 @@
+Copyright (C) 2013-2020 Masterminds
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/github.com/Masterminds/sprig/v3/Makefile b/vendor/github.com/Masterminds/sprig/v3/Makefile
new file mode 100644
index 0000000000..78d409cde2
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/v3/Makefile
@@ -0,0 +1,9 @@
+.PHONY: test
+test:
+ @echo "==> Running tests"
+ GO111MODULE=on go test -v
+
+.PHONY: test-cover
+test-cover:
+ @echo "==> Running Tests with coverage"
+ GO111MODULE=on go test -cover .
diff --git a/vendor/github.com/Masterminds/sprig/v3/README.md b/vendor/github.com/Masterminds/sprig/v3/README.md
new file mode 100644
index 0000000000..3e22c60e1a
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/v3/README.md
@@ -0,0 +1,100 @@
+# Sprig: Template functions for Go templates
+
+[](https://pkg.go.dev/github.com/Masterminds/sprig/v3)
+[](https://goreportcard.com/report/github.com/Masterminds/sprig)
+[](https://masterminds.github.io/stability/sustained.html)
+[](https://github.com/Masterminds/sprig/actions)
+
+The Go language comes with a [built-in template
+language](http://golang.org/pkg/text/template/), but not
+very many template functions. Sprig is a library that provides more than 100 commonly
+used template functions.
+
+It is inspired by the template functions found in
+[Twig](http://twig.sensiolabs.org/documentation) and in various
+JavaScript libraries, such as [underscore.js](http://underscorejs.org/).
+
+## IMPORTANT NOTES
+
+Sprig leverages [mergo](https://github.com/imdario/mergo) to handle merges. In
+its v0.3.9 release, there was a behavior change that impacts merging template
+functions in sprig. It is currently recommended to use v0.3.10 or later of that package.
+Using v0.3.9 will cause sprig tests to fail.
+
+## Package Versions
+
+There are two active major versions of the `sprig` package.
+
+* v3 is currently stable release series on the `master` branch. The Go API should
+ remain compatible with v2, the current stable version. Behavior change behind
+ some functions is the reason for the new major version.
+* v2 is the previous stable release series. It has been more than three years since
+ the initial release of v2. You can read the documentation and see the code
+ on the [release-2](https://github.com/Masterminds/sprig/tree/release-2) branch.
+ Bug fixes to this major version will continue for some time.
+
+## Usage
+
+**Template developers**: Please use Sprig's [function documentation](http://masterminds.github.io/sprig/) for
+detailed instructions and code snippets for the >100 template functions available.
+
+**Go developers**: If you'd like to include Sprig as a library in your program,
+our API documentation is available [at GoDoc.org](http://godoc.org/github.com/Masterminds/sprig).
+
+For standard usage, read on.
+
+### Load the Sprig library
+
+To load the Sprig `FuncMap`:
+
+```go
+
+import (
+ "github.com/Masterminds/sprig/v3"
+ "html/template"
+)
+
+// This example illustrates that the FuncMap *must* be set before the
+// templates themselves are loaded.
+tpl := template.Must(
+ template.New("base").Funcs(sprig.FuncMap()).ParseGlob("*.html")
+)
+
+
+```
+
+### Calling the functions inside of templates
+
+By convention, all functions are lowercase. This seems to follow the Go
+idiom for template functions (as opposed to template methods, which are
+TitleCase). For example, this:
+
+```
+{{ "hello!" | upper | repeat 5 }}
+```
+
+produces this:
+
+```
+HELLO!HELLO!HELLO!HELLO!HELLO!
+```
+
+## Principles Driving Our Function Selection
+
+We followed these principles to decide which functions to add and how to implement them:
+
+- Use template functions to build layout. The following
+ types of operations are within the domain of template functions:
+ - Formatting
+ - Layout
+ - Simple type conversions
+ - Utilities that assist in handling common formatting and layout needs (e.g. arithmetic)
+- Template functions should not return errors unless there is no way to print
+ a sensible value. For example, converting a string to an integer should not
+ produce an error if conversion fails. Instead, it should display a default
+ value.
+- Simple math is necessary for grid layouts, pagers, and so on. Complex math
+ (anything other than arithmetic) should be done outside of templates.
+- Template functions only deal with the data passed into them. They never retrieve
+ data from a source.
+- Finally, do not override core Go template functions.
diff --git a/vendor/github.com/Masterminds/sprig/v3/crypto.go b/vendor/github.com/Masterminds/sprig/v3/crypto.go
new file mode 100644
index 0000000000..75fe027e4d
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/v3/crypto.go
@@ -0,0 +1,659 @@
+package sprig
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/dsa"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/elliptic"
+ "crypto/hmac"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/sha512"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/asn1"
+ "encoding/base64"
+ "encoding/binary"
+ "encoding/hex"
+ "encoding/pem"
+ "errors"
+ "fmt"
+ "hash/adler32"
+ "io"
+ "math/big"
+ "net"
+ "time"
+
+ "strings"
+
+ "github.com/google/uuid"
+ bcrypt_lib "golang.org/x/crypto/bcrypt"
+ "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[:])
+}
+
+func sha1sum(input string) string {
+ hash := sha1.Sum([]byte(input))
+ return hex.EncodeToString(hash[:])
+}
+
+func adler32sum(input string) string {
+ hash := adler32.Checksum([]byte(input))
+ return fmt.Sprintf("%d", hash)
+}
+
+func bcrypt(input string) string {
+ hash, err := bcrypt_lib.GenerateFromPassword([]byte(input), bcrypt_lib.DefaultCost)
+ if err != nil {
+ return fmt.Sprintf("failed to encrypt string with bcrypt: %s", err)
+ }
+
+ return string(hash)
+}
+
+func htpasswd(username string, password string) string {
+ if strings.Contains(username, ":") {
+ return fmt.Sprintf("invalid username: %s", username)
+ }
+ return fmt.Sprintf("%s:%s", username, bcrypt(password))
+}
+
+func randBytes(count int) (string, error) {
+ buf := make([]byte, count)
+ if _, err := rand.Read(buf); err != nil {
+ return "", err
+ }
+ return base64.StdEncoding.EncodeToString(buf), nil
+}
+
+// uuidv4 provides a safe and secure UUID v4 implementation
+func uuidv4() string {
+ return uuid.New().String()
+}
+
+var masterPasswordSeed = "com.lyndir.masterpassword"
+
+var passwordTypeTemplates = map[string][][]byte{
+ "maximum": {[]byte("anoxxxxxxxxxxxxxxxxx"), []byte("axxxxxxxxxxxxxxxxxno")},
+ "long": {[]byte("CvcvnoCvcvCvcv"), []byte("CvcvCvcvnoCvcv"), []byte("CvcvCvcvCvcvno"), []byte("CvccnoCvcvCvcv"), []byte("CvccCvcvnoCvcv"),
+ []byte("CvccCvcvCvcvno"), []byte("CvcvnoCvccCvcv"), []byte("CvcvCvccnoCvcv"), []byte("CvcvCvccCvcvno"), []byte("CvcvnoCvcvCvcc"),
+ []byte("CvcvCvcvnoCvcc"), []byte("CvcvCvcvCvccno"), []byte("CvccnoCvccCvcv"), []byte("CvccCvccnoCvcv"), []byte("CvccCvccCvcvno"),
+ []byte("CvcvnoCvccCvcc"), []byte("CvcvCvccnoCvcc"), []byte("CvcvCvccCvccno"), []byte("CvccnoCvcvCvcc"), []byte("CvccCvcvnoCvcc"),
+ []byte("CvccCvcvCvccno")},
+ "medium": {[]byte("CvcnoCvc"), []byte("CvcCvcno")},
+ "short": {[]byte("Cvcn")},
+ "basic": {[]byte("aaanaaan"), []byte("aannaaan"), []byte("aaannaaa")},
+ "pin": {[]byte("nnnn")},
+}
+
+var templateCharacters = map[byte]string{
+ 'V': "AEIOU",
+ 'C': "BCDFGHJKLMNPQRSTVWXYZ",
+ 'v': "aeiou",
+ 'c': "bcdfghjklmnpqrstvwxyz",
+ 'A': "AEIOUBCDFGHJKLMNPQRSTVWXYZ",
+ 'a': "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz",
+ 'n': "0123456789",
+ 'o': "@&%?,=[]_:-+*$#!'^~;()/.",
+ 'x': "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()",
+}
+
+func derivePassword(counter uint32, passwordType, password, user, site string) string {
+ var templates = passwordTypeTemplates[passwordType]
+ if templates == nil {
+ return fmt.Sprintf("cannot find password template %s", passwordType)
+ }
+
+ var buffer bytes.Buffer
+ buffer.WriteString(masterPasswordSeed)
+ binary.Write(&buffer, binary.BigEndian, uint32(len(user)))
+ buffer.WriteString(user)
+
+ salt := buffer.Bytes()
+ key, err := scrypt.Key([]byte(password), salt, 32768, 8, 2, 64)
+ if err != nil {
+ return fmt.Sprintf("failed to derive password: %s", err)
+ }
+
+ buffer.Truncate(len(masterPasswordSeed))
+ binary.Write(&buffer, binary.BigEndian, uint32(len(site)))
+ buffer.WriteString(site)
+ binary.Write(&buffer, binary.BigEndian, counter)
+
+ var hmacv = hmac.New(sha256.New, key)
+ hmacv.Write(buffer.Bytes())
+ var seed = hmacv.Sum(nil)
+ var temp = templates[int(seed[0])%len(templates)]
+
+ buffer.Truncate(0)
+ for i, element := range temp {
+ passChars := templateCharacters[element]
+ passChar := passChars[int(seed[i+1])%len(passChars)]
+ buffer.WriteByte(passChar)
+ }
+
+ return buffer.String()
+}
+
+func generatePrivateKey(typ string) string {
+ var priv interface{}
+ var err error
+ switch typ {
+ case "", "rsa":
+ // good enough for government work
+ priv, err = rsa.GenerateKey(rand.Reader, 4096)
+ case "dsa":
+ key := new(dsa.PrivateKey)
+ // again, good enough for government work
+ if err = dsa.GenerateParameters(&key.Parameters, rand.Reader, dsa.L2048N256); err != nil {
+ return fmt.Sprintf("failed to generate dsa params: %s", err)
+ }
+ err = dsa.GenerateKey(key, rand.Reader)
+ priv = key
+ case "ecdsa":
+ // again, good enough for government work
+ priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ case "ed25519":
+ _, priv, err = ed25519.GenerateKey(rand.Reader)
+ default:
+ return "Unknown type " + typ
+ }
+ if err != nil {
+ return fmt.Sprintf("failed to generate private key: %s", err)
+ }
+
+ return string(pem.EncodeToMemory(pemBlockForKey(priv)))
+}
+
+// DSAKeyFormat stores the format for DSA keys.
+// Used by pemBlockForKey
+type DSAKeyFormat struct {
+ Version int
+ P, Q, G, Y, X *big.Int
+}
+
+func pemBlockForKey(priv interface{}) *pem.Block {
+ switch k := priv.(type) {
+ case *rsa.PrivateKey:
+ return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
+ case *dsa.PrivateKey:
+ val := DSAKeyFormat{
+ P: k.P, Q: k.Q, G: k.G,
+ Y: k.Y, X: k.X,
+ }
+ bytes, _ := asn1.Marshal(val)
+ return &pem.Block{Type: "DSA PRIVATE KEY", Bytes: bytes}
+ case *ecdsa.PrivateKey:
+ b, _ := x509.MarshalECPrivateKey(k)
+ return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
+ default:
+ // attempt PKCS#8 format for all other keys
+ b, err := x509.MarshalPKCS8PrivateKey(k)
+ if err != nil {
+ return nil
+ }
+ return &pem.Block{Type: "PRIVATE KEY", Bytes: b}
+ }
+}
+
+func parsePrivateKeyPEM(pemBlock string) (crypto.PrivateKey, error) {
+ block, _ := pem.Decode([]byte(pemBlock))
+ if block == nil {
+ return nil, errors.New("no PEM data in input")
+ }
+
+ if block.Type == "PRIVATE KEY" {
+ priv, err := x509.ParsePKCS8PrivateKey(block.Bytes)
+ if err != nil {
+ return nil, fmt.Errorf("decoding PEM as PKCS#8: %s", err)
+ }
+ return priv, nil
+ } else if !strings.HasSuffix(block.Type, " PRIVATE KEY") {
+ return nil, fmt.Errorf("no private key data in PEM block of type %s", block.Type)
+ }
+
+ switch block.Type[:len(block.Type)-12] { // strip " PRIVATE KEY"
+ case "RSA":
+ priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
+ if err != nil {
+ return nil, fmt.Errorf("parsing RSA private key from PEM: %s", err)
+ }
+ return priv, nil
+ case "EC":
+ priv, err := x509.ParseECPrivateKey(block.Bytes)
+ if err != nil {
+ return nil, fmt.Errorf("parsing EC private key from PEM: %s", err)
+ }
+ return priv, nil
+ case "DSA":
+ var k DSAKeyFormat
+ _, err := asn1.Unmarshal(block.Bytes, &k)
+ if err != nil {
+ return nil, fmt.Errorf("parsing DSA private key from PEM: %s", err)
+ }
+ priv := &dsa.PrivateKey{
+ PublicKey: dsa.PublicKey{
+ Parameters: dsa.Parameters{
+ P: k.P, Q: k.Q, G: k.G,
+ },
+ Y: k.Y,
+ },
+ X: k.X,
+ }
+ return priv, nil
+ default:
+ return nil, fmt.Errorf("invalid private key type %s", block.Type)
+ }
+}
+
+func getPublicKey(priv crypto.PrivateKey) (crypto.PublicKey, error) {
+ switch k := priv.(type) {
+ case interface{ Public() crypto.PublicKey }:
+ return k.Public(), nil
+ case *dsa.PrivateKey:
+ return &k.PublicKey, nil
+ default:
+ return nil, fmt.Errorf("unable to get public key for type %T", priv)
+ }
+}
+
+type certificate struct {
+ Cert string
+ Key string
+}
+
+func buildCustomCertificate(b64cert string, b64key string) (certificate, error) {
+ crt := certificate{}
+
+ cert, err := base64.StdEncoding.DecodeString(b64cert)
+ if err != nil {
+ return crt, errors.New("unable to decode base64 certificate")
+ }
+
+ key, err := base64.StdEncoding.DecodeString(b64key)
+ if err != nil {
+ return crt, errors.New("unable to decode base64 private key")
+ }
+
+ decodedCert, _ := pem.Decode(cert)
+ if decodedCert == nil {
+ return crt, errors.New("unable to decode certificate")
+ }
+ _, err = x509.ParseCertificate(decodedCert.Bytes)
+ if err != nil {
+ return crt, fmt.Errorf(
+ "error parsing certificate: decodedCert.Bytes: %s",
+ err,
+ )
+ }
+
+ _, err = parsePrivateKeyPEM(string(key))
+ if err != nil {
+ return crt, fmt.Errorf(
+ "error parsing private key: %s",
+ err,
+ )
+ }
+
+ crt.Cert = string(cert)
+ crt.Key = string(key)
+
+ return crt, nil
+}
+
+func generateCertificateAuthority(
+ cn string,
+ daysValid int,
+) (certificate, error) {
+ priv, err := rsa.GenerateKey(rand.Reader, 2048)
+ if err != nil {
+ return certificate{}, fmt.Errorf("error generating rsa key: %s", err)
+ }
+
+ return generateCertificateAuthorityWithKeyInternal(cn, daysValid, priv)
+}
+
+func generateCertificateAuthorityWithPEMKey(
+ cn string,
+ daysValid int,
+ privPEM string,
+) (certificate, error) {
+ priv, err := parsePrivateKeyPEM(privPEM)
+ if err != nil {
+ return certificate{}, fmt.Errorf("parsing private key: %s", err)
+ }
+ return generateCertificateAuthorityWithKeyInternal(cn, daysValid, priv)
+}
+
+func generateCertificateAuthorityWithKeyInternal(
+ cn string,
+ daysValid int,
+ priv crypto.PrivateKey,
+) (certificate, error) {
+ ca := certificate{}
+
+ template, err := getBaseCertTemplate(cn, nil, nil, daysValid)
+ if err != nil {
+ return ca, err
+ }
+ // Override KeyUsage and IsCA
+ template.KeyUsage = x509.KeyUsageKeyEncipherment |
+ x509.KeyUsageDigitalSignature |
+ x509.KeyUsageCertSign
+ template.IsCA = true
+
+ ca.Cert, ca.Key, err = getCertAndKey(template, priv, template, priv)
+
+ return ca, err
+}
+
+func generateSelfSignedCertificate(
+ cn string,
+ ips []interface{},
+ alternateDNS []interface{},
+ daysValid int,
+) (certificate, error) {
+ priv, err := rsa.GenerateKey(rand.Reader, 2048)
+ if err != nil {
+ return certificate{}, fmt.Errorf("error generating rsa key: %s", err)
+ }
+ return generateSelfSignedCertificateWithKeyInternal(cn, ips, alternateDNS, daysValid, priv)
+}
+
+func generateSelfSignedCertificateWithPEMKey(
+ cn string,
+ ips []interface{},
+ alternateDNS []interface{},
+ daysValid int,
+ privPEM string,
+) (certificate, error) {
+ priv, err := parsePrivateKeyPEM(privPEM)
+ if err != nil {
+ return certificate{}, fmt.Errorf("parsing private key: %s", err)
+ }
+ return generateSelfSignedCertificateWithKeyInternal(cn, ips, alternateDNS, daysValid, priv)
+}
+
+func generateSelfSignedCertificateWithKeyInternal(
+ cn string,
+ ips []interface{},
+ alternateDNS []interface{},
+ daysValid int,
+ priv crypto.PrivateKey,
+) (certificate, error) {
+ cert := certificate{}
+
+ template, err := getBaseCertTemplate(cn, ips, alternateDNS, daysValid)
+ if err != nil {
+ return cert, err
+ }
+
+ cert.Cert, cert.Key, err = getCertAndKey(template, priv, template, priv)
+
+ return cert, err
+}
+
+func generateSignedCertificate(
+ cn string,
+ ips []interface{},
+ alternateDNS []interface{},
+ daysValid int,
+ ca certificate,
+) (certificate, error) {
+ priv, err := rsa.GenerateKey(rand.Reader, 2048)
+ if err != nil {
+ return certificate{}, fmt.Errorf("error generating rsa key: %s", err)
+ }
+ return generateSignedCertificateWithKeyInternal(cn, ips, alternateDNS, daysValid, ca, priv)
+}
+
+func generateSignedCertificateWithPEMKey(
+ cn string,
+ ips []interface{},
+ alternateDNS []interface{},
+ daysValid int,
+ ca certificate,
+ privPEM string,
+) (certificate, error) {
+ priv, err := parsePrivateKeyPEM(privPEM)
+ if err != nil {
+ return certificate{}, fmt.Errorf("parsing private key: %s", err)
+ }
+ return generateSignedCertificateWithKeyInternal(cn, ips, alternateDNS, daysValid, ca, priv)
+}
+
+func generateSignedCertificateWithKeyInternal(
+ cn string,
+ ips []interface{},
+ alternateDNS []interface{},
+ daysValid int,
+ ca certificate,
+ priv crypto.PrivateKey,
+) (certificate, error) {
+ cert := certificate{}
+
+ decodedSignerCert, _ := pem.Decode([]byte(ca.Cert))
+ if decodedSignerCert == nil {
+ return cert, errors.New("unable to decode certificate")
+ }
+ signerCert, err := x509.ParseCertificate(decodedSignerCert.Bytes)
+ if err != nil {
+ return cert, fmt.Errorf(
+ "error parsing certificate: decodedSignerCert.Bytes: %s",
+ err,
+ )
+ }
+ signerKey, err := parsePrivateKeyPEM(ca.Key)
+ if err != nil {
+ return cert, fmt.Errorf(
+ "error parsing private key: %s",
+ err,
+ )
+ }
+
+ template, err := getBaseCertTemplate(cn, ips, alternateDNS, daysValid)
+ if err != nil {
+ return cert, err
+ }
+
+ cert.Cert, cert.Key, err = getCertAndKey(
+ template,
+ priv,
+ signerCert,
+ signerKey,
+ )
+
+ return cert, err
+}
+
+func getCertAndKey(
+ template *x509.Certificate,
+ signeeKey crypto.PrivateKey,
+ parent *x509.Certificate,
+ signingKey crypto.PrivateKey,
+) (string, string, error) {
+ signeePubKey, err := getPublicKey(signeeKey)
+ if err != nil {
+ return "", "", fmt.Errorf("error retrieving public key from signee key: %s", err)
+ }
+ derBytes, err := x509.CreateCertificate(
+ rand.Reader,
+ template,
+ parent,
+ signeePubKey,
+ signingKey,
+ )
+ if err != nil {
+ return "", "", fmt.Errorf("error creating certificate: %s", err)
+ }
+
+ certBuffer := bytes.Buffer{}
+ if err := pem.Encode(
+ &certBuffer,
+ &pem.Block{Type: "CERTIFICATE", Bytes: derBytes},
+ ); err != nil {
+ return "", "", fmt.Errorf("error pem-encoding certificate: %s", err)
+ }
+
+ keyBuffer := bytes.Buffer{}
+ if err := pem.Encode(
+ &keyBuffer,
+ pemBlockForKey(signeeKey),
+ ); err != nil {
+ return "", "", fmt.Errorf("error pem-encoding key: %s", err)
+ }
+
+ return certBuffer.String(), keyBuffer.String(), nil
+}
+
+func getBaseCertTemplate(
+ cn string,
+ ips []interface{},
+ alternateDNS []interface{},
+ daysValid int,
+) (*x509.Certificate, error) {
+ ipAddresses, err := getNetIPs(ips)
+ if err != nil {
+ return nil, err
+ }
+ dnsNames, err := getAlternateDNSStrs(alternateDNS)
+ if err != nil {
+ return nil, err
+ }
+ serialNumberUpperBound := new(big.Int).Lsh(big.NewInt(1), 128)
+ serialNumber, err := rand.Int(rand.Reader, serialNumberUpperBound)
+ if err != nil {
+ return nil, err
+ }
+ return &x509.Certificate{
+ SerialNumber: serialNumber,
+ Subject: pkix.Name{
+ CommonName: cn,
+ },
+ IPAddresses: ipAddresses,
+ DNSNames: dnsNames,
+ NotBefore: time.Now(),
+ NotAfter: time.Now().Add(time.Hour * 24 * time.Duration(daysValid)),
+ KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+ ExtKeyUsage: []x509.ExtKeyUsage{
+ x509.ExtKeyUsageServerAuth,
+ x509.ExtKeyUsageClientAuth,
+ },
+ BasicConstraintsValid: true,
+ }, nil
+}
+
+func getNetIPs(ips []interface{}) ([]net.IP, error) {
+ if ips == nil {
+ return []net.IP{}, nil
+ }
+ var ipStr string
+ var ok bool
+ var netIP net.IP
+ netIPs := make([]net.IP, len(ips))
+ for i, ip := range ips {
+ ipStr, ok = ip.(string)
+ if !ok {
+ return nil, fmt.Errorf("error parsing ip: %v is not a string", ip)
+ }
+ netIP = net.ParseIP(ipStr)
+ if netIP == nil {
+ return nil, fmt.Errorf("error parsing ip: %s", ipStr)
+ }
+ netIPs[i] = netIP
+ }
+ return netIPs, nil
+}
+
+func getAlternateDNSStrs(alternateDNS []interface{}) ([]string, error) {
+ if alternateDNS == nil {
+ return []string{}, nil
+ }
+ var dnsStr string
+ var ok bool
+ alternateDNSStrs := make([]string, len(alternateDNS))
+ for i, dns := range alternateDNS {
+ dnsStr, ok = dns.(string)
+ if !ok {
+ return nil, fmt.Errorf(
+ "error processing alternate dns name: %v is not a string",
+ dns,
+ )
+ }
+ alternateDNSStrs[i] = dnsStr
+ }
+ return alternateDNSStrs, nil
+}
+
+func encryptAES(password string, plaintext string) (string, error) {
+ if plaintext == "" {
+ return "", nil
+ }
+
+ key := make([]byte, 32)
+ copy(key, []byte(password))
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ return "", err
+ }
+
+ content := []byte(plaintext)
+ blockSize := block.BlockSize()
+ padding := blockSize - len(content)%blockSize
+ padtext := bytes.Repeat([]byte{byte(padding)}, padding)
+ content = append(content, padtext...)
+
+ ciphertext := make([]byte, aes.BlockSize+len(content))
+
+ iv := ciphertext[:aes.BlockSize]
+ if _, err := io.ReadFull(rand.Reader, iv); err != nil {
+ return "", err
+ }
+
+ mode := cipher.NewCBCEncrypter(block, iv)
+ mode.CryptBlocks(ciphertext[aes.BlockSize:], content)
+
+ return base64.StdEncoding.EncodeToString(ciphertext), nil
+}
+
+func decryptAES(password string, crypt64 string) (string, error) {
+ if crypt64 == "" {
+ return "", nil
+ }
+
+ key := make([]byte, 32)
+ copy(key, []byte(password))
+
+ crypt, err := base64.StdEncoding.DecodeString(crypt64)
+ if err != nil {
+ return "", err
+ }
+
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ return "", err
+ }
+
+ iv := crypt[:aes.BlockSize]
+ crypt = crypt[aes.BlockSize:]
+ decrypted := make([]byte, len(crypt))
+ mode := cipher.NewCBCDecrypter(block, iv)
+ mode.CryptBlocks(decrypted, crypt)
+
+ return string(decrypted[:len(decrypted)-int(decrypted[len(decrypted)-1])]), nil
+}
diff --git a/vendor/github.com/Masterminds/sprig/v3/date.go b/vendor/github.com/Masterminds/sprig/v3/date.go
new file mode 100644
index 0000000000..ed022ddaca
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/v3/date.go
@@ -0,0 +1,152 @@
+package sprig
+
+import (
+ "strconv"
+ "time"
+)
+
+// Given a format and a date, format the date string.
+//
+// Date can be a `time.Time` or an `int, int32, int64`.
+// In the later case, it is treated as seconds since UNIX
+// epoch.
+func date(fmt string, date interface{}) string {
+ return dateInZone(fmt, date, "Local")
+}
+
+func htmlDate(date interface{}) string {
+ return dateInZone("2006-01-02", date, "Local")
+}
+
+func htmlDateInZone(date interface{}, zone string) string {
+ return dateInZone("2006-01-02", date, zone)
+}
+
+func dateInZone(fmt string, date interface{}, zone string) string {
+ var t time.Time
+ switch date := date.(type) {
+ default:
+ t = time.Now()
+ case time.Time:
+ t = date
+ case *time.Time:
+ t = *date
+ case int64:
+ t = time.Unix(date, 0)
+ case int:
+ t = time.Unix(int64(date), 0)
+ case int32:
+ t = time.Unix(int64(date), 0)
+ }
+
+ loc, err := time.LoadLocation(zone)
+ if err != nil {
+ loc, _ = time.LoadLocation("UTC")
+ }
+
+ return t.In(loc).Format(fmt)
+}
+
+func dateModify(fmt string, date time.Time) time.Time {
+ d, err := time.ParseDuration(fmt)
+ if err != nil {
+ return date
+ }
+ return date.Add(d)
+}
+
+func mustDateModify(fmt string, date time.Time) (time.Time, error) {
+ d, err := time.ParseDuration(fmt)
+ if err != nil {
+ return time.Time{}, err
+ }
+ return date.Add(d), nil
+}
+
+func dateAgo(date interface{}) string {
+ var t time.Time
+
+ switch date := date.(type) {
+ default:
+ t = time.Now()
+ case time.Time:
+ t = date
+ case int64:
+ t = time.Unix(date, 0)
+ case int:
+ t = time.Unix(int64(date), 0)
+ }
+ // Drop resolution to seconds
+ duration := time.Since(t).Round(time.Second)
+ return duration.String()
+}
+
+func duration(sec interface{}) string {
+ var n int64
+ switch value := sec.(type) {
+ default:
+ n = 0
+ case string:
+ n, _ = strconv.ParseInt(value, 10, 64)
+ case int64:
+ n = value
+ }
+ return (time.Duration(n) * time.Second).String()
+}
+
+func durationRound(duration interface{}) string {
+ var d time.Duration
+ switch duration := duration.(type) {
+ default:
+ d = 0
+ case string:
+ d, _ = time.ParseDuration(duration)
+ case int64:
+ d = time.Duration(duration)
+ case time.Time:
+ d = time.Since(duration)
+ }
+
+ u := uint64(d)
+ neg := d < 0
+ if neg {
+ u = -u
+ }
+
+ var (
+ year = uint64(time.Hour) * 24 * 365
+ month = uint64(time.Hour) * 24 * 30
+ day = uint64(time.Hour) * 24
+ hour = uint64(time.Hour)
+ minute = uint64(time.Minute)
+ second = uint64(time.Second)
+ )
+ switch {
+ case u > year:
+ return strconv.FormatUint(u/year, 10) + "y"
+ case u > month:
+ return strconv.FormatUint(u/month, 10) + "mo"
+ case u > day:
+ return strconv.FormatUint(u/day, 10) + "d"
+ case u > hour:
+ return strconv.FormatUint(u/hour, 10) + "h"
+ case u > minute:
+ return strconv.FormatUint(u/minute, 10) + "m"
+ case u > second:
+ return strconv.FormatUint(u/second, 10) + "s"
+ }
+ return "0s"
+}
+
+func toDate(fmt, str string) time.Time {
+ t, _ := time.ParseInLocation(fmt, str, time.Local)
+ return t
+}
+
+func mustToDate(fmt, str string) (time.Time, error) {
+ return time.ParseInLocation(fmt, str, time.Local)
+}
+
+func unixEpoch(date time.Time) string {
+ return strconv.FormatInt(date.Unix(), 10)
+}
diff --git a/vendor/github.com/Masterminds/sprig/v3/defaults.go b/vendor/github.com/Masterminds/sprig/v3/defaults.go
new file mode 100644
index 0000000000..b9f979666d
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/v3/defaults.go
@@ -0,0 +1,163 @@
+package sprig
+
+import (
+ "bytes"
+ "encoding/json"
+ "math/rand"
+ "reflect"
+ "strings"
+ "time"
+)
+
+func init() {
+ rand.Seed(time.Now().UnixNano())
+}
+
+// dfault checks whether `given` is set, and returns default if not set.
+//
+// This returns `d` if `given` appears not to be set, and `given` otherwise.
+//
+// For numeric types 0 is unset.
+// For strings, maps, arrays, and slices, len() = 0 is considered unset.
+// For bool, false is unset.
+// Structs are never considered unset.
+//
+// For everything else, including pointers, a nil value is unset.
+func dfault(d interface{}, given ...interface{}) interface{} {
+
+ if empty(given) || empty(given[0]) {
+ return d
+ }
+ return given[0]
+}
+
+// empty returns true if the given value has the zero value for its type.
+func empty(given interface{}) bool {
+ g := reflect.ValueOf(given)
+ if !g.IsValid() {
+ return true
+ }
+
+ // Basically adapted from text/template.isTrue
+ switch g.Kind() {
+ default:
+ return g.IsNil()
+ case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
+ return g.Len() == 0
+ case reflect.Bool:
+ return !g.Bool()
+ case reflect.Complex64, reflect.Complex128:
+ return g.Complex() == 0
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return g.Int() == 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return g.Uint() == 0
+ case reflect.Float32, reflect.Float64:
+ return g.Float() == 0
+ case reflect.Struct:
+ return false
+ }
+}
+
+// coalesce returns the first non-empty value.
+func coalesce(v ...interface{}) interface{} {
+ for _, val := range v {
+ if !empty(val) {
+ return val
+ }
+ }
+ return nil
+}
+
+// all returns true if empty(x) is false for all values x in the list.
+// If the list is empty, return true.
+func all(v ...interface{}) bool {
+ for _, val := range v {
+ if empty(val) {
+ return false
+ }
+ }
+ return true
+}
+
+// any returns true if empty(x) is false for any x in the list.
+// If the list is empty, return false.
+func any(v ...interface{}) bool {
+ for _, val := range v {
+ if !empty(val) {
+ return true
+ }
+ }
+ return false
+}
+
+// fromJson decodes JSON into a structured value, ignoring errors.
+func fromJson(v string) interface{} {
+ output, _ := mustFromJson(v)
+ return output
+}
+
+// mustFromJson decodes JSON into a structured value, returning errors.
+func mustFromJson(v string) (interface{}, error) {
+ var output interface{}
+ err := json.Unmarshal([]byte(v), &output)
+ return output, err
+}
+
+// toJson encodes an item into a JSON string
+func toJson(v interface{}) string {
+ output, _ := json.Marshal(v)
+ return string(output)
+}
+
+func mustToJson(v interface{}) (string, error) {
+ output, err := json.Marshal(v)
+ if err != nil {
+ return "", err
+ }
+ return string(output), nil
+}
+
+// toPrettyJson encodes an item into a pretty (indented) JSON string
+func toPrettyJson(v interface{}) string {
+ output, _ := json.MarshalIndent(v, "", " ")
+ return string(output)
+}
+
+func mustToPrettyJson(v interface{}) (string, error) {
+ output, err := json.MarshalIndent(v, "", " ")
+ if err != nil {
+ return "", err
+ }
+ return string(output), nil
+}
+
+// toRawJson encodes an item into a JSON string with no escaping of HTML characters.
+func toRawJson(v interface{}) string {
+ output, err := mustToRawJson(v)
+ if err != nil {
+ panic(err)
+ }
+ return string(output)
+}
+
+// mustToRawJson encodes an item into a JSON string with no escaping of HTML characters.
+func mustToRawJson(v interface{}) (string, error) {
+ buf := new(bytes.Buffer)
+ enc := json.NewEncoder(buf)
+ enc.SetEscapeHTML(false)
+ err := enc.Encode(&v)
+ if err != nil {
+ return "", err
+ }
+ return strings.TrimSuffix(buf.String(), "\n"), nil
+}
+
+// ternary returns the first value if the last value is true, otherwise returns the second value.
+func ternary(vt interface{}, vf interface{}, v bool) interface{} {
+ if v {
+ return vt
+ }
+
+ return vf
+}
diff --git a/vendor/github.com/Masterminds/sprig/v3/dict.go b/vendor/github.com/Masterminds/sprig/v3/dict.go
new file mode 100644
index 0000000000..4315b3542a
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/v3/dict.go
@@ -0,0 +1,174 @@
+package sprig
+
+import (
+ "dario.cat/mergo"
+ "github.com/mitchellh/copystructure"
+)
+
+func get(d map[string]interface{}, key string) interface{} {
+ if val, ok := d[key]; ok {
+ return val
+ }
+ return ""
+}
+
+func set(d map[string]interface{}, key string, value interface{}) map[string]interface{} {
+ d[key] = value
+ return d
+}
+
+func unset(d map[string]interface{}, key string) map[string]interface{} {
+ delete(d, key)
+ return d
+}
+
+func hasKey(d map[string]interface{}, key string) bool {
+ _, ok := d[key]
+ return ok
+}
+
+func pluck(key string, d ...map[string]interface{}) []interface{} {
+ res := []interface{}{}
+ for _, dict := range d {
+ if val, ok := dict[key]; ok {
+ res = append(res, val)
+ }
+ }
+ return res
+}
+
+func keys(dicts ...map[string]interface{}) []string {
+ k := []string{}
+ for _, dict := range dicts {
+ for key := range dict {
+ k = append(k, key)
+ }
+ }
+ return k
+}
+
+func pick(dict map[string]interface{}, keys ...string) map[string]interface{} {
+ res := map[string]interface{}{}
+ for _, k := range keys {
+ if v, ok := dict[k]; ok {
+ res[k] = v
+ }
+ }
+ return res
+}
+
+func omit(dict map[string]interface{}, keys ...string) map[string]interface{} {
+ res := map[string]interface{}{}
+
+ omit := make(map[string]bool, len(keys))
+ for _, k := range keys {
+ omit[k] = true
+ }
+
+ for k, v := range dict {
+ if _, ok := omit[k]; !ok {
+ res[k] = v
+ }
+ }
+ return res
+}
+
+func dict(v ...interface{}) map[string]interface{} {
+ dict := map[string]interface{}{}
+ lenv := len(v)
+ for i := 0; i < lenv; i += 2 {
+ key := strval(v[i])
+ if i+1 >= lenv {
+ dict[key] = ""
+ continue
+ }
+ dict[key] = v[i+1]
+ }
+ return dict
+}
+
+func merge(dst map[string]interface{}, srcs ...map[string]interface{}) interface{} {
+ for _, src := range srcs {
+ if err := mergo.Merge(&dst, src); err != nil {
+ // Swallow errors inside of a template.
+ return ""
+ }
+ }
+ return dst
+}
+
+func mustMerge(dst map[string]interface{}, srcs ...map[string]interface{}) (interface{}, error) {
+ for _, src := range srcs {
+ if err := mergo.Merge(&dst, src); err != nil {
+ return nil, err
+ }
+ }
+ return dst, nil
+}
+
+func mergeOverwrite(dst map[string]interface{}, srcs ...map[string]interface{}) interface{} {
+ for _, src := range srcs {
+ if err := mergo.MergeWithOverwrite(&dst, src); err != nil {
+ // Swallow errors inside of a template.
+ return ""
+ }
+ }
+ return dst
+}
+
+func mustMergeOverwrite(dst map[string]interface{}, srcs ...map[string]interface{}) (interface{}, error) {
+ for _, src := range srcs {
+ if err := mergo.MergeWithOverwrite(&dst, src); err != nil {
+ return nil, err
+ }
+ }
+ return dst, nil
+}
+
+func values(dict map[string]interface{}) []interface{} {
+ values := []interface{}{}
+ for _, value := range dict {
+ values = append(values, value)
+ }
+
+ return values
+}
+
+func deepCopy(i interface{}) interface{} {
+ c, err := mustDeepCopy(i)
+ if err != nil {
+ panic("deepCopy error: " + err.Error())
+ }
+
+ return c
+}
+
+func mustDeepCopy(i interface{}) (interface{}, error) {
+ return copystructure.Copy(i)
+}
+
+func dig(ps ...interface{}) (interface{}, error) {
+ if len(ps) < 3 {
+ panic("dig needs at least three arguments")
+ }
+ dict := ps[len(ps)-1].(map[string]interface{})
+ def := ps[len(ps)-2]
+ ks := make([]string, len(ps)-2)
+ for i := 0; i < len(ks); i++ {
+ ks[i] = ps[i].(string)
+ }
+
+ return digFromDict(dict, def, ks)
+}
+
+func digFromDict(dict map[string]interface{}, d interface{}, ks []string) (interface{}, error) {
+ k, ns := ks[0], ks[1:len(ks)]
+ step, has := dict[k]
+ if !has {
+ return d, nil
+ }
+ if len(ns) == 0 {
+ return step, nil
+ }
+ return digFromDict(step.(map[string]interface{}), d, ns)
+}
diff --git a/vendor/github.com/Masterminds/sprig/v3/doc.go b/vendor/github.com/Masterminds/sprig/v3/doc.go
new file mode 100644
index 0000000000..91031d6d19
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/v3/doc.go
@@ -0,0 +1,19 @@
+/*
+Package sprig provides template functions for Go.
+
+This package contains a number of utility functions for working with data
+inside of Go `html/template` and `text/template` files.
+
+To add these functions, use the `template.Funcs()` method:
+
+ t := template.New("foo").Funcs(sprig.FuncMap())
+
+Note that you should add the function map before you parse any template files.
+
+ In several cases, Sprig reverses the order of arguments from the way they
+ appear in the standard library. This is to make it easier to pipe
+ arguments into functions.
+
+See http://masterminds.github.io/sprig/ for more detailed documentation on each of the available functions.
+*/
+package sprig
diff --git a/vendor/github.com/Masterminds/sprig/v3/functions.go b/vendor/github.com/Masterminds/sprig/v3/functions.go
new file mode 100644
index 0000000000..cda47d26f2
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/v3/functions.go
@@ -0,0 +1,385 @@
+package sprig
+
+import (
+ "errors"
+ "html/template"
+ "math/rand"
+ "os"
+ "path"
+ "path/filepath"
+ "reflect"
+ "strconv"
+ "strings"
+ ttemplate "text/template"
+ "time"
+
+ util "github.com/Masterminds/goutils"
+ "github.com/huandu/xstrings"
+ "github.com/shopspring/decimal"
+)
+
+// FuncMap produces the function map.
+//
+// Use this to pass the functions into the template engine:
+//
+// tpl := template.New("foo").Funcs(sprig.FuncMap()))
+func FuncMap() template.FuncMap {
+ return HtmlFuncMap()
+}
+
+// HermeticTxtFuncMap returns a 'text/template'.FuncMap with only repeatable functions.
+func HermeticTxtFuncMap() ttemplate.FuncMap {
+ r := TxtFuncMap()
+ for _, name := range nonhermeticFunctions {
+ delete(r, name)
+ }
+ return r
+}
+
+// HermeticHtmlFuncMap returns an 'html/template'.Funcmap with only repeatable functions.
+func HermeticHtmlFuncMap() template.FuncMap {
+ r := HtmlFuncMap()
+ for _, name := range nonhermeticFunctions {
+ delete(r, name)
+ }
+ return r
+}
+
+// TxtFuncMap returns a 'text/template'.FuncMap
+func TxtFuncMap() ttemplate.FuncMap {
+ return ttemplate.FuncMap(GenericFuncMap())
+}
+
+// HtmlFuncMap returns an 'html/template'.Funcmap
+func HtmlFuncMap() template.FuncMap {
+ return template.FuncMap(GenericFuncMap())
+}
+
+// GenericFuncMap returns a copy of the basic function map as a map[string]interface{}.
+func GenericFuncMap() map[string]interface{} {
+ gfm := make(map[string]interface{}, len(genericMap))
+ for k, v := range genericMap {
+ gfm[k] = v
+ }
+ return gfm
+}
+
+// These functions are not guaranteed to evaluate to the same result for given input, because they
+// refer to the environment or global state.
+var nonhermeticFunctions = []string{
+ // Date functions
+ "date",
+ "date_in_zone",
+ "date_modify",
+ "now",
+ "htmlDate",
+ "htmlDateInZone",
+ "dateInZone",
+ "dateModify",
+
+ // Strings
+ "randAlphaNum",
+ "randAlpha",
+ "randAscii",
+ "randNumeric",
+ "randBytes",
+ "uuidv4",
+
+ // OS
+ "env",
+ "expandenv",
+
+ // Network
+ "getHostByName",
+}
+
+var genericMap = map[string]interface{}{
+ "hello": func() string { return "Hello!" },
+
+ // Date functions
+ "ago": dateAgo,
+ "date": date,
+ "date_in_zone": dateInZone,
+ "date_modify": dateModify,
+ "dateInZone": dateInZone,
+ "dateModify": dateModify,
+ "duration": duration,
+ "durationRound": durationRound,
+ "htmlDate": htmlDate,
+ "htmlDateInZone": htmlDateInZone,
+ "must_date_modify": mustDateModify,
+ "mustDateModify": mustDateModify,
+ "mustToDate": mustToDate,
+ "now": time.Now,
+ "toDate": toDate,
+ "unixEpoch": unixEpoch,
+
+ // Strings
+ "abbrev": abbrev,
+ "abbrevboth": abbrevboth,
+ "trunc": trunc,
+ "trim": strings.TrimSpace,
+ "upper": strings.ToUpper,
+ "lower": strings.ToLower,
+ "title": strings.Title,
+ "untitle": untitle,
+ "substr": substring,
+ // Switch order so that "foo" | repeat 5
+ "repeat": func(count int, str string) string { return strings.Repeat(str, count) },
+ // Deprecated: Use trimAll.
+ "trimall": func(a, b string) string { return strings.Trim(b, a) },
+ // Switch order so that "$foo" | trimall "$"
+ "trimAll": func(a, b string) string { return strings.Trim(b, a) },
+ "trimSuffix": func(a, b string) string { return strings.TrimSuffix(b, a) },
+ "trimPrefix": func(a, b string) string { return strings.TrimPrefix(b, a) },
+ "nospace": util.DeleteWhiteSpace,
+ "initials": initials,
+ "randAlphaNum": randAlphaNumeric,
+ "randAlpha": randAlpha,
+ "randAscii": randAscii,
+ "randNumeric": randNumeric,
+ "swapcase": util.SwapCase,
+ "shuffle": xstrings.Shuffle,
+ "snakecase": xstrings.ToSnakeCase,
+ // 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) },
+ "hasSuffix": func(substr string, str string) bool { return strings.HasSuffix(str, substr) },
+ "quote": quote,
+ "squote": squote,
+ "cat": cat,
+ "indent": indent,
+ "nindent": nindent,
+ "replace": replace,
+ "plural": plural,
+ "sha1sum": sha1sum,
+ "sha256sum": sha256sum,
+ "sha512sum": sha512sum,
+ "adler32sum": adler32sum,
+ "toString": strval,
+
+ // Wrap Atoi to stop errors.
+ "atoi": func(a string) int { i, _ := strconv.Atoi(a); return i },
+ "int64": toInt64,
+ "int": toInt,
+ "float64": toFloat64,
+ "seq": seq,
+ "toDecimal": toDecimal,
+
+ //"gt": func(a, b int) bool {return a > b},
+ //"gte": func(a, b int) bool {return a >= b},
+ //"lt": func(a, b int) bool {return a < b},
+ //"lte": func(a, b int) bool {return a <= b},
+
+ // split "/" foo/bar returns map[int]string{0: foo, 1: bar}
+ "split": split,
+ "splitList": func(sep, orig string) []string { return strings.Split(orig, sep) },
+ // splitn "/" foo/bar/fuu returns map[int]string{0: foo, 1: bar/fuu}
+ "splitn": splitn,
+ "toStrings": strslice,
+
+ "until": until,
+ "untilStep": untilStep,
+
+ // VERY basic arithmetic.
+ "add1": func(i interface{}) int64 { return toInt64(i) + 1 },
+ "add": func(i ...interface{}) int64 {
+ var a int64 = 0
+ for _, b := range i {
+ a += toInt64(b)
+ }
+ return a
+ },
+ "sub": func(a, b interface{}) int64 { return toInt64(a) - toInt64(b) },
+ "div": func(a, b interface{}) int64 { return toInt64(a) / toInt64(b) },
+ "mod": func(a, b interface{}) int64 { return toInt64(a) % toInt64(b) },
+ "mul": func(a interface{}, v ...interface{}) int64 {
+ val := toInt64(a)
+ for _, b := range v {
+ val = val * toInt64(b)
+ }
+ return val
+ },
+ "randInt": func(min, max int) int { return rand.Intn(max-min) + min },
+ "add1f": func(i interface{}) float64 {
+ return execDecimalOp(i, []interface{}{1}, func(d1, d2 decimal.Decimal) decimal.Decimal { return d1.Add(d2) })
+ },
+ "addf": func(i ...interface{}) float64 {
+ a := interface{}(float64(0))
+ return execDecimalOp(a, i, func(d1, d2 decimal.Decimal) decimal.Decimal { return d1.Add(d2) })
+ },
+ "subf": func(a interface{}, v ...interface{}) float64 {
+ return execDecimalOp(a, v, func(d1, d2 decimal.Decimal) decimal.Decimal { return d1.Sub(d2) })
+ },
+ "divf": func(a interface{}, v ...interface{}) float64 {
+ return execDecimalOp(a, v, func(d1, d2 decimal.Decimal) decimal.Decimal { return d1.Div(d2) })
+ },
+ "mulf": func(a interface{}, v ...interface{}) float64 {
+ return execDecimalOp(a, v, func(d1, d2 decimal.Decimal) decimal.Decimal { return d1.Mul(d2) })
+ },
+ "biggest": max,
+ "max": max,
+ "min": min,
+ "maxf": maxf,
+ "minf": minf,
+ "ceil": ceil,
+ "floor": floor,
+ "round": round,
+
+ // string slices. Note that we reverse the order b/c that's better
+ // for template processing.
+ "join": join,
+ "sortAlpha": sortAlpha,
+
+ // Defaults
+ "default": dfault,
+ "empty": empty,
+ "coalesce": coalesce,
+ "all": all,
+ "any": any,
+ "compact": compact,
+ "mustCompact": mustCompact,
+ "fromJson": fromJson,
+ "toJson": toJson,
+ "toPrettyJson": toPrettyJson,
+ "toRawJson": toRawJson,
+ "mustFromJson": mustFromJson,
+ "mustToJson": mustToJson,
+ "mustToPrettyJson": mustToPrettyJson,
+ "mustToRawJson": mustToRawJson,
+ "ternary": ternary,
+ "deepCopy": deepCopy,
+ "mustDeepCopy": mustDeepCopy,
+
+ // Reflection
+ "typeOf": typeOf,
+ "typeIs": typeIs,
+ "typeIsLike": typeIsLike,
+ "kindOf": kindOf,
+ "kindIs": kindIs,
+ "deepEqual": reflect.DeepEqual,
+
+ // OS:
+ "env": os.Getenv,
+ "expandenv": os.ExpandEnv,
+
+ // Network:
+ "getHostByName": getHostByName,
+
+ // Paths:
+ "base": path.Base,
+ "dir": path.Dir,
+ "clean": path.Clean,
+ "ext": path.Ext,
+ "isAbs": path.IsAbs,
+
+ // Filepaths:
+ "osBase": filepath.Base,
+ "osClean": filepath.Clean,
+ "osDir": filepath.Dir,
+ "osExt": filepath.Ext,
+ "osIsAbs": filepath.IsAbs,
+
+ // Encoding:
+ "b64enc": base64encode,
+ "b64dec": base64decode,
+ "b32enc": base32encode,
+ "b32dec": base32decode,
+
+ // Data Structures:
+ "tuple": list, // FIXME: with the addition of append/prepend these are no longer immutable.
+ "list": list,
+ "dict": dict,
+ "get": get,
+ "set": set,
+ "unset": unset,
+ "hasKey": hasKey,
+ "pluck": pluck,
+ "keys": keys,
+ "pick": pick,
+ "omit": omit,
+ "merge": merge,
+ "mergeOverwrite": mergeOverwrite,
+ "mustMerge": mustMerge,
+ "mustMergeOverwrite": mustMergeOverwrite,
+ "values": values,
+
+ "append": push, "push": push,
+ "mustAppend": mustPush, "mustPush": mustPush,
+ "prepend": prepend,
+ "mustPrepend": mustPrepend,
+ "first": first,
+ "mustFirst": mustFirst,
+ "rest": rest,
+ "mustRest": mustRest,
+ "last": last,
+ "mustLast": mustLast,
+ "initial": initial,
+ "mustInitial": mustInitial,
+ "reverse": reverse,
+ "mustReverse": mustReverse,
+ "uniq": uniq,
+ "mustUniq": mustUniq,
+ "without": without,
+ "mustWithout": mustWithout,
+ "has": has,
+ "mustHas": mustHas,
+ "slice": slice,
+ "mustSlice": mustSlice,
+ "concat": concat,
+ "dig": dig,
+ "chunk": chunk,
+ "mustChunk": mustChunk,
+
+ // Crypto:
+ "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,
+
+ // UUIDs:
+ "uuidv4": uuidv4,
+
+ // SemVer:
+ "semver": semver,
+ "semverCompare": semverCompare,
+
+ // Flow Control:
+ "fail": func(msg string) (string, error) { return "", errors.New(msg) },
+
+ // Regex
+ "regexMatch": regexMatch,
+ "mustRegexMatch": mustRegexMatch,
+ "regexFindAll": regexFindAll,
+ "mustRegexFindAll": mustRegexFindAll,
+ "regexFind": regexFind,
+ "mustRegexFind": mustRegexFind,
+ "regexReplaceAll": regexReplaceAll,
+ "mustRegexReplaceAll": mustRegexReplaceAll,
+ "regexReplaceAllLiteral": regexReplaceAllLiteral,
+ "mustRegexReplaceAllLiteral": mustRegexReplaceAllLiteral,
+ "regexSplit": regexSplit,
+ "mustRegexSplit": mustRegexSplit,
+ "regexQuoteMeta": regexQuoteMeta,
+
+ // URLs:
+ "urlParse": urlParse,
+ "urlJoin": urlJoin,
+}
diff --git a/vendor/github.com/Masterminds/sprig/v3/list.go b/vendor/github.com/Masterminds/sprig/v3/list.go
new file mode 100644
index 0000000000..ca0fbb7893
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/v3/list.go
@@ -0,0 +1,464 @@
+package sprig
+
+import (
+ "fmt"
+ "math"
+ "reflect"
+ "sort"
+)
+
+// Reflection is used in these functions so that slices and arrays of strings,
+// ints, and other types not implementing []interface{} can be worked with.
+// For example, this is useful if you need to work on the output of regexs.
+
+func list(v ...interface{}) []interface{} {
+ return v
+}
+
+func push(list interface{}, v interface{}) []interface{} {
+ l, err := mustPush(list, v)
+ if err != nil {
+ panic(err)
+ }
+
+ return l
+}
+
+func mustPush(list interface{}, v interface{}) ([]interface{}, error) {
+ tp := reflect.TypeOf(list).Kind()
+ switch tp {
+ case reflect.Slice, reflect.Array:
+ l2 := reflect.ValueOf(list)
+
+ l := l2.Len()
+ nl := make([]interface{}, l)
+ for i := 0; i < l; i++ {
+ nl[i] = l2.Index(i).Interface()
+ }
+
+ return append(nl, v), nil
+
+ default:
+ return nil, fmt.Errorf("Cannot push on type %s", tp)
+ }
+}
+
+func prepend(list interface{}, v interface{}) []interface{} {
+ l, err := mustPrepend(list, v)
+ if err != nil {
+ panic(err)
+ }
+
+ return l
+}
+
+func mustPrepend(list interface{}, v interface{}) ([]interface{}, error) {
+ //return append([]interface{}{v}, list...)
+
+ tp := reflect.TypeOf(list).Kind()
+ switch tp {
+ case reflect.Slice, reflect.Array:
+ l2 := reflect.ValueOf(list)
+
+ l := l2.Len()
+ nl := make([]interface{}, l)
+ for i := 0; i < l; i++ {
+ nl[i] = l2.Index(i).Interface()
+ }
+
+ return append([]interface{}{v}, nl...), nil
+
+ default:
+ return nil, fmt.Errorf("Cannot prepend on type %s", tp)
+ }
+}
+
+func chunk(size int, list interface{}) [][]interface{} {
+ l, err := mustChunk(size, list)
+ if err != nil {
+ panic(err)
+ }
+
+ return l
+}
+
+func mustChunk(size int, list interface{}) ([][]interface{}, error) {
+ tp := reflect.TypeOf(list).Kind()
+ switch tp {
+ case reflect.Slice, reflect.Array:
+ l2 := reflect.ValueOf(list)
+
+ l := l2.Len()
+
+ cs := int(math.Floor(float64(l-1)/float64(size)) + 1)
+ nl := make([][]interface{}, cs)
+
+ for i := 0; i < cs; i++ {
+ clen := size
+ if i == cs-1 {
+ clen = int(math.Floor(math.Mod(float64(l), float64(size))))
+ if clen == 0 {
+ clen = size
+ }
+ }
+
+ nl[i] = make([]interface{}, clen)
+
+ for j := 0; j < clen; j++ {
+ ix := i*size + j
+ nl[i][j] = l2.Index(ix).Interface()
+ }
+ }
+
+ return nl, nil
+
+ default:
+ return nil, fmt.Errorf("Cannot chunk type %s", tp)
+ }
+}
+
+func last(list interface{}) interface{} {
+ l, err := mustLast(list)
+ if err != nil {
+ panic(err)
+ }
+
+ return l
+}
+
+func mustLast(list interface{}) (interface{}, error) {
+ tp := reflect.TypeOf(list).Kind()
+ switch tp {
+ case reflect.Slice, reflect.Array:
+ l2 := reflect.ValueOf(list)
+
+ l := l2.Len()
+ if l == 0 {
+ return nil, nil
+ }
+
+ return l2.Index(l - 1).Interface(), nil
+ default:
+ return nil, fmt.Errorf("Cannot find last on type %s", tp)
+ }
+}
+
+func first(list interface{}) interface{} {
+ l, err := mustFirst(list)
+ if err != nil {
+ panic(err)
+ }
+
+ return l
+}
+
+func mustFirst(list interface{}) (interface{}, error) {
+ tp := reflect.TypeOf(list).Kind()
+ switch tp {
+ case reflect.Slice, reflect.Array:
+ l2 := reflect.ValueOf(list)
+
+ l := l2.Len()
+ if l == 0 {
+ return nil, nil
+ }
+
+ return l2.Index(0).Interface(), nil
+ default:
+ return nil, fmt.Errorf("Cannot find first on type %s", tp)
+ }
+}
+
+func rest(list interface{}) []interface{} {
+ l, err := mustRest(list)
+ if err != nil {
+ panic(err)
+ }
+
+ return l
+}
+
+func mustRest(list interface{}) ([]interface{}, error) {
+ tp := reflect.TypeOf(list).Kind()
+ switch tp {
+ case reflect.Slice, reflect.Array:
+ l2 := reflect.ValueOf(list)
+
+ l := l2.Len()
+ if l == 0 {
+ return nil, nil
+ }
+
+ nl := make([]interface{}, l-1)
+ for i := 1; i < l; i++ {
+ nl[i-1] = l2.Index(i).Interface()
+ }
+
+ return nl, nil
+ default:
+ return nil, fmt.Errorf("Cannot find rest on type %s", tp)
+ }
+}
+
+func initial(list interface{}) []interface{} {
+ l, err := mustInitial(list)
+ if err != nil {
+ panic(err)
+ }
+
+ return l
+}
+
+func mustInitial(list interface{}) ([]interface{}, error) {
+ tp := reflect.TypeOf(list).Kind()
+ switch tp {
+ case reflect.Slice, reflect.Array:
+ l2 := reflect.ValueOf(list)
+
+ l := l2.Len()
+ if l == 0 {
+ return nil, nil
+ }
+
+ nl := make([]interface{}, l-1)
+ for i := 0; i < l-1; i++ {
+ nl[i] = l2.Index(i).Interface()
+ }
+
+ return nl, nil
+ default:
+ return nil, fmt.Errorf("Cannot find initial on type %s", tp)
+ }
+}
+
+func sortAlpha(list interface{}) []string {
+ k := reflect.Indirect(reflect.ValueOf(list)).Kind()
+ switch k {
+ case reflect.Slice, reflect.Array:
+ a := strslice(list)
+ s := sort.StringSlice(a)
+ s.Sort()
+ return s
+ }
+ return []string{strval(list)}
+}
+
+func reverse(v interface{}) []interface{} {
+ l, err := mustReverse(v)
+ if err != nil {
+ panic(err)
+ }
+
+ return l
+}
+
+func mustReverse(v interface{}) ([]interface{}, error) {
+ tp := reflect.TypeOf(v).Kind()
+ switch tp {
+ case reflect.Slice, reflect.Array:
+ l2 := reflect.ValueOf(v)
+
+ l := l2.Len()
+ // We do not sort in place because the incoming array should not be altered.
+ nl := make([]interface{}, l)
+ for i := 0; i < l; i++ {
+ nl[l-i-1] = l2.Index(i).Interface()
+ }
+
+ return nl, nil
+ default:
+ return nil, fmt.Errorf("Cannot find reverse on type %s", tp)
+ }
+}
+
+func compact(list interface{}) []interface{} {
+ l, err := mustCompact(list)
+ if err != nil {
+ panic(err)
+ }
+
+ return l
+}
+
+func mustCompact(list interface{}) ([]interface{}, error) {
+ tp := reflect.TypeOf(list).Kind()
+ switch tp {
+ case reflect.Slice, reflect.Array:
+ l2 := reflect.ValueOf(list)
+
+ l := l2.Len()
+ nl := []interface{}{}
+ var item interface{}
+ for i := 0; i < l; i++ {
+ item = l2.Index(i).Interface()
+ if !empty(item) {
+ nl = append(nl, item)
+ }
+ }
+
+ return nl, nil
+ default:
+ return nil, fmt.Errorf("Cannot compact on type %s", tp)
+ }
+}
+
+func uniq(list interface{}) []interface{} {
+ l, err := mustUniq(list)
+ if err != nil {
+ panic(err)
+ }
+
+ return l
+}
+
+func mustUniq(list interface{}) ([]interface{}, error) {
+ tp := reflect.TypeOf(list).Kind()
+ switch tp {
+ case reflect.Slice, reflect.Array:
+ l2 := reflect.ValueOf(list)
+
+ l := l2.Len()
+ dest := []interface{}{}
+ var item interface{}
+ for i := 0; i < l; i++ {
+ item = l2.Index(i).Interface()
+ if !inList(dest, item) {
+ dest = append(dest, item)
+ }
+ }
+
+ return dest, nil
+ default:
+ return nil, fmt.Errorf("Cannot find uniq on type %s", tp)
+ }
+}
+
+func inList(haystack []interface{}, needle interface{}) bool {
+ for _, h := range haystack {
+ if reflect.DeepEqual(needle, h) {
+ return true
+ }
+ }
+ return false
+}
+
+func without(list interface{}, omit ...interface{}) []interface{} {
+ l, err := mustWithout(list, omit...)
+ if err != nil {
+ panic(err)
+ }
+
+ return l
+}
+
+func mustWithout(list interface{}, omit ...interface{}) ([]interface{}, error) {
+ tp := reflect.TypeOf(list).Kind()
+ switch tp {
+ case reflect.Slice, reflect.Array:
+ l2 := reflect.ValueOf(list)
+
+ l := l2.Len()
+ res := []interface{}{}
+ var item interface{}
+ for i := 0; i < l; i++ {
+ item = l2.Index(i).Interface()
+ if !inList(omit, item) {
+ res = append(res, item)
+ }
+ }
+
+ return res, nil
+ default:
+ return nil, fmt.Errorf("Cannot find without on type %s", tp)
+ }
+}
+
+func has(needle interface{}, haystack interface{}) bool {
+ l, err := mustHas(needle, haystack)
+ if err != nil {
+ panic(err)
+ }
+
+ return l
+}
+
+func mustHas(needle interface{}, haystack interface{}) (bool, error) {
+ if haystack == nil {
+ return false, nil
+ }
+ tp := reflect.TypeOf(haystack).Kind()
+ switch tp {
+ case reflect.Slice, reflect.Array:
+ l2 := reflect.ValueOf(haystack)
+ var item interface{}
+ l := l2.Len()
+ for i := 0; i < l; i++ {
+ item = l2.Index(i).Interface()
+ if reflect.DeepEqual(needle, item) {
+ return true, nil
+ }
+ }
+
+ return false, nil
+ default:
+ return false, fmt.Errorf("Cannot find has on type %s", tp)
+ }
+}
+
+// $list := [1, 2, 3, 4, 5]
+// slice $list -> list[0:5] = list[:]
+// slice $list 0 3 -> list[0:3] = list[:3]
+// slice $list 3 5 -> list[3:5]
+// slice $list 3 -> list[3:5] = list[3:]
+func slice(list interface{}, indices ...interface{}) interface{} {
+ l, err := mustSlice(list, indices...)
+ if err != nil {
+ panic(err)
+ }
+
+ return l
+}
+
+func mustSlice(list interface{}, indices ...interface{}) (interface{}, error) {
+ tp := reflect.TypeOf(list).Kind()
+ switch tp {
+ case reflect.Slice, reflect.Array:
+ l2 := reflect.ValueOf(list)
+
+ l := l2.Len()
+ if l == 0 {
+ return nil, nil
+ }
+
+ var start, end int
+ if len(indices) > 0 {
+ start = toInt(indices[0])
+ }
+ if len(indices) < 2 {
+ end = l
+ } else {
+ end = toInt(indices[1])
+ }
+
+ return l2.Slice(start, end).Interface(), nil
+ default:
+ return nil, fmt.Errorf("list should be type of slice or array but %s", tp)
+ }
+}
+
+func concat(lists ...interface{}) interface{} {
+ var res []interface{}
+ for _, list := range lists {
+ tp := reflect.TypeOf(list).Kind()
+ switch tp {
+ case reflect.Slice, reflect.Array:
+ l2 := reflect.ValueOf(list)
+ for i := 0; i < l2.Len(); i++ {
+ res = append(res, l2.Index(i).Interface())
+ }
+ default:
+ panic(fmt.Sprintf("Cannot concat type %s as list", tp))
+ }
+ }
+ return res
+}
diff --git a/vendor/github.com/Masterminds/sprig/v3/network.go b/vendor/github.com/Masterminds/sprig/v3/network.go
new file mode 100644
index 0000000000..108d78a946
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/v3/network.go
@@ -0,0 +1,12 @@
+package sprig
+
+import (
+ "math/rand"
+ "net"
+)
+
+func getHostByName(name string) string {
+ addrs, _ := net.LookupHost(name)
+ //TODO: add error handing when release v3 comes out
+ return addrs[rand.Intn(len(addrs))]
+}
diff --git a/vendor/github.com/Masterminds/sprig/v3/numeric.go b/vendor/github.com/Masterminds/sprig/v3/numeric.go
new file mode 100644
index 0000000000..f68e4182ee
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/v3/numeric.go
@@ -0,0 +1,186 @@
+package sprig
+
+import (
+ "fmt"
+ "math"
+ "strconv"
+ "strings"
+
+ "github.com/spf13/cast"
+ "github.com/shopspring/decimal"
+)
+
+// toFloat64 converts 64-bit floats
+func toFloat64(v interface{}) float64 {
+ return cast.ToFloat64(v)
+}
+
+func toInt(v interface{}) int {
+ return cast.ToInt(v)
+}
+
+// toInt64 converts integer types to 64-bit integers
+func toInt64(v interface{}) int64 {
+ return cast.ToInt64(v)
+}
+
+func max(a interface{}, i ...interface{}) int64 {
+ aa := toInt64(a)
+ for _, b := range i {
+ bb := toInt64(b)
+ if bb > aa {
+ aa = bb
+ }
+ }
+ return aa
+}
+
+func maxf(a interface{}, i ...interface{}) float64 {
+ aa := toFloat64(a)
+ for _, b := range i {
+ bb := toFloat64(b)
+ aa = math.Max(aa, bb)
+ }
+ return aa
+}
+
+func min(a interface{}, i ...interface{}) int64 {
+ aa := toInt64(a)
+ for _, b := range i {
+ bb := toInt64(b)
+ if bb < aa {
+ aa = bb
+ }
+ }
+ return aa
+}
+
+func minf(a interface{}, i ...interface{}) float64 {
+ aa := toFloat64(a)
+ for _, b := range i {
+ bb := toFloat64(b)
+ aa = math.Min(aa, bb)
+ }
+ return aa
+}
+
+func until(count int) []int {
+ step := 1
+ if count < 0 {
+ step = -1
+ }
+ return untilStep(0, count, step)
+}
+
+func untilStep(start, stop, step int) []int {
+ v := []int{}
+
+ if stop < start {
+ if step >= 0 {
+ return v
+ }
+ for i := start; i > stop; i += step {
+ v = append(v, i)
+ }
+ return v
+ }
+
+ if step <= 0 {
+ return v
+ }
+ for i := start; i < stop; i += step {
+ v = append(v, i)
+ }
+ return v
+}
+
+func floor(a interface{}) float64 {
+ aa := toFloat64(a)
+ return math.Floor(aa)
+}
+
+func ceil(a interface{}) float64 {
+ aa := toFloat64(a)
+ return math.Ceil(aa)
+}
+
+func round(a interface{}, p int, rOpt ...float64) float64 {
+ roundOn := .5
+ if len(rOpt) > 0 {
+ roundOn = rOpt[0]
+ }
+ val := toFloat64(a)
+ places := toFloat64(p)
+
+ var round float64
+ pow := math.Pow(10, places)
+ digit := pow * val
+ _, div := math.Modf(digit)
+ if div >= roundOn {
+ round = math.Ceil(digit)
+ } else {
+ round = math.Floor(digit)
+ }
+ return round / pow
+}
+
+// converts unix octal to decimal
+func toDecimal(v interface{}) int64 {
+ result, err := strconv.ParseInt(fmt.Sprint(v), 8, 64)
+ if err != nil {
+ return 0
+ }
+ return result
+}
+
+func seq(params ...int) string {
+ increment := 1
+ switch len(params) {
+ case 0:
+ return ""
+ case 1:
+ start := 1
+ end := params[0]
+ if end < start {
+ increment = -1
+ }
+ return intArrayToString(untilStep(start, end+increment, increment), " ")
+ case 3:
+ start := params[0]
+ end := params[2]
+ step := params[1]
+ if end < start {
+ increment = -1
+ if step > 0 {
+ return ""
+ }
+ }
+ return intArrayToString(untilStep(start, end+increment, step), " ")
+ case 2:
+ start := params[0]
+ end := params[1]
+ step := 1
+ if end < start {
+ step = -1
+ }
+ return intArrayToString(untilStep(start, end+step, step), " ")
+ default:
+ return ""
+ }
+}
+
+func intArrayToString(slice []int, delimeter string) string {
+ return strings.Trim(strings.Join(strings.Fields(fmt.Sprint(slice)), delimeter), "[]")
+}
+
+// performs a float and subsequent decimal.Decimal conversion on inputs,
+// and iterates through a and b executing the mathmetical operation f
+func execDecimalOp(a interface{}, b []interface{}, f func(d1, d2 decimal.Decimal) decimal.Decimal) float64 {
+ prt := decimal.NewFromFloat(toFloat64(a))
+ for _, x := range b {
+ dx := decimal.NewFromFloat(toFloat64(x))
+ prt = f(prt, dx)
+ }
+ rslt, _ := prt.Float64()
+ return rslt
+}
diff --git a/vendor/github.com/Masterminds/sprig/v3/reflect.go b/vendor/github.com/Masterminds/sprig/v3/reflect.go
new file mode 100644
index 0000000000..8a65c132f0
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/v3/reflect.go
@@ -0,0 +1,28 @@
+package sprig
+
+import (
+ "fmt"
+ "reflect"
+)
+
+// typeIs returns true if the src is the type named in target.
+func typeIs(target string, src interface{}) bool {
+ return target == typeOf(src)
+}
+
+func typeIsLike(target string, src interface{}) bool {
+ t := typeOf(src)
+ return target == t || "*"+target == t
+}
+
+func typeOf(src interface{}) string {
+ return fmt.Sprintf("%T", src)
+}
+
+func kindIs(target string, src interface{}) bool {
+ return target == kindOf(src)
+}
+
+func kindOf(src interface{}) string {
+ return reflect.ValueOf(src).Kind().String()
+}
diff --git a/vendor/github.com/Masterminds/sprig/v3/regex.go b/vendor/github.com/Masterminds/sprig/v3/regex.go
new file mode 100644
index 0000000000..fab5510189
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/v3/regex.go
@@ -0,0 +1,83 @@
+package sprig
+
+import (
+ "regexp"
+)
+
+func regexMatch(regex string, s string) bool {
+ match, _ := regexp.MatchString(regex, s)
+ return match
+}
+
+func mustRegexMatch(regex string, s string) (bool, error) {
+ return regexp.MatchString(regex, s)
+}
+
+func regexFindAll(regex string, s string, n int) []string {
+ r := regexp.MustCompile(regex)
+ return r.FindAllString(s, n)
+}
+
+func mustRegexFindAll(regex string, s string, n int) ([]string, error) {
+ r, err := regexp.Compile(regex)
+ if err != nil {
+ return []string{}, err
+ }
+ return r.FindAllString(s, n), nil
+}
+
+func regexFind(regex string, s string) string {
+ r := regexp.MustCompile(regex)
+ return r.FindString(s)
+}
+
+func mustRegexFind(regex string, s string) (string, error) {
+ r, err := regexp.Compile(regex)
+ if err != nil {
+ return "", err
+ }
+ return r.FindString(s), nil
+}
+
+func regexReplaceAll(regex string, s string, repl string) string {
+ r := regexp.MustCompile(regex)
+ return r.ReplaceAllString(s, repl)
+}
+
+func mustRegexReplaceAll(regex string, s string, repl string) (string, error) {
+ r, err := regexp.Compile(regex)
+ if err != nil {
+ return "", err
+ }
+ return r.ReplaceAllString(s, repl), nil
+}
+
+func regexReplaceAllLiteral(regex string, s string, repl string) string {
+ r := regexp.MustCompile(regex)
+ return r.ReplaceAllLiteralString(s, repl)
+}
+
+func mustRegexReplaceAllLiteral(regex string, s string, repl string) (string, error) {
+ r, err := regexp.Compile(regex)
+ if err != nil {
+ return "", err
+ }
+ return r.ReplaceAllLiteralString(s, repl), nil
+}
+
+func regexSplit(regex string, s string, n int) []string {
+ r := regexp.MustCompile(regex)
+ return r.Split(s, n)
+}
+
+func mustRegexSplit(regex string, s string, n int) ([]string, error) {
+ r, err := regexp.Compile(regex)
+ if err != nil {
+ return []string{}, err
+ }
+ return r.Split(s, n), nil
+}
+
+func regexQuoteMeta(s string) string {
+ return regexp.QuoteMeta(s)
+}
diff --git a/vendor/github.com/Masterminds/sprig/v3/semver.go b/vendor/github.com/Masterminds/sprig/v3/semver.go
new file mode 100644
index 0000000000..3fbe08aa63
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/v3/semver.go
@@ -0,0 +1,23 @@
+package sprig
+
+import (
+ sv2 "github.com/Masterminds/semver/v3"
+)
+
+func semverCompare(constraint, version string) (bool, error) {
+ c, err := sv2.NewConstraint(constraint)
+ if err != nil {
+ return false, err
+ }
+
+ v, err := sv2.NewVersion(version)
+ if err != nil {
+ return false, err
+ }
+
+ return c.Check(v), nil
+}
+
+func semver(version string) (*sv2.Version, error) {
+ return sv2.NewVersion(version)
+}
diff --git a/vendor/github.com/Masterminds/sprig/v3/strings.go b/vendor/github.com/Masterminds/sprig/v3/strings.go
new file mode 100644
index 0000000000..e0ae628c84
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/v3/strings.go
@@ -0,0 +1,236 @@
+package sprig
+
+import (
+ "encoding/base32"
+ "encoding/base64"
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+
+ util "github.com/Masterminds/goutils"
+)
+
+func base64encode(v string) string {
+ return base64.StdEncoding.EncodeToString([]byte(v))
+}
+
+func base64decode(v string) string {
+ data, err := base64.StdEncoding.DecodeString(v)
+ if err != nil {
+ return err.Error()
+ }
+ return string(data)
+}
+
+func base32encode(v string) string {
+ return base32.StdEncoding.EncodeToString([]byte(v))
+}
+
+func base32decode(v string) string {
+ data, err := base32.StdEncoding.DecodeString(v)
+ if err != nil {
+ return err.Error()
+ }
+ return string(data)
+}
+
+func abbrev(width int, s string) string {
+ if width < 4 {
+ return s
+ }
+ r, _ := util.Abbreviate(s, width)
+ return r
+}
+
+func abbrevboth(left, right int, s string) string {
+ if right < 4 || left > 0 && right < 7 {
+ return s
+ }
+ r, _ := util.AbbreviateFull(s, left, right)
+ return r
+}
+func initials(s string) string {
+ // Wrap this just to eliminate the var args, which templates don't do well.
+ return util.Initials(s)
+}
+
+func randAlphaNumeric(count int) string {
+ // It is not possible, it appears, to actually generate an error here.
+ r, _ := util.CryptoRandomAlphaNumeric(count)
+ return r
+}
+
+func randAlpha(count int) string {
+ r, _ := util.CryptoRandomAlphabetic(count)
+ return r
+}
+
+func randAscii(count int) string {
+ r, _ := util.CryptoRandomAscii(count)
+ return r
+}
+
+func randNumeric(count int) string {
+ r, _ := util.CryptoRandomNumeric(count)
+ return r
+}
+
+func untitle(str string) string {
+ return util.Uncapitalize(str)
+}
+
+func quote(str ...interface{}) string {
+ out := make([]string, 0, len(str))
+ for _, s := range str {
+ if s != nil {
+ out = append(out, fmt.Sprintf("%q", strval(s)))
+ }
+ }
+ return strings.Join(out, " ")
+}
+
+func squote(str ...interface{}) string {
+ out := make([]string, 0, len(str))
+ for _, s := range str {
+ if s != nil {
+ out = append(out, fmt.Sprintf("'%v'", s))
+ }
+ }
+ return strings.Join(out, " ")
+}
+
+func cat(v ...interface{}) string {
+ v = removeNilElements(v)
+ r := strings.TrimSpace(strings.Repeat("%v ", len(v)))
+ return fmt.Sprintf(r, v...)
+}
+
+func indent(spaces int, v string) string {
+ pad := strings.Repeat(" ", spaces)
+ return pad + strings.Replace(v, "\n", "\n"+pad, -1)
+}
+
+func nindent(spaces int, v string) string {
+ return "\n" + indent(spaces, v)
+}
+
+func replace(old, new, src string) string {
+ return strings.Replace(src, old, new, -1)
+}
+
+func plural(one, many string, count int) string {
+ if count == 1 {
+ return one
+ }
+ return many
+}
+
+func strslice(v interface{}) []string {
+ switch v := v.(type) {
+ case []string:
+ return v
+ case []interface{}:
+ b := make([]string, 0, len(v))
+ for _, s := range v {
+ if s != nil {
+ b = append(b, strval(s))
+ }
+ }
+ return b
+ default:
+ val := reflect.ValueOf(v)
+ switch val.Kind() {
+ case reflect.Array, reflect.Slice:
+ l := val.Len()
+ b := make([]string, 0, l)
+ for i := 0; i < l; i++ {
+ value := val.Index(i).Interface()
+ if value != nil {
+ b = append(b, strval(value))
+ }
+ }
+ return b
+ default:
+ if v == nil {
+ return []string{}
+ }
+
+ return []string{strval(v)}
+ }
+ }
+}
+
+func removeNilElements(v []interface{}) []interface{} {
+ newSlice := make([]interface{}, 0, len(v))
+ for _, i := range v {
+ if i != nil {
+ newSlice = append(newSlice, i)
+ }
+ }
+ return newSlice
+}
+
+func strval(v interface{}) string {
+ switch v := v.(type) {
+ case string:
+ return v
+ case []byte:
+ return string(v)
+ case error:
+ return v.Error()
+ case fmt.Stringer:
+ return v.String()
+ default:
+ return fmt.Sprintf("%v", v)
+ }
+}
+
+func trunc(c int, s string) string {
+ if c < 0 && len(s)+c > 0 {
+ return s[len(s)+c:]
+ }
+ if c >= 0 && len(s) > c {
+ return s[:c]
+ }
+ return s
+}
+
+func join(sep string, v interface{}) string {
+ return strings.Join(strslice(v), sep)
+}
+
+func split(sep, orig string) map[string]string {
+ parts := strings.Split(orig, sep)
+ res := make(map[string]string, len(parts))
+ for i, v := range parts {
+ res["_"+strconv.Itoa(i)] = v
+ }
+ return res
+}
+
+func splitn(sep string, n int, orig string) map[string]string {
+ parts := strings.SplitN(orig, sep, n)
+ res := make(map[string]string, len(parts))
+ for i, v := range parts {
+ res["_"+strconv.Itoa(i)] = v
+ }
+ return res
+}
+
+// substring creates a substring of the given string.
+//
+// If start is < 0, this calls string[:end].
+//
+// If start is >= 0 and end < 0 or end bigger than s length, this calls string[start:]
+//
+// Otherwise, this calls string[start, end].
+func substring(start, end int, s string) string {
+ if start < 0 {
+ return s[:end]
+ }
+ if end < 0 || end > len(s) {
+ return s[start:]
+ }
+ return s[start:end]
+}
diff --git a/vendor/github.com/Masterminds/sprig/v3/url.go b/vendor/github.com/Masterminds/sprig/v3/url.go
new file mode 100644
index 0000000000..b8e120e19b
--- /dev/null
+++ b/vendor/github.com/Masterminds/sprig/v3/url.go
@@ -0,0 +1,66 @@
+package sprig
+
+import (
+ "fmt"
+ "net/url"
+ "reflect"
+)
+
+func dictGetOrEmpty(dict map[string]interface{}, key string) string {
+ value, ok := dict[key]
+ if !ok {
+ return ""
+ }
+ tp := reflect.TypeOf(value).Kind()
+ if tp != reflect.String {
+ panic(fmt.Sprintf("unable to parse %s key, must be of type string, but %s found", key, tp.String()))
+ }
+ return reflect.ValueOf(value).String()
+}
+
+// parses given URL to return dict object
+func urlParse(v string) map[string]interface{} {
+ dict := map[string]interface{}{}
+ parsedURL, err := url.Parse(v)
+ if err != nil {
+ panic(fmt.Sprintf("unable to parse url: %s", err))
+ }
+ dict["scheme"] = parsedURL.Scheme
+ dict["host"] = parsedURL.Host
+ dict["hostname"] = parsedURL.Hostname()
+ dict["path"] = parsedURL.Path
+ dict["query"] = parsedURL.RawQuery
+ dict["opaque"] = parsedURL.Opaque
+ dict["fragment"] = parsedURL.Fragment
+ if parsedURL.User != nil {
+ dict["userinfo"] = parsedURL.User.String()
+ } else {
+ dict["userinfo"] = ""
+ }
+
+ return dict
+}
+
+// join given dict to URL string
+func urlJoin(d map[string]interface{}) string {
+ resURL := url.URL{
+ Scheme: dictGetOrEmpty(d, "scheme"),
+ Host: dictGetOrEmpty(d, "host"),
+ Path: dictGetOrEmpty(d, "path"),
+ RawQuery: dictGetOrEmpty(d, "query"),
+ Opaque: dictGetOrEmpty(d, "opaque"),
+ Fragment: dictGetOrEmpty(d, "fragment"),
+ }
+ userinfo := dictGetOrEmpty(d, "userinfo")
+ var user *url.Userinfo
+ if userinfo != "" {
+ tempURL, err := url.Parse(fmt.Sprintf("proto://%s@host", userinfo))
+ if err != nil {
+ panic(fmt.Sprintf("unable to parse userinfo in dict: %s", err))
+ }
+ user = tempURL.User
+ }
+
+ resURL.User = user
+ return resURL.String()
+}
diff --git a/vendor/github.com/Masterminds/squirrel/.gitignore b/vendor/github.com/Masterminds/squirrel/.gitignore
new file mode 100644
index 0000000000..4a0699f0b7
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/.gitignore
@@ -0,0 +1 @@
+squirrel.test
\ No newline at end of file
diff --git a/vendor/github.com/Masterminds/squirrel/.travis.yml b/vendor/github.com/Masterminds/squirrel/.travis.yml
new file mode 100644
index 0000000000..7bb6da4878
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/.travis.yml
@@ -0,0 +1,30 @@
+language: go
+
+go:
+ - 1.11.x
+ - 1.12.x
+ - 1.13.x
+
+services:
+ - mysql
+ - postgresql
+
+# Setting sudo access to false will let Travis CI use containers rather than
+# VMs to run the tests. For more details see:
+# - http://docs.travis-ci.com/user/workers/container-based-infrastructure/
+# - http://docs.travis-ci.com/user/workers/standard-infrastructure/
+sudo: false
+
+before_script:
+ - mysql -e 'CREATE DATABASE squirrel;'
+ - psql -c 'CREATE DATABASE squirrel;' -U postgres
+
+script:
+ - go test
+ - cd integration
+ - go test -args -driver sqlite3
+ - go test -args -driver mysql -dataSource travis@/squirrel
+ - go test -args -driver postgres -dataSource 'postgres://postgres@localhost/squirrel?sslmode=disable'
+
+notifications:
+ irc: "irc.freenode.net#masterminds"
diff --git a/vendor/github.com/Masterminds/squirrel/LICENSE b/vendor/github.com/Masterminds/squirrel/LICENSE
new file mode 100644
index 0000000000..b459007fd8
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/LICENSE
@@ -0,0 +1,23 @@
+MIT License
+
+Squirrel: The Masterminds
+Copyright (c) 2014-2015, Lann Martin. Copyright (C) 2015-2016, Google. Copyright (C) 2015, Matt Farina and Matt Butcher.
+
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/Masterminds/squirrel/README.md b/vendor/github.com/Masterminds/squirrel/README.md
new file mode 100644
index 0000000000..1d37f282f1
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/README.md
@@ -0,0 +1,142 @@
+[](https://masterminds.github.io/stability/maintenance.html)
+### Squirrel is "complete".
+Bug fixes will still be merged (slowly). Bug reports are welcome, but I will not necessarily respond to them. If another fork (or substantially similar project) actively improves on what Squirrel does, let me know and I may link to it here.
+
+
+# Squirrel - fluent SQL generator for Go
+
+```go
+import "github.com/Masterminds/squirrel"
+```
+
+
+[](https://godoc.org/github.com/Masterminds/squirrel)
+[](https://travis-ci.org/Masterminds/squirrel)
+
+**Squirrel is not an ORM.** For an application of Squirrel, check out
+[structable, a table-struct mapper](https://github.com/Masterminds/structable)
+
+
+Squirrel helps you build SQL queries from composable parts:
+
+```go
+import sq "github.com/Masterminds/squirrel"
+
+users := sq.Select("*").From("users").Join("emails USING (email_id)")
+
+active := users.Where(sq.Eq{"deleted_at": nil})
+
+sql, args, err := active.ToSql()
+
+sql == "SELECT * FROM users JOIN emails USING (email_id) WHERE deleted_at IS NULL"
+```
+
+```go
+sql, args, err := sq.
+ Insert("users").Columns("name", "age").
+ Values("moe", 13).Values("larry", sq.Expr("? + 5", 12)).
+ ToSql()
+
+sql == "INSERT INTO users (name,age) VALUES (?,?),(?,? + 5)"
+```
+
+Squirrel can also execute queries directly:
+
+```go
+stooges := users.Where(sq.Eq{"username": []string{"moe", "larry", "curly", "shemp"}})
+three_stooges := stooges.Limit(3)
+rows, err := three_stooges.RunWith(db).Query()
+
+// Behaves like:
+rows, err := db.Query("SELECT * FROM users WHERE username IN (?,?,?,?) LIMIT 3",
+ "moe", "larry", "curly", "shemp")
+```
+
+Squirrel makes conditional query building a breeze:
+
+```go
+if len(q) > 0 {
+ users = users.Where("name LIKE ?", fmt.Sprint("%", q, "%"))
+}
+```
+
+Squirrel wants to make your life easier:
+
+```go
+// StmtCache caches Prepared Stmts for you
+dbCache := sq.NewStmtCache(db)
+
+// StatementBuilder keeps your syntax neat
+mydb := sq.StatementBuilder.RunWith(dbCache)
+select_users := mydb.Select("*").From("users")
+```
+
+Squirrel loves PostgreSQL:
+
+```go
+psql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar)
+
+// You use question marks for placeholders...
+sql, _, _ := psql.Select("*").From("elephants").Where("name IN (?,?)", "Dumbo", "Verna").ToSql()
+
+/// ...squirrel replaces them using PlaceholderFormat.
+sql == "SELECT * FROM elephants WHERE name IN ($1,$2)"
+
+
+/// You can retrieve id ...
+query := sq.Insert("nodes").
+ Columns("uuid", "type", "data").
+ Values(node.Uuid, node.Type, node.Data).
+ Suffix("RETURNING \"id\"").
+ RunWith(m.db).
+ PlaceholderFormat(sq.Dollar)
+
+query.QueryRow().Scan(&node.id)
+```
+
+You can escape question marks by inserting two question marks:
+
+```sql
+SELECT * FROM nodes WHERE meta->'format' ??| array[?,?]
+```
+
+will generate with the Dollar Placeholder:
+
+```sql
+SELECT * FROM nodes WHERE meta->'format' ?| array[$1,$2]
+```
+
+## FAQ
+
+* **How can I build an IN query on composite keys / tuples, e.g. `WHERE (col1, col2) IN ((1,2),(3,4))`? ([#104](https://github.com/Masterminds/squirrel/issues/104))**
+
+ Squirrel does not explicitly support tuples, but you can get the same effect with e.g.:
+
+ ```go
+ sq.Or{
+ sq.Eq{"col1": 1, "col2": 2},
+ sq.Eq{"col1": 3, "col2": 4}}
+ ```
+
+ ```sql
+ WHERE (col1 = 1 AND col2 = 2) OR (col1 = 3 AND col2 = 4)
+ ```
+
+ (which should produce the same query plan as the tuple version)
+
+* **Why doesn't `Eq{"mynumber": []uint8{1,2,3}}` turn into an `IN` query? ([#114](https://github.com/Masterminds/squirrel/issues/114))**
+
+ Values of type `[]byte` are handled specially by `database/sql`. In Go, [`byte` is just an alias of `uint8`](https://golang.org/pkg/builtin/#byte), so there is no way to distinguish `[]uint8` from `[]byte`.
+
+* **Some features are poorly documented!**
+
+ This isn't a frequent complaints section!
+
+* **Some features are poorly documented?**
+
+ Yes. The tests should be considered a part of the documentation; take a look at those for ideas on how to express more complex queries.
+
+## License
+
+Squirrel is released under the
+[MIT License](http://www.opensource.org/licenses/MIT).
diff --git a/vendor/github.com/Masterminds/squirrel/case.go b/vendor/github.com/Masterminds/squirrel/case.go
new file mode 100644
index 0000000000..299e14b9d4
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/case.go
@@ -0,0 +1,128 @@
+package squirrel
+
+import (
+ "bytes"
+ "errors"
+
+ "github.com/lann/builder"
+)
+
+func init() {
+ builder.Register(CaseBuilder{}, caseData{})
+}
+
+// sqlizerBuffer is a helper that allows to write many Sqlizers one by one
+// without constant checks for errors that may come from Sqlizer
+type sqlizerBuffer struct {
+ bytes.Buffer
+ args []interface{}
+ err error
+}
+
+// WriteSql converts Sqlizer to SQL strings and writes it to buffer
+func (b *sqlizerBuffer) WriteSql(item Sqlizer) {
+ if b.err != nil {
+ return
+ }
+
+ var str string
+ var args []interface{}
+ str, args, b.err = nestedToSql(item)
+
+ if b.err != nil {
+ return
+ }
+
+ b.WriteString(str)
+ b.WriteByte(' ')
+ b.args = append(b.args, args...)
+}
+
+func (b *sqlizerBuffer) ToSql() (string, []interface{}, error) {
+ return b.String(), b.args, b.err
+}
+
+// whenPart is a helper structure to describe SQLs "WHEN ... THEN ..." expression
+type whenPart struct {
+ when Sqlizer
+ then Sqlizer
+}
+
+func newWhenPart(when interface{}, then interface{}) whenPart {
+ return whenPart{newPart(when), newPart(then)}
+}
+
+// caseData holds all the data required to build a CASE SQL construct
+type caseData struct {
+ What Sqlizer
+ WhenParts []whenPart
+ Else Sqlizer
+}
+
+// ToSql implements Sqlizer
+func (d *caseData) ToSql() (sqlStr string, args []interface{}, err error) {
+ if len(d.WhenParts) == 0 {
+ err = errors.New("case expression must contain at lease one WHEN clause")
+
+ return
+ }
+
+ sql := sqlizerBuffer{}
+
+ sql.WriteString("CASE ")
+ if d.What != nil {
+ sql.WriteSql(d.What)
+ }
+
+ for _, p := range d.WhenParts {
+ sql.WriteString("WHEN ")
+ sql.WriteSql(p.when)
+ sql.WriteString("THEN ")
+ sql.WriteSql(p.then)
+ }
+
+ if d.Else != nil {
+ sql.WriteString("ELSE ")
+ sql.WriteSql(d.Else)
+ }
+
+ sql.WriteString("END")
+
+ return sql.ToSql()
+}
+
+// CaseBuilder builds SQL CASE construct which could be used as parts of queries.
+type CaseBuilder builder.Builder
+
+// ToSql builds the query into a SQL string and bound args.
+func (b CaseBuilder) ToSql() (string, []interface{}, error) {
+ data := builder.GetStruct(b).(caseData)
+ return data.ToSql()
+}
+
+// MustSql builds the query into a SQL string and bound args.
+// It panics if there are any errors.
+func (b CaseBuilder) MustSql() (string, []interface{}) {
+ sql, args, err := b.ToSql()
+ if err != nil {
+ panic(err)
+ }
+ return sql, args
+}
+
+// what sets optional value for CASE construct "CASE [value] ..."
+func (b CaseBuilder) what(expr interface{}) CaseBuilder {
+ return builder.Set(b, "What", newPart(expr)).(CaseBuilder)
+}
+
+// When adds "WHEN ... THEN ..." part to CASE construct
+func (b CaseBuilder) When(when interface{}, then interface{}) CaseBuilder {
+ // TODO: performance hint: replace slice of WhenPart with just slice of parts
+ // where even indices of the slice belong to "when"s and odd indices belong to "then"s
+ return builder.Append(b, "WhenParts", newWhenPart(when, then)).(CaseBuilder)
+}
+
+// What sets optional "ELSE ..." part for CASE construct
+func (b CaseBuilder) Else(expr interface{}) CaseBuilder {
+ return builder.Set(b, "Else", newPart(expr)).(CaseBuilder)
+}
diff --git a/vendor/github.com/Masterminds/squirrel/delete.go b/vendor/github.com/Masterminds/squirrel/delete.go
new file mode 100644
index 0000000000..f3f31e63ef
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/delete.go
@@ -0,0 +1,191 @@
+package squirrel
+
+import (
+ "bytes"
+ "database/sql"
+ "fmt"
+ "strings"
+
+ "github.com/lann/builder"
+)
+
+type deleteData struct {
+ PlaceholderFormat PlaceholderFormat
+ RunWith BaseRunner
+ Prefixes []Sqlizer
+ From string
+ WhereParts []Sqlizer
+ OrderBys []string
+ Limit string
+ Offset string
+ Suffixes []Sqlizer
+}
+
+func (d *deleteData) Exec() (sql.Result, error) {
+ if d.RunWith == nil {
+ return nil, RunnerNotSet
+ }
+ return ExecWith(d.RunWith, d)
+}
+
+func (d *deleteData) ToSql() (sqlStr string, args []interface{}, err error) {
+ if len(d.From) == 0 {
+ err = fmt.Errorf("delete statements must specify a From table")
+ return
+ }
+
+ sql := &bytes.Buffer{}
+
+ if len(d.Prefixes) > 0 {
+ args, err = appendToSql(d.Prefixes, sql, " ", args)
+ if err != nil {
+ return
+ }
+
+ sql.WriteString(" ")
+ }
+
+ sql.WriteString("DELETE FROM ")
+ sql.WriteString(d.From)
+
+ if len(d.WhereParts) > 0 {
+ sql.WriteString(" WHERE ")
+ args, err = appendToSql(d.WhereParts, sql, " AND ", args)
+ if err != nil {
+ return
+ }
+ }
+
+ if len(d.OrderBys) > 0 {
+ sql.WriteString(" ORDER BY ")
+ sql.WriteString(strings.Join(d.OrderBys, ", "))
+ }
+
+ if len(d.Limit) > 0 {
+ sql.WriteString(" LIMIT ")
+ sql.WriteString(d.Limit)
+ }
+
+ if len(d.Offset) > 0 {
+ sql.WriteString(" OFFSET ")
+ sql.WriteString(d.Offset)
+ }
+
+ if len(d.Suffixes) > 0 {
+ sql.WriteString(" ")
+ args, err = appendToSql(d.Suffixes, sql, " ", args)
+ if err != nil {
+ return
+ }
+ }
+
+ sqlStr, err = d.PlaceholderFormat.ReplacePlaceholders(sql.String())
+ return
+}
+
+// Builder
+
+// DeleteBuilder builds SQL DELETE statements.
+type DeleteBuilder builder.Builder
+
+func init() {
+ builder.Register(DeleteBuilder{}, deleteData{})
+}
+
+// Format methods
+
+// PlaceholderFormat sets PlaceholderFormat (e.g. Question or Dollar) for the
+// query.
+func (b DeleteBuilder) PlaceholderFormat(f PlaceholderFormat) DeleteBuilder {
+ return builder.Set(b, "PlaceholderFormat", f).(DeleteBuilder)
+}
+
+// Runner methods
+
+// RunWith sets a Runner (like database/sql.DB) to be used with e.g. Exec.
+func (b DeleteBuilder) RunWith(runner BaseRunner) DeleteBuilder {
+ return setRunWith(b, runner).(DeleteBuilder)
+}
+
+// Exec builds and Execs the query with the Runner set by RunWith.
+func (b DeleteBuilder) Exec() (sql.Result, error) {
+ data := builder.GetStruct(b).(deleteData)
+ return data.Exec()
+}
+
+// SQL methods
+
+// ToSql builds the query into a SQL string and bound args.
+func (b DeleteBuilder) ToSql() (string, []interface{}, error) {
+ data := builder.GetStruct(b).(deleteData)
+ return data.ToSql()
+}
+
+// MustSql builds the query into a SQL string and bound args.
+// It panics if there are any errors.
+func (b DeleteBuilder) MustSql() (string, []interface{}) {
+ sql, args, err := b.ToSql()
+ if err != nil {
+ panic(err)
+ }
+ return sql, args
+}
+
+// Prefix adds an expression to the beginning of the query
+func (b DeleteBuilder) Prefix(sql string, args ...interface{}) DeleteBuilder {
+ return b.PrefixExpr(Expr(sql, args...))
+}
+
+// PrefixExpr adds an expression to the very beginning of the query
+func (b DeleteBuilder) PrefixExpr(expr Sqlizer) DeleteBuilder {
+ return builder.Append(b, "Prefixes", expr).(DeleteBuilder)
+}
+
+// From sets the table to be deleted from.
+func (b DeleteBuilder) From(from string) DeleteBuilder {
+ return builder.Set(b, "From", from).(DeleteBuilder)
+}
+
+// Where adds WHERE expressions to the query.
+//
+// See SelectBuilder.Where for more information.
+func (b DeleteBuilder) Where(pred interface{}, args ...interface{}) DeleteBuilder {
+ return builder.Append(b, "WhereParts", newWherePart(pred, args...)).(DeleteBuilder)
+}
+
+// OrderBy adds ORDER BY expressions to the query.
+func (b DeleteBuilder) OrderBy(orderBys ...string) DeleteBuilder {
+ return builder.Extend(b, "OrderBys", orderBys).(DeleteBuilder)
+}
+
+// Limit sets a LIMIT clause on the query.
+func (b DeleteBuilder) Limit(limit uint64) DeleteBuilder {
+ return builder.Set(b, "Limit", fmt.Sprintf("%d", limit)).(DeleteBuilder)
+}
+
+// Offset sets a OFFSET clause on the query.
+func (b DeleteBuilder) Offset(offset uint64) DeleteBuilder {
+ return builder.Set(b, "Offset", fmt.Sprintf("%d", offset)).(DeleteBuilder)
+}
+
+// Suffix adds an expression to the end of the query
+func (b DeleteBuilder) Suffix(sql string, args ...interface{}) DeleteBuilder {
+ return b.SuffixExpr(Expr(sql, args...))
+}
+
+// SuffixExpr adds an expression to the end of the query
+func (b DeleteBuilder) SuffixExpr(expr Sqlizer) DeleteBuilder {
+ return builder.Append(b, "Suffixes", expr).(DeleteBuilder)
+}
+
+func (b DeleteBuilder) Query() (*sql.Rows, error) {
+ data := builder.GetStruct(b).(deleteData)
+ return data.Query()
+}
+
+func (d *deleteData) Query() (*sql.Rows, error) {
+ if d.RunWith == nil {
+ return nil, RunnerNotSet
+ }
+ return QueryWith(d.RunWith, d)
+}
diff --git a/vendor/github.com/Masterminds/squirrel/delete_ctx.go b/vendor/github.com/Masterminds/squirrel/delete_ctx.go
new file mode 100644
index 0000000000..de83c55df3
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/delete_ctx.go
@@ -0,0 +1,69 @@
+// +build go1.8
+
+package squirrel
+
+import (
+ "context"
+ "database/sql"
+
+ "github.com/lann/builder"
+)
+
+func (d *deleteData) ExecContext(ctx context.Context) (sql.Result, error) {
+ if d.RunWith == nil {
+ return nil, RunnerNotSet
+ }
+ ctxRunner, ok := d.RunWith.(ExecerContext)
+ if !ok {
+ return nil, NoContextSupport
+ }
+ return ExecContextWith(ctx, ctxRunner, d)
+}
+
+func (d *deleteData) QueryContext(ctx context.Context) (*sql.Rows, error) {
+ if d.RunWith == nil {
+ return nil, RunnerNotSet
+ }
+ ctxRunner, ok := d.RunWith.(QueryerContext)
+ if !ok {
+ return nil, NoContextSupport
+ }
+ return QueryContextWith(ctx, ctxRunner, d)
+}
+
+func (d *deleteData) QueryRowContext(ctx context.Context) RowScanner {
+ if d.RunWith == nil {
+ return &Row{err: RunnerNotSet}
+ }
+ queryRower, ok := d.RunWith.(QueryRowerContext)
+ if !ok {
+ if _, ok := d.RunWith.(QueryerContext); !ok {
+ return &Row{err: RunnerNotQueryRunner}
+ }
+ return &Row{err: NoContextSupport}
+ }
+ return QueryRowContextWith(ctx, queryRower, d)
+}
+
+// ExecContext builds and ExecContexts the query with the Runner set by RunWith.
+func (b DeleteBuilder) ExecContext(ctx context.Context) (sql.Result, error) {
+ data := builder.GetStruct(b).(deleteData)
+ return data.ExecContext(ctx)
+}
+
+// QueryContext builds and QueryContexts the query with the Runner set by RunWith.
+func (b DeleteBuilder) QueryContext(ctx context.Context) (*sql.Rows, error) {
+ data := builder.GetStruct(b).(deleteData)
+ return data.QueryContext(ctx)
+}
+
+// QueryRowContext builds and QueryRowContexts the query with the Runner set by RunWith.
+func (b DeleteBuilder) QueryRowContext(ctx context.Context) RowScanner {
+ data := builder.GetStruct(b).(deleteData)
+ return data.QueryRowContext(ctx)
+}
+
+// ScanContext is a shortcut for QueryRowContext().Scan.
+func (b DeleteBuilder) ScanContext(ctx context.Context, dest ...interface{}) error {
+ return b.QueryRowContext(ctx).Scan(dest...)
+}
diff --git a/vendor/github.com/Masterminds/squirrel/expr.go b/vendor/github.com/Masterminds/squirrel/expr.go
new file mode 100644
index 0000000000..eba1b4579e
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/expr.go
@@ -0,0 +1,419 @@
+package squirrel
+
+import (
+ "bytes"
+ "database/sql/driver"
+ "fmt"
+ "reflect"
+ "sort"
+ "strings"
+)
+
+const (
+ // Portable true/false literals.
+ sqlTrue = "(1=1)"
+ sqlFalse = "(1=0)"
+)
+
+type expr struct {
+ sql string
+ args []interface{}
+}
+
+// Expr builds an expression from a SQL fragment and arguments.
+//
+// Ex:
+// Expr("FROM_UNIXTIME(?)", t)
+func Expr(sql string, args ...interface{}) Sqlizer {
+ return expr{sql: sql, args: args}
+}
+
+func (e expr) ToSql() (sql string, args []interface{}, err error) {
+ simple := true
+ for _, arg := range e.args {
+ if _, ok := arg.(Sqlizer); ok {
+ simple = false
+ }
+ }
+ if simple {
+ return e.sql, e.args, nil
+ }
+
+ buf := &bytes.Buffer{}
+ ap := e.args
+ sp := e.sql
+
+ var isql string
+ var iargs []interface{}
+
+ for err == nil && len(ap) > 0 && len(sp) > 0 {
+ i := strings.Index(sp, "?")
+ if i < 0 {
+ // no more placeholders
+ break
+ }
+ if len(sp) > i+1 && sp[i+1:i+2] == "?" {
+ // escaped "??"; append it and step past
+ buf.WriteString(sp[:i+2])
+ sp = sp[i+2:]
+ continue
+ }
+
+ if as, ok := ap[0].(Sqlizer); ok {
+ // sqlizer argument; expand it and append the result
+ isql, iargs, err = as.ToSql()
+ buf.WriteString(sp[:i])
+ buf.WriteString(isql)
+ args = append(args, iargs...)
+ } else {
+ // normal argument; append it and the placeholder
+ buf.WriteString(sp[:i+1])
+ args = append(args, ap[0])
+ }
+
+ // step past the argument and placeholder
+ ap = ap[1:]
+ sp = sp[i+1:]
+ }
+
+ // append the remaining sql and arguments
+ buf.WriteString(sp)
+ return buf.String(), append(args, ap...), err
+}
+
+type concatExpr []interface{}
+
+func (ce concatExpr) ToSql() (sql string, args []interface{}, err error) {
+ for _, part := range ce {
+ switch p := part.(type) {
+ case string:
+ sql += p
+ case Sqlizer:
+ pSql, pArgs, err := p.ToSql()
+ if err != nil {
+ return "", nil, err
+ }
+ sql += pSql
+ args = append(args, pArgs...)
+ default:
+ return "", nil, fmt.Errorf("%#v is not a string or Sqlizer", part)
+ }
+ }
+ return
+}
+
+// ConcatExpr builds an expression by concatenating strings and other expressions.
+//
+// Ex:
+// name_expr := Expr("CONCAT(?, ' ', ?)", firstName, lastName)
+// ConcatExpr("COALESCE(full_name,", name_expr, ")")
+func ConcatExpr(parts ...interface{}) concatExpr {
+ return concatExpr(parts)
+}
+
+// aliasExpr helps to alias part of SQL query generated with underlying "expr"
+type aliasExpr struct {
+ expr Sqlizer
+ alias string
+}
+
+// Alias allows to define alias for column in SelectBuilder. Useful when column is
+// defined as complex expression like IF or CASE
+// Ex:
+// .Column(Alias(caseStmt, "case_column"))
+func Alias(expr Sqlizer, alias string) aliasExpr {
+ return aliasExpr{expr, alias}
+}
+
+func (e aliasExpr) ToSql() (sql string, args []interface{}, err error) {
+ sql, args, err = e.expr.ToSql()
+ if err == nil {
+ sql = fmt.Sprintf("(%s) AS %s", sql, e.alias)
+ }
+ return
+}
+
+// Eq is syntactic sugar for use with Where/Having/Set methods.
+type Eq map[string]interface{}
+
+func (eq Eq) toSQL(useNotOpr bool) (sql string, args []interface{}, err error) {
+ if len(eq) == 0 {
+ // Empty Sql{} evaluates to true.
+ sql = sqlTrue
+ return
+ }
+
+ var (
+ exprs []string
+ equalOpr = "="
+ inOpr = "IN"
+ nullOpr = "IS"
+ inEmptyExpr = sqlFalse
+ )
+
+ if useNotOpr {
+ equalOpr = "<>"
+ inOpr = "NOT IN"
+ nullOpr = "IS NOT"
+ inEmptyExpr = sqlTrue
+ }
+
+ sortedKeys := getSortedKeys(eq)
+ for _, key := range sortedKeys {
+ var expr string
+ val := eq[key]
+
+ switch v := val.(type) {
+ case driver.Valuer:
+ if val, err = v.Value(); err != nil {
+ return
+ }
+ }
+
+ r := reflect.ValueOf(val)
+ if r.Kind() == reflect.Ptr {
+ if r.IsNil() {
+ val = nil
+ } else {
+ val = r.Elem().Interface()
+ }
+ }
+
+ if val == nil {
+ expr = fmt.Sprintf("%s %s NULL", key, nullOpr)
+ } else {
+ if isListType(val) {
+ valVal := reflect.ValueOf(val)
+ if valVal.Len() == 0 {
+ expr = inEmptyExpr
+ if args == nil {
+ args = []interface{}{}
+ }
+ } else {
+ for i := 0; i < valVal.Len(); i++ {
+ args = append(args, valVal.Index(i).Interface())
+ }
+ expr = fmt.Sprintf("%s %s (%s)", key, inOpr, Placeholders(valVal.Len()))
+ }
+ } else {
+ expr = fmt.Sprintf("%s %s ?", key, equalOpr)
+ args = append(args, val)
+ }
+ }
+ exprs = append(exprs, expr)
+ }
+ sql = strings.Join(exprs, " AND ")
+ return
+}
+
+func (eq Eq) ToSql() (sql string, args []interface{}, err error) {
+ return eq.toSQL(false)
+}
+
+// NotEq is syntactic sugar for use with Where/Having/Set methods.
+// Ex:
+// .Where(NotEq{"id": 1}) == "id <> 1"
+type NotEq Eq
+
+func (neq NotEq) ToSql() (sql string, args []interface{}, err error) {
+ return Eq(neq).toSQL(true)
+}
+
+// Like is syntactic sugar for use with LIKE conditions.
+// Ex:
+// .Where(Like{"name": "%irrel"})
+type Like map[string]interface{}
+
+func (lk Like) toSql(opr string) (sql string, args []interface{}, err error) {
+ var exprs []string
+ for key, val := range lk {
+ expr := ""
+
+ switch v := val.(type) {
+ case driver.Valuer:
+ if val, err = v.Value(); err != nil {
+ return
+ }
+ }
+
+ if val == nil {
+ err = fmt.Errorf("cannot use null with like operators")
+ return
+ } else {
+ if isListType(val) {
+ err = fmt.Errorf("cannot use array or slice with like operators")
+ return
+ } else {
+ expr = fmt.Sprintf("%s %s ?", key, opr)
+ args = append(args, val)
+ }
+ }
+ exprs = append(exprs, expr)
+ }
+ sql = strings.Join(exprs, " AND ")
+ return
+}
+
+func (lk Like) ToSql() (sql string, args []interface{}, err error) {
+ return lk.toSql("LIKE")
+}
+
+// NotLike is syntactic sugar for use with LIKE conditions.
+// Ex:
+// .Where(NotLike{"name": "%irrel"})
+type NotLike Like
+
+func (nlk NotLike) ToSql() (sql string, args []interface{}, err error) {
+ return Like(nlk).toSql("NOT LIKE")
+}
+
+// ILike is syntactic sugar for use with ILIKE conditions.
+// Ex:
+// .Where(ILike{"name": "sq%"})
+type ILike Like
+
+func (ilk ILike) ToSql() (sql string, args []interface{}, err error) {
+ return Like(ilk).toSql("ILIKE")
+}
+
+// NotILike is syntactic sugar for use with ILIKE conditions.
+// Ex:
+// .Where(NotILike{"name": "sq%"})
+type NotILike Like
+
+func (nilk NotILike) ToSql() (sql string, args []interface{}, err error) {
+ return Like(nilk).toSql("NOT ILIKE")
+}
+
+// Lt is syntactic sugar for use with Where/Having/Set methods.
+// Ex:
+// .Where(Lt{"id": 1})
+type Lt map[string]interface{}
+
+func (lt Lt) toSql(opposite, orEq bool) (sql string, args []interface{}, err error) {
+ var (
+ exprs []string
+ opr = "<"
+ )
+
+ if opposite {
+ opr = ">"
+ }
+
+ if orEq {
+ opr = fmt.Sprintf("%s%s", opr, "=")
+ }
+
+ sortedKeys := getSortedKeys(lt)
+ for _, key := range sortedKeys {
+ var expr string
+ val := lt[key]
+
+ switch v := val.(type) {
+ case driver.Valuer:
+ if val, err = v.Value(); err != nil {
+ return
+ }
+ }
+
+ if val == nil {
+ err = fmt.Errorf("cannot use null with less than or greater than operators")
+ return
+ }
+ if isListType(val) {
+ err = fmt.Errorf("cannot use array or slice with less than or greater than operators")
+ return
+ }
+ expr = fmt.Sprintf("%s %s ?", key, opr)
+ args = append(args, val)
+
+ exprs = append(exprs, expr)
+ }
+ sql = strings.Join(exprs, " AND ")
+ return
+}
+
+func (lt Lt) ToSql() (sql string, args []interface{}, err error) {
+ return lt.toSql(false, false)
+}
+
+// LtOrEq is syntactic sugar for use with Where/Having/Set methods.
+// Ex:
+// .Where(LtOrEq{"id": 1}) == "id <= 1"
+type LtOrEq Lt
+
+func (ltOrEq LtOrEq) ToSql() (sql string, args []interface{}, err error) {
+ return Lt(ltOrEq).toSql(false, true)
+}
+
+// Gt is syntactic sugar for use with Where/Having/Set methods.
+// Ex:
+// .Where(Gt{"id": 1}) == "id > 1"
+type Gt Lt
+
+func (gt Gt) ToSql() (sql string, args []interface{}, err error) {
+ return Lt(gt).toSql(true, false)
+}
+
+// GtOrEq is syntactic sugar for use with Where/Having/Set methods.
+// Ex:
+// .Where(GtOrEq{"id": 1}) == "id >= 1"
+type GtOrEq Lt
+
+func (gtOrEq GtOrEq) ToSql() (sql string, args []interface{}, err error) {
+ return Lt(gtOrEq).toSql(true, true)
+}
+
+type conj []Sqlizer
+
+func (c conj) join(sep, defaultExpr string) (sql string, args []interface{}, err error) {
+ if len(c) == 0 {
+ return defaultExpr, []interface{}{}, nil
+ }
+ var sqlParts []string
+ for _, sqlizer := range c {
+ partSQL, partArgs, err := nestedToSql(sqlizer)
+ if err != nil {
+ return "", nil, err
+ }
+ if partSQL != "" {
+ sqlParts = append(sqlParts, partSQL)
+ args = append(args, partArgs...)
+ }
+ }
+ if len(sqlParts) > 0 {
+ sql = fmt.Sprintf("(%s)", strings.Join(sqlParts, sep))
+ }
+ return
+}
+
+// And conjunction Sqlizers
+type And conj
+
+func (a And) ToSql() (string, []interface{}, error) {
+ return conj(a).join(" AND ", sqlTrue)
+}
+
+// Or conjunction Sqlizers
+type Or conj
+
+func (o Or) ToSql() (string, []interface{}, error) {
+ return conj(o).join(" OR ", sqlFalse)
+}
+
+func getSortedKeys(exp map[string]interface{}) []string {
+ sortedKeys := make([]string, 0, len(exp))
+ for k := range exp {
+ sortedKeys = append(sortedKeys, k)
+ }
+ sort.Strings(sortedKeys)
+ return sortedKeys
+}
+
+func isListType(val interface{}) bool {
+ if driver.IsValue(val) {
+ return false
+ }
+ valVal := reflect.ValueOf(val)
+ return valVal.Kind() == reflect.Array || valVal.Kind() == reflect.Slice
+}
diff --git a/vendor/github.com/Masterminds/squirrel/insert.go b/vendor/github.com/Masterminds/squirrel/insert.go
new file mode 100644
index 0000000000..c23a57935b
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/insert.go
@@ -0,0 +1,298 @@
+package squirrel
+
+import (
+ "bytes"
+ "database/sql"
+ "errors"
+ "fmt"
+ "io"
+ "sort"
+ "strings"
+
+ "github.com/lann/builder"
+)
+
+type insertData struct {
+ PlaceholderFormat PlaceholderFormat
+ RunWith BaseRunner
+ Prefixes []Sqlizer
+ StatementKeyword string
+ Options []string
+ Into string
+ Columns []string
+ Values [][]interface{}
+ Suffixes []Sqlizer
+ Select *SelectBuilder
+}
+
+func (d *insertData) Exec() (sql.Result, error) {
+ if d.RunWith == nil {
+ return nil, RunnerNotSet
+ }
+ return ExecWith(d.RunWith, d)
+}
+
+func (d *insertData) Query() (*sql.Rows, error) {
+ if d.RunWith == nil {
+ return nil, RunnerNotSet
+ }
+ return QueryWith(d.RunWith, d)
+}
+
+func (d *insertData) QueryRow() RowScanner {
+ if d.RunWith == nil {
+ return &Row{err: RunnerNotSet}
+ }
+ queryRower, ok := d.RunWith.(QueryRower)
+ if !ok {
+ return &Row{err: RunnerNotQueryRunner}
+ }
+ return QueryRowWith(queryRower, d)
+}
+
+func (d *insertData) ToSql() (sqlStr string, args []interface{}, err error) {
+ if len(d.Into) == 0 {
+ err = errors.New("insert statements must specify a table")
+ return
+ }
+ if len(d.Values) == 0 && d.Select == nil {
+ err = errors.New("insert statements must have at least one set of values or select clause")
+ return
+ }
+
+ sql := &bytes.Buffer{}
+
+ if len(d.Prefixes) > 0 {
+ args, err = appendToSql(d.Prefixes, sql, " ", args)
+ if err != nil {
+ return
+ }
+
+ sql.WriteString(" ")
+ }
+
+ if d.StatementKeyword == "" {
+ sql.WriteString("INSERT ")
+ } else {
+ sql.WriteString(d.StatementKeyword)
+ sql.WriteString(" ")
+ }
+
+ if len(d.Options) > 0 {
+ sql.WriteString(strings.Join(d.Options, " "))
+ sql.WriteString(" ")
+ }
+
+ sql.WriteString("INTO ")
+ sql.WriteString(d.Into)
+ sql.WriteString(" ")
+
+ if len(d.Columns) > 0 {
+ sql.WriteString("(")
+ sql.WriteString(strings.Join(d.Columns, ","))
+ sql.WriteString(") ")
+ }
+
+ if d.Select != nil {
+ args, err = d.appendSelectToSQL(sql, args)
+ } else {
+ args, err = d.appendValuesToSQL(sql, args)
+ }
+ if err != nil {
+ return
+ }
+
+ if len(d.Suffixes) > 0 {
+ sql.WriteString(" ")
+ args, err = appendToSql(d.Suffixes, sql, " ", args)
+ if err != nil {
+ return
+ }
+ }
+
+ sqlStr, err = d.PlaceholderFormat.ReplacePlaceholders(sql.String())
+ return
+}
+
+func (d *insertData) appendValuesToSQL(w io.Writer, args []interface{}) ([]interface{}, error) {
+ if len(d.Values) == 0 {
+ return args, errors.New("values for insert statements are not set")
+ }
+
+ io.WriteString(w, "VALUES ")
+
+ valuesStrings := make([]string, len(d.Values))
+ for r, row := range d.Values {
+ valueStrings := make([]string, len(row))
+ for v, val := range row {
+ if vs, ok := val.(Sqlizer); ok {
+ vsql, vargs, err := vs.ToSql()
+ if err != nil {
+ return nil, err
+ }
+ valueStrings[v] = vsql
+ args = append(args, vargs...)
+ } else {
+ valueStrings[v] = "?"
+ args = append(args, val)
+ }
+ }
+ valuesStrings[r] = fmt.Sprintf("(%s)", strings.Join(valueStrings, ","))
+ }
+
+ io.WriteString(w, strings.Join(valuesStrings, ","))
+
+ return args, nil
+}
+
+func (d *insertData) appendSelectToSQL(w io.Writer, args []interface{}) ([]interface{}, error) {
+ if d.Select == nil {
+ return args, errors.New("select clause for insert statements are not set")
+ }
+
+ selectClause, sArgs, err := d.Select.ToSql()
+ if err != nil {
+ return args, err
+ }
+
+ io.WriteString(w, selectClause)
+ args = append(args, sArgs...)
+
+ return args, nil
+}
+
+// Builder
+
+// InsertBuilder builds SQL INSERT statements.
+type InsertBuilder builder.Builder
+
+func init() {
+ builder.Register(InsertBuilder{}, insertData{})
+}
+
+// Format methods
+
+// PlaceholderFormat sets PlaceholderFormat (e.g. Question or Dollar) for the
+// query.
+func (b InsertBuilder) PlaceholderFormat(f PlaceholderFormat) InsertBuilder {
+ return builder.Set(b, "PlaceholderFormat", f).(InsertBuilder)
+}
+
+// Runner methods
+
+// RunWith sets a Runner (like database/sql.DB) to be used with e.g. Exec.
+func (b InsertBuilder) RunWith(runner BaseRunner) InsertBuilder {
+ return setRunWith(b, runner).(InsertBuilder)
+}
+
+// Exec builds and Execs the query with the Runner set by RunWith.
+func (b InsertBuilder) Exec() (sql.Result, error) {
+ data := builder.GetStruct(b).(insertData)
+ return data.Exec()
+}
+
+// Query builds and Querys the query with the Runner set by RunWith.
+func (b InsertBuilder) Query() (*sql.Rows, error) {
+ data := builder.GetStruct(b).(insertData)
+ return data.Query()
+}
+
+// QueryRow builds and QueryRows the query with the Runner set by RunWith.
+func (b InsertBuilder) QueryRow() RowScanner {
+ data := builder.GetStruct(b).(insertData)
+ return data.QueryRow()
+}
+
+// Scan is a shortcut for QueryRow().Scan.
+func (b InsertBuilder) Scan(dest ...interface{}) error {
+ return b.QueryRow().Scan(dest...)
+}
+
+// SQL methods
+
+// ToSql builds the query into a SQL string and bound args.
+func (b InsertBuilder) ToSql() (string, []interface{}, error) {
+ data := builder.GetStruct(b).(insertData)
+ return data.ToSql()
+}
+
+// MustSql builds the query into a SQL string and bound args.
+// It panics if there are any errors.
+func (b InsertBuilder) MustSql() (string, []interface{}) {
+ sql, args, err := b.ToSql()
+ if err != nil {
+ panic(err)
+ }
+ return sql, args
+}
+
+// Prefix adds an expression to the beginning of the query
+func (b InsertBuilder) Prefix(sql string, args ...interface{}) InsertBuilder {
+ return b.PrefixExpr(Expr(sql, args...))
+}
+
+// PrefixExpr adds an expression to the very beginning of the query
+func (b InsertBuilder) PrefixExpr(expr Sqlizer) InsertBuilder {
+ return builder.Append(b, "Prefixes", expr).(InsertBuilder)
+}
+
+// Options adds keyword options before the INTO clause of the query.
+func (b InsertBuilder) Options(options ...string) InsertBuilder {
+ return builder.Extend(b, "Options", options).(InsertBuilder)
+}
+
+// Into sets the INTO clause of the query.
+func (b InsertBuilder) Into(from string) InsertBuilder {
+ return builder.Set(b, "Into", from).(InsertBuilder)
+}
+
+// Columns adds insert columns to the query.
+func (b InsertBuilder) Columns(columns ...string) InsertBuilder {
+ return builder.Extend(b, "Columns", columns).(InsertBuilder)
+}
+
+// Values adds a single row's values to the query.
+func (b InsertBuilder) Values(values ...interface{}) InsertBuilder {
+ return builder.Append(b, "Values", values).(InsertBuilder)
+}
+
+// Suffix adds an expression to the end of the query
+func (b InsertBuilder) Suffix(sql string, args ...interface{}) InsertBuilder {
+ return b.SuffixExpr(Expr(sql, args...))
+}
+
+// SuffixExpr adds an expression to the end of the query
+func (b InsertBuilder) SuffixExpr(expr Sqlizer) InsertBuilder {
+ return builder.Append(b, "Suffixes", expr).(InsertBuilder)
+}
+
+// SetMap set columns and values for insert builder from a map of column name and value
+// note that it will reset all previous columns and values was set if any
+func (b InsertBuilder) SetMap(clauses map[string]interface{}) InsertBuilder {
+ // Keep the columns in a consistent order by sorting the column key string.
+ cols := make([]string, 0, len(clauses))
+ for col := range clauses {
+ cols = append(cols, col)
+ }
+ sort.Strings(cols)
+
+ vals := make([]interface{}, 0, len(clauses))
+ for _, col := range cols {
+ vals = append(vals, clauses[col])
+ }
+
+ b = builder.Set(b, "Columns", cols).(InsertBuilder)
+ b = builder.Set(b, "Values", [][]interface{}{vals}).(InsertBuilder)
+
+ return b
+}
+
+// Select set Select clause for insert query
+// If Values and Select are used, then Select has higher priority
+func (b InsertBuilder) Select(sb SelectBuilder) InsertBuilder {
+ return builder.Set(b, "Select", &sb).(InsertBuilder)
+}
+
+func (b InsertBuilder) statementKeyword(keyword string) InsertBuilder {
+ return builder.Set(b, "StatementKeyword", keyword).(InsertBuilder)
+}
diff --git a/vendor/github.com/Masterminds/squirrel/insert_ctx.go b/vendor/github.com/Masterminds/squirrel/insert_ctx.go
new file mode 100644
index 0000000000..4541c2fed3
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/insert_ctx.go
@@ -0,0 +1,69 @@
+// +build go1.8
+
+package squirrel
+
+import (
+ "context"
+ "database/sql"
+
+ "github.com/lann/builder"
+)
+
+func (d *insertData) ExecContext(ctx context.Context) (sql.Result, error) {
+ if d.RunWith == nil {
+ return nil, RunnerNotSet
+ }
+ ctxRunner, ok := d.RunWith.(ExecerContext)
+ if !ok {
+ return nil, NoContextSupport
+ }
+ return ExecContextWith(ctx, ctxRunner, d)
+}
+
+func (d *insertData) QueryContext(ctx context.Context) (*sql.Rows, error) {
+ if d.RunWith == nil {
+ return nil, RunnerNotSet
+ }
+ ctxRunner, ok := d.RunWith.(QueryerContext)
+ if !ok {
+ return nil, NoContextSupport
+ }
+ return QueryContextWith(ctx, ctxRunner, d)
+}
+
+func (d *insertData) QueryRowContext(ctx context.Context) RowScanner {
+ if d.RunWith == nil {
+ return &Row{err: RunnerNotSet}
+ }
+ queryRower, ok := d.RunWith.(QueryRowerContext)
+ if !ok {
+ if _, ok := d.RunWith.(QueryerContext); !ok {
+ return &Row{err: RunnerNotQueryRunner}
+ }
+ return &Row{err: NoContextSupport}
+ }
+ return QueryRowContextWith(ctx, queryRower, d)
+}
+
+// ExecContext builds and ExecContexts the query with the Runner set by RunWith.
+func (b InsertBuilder) ExecContext(ctx context.Context) (sql.Result, error) {
+ data := builder.GetStruct(b).(insertData)
+ return data.ExecContext(ctx)
+}
+
+// QueryContext builds and QueryContexts the query with the Runner set by RunWith.
+func (b InsertBuilder) QueryContext(ctx context.Context) (*sql.Rows, error) {
+ data := builder.GetStruct(b).(insertData)
+ return data.QueryContext(ctx)
+}
+
+// QueryRowContext builds and QueryRowContexts the query with the Runner set by RunWith.
+func (b InsertBuilder) QueryRowContext(ctx context.Context) RowScanner {
+ data := builder.GetStruct(b).(insertData)
+ return data.QueryRowContext(ctx)
+}
+
+// ScanContext is a shortcut for QueryRowContext().Scan.
+func (b InsertBuilder) ScanContext(ctx context.Context, dest ...interface{}) error {
+ return b.QueryRowContext(ctx).Scan(dest...)
+}
diff --git a/vendor/github.com/Masterminds/squirrel/part.go b/vendor/github.com/Masterminds/squirrel/part.go
new file mode 100644
index 0000000000..c58f68f1a4
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/part.go
@@ -0,0 +1,63 @@
+package squirrel
+
+import (
+ "fmt"
+ "io"
+)
+
+type part struct {
+ pred interface{}
+ args []interface{}
+}
+
+func newPart(pred interface{}, args ...interface{}) Sqlizer {
+ return &part{pred, args}
+}
+
+func (p part) ToSql() (sql string, args []interface{}, err error) {
+ switch pred := p.pred.(type) {
+ case nil:
+ // no-op
+ case Sqlizer:
+ sql, args, err = nestedToSql(pred)
+ case string:
+ sql = pred
+ args = p.args
+ default:
+ err = fmt.Errorf("expected string or Sqlizer, not %T", pred)
+ }
+ return
+}
+
+func nestedToSql(s Sqlizer) (string, []interface{}, error) {
+ if raw, ok := s.(rawSqlizer); ok {
+ return raw.toSqlRaw()
+ } else {
+ return s.ToSql()
+ }
+}
+
+func appendToSql(parts []Sqlizer, w io.Writer, sep string, args []interface{}) ([]interface{}, error) {
+ for i, p := range parts {
+ partSql, partArgs, err := nestedToSql(p)
+ if err != nil {
+ return nil, err
+ } else if len(partSql) == 0 {
+ continue
+ }
+
+ if i > 0 {
+ _, err := io.WriteString(w, sep)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ _, err = io.WriteString(w, partSql)
+ if err != nil {
+ return nil, err
+ }
+ args = append(args, partArgs...)
+ }
+ return args, nil
+}
diff --git a/vendor/github.com/Masterminds/squirrel/placeholder.go b/vendor/github.com/Masterminds/squirrel/placeholder.go
new file mode 100644
index 0000000000..8e97a6c62d
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/placeholder.go
@@ -0,0 +1,114 @@
+package squirrel
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+)
+
+// PlaceholderFormat is the interface that wraps the ReplacePlaceholders method.
+//
+// ReplacePlaceholders takes a SQL statement and replaces each question mark
+// placeholder with a (possibly different) SQL placeholder.
+type PlaceholderFormat interface {
+ ReplacePlaceholders(sql string) (string, error)
+}
+
+type placeholderDebugger interface {
+ debugPlaceholder() string
+}
+
+var (
+ // Question is a PlaceholderFormat instance that leaves placeholders as
+ // question marks.
+ Question = questionFormat{}
+
+ // Dollar is a PlaceholderFormat instance that replaces placeholders with
+ // dollar-prefixed positional placeholders (e.g. $1, $2, $3).
+ Dollar = dollarFormat{}
+
+ // Colon is a PlaceholderFormat instance that replaces placeholders with
+ // colon-prefixed positional placeholders (e.g. :1, :2, :3).
+ Colon = colonFormat{}
+
+ // AtP is a PlaceholderFormat instance that replaces placeholders with
+ // "@p"-prefixed positional placeholders (e.g. @p1, @p2, @p3).
+ AtP = atpFormat{}
+)
+
+type questionFormat struct{}
+
+func (questionFormat) ReplacePlaceholders(sql string) (string, error) {
+ return sql, nil
+}
+
+func (questionFormat) debugPlaceholder() string {
+ return "?"
+}
+
+type dollarFormat struct{}
+
+func (dollarFormat) ReplacePlaceholders(sql string) (string, error) {
+ return replacePositionalPlaceholders(sql, "$")
+}
+
+func (dollarFormat) debugPlaceholder() string {
+ return "$"
+}
+
+type colonFormat struct{}
+
+func (colonFormat) ReplacePlaceholders(sql string) (string, error) {
+ return replacePositionalPlaceholders(sql, ":")
+}
+
+func (colonFormat) debugPlaceholder() string {
+ return ":"
+}
+
+type atpFormat struct{}
+
+func (atpFormat) ReplacePlaceholders(sql string) (string, error) {
+ return replacePositionalPlaceholders(sql, "@p")
+}
+
+func (atpFormat) debugPlaceholder() string {
+ return "@p"
+}
+
+// Placeholders returns a string with count ? placeholders joined with commas.
+func Placeholders(count int) string {
+ if count < 1 {
+ return ""
+ }
+
+ return strings.Repeat(",?", count)[1:]
+}
+
+func replacePositionalPlaceholders(sql, prefix string) (string, error) {
+ buf := &bytes.Buffer{}
+ i := 0
+ for {
+ p := strings.Index(sql, "?")
+ if p == -1 {
+ break
+ }
+
+ if len(sql[p:]) > 1 && sql[p:p+2] == "??" { // escape ?? => ?
+ buf.WriteString(sql[:p])
+ buf.WriteString("?")
+ if len(sql[p:]) == 1 {
+ break
+ }
+ sql = sql[p+2:]
+ } else {
+ i++
+ buf.WriteString(sql[:p])
+ fmt.Fprintf(buf, "%s%d", prefix, i)
+ sql = sql[p+1:]
+ }
+ }
+
+ buf.WriteString(sql)
+ return buf.String(), nil
+}
diff --git a/vendor/github.com/Masterminds/squirrel/row.go b/vendor/github.com/Masterminds/squirrel/row.go
new file mode 100644
index 0000000000..74ffda92bd
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/row.go
@@ -0,0 +1,22 @@
+package squirrel
+
+// RowScanner is the interface that wraps the Scan method.
+//
+// Scan behaves like database/sql.Row.Scan.
+type RowScanner interface {
+ Scan(...interface{}) error
+}
+
+// Row wraps database/sql.Row to let squirrel return new errors on Scan.
+type Row struct {
+ RowScanner
+ err error
+}
+
+// Scan returns Row.err or calls RowScanner.Scan.
+func (r *Row) Scan(dest ...interface{}) error {
+ if r.err != nil {
+ return r.err
+ }
+ return r.RowScanner.Scan(dest...)
+}
diff --git a/vendor/github.com/Masterminds/squirrel/select.go b/vendor/github.com/Masterminds/squirrel/select.go
new file mode 100644
index 0000000000..d55ce4c740
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/select.go
@@ -0,0 +1,403 @@
+package squirrel
+
+import (
+ "bytes"
+ "database/sql"
+ "fmt"
+ "strings"
+
+ "github.com/lann/builder"
+)
+
+type selectData struct {
+ PlaceholderFormat PlaceholderFormat
+ RunWith BaseRunner
+ Prefixes []Sqlizer
+ Options []string
+ Columns []Sqlizer
+ From Sqlizer
+ Joins []Sqlizer
+ WhereParts []Sqlizer
+ GroupBys []string
+ HavingParts []Sqlizer
+ OrderByParts []Sqlizer
+ Limit string
+ Offset string
+ Suffixes []Sqlizer
+}
+
+func (d *selectData) Exec() (sql.Result, error) {
+ if d.RunWith == nil {
+ return nil, RunnerNotSet
+ }
+ return ExecWith(d.RunWith, d)
+}
+
+func (d *selectData) Query() (*sql.Rows, error) {
+ if d.RunWith == nil {
+ return nil, RunnerNotSet
+ }
+ return QueryWith(d.RunWith, d)
+}
+
+func (d *selectData) QueryRow() RowScanner {
+ if d.RunWith == nil {
+ return &Row{err: RunnerNotSet}
+ }
+ queryRower, ok := d.RunWith.(QueryRower)
+ if !ok {
+ return &Row{err: RunnerNotQueryRunner}
+ }
+ return QueryRowWith(queryRower, d)
+}
+
+func (d *selectData) ToSql() (sqlStr string, args []interface{}, err error) {
+ sqlStr, args, err = d.toSqlRaw()
+ if err != nil {
+ return
+ }
+
+ sqlStr, err = d.PlaceholderFormat.ReplacePlaceholders(sqlStr)
+ return
+}
+
+func (d *selectData) toSqlRaw() (sqlStr string, args []interface{}, err error) {
+ if len(d.Columns) == 0 {
+ err = fmt.Errorf("select statements must have at least one result column")
+ return
+ }
+
+ sql := &bytes.Buffer{}
+
+ if len(d.Prefixes) > 0 {
+ args, err = appendToSql(d.Prefixes, sql, " ", args)
+ if err != nil {
+ return
+ }
+
+ sql.WriteString(" ")
+ }
+
+ sql.WriteString("SELECT ")
+
+ if len(d.Options) > 0 {
+ sql.WriteString(strings.Join(d.Options, " "))
+ sql.WriteString(" ")
+ }
+
+ if len(d.Columns) > 0 {
+ args, err = appendToSql(d.Columns, sql, ", ", args)
+ if err != nil {
+ return
+ }
+ }
+
+ if d.From != nil {
+ sql.WriteString(" FROM ")
+ args, err = appendToSql([]Sqlizer{d.From}, sql, "", args)
+ if err != nil {
+ return
+ }
+ }
+
+ if len(d.Joins) > 0 {
+ sql.WriteString(" ")
+ args, err = appendToSql(d.Joins, sql, " ", args)
+ if err != nil {
+ return
+ }
+ }
+
+ if len(d.WhereParts) > 0 {
+ sql.WriteString(" WHERE ")
+ args, err = appendToSql(d.WhereParts, sql, " AND ", args)
+ if err != nil {
+ return
+ }
+ }
+
+ if len(d.GroupBys) > 0 {
+ sql.WriteString(" GROUP BY ")
+ sql.WriteString(strings.Join(d.GroupBys, ", "))
+ }
+
+ if len(d.HavingParts) > 0 {
+ sql.WriteString(" HAVING ")
+ args, err = appendToSql(d.HavingParts, sql, " AND ", args)
+ if err != nil {
+ return
+ }
+ }
+
+ if len(d.OrderByParts) > 0 {
+ sql.WriteString(" ORDER BY ")
+ args, err = appendToSql(d.OrderByParts, sql, ", ", args)
+ if err != nil {
+ return
+ }
+ }
+
+ if len(d.Limit) > 0 {
+ sql.WriteString(" LIMIT ")
+ sql.WriteString(d.Limit)
+ }
+
+ if len(d.Offset) > 0 {
+ sql.WriteString(" OFFSET ")
+ sql.WriteString(d.Offset)
+ }
+
+ if len(d.Suffixes) > 0 {
+ sql.WriteString(" ")
+
+ args, err = appendToSql(d.Suffixes, sql, " ", args)
+ if err != nil {
+ return
+ }
+ }
+
+ sqlStr = sql.String()
+ return
+}
+
+// Builder
+
+// SelectBuilder builds SQL SELECT statements.
+type SelectBuilder builder.Builder
+
+func init() {
+ builder.Register(SelectBuilder{}, selectData{})
+}
+
+// Format methods
+
+// PlaceholderFormat sets PlaceholderFormat (e.g. Question or Dollar) for the
+// query.
+func (b SelectBuilder) PlaceholderFormat(f PlaceholderFormat) SelectBuilder {
+ return builder.Set(b, "PlaceholderFormat", f).(SelectBuilder)
+}
+
+// Runner methods
+
+// RunWith sets a Runner (like database/sql.DB) to be used with e.g. Exec.
+// For most cases runner will be a database connection.
+//
+// Internally we use this to mock out the database connection for testing.
+func (b SelectBuilder) RunWith(runner BaseRunner) SelectBuilder {
+ return setRunWith(b, runner).(SelectBuilder)
+}
+
+// Exec builds and Execs the query with the Runner set by RunWith.
+func (b SelectBuilder) Exec() (sql.Result, error) {
+ data := builder.GetStruct(b).(selectData)
+ return data.Exec()
+}
+
+// Query builds and Querys the query with the Runner set by RunWith.
+func (b SelectBuilder) Query() (*sql.Rows, error) {
+ data := builder.GetStruct(b).(selectData)
+ return data.Query()
+}
+
+// QueryRow builds and QueryRows the query with the Runner set by RunWith.
+func (b SelectBuilder) QueryRow() RowScanner {
+ data := builder.GetStruct(b).(selectData)
+ return data.QueryRow()
+}
+
+// Scan is a shortcut for QueryRow().Scan.
+func (b SelectBuilder) Scan(dest ...interface{}) error {
+ return b.QueryRow().Scan(dest...)
+}
+
+// SQL methods
+
+// ToSql builds the query into a SQL string and bound args.
+func (b SelectBuilder) ToSql() (string, []interface{}, error) {
+ data := builder.GetStruct(b).(selectData)
+ return data.ToSql()
+}
+
+func (b SelectBuilder) toSqlRaw() (string, []interface{}, error) {
+ data := builder.GetStruct(b).(selectData)
+ return data.toSqlRaw()
+}
+
+// MustSql builds the query into a SQL string and bound args.
+// It panics if there are any errors.
+func (b SelectBuilder) MustSql() (string, []interface{}) {
+ sql, args, err := b.ToSql()
+ if err != nil {
+ panic(err)
+ }
+ return sql, args
+}
+
+// Prefix adds an expression to the beginning of the query
+func (b SelectBuilder) Prefix(sql string, args ...interface{}) SelectBuilder {
+ return b.PrefixExpr(Expr(sql, args...))
+}
+
+// PrefixExpr adds an expression to the very beginning of the query
+func (b SelectBuilder) PrefixExpr(expr Sqlizer) SelectBuilder {
+ return builder.Append(b, "Prefixes", expr).(SelectBuilder)
+}
+
+// Distinct adds a DISTINCT clause to the query.
+func (b SelectBuilder) Distinct() SelectBuilder {
+ return b.Options("DISTINCT")
+}
+
+// Options adds select option to the query
+func (b SelectBuilder) Options(options ...string) SelectBuilder {
+ return builder.Extend(b, "Options", options).(SelectBuilder)
+}
+
+// Columns adds result columns to the query.
+func (b SelectBuilder) Columns(columns ...string) SelectBuilder {
+ parts := make([]interface{}, 0, len(columns))
+ for _, str := range columns {
+ parts = append(parts, newPart(str))
+ }
+ return builder.Extend(b, "Columns", parts).(SelectBuilder)
+}
+
+// RemoveColumns remove all columns from query.
+// Must add a new column with Column or Columns methods, otherwise
+// return a error.
+func (b SelectBuilder) RemoveColumns() SelectBuilder {
+ return builder.Delete(b, "Columns").(SelectBuilder)
+}
+
+// Column adds a result column to the query.
+// Unlike Columns, Column accepts args which will be bound to placeholders in
+// the columns string, for example:
+// Column("IF(col IN ("+squirrel.Placeholders(3)+"), 1, 0) as col", 1, 2, 3)
+func (b SelectBuilder) Column(column interface{}, args ...interface{}) SelectBuilder {
+ return builder.Append(b, "Columns", newPart(column, args...)).(SelectBuilder)
+}
+
+// From sets the FROM clause of the query.
+func (b SelectBuilder) From(from string) SelectBuilder {
+ return builder.Set(b, "From", newPart(from)).(SelectBuilder)
+}
+
+// FromSelect sets a subquery into the FROM clause of the query.
+func (b SelectBuilder) FromSelect(from SelectBuilder, alias string) SelectBuilder {
+ // Prevent misnumbered parameters in nested selects (#183).
+ from = from.PlaceholderFormat(Question)
+ return builder.Set(b, "From", Alias(from, alias)).(SelectBuilder)
+}
+
+// JoinClause adds a join clause to the query.
+func (b SelectBuilder) JoinClause(pred interface{}, args ...interface{}) SelectBuilder {
+ return builder.Append(b, "Joins", newPart(pred, args...)).(SelectBuilder)
+}
+
+// Join adds a JOIN clause to the query.
+func (b SelectBuilder) Join(join string, rest ...interface{}) SelectBuilder {
+ return b.JoinClause("JOIN "+join, rest...)
+}
+
+// LeftJoin adds a LEFT JOIN clause to the query.
+func (b SelectBuilder) LeftJoin(join string, rest ...interface{}) SelectBuilder {
+ return b.JoinClause("LEFT JOIN "+join, rest...)
+}
+
+// RightJoin adds a RIGHT JOIN clause to the query.
+func (b SelectBuilder) RightJoin(join string, rest ...interface{}) SelectBuilder {
+ return b.JoinClause("RIGHT JOIN "+join, rest...)
+}
+
+// InnerJoin adds a INNER JOIN clause to the query.
+func (b SelectBuilder) InnerJoin(join string, rest ...interface{}) SelectBuilder {
+ return b.JoinClause("INNER JOIN "+join, rest...)
+}
+
+// CrossJoin adds a CROSS JOIN clause to the query.
+func (b SelectBuilder) CrossJoin(join string, rest ...interface{}) SelectBuilder {
+ return b.JoinClause("CROSS JOIN "+join, rest...)
+}
+
+// Where adds an expression to the WHERE clause of the query.
+//
+// Expressions are ANDed together in the generated SQL.
+//
+// Where accepts several types for its pred argument:
+//
+// nil OR "" - ignored.
+//
+// string - SQL expression.
+// If the expression has SQL placeholders then a set of arguments must be passed
+// as well, one for each placeholder.
+//
+// map[string]interface{} OR Eq - map of SQL expressions to values. Each key is
+// transformed into an expression like " = ?", with the corresponding value
+// bound to the placeholder. If the value is nil, the expression will be "
+// IS NULL". If the value is an array or slice, the expression will be " IN
+// (?,?,...)", with one placeholder for each item in the value. These expressions
+// are ANDed together.
+//
+// Where will panic if pred isn't any of the above types.
+func (b SelectBuilder) Where(pred interface{}, args ...interface{}) SelectBuilder {
+ if pred == nil || pred == "" {
+ return b
+ }
+ return builder.Append(b, "WhereParts", newWherePart(pred, args...)).(SelectBuilder)
+}
+
+// GroupBy adds GROUP BY expressions to the query.
+func (b SelectBuilder) GroupBy(groupBys ...string) SelectBuilder {
+ return builder.Extend(b, "GroupBys", groupBys).(SelectBuilder)
+}
+
+// Having adds an expression to the HAVING clause of the query.
+//
+// See Where.
+func (b SelectBuilder) Having(pred interface{}, rest ...interface{}) SelectBuilder {
+ return builder.Append(b, "HavingParts", newWherePart(pred, rest...)).(SelectBuilder)
+}
+
+// OrderByClause adds ORDER BY clause to the query.
+func (b SelectBuilder) OrderByClause(pred interface{}, args ...interface{}) SelectBuilder {
+ return builder.Append(b, "OrderByParts", newPart(pred, args...)).(SelectBuilder)
+}
+
+// OrderBy adds ORDER BY expressions to the query.
+func (b SelectBuilder) OrderBy(orderBys ...string) SelectBuilder {
+ for _, orderBy := range orderBys {
+ b = b.OrderByClause(orderBy)
+ }
+
+ return b
+}
+
+// Limit sets a LIMIT clause on the query.
+func (b SelectBuilder) Limit(limit uint64) SelectBuilder {
+ return builder.Set(b, "Limit", fmt.Sprintf("%d", limit)).(SelectBuilder)
+}
+
+// Limit ALL allows to access all records with limit
+func (b SelectBuilder) RemoveLimit() SelectBuilder {
+ return builder.Delete(b, "Limit").(SelectBuilder)
+}
+
+// Offset sets a OFFSET clause on the query.
+func (b SelectBuilder) Offset(offset uint64) SelectBuilder {
+ return builder.Set(b, "Offset", fmt.Sprintf("%d", offset)).(SelectBuilder)
+}
+
+// RemoveOffset removes OFFSET clause.
+func (b SelectBuilder) RemoveOffset() SelectBuilder {
+ return builder.Delete(b, "Offset").(SelectBuilder)
+}
+
+// Suffix adds an expression to the end of the query
+func (b SelectBuilder) Suffix(sql string, args ...interface{}) SelectBuilder {
+ return b.SuffixExpr(Expr(sql, args...))
+}
+
+// SuffixExpr adds an expression to the end of the query
+func (b SelectBuilder) SuffixExpr(expr Sqlizer) SelectBuilder {
+ return builder.Append(b, "Suffixes", expr).(SelectBuilder)
+}
diff --git a/vendor/github.com/Masterminds/squirrel/select_ctx.go b/vendor/github.com/Masterminds/squirrel/select_ctx.go
new file mode 100644
index 0000000000..4c42c13f47
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/select_ctx.go
@@ -0,0 +1,69 @@
+// +build go1.8
+
+package squirrel
+
+import (
+ "context"
+ "database/sql"
+
+ "github.com/lann/builder"
+)
+
+func (d *selectData) ExecContext(ctx context.Context) (sql.Result, error) {
+ if d.RunWith == nil {
+ return nil, RunnerNotSet
+ }
+ ctxRunner, ok := d.RunWith.(ExecerContext)
+ if !ok {
+ return nil, NoContextSupport
+ }
+ return ExecContextWith(ctx, ctxRunner, d)
+}
+
+func (d *selectData) QueryContext(ctx context.Context) (*sql.Rows, error) {
+ if d.RunWith == nil {
+ return nil, RunnerNotSet
+ }
+ ctxRunner, ok := d.RunWith.(QueryerContext)
+ if !ok {
+ return nil, NoContextSupport
+ }
+ return QueryContextWith(ctx, ctxRunner, d)
+}
+
+func (d *selectData) QueryRowContext(ctx context.Context) RowScanner {
+ if d.RunWith == nil {
+ return &Row{err: RunnerNotSet}
+ }
+ queryRower, ok := d.RunWith.(QueryRowerContext)
+ if !ok {
+ if _, ok := d.RunWith.(QueryerContext); !ok {
+ return &Row{err: RunnerNotQueryRunner}
+ }
+ return &Row{err: NoContextSupport}
+ }
+ return QueryRowContextWith(ctx, queryRower, d)
+}
+
+// ExecContext builds and ExecContexts the query with the Runner set by RunWith.
+func (b SelectBuilder) ExecContext(ctx context.Context) (sql.Result, error) {
+ data := builder.GetStruct(b).(selectData)
+ return data.ExecContext(ctx)
+}
+
+// QueryContext builds and QueryContexts the query with the Runner set by RunWith.
+func (b SelectBuilder) QueryContext(ctx context.Context) (*sql.Rows, error) {
+ data := builder.GetStruct(b).(selectData)
+ return data.QueryContext(ctx)
+}
+
+// QueryRowContext builds and QueryRowContexts the query with the Runner set by RunWith.
+func (b SelectBuilder) QueryRowContext(ctx context.Context) RowScanner {
+ data := builder.GetStruct(b).(selectData)
+ return data.QueryRowContext(ctx)
+}
+
+// ScanContext is a shortcut for QueryRowContext().Scan.
+func (b SelectBuilder) ScanContext(ctx context.Context, dest ...interface{}) error {
+ return b.QueryRowContext(ctx).Scan(dest...)
+}
diff --git a/vendor/github.com/Masterminds/squirrel/squirrel.go b/vendor/github.com/Masterminds/squirrel/squirrel.go
new file mode 100644
index 0000000000..46d456eb62
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/squirrel.go
@@ -0,0 +1,183 @@
+// Package squirrel provides a fluent SQL generator.
+//
+// See https://github.com/Masterminds/squirrel for examples.
+package squirrel
+
+import (
+ "bytes"
+ "database/sql"
+ "fmt"
+ "strings"
+
+ "github.com/lann/builder"
+)
+
+// Sqlizer is the interface that wraps the ToSql method.
+//
+// ToSql returns a SQL representation of the Sqlizer, along with a slice of args
+// as passed to e.g. database/sql.Exec. It can also return an error.
+type Sqlizer interface {
+ ToSql() (string, []interface{}, error)
+}
+
+// rawSqlizer is expected to do what Sqlizer does, but without finalizing placeholders.
+// This is useful for nested queries.
+type rawSqlizer interface {
+ toSqlRaw() (string, []interface{}, error)
+}
+
+// Execer is the interface that wraps the Exec method.
+//
+// Exec executes the given query as implemented by database/sql.Exec.
+type Execer interface {
+ Exec(query string, args ...interface{}) (sql.Result, error)
+}
+
+// Queryer is the interface that wraps the Query method.
+//
+// Query executes the given query as implemented by database/sql.Query.
+type Queryer interface {
+ Query(query string, args ...interface{}) (*sql.Rows, error)
+}
+
+// QueryRower is the interface that wraps the QueryRow method.
+//
+// QueryRow executes the given query as implemented by database/sql.QueryRow.
+type QueryRower interface {
+ QueryRow(query string, args ...interface{}) RowScanner
+}
+
+// BaseRunner groups the Execer and Queryer interfaces.
+type BaseRunner interface {
+ Execer
+ Queryer
+}
+
+// Runner groups the Execer, Queryer, and QueryRower interfaces.
+type Runner interface {
+ Execer
+ Queryer
+ QueryRower
+}
+
+// WrapStdSql wraps a type implementing the standard SQL interface with methods that
+// squirrel expects.
+func WrapStdSql(stdSql StdSql) Runner {
+ return &stdsqlRunner{stdSql}
+}
+
+// StdSql encompasses the standard methods of the *sql.DB type, and other types that
+// wrap these methods.
+type StdSql interface {
+ Query(string, ...interface{}) (*sql.Rows, error)
+ QueryRow(string, ...interface{}) *sql.Row
+ Exec(string, ...interface{}) (sql.Result, error)
+}
+
+type stdsqlRunner struct {
+ StdSql
+}
+
+func (r *stdsqlRunner) QueryRow(query string, args ...interface{}) RowScanner {
+ return r.StdSql.QueryRow(query, args...)
+}
+
+func setRunWith(b interface{}, runner BaseRunner) interface{} {
+ switch r := runner.(type) {
+ case StdSqlCtx:
+ runner = WrapStdSqlCtx(r)
+ case StdSql:
+ runner = WrapStdSql(r)
+ }
+ return builder.Set(b, "RunWith", runner)
+}
+
+// RunnerNotSet is returned by methods that need a Runner if it isn't set.
+var RunnerNotSet = fmt.Errorf("cannot run; no Runner set (RunWith)")
+
+// RunnerNotQueryRunner is returned by QueryRow if the RunWith value doesn't implement QueryRower.
+var RunnerNotQueryRunner = fmt.Errorf("cannot QueryRow; Runner is not a QueryRower")
+
+// ExecWith Execs the SQL returned by s with db.
+func ExecWith(db Execer, s Sqlizer) (res sql.Result, err error) {
+ query, args, err := s.ToSql()
+ if err != nil {
+ return
+ }
+ return db.Exec(query, args...)
+}
+
+// QueryWith Querys the SQL returned by s with db.
+func QueryWith(db Queryer, s Sqlizer) (rows *sql.Rows, err error) {
+ query, args, err := s.ToSql()
+ if err != nil {
+ return
+ }
+ return db.Query(query, args...)
+}
+
+// QueryRowWith QueryRows the SQL returned by s with db.
+func QueryRowWith(db QueryRower, s Sqlizer) RowScanner {
+ query, args, err := s.ToSql()
+ return &Row{RowScanner: db.QueryRow(query, args...), err: err}
+}
+
+// DebugSqlizer calls ToSql on s and shows the approximate SQL to be executed
+//
+// If ToSql returns an error, the result of this method will look like:
+// "[ToSql error: %s]" or "[DebugSqlizer error: %s]"
+//
+// IMPORTANT: As its name suggests, this function should only be used for
+// debugging. While the string result *might* be valid SQL, this function does
+// not try very hard to ensure it. Additionally, executing the output of this
+// function with any untrusted user input is certainly insecure.
+func DebugSqlizer(s Sqlizer) string {
+ sql, args, err := s.ToSql()
+ if err != nil {
+ return fmt.Sprintf("[ToSql error: %s]", err)
+ }
+
+ var placeholder string
+ downCast, ok := s.(placeholderDebugger)
+ if !ok {
+ placeholder = "?"
+ } else {
+ placeholder = downCast.debugPlaceholder()
+ }
+ // TODO: dedupe this with placeholder.go
+ buf := &bytes.Buffer{}
+ i := 0
+ for {
+ p := strings.Index(sql, placeholder)
+ if p == -1 {
+ break
+ }
+ if len(sql[p:]) > 1 && sql[p:p+2] == "??" { // escape ?? => ?
+ buf.WriteString(sql[:p])
+ buf.WriteString("?")
+ if len(sql[p:]) == 1 {
+ break
+ }
+ sql = sql[p+2:]
+ } else {
+ if i+1 > len(args) {
+ return fmt.Sprintf(
+ "[DebugSqlizer error: too many placeholders in %#v for %d args]",
+ sql, len(args))
+ }
+ buf.WriteString(sql[:p])
+ fmt.Fprintf(buf, "'%v'", args[i])
+ // advance our sql string "cursor" beyond the arg we placed
+ sql = sql[p+1:]
+ i++
+ }
+ }
+ if i < len(args) {
+ return fmt.Sprintf(
+ "[DebugSqlizer error: not enough placeholders in %#v for %d args]",
+ sql, len(args))
+ }
+ // "append" any remaning sql that won't need interpolating
+ buf.WriteString(sql)
+ return buf.String()
+}
diff --git a/vendor/github.com/Masterminds/squirrel/squirrel_ctx.go b/vendor/github.com/Masterminds/squirrel/squirrel_ctx.go
new file mode 100644
index 0000000000..c20148ad33
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/squirrel_ctx.go
@@ -0,0 +1,93 @@
+// +build go1.8
+
+package squirrel
+
+import (
+ "context"
+ "database/sql"
+ "errors"
+)
+
+// NoContextSupport is returned if a db doesn't support Context.
+var NoContextSupport = errors.New("DB does not support Context")
+
+// ExecerContext is the interface that wraps the ExecContext method.
+//
+// Exec executes the given query as implemented by database/sql.ExecContext.
+type ExecerContext interface {
+ ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
+}
+
+// QueryerContext is the interface that wraps the QueryContext method.
+//
+// QueryContext executes the given query as implemented by database/sql.QueryContext.
+type QueryerContext interface {
+ QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
+}
+
+// QueryRowerContext is the interface that wraps the QueryRowContext method.
+//
+// QueryRowContext executes the given query as implemented by database/sql.QueryRowContext.
+type QueryRowerContext interface {
+ QueryRowContext(ctx context.Context, query string, args ...interface{}) RowScanner
+}
+
+// RunnerContext groups the Runner interface, along with the Context versions of each of
+// its methods
+type RunnerContext interface {
+ Runner
+ QueryerContext
+ QueryRowerContext
+ ExecerContext
+}
+
+// WrapStdSqlCtx wraps a type implementing the standard SQL interface plus the context
+// versions of the methods with methods that squirrel expects.
+func WrapStdSqlCtx(stdSqlCtx StdSqlCtx) RunnerContext {
+ return &stdsqlCtxRunner{stdSqlCtx}
+}
+
+// StdSqlCtx encompasses the standard methods of the *sql.DB type, along with the Context
+// versions of those methods, and other types that wrap these methods.
+type StdSqlCtx interface {
+ StdSql
+ QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
+ QueryRowContext(context.Context, string, ...interface{}) *sql.Row
+ ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
+}
+
+type stdsqlCtxRunner struct {
+ StdSqlCtx
+}
+
+func (r *stdsqlCtxRunner) QueryRow(query string, args ...interface{}) RowScanner {
+ return r.StdSqlCtx.QueryRow(query, args...)
+}
+
+func (r *stdsqlCtxRunner) QueryRowContext(ctx context.Context, query string, args ...interface{}) RowScanner {
+ return r.StdSqlCtx.QueryRowContext(ctx, query, args...)
+}
+
+// ExecContextWith ExecContexts the SQL returned by s with db.
+func ExecContextWith(ctx context.Context, db ExecerContext, s Sqlizer) (res sql.Result, err error) {
+ query, args, err := s.ToSql()
+ if err != nil {
+ return
+ }
+ return db.ExecContext(ctx, query, args...)
+}
+
+// QueryContextWith QueryContexts the SQL returned by s with db.
+func QueryContextWith(ctx context.Context, db QueryerContext, s Sqlizer) (rows *sql.Rows, err error) {
+ query, args, err := s.ToSql()
+ if err != nil {
+ return
+ }
+ return db.QueryContext(ctx, query, args...)
+}
+
+// QueryRowContextWith QueryRowContexts the SQL returned by s with db.
+func QueryRowContextWith(ctx context.Context, db QueryRowerContext, s Sqlizer) RowScanner {
+ query, args, err := s.ToSql()
+ return &Row{RowScanner: db.QueryRowContext(ctx, query, args...), err: err}
+}
diff --git a/vendor/github.com/Masterminds/squirrel/statement.go b/vendor/github.com/Masterminds/squirrel/statement.go
new file mode 100644
index 0000000000..9420c67f8e
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/statement.go
@@ -0,0 +1,104 @@
+package squirrel
+
+import "github.com/lann/builder"
+
+// StatementBuilderType is the type of StatementBuilder.
+type StatementBuilderType builder.Builder
+
+// Select returns a SelectBuilder for this StatementBuilderType.
+func (b StatementBuilderType) Select(columns ...string) SelectBuilder {
+ return SelectBuilder(b).Columns(columns...)
+}
+
+// Insert returns a InsertBuilder for this StatementBuilderType.
+func (b StatementBuilderType) Insert(into string) InsertBuilder {
+ return InsertBuilder(b).Into(into)
+}
+
+// Replace returns a InsertBuilder for this StatementBuilderType with the
+// statement keyword set to "REPLACE".
+func (b StatementBuilderType) Replace(into string) InsertBuilder {
+ return InsertBuilder(b).statementKeyword("REPLACE").Into(into)
+}
+
+// Update returns a UpdateBuilder for this StatementBuilderType.
+func (b StatementBuilderType) Update(table string) UpdateBuilder {
+ return UpdateBuilder(b).Table(table)
+}
+
+// Delete returns a DeleteBuilder for this StatementBuilderType.
+func (b StatementBuilderType) Delete(from string) DeleteBuilder {
+ return DeleteBuilder(b).From(from)
+}
+
+// PlaceholderFormat sets the PlaceholderFormat field for any child builders.
+func (b StatementBuilderType) PlaceholderFormat(f PlaceholderFormat) StatementBuilderType {
+ return builder.Set(b, "PlaceholderFormat", f).(StatementBuilderType)
+}
+
+// RunWith sets the RunWith field for any child builders.
+func (b StatementBuilderType) RunWith(runner BaseRunner) StatementBuilderType {
+ return setRunWith(b, runner).(StatementBuilderType)
+}
+
+// Where adds WHERE expressions to the query.
+//
+// See SelectBuilder.Where for more information.
+func (b StatementBuilderType) Where(pred interface{}, args ...interface{}) StatementBuilderType {
+ return builder.Append(b, "WhereParts", newWherePart(pred, args...)).(StatementBuilderType)
+}
+
+// StatementBuilder is a parent builder for other builders, e.g. SelectBuilder.
+var StatementBuilder = StatementBuilderType(builder.EmptyBuilder).PlaceholderFormat(Question)
+
+// Select returns a new SelectBuilder, optionally setting some result columns.
+//
+// See SelectBuilder.Columns.
+func Select(columns ...string) SelectBuilder {
+ return StatementBuilder.Select(columns...)
+}
+
+// Insert returns a new InsertBuilder with the given table name.
+//
+// See InsertBuilder.Into.
+func Insert(into string) InsertBuilder {
+ return StatementBuilder.Insert(into)
+}
+
+// Replace returns a new InsertBuilder with the statement keyword set to
+// "REPLACE" and with the given table name.
+//
+// See InsertBuilder.Into.
+func Replace(into string) InsertBuilder {
+ return StatementBuilder.Replace(into)
+}
+
+// Update returns a new UpdateBuilder with the given table name.
+//
+// See UpdateBuilder.Table.
+func Update(table string) UpdateBuilder {
+ return StatementBuilder.Update(table)
+}
+
+// Delete returns a new DeleteBuilder with the given table name.
+//
+// See DeleteBuilder.Table.
+func Delete(from string) DeleteBuilder {
+ return StatementBuilder.Delete(from)
+}
+
+// Case returns a new CaseBuilder
+// "what" represents case value
+func Case(what ...interface{}) CaseBuilder {
+ b := CaseBuilder(builder.EmptyBuilder)
+
+ switch len(what) {
+ case 0:
+ case 1:
+ b = b.what(what[0])
+ default:
+ b = b.what(newPart(what[0], what[1:]...))
+
+ }
+ return b
+}
diff --git a/vendor/github.com/Masterminds/squirrel/stmtcacher.go b/vendor/github.com/Masterminds/squirrel/stmtcacher.go
new file mode 100644
index 0000000000..5bf267a136
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/stmtcacher.go
@@ -0,0 +1,121 @@
+package squirrel
+
+import (
+ "database/sql"
+ "fmt"
+ "sync"
+)
+
+// Prepareer is the interface that wraps the Prepare method.
+//
+// Prepare executes the given query as implemented by database/sql.Prepare.
+type Preparer interface {
+ Prepare(query string) (*sql.Stmt, error)
+}
+
+// DBProxy groups the Execer, Queryer, QueryRower, and Preparer interfaces.
+type DBProxy interface {
+ Execer
+ Queryer
+ QueryRower
+ Preparer
+}
+
+// NOTE: NewStmtCache is defined in stmtcacher_ctx.go (Go >= 1.8) or stmtcacher_noctx.go (Go < 1.8).
+
+// StmtCache wraps and delegates down to a Preparer type
+//
+// It also automatically prepares all statements sent to the underlying Preparer calls
+// for Exec, Query and QueryRow and caches the returns *sql.Stmt using the provided
+// query as the key. So that it can be automatically re-used.
+type StmtCache struct {
+ prep Preparer
+ cache map[string]*sql.Stmt
+ mu sync.Mutex
+}
+
+// Prepare delegates down to the underlying Preparer and caches the result
+// using the provided query as a key
+func (sc *StmtCache) Prepare(query string) (*sql.Stmt, error) {
+ sc.mu.Lock()
+ defer sc.mu.Unlock()
+
+ stmt, ok := sc.cache[query]
+ if ok {
+ return stmt, nil
+ }
+ stmt, err := sc.prep.Prepare(query)
+ if err == nil {
+ sc.cache[query] = stmt
+ }
+ return stmt, err
+}
+
+// Exec delegates down to the underlying Preparer using a prepared statement
+func (sc *StmtCache) Exec(query string, args ...interface{}) (res sql.Result, err error) {
+ stmt, err := sc.Prepare(query)
+ if err != nil {
+ return
+ }
+ return stmt.Exec(args...)
+}
+
+// Query delegates down to the underlying Preparer using a prepared statement
+func (sc *StmtCache) Query(query string, args ...interface{}) (rows *sql.Rows, err error) {
+ stmt, err := sc.Prepare(query)
+ if err != nil {
+ return
+ }
+ return stmt.Query(args...)
+}
+
+// QueryRow delegates down to the underlying Preparer using a prepared statement
+func (sc *StmtCache) QueryRow(query string, args ...interface{}) RowScanner {
+ stmt, err := sc.Prepare(query)
+ if err != nil {
+ return &Row{err: err}
+ }
+ return stmt.QueryRow(args...)
+}
+
+// Clear removes and closes all the currently cached prepared statements
+func (sc *StmtCache) Clear() (err error) {
+ sc.mu.Lock()
+ defer sc.mu.Unlock()
+
+ for key, stmt := range sc.cache {
+ delete(sc.cache, key)
+
+ if stmt == nil {
+ continue
+ }
+
+ if cerr := stmt.Close(); cerr != nil {
+ err = cerr
+ }
+ }
+
+ if err != nil {
+ return fmt.Errorf("one or more Stmt.Close failed; last error: %v", err)
+ }
+
+ return
+}
+
+type DBProxyBeginner interface {
+ DBProxy
+ Begin() (*sql.Tx, error)
+}
+
+type stmtCacheProxy struct {
+ DBProxy
+ db *sql.DB
+}
+
+func NewStmtCacheProxy(db *sql.DB) DBProxyBeginner {
+ return &stmtCacheProxy{DBProxy: NewStmtCache(db), db: db}
+}
+
+func (sp *stmtCacheProxy) Begin() (*sql.Tx, error) {
+ return sp.db.Begin()
+}
diff --git a/vendor/github.com/Masterminds/squirrel/stmtcacher_ctx.go b/vendor/github.com/Masterminds/squirrel/stmtcacher_ctx.go
new file mode 100644
index 0000000000..53603cf4c9
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/stmtcacher_ctx.go
@@ -0,0 +1,86 @@
+// +build go1.8
+
+package squirrel
+
+import (
+ "context"
+ "database/sql"
+)
+
+// PrepareerContext is the interface that wraps the Prepare and PrepareContext methods.
+//
+// Prepare executes the given query as implemented by database/sql.Prepare.
+// PrepareContext executes the given query as implemented by database/sql.PrepareContext.
+type PreparerContext interface {
+ Preparer
+ PrepareContext(ctx context.Context, query string) (*sql.Stmt, error)
+}
+
+// DBProxyContext groups the Execer, Queryer, QueryRower and PreparerContext interfaces.
+type DBProxyContext interface {
+ Execer
+ Queryer
+ QueryRower
+ PreparerContext
+}
+
+// NewStmtCache returns a *StmtCache wrapping a PreparerContext that caches Prepared Stmts.
+//
+// Stmts are cached based on the string value of their queries.
+func NewStmtCache(prep PreparerContext) *StmtCache {
+ return &StmtCache{prep: prep, cache: make(map[string]*sql.Stmt)}
+}
+
+// NewStmtCacher is deprecated
+//
+// Use NewStmtCache instead
+func NewStmtCacher(prep PreparerContext) DBProxyContext {
+ return NewStmtCache(prep)
+}
+
+// PrepareContext delegates down to the underlying PreparerContext and caches the result
+// using the provided query as a key
+func (sc *StmtCache) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) {
+ ctxPrep, ok := sc.prep.(PreparerContext)
+ if !ok {
+ return nil, NoContextSupport
+ }
+ sc.mu.Lock()
+ defer sc.mu.Unlock()
+ stmt, ok := sc.cache[query]
+ if ok {
+ return stmt, nil
+ }
+ stmt, err := ctxPrep.PrepareContext(ctx, query)
+ if err == nil {
+ sc.cache[query] = stmt
+ }
+ return stmt, err
+}
+
+// ExecContext delegates down to the underlying PreparerContext using a prepared statement
+func (sc *StmtCache) ExecContext(ctx context.Context, query string, args ...interface{}) (res sql.Result, err error) {
+ stmt, err := sc.PrepareContext(ctx, query)
+ if err != nil {
+ return
+ }
+ return stmt.ExecContext(ctx, args...)
+}
+
+// QueryContext delegates down to the underlying PreparerContext using a prepared statement
+func (sc *StmtCache) QueryContext(ctx context.Context, query string, args ...interface{}) (rows *sql.Rows, err error) {
+ stmt, err := sc.PrepareContext(ctx, query)
+ if err != nil {
+ return
+ }
+ return stmt.QueryContext(ctx, args...)
+}
+
+// QueryRowContext delegates down to the underlying PreparerContext using a prepared statement
+func (sc *StmtCache) QueryRowContext(ctx context.Context, query string, args ...interface{}) RowScanner {
+ stmt, err := sc.PrepareContext(ctx, query)
+ if err != nil {
+ return &Row{err: err}
+ }
+ return stmt.QueryRowContext(ctx, args...)
+}
diff --git a/vendor/github.com/Masterminds/squirrel/stmtcacher_noctx.go b/vendor/github.com/Masterminds/squirrel/stmtcacher_noctx.go
new file mode 100644
index 0000000000..deac96777b
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/stmtcacher_noctx.go
@@ -0,0 +1,21 @@
+// +build !go1.8
+
+package squirrel
+
+import (
+ "database/sql"
+)
+
+// NewStmtCacher returns a DBProxy wrapping prep that caches Prepared Stmts.
+//
+// Stmts are cached based on the string value of their queries.
+func NewStmtCache(prep Preparer) *StmtCache {
+ return &StmtCacher{prep: prep, cache: make(map[string]*sql.Stmt)}
+}
+
+// NewStmtCacher is deprecated
+//
+// Use NewStmtCache instead
+func NewStmtCacher(prep Preparer) DBProxy {
+ return NewStmtCache(prep)
+}
diff --git a/vendor/github.com/Masterminds/squirrel/update.go b/vendor/github.com/Masterminds/squirrel/update.go
new file mode 100644
index 0000000000..eb2a9c4dd9
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/update.go
@@ -0,0 +1,288 @@
+package squirrel
+
+import (
+ "bytes"
+ "database/sql"
+ "fmt"
+ "sort"
+ "strings"
+
+ "github.com/lann/builder"
+)
+
+type updateData struct {
+ PlaceholderFormat PlaceholderFormat
+ RunWith BaseRunner
+ Prefixes []Sqlizer
+ Table string
+ SetClauses []setClause
+ From Sqlizer
+ WhereParts []Sqlizer
+ OrderBys []string
+ Limit string
+ Offset string
+ Suffixes []Sqlizer
+}
+
+type setClause struct {
+ column string
+ value interface{}
+}
+
+func (d *updateData) Exec() (sql.Result, error) {
+ if d.RunWith == nil {
+ return nil, RunnerNotSet
+ }
+ return ExecWith(d.RunWith, d)
+}
+
+func (d *updateData) Query() (*sql.Rows, error) {
+ if d.RunWith == nil {
+ return nil, RunnerNotSet
+ }
+ return QueryWith(d.RunWith, d)
+}
+
+func (d *updateData) QueryRow() RowScanner {
+ if d.RunWith == nil {
+ return &Row{err: RunnerNotSet}
+ }
+ queryRower, ok := d.RunWith.(QueryRower)
+ if !ok {
+ return &Row{err: RunnerNotQueryRunner}
+ }
+ return QueryRowWith(queryRower, d)
+}
+
+func (d *updateData) ToSql() (sqlStr string, args []interface{}, err error) {
+ if len(d.Table) == 0 {
+ err = fmt.Errorf("update statements must specify a table")
+ return
+ }
+ if len(d.SetClauses) == 0 {
+ err = fmt.Errorf("update statements must have at least one Set clause")
+ return
+ }
+
+ sql := &bytes.Buffer{}
+
+ if len(d.Prefixes) > 0 {
+ args, err = appendToSql(d.Prefixes, sql, " ", args)
+ if err != nil {
+ return
+ }
+
+ sql.WriteString(" ")
+ }
+
+ sql.WriteString("UPDATE ")
+ sql.WriteString(d.Table)
+
+ sql.WriteString(" SET ")
+ setSqls := make([]string, len(d.SetClauses))
+ for i, setClause := range d.SetClauses {
+ var valSql string
+ if vs, ok := setClause.value.(Sqlizer); ok {
+ vsql, vargs, err := vs.ToSql()
+ if err != nil {
+ return "", nil, err
+ }
+ if _, ok := vs.(SelectBuilder); ok {
+ valSql = fmt.Sprintf("(%s)", vsql)
+ } else {
+ valSql = vsql
+ }
+ args = append(args, vargs...)
+ } else {
+ valSql = "?"
+ args = append(args, setClause.value)
+ }
+ setSqls[i] = fmt.Sprintf("%s = %s", setClause.column, valSql)
+ }
+ sql.WriteString(strings.Join(setSqls, ", "))
+
+ if d.From != nil {
+ sql.WriteString(" FROM ")
+ args, err = appendToSql([]Sqlizer{d.From}, sql, "", args)
+ if err != nil {
+ return
+ }
+ }
+
+ if len(d.WhereParts) > 0 {
+ sql.WriteString(" WHERE ")
+ args, err = appendToSql(d.WhereParts, sql, " AND ", args)
+ if err != nil {
+ return
+ }
+ }
+
+ if len(d.OrderBys) > 0 {
+ sql.WriteString(" ORDER BY ")
+ sql.WriteString(strings.Join(d.OrderBys, ", "))
+ }
+
+ if len(d.Limit) > 0 {
+ sql.WriteString(" LIMIT ")
+ sql.WriteString(d.Limit)
+ }
+
+ if len(d.Offset) > 0 {
+ sql.WriteString(" OFFSET ")
+ sql.WriteString(d.Offset)
+ }
+
+ if len(d.Suffixes) > 0 {
+ sql.WriteString(" ")
+ args, err = appendToSql(d.Suffixes, sql, " ", args)
+ if err != nil {
+ return
+ }
+ }
+
+ sqlStr, err = d.PlaceholderFormat.ReplacePlaceholders(sql.String())
+ return
+}
+
+// Builder
+
+// UpdateBuilder builds SQL UPDATE statements.
+type UpdateBuilder builder.Builder
+
+func init() {
+ builder.Register(UpdateBuilder{}, updateData{})
+}
+
+// Format methods
+
+// PlaceholderFormat sets PlaceholderFormat (e.g. Question or Dollar) for the
+// query.
+func (b UpdateBuilder) PlaceholderFormat(f PlaceholderFormat) UpdateBuilder {
+ return builder.Set(b, "PlaceholderFormat", f).(UpdateBuilder)
+}
+
+// Runner methods
+
+// RunWith sets a Runner (like database/sql.DB) to be used with e.g. Exec.
+func (b UpdateBuilder) RunWith(runner BaseRunner) UpdateBuilder {
+ return setRunWith(b, runner).(UpdateBuilder)
+}
+
+// Exec builds and Execs the query with the Runner set by RunWith.
+func (b UpdateBuilder) Exec() (sql.Result, error) {
+ data := builder.GetStruct(b).(updateData)
+ return data.Exec()
+}
+
+func (b UpdateBuilder) Query() (*sql.Rows, error) {
+ data := builder.GetStruct(b).(updateData)
+ return data.Query()
+}
+
+func (b UpdateBuilder) QueryRow() RowScanner {
+ data := builder.GetStruct(b).(updateData)
+ return data.QueryRow()
+}
+
+func (b UpdateBuilder) Scan(dest ...interface{}) error {
+ return b.QueryRow().Scan(dest...)
+}
+
+// SQL methods
+
+// ToSql builds the query into a SQL string and bound args.
+func (b UpdateBuilder) ToSql() (string, []interface{}, error) {
+ data := builder.GetStruct(b).(updateData)
+ return data.ToSql()
+}
+
+// MustSql builds the query into a SQL string and bound args.
+// It panics if there are any errors.
+func (b UpdateBuilder) MustSql() (string, []interface{}) {
+ sql, args, err := b.ToSql()
+ if err != nil {
+ panic(err)
+ }
+ return sql, args
+}
+
+// Prefix adds an expression to the beginning of the query
+func (b UpdateBuilder) Prefix(sql string, args ...interface{}) UpdateBuilder {
+ return b.PrefixExpr(Expr(sql, args...))
+}
+
+// PrefixExpr adds an expression to the very beginning of the query
+func (b UpdateBuilder) PrefixExpr(expr Sqlizer) UpdateBuilder {
+ return builder.Append(b, "Prefixes", expr).(UpdateBuilder)
+}
+
+// Table sets the table to be updated.
+func (b UpdateBuilder) Table(table string) UpdateBuilder {
+ return builder.Set(b, "Table", table).(UpdateBuilder)
+}
+
+// Set adds SET clauses to the query.
+func (b UpdateBuilder) Set(column string, value interface{}) UpdateBuilder {
+ return builder.Append(b, "SetClauses", setClause{column: column, value: value}).(UpdateBuilder)
+}
+
+// SetMap is a convenience method which calls .Set for each key/value pair in clauses.
+func (b UpdateBuilder) SetMap(clauses map[string]interface{}) UpdateBuilder {
+ keys := make([]string, len(clauses))
+ i := 0
+ for key := range clauses {
+ keys[i] = key
+ i++
+ }
+ sort.Strings(keys)
+ for _, key := range keys {
+ val, _ := clauses[key]
+ b = b.Set(key, val)
+ }
+ return b
+}
+
+// From adds FROM clause to the query
+// FROM is valid construct in postgresql only.
+func (b UpdateBuilder) From(from string) UpdateBuilder {
+ return builder.Set(b, "From", newPart(from)).(UpdateBuilder)
+}
+
+// FromSelect sets a subquery into the FROM clause of the query.
+func (b UpdateBuilder) FromSelect(from SelectBuilder, alias string) UpdateBuilder {
+ // Prevent misnumbered parameters in nested selects (#183).
+ from = from.PlaceholderFormat(Question)
+ return builder.Set(b, "From", Alias(from, alias)).(UpdateBuilder)
+}
+
+// Where adds WHERE expressions to the query.
+//
+// See SelectBuilder.Where for more information.
+func (b UpdateBuilder) Where(pred interface{}, args ...interface{}) UpdateBuilder {
+ return builder.Append(b, "WhereParts", newWherePart(pred, args...)).(UpdateBuilder)
+}
+
+// OrderBy adds ORDER BY expressions to the query.
+func (b UpdateBuilder) OrderBy(orderBys ...string) UpdateBuilder {
+ return builder.Extend(b, "OrderBys", orderBys).(UpdateBuilder)
+}
+
+// Limit sets a LIMIT clause on the query.
+func (b UpdateBuilder) Limit(limit uint64) UpdateBuilder {
+ return builder.Set(b, "Limit", fmt.Sprintf("%d", limit)).(UpdateBuilder)
+}
+
+// Offset sets a OFFSET clause on the query.
+func (b UpdateBuilder) Offset(offset uint64) UpdateBuilder {
+ return builder.Set(b, "Offset", fmt.Sprintf("%d", offset)).(UpdateBuilder)
+}
+
+// Suffix adds an expression to the end of the query
+func (b UpdateBuilder) Suffix(sql string, args ...interface{}) UpdateBuilder {
+ return b.SuffixExpr(Expr(sql, args...))
+}
+
+// SuffixExpr adds an expression to the end of the query
+func (b UpdateBuilder) SuffixExpr(expr Sqlizer) UpdateBuilder {
+ return builder.Append(b, "Suffixes", expr).(UpdateBuilder)
+}
diff --git a/vendor/github.com/Masterminds/squirrel/update_ctx.go b/vendor/github.com/Masterminds/squirrel/update_ctx.go
new file mode 100644
index 0000000000..ad479f96f4
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/update_ctx.go
@@ -0,0 +1,69 @@
+// +build go1.8
+
+package squirrel
+
+import (
+ "context"
+ "database/sql"
+
+ "github.com/lann/builder"
+)
+
+func (d *updateData) ExecContext(ctx context.Context) (sql.Result, error) {
+ if d.RunWith == nil {
+ return nil, RunnerNotSet
+ }
+ ctxRunner, ok := d.RunWith.(ExecerContext)
+ if !ok {
+ return nil, NoContextSupport
+ }
+ return ExecContextWith(ctx, ctxRunner, d)
+}
+
+func (d *updateData) QueryContext(ctx context.Context) (*sql.Rows, error) {
+ if d.RunWith == nil {
+ return nil, RunnerNotSet
+ }
+ ctxRunner, ok := d.RunWith.(QueryerContext)
+ if !ok {
+ return nil, NoContextSupport
+ }
+ return QueryContextWith(ctx, ctxRunner, d)
+}
+
+func (d *updateData) QueryRowContext(ctx context.Context) RowScanner {
+ if d.RunWith == nil {
+ return &Row{err: RunnerNotSet}
+ }
+ queryRower, ok := d.RunWith.(QueryRowerContext)
+ if !ok {
+ if _, ok := d.RunWith.(QueryerContext); !ok {
+ return &Row{err: RunnerNotQueryRunner}
+ }
+ return &Row{err: NoContextSupport}
+ }
+ return QueryRowContextWith(ctx, queryRower, d)
+}
+
+// ExecContext builds and ExecContexts the query with the Runner set by RunWith.
+func (b UpdateBuilder) ExecContext(ctx context.Context) (sql.Result, error) {
+ data := builder.GetStruct(b).(updateData)
+ return data.ExecContext(ctx)
+}
+
+// QueryContext builds and QueryContexts the query with the Runner set by RunWith.
+func (b UpdateBuilder) QueryContext(ctx context.Context) (*sql.Rows, error) {
+ data := builder.GetStruct(b).(updateData)
+ return data.QueryContext(ctx)
+}
+
+// QueryRowContext builds and QueryRowContexts the query with the Runner set by RunWith.
+func (b UpdateBuilder) QueryRowContext(ctx context.Context) RowScanner {
+ data := builder.GetStruct(b).(updateData)
+ return data.QueryRowContext(ctx)
+}
+
+// ScanContext is a shortcut for QueryRowContext().Scan.
+func (b UpdateBuilder) ScanContext(ctx context.Context, dest ...interface{}) error {
+ return b.QueryRowContext(ctx).Scan(dest...)
+}
diff --git a/vendor/github.com/Masterminds/squirrel/where.go b/vendor/github.com/Masterminds/squirrel/where.go
new file mode 100644
index 0000000000..976b63ace4
--- /dev/null
+++ b/vendor/github.com/Masterminds/squirrel/where.go
@@ -0,0 +1,30 @@
+package squirrel
+
+import (
+ "fmt"
+)
+
+type wherePart part
+
+func newWherePart(pred interface{}, args ...interface{}) Sqlizer {
+ return &wherePart{pred: pred, args: args}
+}
+
+func (p wherePart) ToSql() (sql string, args []interface{}, err error) {
+ switch pred := p.pred.(type) {
+ case nil:
+ // no-op
+ case rawSqlizer:
+ return pred.toSqlRaw()
+ case Sqlizer:
+ return pred.ToSql()
+ case map[string]interface{}:
+ return Eq(pred).ToSql()
+ case string:
+ sql = pred
+ args = p.args
+ default:
+ err = fmt.Errorf("expected string-keyed map or string, not %T", pred)
+ }
+ return
+}
diff --git a/vendor/github.com/chai2010/gettext-go/.travis.yml b/vendor/github.com/chai2010/gettext-go/.travis.yml
new file mode 100644
index 0000000000..4eac3982bc
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/.travis.yml
@@ -0,0 +1,5 @@
+language: go
+
+go:
+ - "1.14"
+ - tip
diff --git a/vendor/github.com/chai2010/gettext-go/LICENSE b/vendor/github.com/chai2010/gettext-go/LICENSE
new file mode 100644
index 0000000000..8f39408250
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2013 ChaiShushan . 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.
diff --git a/vendor/github.com/chai2010/gettext-go/README.md b/vendor/github.com/chai2010/gettext-go/README.md
new file mode 100644
index 0000000000..d766fab4d7
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/README.md
@@ -0,0 +1,190 @@
+- *Goè¯è¨€QQ群: 102319854, 1055927514*
+- *凹è¯è¨€(凹读音“Waâ€)(The Wa Programming Language): https://github.com/wa-lang/wa*
+
+----
+
+# gettext-go: GNU gettext for Go ([Imported By Kubernetes](https://pkg.go.dev/github.com/chai2010/gettext-go@v0.1.0/gettext?tab=importedby))
+
+- PkgDoc: [http://godoc.org/github.com/chai2010/gettext-go](http://godoc.org/github.com/chai2010/gettext-go)
+- PkgDoc: [http://pkg.go.dev/github.com/chai2010/gettext-go](http://pkg.go.dev/github.com/chai2010/gettext-go)
+
+## Install
+
+1. `go get github.com/chai2010/gettext-go`
+2. `go run hello.go`
+
+The godoc.org or go.dev has more information.
+
+## Examples
+
+```Go
+package main
+
+import (
+ "fmt"
+
+ "github.com/chai2010/gettext-go"
+)
+
+func main() {
+ gettext := gettext.New("hello", "./examples/locale").SetLanguage("zh_CN")
+ fmt.Println(gettext.Gettext("Hello, world!"))
+
+ // Output: ä½ å¥½, 世界!
+}
+```
+
+```Go
+package main
+
+import (
+ "fmt"
+
+ "github.com/chai2010/gettext-go"
+)
+
+func main() {
+ gettext.SetLanguage("zh_CN")
+ gettext.BindLocale(gettext.New("hello", "locale"))
+
+ // gettext.BindLocale("hello", "locale") // from locale dir
+ // gettext.BindLocale("hello", "locale.zip") // from locale zip file
+ // gettext.BindLocale("hello", "locale.zip", zipData) // from embedded zip data
+
+ // translate source text
+ fmt.Println(gettext.Gettext("Hello, world!"))
+ // Output: ä½ å¥½, 世界!
+
+ // if no msgctxt in PO file (only msgid and msgstr),
+ // specify context as "" by
+ fmt.Println(gettext.PGettext("", "Hello, world!"))
+ // Output: ä½ å¥½, 世界!
+
+ // translate resource
+ fmt.Println(string(gettext.Getdata("poems.txt"))))
+ // Output: ...
+}
+```
+
+Go file: [hello.go](https://github.com/chai2010/gettext-go/blob/master/examples/hello.go); PO file: [hello.po](https://github.com/chai2010/gettext-go/blob/master/examples/locale/default/LC_MESSAGES/hello.po);
+
+----
+
+## API Changes (v0.1.0 vs v1.0.0)
+
+### Renamed package path
+
+| v0.1.0 (old) | v1.0.0 (new) |
+| ----------------------------------------------- | --------------------------------------- |
+| `github.com/chai2010/gettext-go/gettext` | `github.com/chai2010/gettext-go` |
+| `github.com/chai2010/gettext-go/gettext/po` | `github.com/chai2010/gettext-go/po` |
+| `github.com/chai2010/gettext-go/gettext/mo` | `github.com/chai2010/gettext-go/mo` |
+| `github.com/chai2010/gettext-go/gettext/plural` | `github.com/chai2010/gettext-go/plural` |
+
+### Renamed functions
+
+| v0.1.0 (old) | v1.0.0 (new) |
+| ---------------------------------- | --------------------------- |
+| `gettext-go/gettext.*` | `gettext-go.*` |
+| `gettext-go/gettext.DefaultLocal` | `gettext-go.DefaultLanguage`|
+| `gettext-go/gettext.BindTextdomain`| `gettext-go.BindLocale` |
+| `gettext-go/gettext.Textdomain` | `gettext-go.SetDomain` |
+| `gettext-go/gettext.SetLocale` | `gettext-go.SetLanguage` |
+| `gettext-go/gettext/po.Load` | `gettext-go/po.LoadFile` |
+| `gettext-go/gettext/po.LoadData` | `gettext-go/po.Load` |
+| `gettext-go/gettext/mo.Load` | `gettext-go/mo.LoadFile` |
+| `gettext-go/gettext/mo.LoadData` | `gettext-go/mo.Load` |
+
+### Use empty string as the default context for `gettext.Gettext`
+
+```go
+package main
+
+// v0.1.0
+// if the **context** missing, use `callerName(2)` as the context:
+
+// v1.0.0
+// if the **context** missing, use empty string as the context:
+
+func main() {
+ gettext.Gettext("hello")
+ // v0.1.0 => gettext.PGettext("main.main", "hello")
+ // v1.0.0 => gettext.PGettext("", "hello")
+
+ gettext.DGettext("domain", "hello")
+ // v0.1.0 => gettext.DPGettext("domain", "main.main", "hello")
+ // v1.0.0 => gettext.DPGettext("domain", "", "hello")
+
+ gettext.NGettext("domain", "hello", "hello2", n)
+ // v0.1.0 => gettext.PNGettext("domain", "main.main", "hello", "hello2", n)
+ // v1.0.0 => gettext.PNGettext("domain", "", "hello", "hello2", n)
+
+ gettext.DNGettext("domain", "hello", "hello2", n)
+ // v0.1.0 => gettext.DPNGettext("domain", "main.main", "hello", "hello2", n)
+ // v1.0.0 => gettext.DPNGettext("domain", "", "hello", "hello2", n)
+}
+```
+
+### `BindLocale` support `FileSystem` interface
+
+```go
+// Use FileSystem:
+// BindLocale(New("poedit", "name", OS("path/to/dir"))) // bind "poedit" domain
+// BindLocale(New("poedit", "name", OS("path/to.zip"))) // bind "poedit" domain
+```
+
+## New API in v1.0.0
+
+`Gettexter` interface:
+
+```go
+type Gettexter interface {
+ FileSystem() FileSystem
+
+ GetDomain() string
+ SetDomain(domain string) Gettexter
+
+ GetLanguage() string
+ SetLanguage(lang string) Gettexter
+
+ Gettext(msgid string) string
+ PGettext(msgctxt, msgid string) string
+
+ NGettext(msgid, msgidPlural string, n int) string
+ PNGettext(msgctxt, msgid, msgidPlural string, n int) string
+
+ DGettext(domain, msgid string) string
+ DPGettext(domain, msgctxt, msgid string) string
+ DNGettext(domain, msgid, msgidPlural string, n int) string
+ DPNGettext(domain, msgctxt, msgid, msgidPlural string, n int) string
+
+ Getdata(name string) []byte
+ DGetdata(domain, name string) []byte
+}
+
+func New(domain, path string, data ...interface{}) Gettexter
+```
+
+`FileSystem` interface:
+
+```go
+type FileSystem interface {
+ LocaleList() []string
+ LoadMessagesFile(domain, lang, ext string) ([]byte, error)
+ LoadResourceFile(domain, lang, name string) ([]byte, error)
+ String() string
+}
+
+func NewFS(name string, x interface{}) FileSystem
+func OS(root string) FileSystem
+func ZipFS(r *zip.Reader, name string) FileSystem
+func NilFS(name string) FileSystem
+```
+
+----
+
+## BUGS
+
+Please report bugs to .
+
+Thanks!
diff --git a/vendor/github.com/chai2010/gettext-go/doc.go b/vendor/github.com/chai2010/gettext-go/doc.go
new file mode 100644
index 0000000000..50dfea3305
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/doc.go
@@ -0,0 +1,67 @@
+// Copyright 2013 . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package gettext implements a basic GNU's gettext library.
+
+Example:
+ import (
+ "github.com/chai2010/gettext-go"
+ )
+
+ func main() {
+ gettext.SetLanguage("zh_CN")
+
+ // gettext.BindLocale(gettext.New("hello", "locale")) // from locale dir
+ // gettext.BindLocale(gettext.New("hello", "locale.zip")) // from locale zip file
+ // gettext.BindLocale(gettext.New("hello", "locale.zip", zipData)) // from embedded zip data
+
+ gettext.BindLocale(gettext.New("hello", "locale"))
+
+ // translate source text
+ fmt.Println(gettext.Gettext("Hello, world!"))
+ // Output: ä½ å¥½, 世界!
+
+ // translate resource
+ fmt.Println(string(gettext.Getdata("poems.txt")))
+ // Output: ...
+ }
+
+Translate directory struct("./examples/locale.zip"):
+
+ Root: "path" or "file.zip/zipBaseName"
+ +-default # locale: $(LC_MESSAGES) or $(LANG) or "default"
+ | +-LC_MESSAGES # just for `gettext.Gettext`
+ | | +-hello.mo # $(Root)/$(lang)/LC_MESSAGES/$(domain).mo
+ | | +-hello.po # $(Root)/$(lang)/LC_MESSAGES/$(domain).po
+ | | \-hello.json # $(Root)/$(lang)/LC_MESSAGES/$(domain).json
+ | |
+ | \-LC_RESOURCE # just for `gettext.Getdata`
+ | +-hello # domain map a dir in resource translate
+ | +-favicon.ico # $(Root)/$(lang)/LC_RESOURCE/$(domain)/$(filename)
+ | \-poems.txt
+ |
+ \-zh_CN # simple chinese translate
+ +-LC_MESSAGES
+ | +-hello.po # try "$(domain).po" first
+ | +-hello.mo # try "$(domain).mo" second
+ | \-hello.json # try "$(domain).json" third
+ |
+ \-LC_RESOURCE
+ +-hello
+ +-favicon.ico # $(lang)/$(domain)/favicon.ico
+ \-poems.txt # $(lang)/$(domain)/poems.txt
+
+See:
+ http://en.wikipedia.org/wiki/Gettext
+ http://www.gnu.org/software/gettext/manual/html_node
+ http://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html
+ http://www.gnu.org/software/gettext/manual/html_node/PO-Files.html
+ http://www.gnu.org/software/gettext/manual/html_node/MO-Files.html
+ http://www.poedit.net/
+
+Please report bugs to .
+Thanks!
+*/
+package gettext
diff --git a/vendor/github.com/chai2010/gettext-go/fs.go b/vendor/github.com/chai2010/gettext-go/fs.go
new file mode 100644
index 0000000000..4e66fae7c6
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/fs.go
@@ -0,0 +1,84 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gettext
+
+import (
+ "archive/zip"
+ "bytes"
+ "fmt"
+)
+
+type FileSystem interface {
+ LocaleList() []string
+ LoadMessagesFile(domain, lang, ext string) ([]byte, error)
+ LoadResourceFile(domain, lang, name string) ([]byte, error)
+ String() string
+}
+
+func NewFS(name string, x interface{}) FileSystem {
+ if x == nil {
+ if name != "" {
+ return OS(name)
+ }
+ return NilFS(name)
+ }
+
+ switch x := x.(type) {
+ case []byte:
+ if len(x) == 0 {
+ return OS(name)
+ }
+ if r, err := zip.NewReader(bytes.NewReader(x), int64(len(x))); err == nil {
+ return ZipFS(r, name)
+ }
+ if fs, err := newJson(x, name); err == nil {
+ return fs
+ }
+ case string:
+ if len(x) == 0 {
+ return OS(name)
+ }
+ if r, err := zip.NewReader(bytes.NewReader([]byte(x)), int64(len(x))); err == nil {
+ return ZipFS(r, name)
+ }
+ if fs, err := newJson([]byte(x), name); err == nil {
+ return fs
+ }
+ case FileSystem:
+ return x
+ }
+
+ return NilFS(name)
+}
+
+func OS(root string) FileSystem {
+ return newOsFS(root)
+}
+
+func ZipFS(r *zip.Reader, name string) FileSystem {
+ return newZipFS(r, name)
+}
+
+func NilFS(name string) FileSystem {
+ return &nilFS{name}
+}
+
+type nilFS struct {
+ name string
+}
+
+func (p *nilFS) LocaleList() []string {
+ return nil
+}
+
+func (p *nilFS) LoadMessagesFile(domain, lang, ext string) ([]byte, error) {
+ return nil, fmt.Errorf("not found")
+}
+func (p *nilFS) LoadResourceFile(domain, lang, name string) ([]byte, error) {
+ return nil, fmt.Errorf("not found")
+}
+func (p *nilFS) String() string {
+ return "gettext.nilfs(" + p.name + ")"
+}
diff --git a/vendor/github.com/chai2010/gettext-go/fs_json.go b/vendor/github.com/chai2010/gettext-go/fs_json.go
new file mode 100644
index 0000000000..c7138c9954
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/fs_json.go
@@ -0,0 +1,66 @@
+// Copyright 2020 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gettext
+
+import (
+ "encoding/json"
+ "fmt"
+ "sort"
+)
+
+type jsonFS struct {
+ name string
+ x map[string]struct {
+ LC_MESSAGES map[string][]struct {
+ MsgContext string `json:"msgctxt"` // msgctxt context
+ MsgId string `json:"msgid"` // msgid untranslated-string
+ MsgIdPlural string `json:"msgid_plural"` // msgid_plural untranslated-string-plural
+ MsgStr []string `json:"msgstr"` // msgstr translated-string
+ }
+ LC_RESOURCE map[string]map[string]string
+ }
+}
+
+func isJsonData() bool {
+ return false
+}
+
+func newJson(jsonData []byte, name string) (*jsonFS, error) {
+ p := &jsonFS{name: name}
+ if err := json.Unmarshal(jsonData, &p.x); err != nil {
+ return nil, err
+ }
+
+ return p, nil
+}
+
+func (p *jsonFS) LocaleList() []string {
+ var ss []string
+ for lang := range p.x {
+ ss = append(ss, lang)
+ }
+ sort.Strings(ss)
+ return ss
+}
+
+func (p *jsonFS) LoadMessagesFile(domain, lang, ext string) ([]byte, error) {
+ if v, ok := p.x[lang]; ok {
+ if v, ok := v.LC_MESSAGES[domain+ext]; ok {
+ return json.Marshal(v)
+ }
+ }
+ return nil, fmt.Errorf("not found")
+}
+func (p *jsonFS) LoadResourceFile(domain, lang, name string) ([]byte, error) {
+ if v, ok := p.x[lang]; ok {
+ if v, ok := v.LC_RESOURCE[domain]; ok {
+ return []byte(v[name]), nil
+ }
+ }
+ return nil, fmt.Errorf("not found")
+}
+func (p *jsonFS) String() string {
+ return "gettext.nilfs(" + p.name + ")"
+}
diff --git a/vendor/github.com/chai2010/gettext-go/fs_os.go b/vendor/github.com/chai2010/gettext-go/fs_os.go
new file mode 100644
index 0000000000..80d4f51bac
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/fs_os.go
@@ -0,0 +1,91 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gettext
+
+import (
+ "archive/zip"
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "sort"
+ "strings"
+)
+
+type osFS struct {
+ root string
+}
+
+func newOsFS(root string) FileSystem {
+ // locale zip file
+ if fi, err := os.Stat(root); err == nil && !fi.IsDir() {
+ if strings.HasSuffix(strings.ToLower(root), ".zip") {
+ if x, err := ioutil.ReadFile(root); err == nil {
+ if r, err := zip.NewReader(bytes.NewReader(x), int64(len(x))); err == nil {
+ return ZipFS(r, root)
+ }
+ }
+ }
+ if strings.HasSuffix(strings.ToLower(root), ".json") {
+ if x, err := ioutil.ReadFile(root); err == nil {
+ if fs, err := newJson(x, root); err == nil {
+ return fs
+ }
+ }
+ }
+ }
+
+ // locale dir
+ return &osFS{root: root}
+}
+
+func (p *osFS) LocaleList() []string {
+ list, err := ioutil.ReadDir(p.root)
+ if err != nil {
+ return nil
+ }
+ ssMap := make(map[string]bool)
+ for _, dir := range list {
+ if dir.IsDir() {
+ ssMap[dir.Name()] = true
+ }
+ }
+ var locales = make([]string, 0, len(ssMap))
+ for s := range ssMap {
+ locales = append(locales, s)
+ }
+ sort.Strings(locales)
+ return locales
+}
+
+func (p *osFS) LoadMessagesFile(domain, locale, ext string) ([]byte, error) {
+ trName := p.makeMessagesFileName(domain, locale, ext)
+ rcData, err := ioutil.ReadFile(trName)
+ if err != nil {
+ return nil, err
+ }
+ return rcData, nil
+}
+
+func (p *osFS) LoadResourceFile(domain, locale, name string) ([]byte, error) {
+ rcName := p.makeResourceFileName(domain, locale, name)
+ rcData, err := ioutil.ReadFile(rcName)
+ if err != nil {
+ return nil, err
+ }
+ return rcData, nil
+}
+
+func (p *osFS) String() string {
+ return "gettext.localfs(" + p.root + ")"
+}
+
+func (p *osFS) makeMessagesFileName(domain, lang, ext string) string {
+ return fmt.Sprintf("%s/%s/LC_MESSAGES/%s%s", p.root, lang, domain, ext)
+}
+
+func (p *osFS) makeResourceFileName(domain, lang, name string) string {
+ return fmt.Sprintf("%s/%s/LC_RESOURCE/%s/%s", p.root, lang, domain, name)
+}
diff --git a/vendor/github.com/chai2010/gettext-go/fs_zip.go b/vendor/github.com/chai2010/gettext-go/fs_zip.go
new file mode 100644
index 0000000000..61eb8359da
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/fs_zip.go
@@ -0,0 +1,142 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gettext
+
+import (
+ "archive/zip"
+ "fmt"
+ "io/ioutil"
+ "sort"
+ "strings"
+)
+
+type zipFS struct {
+ root string
+ name string
+ r *zip.Reader
+}
+
+func newZipFS(r *zip.Reader, name string) *zipFS {
+ fs := &zipFS{r: r, name: name}
+ fs.root = fs.zipRoot()
+ return fs
+}
+
+func (p *zipFS) zipName() string {
+ name := p.name
+ if x := strings.LastIndexAny(name, `\/`); x != -1 {
+ name = name[x+1:]
+ }
+ name = strings.TrimSuffix(name, ".zip")
+ return name
+}
+
+func (p *zipFS) zipRoot() string {
+ var somepath string
+ for _, f := range p.r.File {
+ if x := strings.Index(f.Name, "LC_MESSAGES"); x != -1 {
+ somepath = f.Name
+ }
+ if x := strings.Index(f.Name, "LC_RESOURCE"); x != -1 {
+ somepath = f.Name
+ }
+ }
+ if somepath == "" {
+ return p.zipName()
+ }
+
+ ss := strings.Split(somepath, "/")
+ for i, s := range ss {
+ // $(root)/$(lang)/LC_MESSAGES
+ // $(root)/$(lang)/LC_RESOURCE
+ if (s == "LC_MESSAGES" || s == "LC_RESOURCE") && i >= 2 {
+ return strings.Join(ss[:i-1], "/")
+ }
+ }
+
+ return p.zipName()
+}
+
+func (p *zipFS) LocaleList() []string {
+ var locals []string
+ for s := range p.lsZip(p.r) {
+ locals = append(locals, s)
+ }
+ sort.Strings(locals)
+ return locals
+}
+
+func (p *zipFS) LoadMessagesFile(domain, lang, ext string) ([]byte, error) {
+ trName := p.makeMessagesFileName(domain, lang, ext)
+ for _, f := range p.r.File {
+ if f.Name != trName {
+ continue
+ }
+ rc, err := f.Open()
+ if err != nil {
+ return nil, err
+ }
+ rcData, err := ioutil.ReadAll(rc)
+ rc.Close()
+ return rcData, err
+ }
+ return nil, fmt.Errorf("not found")
+}
+
+func (p *zipFS) LoadResourceFile(domain, lang, name string) ([]byte, error) {
+ rcName := p.makeResourceFileName(domain, lang, name)
+ for _, f := range p.r.File {
+ if f.Name != rcName {
+ continue
+ }
+ rc, err := f.Open()
+ if err != nil {
+ return nil, err
+ }
+ rcData, err := ioutil.ReadAll(rc)
+ rc.Close()
+ return rcData, err
+ }
+ return nil, fmt.Errorf("not found")
+}
+
+func (p *zipFS) String() string {
+ return "gettext.zipfs(" + p.name + ")"
+}
+
+func (p *zipFS) makeMessagesFileName(domain, lang, ext string) string {
+ return fmt.Sprintf("%s/%s/LC_MESSAGES/%s%s", p.root, lang, domain, ext)
+}
+
+func (p *zipFS) makeResourceFileName(domain, lang, name string) string {
+ return fmt.Sprintf("%s/%s/LC_RESOURCE/%s/%s", p.root, lang, domain, name)
+}
+
+func (p *zipFS) lsZip(r *zip.Reader) map[string]bool {
+ ssMap := make(map[string]bool)
+ for _, f := range r.File {
+ if x := strings.Index(f.Name, "LC_MESSAGES"); x != -1 {
+ s := strings.TrimRight(f.Name[:x], `\/`)
+ if x = strings.LastIndexAny(s, `\/`); x != -1 {
+ s = s[x+1:]
+ }
+ if s != "" {
+ ssMap[s] = true
+ }
+ continue
+ }
+ if x := strings.Index(f.Name, "LC_RESOURCE"); x != -1 {
+ s := strings.TrimRight(f.Name[:x], `\/`)
+ if x = strings.LastIndexAny(s, `\/`); x != -1 {
+ s = s[x+1:]
+ }
+ if s != "" {
+ ssMap[s] = true
+ }
+ continue
+ }
+ }
+ return ssMap
+}
diff --git a/vendor/github.com/chai2010/gettext-go/gettext.go b/vendor/github.com/chai2010/gettext-go/gettext.go
new file mode 100644
index 0000000000..7747188ab4
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/gettext.go
@@ -0,0 +1,219 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gettext
+
+var (
+ DefaultLanguage string = getDefaultLanguage() // use $(LC_MESSAGES) or $(LANG) or "default"
+)
+
+type Gettexter interface {
+ FileSystem() FileSystem
+
+ GetDomain() string
+ SetDomain(domain string) Gettexter
+
+ GetLanguage() string
+ SetLanguage(lang string) Gettexter
+
+ Gettext(msgid string) string
+ PGettext(msgctxt, msgid string) string
+
+ NGettext(msgid, msgidPlural string, n int) string
+ PNGettext(msgctxt, msgid, msgidPlural string, n int) string
+
+ DGettext(domain, msgid string) string
+ DPGettext(domain, msgctxt, msgid string) string
+ DNGettext(domain, msgid, msgidPlural string, n int) string
+ DPNGettext(domain, msgctxt, msgid, msgidPlural string, n int) string
+
+ Getdata(name string) []byte
+ DGetdata(domain, name string) []byte
+}
+
+// New create Interface use default language.
+func New(domain, path string, data ...interface{}) Gettexter {
+ return newLocale(domain, path, data...)
+}
+
+var defaultGettexter struct {
+ lang string
+ domain string
+ Gettexter
+}
+
+func init() {
+ defaultGettexter.lang = getDefaultLanguage()
+ defaultGettexter.domain = "default"
+ defaultGettexter.Gettexter = newLocale("", "")
+}
+
+// BindLocale sets and queries program's domains.
+//
+// Examples:
+// BindLocale(New("poedit", "locale")) // bind "poedit" domain
+//
+// Use zip file:
+// BindLocale(New("poedit", "locale.zip")) // bind "poedit" domain
+// BindLocale(New("poedit", "locale.zip", zipData)) // bind "poedit" domain
+//
+// Use FileSystem:
+// BindLocale(New("poedit", "name", OS("path/to/dir"))) // bind "poedit" domain
+// BindLocale(New("poedit", "name", OS("path/to.zip"))) // bind "poedit" domain
+//
+func BindLocale(g Gettexter) {
+ if g != nil {
+ defaultGettexter.Gettexter = g
+ defaultGettexter.SetLanguage(defaultGettexter.lang)
+ } else {
+ defaultGettexter.Gettexter = newLocale("", "")
+ defaultGettexter.SetLanguage(defaultGettexter.lang)
+ }
+}
+
+// SetLanguage sets and queries the program's current lang.
+//
+// If the lang is not empty string, set the new locale.
+//
+// If the lang is empty string, don't change anything.
+//
+// Returns is the current locale.
+//
+// Examples:
+// SetLanguage("") // get locale: return DefaultLocale
+// SetLanguage("zh_CN") // set locale: return zh_CN
+// SetLanguage("") // get locale: return zh_CN
+func SetLanguage(lang string) string {
+ defaultGettexter.SetLanguage(lang)
+ return defaultGettexter.GetLanguage()
+}
+
+// SetDomain sets and retrieves the current message domain.
+//
+// If the domain is not empty string, set the new domains.
+//
+// If the domain is empty string, don't change anything.
+//
+// Returns is the all used domains.
+//
+// Examples:
+// SetDomain("poedit") // set domain: poedit
+// SetDomain("") // get domain: return poedit
+func SetDomain(domain string) string {
+ defaultGettexter.SetDomain(domain)
+ return defaultGettexter.GetDomain()
+}
+
+// Gettext attempt to translate a text string into the user's native language,
+// by looking up the translation in a message catalog.
+//
+// It use the caller's function name as the msgctxt.
+//
+// Examples:
+// func Foo() {
+// msg := gettext.Gettext("Hello") // msgctxt is ""
+// }
+func Gettext(msgid string) string {
+ return defaultGettexter.Gettext(msgid)
+}
+
+// Getdata attempt to translate a resource file into the user's native language,
+// by looking up the translation in a message catalog.
+//
+// Examples:
+// func Foo() {
+// Textdomain("hello")
+// BindLocale("hello", "locale.zip", nilOrZipData)
+// poems := gettext.Getdata("poems.txt")
+// }
+func Getdata(name string) []byte {
+ return defaultGettexter.Getdata(name)
+}
+
+// NGettext attempt to translate a text string into the user's native language,
+// by looking up the appropriate plural form of the translation in a message
+// catalog.
+//
+// It use the caller's function name as the msgctxt.
+//
+// Examples:
+// func Foo() {
+// msg := gettext.NGettext("%d people", "%d peoples", 2)
+// }
+func NGettext(msgid, msgidPlural string, n int) string {
+ return defaultGettexter.NGettext(msgid, msgidPlural, n)
+}
+
+// PGettext attempt to translate a text string into the user's native language,
+// by looking up the translation in a message catalog.
+//
+// Examples:
+// func Foo() {
+// msg := gettext.PGettext("gettext-go.example", "Hello") // msgctxt is "gettext-go.example"
+// }
+func PGettext(msgctxt, msgid string) string {
+ return defaultGettexter.PGettext(msgctxt, msgid)
+}
+
+// PNGettext attempt to translate a text string into the user's native language,
+// by looking up the appropriate plural form of the translation in a message
+// catalog.
+//
+// Examples:
+// func Foo() {
+// msg := gettext.PNGettext("gettext-go.example", "%d people", "%d peoples", 2)
+// }
+func PNGettext(msgctxt, msgid, msgidPlural string, n int) string {
+ return defaultGettexter.PNGettext(msgctxt, msgid, msgidPlural, n)
+}
+
+// DGettext like Gettext(), but looking up the message in the specified domain.
+//
+// Examples:
+// func Foo() {
+// msg := gettext.DGettext("poedit", "Hello")
+// }
+func DGettext(domain, msgid string) string {
+ return defaultGettexter.DGettext(domain, msgid)
+}
+
+// DNGettext like NGettext(), but looking up the message in the specified domain.
+//
+// Examples:
+// func Foo() {
+// msg := gettext.PNGettext("poedit", "gettext-go.example", "%d people", "%d peoples", 2)
+// }
+func DNGettext(domain, msgid, msgidPlural string, n int) string {
+ return defaultGettexter.DNGettext(domain, msgid, msgidPlural, n)
+}
+
+// DPGettext like PGettext(), but looking up the message in the specified domain.
+//
+// Examples:
+// func Foo() {
+// msg := gettext.DPGettext("poedit", "gettext-go.example", "Hello")
+// }
+func DPGettext(domain, msgctxt, msgid string) string {
+ return defaultGettexter.DPGettext(domain, msgctxt, msgid)
+}
+
+// DPNGettext like PNGettext(), but looking up the message in the specified domain.
+//
+// Examples:
+// func Foo() {
+// msg := gettext.DPNGettext("poedit", "gettext-go.example", "%d people", "%d peoples", 2)
+// }
+func DPNGettext(domain, msgctxt, msgid, msgidPlural string, n int) string {
+ return defaultGettexter.DPNGettext(domain, msgctxt, msgid, msgidPlural, n)
+}
+
+// DGetdata like Getdata(), but looking up the resource in the specified domain.
+//
+// Examples:
+// func Foo() {
+// msg := gettext.DGetdata("hello", "poems.txt")
+// }
+func DGetdata(domain, name string) []byte {
+ return defaultGettexter.DGetdata(domain, name)
+}
diff --git a/vendor/github.com/chai2010/gettext-go/locale.go b/vendor/github.com/chai2010/gettext-go/locale.go
new file mode 100644
index 0000000000..e7a2d4b37b
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/locale.go
@@ -0,0 +1,205 @@
+// Copyright 2020 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gettext
+
+import (
+ "fmt"
+ "sync"
+)
+
+type _Locale struct {
+ mutex sync.Mutex
+ fs FileSystem
+ lang string
+ domain string
+ trMap map[string]*translator
+ trCurrent *translator
+}
+
+var _ Gettexter = (*_Locale)(nil)
+
+func newLocale(domain, path string, data ...interface{}) *_Locale {
+ if domain == "" {
+ domain = "default"
+ }
+ p := &_Locale{
+ lang: DefaultLanguage,
+ domain: domain,
+ }
+ if len(data) > 0 {
+ p.fs = NewFS(path, data[0])
+ } else {
+ p.fs = NewFS(path, nil)
+ }
+
+ p.syncTrMap()
+ return p
+}
+
+func (p *_Locale) makeTrMapKey(domain, _Locale string) string {
+ return domain + "_$$$_" + _Locale
+}
+
+func (p *_Locale) FileSystem() FileSystem {
+ return p.fs
+}
+
+func (p *_Locale) GetLanguage() string {
+ p.mutex.Lock()
+ defer p.mutex.Unlock()
+
+ return p.lang
+}
+func (p *_Locale) SetLanguage(lang string) Gettexter {
+ p.mutex.Lock()
+ defer p.mutex.Unlock()
+
+ if lang == "" {
+ lang = DefaultLanguage
+ }
+ if lang == p.lang {
+ return p
+ }
+
+ p.lang = lang
+ p.syncTrMap()
+ return p
+}
+
+func (p *_Locale) GetDomain() string {
+ p.mutex.Lock()
+ defer p.mutex.Unlock()
+ return p.domain
+}
+
+func (p *_Locale) SetDomain(domain string) Gettexter {
+ p.mutex.Lock()
+ defer p.mutex.Unlock()
+
+ if domain == "" || domain == p.domain {
+ return p
+ }
+
+ p.domain = domain
+ p.syncTrMap()
+ return p
+}
+
+func (p *_Locale) syncTrMap() {
+ p.trMap = make(map[string]*translator)
+ trMapKey := p.makeTrMapKey(p.domain, p.lang)
+
+ if tr, ok := p.trMap[trMapKey]; ok {
+ p.trCurrent = tr
+ return
+ }
+
+ // try load po file
+ if data, err := p.fs.LoadMessagesFile(p.domain, p.lang, ".po"); err == nil {
+ if tr, err := newPoTranslator(fmt.Sprintf("%s_%s.po", p.domain, p.lang), data); err == nil {
+ p.trMap[trMapKey] = tr
+ p.trCurrent = tr
+ return
+ }
+ }
+
+ // try load mo file
+ if data, err := p.fs.LoadMessagesFile(p.domain, p.lang, ".mo"); err == nil {
+ if tr, err := newMoTranslator(fmt.Sprintf("%s_%s.mo", p.domain, p.lang), data); err == nil {
+ p.trMap[trMapKey] = tr
+ p.trCurrent = tr
+ return
+ }
+ }
+
+ // try load json file
+ if data, err := p.fs.LoadMessagesFile(p.domain, p.lang, ".json"); err == nil {
+ if tr, err := newJsonTranslator(p.lang, fmt.Sprintf("%s_%s.json", p.domain, p.lang), data); err == nil {
+ p.trMap[trMapKey] = tr
+ p.trCurrent = tr
+ return
+ }
+ }
+
+ // no po/mo file
+ p.trMap[trMapKey] = nilTranslator
+ p.trCurrent = nilTranslator
+ return
+}
+
+func (p *_Locale) Gettext(msgid string) string {
+ p.mutex.Lock()
+ defer p.mutex.Unlock()
+ return p.trCurrent.PGettext("", msgid)
+}
+
+func (p *_Locale) PGettext(msgctxt, msgid string) string {
+ p.mutex.Lock()
+ defer p.mutex.Unlock()
+ return p.trCurrent.PGettext(msgctxt, msgid)
+}
+
+func (p *_Locale) NGettext(msgid, msgidPlural string, n int) string {
+ p.mutex.Lock()
+ defer p.mutex.Unlock()
+ return p.trCurrent.PNGettext("", msgid, msgidPlural, n)
+}
+
+func (p *_Locale) PNGettext(msgctxt, msgid, msgidPlural string, n int) string {
+ p.mutex.Lock()
+ defer p.mutex.Unlock()
+ return p.trCurrent.PNGettext(msgctxt, msgid, msgidPlural, n)
+}
+
+func (p *_Locale) DGettext(domain, msgid string) string {
+ p.mutex.Lock()
+ defer p.mutex.Unlock()
+ return p.gettext(domain, "", msgid, "", 0)
+}
+
+func (p *_Locale) DNGettext(domain, msgid, msgidPlural string, n int) string {
+ p.mutex.Lock()
+ defer p.mutex.Unlock()
+ return p.gettext(domain, "", msgid, msgidPlural, n)
+}
+
+func (p *_Locale) DPGettext(domain, msgctxt, msgid string) string {
+ p.mutex.Lock()
+ defer p.mutex.Unlock()
+ return p.gettext(domain, msgctxt, msgid, "", 0)
+}
+
+func (p *_Locale) DPNGettext(domain, msgctxt, msgid, msgidPlural string, n int) string {
+ p.mutex.Lock()
+ defer p.mutex.Unlock()
+ return p.gettext(domain, msgctxt, msgid, msgidPlural, n)
+}
+
+func (p *_Locale) Getdata(name string) []byte {
+ return p.getdata(p.domain, name)
+}
+
+func (p *_Locale) DGetdata(domain, name string) []byte {
+ return p.getdata(domain, name)
+}
+
+func (p *_Locale) gettext(domain, msgctxt, msgid, msgidPlural string, n int) string {
+ if f, ok := p.trMap[p.makeTrMapKey(domain, p.lang)]; ok {
+ return f.PNGettext(msgctxt, msgid, msgidPlural, n)
+ }
+ return msgid
+}
+
+func (p *_Locale) getdata(domain, name string) []byte {
+ if data, err := p.fs.LoadResourceFile(domain, p.lang, name); err == nil {
+ return data
+ }
+ if p.lang != "default" {
+ if data, err := p.fs.LoadResourceFile(domain, "default", name); err == nil {
+ return data
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/chai2010/gettext-go/mo/doc.go b/vendor/github.com/chai2010/gettext-go/mo/doc.go
new file mode 100644
index 0000000000..5fefc18930
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/mo/doc.go
@@ -0,0 +1,74 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package mo provides support for reading and writing GNU MO file.
+
+Examples:
+ import (
+ "github.com/chai2010/gettext-go/mo"
+ )
+
+ func main() {
+ moFile, err := mo.LoadFile("test.mo")
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("%v", moFile)
+ }
+
+GNU MO file struct:
+
+ byte
+ +------------------------------------------+
+ 0 | magic number = 0x950412de |
+ | |
+ 4 | file format revision = 0 |
+ | |
+ 8 | number of strings | == N
+ | |
+ 12 | offset of table with original strings | == O
+ | |
+ 16 | offset of table with translation strings | == T
+ | |
+ 20 | size of hashing table | == S
+ | |
+ 24 | offset of hashing table | == H
+ | |
+ . .
+ . (possibly more entries later) .
+ . .
+ | |
+ O | length & offset 0th string ----------------.
+ O + 8 | length & offset 1st string ------------------.
+ ... ... | |
+ O + ((N-1)*8)| length & offset (N-1)th string | | |
+ | | | |
+ T | length & offset 0th translation ---------------.
+ T + 8 | length & offset 1st translation -----------------.
+ ... ... | | | |
+ T + ((N-1)*8)| length & offset (N-1)th translation | | | | |
+ | | | | | |
+ H | start hash table | | | | |
+ ... ... | | | |
+ H + S * 4 | end hash table | | | | |
+ | | | | | |
+ | NUL terminated 0th string <----------------' | | |
+ | | | | |
+ | NUL terminated 1st string <------------------' | |
+ | | | |
+ ... ... | |
+ | | | |
+ | NUL terminated 0th translation <---------------' |
+ | | |
+ | NUL terminated 1st translation <-----------------'
+ | |
+ ... ...
+ | |
+ +------------------------------------------+
+
+The GNU MO file specification is at
+http://www.gnu.org/software/gettext/manual/html_node/MO-Files.html.
+*/
+package mo
diff --git a/vendor/github.com/chai2010/gettext-go/mo/encoder.go b/vendor/github.com/chai2010/gettext-go/mo/encoder.go
new file mode 100644
index 0000000000..f953fd3cb8
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/mo/encoder.go
@@ -0,0 +1,105 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mo
+
+import (
+ "bytes"
+ "encoding/binary"
+ "sort"
+ "strings"
+)
+
+type moHeader struct {
+ MagicNumber uint32
+ MajorVersion uint16
+ MinorVersion uint16
+ MsgIdCount uint32
+ MsgIdOffset uint32
+ MsgStrOffset uint32
+ HashSize uint32
+ HashOffset uint32
+}
+
+type moStrPos struct {
+ Size uint32 // must keep fields order
+ Addr uint32
+}
+
+func encodeFile(f *File) []byte {
+ hdr := &moHeader{
+ MagicNumber: MoMagicLittleEndian,
+ }
+ data := encodeData(hdr, f)
+ data = append(encodeHeader(hdr), data...)
+ return data
+}
+
+// encode data and init moHeader
+func encodeData(hdr *moHeader, f *File) []byte {
+ msgList := []Message{f.MimeHeader.toMessage()}
+ for _, v := range f.Messages {
+ if len(v.MsgId) == 0 {
+ continue
+ }
+ if len(v.MsgStr) == 0 && len(v.MsgStrPlural) == 0 {
+ continue
+ }
+ msgList = append(msgList, v)
+ }
+ sort.Slice(msgList, func(i, j int) bool {
+ return msgList[i].less(&msgList[j])
+ })
+
+ var buf bytes.Buffer
+ var msgIdPosList = make([]moStrPos, len(msgList))
+ var msgStrPosList = make([]moStrPos, len(msgList))
+ for i, v := range msgList {
+ // write msgid
+ msgId := encodeMsgId(v)
+ msgIdPosList[i].Addr = uint32(buf.Len() + MoHeaderSize)
+ msgIdPosList[i].Size = uint32(len(msgId))
+ buf.WriteString(msgId)
+ // write msgstr
+ msgStr := encodeMsgStr(v)
+ msgStrPosList[i].Addr = uint32(buf.Len() + MoHeaderSize)
+ msgStrPosList[i].Size = uint32(len(msgStr))
+ buf.WriteString(msgStr)
+ }
+
+ hdr.MsgIdOffset = uint32(buf.Len() + MoHeaderSize)
+ binary.Write(&buf, binary.LittleEndian, msgIdPosList)
+ hdr.MsgStrOffset = uint32(buf.Len() + MoHeaderSize)
+ binary.Write(&buf, binary.LittleEndian, msgStrPosList)
+
+ hdr.MsgIdCount = uint32(len(msgList))
+ return buf.Bytes()
+}
+
+// must called after encodeData
+func encodeHeader(hdr *moHeader) []byte {
+ var buf bytes.Buffer
+ binary.Write(&buf, binary.LittleEndian, hdr)
+ return buf.Bytes()
+}
+
+func encodeMsgId(v Message) string {
+ if v.MsgContext != "" && v.MsgIdPlural != "" {
+ return v.MsgContext + EotSeparator + v.MsgId + NulSeparator + v.MsgIdPlural
+ }
+ if v.MsgContext != "" && v.MsgIdPlural == "" {
+ return v.MsgContext + EotSeparator + v.MsgId
+ }
+ if v.MsgContext == "" && v.MsgIdPlural != "" {
+ return v.MsgId + NulSeparator + v.MsgIdPlural
+ }
+ return v.MsgId
+}
+
+func encodeMsgStr(v Message) string {
+ if v.MsgIdPlural != "" {
+ return strings.Join(v.MsgStrPlural, NulSeparator)
+ }
+ return v.MsgStr
+}
diff --git a/vendor/github.com/chai2010/gettext-go/mo/file.go b/vendor/github.com/chai2010/gettext-go/mo/file.go
new file mode 100644
index 0000000000..6f7ed161c1
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/mo/file.go
@@ -0,0 +1,197 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mo
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "io/ioutil"
+ "strings"
+)
+
+const (
+ MoHeaderSize = 28
+ MoMagicLittleEndian = 0x950412de
+ MoMagicBigEndian = 0xde120495
+
+ EotSeparator = "\x04" // msgctxt and msgid separator
+ NulSeparator = "\x00" // msgid and msgstr separator
+)
+
+// File represents an MO File.
+//
+// See http://www.gnu.org/software/gettext/manual/html_node/MO-Files.html
+type File struct {
+ MagicNumber uint32
+ MajorVersion uint16
+ MinorVersion uint16
+ MsgIdCount uint32
+ MsgIdOffset uint32
+ MsgStrOffset uint32
+ HashSize uint32
+ HashOffset uint32
+ MimeHeader Header
+ Messages []Message
+}
+
+// Load loads mo file format data.
+func Load(data []byte) (*File, error) {
+ return loadData(data)
+}
+
+// Load loads a named mo file.
+func LoadFile(path string) (*File, error) {
+ data, err := ioutil.ReadFile(path)
+ if err != nil {
+ return nil, err
+ }
+ return loadData(data)
+}
+
+func loadData(data []byte) (*File, error) {
+ r := bytes.NewReader(data)
+
+ var magicNumber uint32
+ if err := binary.Read(r, binary.LittleEndian, &magicNumber); err != nil {
+ return nil, fmt.Errorf("gettext: %v", err)
+ }
+ var bo binary.ByteOrder
+ switch magicNumber {
+ case MoMagicLittleEndian:
+ bo = binary.LittleEndian
+ case MoMagicBigEndian:
+ bo = binary.BigEndian
+ default:
+ return nil, fmt.Errorf("gettext: %v", "invalid magic number")
+ }
+
+ var header struct {
+ MajorVersion uint16
+ MinorVersion uint16
+ MsgIdCount uint32
+ MsgIdOffset uint32
+ MsgStrOffset uint32
+ HashSize uint32
+ HashOffset uint32
+ }
+ if err := binary.Read(r, bo, &header); err != nil {
+ return nil, fmt.Errorf("gettext: %v", err)
+ }
+ if v := header.MajorVersion; v != 0 && v != 1 {
+ return nil, fmt.Errorf("gettext: %v", "invalid version number")
+ }
+ if v := header.MinorVersion; v != 0 && v != 1 {
+ return nil, fmt.Errorf("gettext: %v", "invalid version number")
+ }
+
+ msgIdStart := make([]uint32, header.MsgIdCount)
+ msgIdLen := make([]uint32, header.MsgIdCount)
+ if _, err := r.Seek(int64(header.MsgIdOffset), 0); err != nil {
+ return nil, fmt.Errorf("gettext: %v", err)
+ }
+ for i := 0; i < int(header.MsgIdCount); i++ {
+ if err := binary.Read(r, bo, &msgIdLen[i]); err != nil {
+ return nil, fmt.Errorf("gettext: %v", err)
+ }
+ if err := binary.Read(r, bo, &msgIdStart[i]); err != nil {
+ return nil, fmt.Errorf("gettext: %v", err)
+ }
+ }
+
+ msgStrStart := make([]int32, header.MsgIdCount)
+ msgStrLen := make([]int32, header.MsgIdCount)
+ if _, err := r.Seek(int64(header.MsgStrOffset), 0); err != nil {
+ return nil, fmt.Errorf("gettext: %v", err)
+ }
+ for i := 0; i < int(header.MsgIdCount); i++ {
+ if err := binary.Read(r, bo, &msgStrLen[i]); err != nil {
+ return nil, fmt.Errorf("gettext: %v", err)
+ }
+ if err := binary.Read(r, bo, &msgStrStart[i]); err != nil {
+ return nil, fmt.Errorf("gettext: %v", err)
+ }
+ }
+
+ file := &File{
+ MagicNumber: magicNumber,
+ MajorVersion: header.MajorVersion,
+ MinorVersion: header.MinorVersion,
+ MsgIdCount: header.MsgIdCount,
+ MsgIdOffset: header.MsgIdOffset,
+ MsgStrOffset: header.MsgStrOffset,
+ HashSize: header.HashSize,
+ HashOffset: header.HashOffset,
+ }
+ for i := 0; i < int(header.MsgIdCount); i++ {
+ if _, err := r.Seek(int64(msgIdStart[i]), 0); err != nil {
+ return nil, fmt.Errorf("gettext: %v", err)
+ }
+ msgIdData := make([]byte, msgIdLen[i])
+ if _, err := r.Read(msgIdData); err != nil {
+ return nil, fmt.Errorf("gettext: %v", err)
+ }
+
+ if _, err := r.Seek(int64(msgStrStart[i]), 0); err != nil {
+ return nil, fmt.Errorf("gettext: %v", err)
+ }
+ msgStrData := make([]byte, msgStrLen[i])
+ if _, err := r.Read(msgStrData); err != nil {
+ return nil, fmt.Errorf("gettext: %v", err)
+ }
+
+ if len(msgIdData) == 0 {
+ var msg = Message{
+ MsgId: string(msgIdData),
+ MsgStr: string(msgStrData),
+ }
+ file.MimeHeader.fromMessage(&msg)
+ } else {
+ var msg = Message{
+ MsgId: string(msgIdData),
+ MsgStr: string(msgStrData),
+ }
+ // Is this a context message?
+ if idx := strings.Index(msg.MsgId, EotSeparator); idx != -1 {
+ msg.MsgContext, msg.MsgId = msg.MsgId[:idx], msg.MsgId[idx+1:]
+ }
+ // Is this a plural message?
+ if idx := strings.Index(msg.MsgId, NulSeparator); idx != -1 {
+ msg.MsgId, msg.MsgIdPlural = msg.MsgId[:idx], msg.MsgId[idx+1:]
+ msg.MsgStrPlural = strings.Split(msg.MsgStr, NulSeparator)
+ msg.MsgStr = ""
+ }
+ file.Messages = append(file.Messages, msg)
+ }
+ }
+
+ return file, nil
+}
+
+// Save saves a mo file.
+func (f *File) Save(name string) error {
+ return ioutil.WriteFile(name, f.Data(), 0666)
+}
+
+// Save returns a mo file format data.
+func (f *File) Data() []byte {
+ return encodeFile(f)
+}
+
+// String returns the po format file string.
+func (f *File) String() string {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "# version: %d.%d\n", f.MajorVersion, f.MinorVersion)
+ fmt.Fprintf(&buf, "%s\n", f.MimeHeader.String())
+ fmt.Fprintf(&buf, "\n")
+
+ for k, v := range f.Messages {
+ fmt.Fprintf(&buf, `msgid "%v"`+"\n", k)
+ fmt.Fprintf(&buf, `msgstr "%s"`+"\n", v.MsgStr)
+ fmt.Fprintf(&buf, "\n")
+ }
+
+ return buf.String()
+}
diff --git a/vendor/github.com/chai2010/gettext-go/mo/header.go b/vendor/github.com/chai2010/gettext-go/mo/header.go
new file mode 100644
index 0000000000..d8c7a5e3a3
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/mo/header.go
@@ -0,0 +1,109 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mo
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+)
+
+// Header is the initial comments "SOME DESCRIPTIVE TITLE", "YEAR"
+// and "FIRST AUTHOR , YEAR" ought to be replaced by sensible information.
+//
+// See http://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#Header-Entry
+type Header struct {
+ ProjectIdVersion string // Project-Id-Version: PACKAGE VERSION
+ ReportMsgidBugsTo string // Report-Msgid-Bugs-To: FIRST AUTHOR
+ POTCreationDate string // POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE
+ PORevisionDate string // PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE
+ LastTranslator string // Last-Translator: FIRST AUTHOR
+ LanguageTeam string // Language-Team: golang-china
+ Language string // Language: zh_CN
+ MimeVersion string // MIME-Version: 1.0
+ ContentType string // Content-Type: text/plain; charset=UTF-8
+ ContentTransferEncoding string // Content-Transfer-Encoding: 8bit
+ PluralForms string // Plural-Forms: nplurals=2; plural=n == 1 ? 0 : 1;
+ XGenerator string // X-Generator: Poedit 1.5.5
+ UnknowFields map[string]string
+}
+
+func (p *Header) fromMessage(msg *Message) {
+ if msg.MsgId != "" || msg.MsgStr == "" {
+ return
+ }
+ lines := strings.Split(msg.MsgStr, "\n")
+ for i := 0; i < len(lines); i++ {
+ idx := strings.Index(lines[i], ":")
+ if idx < 0 {
+ continue
+ }
+ key := strings.TrimSpace(lines[i][:idx])
+ val := strings.TrimSpace(lines[i][idx+1:])
+ switch strings.ToUpper(key) {
+ case strings.ToUpper("Project-Id-Version"):
+ p.ProjectIdVersion = val
+ case strings.ToUpper("Report-Msgid-Bugs-To"):
+ p.ReportMsgidBugsTo = val
+ case strings.ToUpper("POT-Creation-Date"):
+ p.POTCreationDate = val
+ case strings.ToUpper("PO-Revision-Date"):
+ p.PORevisionDate = val
+ case strings.ToUpper("Last-Translator"):
+ p.LastTranslator = val
+ case strings.ToUpper("Language-Team"):
+ p.LanguageTeam = val
+ case strings.ToUpper("Language"):
+ p.Language = val
+ case strings.ToUpper("MIME-Version"):
+ p.MimeVersion = val
+ case strings.ToUpper("Content-Type"):
+ p.ContentType = val
+ case strings.ToUpper("Content-Transfer-Encoding"):
+ p.ContentTransferEncoding = val
+ case strings.ToUpper("Plural-Forms"):
+ p.PluralForms = val
+ case strings.ToUpper("X-Generator"):
+ p.XGenerator = val
+ default:
+ if p.UnknowFields == nil {
+ p.UnknowFields = make(map[string]string)
+ }
+ p.UnknowFields[key] = val
+ }
+ }
+}
+
+func (p *Header) toMessage() Message {
+ return Message{
+ MsgStr: p.String(),
+ }
+}
+
+// String returns the po format header string.
+func (p Header) String() string {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, `msgid ""`+"\n")
+ fmt.Fprintf(&buf, `msgstr ""`+"\n")
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Project-Id-Version", p.ProjectIdVersion)
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Report-Msgid-Bugs-To", p.ReportMsgidBugsTo)
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "POT-Creation-Date", p.POTCreationDate)
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "PO-Revision-Date", p.PORevisionDate)
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Last-Translator", p.LastTranslator)
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Language-Team", p.LanguageTeam)
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Language", p.Language)
+ if p.MimeVersion != "" {
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "MIME-Version", p.MimeVersion)
+ }
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Content-Type", p.ContentType)
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Content-Transfer-Encoding", p.ContentTransferEncoding)
+ if p.XGenerator != "" {
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "X-Generator", p.XGenerator)
+ }
+ for k, v := range p.UnknowFields {
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", k, v)
+ }
+ return buf.String()
+}
diff --git a/vendor/github.com/chai2010/gettext-go/mo/message.go b/vendor/github.com/chai2010/gettext-go/mo/message.go
new file mode 100644
index 0000000000..b67bde0b70
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/mo/message.go
@@ -0,0 +1,52 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mo
+
+import (
+ "bytes"
+ "fmt"
+)
+
+// A MO file is made up of many entries,
+// each entry holding the relation between an original untranslated string
+// and its corresponding translation.
+//
+// See http://www.gnu.org/software/gettext/manual/html_node/MO-Files.html
+type Message struct {
+ MsgContext string // msgctxt context
+ MsgId string // msgid untranslated-string
+ MsgIdPlural string // msgid_plural untranslated-string-plural
+ MsgStr string // msgstr translated-string
+ MsgStrPlural []string // msgstr[0] translated-string-case-0
+}
+
+// String returns the po format entry string.
+func (p Message) String() string {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "msgid %s", encodePoString(p.MsgId))
+ if p.MsgIdPlural != "" {
+ fmt.Fprintf(&buf, "msgid_plural %s", encodePoString(p.MsgIdPlural))
+ }
+ if p.MsgStr != "" {
+ fmt.Fprintf(&buf, "msgstr %s", encodePoString(p.MsgStr))
+ }
+ for i := 0; i < len(p.MsgStrPlural); i++ {
+ fmt.Fprintf(&buf, "msgstr[%d] %s", i, encodePoString(p.MsgStrPlural[i]))
+ }
+ return buf.String()
+}
+
+func (m_i *Message) less(m_j *Message) bool {
+ if a, b := m_i.MsgContext, m_j.MsgContext; a != b {
+ return a < b
+ }
+ if a, b := m_i.MsgId, m_j.MsgId; a != b {
+ return a < b
+ }
+ if a, b := m_i.MsgIdPlural, m_j.MsgIdPlural; a != b {
+ return a < b
+ }
+ return false
+}
diff --git a/vendor/github.com/chai2010/gettext-go/mo/util.go b/vendor/github.com/chai2010/gettext-go/mo/util.go
new file mode 100644
index 0000000000..3804511053
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/mo/util.go
@@ -0,0 +1,110 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mo
+
+import (
+ "bytes"
+ "strings"
+)
+
+func decodePoString(text string) string {
+ lines := strings.Split(text, "\n")
+ for i := 0; i < len(lines); i++ {
+ left := strings.Index(lines[i], `"`)
+ right := strings.LastIndex(lines[i], `"`)
+ if left < 0 || right < 0 || left == right {
+ lines[i] = ""
+ continue
+ }
+ line := lines[i][left+1 : right]
+ data := make([]byte, 0, len(line))
+ for i := 0; i < len(line); i++ {
+ if line[i] != '\\' {
+ data = append(data, line[i])
+ continue
+ }
+ if i+1 >= len(line) {
+ break
+ }
+ switch line[i+1] {
+ case 'n': // \\n -> \n
+ data = append(data, '\n')
+ i++
+ case 't': // \\t -> \n
+ data = append(data, '\t')
+ i++
+ case '\\': // \\\ -> ?
+ data = append(data, '\\')
+ i++
+ }
+ }
+ lines[i] = string(data)
+ }
+ return strings.Join(lines, "")
+}
+
+func encodePoString(text string) string {
+ var buf bytes.Buffer
+ lines := strings.Split(text, "\n")
+ for i := 0; i < len(lines); i++ {
+ if lines[i] == "" {
+ if i != len(lines)-1 {
+ buf.WriteString(`"\n"` + "\n")
+ }
+ continue
+ }
+ buf.WriteRune('"')
+ for _, r := range lines[i] {
+ switch r {
+ case '\\':
+ buf.WriteString(`\\`)
+ case '"':
+ buf.WriteString(`\"`)
+ case '\n':
+ buf.WriteString(`\n`)
+ case '\t':
+ buf.WriteString(`\t`)
+ default:
+ buf.WriteRune(r)
+ }
+ }
+ buf.WriteString(`\n"` + "\n")
+ }
+ return buf.String()
+}
+
+func encodeCommentPoString(text string) string {
+ var buf bytes.Buffer
+ lines := strings.Split(text, "\n")
+ if len(lines) > 1 {
+ buf.WriteString(`""` + "\n")
+ }
+ for i := 0; i < len(lines); i++ {
+ if len(lines) > 0 {
+ buf.WriteString("#| ")
+ }
+ buf.WriteRune('"')
+ for _, r := range lines[i] {
+ switch r {
+ case '\\':
+ buf.WriteString(`\\`)
+ case '"':
+ buf.WriteString(`\"`)
+ case '\n':
+ buf.WriteString(`\n`)
+ case '\t':
+ buf.WriteString(`\t`)
+ default:
+ buf.WriteRune(r)
+ }
+ }
+ if i < len(lines)-1 {
+ buf.WriteString(`\n"` + "\n")
+ } else {
+ buf.WriteString(`"`)
+ }
+ }
+ return buf.String()
+}
diff --git a/vendor/github.com/chai2010/gettext-go/plural/doc.go b/vendor/github.com/chai2010/gettext-go/plural/doc.go
new file mode 100644
index 0000000000..31cb8fae9f
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/plural/doc.go
@@ -0,0 +1,36 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package plural provides standard plural formulas.
+
+Examples:
+ import (
+ "github.com/chai2010/gettext-go/plural"
+ )
+
+ func main() {
+ enFormula := plural.Formula("en_US")
+ xxFormula := plural.Formula("zh_CN")
+
+ fmt.Printf("%s: %d\n", "en", enFormula(0))
+ fmt.Printf("%s: %d\n", "en", enFormula(1))
+ fmt.Printf("%s: %d\n", "en", enFormula(2))
+ fmt.Printf("%s: %d\n", "??", xxFormula(0))
+ fmt.Printf("%s: %d\n", "??", xxFormula(1))
+ fmt.Printf("%s: %d\n", "??", xxFormula(2))
+ fmt.Printf("%s: %d\n", "??", xxFormula(9))
+ // Output:
+ // en: 0
+ // en: 0
+ // en: 1
+ // ??: 0
+ // ??: 0
+ // ??: 1
+ // ??: 8
+ }
+
+See http://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html
+*/
+package plural
diff --git a/vendor/github.com/chai2010/gettext-go/plural/formula.go b/vendor/github.com/chai2010/gettext-go/plural/formula.go
new file mode 100644
index 0000000000..c92dc19ead
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/plural/formula.go
@@ -0,0 +1,181 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package plural
+
+import (
+ "strings"
+)
+
+// Formula provides the language's standard plural formula.
+func Formula(lang string) func(n int) int {
+ if idx := index(lang); idx != -1 {
+ return formulaTable[fmtForms(FormsTable[idx].Value)]
+ }
+ if idx := index("??"); idx != -1 {
+ return formulaTable[fmtForms(FormsTable[idx].Value)]
+ }
+ return func(n int) int {
+ return n
+ }
+}
+
+func index(lang string) int {
+ for i := 0; i < len(FormsTable); i++ {
+ if strings.HasPrefix(lang, FormsTable[i].Lang) {
+ return i
+ }
+ }
+ return -1
+}
+
+func fmtForms(forms string) string {
+ forms = strings.TrimSpace(forms)
+ forms = strings.Replace(forms, " ", "", -1)
+ return forms
+}
+
+var formulaTable = map[string]func(n int) int{
+ fmtForms("nplurals=n; plural=n-1;"): func(n int) int {
+ if n > 0 {
+ return n - 1
+ }
+ return 0
+ },
+ fmtForms("nplurals=1; plural=0;"): func(n int) int {
+ return 0
+ },
+ fmtForms("nplurals=2; plural=(n != 1);"): func(n int) int {
+ if n == 1 {
+ return 0
+ }
+ return 1
+ },
+ fmtForms("nplurals=2; plural=(n > 1);"): func(n int) int {
+ if n <= 1 {
+ return 0
+ }
+ return 1
+ },
+ fmtForms("nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);"): func(n int) int {
+ if n%10 == 1 && n%100 != 11 {
+ return 0
+ }
+ if n != 0 {
+ return 1
+ }
+ return 2
+ },
+ fmtForms("nplurals=3; plural=n==1 ? 0 : n==2 ? 1 : 2;"): func(n int) int {
+ if n == 1 {
+ return 0
+ }
+ if n == 2 {
+ return 1
+ }
+ return 2
+ },
+ fmtForms("nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2;"): func(n int) int {
+ if n == 1 {
+ return 0
+ }
+ if n == 0 || (n%100 > 0 && n%100 < 20) {
+ return 1
+ }
+ return 2
+ },
+ fmtForms("nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);"): func(n int) int {
+ if n%10 == 1 && n%100 != 11 {
+ return 0
+ }
+ if n%10 >= 2 && (n%100 < 10 || n%100 >= 20) {
+ return 1
+ }
+ return 2
+ },
+ fmtForms("nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"): func(n int) int {
+ if n%10 == 1 && n%100 != 11 {
+ return 0
+ }
+ if n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20) {
+ return 1
+ }
+ return 2
+ },
+ fmtForms("nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"): func(n int) int {
+ if n%10 == 1 && n%100 != 11 {
+ return 0
+ }
+ if n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20) {
+ return 1
+ }
+ return 2
+ },
+ fmtForms("nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"): func(n int) int {
+ if n%10 == 1 && n%100 != 11 {
+ return 0
+ }
+ if n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20) {
+ return 1
+ }
+ return 2
+ },
+ fmtForms("nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"): func(n int) int {
+ if n%10 == 1 && n%100 != 11 {
+ return 0
+ }
+ if n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20) {
+ return 1
+ }
+ return 2
+ },
+ fmtForms("nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"): func(n int) int {
+ if n%10 == 1 && n%100 != 11 {
+ return 0
+ }
+ if n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20) {
+ return 1
+ }
+ return 2
+ },
+ fmtForms("nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"): func(n int) int {
+ if n == 1 {
+ return 0
+ }
+ if n >= 2 && n <= 4 {
+ return 1
+ }
+ return 2
+ },
+ fmtForms("nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"): func(n int) int {
+ if n == 1 {
+ return 0
+ }
+ if n >= 2 && n <= 4 {
+ return 1
+ }
+ return 2
+ },
+ fmtForms("nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"): func(n int) int {
+ if n == 1 {
+ return 0
+ }
+ if n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20) {
+ return 1
+ }
+ return 2
+ },
+ fmtForms("nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);"): func(n int) int {
+ if n%100 == 1 {
+ return 0
+ }
+ if n%100 == 2 {
+ return 1
+ }
+ if n%100 == 3 || n%100 == 4 {
+ return 2
+ }
+ return 3
+ },
+}
diff --git a/vendor/github.com/chai2010/gettext-go/plural/table.go b/vendor/github.com/chai2010/gettext-go/plural/table.go
new file mode 100644
index 0000000000..cdc50d2110
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/plural/table.go
@@ -0,0 +1,55 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package plural
+
+// FormsTable are standard hard-coded plural rules.
+// The application developers and the translators need to understand them.
+//
+// See GNU's gettext library source code: gettext/gettext-tools/src/plural-table.c
+var FormsTable = []struct {
+ Lang string
+ Language string
+ Value string
+}{
+ {"??", "Unknown", "nplurals=1; plural=0;"},
+ {"ja", "Japanese", "nplurals=1; plural=0;"},
+ {"vi", "Vietnamese", "nplurals=1; plural=0;"},
+ {"ko", "Korean", "nplurals=1; plural=0;"},
+ {"en", "English", "nplurals=2; plural=(n != 1);"},
+ {"de", "German", "nplurals=2; plural=(n != 1);"},
+ {"nl", "Dutch", "nplurals=2; plural=(n != 1);"},
+ {"sv", "Swedish", "nplurals=2; plural=(n != 1);"},
+ {"da", "Danish", "nplurals=2; plural=(n != 1);"},
+ {"no", "Norwegian", "nplurals=2; plural=(n != 1);"},
+ {"nb", "Norwegian Bokmal", "nplurals=2; plural=(n != 1);"},
+ {"nn", "Norwegian Nynorsk", "nplurals=2; plural=(n != 1);"},
+ {"fo", "Faroese", "nplurals=2; plural=(n != 1);"},
+ {"es", "Spanish", "nplurals=2; plural=(n != 1);"},
+ {"pt", "Portuguese", "nplurals=2; plural=(n != 1);"},
+ {"it", "Italian", "nplurals=2; plural=(n != 1);"},
+ {"bg", "Bulgarian", "nplurals=2; plural=(n != 1);"},
+ {"el", "Greek", "nplurals=2; plural=(n != 1);"},
+ {"fi", "Finnish", "nplurals=2; plural=(n != 1);"},
+ {"et", "Estonian", "nplurals=2; plural=(n != 1);"},
+ {"he", "Hebrew", "nplurals=2; plural=(n != 1);"},
+ {"eo", "Esperanto", "nplurals=2; plural=(n != 1);"},
+ {"hu", "Hungarian", "nplurals=2; plural=(n != 1);"},
+ {"tr", "Turkish", "nplurals=2; plural=(n != 1);"},
+ {"pt_BR", "Brazilian", "nplurals=2; plural=(n > 1);"},
+ {"fr", "French", "nplurals=2; plural=(n > 1);"},
+ {"lv", "Latvian", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);"},
+ {"ga", "Irish", "nplurals=3; plural=n==1 ? 0 : n==2 ? 1 : 2;"},
+ {"ro", "Romanian", "nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2;"},
+ {"lt", "Lithuanian", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);"},
+ {"ru", "Russian", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"},
+ {"uk", "Ukrainian", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"},
+ {"be", "Belarusian", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"},
+ {"sr", "Serbian", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"},
+ {"hr", "Croatian", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"},
+ {"cs", "Czech", "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"},
+ {"sk", "Slovak", "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"},
+ {"pl", "Polish", "nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"},
+ {"sl", "Slovenian", "nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);"},
+}
diff --git a/vendor/github.com/chai2010/gettext-go/po/comment.go b/vendor/github.com/chai2010/gettext-go/po/comment.go
new file mode 100644
index 0000000000..d4abe7c106
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/po/comment.go
@@ -0,0 +1,270 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package po
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "strconv"
+ "strings"
+)
+
+// Comment represents every message's comments.
+type Comment struct {
+ StartLine int // comment start line
+ TranslatorComment string // # translator-comments // TrimSpace
+ ExtractedComment string // #. extracted-comments
+ ReferenceFile []string // #: src/msgcmp.c:338 src/po-lex.c:699
+ ReferenceLine []int // #: src/msgcmp.c:338 src/po-lex.c:699
+ Flags []string // #, fuzzy,c-format,range:0..10
+ PrevMsgContext string // #| msgctxt previous-context
+ PrevMsgId string // #| msgid previous-untranslated-string
+}
+
+func (p *Comment) less(q *Comment) bool {
+ if p.StartLine != 0 || q.StartLine != 0 {
+ return p.StartLine < q.StartLine
+ }
+ if a, b := len(p.ReferenceFile), len(q.ReferenceFile); a != b {
+ return a < b
+ }
+ for i := 0; i < len(p.ReferenceFile); i++ {
+ if a, b := p.ReferenceFile[i], q.ReferenceFile[i]; a != b {
+ return a < b
+ }
+ if a, b := p.ReferenceLine[i], q.ReferenceLine[i]; a != b {
+ return a < b
+ }
+ }
+ return false
+}
+
+func (p *Comment) readPoComment(r *lineReader) (err error) {
+ *p = Comment{}
+ if err = r.skipBlankLine(); err != nil {
+ return err
+ }
+ defer func(oldPos int) {
+ newPos := r.currentPos()
+ if newPos != oldPos && err == io.EOF {
+ err = nil
+ }
+ }(r.currentPos())
+
+ p.StartLine = r.currentPos() + 1
+ for {
+ var s string
+ if s, _, err = r.currentLine(); err != nil {
+ return
+ }
+ if len(s) == 0 || s[0] != '#' {
+ return
+ }
+
+ if err = p.readTranslatorComment(r); err != nil {
+ return
+ }
+ if err = p.readExtractedComment(r); err != nil {
+ return
+ }
+ if err = p.readReferenceComment(r); err != nil {
+ return
+ }
+ if err = p.readFlagsComment(r); err != nil {
+ return
+ }
+ if err = p.readPrevMsgContext(r); err != nil {
+ return
+ }
+ if err = p.readPrevMsgId(r); err != nil {
+ return
+ }
+ }
+}
+
+func (p *Comment) readTranslatorComment(r *lineReader) (err error) {
+ const prefix = "# " // .,:|
+ for {
+ var s string
+ if s, _, err = r.readLine(); err != nil {
+ return err
+ }
+ if len(s) < 1 || s[0] != '#' {
+ r.unreadLine()
+ return nil
+ }
+ if len(s) >= 2 {
+ switch s[1] {
+ case '.', ',', ':', '|':
+ r.unreadLine()
+ return nil
+ }
+ }
+ if p.TranslatorComment != "" {
+ p.TranslatorComment += "\n"
+ }
+ p.TranslatorComment += strings.TrimSpace(s[1:])
+ }
+}
+
+func (p *Comment) readExtractedComment(r *lineReader) (err error) {
+ const prefix = "#."
+ for {
+ var s string
+ if s, _, err = r.readLine(); err != nil {
+ return err
+ }
+ if len(s) < len(prefix) || s[:len(prefix)] != prefix {
+ r.unreadLine()
+ return nil
+ }
+ if p.ExtractedComment != "" {
+ p.ExtractedComment += "\n"
+ }
+ p.ExtractedComment += strings.TrimSpace(s[len(prefix):])
+ }
+}
+
+func (p *Comment) readReferenceComment(r *lineReader) (err error) {
+ const prefix = "#:"
+ for {
+ var s string
+ if s, _, err = r.readLine(); err != nil {
+ return err
+ }
+ if len(s) < len(prefix) || s[:len(prefix)] != prefix {
+ r.unreadLine()
+ return nil
+ }
+ ss := strings.Split(strings.TrimSpace(s[len(prefix):]), " ")
+ for i := 0; i < len(ss); i++ {
+ idx := strings.Index(ss[i], ":")
+ if idx <= 0 {
+ continue
+ }
+ name := strings.TrimSpace(ss[i][:idx])
+ line, _ := strconv.Atoi(strings.TrimSpace(ss[i][idx+1:]))
+ p.ReferenceFile = append(p.ReferenceFile, name)
+ p.ReferenceLine = append(p.ReferenceLine, line)
+ }
+ }
+}
+
+func (p *Comment) readFlagsComment(r *lineReader) (err error) {
+ const prefix = "#,"
+ for {
+ var s string
+ if s, _, err = r.readLine(); err != nil {
+ return err
+ }
+ if len(s) < len(prefix) || s[:len(prefix)] != prefix {
+ r.unreadLine()
+ return nil
+ }
+ ss := strings.Split(strings.TrimSpace(s[len(prefix):]), ",")
+ for i := 0; i < len(ss); i++ {
+ p.Flags = append(p.Flags, strings.TrimSpace(ss[i]))
+ }
+ }
+}
+
+func (p *Comment) readPrevMsgContext(r *lineReader) (err error) {
+ var s string
+ if s, _, err = r.currentLine(); err != nil {
+ return
+ }
+ if !rePrevMsgContextComments.MatchString(s) {
+ return
+ }
+ p.PrevMsgContext, err = p.readString(r)
+ return
+}
+
+func (p *Comment) readPrevMsgId(r *lineReader) (err error) {
+ var s string
+ if s, _, err = r.currentLine(); err != nil {
+ return
+ }
+ if !rePrevMsgIdComments.MatchString(s) {
+ return
+ }
+ p.PrevMsgId, err = p.readString(r)
+ return
+}
+
+func (p *Comment) readString(r *lineReader) (msg string, err error) {
+ var s string
+ if s, _, err = r.readLine(); err != nil {
+ return
+ }
+ msg += decodePoString(s)
+ for {
+ if s, _, err = r.readLine(); err != nil {
+ return
+ }
+ if !reStringLineComments.MatchString(s) {
+ r.unreadLine()
+ break
+ }
+ msg += decodePoString(s)
+ }
+ return
+}
+
+// GetFuzzy gets the fuzzy flag.
+func (p *Comment) GetFuzzy() bool {
+ for _, s := range p.Flags {
+ if s == "fuzzy" {
+ return true
+ }
+ }
+ return false
+}
+
+// SetFuzzy sets the fuzzy flag.
+func (p *Comment) SetFuzzy(fuzzy bool) {
+ //
+}
+
+// String returns the po format comment string.
+func (p Comment) String() string {
+ var buf bytes.Buffer
+ if p.TranslatorComment != "" {
+ ss := strings.Split(p.TranslatorComment, "\n")
+ for i := 0; i < len(ss); i++ {
+ fmt.Fprintf(&buf, "# %s\n", ss[i])
+ }
+ }
+ if p.ExtractedComment != "" {
+ ss := strings.Split(p.ExtractedComment, "\n")
+ for i := 0; i < len(ss); i++ {
+ fmt.Fprintf(&buf, "#. %s\n", ss[i])
+ }
+ }
+ if a, b := len(p.ReferenceFile), len(p.ReferenceLine); a != 0 && a == b {
+ fmt.Fprintf(&buf, "#:")
+ for i := 0; i < len(p.ReferenceFile); i++ {
+ fmt.Fprintf(&buf, " %s:%d", p.ReferenceFile[i], p.ReferenceLine[i])
+ }
+ fmt.Fprintf(&buf, "\n")
+ }
+ if len(p.Flags) != 0 {
+ fmt.Fprintf(&buf, "#, %s", p.Flags[0])
+ for i := 1; i < len(p.Flags); i++ {
+ fmt.Fprintf(&buf, ", %s", p.Flags[i])
+ }
+ fmt.Fprintf(&buf, "\n")
+ }
+ if p.PrevMsgContext != "" {
+ s := encodeCommentPoString(p.PrevMsgContext)
+ fmt.Fprintf(&buf, "#| msgctxt %s\n", s)
+ }
+ if p.PrevMsgId != "" {
+ s := encodeCommentPoString(p.PrevMsgId)
+ fmt.Fprintf(&buf, "#| msgid %s\n", s)
+ }
+ return buf.String()
+}
diff --git a/vendor/github.com/chai2010/gettext-go/po/doc.go b/vendor/github.com/chai2010/gettext-go/po/doc.go
new file mode 100644
index 0000000000..6cfa2a24be
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/po/doc.go
@@ -0,0 +1,24 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package po provides support for reading and writing GNU PO file.
+
+Examples:
+ import (
+ "github.com/chai2010/gettext-go/po"
+ )
+
+ func main() {
+ poFile, err := po.LoadFile("test.po")
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("%v", poFile)
+ }
+
+The GNU PO file specification is at
+http://www.gnu.org/software/gettext/manual/html_node/PO-Files.html.
+*/
+package po
diff --git a/vendor/github.com/chai2010/gettext-go/po/file.go b/vendor/github.com/chai2010/gettext-go/po/file.go
new file mode 100644
index 0000000000..4a122eeb8b
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/po/file.go
@@ -0,0 +1,81 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package po
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "sort"
+)
+
+// File represents an PO File.
+//
+// See http://www.gnu.org/software/gettext/manual/html_node/PO-Files.html
+type File struct {
+ MimeHeader Header
+ Messages []Message
+}
+
+// Load loads po file format data.
+func Load(data []byte) (*File, error) {
+ return loadData(data)
+}
+
+// LoadFile loads a named po file.
+func LoadFile(path string) (*File, error) {
+ data, err := ioutil.ReadFile(path)
+ if err != nil {
+ return nil, err
+ }
+ return loadData(data)
+}
+
+func loadData(data []byte) (*File, error) {
+ r := newLineReader(string(data))
+ var file File
+ for {
+ var msg Message
+ if err := msg.readPoEntry(r); err != nil {
+ if err == io.EOF {
+ return &file, nil
+ }
+ return nil, err
+ }
+ if msg.MsgId == "" {
+ file.MimeHeader.parseHeader(&msg)
+ continue
+ }
+ file.Messages = append(file.Messages, msg)
+ }
+}
+
+// Save saves a po file.
+func (f *File) Save(name string) error {
+ return ioutil.WriteFile(name, []byte(f.String()), 0666)
+}
+
+// Save returns a po file format data.
+func (f *File) Data() []byte {
+ // sort the massge as ReferenceFile/ReferenceLine field
+ var messages []Message
+ messages = append(messages, f.Messages...)
+ sort.Slice(messages, func(i, j int) bool {
+ return messages[i].less(&messages[j])
+ })
+
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "%s\n", f.MimeHeader.String())
+ for i := 0; i < len(messages); i++ {
+ fmt.Fprintf(&buf, "%s\n", messages[i].String())
+ }
+ return buf.Bytes()
+}
+
+// String returns the po format file string.
+func (f *File) String() string {
+ return string(f.Data())
+}
diff --git a/vendor/github.com/chai2010/gettext-go/po/header.go b/vendor/github.com/chai2010/gettext-go/po/header.go
new file mode 100644
index 0000000000..a9b5b6671b
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/po/header.go
@@ -0,0 +1,106 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package po
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+)
+
+// Header is the initial comments "SOME DESCRIPTIVE TITLE", "YEAR"
+// and "FIRST AUTHOR , YEAR" ought to be replaced by sensible information.
+//
+// See http://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#Header-Entry
+type Header struct {
+ Comment // Header Comments
+ ProjectIdVersion string // Project-Id-Version: PACKAGE VERSION
+ ReportMsgidBugsTo string // Report-Msgid-Bugs-To: FIRST AUTHOR
+ POTCreationDate string // POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE
+ PORevisionDate string // PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE
+ LastTranslator string // Last-Translator: FIRST AUTHOR
+ LanguageTeam string // Language-Team: golang-china
+ Language string // Language: zh_CN
+ MimeVersion string // MIME-Version: 1.0
+ ContentType string // Content-Type: text/plain; charset=UTF-8
+ ContentTransferEncoding string // Content-Transfer-Encoding: 8bit
+ PluralForms string // Plural-Forms: nplurals=2; plural=n == 1 ? 0 : 1;
+ XGenerator string // X-Generator: Poedit 1.5.5
+ UnknowFields map[string]string
+}
+
+func (p *Header) parseHeader(msg *Message) {
+ if msg.MsgId != "" || msg.MsgStr == "" {
+ return
+ }
+ lines := strings.Split(msg.MsgStr, "\n")
+ for i := 0; i < len(lines); i++ {
+ idx := strings.Index(lines[i], ":")
+ if idx < 0 {
+ continue
+ }
+ key := strings.TrimSpace(lines[i][:idx])
+ val := strings.TrimSpace(lines[i][idx+1:])
+ switch strings.ToUpper(key) {
+ case strings.ToUpper("Project-Id-Version"):
+ p.ProjectIdVersion = val
+ case strings.ToUpper("Report-Msgid-Bugs-To"):
+ p.ReportMsgidBugsTo = val
+ case strings.ToUpper("POT-Creation-Date"):
+ p.POTCreationDate = val
+ case strings.ToUpper("PO-Revision-Date"):
+ p.PORevisionDate = val
+ case strings.ToUpper("Last-Translator"):
+ p.LastTranslator = val
+ case strings.ToUpper("Language-Team"):
+ p.LanguageTeam = val
+ case strings.ToUpper("Language"):
+ p.Language = val
+ case strings.ToUpper("MIME-Version"):
+ p.MimeVersion = val
+ case strings.ToUpper("Content-Type"):
+ p.ContentType = val
+ case strings.ToUpper("Content-Transfer-Encoding"):
+ p.ContentTransferEncoding = val
+ case strings.ToUpper("Plural-Forms"):
+ p.PluralForms = val
+ case strings.ToUpper("X-Generator"):
+ p.XGenerator = val
+ default:
+ if p.UnknowFields == nil {
+ p.UnknowFields = make(map[string]string)
+ }
+ p.UnknowFields[key] = val
+ }
+ }
+ p.Comment = msg.Comment
+}
+
+// String returns the po format header string.
+func (p Header) String() string {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "%s", p.Comment.String())
+ fmt.Fprintf(&buf, `msgid ""`+"\n")
+ fmt.Fprintf(&buf, `msgstr ""`+"\n")
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Project-Id-Version", p.ProjectIdVersion)
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Report-Msgid-Bugs-To", p.ReportMsgidBugsTo)
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "POT-Creation-Date", p.POTCreationDate)
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "PO-Revision-Date", p.PORevisionDate)
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Last-Translator", p.LastTranslator)
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Language-Team", p.LanguageTeam)
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Language", p.Language)
+ if p.MimeVersion != "" {
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "MIME-Version", p.MimeVersion)
+ }
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Content-Type", p.ContentType)
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Content-Transfer-Encoding", p.ContentTransferEncoding)
+ if p.XGenerator != "" {
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "X-Generator", p.XGenerator)
+ }
+ for k, v := range p.UnknowFields {
+ fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", k, v)
+ }
+ return buf.String()
+}
diff --git a/vendor/github.com/chai2010/gettext-go/po/line_reader.go b/vendor/github.com/chai2010/gettext-go/po/line_reader.go
new file mode 100644
index 0000000000..8597273a2b
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/po/line_reader.go
@@ -0,0 +1,62 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package po
+
+import (
+ "io"
+ "strings"
+)
+
+type lineReader struct {
+ lines []string
+ pos int
+}
+
+func newLineReader(data string) *lineReader {
+ data = strings.Replace(data, "\r", "", -1)
+ lines := strings.Split(data, "\n")
+ return &lineReader{lines: lines}
+}
+
+func (r *lineReader) skipBlankLine() error {
+ for ; r.pos < len(r.lines); r.pos++ {
+ if strings.TrimSpace(r.lines[r.pos]) != "" {
+ break
+ }
+ }
+ if r.pos >= len(r.lines) {
+ return io.EOF
+ }
+ return nil
+}
+
+func (r *lineReader) currentPos() int {
+ return r.pos
+}
+
+func (r *lineReader) currentLine() (s string, pos int, err error) {
+ if r.pos >= len(r.lines) {
+ err = io.EOF
+ return
+ }
+ s, pos = r.lines[r.pos], r.pos
+ return
+}
+
+func (r *lineReader) readLine() (s string, pos int, err error) {
+ if r.pos >= len(r.lines) {
+ err = io.EOF
+ return
+ }
+ s, pos = r.lines[r.pos], r.pos
+ r.pos++
+ return
+}
+
+func (r *lineReader) unreadLine() {
+ if r.pos >= 0 {
+ r.pos--
+ }
+}
diff --git a/vendor/github.com/chai2010/gettext-go/po/message.go b/vendor/github.com/chai2010/gettext-go/po/message.go
new file mode 100644
index 0000000000..39936dcc7b
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/po/message.go
@@ -0,0 +1,193 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package po
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "strconv"
+ "strings"
+)
+
+// A PO file is made up of many entries,
+// each entry holding the relation between an original untranslated string
+// and its corresponding translation.
+//
+// See http://www.gnu.org/software/gettext/manual/html_node/PO-Files.html
+type Message struct {
+ Comment // Coments
+ MsgContext string // msgctxt context
+ MsgId string // msgid untranslated-string
+ MsgIdPlural string // msgid_plural untranslated-string-plural
+ MsgStr string // msgstr translated-string
+ MsgStrPlural []string // msgstr[0] translated-string-case-0
+}
+
+func (p *Message) less(q *Message) bool {
+ if p.Comment.less(&q.Comment) {
+ return true
+ }
+ if a, b := p.MsgContext, q.MsgContext; a != b {
+ return a < b
+ }
+ if a, b := p.MsgId, q.MsgId; a != b {
+ return a < b
+ }
+ if a, b := p.MsgIdPlural, q.MsgIdPlural; a != b {
+ return a < b
+ }
+ return false
+}
+
+func (p *Message) readPoEntry(r *lineReader) (err error) {
+ *p = Message{}
+ if err = r.skipBlankLine(); err != nil {
+ return
+ }
+ defer func(oldPos int) {
+ newPos := r.currentPos()
+ if newPos != oldPos && err == io.EOF {
+ err = nil
+ }
+ }(r.currentPos())
+
+ if err = p.Comment.readPoComment(r); err != nil {
+ return
+ }
+ for {
+ var s string
+ if s, _, err = r.currentLine(); err != nil {
+ return
+ }
+
+ if p.isInvalidLine(s) {
+ err = fmt.Errorf("gettext: line %d, %v", r.currentPos(), "invalid line")
+ return
+ }
+ if reComment.MatchString(s) || reBlankLine.MatchString(s) {
+ return
+ }
+
+ if err = p.readMsgContext(r); err != nil {
+ return
+ }
+ if err = p.readMsgId(r); err != nil {
+ return
+ }
+ if err = p.readMsgIdPlural(r); err != nil {
+ return
+ }
+ if err = p.readMsgStrOrPlural(r); err != nil {
+ return
+ }
+ }
+}
+
+func (p *Message) readMsgContext(r *lineReader) (err error) {
+ var s string
+ if s, _, err = r.currentLine(); err != nil {
+ return
+ }
+ if !reMsgContext.MatchString(s) {
+ return
+ }
+ p.MsgContext, err = p.readString(r)
+ return
+}
+
+func (p *Message) readMsgId(r *lineReader) (err error) {
+ var s string
+ if s, _, err = r.currentLine(); err != nil {
+ return
+ }
+ if !reMsgId.MatchString(s) {
+ return
+ }
+ p.MsgId, err = p.readString(r)
+ return
+}
+
+func (p *Message) readMsgIdPlural(r *lineReader) (err error) {
+ var s string
+ if s, _, err = r.currentLine(); err != nil {
+ return
+ }
+ if !reMsgIdPlural.MatchString(s) {
+ return
+ }
+ p.MsgIdPlural, err = p.readString(r)
+ return nil
+}
+
+func (p *Message) readMsgStrOrPlural(r *lineReader) (err error) {
+ var s string
+ if s, _, err = r.currentLine(); err != nil {
+ return
+ }
+ if !reMsgStr.MatchString(s) && !reMsgStrPlural.MatchString(s) {
+ return
+ }
+ if reMsgStrPlural.MatchString(s) {
+ left, right := strings.Index(s, `[`), strings.LastIndex(s, `]`)
+ idx, _ := strconv.Atoi(s[left+1 : right])
+ s, err = p.readString(r)
+ if n := len(p.MsgStrPlural); (idx + 1) > n {
+ p.MsgStrPlural = append(p.MsgStrPlural, make([]string, (idx+1)-n)...)
+ }
+ p.MsgStrPlural[idx] = s
+ } else {
+ p.MsgStr, err = p.readString(r)
+ }
+ return nil
+}
+
+func (p *Message) readString(r *lineReader) (msg string, err error) {
+ var s string
+ if s, _, err = r.readLine(); err != nil {
+ return
+ }
+ msg += decodePoString(s)
+ for {
+ if s, _, err = r.readLine(); err != nil {
+ return
+ }
+ if !reStringLine.MatchString(s) {
+ r.unreadLine()
+ break
+ }
+ msg += decodePoString(s)
+ }
+ return
+}
+
+// String returns the po format entry string.
+func (p Message) String() string {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "%s", p.Comment.String())
+ if p.MsgContext != "" {
+ fmt.Fprintf(&buf, "msgctxt %s", encodePoString(p.MsgContext))
+ }
+ fmt.Fprintf(&buf, "msgid %s", encodePoString(p.MsgId))
+ if p.MsgIdPlural != "" {
+ fmt.Fprintf(&buf, "msgid_plural %s", encodePoString(p.MsgIdPlural))
+ }
+ if len(p.MsgStrPlural) == 0 {
+ if p.MsgStr != "" {
+ fmt.Fprintf(&buf, "msgstr %s", encodePoString(p.MsgStr))
+ } else {
+ fmt.Fprintf(&buf, "msgstr %s", `""`+"\n")
+ }
+ } else {
+ for i := 0; i < len(p.MsgStrPlural); i++ {
+ if p.MsgStrPlural[i] != "" {
+ fmt.Fprintf(&buf, "msgstr[%d] %s", i, encodePoString(p.MsgStrPlural[i]))
+ } else {
+ fmt.Fprintf(&buf, "msgstr[%d] %s", i, `""`+"\n")
+ }
+ }
+ }
+ return buf.String()
+}
diff --git a/vendor/github.com/chai2010/gettext-go/po/re.go b/vendor/github.com/chai2010/gettext-go/po/re.go
new file mode 100644
index 0000000000..67c240a57b
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/po/re.go
@@ -0,0 +1,58 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package po
+
+import (
+ "regexp"
+)
+
+var (
+ reComment = regexp.MustCompile(`^#`) // #
+ reExtractedComments = regexp.MustCompile(`^#\.`) // #.
+ reReferenceComments = regexp.MustCompile(`^#:`) // #:
+ reFlagsComments = regexp.MustCompile(`^#,`) // #, fuzzy,c-format
+ rePrevMsgContextComments = regexp.MustCompile(`^#\|\s+msgctxt`) // #| msgctxt
+ rePrevMsgIdComments = regexp.MustCompile(`^#\|\s+msgid`) // #| msgid
+ reStringLineComments = regexp.MustCompile(`^#\|\s+".*"\s*$`) // #| "message"
+
+ reMsgContext = regexp.MustCompile(`^msgctxt\s+".*"\s*$`) // msgctxt
+ reMsgId = regexp.MustCompile(`^msgid\s+".*"\s*$`) // msgid
+ reMsgIdPlural = regexp.MustCompile(`^msgid_plural\s+".*"\s*$`) // msgid_plural
+ reMsgStr = regexp.MustCompile(`^msgstr\s*".*"\s*$`) // msgstr
+ reMsgStrPlural = regexp.MustCompile(`^msgstr\s*(\[\d+\])\s*".*"\s*$`) // msgstr[0]
+ reStringLine = regexp.MustCompile(`^\s*".*"\s*$`) // "message"
+ reBlankLine = regexp.MustCompile(`^\s*$`) //
+)
+
+func (p *Message) isInvalidLine(s string) bool {
+ if reComment.MatchString(s) {
+ return false
+ }
+ if reBlankLine.MatchString(s) {
+ return false
+ }
+
+ if reMsgContext.MatchString(s) {
+ return false
+ }
+ if reMsgId.MatchString(s) {
+ return false
+ }
+ if reMsgIdPlural.MatchString(s) {
+ return false
+ }
+ if reMsgStr.MatchString(s) {
+ return false
+ }
+ if reMsgStrPlural.MatchString(s) {
+ return false
+ }
+
+ if reStringLine.MatchString(s) {
+ return false
+ }
+
+ return true
+}
diff --git a/vendor/github.com/chai2010/gettext-go/po/util.go b/vendor/github.com/chai2010/gettext-go/po/util.go
new file mode 100644
index 0000000000..1a0928b111
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/po/util.go
@@ -0,0 +1,121 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package po
+
+import (
+ "bytes"
+ "strings"
+)
+
+func decodePoString(text string) string {
+ lines := strings.Split(text, "\n")
+ for i := 0; i < len(lines); i++ {
+ left := strings.Index(lines[i], `"`)
+ right := strings.LastIndex(lines[i], `"`)
+ if left < 0 || right < 0 || left == right {
+ lines[i] = ""
+ continue
+ }
+ line := lines[i][left+1 : right]
+ data := make([]byte, 0, len(line))
+ for i := 0; i < len(line); i++ {
+ if line[i] != '\\' {
+ data = append(data, line[i])
+ continue
+ }
+ if i+1 >= len(line) {
+ break
+ }
+ switch line[i+1] {
+ case 'r': // \\r -> \r
+ data = append(data, '\r')
+ i++
+ case 'n': // \\n -> \n
+ data = append(data, '\n')
+ i++
+ case 't': // \\t -> \n
+ data = append(data, '\t')
+ i++
+ case '\\': // \\\ -> ?
+ data = append(data, '\\')
+ i++
+ }
+ }
+ lines[i] = string(data)
+ }
+ return strings.Join(lines, "")
+}
+
+func encodePoString(text string) string {
+ var buf bytes.Buffer
+ lines := strings.Split(text, "\n")
+ for i := 0; i < len(lines); i++ {
+ if lines[i] == "" {
+ if i != len(lines)-1 {
+ buf.WriteString(`"\n"` + "\n")
+ }
+ continue
+ }
+ buf.WriteRune('"')
+ for _, r := range lines[i] {
+ switch r {
+ case '\\':
+ buf.WriteString(`\\`)
+ case '"':
+ buf.WriteString(`\"`)
+ case '\r':
+ buf.WriteString(`\r`)
+ case '\n':
+ buf.WriteString(`\n`)
+ case '\t':
+ buf.WriteString(`\t`)
+ default:
+ buf.WriteRune(r)
+ }
+ }
+ if i < len(lines)-1 {
+ buf.WriteString(`\n"` + "\n")
+ } else {
+ buf.WriteString(`"` + "\n")
+ }
+ }
+ return buf.String()
+}
+
+func encodeCommentPoString(text string) string {
+ var buf bytes.Buffer
+ lines := strings.Split(text, "\n")
+ if len(lines) > 1 {
+ buf.WriteString(`""` + "\n")
+ }
+ for i := 0; i < len(lines); i++ {
+ if len(lines) > 0 {
+ buf.WriteString("#| ")
+ }
+ buf.WriteRune('"')
+ for _, r := range lines[i] {
+ switch r {
+ case '\\':
+ buf.WriteString(`\\`)
+ case '"':
+ buf.WriteString(`\"`)
+ case '\r':
+ buf.WriteString(`\r`)
+ case '\n':
+ buf.WriteString(`\n`)
+ case '\t':
+ buf.WriteString(`\t`)
+ default:
+ buf.WriteRune(r)
+ }
+ }
+ if i < len(lines)-1 {
+ buf.WriteString(`\n"` + "\n")
+ } else {
+ buf.WriteString(`"`)
+ }
+ }
+ return buf.String()
+}
diff --git a/vendor/github.com/chai2010/gettext-go/tr.go b/vendor/github.com/chai2010/gettext-go/tr.go
new file mode 100644
index 0000000000..5b9d08f426
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/tr.go
@@ -0,0 +1,175 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gettext
+
+import (
+ "encoding/json"
+
+ "github.com/chai2010/gettext-go/mo"
+ "github.com/chai2010/gettext-go/plural"
+ "github.com/chai2010/gettext-go/po"
+)
+
+var nilTranslator = &translator{
+ MessageMap: make(map[string]mo.Message),
+ PluralFormula: plural.Formula("??"),
+}
+
+type translator struct {
+ MessageMap map[string]mo.Message
+ PluralFormula func(n int) int
+}
+
+func newMoTranslator(name string, data []byte) (*translator, error) {
+ var (
+ f *mo.File
+ err error
+ )
+ if len(data) != 0 {
+ f, err = mo.Load(data)
+ } else {
+ f, err = mo.LoadFile(name)
+ }
+ if err != nil {
+ return nil, err
+ }
+ var tr = &translator{
+ MessageMap: make(map[string]mo.Message),
+ }
+ for _, v := range f.Messages {
+ tr.MessageMap[tr.makeMapKey(v.MsgContext, v.MsgId)] = v
+ }
+ if lang := f.MimeHeader.Language; lang != "" {
+ tr.PluralFormula = plural.Formula(lang)
+ } else {
+ tr.PluralFormula = plural.Formula("??")
+ }
+ return tr, nil
+}
+
+func newPoTranslator(name string, data []byte) (*translator, error) {
+ var (
+ f *po.File
+ err error
+ )
+ if len(data) != 0 {
+ f, err = po.Load(data)
+ } else {
+ f, err = po.LoadFile(name)
+ }
+ if err != nil {
+ return nil, err
+ }
+ var tr = &translator{
+ MessageMap: make(map[string]mo.Message),
+ }
+ for _, v := range f.Messages {
+ tr.MessageMap[tr.makeMapKey(v.MsgContext, v.MsgId)] = mo.Message{
+ MsgContext: v.MsgContext,
+ MsgId: v.MsgId,
+ MsgIdPlural: v.MsgIdPlural,
+ MsgStr: v.MsgStr,
+ MsgStrPlural: v.MsgStrPlural,
+ }
+ }
+ if lang := f.MimeHeader.Language; lang != "" {
+ tr.PluralFormula = plural.Formula(lang)
+ } else {
+ tr.PluralFormula = plural.Formula("??")
+ }
+ return tr, nil
+}
+
+func newJsonTranslator(lang, name string, jsonData []byte) (*translator, error) {
+ var msgList []struct {
+ MsgContext string `json:"msgctxt"` // msgctxt context
+ MsgId string `json:"msgid"` // msgid untranslated-string
+ MsgIdPlural string `json:"msgid_plural"` // msgid_plural untranslated-string-plural
+ MsgStr []string `json:"msgstr"` // msgstr translated-string
+ }
+ if err := json.Unmarshal(jsonData, &msgList); err != nil {
+ return nil, err
+ }
+
+ var tr = &translator{
+ MessageMap: make(map[string]mo.Message),
+ PluralFormula: plural.Formula(lang),
+ }
+
+ for _, v := range msgList {
+ var v_MsgStr string
+ var v_MsgStrPlural = v.MsgStr
+
+ if len(v.MsgStr) != 0 {
+ v_MsgStr = v.MsgStr[0]
+ }
+
+ tr.MessageMap[tr.makeMapKey(v.MsgContext, v.MsgId)] = mo.Message{
+ MsgContext: v.MsgContext,
+ MsgId: v.MsgId,
+ MsgIdPlural: v.MsgIdPlural,
+ MsgStr: v_MsgStr,
+ MsgStrPlural: v_MsgStrPlural,
+ }
+ }
+ return tr, nil
+}
+
+func (p *translator) PGettext(msgctxt, msgid string) string {
+ return p.findMsgStr(msgctxt, msgid)
+}
+
+func (p *translator) PNGettext(msgctxt, msgid, msgidPlural string, n int) string {
+ n = p.PluralFormula(n)
+ if ss := p.findMsgStrPlural(msgctxt, msgid, msgidPlural); len(ss) != 0 {
+ if n >= len(ss) {
+ n = len(ss) - 1
+ }
+ if ss[n] != "" {
+ return ss[n]
+ }
+ }
+ if msgidPlural != "" && n > 0 {
+ return msgidPlural
+ }
+ return msgid
+}
+
+func (p *translator) findMsgStr(msgctxt, msgid string) string {
+ key := p.makeMapKey(msgctxt, msgid)
+ if v, ok := p.MessageMap[key]; ok {
+ if v.MsgStr != "" {
+ return v.MsgStr
+ }
+ }
+ return msgid
+}
+
+func (p *translator) findMsgStrPlural(msgctxt, msgid, msgidPlural string) []string {
+ key := p.makeMapKey(msgctxt, msgid)
+ if v, ok := p.MessageMap[key]; ok {
+ if len(v.MsgIdPlural) != 0 {
+ if len(v.MsgStrPlural) != 0 {
+ return v.MsgStrPlural
+ } else {
+ return nil
+ }
+ } else {
+ if len(v.MsgStr) != 0 {
+ return []string{v.MsgStr}
+ } else {
+ return nil
+ }
+ }
+ }
+ return nil
+}
+
+func (p *translator) makeMapKey(msgctxt, msgid string) string {
+ if msgctxt != "" {
+ return msgctxt + mo.EotSeparator + msgid
+ }
+ return msgid
+}
diff --git a/vendor/github.com/chai2010/gettext-go/util.go b/vendor/github.com/chai2010/gettext-go/util.go
new file mode 100644
index 0000000000..b8269a605c
--- /dev/null
+++ b/vendor/github.com/chai2010/gettext-go/util.go
@@ -0,0 +1,34 @@
+// Copyright 2013 ChaiShushan . All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gettext
+
+import (
+ "os"
+ "strings"
+)
+
+func getDefaultLanguage() string {
+ if v := os.Getenv("LC_MESSAGES"); v != "" {
+ return simplifiedLanguage(v)
+ }
+ if v := os.Getenv("LANG"); v != "" {
+ return simplifiedLanguage(v)
+ }
+ return "default"
+}
+
+func simplifiedLanguage(lang string) string {
+ // en_US/en_US.UTF-8/zh_CN/zh_TW/el_GR@euro/...
+ if idx := strings.Index(lang, ":"); idx != -1 {
+ lang = lang[:idx]
+ }
+ if idx := strings.Index(lang, "@"); idx != -1 {
+ lang = lang[:idx]
+ }
+ if idx := strings.Index(lang, "."); idx != -1 {
+ lang = lang[:idx]
+ }
+ return strings.TrimSpace(lang)
+}
diff --git a/vendor/github.com/cncf/xds/go/xds/data/orca/v3/orca_load_report.pb.go b/vendor/github.com/cncf/xds/go/xds/data/orca/v3/orca_load_report.pb.go
index f929ca6374..44db331868 100644
--- a/vendor/github.com/cncf/xds/go/xds/data/orca/v3/orca_load_report.pb.go
+++ b/vendor/github.com/cncf/xds/go/xds/data/orca/v3/orca_load_report.pb.go
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.33.0
-// protoc v5.29.1
+// protoc-gen-go v1.36.10
+// protoc v5.29.3
// source: xds/data/orca/v3/orca_load_report.proto
package v3
@@ -12,6 +12,7 @@ import (
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
+ unsafe "unsafe"
)
const (
@@ -22,29 +23,26 @@ const (
)
type OrcaLoadReport struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- CpuUtilization float64 `protobuf:"fixed64,1,opt,name=cpu_utilization,json=cpuUtilization,proto3" json:"cpu_utilization,omitempty"`
- MemUtilization float64 `protobuf:"fixed64,2,opt,name=mem_utilization,json=memUtilization,proto3" json:"mem_utilization,omitempty"`
+ state protoimpl.MessageState `protogen:"open.v1"`
+ CpuUtilization float64 `protobuf:"fixed64,1,opt,name=cpu_utilization,json=cpuUtilization,proto3" json:"cpu_utilization,omitempty"`
+ MemUtilization float64 `protobuf:"fixed64,2,opt,name=mem_utilization,json=memUtilization,proto3" json:"mem_utilization,omitempty"`
// Deprecated: Marked as deprecated in xds/data/orca/v3/orca_load_report.proto.
Rps uint64 `protobuf:"varint,3,opt,name=rps,proto3" json:"rps,omitempty"`
- RequestCost map[string]float64 `protobuf:"bytes,4,rep,name=request_cost,json=requestCost,proto3" json:"request_cost,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"fixed64,2,opt,name=value,proto3"`
- Utilization map[string]float64 `protobuf:"bytes,5,rep,name=utilization,proto3" json:"utilization,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"fixed64,2,opt,name=value,proto3"`
+ RequestCost map[string]float64 `protobuf:"bytes,4,rep,name=request_cost,json=requestCost,proto3" json:"request_cost,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"fixed64,2,opt,name=value"`
+ Utilization map[string]float64 `protobuf:"bytes,5,rep,name=utilization,proto3" json:"utilization,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"fixed64,2,opt,name=value"`
RpsFractional float64 `protobuf:"fixed64,6,opt,name=rps_fractional,json=rpsFractional,proto3" json:"rps_fractional,omitempty"`
Eps float64 `protobuf:"fixed64,7,opt,name=eps,proto3" json:"eps,omitempty"`
- NamedMetrics map[string]float64 `protobuf:"bytes,8,rep,name=named_metrics,json=namedMetrics,proto3" json:"named_metrics,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"fixed64,2,opt,name=value,proto3"`
+ NamedMetrics map[string]float64 `protobuf:"bytes,8,rep,name=named_metrics,json=namedMetrics,proto3" json:"named_metrics,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"fixed64,2,opt,name=value"`
ApplicationUtilization float64 `protobuf:"fixed64,9,opt,name=application_utilization,json=applicationUtilization,proto3" json:"application_utilization,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
}
func (x *OrcaLoadReport) Reset() {
*x = OrcaLoadReport{}
- if protoimpl.UnsafeEnabled {
- mi := &file_xds_data_orca_v3_orca_load_report_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_xds_data_orca_v3_orca_load_report_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *OrcaLoadReport) String() string {
@@ -55,7 +53,7 @@ func (*OrcaLoadReport) ProtoMessage() {}
func (x *OrcaLoadReport) ProtoReflect() protoreflect.Message {
mi := &file_xds_data_orca_v3_orca_load_report_proto_msgTypes[0]
- if protoimpl.UnsafeEnabled && x != nil {
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -136,86 +134,44 @@ func (x *OrcaLoadReport) GetApplicationUtilization() float64 {
var File_xds_data_orca_v3_orca_load_report_proto protoreflect.FileDescriptor
-var file_xds_data_orca_v3_orca_load_report_proto_rawDesc = []byte{
- 0x0a, 0x27, 0x78, 0x64, 0x73, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x6f, 0x72, 0x63, 0x61, 0x2f,
- 0x76, 0x33, 0x2f, 0x6f, 0x72, 0x63, 0x61, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x72, 0x65, 0x70,
- 0x6f, 0x72, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x78, 0x64, 0x73, 0x2e, 0x64,
- 0x61, 0x74, 0x61, 0x2e, 0x6f, 0x72, 0x63, 0x61, 0x2e, 0x76, 0x33, 0x1a, 0x17, 0x76, 0x61, 0x6c,
- 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70,
- 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa6, 0x06, 0x0a, 0x0e, 0x4f, 0x72, 0x63, 0x61, 0x4c, 0x6f, 0x61,
- 0x64, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x37, 0x0a, 0x0f, 0x63, 0x70, 0x75, 0x5f, 0x75,
- 0x74, 0x69, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01,
- 0x42, 0x0e, 0xfa, 0x42, 0x0b, 0x12, 0x09, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x52, 0x0e, 0x63, 0x70, 0x75, 0x55, 0x74, 0x69, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x12, 0x40, 0x0a, 0x0f, 0x6d, 0x65, 0x6d, 0x5f, 0x75, 0x74, 0x69, 0x6c, 0x69, 0x7a, 0x61, 0x74,
- 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x42, 0x17, 0xfa, 0x42, 0x14, 0x12, 0x12,
- 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x52, 0x0e, 0x6d, 0x65, 0x6d, 0x55, 0x74, 0x69, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x03, 0x72, 0x70, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x42,
- 0x02, 0x18, 0x01, 0x52, 0x03, 0x72, 0x70, 0x73, 0x12, 0x54, 0x0a, 0x0c, 0x72, 0x65, 0x71, 0x75,
- 0x65, 0x73, 0x74, 0x5f, 0x63, 0x6f, 0x73, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31,
- 0x2e, 0x78, 0x64, 0x73, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x6f, 0x72, 0x63, 0x61, 0x2e, 0x76,
- 0x33, 0x2e, 0x4f, 0x72, 0x63, 0x61, 0x4c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74,
- 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x73, 0x74, 0x45, 0x6e, 0x74, 0x72,
- 0x79, 0x52, 0x0b, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x73, 0x74, 0x12, 0x71,
- 0x0a, 0x0b, 0x75, 0x74, 0x69, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20,
- 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x78, 0x64, 0x73, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x6f,
- 0x72, 0x63, 0x61, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x63, 0x61, 0x4c, 0x6f, 0x61, 0x64, 0x52,
- 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x55, 0x74, 0x69, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x1c, 0xfa, 0x42, 0x19, 0x9a, 0x01, 0x16, 0x2a, 0x14,
- 0x12, 0x12, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0x29, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x52, 0x0b, 0x75, 0x74, 0x69, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x12, 0x35, 0x0a, 0x0e, 0x72, 0x70, 0x73, 0x5f, 0x66, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f,
- 0x6e, 0x61, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x01, 0x42, 0x0e, 0xfa, 0x42, 0x0b, 0x12, 0x09,
- 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x0d, 0x72, 0x70, 0x73, 0x46, 0x72,
- 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x12, 0x20, 0x0a, 0x03, 0x65, 0x70, 0x73, 0x18,
- 0x07, 0x20, 0x01, 0x28, 0x01, 0x42, 0x0e, 0xfa, 0x42, 0x0b, 0x12, 0x09, 0x29, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x03, 0x65, 0x70, 0x73, 0x12, 0x57, 0x0a, 0x0d, 0x6e, 0x61,
- 0x6d, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28,
- 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x64, 0x73, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x6f, 0x72, 0x63,
- 0x61, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x63, 0x61, 0x4c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x70,
- 0x6f, 0x72, 0x74, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
- 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x4d, 0x65, 0x74, 0x72,
- 0x69, 0x63, 0x73, 0x12, 0x47, 0x0a, 0x17, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x5f, 0x75, 0x74, 0x69, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09,
- 0x20, 0x01, 0x28, 0x01, 0x42, 0x0e, 0xfa, 0x42, 0x0b, 0x12, 0x09, 0x29, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x52, 0x16, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x55, 0x74, 0x69, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x3e, 0x0a, 0x10,
- 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x73, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79,
- 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
- 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
- 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3e, 0x0a, 0x10,
- 0x55, 0x74, 0x69, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x74, 0x72, 0x79,
- 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
- 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
- 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3f, 0x0a, 0x11,
- 0x4e, 0x61, 0x6d, 0x65, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x74, 0x72,
- 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
- 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
- 0x28, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x5d, 0x0a,
- 0x1b, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x78, 0x64, 0x73, 0x2e,
- 0x64, 0x61, 0x74, 0x61, 0x2e, 0x6f, 0x72, 0x63, 0x61, 0x2e, 0x76, 0x33, 0x42, 0x13, 0x4f, 0x72,
- 0x63, 0x61, 0x4c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x74,
- 0x6f, 0x50, 0x01, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
- 0x63, 0x6e, 0x63, 0x66, 0x2f, 0x78, 0x64, 0x73, 0x2f, 0x67, 0x6f, 0x2f, 0x78, 0x64, 0x73, 0x2f,
- 0x64, 0x61, 0x74, 0x61, 0x2f, 0x6f, 0x72, 0x63, 0x61, 0x2f, 0x76, 0x33, 0x62, 0x06, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x33,
-}
+const file_xds_data_orca_v3_orca_load_report_proto_rawDesc = "" +
+ "\n" +
+ "'xds/data/orca/v3/orca_load_report.proto\x12\x10xds.data.orca.v3\x1a\x17validate/validate.proto\"\xa6\x06\n" +
+ "\x0eOrcaLoadReport\x127\n" +
+ "\x0fcpu_utilization\x18\x01 \x01(\x01B\x0e\xfaB\v\x12\t)\x00\x00\x00\x00\x00\x00\x00\x00R\x0ecpuUtilization\x12@\n" +
+ "\x0fmem_utilization\x18\x02 \x01(\x01B\x17\xfaB\x14\x12\x12\x19\x00\x00\x00\x00\x00\x00\xf0?)\x00\x00\x00\x00\x00\x00\x00\x00R\x0ememUtilization\x12\x14\n" +
+ "\x03rps\x18\x03 \x01(\x04B\x02\x18\x01R\x03rps\x12T\n" +
+ "\frequest_cost\x18\x04 \x03(\v21.xds.data.orca.v3.OrcaLoadReport.RequestCostEntryR\vrequestCost\x12q\n" +
+ "\vutilization\x18\x05 \x03(\v21.xds.data.orca.v3.OrcaLoadReport.UtilizationEntryB\x1c\xfaB\x19\x9a\x01\x16*\x14\x12\x12\x19\x00\x00\x00\x00\x00\x00\xf0?)\x00\x00\x00\x00\x00\x00\x00\x00R\vutilization\x125\n" +
+ "\x0erps_fractional\x18\x06 \x01(\x01B\x0e\xfaB\v\x12\t)\x00\x00\x00\x00\x00\x00\x00\x00R\rrpsFractional\x12 \n" +
+ "\x03eps\x18\a \x01(\x01B\x0e\xfaB\v\x12\t)\x00\x00\x00\x00\x00\x00\x00\x00R\x03eps\x12W\n" +
+ "\rnamed_metrics\x18\b \x03(\v22.xds.data.orca.v3.OrcaLoadReport.NamedMetricsEntryR\fnamedMetrics\x12G\n" +
+ "\x17application_utilization\x18\t \x01(\x01B\x0e\xfaB\v\x12\t)\x00\x00\x00\x00\x00\x00\x00\x00R\x16applicationUtilization\x1a>\n" +
+ "\x10RequestCostEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\x01R\x05value:\x028\x01\x1a>\n" +
+ "\x10UtilizationEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\x01R\x05value:\x028\x01\x1a?\n" +
+ "\x11NamedMetricsEntry\x12\x10\n" +
+ "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
+ "\x05value\x18\x02 \x01(\x01R\x05value:\x028\x01B]\n" +
+ "\x1bcom.github.xds.data.orca.v3B\x13OrcaLoadReportProtoP\x01Z'github.com/cncf/xds/go/xds/data/orca/v3b\x06proto3"
var (
file_xds_data_orca_v3_orca_load_report_proto_rawDescOnce sync.Once
- file_xds_data_orca_v3_orca_load_report_proto_rawDescData = file_xds_data_orca_v3_orca_load_report_proto_rawDesc
+ file_xds_data_orca_v3_orca_load_report_proto_rawDescData []byte
)
func file_xds_data_orca_v3_orca_load_report_proto_rawDescGZIP() []byte {
file_xds_data_orca_v3_orca_load_report_proto_rawDescOnce.Do(func() {
- file_xds_data_orca_v3_orca_load_report_proto_rawDescData = protoimpl.X.CompressGZIP(file_xds_data_orca_v3_orca_load_report_proto_rawDescData)
+ file_xds_data_orca_v3_orca_load_report_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_xds_data_orca_v3_orca_load_report_proto_rawDesc), len(file_xds_data_orca_v3_orca_load_report_proto_rawDesc)))
})
return file_xds_data_orca_v3_orca_load_report_proto_rawDescData
}
var file_xds_data_orca_v3_orca_load_report_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
-var file_xds_data_orca_v3_orca_load_report_proto_goTypes = []interface{}{
+var file_xds_data_orca_v3_orca_load_report_proto_goTypes = []any{
(*OrcaLoadReport)(nil), // 0: xds.data.orca.v3.OrcaLoadReport
nil, // 1: xds.data.orca.v3.OrcaLoadReport.RequestCostEntry
nil, // 2: xds.data.orca.v3.OrcaLoadReport.UtilizationEntry
@@ -237,25 +193,11 @@ func file_xds_data_orca_v3_orca_load_report_proto_init() {
if File_xds_data_orca_v3_orca_load_report_proto != nil {
return
}
- if !protoimpl.UnsafeEnabled {
- file_xds_data_orca_v3_orca_load_report_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*OrcaLoadReport); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- }
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: file_xds_data_orca_v3_orca_load_report_proto_rawDesc,
+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_xds_data_orca_v3_orca_load_report_proto_rawDesc), len(file_xds_data_orca_v3_orca_load_report_proto_rawDesc)),
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
@@ -266,7 +208,6 @@ func file_xds_data_orca_v3_orca_load_report_proto_init() {
MessageInfos: file_xds_data_orca_v3_orca_load_report_proto_msgTypes,
}.Build()
File_xds_data_orca_v3_orca_load_report_proto = out.File
- file_xds_data_orca_v3_orca_load_report_proto_rawDesc = nil
file_xds_data_orca_v3_orca_load_report_proto_goTypes = nil
file_xds_data_orca_v3_orca_load_report_proto_depIdxs = nil
}
diff --git a/vendor/github.com/cncf/xds/go/xds/data/orca/v3/orca_load_report.pb.validate.go b/vendor/github.com/cncf/xds/go/xds/data/orca/v3/orca_load_report.pb.validate.go
index 8dd55330ac..b9f63bc7d2 100644
--- a/vendor/github.com/cncf/xds/go/xds/data/orca/v3/orca_load_report.pb.validate.go
+++ b/vendor/github.com/cncf/xds/go/xds/data/orca/v3/orca_load_report.pb.validate.go
@@ -160,7 +160,7 @@ type OrcaLoadReportMultiError []error
// Error returns a concatenation of all the error messages it wraps.
func (m OrcaLoadReportMultiError) Error() string {
- var msgs []string
+ msgs := make([]string, 0, len(m))
for _, err := range m {
msgs = append(msgs, err.Error())
}
diff --git a/vendor/github.com/cncf/xds/go/xds/service/orca/v3/orca.pb.go b/vendor/github.com/cncf/xds/go/xds/service/orca/v3/orca.pb.go
index 32e4a37bc8..35ac9b6f3a 100644
--- a/vendor/github.com/cncf/xds/go/xds/service/orca/v3/orca.pb.go
+++ b/vendor/github.com/cncf/xds/go/xds/service/orca/v3/orca.pb.go
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.33.0
-// protoc v5.29.1
+// protoc-gen-go v1.36.10
+// protoc v5.29.3
// source: xds/service/orca/v3/orca.proto
package v3
@@ -13,6 +13,7 @@ import (
durationpb "google.golang.org/protobuf/types/known/durationpb"
reflect "reflect"
sync "sync"
+ unsafe "unsafe"
)
const (
@@ -23,21 +24,18 @@ const (
)
type OrcaLoadReportRequest struct {
- state protoimpl.MessageState
- sizeCache protoimpl.SizeCache
- unknownFields protoimpl.UnknownFields
-
- ReportInterval *durationpb.Duration `protobuf:"bytes,1,opt,name=report_interval,json=reportInterval,proto3" json:"report_interval,omitempty"`
- RequestCostNames []string `protobuf:"bytes,2,rep,name=request_cost_names,json=requestCostNames,proto3" json:"request_cost_names,omitempty"`
+ state protoimpl.MessageState `protogen:"open.v1"`
+ ReportInterval *durationpb.Duration `protobuf:"bytes,1,opt,name=report_interval,json=reportInterval,proto3" json:"report_interval,omitempty"`
+ RequestCostNames []string `protobuf:"bytes,2,rep,name=request_cost_names,json=requestCostNames,proto3" json:"request_cost_names,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
}
func (x *OrcaLoadReportRequest) Reset() {
*x = OrcaLoadReportRequest{}
- if protoimpl.UnsafeEnabled {
- mi := &file_xds_service_orca_v3_orca_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
- }
+ mi := &file_xds_service_orca_v3_orca_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
}
func (x *OrcaLoadReportRequest) String() string {
@@ -48,7 +46,7 @@ func (*OrcaLoadReportRequest) ProtoMessage() {}
func (x *OrcaLoadReportRequest) ProtoReflect() protoreflect.Message {
mi := &file_xds_service_orca_v3_orca_proto_msgTypes[0]
- if protoimpl.UnsafeEnabled && x != nil {
+ if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
@@ -79,54 +77,30 @@ func (x *OrcaLoadReportRequest) GetRequestCostNames() []string {
var File_xds_service_orca_v3_orca_proto protoreflect.FileDescriptor
-var file_xds_service_orca_v3_orca_proto_rawDesc = []byte{
- 0x0a, 0x1e, 0x78, 0x64, 0x73, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x6f, 0x72,
- 0x63, 0x61, 0x2f, 0x76, 0x33, 0x2f, 0x6f, 0x72, 0x63, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
- 0x12, 0x13, 0x78, 0x64, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x6f, 0x72,
- 0x63, 0x61, 0x2e, 0x76, 0x33, 0x1a, 0x27, 0x78, 0x64, 0x73, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x2f,
- 0x6f, 0x72, 0x63, 0x61, 0x2f, 0x76, 0x33, 0x2f, 0x6f, 0x72, 0x63, 0x61, 0x5f, 0x6c, 0x6f, 0x61,
- 0x64, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e,
- 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f,
- 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x89,
- 0x01, 0x0a, 0x15, 0x4f, 0x72, 0x63, 0x61, 0x4c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x70, 0x6f, 0x72,
- 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x0f, 0x72, 0x65, 0x70, 0x6f,
- 0x72, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
- 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0e, 0x72, 0x65,
- 0x70, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x2c, 0x0a, 0x12,
- 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x6f, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d,
- 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73,
- 0x74, 0x43, 0x6f, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x32, 0x75, 0x0a, 0x0e, 0x4f, 0x70,
- 0x65, 0x6e, 0x52, 0x63, 0x61, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x63, 0x0a, 0x11,
- 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x72, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
- 0x73, 0x12, 0x2a, 0x2e, 0x78, 0x64, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e,
- 0x6f, 0x72, 0x63, 0x61, 0x2e, 0x76, 0x33, 0x2e, 0x4f, 0x72, 0x63, 0x61, 0x4c, 0x6f, 0x61, 0x64,
- 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e,
- 0x78, 0x64, 0x73, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x6f, 0x72, 0x63, 0x61, 0x2e, 0x76, 0x33,
- 0x2e, 0x4f, 0x72, 0x63, 0x61, 0x4c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x30,
- 0x01, 0x42, 0x59, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
- 0x78, 0x64, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x6f, 0x72, 0x63, 0x61,
- 0x2e, 0x76, 0x33, 0x42, 0x09, 0x4f, 0x72, 0x63, 0x61, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01,
- 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6e, 0x63,
- 0x66, 0x2f, 0x78, 0x64, 0x73, 0x2f, 0x67, 0x6f, 0x2f, 0x78, 0x64, 0x73, 0x2f, 0x73, 0x65, 0x72,
- 0x76, 0x69, 0x63, 0x65, 0x2f, 0x6f, 0x72, 0x63, 0x61, 0x2f, 0x76, 0x33, 0x62, 0x06, 0x70, 0x72,
- 0x6f, 0x74, 0x6f, 0x33,
-}
+const file_xds_service_orca_v3_orca_proto_rawDesc = "" +
+ "\n" +
+ "\x1exds/service/orca/v3/orca.proto\x12\x13xds.service.orca.v3\x1a'xds/data/orca/v3/orca_load_report.proto\x1a\x1egoogle/protobuf/duration.proto\"\x89\x01\n" +
+ "\x15OrcaLoadReportRequest\x12B\n" +
+ "\x0freport_interval\x18\x01 \x01(\v2\x19.google.protobuf.DurationR\x0ereportInterval\x12,\n" +
+ "\x12request_cost_names\x18\x02 \x03(\tR\x10requestCostNames2u\n" +
+ "\x0eOpenRcaService\x12c\n" +
+ "\x11StreamCoreMetrics\x12*.xds.service.orca.v3.OrcaLoadReportRequest\x1a .xds.data.orca.v3.OrcaLoadReport0\x01BY\n" +
+ "\x1ecom.github.xds.service.orca.v3B\tOrcaProtoP\x01Z*github.com/cncf/xds/go/xds/service/orca/v3b\x06proto3"
var (
file_xds_service_orca_v3_orca_proto_rawDescOnce sync.Once
- file_xds_service_orca_v3_orca_proto_rawDescData = file_xds_service_orca_v3_orca_proto_rawDesc
+ file_xds_service_orca_v3_orca_proto_rawDescData []byte
)
func file_xds_service_orca_v3_orca_proto_rawDescGZIP() []byte {
file_xds_service_orca_v3_orca_proto_rawDescOnce.Do(func() {
- file_xds_service_orca_v3_orca_proto_rawDescData = protoimpl.X.CompressGZIP(file_xds_service_orca_v3_orca_proto_rawDescData)
+ file_xds_service_orca_v3_orca_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_xds_service_orca_v3_orca_proto_rawDesc), len(file_xds_service_orca_v3_orca_proto_rawDesc)))
})
return file_xds_service_orca_v3_orca_proto_rawDescData
}
var file_xds_service_orca_v3_orca_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
-var file_xds_service_orca_v3_orca_proto_goTypes = []interface{}{
+var file_xds_service_orca_v3_orca_proto_goTypes = []any{
(*OrcaLoadReportRequest)(nil), // 0: xds.service.orca.v3.OrcaLoadReportRequest
(*durationpb.Duration)(nil), // 1: google.protobuf.Duration
(*v3.OrcaLoadReport)(nil), // 2: xds.data.orca.v3.OrcaLoadReport
@@ -147,25 +121,11 @@ func file_xds_service_orca_v3_orca_proto_init() {
if File_xds_service_orca_v3_orca_proto != nil {
return
}
- if !protoimpl.UnsafeEnabled {
- file_xds_service_orca_v3_orca_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
- switch v := v.(*OrcaLoadReportRequest); i {
- case 0:
- return &v.state
- case 1:
- return &v.sizeCache
- case 2:
- return &v.unknownFields
- default:
- return nil
- }
- }
- }
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor: file_xds_service_orca_v3_orca_proto_rawDesc,
+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_xds_service_orca_v3_orca_proto_rawDesc), len(file_xds_service_orca_v3_orca_proto_rawDesc)),
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
@@ -176,7 +136,6 @@ func file_xds_service_orca_v3_orca_proto_init() {
MessageInfos: file_xds_service_orca_v3_orca_proto_msgTypes,
}.Build()
File_xds_service_orca_v3_orca_proto = out.File
- file_xds_service_orca_v3_orca_proto_rawDesc = nil
file_xds_service_orca_v3_orca_proto_goTypes = nil
file_xds_service_orca_v3_orca_proto_depIdxs = nil
}
diff --git a/vendor/github.com/cncf/xds/go/xds/service/orca/v3/orca.pb.validate.go b/vendor/github.com/cncf/xds/go/xds/service/orca/v3/orca.pb.validate.go
index 8949e8372b..198b81a3d9 100644
--- a/vendor/github.com/cncf/xds/go/xds/service/orca/v3/orca.pb.validate.go
+++ b/vendor/github.com/cncf/xds/go/xds/service/orca/v3/orca.pb.validate.go
@@ -100,7 +100,7 @@ type OrcaLoadReportRequestMultiError []error
// Error returns a concatenation of all the error messages it wraps.
func (m OrcaLoadReportRequestMultiError) Error() string {
- var msgs []string
+ msgs := make([]string, 0, len(m))
for _, err := range m {
msgs = append(msgs, err.Error())
}
diff --git a/vendor/github.com/cncf/xds/go/xds/service/orca/v3/orca_grpc.pb.go b/vendor/github.com/cncf/xds/go/xds/service/orca/v3/orca_grpc.pb.go
index 8a92439e07..f0666e2e14 100644
--- a/vendor/github.com/cncf/xds/go/xds/service/orca/v3/orca_grpc.pb.go
+++ b/vendor/github.com/cncf/xds/go/xds/service/orca/v3/orca_grpc.pb.go
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
-// - protoc-gen-go-grpc v1.3.0
-// - protoc v5.29.1
+// - protoc-gen-go-grpc v1.5.1
+// - protoc v5.29.3
// source: xds/service/orca/v3/orca.proto
package v3
@@ -16,8 +16,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.32.0 or later.
-const _ = grpc.SupportPackageIsVersion7
+// Requires gRPC-Go v1.64.0 or later.
+const _ = grpc.SupportPackageIsVersion9
const (
OpenRcaService_StreamCoreMetrics_FullMethodName = "/xds.service.orca.v3.OpenRcaService/StreamCoreMetrics"
@@ -27,7 +27,7 @@ const (
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type OpenRcaServiceClient interface {
- StreamCoreMetrics(ctx context.Context, in *OrcaLoadReportRequest, opts ...grpc.CallOption) (OpenRcaService_StreamCoreMetricsClient, error)
+ StreamCoreMetrics(ctx context.Context, in *OrcaLoadReportRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[v3.OrcaLoadReport], error)
}
type openRcaServiceClient struct {
@@ -38,12 +38,13 @@ func NewOpenRcaServiceClient(cc grpc.ClientConnInterface) OpenRcaServiceClient {
return &openRcaServiceClient{cc}
}
-func (c *openRcaServiceClient) StreamCoreMetrics(ctx context.Context, in *OrcaLoadReportRequest, opts ...grpc.CallOption) (OpenRcaService_StreamCoreMetricsClient, error) {
- stream, err := c.cc.NewStream(ctx, &OpenRcaService_ServiceDesc.Streams[0], OpenRcaService_StreamCoreMetrics_FullMethodName, opts...)
+func (c *openRcaServiceClient) StreamCoreMetrics(ctx context.Context, in *OrcaLoadReportRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[v3.OrcaLoadReport], error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ stream, err := c.cc.NewStream(ctx, &OpenRcaService_ServiceDesc.Streams[0], OpenRcaService_StreamCoreMetrics_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
- x := &openRcaServiceStreamCoreMetricsClient{stream}
+ x := &grpc.GenericClientStream[OrcaLoadReportRequest, v3.OrcaLoadReport]{ClientStream: stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
@@ -53,37 +54,27 @@ func (c *openRcaServiceClient) StreamCoreMetrics(ctx context.Context, in *OrcaLo
return x, nil
}
-type OpenRcaService_StreamCoreMetricsClient interface {
- Recv() (*v3.OrcaLoadReport, error)
- grpc.ClientStream
-}
-
-type openRcaServiceStreamCoreMetricsClient struct {
- grpc.ClientStream
-}
-
-func (x *openRcaServiceStreamCoreMetricsClient) Recv() (*v3.OrcaLoadReport, error) {
- m := new(v3.OrcaLoadReport)
- 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 OpenRcaService_StreamCoreMetricsClient = grpc.ServerStreamingClient[v3.OrcaLoadReport]
// OpenRcaServiceServer is the server API for OpenRcaService service.
// All implementations should embed UnimplementedOpenRcaServiceServer
-// for forward compatibility
+// for forward compatibility.
type OpenRcaServiceServer interface {
- StreamCoreMetrics(*OrcaLoadReportRequest, OpenRcaService_StreamCoreMetricsServer) error
+ StreamCoreMetrics(*OrcaLoadReportRequest, grpc.ServerStreamingServer[v3.OrcaLoadReport]) error
}
-// UnimplementedOpenRcaServiceServer should be embedded to have forward compatible implementations.
-type UnimplementedOpenRcaServiceServer struct {
-}
+// UnimplementedOpenRcaServiceServer 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 UnimplementedOpenRcaServiceServer struct{}
-func (UnimplementedOpenRcaServiceServer) StreamCoreMetrics(*OrcaLoadReportRequest, OpenRcaService_StreamCoreMetricsServer) error {
+func (UnimplementedOpenRcaServiceServer) StreamCoreMetrics(*OrcaLoadReportRequest, grpc.ServerStreamingServer[v3.OrcaLoadReport]) error {
return status.Errorf(codes.Unimplemented, "method StreamCoreMetrics not implemented")
}
+func (UnimplementedOpenRcaServiceServer) testEmbeddedByValue() {}
// UnsafeOpenRcaServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to OpenRcaServiceServer will
@@ -93,6 +84,13 @@ type UnsafeOpenRcaServiceServer interface {
}
func RegisterOpenRcaServiceServer(s grpc.ServiceRegistrar, srv OpenRcaServiceServer) {
+ // If the following call pancis, it indicates UnimplementedOpenRcaServiceServer 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(&OpenRcaService_ServiceDesc, srv)
}
@@ -101,21 +99,11 @@ func _OpenRcaService_StreamCoreMetrics_Handler(srv interface{}, stream grpc.Serv
if err := stream.RecvMsg(m); err != nil {
return err
}
- return srv.(OpenRcaServiceServer).StreamCoreMetrics(m, &openRcaServiceStreamCoreMetricsServer{stream})
-}
-
-type OpenRcaService_StreamCoreMetricsServer interface {
- Send(*v3.OrcaLoadReport) error
- grpc.ServerStream
+ return srv.(OpenRcaServiceServer).StreamCoreMetrics(m, &grpc.GenericServerStream[OrcaLoadReportRequest, v3.OrcaLoadReport]{ServerStream: stream})
}
-type openRcaServiceStreamCoreMetricsServer struct {
- grpc.ServerStream
-}
-
-func (x *openRcaServiceStreamCoreMetricsServer) Send(m *v3.OrcaLoadReport) 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 OpenRcaService_StreamCoreMetricsServer = grpc.ServerStreamingServer[v3.OrcaLoadReport]
// OpenRcaService_ServiceDesc is the grpc.ServiceDesc for OpenRcaService service.
// It's only intended for direct use with grpc.RegisterService,
diff --git a/vendor/github.com/containerd/containerd/LICENSE b/vendor/github.com/containerd/containerd/LICENSE
new file mode 100644
index 0000000000..584149b6ee
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/LICENSE
@@ -0,0 +1,191 @@
+
+ Apache License
+ Version 2.0, January 2004
+ https://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ Copyright The containerd 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
+
+ https://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.
diff --git a/vendor/github.com/containerd/containerd/NOTICE b/vendor/github.com/containerd/containerd/NOTICE
new file mode 100644
index 0000000000..8915f02773
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/NOTICE
@@ -0,0 +1,16 @@
+Docker
+Copyright 2012-2015 Docker, Inc.
+
+This product includes software developed at Docker, Inc. (https://www.docker.com).
+
+The following is courtesy of our legal counsel:
+
+
+Use and transfer of Docker may be subject to certain restrictions by the
+United States and other governments.
+It is your responsibility to ensure that your use and/or transfer does not
+violate applicable laws.
+
+For more information, please see https://www.bis.doc.gov
+
+See also https://www.apache.org/dev/crypto.html and/or seek legal counsel.
diff --git a/vendor/github.com/containerd/containerd/archive/compression/compression.go b/vendor/github.com/containerd/containerd/archive/compression/compression.go
new file mode 100644
index 0000000000..3c152f2815
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/archive/compression/compression.go
@@ -0,0 +1,327 @@
+/*
+ Copyright The containerd 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 compression
+
+import (
+ "bufio"
+ "bytes"
+ "compress/gzip"
+ "context"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "os"
+ "os/exec"
+ "strconv"
+ "sync"
+
+ "github.com/containerd/log"
+ "github.com/klauspost/compress/zstd"
+)
+
+type (
+ // Compression is the state represents if compressed or not.
+ Compression int
+)
+
+const (
+ // Uncompressed represents the uncompressed.
+ Uncompressed Compression = iota
+ // Gzip is gzip compression algorithm.
+ Gzip
+ // Zstd is zstd compression algorithm.
+ Zstd
+ // Unknown is used when a plugin handles the algorithm.
+ Unknown
+)
+
+const disablePigzEnv = "CONTAINERD_DISABLE_PIGZ"
+
+var (
+ initPigz sync.Once
+ unpigzPath string
+)
+
+var (
+ bufioReader32KPool = &sync.Pool{
+ New: func() interface{} { return bufio.NewReaderSize(nil, 32*1024) },
+ }
+)
+
+// DecompressReadCloser include the stream after decompress and the compress method detected.
+type DecompressReadCloser interface {
+ io.ReadCloser
+ // GetCompression returns the compress method which is used before decompressing
+ GetCompression() Compression
+}
+
+type readCloserWrapper struct {
+ io.Reader
+ compression Compression
+ closer func() error
+}
+
+func (r *readCloserWrapper) Close() error {
+ if r.closer != nil {
+ return r.closer()
+ }
+ return nil
+}
+
+func (r *readCloserWrapper) GetCompression() Compression {
+ return r.compression
+}
+
+type writeCloserWrapper struct {
+ io.Writer
+ closer func() error
+}
+
+func (w *writeCloserWrapper) Close() error {
+ if w.closer != nil {
+ w.closer()
+ }
+ return nil
+}
+
+type bufferedReader struct {
+ buf *bufio.Reader
+}
+
+func newBufferedReader(r io.Reader) *bufferedReader {
+ buf := bufioReader32KPool.Get().(*bufio.Reader)
+ buf.Reset(r)
+ return &bufferedReader{buf}
+}
+
+func (r *bufferedReader) Read(p []byte) (n int, err error) {
+ if r.buf == nil {
+ return 0, io.EOF
+ }
+ n, err = r.buf.Read(p)
+ if err == io.EOF {
+ r.buf.Reset(nil)
+ bufioReader32KPool.Put(r.buf)
+ r.buf = nil
+ }
+ return
+}
+
+func (r *bufferedReader) Peek(n int) ([]byte, error) {
+ if r.buf == nil {
+ return nil, io.EOF
+ }
+ return r.buf.Peek(n)
+}
+
+const (
+ zstdMagicSkippableStart = 0x184D2A50
+ zstdMagicSkippableMask = 0xFFFFFFF0
+)
+
+var (
+ gzipMagic = []byte{0x1F, 0x8B, 0x08}
+ zstdMagic = []byte{0x28, 0xb5, 0x2f, 0xfd}
+)
+
+type matcher = func([]byte) bool
+
+func magicNumberMatcher(m []byte) matcher {
+ return func(source []byte) bool {
+ return bytes.HasPrefix(source, m)
+ }
+}
+
+// zstdMatcher detects zstd compression algorithm.
+// There are two frame formats defined by Zstandard: Zstandard frames and Skippable frames.
+// See https://tools.ietf.org/id/draft-kucherawy-dispatch-zstd-00.html#rfc.section.2 for more details.
+func zstdMatcher() matcher {
+ return func(source []byte) bool {
+ if bytes.HasPrefix(source, zstdMagic) {
+ // Zstandard frame
+ return true
+ }
+ // skippable frame
+ if len(source) < 8 {
+ return false
+ }
+ // magic number from 0x184D2A50 to 0x184D2A5F.
+ if binary.LittleEndian.Uint32(source[:4])&zstdMagicSkippableMask == zstdMagicSkippableStart {
+ return true
+ }
+ return false
+ }
+}
+
+// DetectCompression detects the compression algorithm of the source.
+func DetectCompression(source []byte) Compression {
+ for compression, fn := range map[Compression]matcher{
+ Gzip: magicNumberMatcher(gzipMagic),
+ Zstd: zstdMatcher(),
+ } {
+ if fn(source) {
+ return compression
+ }
+ }
+ return Uncompressed
+}
+
+// DecompressStream decompresses the archive and returns a ReaderCloser with the decompressed archive.
+func DecompressStream(archive io.Reader) (DecompressReadCloser, error) {
+ buf := newBufferedReader(archive)
+ bs, err := buf.Peek(10)
+ if err != nil && err != io.EOF {
+ // Note: we'll ignore any io.EOF error because there are some odd
+ // cases where the layer.tar file will be empty (zero bytes) and
+ // that results in an io.EOF from the Peek() call. So, in those
+ // cases we'll just treat it as a non-compressed stream and
+ // that means just create an empty layer.
+ // See Issue docker/docker#18170
+ return nil, err
+ }
+
+ switch compression := DetectCompression(bs); compression {
+ case Uncompressed:
+ return &readCloserWrapper{
+ Reader: buf,
+ compression: compression,
+ }, nil
+ case Gzip:
+ ctx, cancel := context.WithCancel(context.Background())
+ gzReader, err := gzipDecompress(ctx, buf)
+ if err != nil {
+ cancel()
+ return nil, err
+ }
+
+ return &readCloserWrapper{
+ Reader: gzReader,
+ compression: compression,
+ closer: func() error {
+ cancel()
+ return gzReader.Close()
+ },
+ }, nil
+ case Zstd:
+ zstdReader, err := zstd.NewReader(buf)
+ if err != nil {
+ return nil, err
+ }
+ return &readCloserWrapper{
+ Reader: zstdReader,
+ compression: compression,
+ closer: func() error {
+ zstdReader.Close()
+ return nil
+ },
+ }, nil
+
+ default:
+ return nil, fmt.Errorf("unsupported compression format %s", (&compression).Extension())
+ }
+}
+
+// CompressStream compresses the dest with specified compression algorithm.
+func CompressStream(dest io.Writer, compression Compression) (io.WriteCloser, error) {
+ switch compression {
+ case Uncompressed:
+ return &writeCloserWrapper{dest, nil}, nil
+ case Gzip:
+ return gzip.NewWriter(dest), nil
+ case Zstd:
+ return zstd.NewWriter(dest)
+ default:
+ return nil, fmt.Errorf("unsupported compression format %s", (&compression).Extension())
+ }
+}
+
+// Extension returns the extension of a file that uses the specified compression algorithm.
+func (compression *Compression) Extension() string {
+ switch *compression {
+ case Gzip:
+ return "gz"
+ case Zstd:
+ return "zst"
+ case Unknown:
+ return "unknown"
+ }
+ return ""
+}
+
+func gzipDecompress(ctx context.Context, buf io.Reader) (io.ReadCloser, error) {
+ initPigz.Do(func() {
+ if unpigzPath = detectPigz(); unpigzPath != "" {
+ log.L.Debug("using pigz for decompression")
+ }
+ })
+
+ if unpigzPath == "" {
+ return gzip.NewReader(buf)
+ }
+
+ return cmdStream(exec.CommandContext(ctx, unpigzPath, "-d", "-c"), buf)
+}
+
+func cmdStream(cmd *exec.Cmd, in io.Reader) (io.ReadCloser, error) {
+ reader, writer := io.Pipe()
+
+ cmd.Stdin = in
+ cmd.Stdout = writer
+
+ var errBuf bytes.Buffer
+ cmd.Stderr = &errBuf
+
+ if err := cmd.Start(); err != nil {
+ return nil, err
+ }
+
+ go func() {
+ if err := cmd.Wait(); err != nil {
+ writer.CloseWithError(fmt.Errorf("%s: %s", err, errBuf.String()))
+ } else {
+ writer.Close()
+ }
+ }()
+
+ return reader, nil
+}
+
+func detectPigz() string {
+ path, err := exec.LookPath("unpigz")
+ if err != nil {
+ log.L.WithError(err).Debug("unpigz not found, falling back to go gzip")
+ return ""
+ }
+
+ // Check if pigz disabled via CONTAINERD_DISABLE_PIGZ env variable
+ value := os.Getenv(disablePigzEnv)
+ if value == "" {
+ return path
+ }
+
+ disable, err := strconv.ParseBool(value)
+ if err != nil {
+ log.L.WithError(err).Warnf("could not parse %s: %s", disablePigzEnv, value)
+ return path
+ }
+
+ if disable {
+ return ""
+ }
+
+ return path
+}
diff --git a/vendor/github.com/containerd/containerd/archive/compression/compression_fuzzer.go b/vendor/github.com/containerd/containerd/archive/compression/compression_fuzzer.go
new file mode 100644
index 0000000000..3516494ac0
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/archive/compression/compression_fuzzer.go
@@ -0,0 +1,28 @@
+//go:build gofuzz
+
+/*
+ Copyright The containerd 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 compression
+
+import (
+ "bytes"
+)
+
+func FuzzDecompressStream(data []byte) int {
+ _, _ = DecompressStream(bytes.NewReader(data))
+ return 1
+}
diff --git a/vendor/github.com/containerd/containerd/content/adaptor.go b/vendor/github.com/containerd/containerd/content/adaptor.go
new file mode 100644
index 0000000000..88bad2610e
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/content/adaptor.go
@@ -0,0 +1,52 @@
+/*
+ Copyright The containerd 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 content
+
+import (
+ "strings"
+
+ "github.com/containerd/containerd/filters"
+)
+
+// AdaptInfo returns `filters.Adaptor` that handles `content.Info`.
+func AdaptInfo(info Info) filters.Adaptor {
+ return filters.AdapterFunc(func(fieldpath []string) (string, bool) {
+ if len(fieldpath) == 0 {
+ return "", false
+ }
+
+ switch fieldpath[0] {
+ case "digest":
+ return info.Digest.String(), true
+ case "size":
+ // TODO: support size based filtering
+ case "labels":
+ return checkMap(fieldpath[1:], info.Labels)
+ }
+
+ return "", false
+ })
+}
+
+func checkMap(fieldpath []string, m map[string]string) (string, bool) {
+ if len(m) == 0 {
+ return "", false
+ }
+
+ value, ok := m[strings.Join(fieldpath, ".")]
+ return value, ok
+}
diff --git a/vendor/github.com/containerd/containerd/content/content.go b/vendor/github.com/containerd/containerd/content/content.go
new file mode 100644
index 0000000000..2dc7bf8b52
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/content/content.go
@@ -0,0 +1,207 @@
+/*
+ Copyright The containerd 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 content
+
+import (
+ "context"
+ "io"
+ "time"
+
+ "github.com/opencontainers/go-digest"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// Store combines the methods of content-oriented interfaces into a set that
+// are commonly provided by complete implementations.
+//
+// Overall content lifecycle:
+// - Ingester is used to initiate a write operation (aka ingestion)
+// - IngestManager is used to manage (e.g. list, abort) active ingestions
+// - Once an ingestion is complete (see Writer.Commit), Provider is used to
+// query a single piece of content by its digest
+// - Manager is used to manage (e.g. list, delete) previously committed content
+//
+// Note that until ingestion is complete, its content is not visible through
+// Provider or Manager. Once ingestion is complete, it is no longer exposed
+// through IngestManager.
+type Store interface {
+ Manager
+ Provider
+ IngestManager
+ Ingester
+}
+
+// ReaderAt extends the standard io.ReaderAt interface with reporting of Size and io.Closer
+type ReaderAt interface {
+ io.ReaderAt
+ io.Closer
+ Size() int64
+}
+
+// Provider provides a reader interface for specific content
+type Provider interface {
+ // ReaderAt only requires desc.Digest to be set.
+ // Other fields in the descriptor may be used internally for resolving
+ // the location of the actual data.
+ ReaderAt(ctx context.Context, desc ocispec.Descriptor) (ReaderAt, error)
+}
+
+// Ingester writes content
+type Ingester interface {
+ // Writer initiates a writing operation (aka ingestion). A single ingestion
+ // is uniquely identified by its ref, provided using a WithRef option.
+ // Writer can be called multiple times with the same ref to access the same
+ // ingestion.
+ // Once all the data is written, use Writer.Commit to complete the ingestion.
+ Writer(ctx context.Context, opts ...WriterOpt) (Writer, error)
+}
+
+// IngestManager provides methods for managing ingestions. An ingestion is a
+// not-yet-complete writing operation initiated using Ingester and identified
+// by a ref string.
+type IngestManager interface {
+ // Status returns the status of the provided ref.
+ Status(ctx context.Context, ref string) (Status, error)
+
+ // ListStatuses returns the status of any active ingestions whose ref match
+ // the provided regular expression. If empty, all active ingestions will be
+ // returned.
+ ListStatuses(ctx context.Context, filters ...string) ([]Status, error)
+
+ // Abort completely cancels the ingest operation targeted by ref.
+ Abort(ctx context.Context, ref string) error
+}
+
+// Info holds content specific information
+type Info struct {
+ Digest digest.Digest
+ Size int64
+ CreatedAt time.Time
+ UpdatedAt time.Time
+ Labels map[string]string
+}
+
+// Status of a content operation (i.e. an ingestion)
+type Status struct {
+ Ref string
+ Offset int64
+ Total int64
+ Expected digest.Digest
+ StartedAt time.Time
+ UpdatedAt time.Time
+}
+
+// WalkFunc defines the callback for a blob walk.
+type WalkFunc func(Info) error
+
+// InfoReaderProvider provides both info and reader for the specific content.
+type InfoReaderProvider interface {
+ InfoProvider
+ Provider
+}
+
+// InfoProvider provides info for content inspection.
+type InfoProvider interface {
+ // Info will return metadata about content available in the content store.
+ //
+ // If the content is not present, ErrNotFound will be returned.
+ Info(ctx context.Context, dgst digest.Digest) (Info, error)
+}
+
+// Manager provides methods for inspecting, listing and removing content.
+type Manager interface {
+ InfoProvider
+
+ // Update updates mutable information related to content.
+ // If one or more fieldpaths are provided, only those
+ // fields will be updated.
+ // Mutable fields:
+ // labels.*
+ Update(ctx context.Context, info Info, fieldpaths ...string) (Info, error)
+
+ // Walk will call fn for each item in the content store which
+ // match the provided filters. If no filters are given all
+ // items will be walked.
+ Walk(ctx context.Context, fn WalkFunc, filters ...string) error
+
+ // Delete removes the content from the store.
+ Delete(ctx context.Context, dgst digest.Digest) error
+}
+
+// Writer handles writing of content into a content store
+type Writer interface {
+ // Close closes the writer, if the writer has not been
+ // committed this allows resuming or aborting.
+ // Calling Close on a closed writer will not error.
+ io.WriteCloser
+
+ // Digest may return empty digest or panics until committed.
+ Digest() digest.Digest
+
+ // Commit commits the blob (but no roll-back is guaranteed on an error).
+ // size and expected can be zero-value when unknown.
+ // Commit always closes the writer, even on error.
+ // ErrAlreadyExists aborts the writer.
+ Commit(ctx context.Context, size int64, expected digest.Digest, opts ...Opt) error
+
+ // Status returns the current state of write
+ Status() (Status, error)
+
+ // Truncate updates the size of the target blob
+ Truncate(size int64) error
+}
+
+// Opt is used to alter the mutable properties of content
+type Opt func(*Info) error
+
+// WithLabels allows labels to be set on content
+func WithLabels(labels map[string]string) Opt {
+ return func(info *Info) error {
+ info.Labels = labels
+ return nil
+ }
+}
+
+// WriterOpts is internally used by WriterOpt.
+type WriterOpts struct {
+ Ref string
+ Desc ocispec.Descriptor
+}
+
+// WriterOpt is used for passing options to Ingester.Writer.
+type WriterOpt func(*WriterOpts) error
+
+// WithDescriptor specifies an OCI descriptor.
+// Writer may optionally use the descriptor internally for resolving
+// the location of the actual data.
+// Write does not require any field of desc to be set.
+// If the data size is unknown, desc.Size should be set to 0.
+// Some implementations may also accept negative values as "unknown".
+func WithDescriptor(desc ocispec.Descriptor) WriterOpt {
+ return func(opts *WriterOpts) error {
+ opts.Desc = desc
+ return nil
+ }
+}
+
+// WithRef specifies a ref string.
+func WithRef(ref string) WriterOpt {
+ return func(opts *WriterOpts) error {
+ opts.Ref = ref
+ return nil
+ }
+}
diff --git a/vendor/github.com/containerd/containerd/content/helpers.go b/vendor/github.com/containerd/containerd/content/helpers.go
new file mode 100644
index 0000000000..93bcdde106
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/content/helpers.go
@@ -0,0 +1,340 @@
+/*
+ Copyright The containerd 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 content
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "sync"
+ "time"
+
+ "github.com/containerd/log"
+ "github.com/opencontainers/go-digest"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+
+ "github.com/containerd/containerd/errdefs"
+ "github.com/containerd/containerd/pkg/randutil"
+)
+
+var ErrReset = errors.New("writer has been reset")
+
+var bufPool = sync.Pool{
+ New: func() interface{} {
+ buffer := make([]byte, 1<<20)
+ return &buffer
+ },
+}
+
+type reader interface {
+ Reader() io.Reader
+}
+
+// NewReader returns a io.Reader from a ReaderAt
+func NewReader(ra ReaderAt) io.Reader {
+ if rd, ok := ra.(reader); ok {
+ return rd.Reader()
+ }
+ return io.NewSectionReader(ra, 0, ra.Size())
+}
+
+// ReadBlob retrieves the entire contents of the blob from the provider.
+//
+// Avoid using this for large blobs, such as layers.
+func ReadBlob(ctx context.Context, provider Provider, desc ocispec.Descriptor) ([]byte, error) {
+ if int64(len(desc.Data)) == desc.Size && digest.FromBytes(desc.Data) == desc.Digest {
+ return desc.Data, nil
+ }
+
+ ra, err := provider.ReaderAt(ctx, desc)
+ if err != nil {
+ return nil, err
+ }
+ defer ra.Close()
+
+ p := make([]byte, ra.Size())
+
+ n, err := ra.ReadAt(p, 0)
+ if err == io.EOF {
+ if int64(n) != ra.Size() {
+ err = io.ErrUnexpectedEOF
+ } else {
+ err = nil
+ }
+ }
+ return p, err
+}
+
+// WriteBlob writes data with the expected digest into the content store. If
+// expected already exists, the method returns immediately and the reader will
+// not be consumed.
+//
+// This is useful when the digest and size are known beforehand.
+//
+// Copy is buffered, so no need to wrap reader in buffered io.
+func WriteBlob(ctx context.Context, cs Ingester, ref string, r io.Reader, desc ocispec.Descriptor, opts ...Opt) error {
+ cw, err := OpenWriter(ctx, cs, WithRef(ref), WithDescriptor(desc))
+ if err != nil {
+ if !errdefs.IsAlreadyExists(err) {
+ return fmt.Errorf("failed to open writer: %w", err)
+ }
+
+ return nil // already present
+ }
+ defer cw.Close()
+
+ return Copy(ctx, cw, r, desc.Size, desc.Digest, opts...)
+}
+
+// OpenWriter opens a new writer for the given reference, retrying if the writer
+// is locked until the reference is available or returns an error.
+func OpenWriter(ctx context.Context, cs Ingester, opts ...WriterOpt) (Writer, error) {
+ var (
+ cw Writer
+ err error
+ retry = 16
+ )
+ for {
+ cw, err = cs.Writer(ctx, opts...)
+ if err != nil {
+ if !errdefs.IsUnavailable(err) {
+ return nil, err
+ }
+
+ // TODO: Check status to determine if the writer is active,
+ // continue waiting while active, otherwise return lock
+ // error or abort. Requires asserting for an ingest manager
+
+ select {
+ case <-time.After(time.Millisecond * time.Duration(randutil.Intn(retry))):
+ if retry < 2048 {
+ retry = retry << 1
+ }
+ continue
+ case <-ctx.Done():
+ // Propagate lock error
+ return nil, err
+ }
+
+ }
+ break
+ }
+
+ return cw, err
+}
+
+// Copy copies data with the expected digest from the reader into the
+// provided content store writer. This copy commits the writer.
+//
+// This is useful when the digest and size are known beforehand. When
+// the size or digest is unknown, these values may be empty.
+//
+// Copy is buffered, so no need to wrap reader in buffered io.
+func Copy(ctx context.Context, cw Writer, or io.Reader, size int64, expected digest.Digest, opts ...Opt) error {
+ ws, err := cw.Status()
+ if err != nil {
+ return fmt.Errorf("failed to get status: %w", err)
+ }
+ r := or
+ if ws.Offset > 0 {
+ r, err = seekReader(or, ws.Offset, size)
+ if err != nil {
+ return fmt.Errorf("unable to resume write to %v: %w", ws.Ref, err)
+ }
+ }
+
+ for i := 0; ; i++ {
+ if i >= 1 {
+ log.G(ctx).WithField("digest", expected).Debugf("retrying copy due to reset")
+ }
+ copied, err := copyWithBuffer(cw, r)
+ if errors.Is(err, ErrReset) {
+ ws, err := cw.Status()
+ if err != nil {
+ return fmt.Errorf("failed to get status: %w", err)
+ }
+ r, err = seekReader(or, ws.Offset, size)
+ if err != nil {
+ return fmt.Errorf("unable to resume write to %v: %w", ws.Ref, err)
+ }
+ continue
+ }
+ if err != nil {
+ return fmt.Errorf("failed to copy: %w", err)
+ }
+ if size != 0 && copied < size-ws.Offset {
+ // Short writes would return its own error, this indicates a read failure
+ return fmt.Errorf("failed to read expected number of bytes: %w", io.ErrUnexpectedEOF)
+ }
+ if err := cw.Commit(ctx, size, expected, opts...); err != nil {
+ if errors.Is(err, ErrReset) {
+ ws, err := cw.Status()
+ if err != nil {
+ return fmt.Errorf("failed to get status: %w", err)
+ }
+ r, err = seekReader(or, ws.Offset, size)
+ if err != nil {
+ return fmt.Errorf("unable to resume write to %v: %w", ws.Ref, err)
+ }
+ continue
+ }
+ if !errdefs.IsAlreadyExists(err) {
+ return fmt.Errorf("failed commit on ref %q: %w", ws.Ref, err)
+ }
+ }
+ return nil
+ }
+}
+
+// CopyReaderAt copies to a writer from a given reader at for the given
+// number of bytes. This copy does not commit the writer.
+func CopyReaderAt(cw Writer, ra ReaderAt, n int64) error {
+ ws, err := cw.Status()
+ if err != nil {
+ return err
+ }
+
+ copied, err := copyWithBuffer(cw, io.NewSectionReader(ra, ws.Offset, n))
+ if err != nil {
+ return fmt.Errorf("failed to copy: %w", err)
+ }
+ if copied < n {
+ // Short writes would return its own error, this indicates a read failure
+ return fmt.Errorf("failed to read expected number of bytes: %w", io.ErrUnexpectedEOF)
+ }
+ return nil
+}
+
+// CopyReader copies to a writer from a given reader, returning
+// the number of bytes copied.
+// Note: if the writer has a non-zero offset, the total number
+// of bytes read may be greater than those copied if the reader
+// is not an io.Seeker.
+// This copy does not commit the writer.
+func CopyReader(cw Writer, r io.Reader) (int64, error) {
+ ws, err := cw.Status()
+ if err != nil {
+ return 0, fmt.Errorf("failed to get status: %w", err)
+ }
+
+ if ws.Offset > 0 {
+ r, err = seekReader(r, ws.Offset, 0)
+ if err != nil {
+ return 0, fmt.Errorf("unable to resume write to %v: %w", ws.Ref, err)
+ }
+ }
+
+ return copyWithBuffer(cw, r)
+}
+
+// seekReader attempts to seek the reader to the given offset, either by
+// resolving `io.Seeker`, by detecting `io.ReaderAt`, or discarding
+// up to the given offset.
+func seekReader(r io.Reader, offset, size int64) (io.Reader, error) {
+ // attempt to resolve r as a seeker and setup the offset.
+ seeker, ok := r.(io.Seeker)
+ if ok {
+ nn, err := seeker.Seek(offset, io.SeekStart)
+ if nn != offset {
+ if err == nil {
+ err = fmt.Errorf("unexpected seek location without seek error")
+ }
+ return nil, fmt.Errorf("failed to seek to offset %v: %w", offset, err)
+ }
+
+ if err != nil {
+ return nil, err
+ }
+
+ return r, nil
+ }
+
+ // ok, let's try io.ReaderAt!
+ readerAt, ok := r.(io.ReaderAt)
+ if ok && size > offset {
+ sr := io.NewSectionReader(readerAt, offset, size)
+ return sr, nil
+ }
+
+ // well then, let's just discard up to the offset
+ n, err := copyWithBuffer(io.Discard, io.LimitReader(r, offset))
+ if err != nil {
+ return nil, fmt.Errorf("failed to discard to offset: %w", err)
+ }
+ if n != offset {
+ return nil, errors.New("unable to discard to offset")
+ }
+
+ return r, nil
+}
+
+// copyWithBuffer is very similar to io.CopyBuffer https://golang.org/pkg/io/#CopyBuffer
+// but instead of using Read to read from the src, we use ReadAtLeast to make sure we have
+// a full buffer before we do a write operation to dst to reduce overheads associated
+// with the write operations of small buffers.
+func copyWithBuffer(dst io.Writer, src io.Reader) (written int64, err error) {
+ // If the reader has a WriteTo method, use it to do the copy.
+ // Avoids an allocation and a copy.
+ if wt, ok := src.(io.WriterTo); ok {
+ return wt.WriteTo(dst)
+ }
+ // Similarly, if the writer has a ReadFrom method, use it to do the copy.
+ if rt, ok := dst.(io.ReaderFrom); ok {
+ return rt.ReadFrom(src)
+ }
+ bufRef := bufPool.Get().(*[]byte)
+ defer bufPool.Put(bufRef)
+ buf := *bufRef
+ for {
+ nr, er := io.ReadAtLeast(src, buf, len(buf))
+ if nr > 0 {
+ nw, ew := dst.Write(buf[0:nr])
+ if nw > 0 {
+ written += int64(nw)
+ }
+ if ew != nil {
+ err = ew
+ break
+ }
+ if nr != nw {
+ err = io.ErrShortWrite
+ break
+ }
+ }
+ if er != nil {
+ // If an EOF happens after reading fewer than the requested bytes,
+ // ReadAtLeast returns ErrUnexpectedEOF.
+ if er != io.EOF && er != io.ErrUnexpectedEOF {
+ err = er
+ }
+ break
+ }
+ }
+ return
+}
+
+// Exists returns whether an attempt to access the content would not error out
+// with an ErrNotFound error. It will return an encountered error if it was
+// different than ErrNotFound.
+func Exists(ctx context.Context, provider InfoProvider, desc ocispec.Descriptor) (bool, error) {
+ _, err := provider.Info(ctx, desc.Digest)
+ if errdefs.IsNotFound(err) {
+ return false, nil
+ }
+ return err == nil, err
+}
diff --git a/vendor/github.com/containerd/containerd/errdefs/errors.go b/vendor/github.com/containerd/containerd/errdefs/errors.go
new file mode 100644
index 0000000000..de22cadd41
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/errdefs/errors.go
@@ -0,0 +1,72 @@
+/*
+ Copyright The containerd 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 errdefs defines the common errors used throughout containerd
+// packages.
+//
+// Use with fmt.Errorf to add context to an error.
+//
+// To detect an error class, use the IsXXX functions to tell whether an error
+// is of a certain type.
+package errdefs
+
+import (
+ "github.com/containerd/errdefs"
+)
+
+// Definitions of common error types used throughout containerd. All containerd
+// errors returned by most packages will map into one of these errors classes.
+// Packages should return errors of these types when they want to instruct a
+// client to take a particular action.
+//
+// These errors map closely to grpc errors.
+var (
+ ErrUnknown = errdefs.ErrUnknown
+ ErrInvalidArgument = errdefs.ErrInvalidArgument
+ ErrNotFound = errdefs.ErrNotFound
+ ErrAlreadyExists = errdefs.ErrAlreadyExists
+ ErrPermissionDenied = errdefs.ErrPermissionDenied
+ ErrResourceExhausted = errdefs.ErrResourceExhausted
+ ErrFailedPrecondition = errdefs.ErrFailedPrecondition
+ ErrConflict = errdefs.ErrConflict
+ ErrNotModified = errdefs.ErrNotModified
+ ErrAborted = errdefs.ErrAborted
+ ErrOutOfRange = errdefs.ErrOutOfRange
+ ErrNotImplemented = errdefs.ErrNotImplemented
+ ErrInternal = errdefs.ErrInternal
+ ErrUnavailable = errdefs.ErrUnavailable
+ ErrDataLoss = errdefs.ErrDataLoss
+ ErrUnauthenticated = errdefs.ErrUnauthenticated
+
+ IsCanceled = errdefs.IsCanceled
+ IsUnknown = errdefs.IsUnknown
+ IsInvalidArgument = errdefs.IsInvalidArgument
+ IsDeadlineExceeded = errdefs.IsDeadlineExceeded
+ IsNotFound = errdefs.IsNotFound
+ IsAlreadyExists = errdefs.IsAlreadyExists
+ IsPermissionDenied = errdefs.IsPermissionDenied
+ IsResourceExhausted = errdefs.IsResourceExhausted
+ IsFailedPrecondition = errdefs.IsFailedPrecondition
+ IsConflict = errdefs.IsConflict
+ IsNotModified = errdefs.IsNotModified
+ IsAborted = errdefs.IsAborted
+ IsOutOfRange = errdefs.IsOutOfRange
+ IsNotImplemented = errdefs.IsNotImplemented
+ IsInternal = errdefs.IsInternal
+ IsUnavailable = errdefs.IsUnavailable
+ IsDataLoss = errdefs.IsDataLoss
+ IsUnauthorized = errdefs.IsUnauthorized
+)
diff --git a/vendor/github.com/containerd/containerd/errdefs/grpc.go b/vendor/github.com/containerd/containerd/errdefs/grpc.go
new file mode 100644
index 0000000000..11091b1db0
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/errdefs/grpc.go
@@ -0,0 +1,147 @@
+/*
+ Copyright The containerd 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 errdefs
+
+import (
+ "context"
+ "fmt"
+ "strings"
+
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+)
+
+// ToGRPC will attempt to map the backend containerd error into a grpc error,
+// using the original error message as a description.
+//
+// Further information may be extracted from certain errors depending on their
+// type.
+//
+// If the error is unmapped, the original error will be returned to be handled
+// by the regular grpc error handling stack.
+func ToGRPC(err error) error {
+ if err == nil {
+ return nil
+ }
+
+ if isGRPCError(err) {
+ // error has already been mapped to grpc
+ return err
+ }
+
+ switch {
+ case IsInvalidArgument(err):
+ return status.Error(codes.InvalidArgument, err.Error())
+ case IsNotFound(err):
+ return status.Error(codes.NotFound, err.Error())
+ case IsAlreadyExists(err):
+ return status.Error(codes.AlreadyExists, err.Error())
+ case IsFailedPrecondition(err):
+ return status.Error(codes.FailedPrecondition, err.Error())
+ case IsUnavailable(err):
+ return status.Error(codes.Unavailable, err.Error())
+ case IsNotImplemented(err):
+ return status.Error(codes.Unimplemented, err.Error())
+ case IsCanceled(err):
+ return status.Error(codes.Canceled, err.Error())
+ case IsDeadlineExceeded(err):
+ return status.Error(codes.DeadlineExceeded, err.Error())
+ }
+
+ return err
+}
+
+// ToGRPCf maps the error to grpc error codes, assembling the formatting string
+// and combining it with the target error string.
+//
+// This is equivalent to errdefs.ToGRPC(fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err))
+func ToGRPCf(err error, format string, args ...interface{}) error {
+ return ToGRPC(fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err))
+}
+
+// FromGRPC returns the underlying error from a grpc service based on the grpc error code
+func FromGRPC(err error) error {
+ if err == nil {
+ return nil
+ }
+
+ var cls error // divide these into error classes, becomes the cause
+
+ switch code(err) {
+ case codes.InvalidArgument:
+ cls = ErrInvalidArgument
+ case codes.AlreadyExists:
+ cls = ErrAlreadyExists
+ case codes.NotFound:
+ cls = ErrNotFound
+ case codes.Unavailable:
+ cls = ErrUnavailable
+ case codes.FailedPrecondition:
+ cls = ErrFailedPrecondition
+ case codes.Unimplemented:
+ cls = ErrNotImplemented
+ case codes.Canceled:
+ cls = context.Canceled
+ case codes.DeadlineExceeded:
+ cls = context.DeadlineExceeded
+ default:
+ cls = ErrUnknown
+ }
+
+ msg := rebaseMessage(cls, err)
+ if msg != "" {
+ err = fmt.Errorf("%s: %w", msg, cls)
+ } else {
+ err = cls
+ }
+
+ return err
+}
+
+// rebaseMessage removes the repeats for an error at the end of an error
+// string. This will happen when taking an error over grpc then remapping it.
+//
+// Effectively, we just remove the string of cls from the end of err if it
+// appears there.
+func rebaseMessage(cls error, err error) string {
+ desc := errDesc(err)
+ clss := cls.Error()
+ if desc == clss {
+ return ""
+ }
+
+ return strings.TrimSuffix(desc, ": "+clss)
+}
+
+func isGRPCError(err error) bool {
+ _, ok := status.FromError(err)
+ return ok
+}
+
+func code(err error) codes.Code {
+ if s, ok := status.FromError(err); ok {
+ return s.Code()
+ }
+ return codes.Unknown
+}
+
+func errDesc(err error) string {
+ if s, ok := status.FromError(err); ok {
+ return s.Message()
+ }
+ return err.Error()
+}
diff --git a/vendor/github.com/containerd/containerd/filters/adaptor.go b/vendor/github.com/containerd/containerd/filters/adaptor.go
new file mode 100644
index 0000000000..5a9c559c1e
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/filters/adaptor.go
@@ -0,0 +1,33 @@
+/*
+ Copyright The containerd 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 filters
+
+// Adaptor specifies the mapping of fieldpaths to a type. For the given field
+// path, the value and whether it is present should be returned. The mapping of
+// the fieldpath to a field is deferred to the adaptor implementation, but
+// should generally follow protobuf field path/mask semantics.
+type Adaptor interface {
+ Field(fieldpath []string) (value string, present bool)
+}
+
+// AdapterFunc allows implementation specific matching of fieldpaths
+type AdapterFunc func(fieldpath []string) (string, bool)
+
+// Field returns the field name and true if it exists
+func (fn AdapterFunc) Field(fieldpath []string) (string, bool) {
+ return fn(fieldpath)
+}
diff --git a/vendor/github.com/containerd/containerd/filters/filter.go b/vendor/github.com/containerd/containerd/filters/filter.go
new file mode 100644
index 0000000000..dcc569a4b7
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/filters/filter.go
@@ -0,0 +1,178 @@
+/*
+ Copyright The containerd 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 filters defines a syntax and parser that can be used for the
+// filtration of items across the containerd API. The core is built on the
+// concept of protobuf field paths, with quoting. Several operators allow the
+// user to flexibly select items based on field presence, equality, inequality
+// and regular expressions. Flexible adaptors support working with any type.
+//
+// The syntax is fairly familiar, if you've used container ecosystem
+// projects. At the core, we base it on the concept of protobuf field
+// paths, augmenting with the ability to quote portions of the field path
+// to match arbitrary labels. These "selectors" come in the following
+// syntax:
+//
+// ```
+// []
+// ```
+//
+// A basic example is as follows:
+//
+// ```
+// name==foo
+// ```
+//
+// This would match all objects that have a field `name` with the value
+// `foo`. If we only want to test if the field is present, we can omit the
+// operator. This is most useful for matching labels in containerd. The
+// following will match objects that have the field "labels" and have the
+// label "foo" defined:
+//
+// ```
+// labels.foo
+// ```
+//
+// We also allow for quoting of parts of the field path to allow matching
+// of arbitrary items:
+//
+// ```
+// labels."very complex label"==something
+// ```
+//
+// We also define `!=` and `~=` as operators. The `!=` will match all
+// objects that don't match the value for a field and `~=` will compile the
+// target value as a regular expression and match the field value against that.
+//
+// Selectors can be combined using a comma, such that the resulting
+// selector will require all selectors are matched for the object to match.
+// The following example will match objects that are named `foo` and have
+// the label `bar`:
+//
+// ```
+// name==foo,labels.bar
+// ```
+package filters
+
+import (
+ "regexp"
+
+ "github.com/containerd/log"
+)
+
+// Filter matches specific resources based the provided filter
+type Filter interface {
+ Match(adaptor Adaptor) bool
+}
+
+// FilterFunc is a function that handles matching with an adaptor
+type FilterFunc func(Adaptor) bool
+
+// Match matches the FilterFunc returning true if the object matches the filter
+func (fn FilterFunc) Match(adaptor Adaptor) bool {
+ return fn(adaptor)
+}
+
+// Always is a filter that always returns true for any type of object
+var Always FilterFunc = func(adaptor Adaptor) bool {
+ return true
+}
+
+// Any allows multiple filters to be matched against the object
+type Any []Filter
+
+// Match returns true if any of the provided filters are true
+func (m Any) Match(adaptor Adaptor) bool {
+ for _, m := range m {
+ if m.Match(adaptor) {
+ return true
+ }
+ }
+
+ return false
+}
+
+// All allows multiple filters to be matched against the object
+type All []Filter
+
+// Match only returns true if all filters match the object
+func (m All) Match(adaptor Adaptor) bool {
+ for _, m := range m {
+ if !m.Match(adaptor) {
+ return false
+ }
+ }
+
+ return true
+}
+
+type operator int
+
+const (
+ operatorPresent = iota
+ operatorEqual
+ operatorNotEqual
+ operatorMatches
+)
+
+func (op operator) String() string {
+ switch op {
+ case operatorPresent:
+ return "?"
+ case operatorEqual:
+ return "=="
+ case operatorNotEqual:
+ return "!="
+ case operatorMatches:
+ return "~="
+ }
+
+ return "unknown"
+}
+
+type selector struct {
+ fieldpath []string
+ operator operator
+ value string
+ re *regexp.Regexp
+}
+
+func (m selector) Match(adaptor Adaptor) bool {
+ value, present := adaptor.Field(m.fieldpath)
+
+ switch m.operator {
+ case operatorPresent:
+ return present
+ case operatorEqual:
+ return present && value == m.value
+ case operatorNotEqual:
+ return value != m.value
+ case operatorMatches:
+ if m.re == nil {
+ r, err := regexp.Compile(m.value)
+ if err != nil {
+ log.L.Errorf("error compiling regexp %q", m.value)
+ return false
+ }
+
+ m.re = r
+ }
+
+ return m.re.MatchString(value)
+ default:
+ return false
+ }
+}
diff --git a/vendor/github.com/containerd/containerd/filters/parser.go b/vendor/github.com/containerd/containerd/filters/parser.go
new file mode 100644
index 0000000000..790597aaf2
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/filters/parser.go
@@ -0,0 +1,294 @@
+/*
+ Copyright The containerd 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 filters
+
+import (
+ "fmt"
+ "io"
+
+ "github.com/containerd/containerd/errdefs"
+)
+
+/*
+Parse the strings into a filter that may be used with an adaptor.
+
+The filter is made up of zero or more selectors.
+
+The format is a comma separated list of expressions, in the form of
+``, known as selectors. All selectors must match the
+target object for the filter to be true.
+
+We define the operators "==" for equality, "!=" for not equal and "~=" for a
+regular expression. If the operator and value are not present, the matcher will
+test for the presence of a value, as defined by the target object.
+
+The formal grammar is as follows:
+
+selectors := selector ("," selector)*
+selector := fieldpath (operator value)
+fieldpath := field ('.' field)*
+field := quoted | [A-Za-z] [A-Za-z0-9_]+
+operator := "==" | "!=" | "~="
+value := quoted | [^\s,]+
+quoted :=
+*/
+func Parse(s string) (Filter, error) {
+ // special case empty to match all
+ if s == "" {
+ return Always, nil
+ }
+
+ p := parser{input: s}
+ return p.parse()
+}
+
+// ParseAll parses each filter in ss and returns a filter that will return true
+// if any filter matches the expression.
+//
+// If no filters are provided, the filter will match anything.
+func ParseAll(ss ...string) (Filter, error) {
+ if len(ss) == 0 {
+ return Always, nil
+ }
+
+ var fs []Filter
+ for _, s := range ss {
+ f, err := Parse(s)
+ if err != nil {
+ return nil, fmt.Errorf("%s: %w", err.Error(), errdefs.ErrInvalidArgument)
+ }
+
+ fs = append(fs, f)
+ }
+
+ return Any(fs), nil
+}
+
+type parser struct {
+ input string
+ scanner scanner
+}
+
+func (p *parser) parse() (Filter, error) {
+ p.scanner.init(p.input)
+
+ ss, err := p.selectors()
+ if err != nil {
+ return nil, fmt.Errorf("filters: %w", err)
+ }
+
+ return ss, nil
+}
+
+func (p *parser) selectors() (Filter, error) {
+ s, err := p.selector()
+ if err != nil {
+ return nil, err
+ }
+
+ ss := All{s}
+
+loop:
+ for {
+ tok := p.scanner.peek()
+ switch tok {
+ case ',':
+ pos, tok, _ := p.scanner.scan()
+ if tok != tokenSeparator {
+ return nil, p.mkerr(pos, "expected a separator")
+ }
+
+ s, err := p.selector()
+ if err != nil {
+ return nil, err
+ }
+
+ ss = append(ss, s)
+ case tokenEOF:
+ break loop
+ default:
+ return nil, p.mkerrf(p.scanner.ppos, "unexpected input: %v", string(tok))
+ }
+ }
+
+ return ss, nil
+}
+
+func (p *parser) selector() (selector, error) {
+ fieldpath, err := p.fieldpath()
+ if err != nil {
+ return selector{}, err
+ }
+
+ switch p.scanner.peek() {
+ case ',', tokenSeparator, tokenEOF:
+ return selector{
+ fieldpath: fieldpath,
+ operator: operatorPresent,
+ }, nil
+ }
+
+ op, err := p.operator()
+ if err != nil {
+ return selector{}, err
+ }
+
+ var allowAltQuotes bool
+ if op == operatorMatches {
+ allowAltQuotes = true
+ }
+
+ value, err := p.value(allowAltQuotes)
+ if err != nil {
+ if err == io.EOF {
+ return selector{}, io.ErrUnexpectedEOF
+ }
+ return selector{}, err
+ }
+
+ return selector{
+ fieldpath: fieldpath,
+ value: value,
+ operator: op,
+ }, nil
+}
+
+func (p *parser) fieldpath() ([]string, error) {
+ f, err := p.field()
+ if err != nil {
+ return nil, err
+ }
+
+ fs := []string{f}
+loop:
+ for {
+ tok := p.scanner.peek() // lookahead to consume field separator
+
+ switch tok {
+ case '.':
+ pos, tok, _ := p.scanner.scan() // consume separator
+ if tok != tokenSeparator {
+ return nil, p.mkerr(pos, "expected a field separator (`.`)")
+ }
+
+ f, err := p.field()
+ if err != nil {
+ return nil, err
+ }
+
+ fs = append(fs, f)
+ default:
+ // let the layer above handle the other bad cases.
+ break loop
+ }
+ }
+
+ return fs, nil
+}
+
+func (p *parser) field() (string, error) {
+ pos, tok, s := p.scanner.scan()
+ switch tok {
+ case tokenField:
+ return s, nil
+ case tokenQuoted:
+ return p.unquote(pos, s, false)
+ case tokenIllegal:
+ return "", p.mkerr(pos, p.scanner.err)
+ }
+
+ return "", p.mkerr(pos, "expected field or quoted")
+}
+
+func (p *parser) operator() (operator, error) {
+ pos, tok, s := p.scanner.scan()
+ switch tok {
+ case tokenOperator:
+ switch s {
+ case "==":
+ return operatorEqual, nil
+ case "!=":
+ return operatorNotEqual, nil
+ case "~=":
+ return operatorMatches, nil
+ default:
+ return 0, p.mkerrf(pos, "unsupported operator %q", s)
+ }
+ case tokenIllegal:
+ return 0, p.mkerr(pos, p.scanner.err)
+ }
+
+ return 0, p.mkerr(pos, `expected an operator ("=="|"!="|"~=")`)
+}
+
+func (p *parser) value(allowAltQuotes bool) (string, error) {
+ pos, tok, s := p.scanner.scan()
+
+ switch tok {
+ case tokenValue, tokenField:
+ return s, nil
+ case tokenQuoted:
+ return p.unquote(pos, s, allowAltQuotes)
+ case tokenIllegal:
+ return "", p.mkerr(pos, p.scanner.err)
+ }
+
+ return "", p.mkerr(pos, "expected value or quoted")
+}
+
+func (p *parser) unquote(pos int, s string, allowAlts bool) (string, error) {
+ if !allowAlts && s[0] != '\'' && s[0] != '"' {
+ return "", p.mkerr(pos, "invalid quote encountered")
+ }
+
+ uq, err := unquote(s)
+ if err != nil {
+ return "", p.mkerrf(pos, "unquoting failed: %v", err)
+ }
+
+ return uq, nil
+}
+
+type parseError struct {
+ input string
+ pos int
+ msg string
+}
+
+func (pe parseError) Error() string {
+ if pe.pos < len(pe.input) {
+ before := pe.input[:pe.pos]
+ location := pe.input[pe.pos : pe.pos+1] // need to handle end
+ after := pe.input[pe.pos+1:]
+
+ return fmt.Sprintf("[%s >|%s|< %s]: %v", before, location, after, pe.msg)
+ }
+
+ return fmt.Sprintf("[%s]: %v", pe.input, pe.msg)
+}
+
+func (p *parser) mkerrf(pos int, format string, args ...interface{}) error {
+ return p.mkerr(pos, fmt.Sprintf(format, args...))
+}
+
+func (p *parser) mkerr(pos int, msg string) error {
+ return fmt.Errorf("parse error: %w", parseError{
+ input: p.input,
+ pos: pos,
+ msg: msg,
+ })
+}
diff --git a/vendor/github.com/containerd/containerd/filters/quote.go b/vendor/github.com/containerd/containerd/filters/quote.go
new file mode 100644
index 0000000000..5c800ef846
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/filters/quote.go
@@ -0,0 +1,252 @@
+/*
+ Copyright The containerd 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 filters
+
+import (
+ "errors"
+ "unicode/utf8"
+)
+
+// NOTE(stevvooe): Most of this code in this file is copied from the stdlib
+// strconv package and modified to be able to handle quoting with `/` and `|`
+// as delimiters. The copyright is held by the Go authors.
+
+var errQuoteSyntax = errors.New("quote syntax error")
+
+// UnquoteChar decodes the first character or byte in the escaped string
+// or character literal represented by the string s.
+// It returns four values:
+//
+// 1. value, the decoded Unicode code point or byte value;
+// 2. multibyte, a boolean indicating whether the decoded character requires a multibyte UTF-8 representation;
+// 3. tail, the remainder of the string after the character; and
+// 4. an error that will be nil if the character is syntactically valid.
+//
+// The second argument, quote, specifies the type of literal being parsed
+// and therefore which escaped quote character is permitted.
+// If set to a single quote, it permits the sequence \' and disallows unescaped '.
+// If set to a double quote, it permits \" and disallows unescaped ".
+// If set to zero, it does not permit either escape and allows both quote characters to appear unescaped.
+//
+// This is from Go strconv package, modified to support `|` and `/` as double
+// quotes for use with regular expressions.
+func unquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, err error) {
+ // easy cases
+ switch c := s[0]; {
+ case c == quote && (quote == '\'' || quote == '"' || quote == '/' || quote == '|'):
+ err = errQuoteSyntax
+ return
+ case c >= utf8.RuneSelf:
+ r, size := utf8.DecodeRuneInString(s)
+ return r, true, s[size:], nil
+ case c != '\\':
+ return rune(s[0]), false, s[1:], nil
+ }
+
+ // hard case: c is backslash
+ if len(s) <= 1 {
+ err = errQuoteSyntax
+ return
+ }
+ c := s[1]
+ s = s[2:]
+
+ switch c {
+ case 'a':
+ value = '\a'
+ case 'b':
+ value = '\b'
+ case 'f':
+ value = '\f'
+ case 'n':
+ value = '\n'
+ case 'r':
+ value = '\r'
+ case 't':
+ value = '\t'
+ case 'v':
+ value = '\v'
+ case 'x', 'u', 'U':
+ n := 0
+ switch c {
+ case 'x':
+ n = 2
+ case 'u':
+ n = 4
+ case 'U':
+ n = 8
+ }
+ var v rune
+ if len(s) < n {
+ err = errQuoteSyntax
+ return
+ }
+ for j := 0; j < n; j++ {
+ x, ok := unhex(s[j])
+ if !ok {
+ err = errQuoteSyntax
+ return
+ }
+ v = v<<4 | x
+ }
+ s = s[n:]
+ if c == 'x' {
+ // single-byte string, possibly not UTF-8
+ value = v
+ break
+ }
+ if v > utf8.MaxRune {
+ err = errQuoteSyntax
+ return
+ }
+ value = v
+ multibyte = true
+ case '0', '1', '2', '3', '4', '5', '6', '7':
+ v := rune(c) - '0'
+ if len(s) < 2 {
+ err = errQuoteSyntax
+ return
+ }
+ for j := 0; j < 2; j++ { // one digit already; two more
+ x := rune(s[j]) - '0'
+ if x < 0 || x > 7 {
+ err = errQuoteSyntax
+ return
+ }
+ v = (v << 3) | x
+ }
+ s = s[2:]
+ if v > 255 {
+ err = errQuoteSyntax
+ return
+ }
+ value = v
+ case '\\':
+ value = '\\'
+ case '\'', '"', '|', '/':
+ if c != quote {
+ err = errQuoteSyntax
+ return
+ }
+ value = rune(c)
+ default:
+ err = errQuoteSyntax
+ return
+ }
+ tail = s
+ return
+}
+
+// unquote interprets s as a single-quoted, double-quoted,
+// or backquoted Go string literal, returning the string value
+// that s quotes. (If s is single-quoted, it would be a Go
+// character literal; Unquote returns the corresponding
+// one-character string.)
+//
+// This is modified from the standard library to support `|` and `/` as quote
+// characters for use with regular expressions.
+func unquote(s string) (string, error) {
+ n := len(s)
+ if n < 2 {
+ return "", errQuoteSyntax
+ }
+ quote := s[0]
+ if quote != s[n-1] {
+ return "", errQuoteSyntax
+ }
+ s = s[1 : n-1]
+
+ if quote == '`' {
+ if contains(s, '`') {
+ return "", errQuoteSyntax
+ }
+ if contains(s, '\r') {
+ // -1 because we know there is at least one \r to remove.
+ buf := make([]byte, 0, len(s)-1)
+ for i := 0; i < len(s); i++ {
+ if s[i] != '\r' {
+ buf = append(buf, s[i])
+ }
+ }
+ return string(buf), nil
+ }
+ return s, nil
+ }
+ if quote != '"' && quote != '\'' && quote != '|' && quote != '/' {
+ return "", errQuoteSyntax
+ }
+ if contains(s, '\n') {
+ return "", errQuoteSyntax
+ }
+
+ // Is it trivial? Avoid allocation.
+ if !contains(s, '\\') && !contains(s, quote) {
+ switch quote {
+ case '"', '/', '|': // pipe and slash are treated like double quote
+ return s, nil
+ case '\'':
+ r, size := utf8.DecodeRuneInString(s)
+ if size == len(s) && (r != utf8.RuneError || size != 1) {
+ return s, nil
+ }
+ }
+ }
+
+ var runeTmp [utf8.UTFMax]byte
+ buf := make([]byte, 0, 3*len(s)/2) // Try to avoid more allocations.
+ for len(s) > 0 {
+ c, multibyte, ss, err := unquoteChar(s, quote)
+ if err != nil {
+ return "", err
+ }
+ s = ss
+ if c < utf8.RuneSelf || !multibyte {
+ buf = append(buf, byte(c))
+ } else {
+ n := utf8.EncodeRune(runeTmp[:], c)
+ buf = append(buf, runeTmp[:n]...)
+ }
+ if quote == '\'' && len(s) != 0 {
+ // single-quoted must be single character
+ return "", errQuoteSyntax
+ }
+ }
+ return string(buf), nil
+}
+
+// contains reports whether the string contains the byte c.
+func contains(s string, c byte) bool {
+ for i := 0; i < len(s); i++ {
+ if s[i] == c {
+ return true
+ }
+ }
+ return false
+}
+
+func unhex(b byte) (v rune, ok bool) {
+ c := rune(b)
+ switch {
+ case '0' <= c && c <= '9':
+ return c - '0', true
+ case 'a' <= c && c <= 'f':
+ return c - 'a' + 10, true
+ case 'A' <= c && c <= 'F':
+ return c - 'A' + 10, true
+ }
+ return
+}
diff --git a/vendor/github.com/containerd/containerd/filters/scanner.go b/vendor/github.com/containerd/containerd/filters/scanner.go
new file mode 100644
index 0000000000..6a485467b8
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/filters/scanner.go
@@ -0,0 +1,297 @@
+/*
+ Copyright The containerd 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 filters
+
+import (
+ "unicode"
+ "unicode/utf8"
+)
+
+const (
+ tokenEOF = -(iota + 1)
+ tokenQuoted
+ tokenValue
+ tokenField
+ tokenSeparator
+ tokenOperator
+ tokenIllegal
+)
+
+type token rune
+
+func (t token) String() string {
+ switch t {
+ case tokenEOF:
+ return "EOF"
+ case tokenQuoted:
+ return "Quoted"
+ case tokenValue:
+ return "Value"
+ case tokenField:
+ return "Field"
+ case tokenSeparator:
+ return "Separator"
+ case tokenOperator:
+ return "Operator"
+ case tokenIllegal:
+ return "Illegal"
+ }
+
+ return string(t)
+}
+
+func (t token) GoString() string {
+ return "token" + t.String()
+}
+
+type scanner struct {
+ input string
+ pos int
+ ppos int // bounds the current rune in the string
+ value bool
+ err string
+}
+
+func (s *scanner) init(input string) {
+ s.input = input
+ s.pos = 0
+ s.ppos = 0
+}
+
+func (s *scanner) next() rune {
+ if s.pos >= len(s.input) {
+ return tokenEOF
+ }
+ s.pos = s.ppos
+
+ r, w := utf8.DecodeRuneInString(s.input[s.ppos:])
+ s.ppos += w
+ if r == utf8.RuneError {
+ if w > 0 {
+ s.error("rune error")
+ return tokenIllegal
+ }
+ return tokenEOF
+ }
+
+ if r == 0 {
+ s.error("unexpected null")
+ return tokenIllegal
+ }
+
+ return r
+}
+
+func (s *scanner) peek() rune {
+ pos := s.pos
+ ppos := s.ppos
+ ch := s.next()
+ s.pos = pos
+ s.ppos = ppos
+ return ch
+}
+
+func (s *scanner) scan() (nextp int, tk token, text string) {
+ var (
+ ch = s.next()
+ pos = s.pos
+ )
+
+chomp:
+ switch {
+ case ch == tokenEOF:
+ case ch == tokenIllegal:
+ case isQuoteRune(ch):
+ if !s.scanQuoted(ch) {
+ return pos, tokenIllegal, s.input[pos:s.ppos]
+ }
+ return pos, tokenQuoted, s.input[pos:s.ppos]
+ case isSeparatorRune(ch):
+ s.value = false
+ return pos, tokenSeparator, s.input[pos:s.ppos]
+ case isOperatorRune(ch):
+ s.scanOperator()
+ s.value = true
+ return pos, tokenOperator, s.input[pos:s.ppos]
+ case unicode.IsSpace(ch):
+ // chomp
+ ch = s.next()
+ pos = s.pos
+ goto chomp
+ case s.value:
+ s.scanValue()
+ s.value = false
+ return pos, tokenValue, s.input[pos:s.ppos]
+ case isFieldRune(ch):
+ s.scanField()
+ return pos, tokenField, s.input[pos:s.ppos]
+ }
+
+ return s.pos, token(ch), ""
+}
+
+func (s *scanner) scanField() {
+ for {
+ ch := s.peek()
+ if !isFieldRune(ch) {
+ break
+ }
+ s.next()
+ }
+}
+
+func (s *scanner) scanOperator() {
+ for {
+ ch := s.peek()
+ switch ch {
+ case '=', '!', '~':
+ s.next()
+ default:
+ return
+ }
+ }
+}
+
+func (s *scanner) scanValue() {
+ for {
+ ch := s.peek()
+ if !isValueRune(ch) {
+ break
+ }
+ s.next()
+ }
+}
+
+func (s *scanner) scanQuoted(quote rune) bool {
+ var illegal bool
+ ch := s.next() // read character after quote
+ for ch != quote {
+ if ch == '\n' || ch < 0 {
+ s.error("quoted literal not terminated")
+ return false
+ }
+ if ch == '\\' {
+ var legal bool
+ ch, legal = s.scanEscape(quote)
+ if !legal {
+ illegal = true
+ }
+ } else {
+ ch = s.next()
+ }
+ }
+ return !illegal
+}
+
+func (s *scanner) scanEscape(quote rune) (ch rune, legal bool) {
+ ch = s.next() // read character after '/'
+ switch ch {
+ case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', quote:
+ // nothing to do
+ ch = s.next()
+ legal = true
+ case '0', '1', '2', '3', '4', '5', '6', '7':
+ ch, legal = s.scanDigits(ch, 8, 3)
+ case 'x':
+ ch, legal = s.scanDigits(s.next(), 16, 2)
+ case 'u':
+ ch, legal = s.scanDigits(s.next(), 16, 4)
+ case 'U':
+ ch, legal = s.scanDigits(s.next(), 16, 8)
+ default:
+ s.error("illegal escape sequence")
+ }
+ return
+}
+
+func (s *scanner) scanDigits(ch rune, base, n int) (rune, bool) {
+ for n > 0 && digitVal(ch) < base {
+ ch = s.next()
+ n--
+ }
+ if n > 0 {
+ s.error("illegal numeric escape sequence")
+ return ch, false
+ }
+ return ch, true
+}
+
+func (s *scanner) error(msg string) {
+ if s.err == "" {
+ s.err = msg
+ }
+}
+
+func digitVal(ch rune) int {
+ switch {
+ case '0' <= ch && ch <= '9':
+ return int(ch - '0')
+ case 'a' <= ch && ch <= 'f':
+ return int(ch - 'a' + 10)
+ case 'A' <= ch && ch <= 'F':
+ return int(ch - 'A' + 10)
+ }
+ return 16 // larger than any legal digit val
+}
+
+func isFieldRune(r rune) bool {
+ return (r == '_' || isAlphaRune(r) || isDigitRune(r))
+}
+
+func isAlphaRune(r rune) bool {
+ return r >= 'A' && r <= 'Z' || r >= 'a' && r <= 'z'
+}
+
+func isDigitRune(r rune) bool {
+ return r >= '0' && r <= '9'
+}
+
+func isOperatorRune(r rune) bool {
+ switch r {
+ case '=', '!', '~':
+ return true
+ }
+
+ return false
+}
+
+func isQuoteRune(r rune) bool {
+ switch r {
+ case '/', '|', '"': // maybe add single quoting?
+ return true
+ }
+
+ return false
+}
+
+func isSeparatorRune(r rune) bool {
+ switch r {
+ case ',', '.':
+ return true
+ }
+
+ return false
+}
+
+func isValueRune(r rune) bool {
+ return r != ',' && !unicode.IsSpace(r) &&
+ (unicode.IsLetter(r) ||
+ unicode.IsDigit(r) ||
+ unicode.IsNumber(r) ||
+ unicode.IsGraphic(r) ||
+ unicode.IsPunct(r))
+}
diff --git a/vendor/github.com/containerd/containerd/images/annotations.go b/vendor/github.com/containerd/containerd/images/annotations.go
new file mode 100644
index 0000000000..47d92104cd
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/images/annotations.go
@@ -0,0 +1,23 @@
+/*
+ Copyright The containerd 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 images
+
+const (
+ // AnnotationImageName is an annotation on a Descriptor in an index.json
+ // containing the `Name` value as used by an `Image` struct
+ AnnotationImageName = "io.containerd.image.name"
+)
diff --git a/vendor/github.com/containerd/containerd/images/diffid.go b/vendor/github.com/containerd/containerd/images/diffid.go
new file mode 100644
index 0000000000..85577eedee
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/images/diffid.go
@@ -0,0 +1,81 @@
+/*
+ Copyright The containerd 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 images
+
+import (
+ "context"
+ "io"
+
+ "github.com/containerd/containerd/archive/compression"
+ "github.com/containerd/containerd/content"
+ "github.com/containerd/containerd/labels"
+ "github.com/opencontainers/go-digest"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+ "github.com/sirupsen/logrus"
+)
+
+// GetDiffID gets the diff ID of the layer blob descriptor.
+func GetDiffID(ctx context.Context, cs content.Store, desc ocispec.Descriptor) (digest.Digest, error) {
+ switch desc.MediaType {
+ case
+ // If the layer is already uncompressed, we can just return its digest
+ MediaTypeDockerSchema2Layer,
+ ocispec.MediaTypeImageLayer,
+ MediaTypeDockerSchema2LayerForeign,
+ ocispec.MediaTypeImageLayerNonDistributable: //nolint:staticcheck // deprecated
+ return desc.Digest, nil
+ }
+ info, err := cs.Info(ctx, desc.Digest)
+ if err != nil {
+ return "", err
+ }
+ v, ok := info.Labels[labels.LabelUncompressed]
+ if ok {
+ // Fast path: if the image is already unpacked, we can use the label value
+ return digest.Parse(v)
+ }
+ // if the image is not unpacked, we may not have the label
+ ra, err := cs.ReaderAt(ctx, desc)
+ if err != nil {
+ return "", err
+ }
+ defer ra.Close()
+ r := content.NewReader(ra)
+ uR, err := compression.DecompressStream(r)
+ if err != nil {
+ return "", err
+ }
+ defer uR.Close()
+ digester := digest.Canonical.Digester()
+ hashW := digester.Hash()
+ if _, err := io.Copy(hashW, uR); err != nil {
+ return "", err
+ }
+ if err := ra.Close(); err != nil {
+ return "", err
+ }
+ digest := digester.Digest()
+ // memorize the computed value
+ if info.Labels == nil {
+ info.Labels = make(map[string]string)
+ }
+ info.Labels[labels.LabelUncompressed] = digest.String()
+ if _, err := cs.Update(ctx, info, "labels"); err != nil {
+ logrus.WithError(err).Warnf("failed to set %s label for %s", labels.LabelUncompressed, desc.Digest)
+ }
+ return digest, nil
+}
diff --git a/vendor/github.com/containerd/containerd/images/handlers.go b/vendor/github.com/containerd/containerd/images/handlers.go
new file mode 100644
index 0000000000..a685092e2c
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/images/handlers.go
@@ -0,0 +1,323 @@
+/*
+ Copyright The containerd 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 images
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "sort"
+
+ "github.com/containerd/platforms"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+ "golang.org/x/sync/errgroup"
+ "golang.org/x/sync/semaphore"
+
+ "github.com/containerd/containerd/content"
+ "github.com/containerd/containerd/errdefs"
+)
+
+var (
+ // ErrSkipDesc is used to skip processing of a descriptor and
+ // its descendants.
+ ErrSkipDesc = errors.New("skip descriptor")
+
+ // ErrStopHandler is used to signify that the descriptor
+ // has been handled and should not be handled further.
+ // This applies only to a single descriptor in a handler
+ // chain and does not apply to descendant descriptors.
+ ErrStopHandler = errors.New("stop handler")
+
+ // ErrEmptyWalk is used when the WalkNotEmpty handlers return no
+ // children (e.g.: they were filtered out).
+ ErrEmptyWalk = errors.New("image might be filtered out")
+)
+
+// Handler handles image manifests
+type Handler interface {
+ Handle(ctx context.Context, desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error)
+}
+
+// HandlerFunc function implementing the Handler interface
+type HandlerFunc func(ctx context.Context, desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error)
+
+// Handle image manifests
+func (fn HandlerFunc) Handle(ctx context.Context, desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error) {
+ return fn(ctx, desc)
+}
+
+// Handlers returns a handler that will run the handlers in sequence.
+//
+// A handler may return `ErrStopHandler` to stop calling additional handlers
+func Handlers(handlers ...Handler) HandlerFunc {
+ return func(ctx context.Context, desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error) {
+ var children []ocispec.Descriptor
+ for _, handler := range handlers {
+ ch, err := handler.Handle(ctx, desc)
+ if err != nil {
+ if errors.Is(err, ErrStopHandler) {
+ break
+ }
+ return nil, err
+ }
+
+ children = append(children, ch...)
+ }
+
+ return children, nil
+ }
+}
+
+// Walk the resources of an image and call the handler for each. If the handler
+// decodes the sub-resources for each image,
+//
+// This differs from dispatch in that each sibling resource is considered
+// synchronously.
+func Walk(ctx context.Context, handler Handler, descs ...ocispec.Descriptor) error {
+ for _, desc := range descs {
+
+ children, err := handler.Handle(ctx, desc)
+ if err != nil {
+ if errors.Is(err, ErrSkipDesc) {
+ continue // don't traverse the children.
+ }
+ return err
+ }
+
+ if len(children) > 0 {
+ if err := Walk(ctx, handler, children...); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+// WalkNotEmpty works the same way Walk does, with the exception that it ensures that
+// some children are still found by Walking the descriptors (for example, not all of
+// them have been filtered out by one of the handlers). If there are no children,
+// then an ErrEmptyWalk error is returned.
+func WalkNotEmpty(ctx context.Context, handler Handler, descs ...ocispec.Descriptor) error {
+ isEmpty := true
+ var notEmptyHandler HandlerFunc = func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ children, err := handler.Handle(ctx, desc)
+ if err != nil {
+ return children, err
+ }
+
+ if len(children) > 0 {
+ isEmpty = false
+ }
+
+ return children, nil
+ }
+
+ err := Walk(ctx, notEmptyHandler, descs...)
+ if err != nil {
+ return err
+ }
+
+ if isEmpty {
+ return ErrEmptyWalk
+ }
+
+ return nil
+}
+
+// Dispatch runs the provided handler for content specified by the descriptors.
+// If the handler decode subresources, they will be visited, as well.
+//
+// Handlers for siblings are run in parallel on the provided descriptors. A
+// handler may return `ErrSkipDesc` to signal to the dispatcher to not traverse
+// any children.
+//
+// A concurrency limiter can be passed in to limit the number of concurrent
+// handlers running. When limiter is nil, there is no limit.
+//
+// Typically, this function will be used with `FetchHandler`, often composed
+// with other handlers.
+//
+// If any handler returns an error, the dispatch session will be canceled.
+func Dispatch(ctx context.Context, handler Handler, limiter *semaphore.Weighted, descs ...ocispec.Descriptor) error {
+ eg, ctx2 := errgroup.WithContext(ctx)
+ for _, desc := range descs {
+ desc := desc
+
+ if limiter != nil {
+ if err := limiter.Acquire(ctx, 1); err != nil {
+ return err
+ }
+ }
+
+ eg.Go(func() error {
+ desc := desc
+
+ children, err := handler.Handle(ctx2, desc)
+ if limiter != nil {
+ limiter.Release(1)
+ }
+ if err != nil {
+ if errors.Is(err, ErrSkipDesc) {
+ return nil // don't traverse the children.
+ }
+ return err
+ }
+
+ if len(children) > 0 {
+ return Dispatch(ctx2, handler, limiter, children...)
+ }
+
+ return nil
+ })
+ }
+
+ return eg.Wait()
+}
+
+// ChildrenHandler decodes well-known manifest types and returns their children.
+//
+// This is useful for supporting recursive fetch and other use cases where you
+// want to do a full walk of resources.
+//
+// One can also replace this with another implementation to allow descending of
+// arbitrary types.
+func ChildrenHandler(provider content.Provider) HandlerFunc {
+ return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ return Children(ctx, provider, desc)
+ }
+}
+
+// SetChildrenLabels is a handler wrapper which sets labels for the content on
+// the children returned by the handler and passes through the children.
+// Must follow a handler that returns the children to be labeled.
+func SetChildrenLabels(manager content.Manager, f HandlerFunc) HandlerFunc {
+ return SetChildrenMappedLabels(manager, f, nil)
+}
+
+// SetChildrenMappedLabels is a handler wrapper which sets labels for the content on
+// the children returned by the handler and passes through the children.
+// Must follow a handler that returns the children to be labeled.
+// The label map allows the caller to control the labels per child descriptor.
+// For returned labels, the index of the child will be appended to the end
+// except for the first index when the returned label does not end with '.'.
+func SetChildrenMappedLabels(manager content.Manager, f HandlerFunc, labelMap func(ocispec.Descriptor) []string) HandlerFunc {
+ if labelMap == nil {
+ labelMap = ChildGCLabels
+ }
+ return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ children, err := f(ctx, desc)
+ if err != nil {
+ return children, err
+ }
+
+ if len(children) > 0 {
+ var (
+ info = content.Info{
+ Digest: desc.Digest,
+ Labels: map[string]string{},
+ }
+ fields = []string{}
+ keys = map[string]uint{}
+ )
+ for _, ch := range children {
+ labelKeys := labelMap(ch)
+ for _, key := range labelKeys {
+ idx := keys[key]
+ keys[key] = idx + 1
+ if idx > 0 || key[len(key)-1] == '.' {
+ key = fmt.Sprintf("%s%d", key, idx)
+ }
+
+ info.Labels[key] = ch.Digest.String()
+ fields = append(fields, "labels."+key)
+ }
+ }
+
+ _, err := manager.Update(ctx, info, fields...)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return children, err
+ }
+}
+
+// FilterPlatforms is a handler wrapper which limits the descriptors returned
+// based on matching the specified platform matcher.
+func FilterPlatforms(f HandlerFunc, m platforms.Matcher) HandlerFunc {
+ return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ children, err := f(ctx, desc)
+ if err != nil {
+ return children, err
+ }
+
+ var descs []ocispec.Descriptor
+
+ if m == nil {
+ descs = children
+ } else {
+ for _, d := range children {
+ if d.Platform == nil || m.Match(*d.Platform) {
+ descs = append(descs, d)
+ }
+ }
+ }
+
+ return descs, nil
+ }
+}
+
+// LimitManifests is a handler wrapper which filters the manifest descriptors
+// returned using the provided platform.
+// The results will be ordered according to the comparison operator and
+// use the ordering in the manifests for equal matches.
+// A limit of 0 or less is considered no limit.
+// A not found error is returned if no manifest is matched.
+func LimitManifests(f HandlerFunc, m platforms.MatchComparer, n int) HandlerFunc {
+ return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ children, err := f(ctx, desc)
+ if err != nil {
+ return children, err
+ }
+
+ switch desc.MediaType {
+ case ocispec.MediaTypeImageIndex, MediaTypeDockerSchema2ManifestList:
+ sort.SliceStable(children, func(i, j int) bool {
+ if children[i].Platform == nil {
+ return false
+ }
+ if children[j].Platform == nil {
+ return true
+ }
+ return m.Less(*children[i].Platform, *children[j].Platform)
+ })
+
+ if n > 0 {
+ if len(children) == 0 {
+ return children, fmt.Errorf("no match for platform in manifest: %w", errdefs.ErrNotFound)
+ }
+ if len(children) > n {
+ children = children[:n]
+ }
+ }
+ default:
+ // only limit manifests from an index
+ }
+ return children, nil
+ }
+}
diff --git a/vendor/github.com/containerd/containerd/images/image.go b/vendor/github.com/containerd/containerd/images/image.go
new file mode 100644
index 0000000000..8bebae19b3
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/images/image.go
@@ -0,0 +1,444 @@
+/*
+ Copyright The containerd 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 images
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "sort"
+ "time"
+
+ "github.com/containerd/log"
+ "github.com/containerd/platforms"
+ digest "github.com/opencontainers/go-digest"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+
+ "github.com/containerd/containerd/content"
+ "github.com/containerd/containerd/errdefs"
+)
+
+// Image provides the model for how containerd views container images.
+type Image struct {
+ // Name of the image.
+ //
+ // To be pulled, it must be a reference compatible with resolvers.
+ //
+ // This field is required.
+ Name string
+
+ // Labels provide runtime decoration for the image record.
+ //
+ // There is no default behavior for how these labels are propagated. They
+ // only decorate the static metadata object.
+ //
+ // This field is optional.
+ Labels map[string]string
+
+ // Target describes the root content for this image. Typically, this is
+ // a manifest, index or manifest list.
+ Target ocispec.Descriptor
+
+ CreatedAt, UpdatedAt time.Time
+}
+
+// DeleteOptions provide options on image delete
+type DeleteOptions struct {
+ Synchronous bool
+}
+
+// DeleteOpt allows configuring a delete operation
+type DeleteOpt func(context.Context, *DeleteOptions) error
+
+// SynchronousDelete is used to indicate that an image deletion and removal of
+// the image resources should occur synchronously before returning a result.
+func SynchronousDelete() DeleteOpt {
+ return func(ctx context.Context, o *DeleteOptions) error {
+ o.Synchronous = true
+ return nil
+ }
+}
+
+// Store and interact with images
+type Store interface {
+ Get(ctx context.Context, name string) (Image, error)
+ List(ctx context.Context, filters ...string) ([]Image, error)
+ Create(ctx context.Context, image Image) (Image, error)
+
+ // Update will replace the data in the store with the provided image. If
+ // one or more fieldpaths are provided, only those fields will be updated.
+ Update(ctx context.Context, image Image, fieldpaths ...string) (Image, error)
+
+ Delete(ctx context.Context, name string, opts ...DeleteOpt) error
+}
+
+// TODO(stevvooe): Many of these functions make strong platform assumptions,
+// which are untrue in a lot of cases. More refactoring must be done here to
+// make this work in all cases.
+
+// Config resolves the image configuration descriptor.
+//
+// The caller can then use the descriptor to resolve and process the
+// configuration of the image.
+func (image *Image) Config(ctx context.Context, provider content.Provider, platform platforms.MatchComparer) (ocispec.Descriptor, error) {
+ return Config(ctx, provider, image.Target, platform)
+}
+
+// RootFS returns the unpacked diffids that make up and images rootfs.
+//
+// These are used to verify that a set of layers unpacked to the expected
+// values.
+func (image *Image) RootFS(ctx context.Context, provider content.Provider, platform platforms.MatchComparer) ([]digest.Digest, error) {
+ desc, err := image.Config(ctx, provider, platform)
+ if err != nil {
+ return nil, err
+ }
+ return RootFS(ctx, provider, desc)
+}
+
+// Size returns the total size of an image's packed resources.
+func (image *Image) Size(ctx context.Context, provider content.Provider, platform platforms.MatchComparer) (int64, error) {
+ var size int64
+ return size, Walk(ctx, Handlers(HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ if desc.Size < 0 {
+ return nil, fmt.Errorf("invalid size %v in %v (%v)", desc.Size, desc.Digest, desc.MediaType)
+ }
+ size += desc.Size
+ return nil, nil
+ }), LimitManifests(FilterPlatforms(ChildrenHandler(provider), platform), platform, 1)), image.Target)
+}
+
+type platformManifest struct {
+ p *ocispec.Platform
+ m *ocispec.Manifest
+}
+
+// Manifest resolves a manifest from the image for the given platform.
+//
+// When a manifest descriptor inside of a manifest index does not have
+// a platform defined, the platform from the image config is considered.
+//
+// If the descriptor points to a non-index manifest, then the manifest is
+// unmarshalled and returned without considering the platform inside of the
+// config.
+//
+// TODO(stevvooe): This violates the current platform agnostic approach to this
+// package by returning a specific manifest type. We'll need to refactor this
+// to return a manifest descriptor or decide that we want to bring the API in
+// this direction because this abstraction is not needed.
+func Manifest(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform platforms.MatchComparer) (ocispec.Manifest, error) {
+ var (
+ limit = 1
+ m []platformManifest
+ wasIndex bool
+ )
+
+ if err := Walk(ctx, HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ switch desc.MediaType {
+ case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
+ p, err := content.ReadBlob(ctx, provider, desc)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := validateMediaType(p, desc.MediaType); err != nil {
+ return nil, fmt.Errorf("manifest: invalid desc %s: %w", desc.Digest, err)
+ }
+
+ var manifest ocispec.Manifest
+ if err := json.Unmarshal(p, &manifest); err != nil {
+ return nil, err
+ }
+
+ if desc.Digest != image.Digest && platform != nil {
+ if desc.Platform != nil && !platform.Match(*desc.Platform) {
+ return nil, nil
+ }
+
+ if desc.Platform == nil {
+ p, err := content.ReadBlob(ctx, provider, manifest.Config)
+ if err != nil {
+ return nil, err
+ }
+
+ var image ocispec.Image
+ if err := json.Unmarshal(p, &image); err != nil {
+ return nil, err
+ }
+
+ if !platform.Match(platforms.Normalize(ocispec.Platform{OS: image.OS, Architecture: image.Architecture})) {
+ return nil, nil
+ }
+
+ }
+ }
+
+ m = append(m, platformManifest{
+ p: desc.Platform,
+ m: &manifest,
+ })
+
+ return nil, nil
+ case MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
+ p, err := content.ReadBlob(ctx, provider, desc)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := validateMediaType(p, desc.MediaType); err != nil {
+ return nil, fmt.Errorf("manifest: invalid desc %s: %w", desc.Digest, err)
+ }
+
+ var idx ocispec.Index
+ if err := json.Unmarshal(p, &idx); err != nil {
+ return nil, err
+ }
+
+ if platform == nil {
+ return idx.Manifests, nil
+ }
+
+ var descs []ocispec.Descriptor
+ for _, d := range idx.Manifests {
+ if d.Platform == nil || platform.Match(*d.Platform) {
+ descs = append(descs, d)
+ }
+ }
+
+ sort.SliceStable(descs, func(i, j int) bool {
+ if descs[i].Platform == nil {
+ return false
+ }
+ if descs[j].Platform == nil {
+ return true
+ }
+ return platform.Less(*descs[i].Platform, *descs[j].Platform)
+ })
+
+ wasIndex = true
+
+ if len(descs) > limit {
+ return descs[:limit], nil
+ }
+ return descs, nil
+ }
+ return nil, fmt.Errorf("unexpected media type %v for %v: %w", desc.MediaType, desc.Digest, errdefs.ErrNotFound)
+ }), image); err != nil {
+ return ocispec.Manifest{}, err
+ }
+
+ if len(m) == 0 {
+ err := fmt.Errorf("manifest %v: %w", image.Digest, errdefs.ErrNotFound)
+ if wasIndex {
+ err = fmt.Errorf("no match for platform in manifest %v: %w", image.Digest, errdefs.ErrNotFound)
+ }
+ return ocispec.Manifest{}, err
+ }
+ return *m[0].m, nil
+}
+
+// Config resolves the image configuration descriptor using a content provided
+// to resolve child resources on the image.
+//
+// The caller can then use the descriptor to resolve and process the
+// configuration of the image.
+func Config(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform platforms.MatchComparer) (ocispec.Descriptor, error) {
+ manifest, err := Manifest(ctx, provider, image, platform)
+ if err != nil {
+ return ocispec.Descriptor{}, err
+ }
+ return manifest.Config, err
+}
+
+// Platforms returns one or more platforms supported by the image.
+func Platforms(ctx context.Context, provider content.Provider, image ocispec.Descriptor) ([]ocispec.Platform, error) {
+ var platformSpecs []ocispec.Platform
+ return platformSpecs, Walk(ctx, Handlers(HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ if desc.Platform != nil {
+ if desc.Platform.OS == "unknown" || desc.Platform.Architecture == "unknown" {
+ return nil, ErrSkipDesc
+ }
+ platformSpecs = append(platformSpecs, *desc.Platform)
+ return nil, ErrSkipDesc
+ }
+
+ switch desc.MediaType {
+ case MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig:
+ p, err := content.ReadBlob(ctx, provider, desc)
+ if err != nil {
+ return nil, err
+ }
+
+ var image ocispec.Image
+ if err := json.Unmarshal(p, &image); err != nil {
+ return nil, err
+ }
+
+ platformSpecs = append(platformSpecs,
+ platforms.Normalize(ocispec.Platform{OS: image.OS, Architecture: image.Architecture}))
+ }
+ return nil, nil
+ }), ChildrenHandler(provider)), image)
+}
+
+// Check returns nil if the all components of an image are available in the
+// provider for the specified platform.
+//
+// If available is true, the caller can assume that required represents the
+// complete set of content required for the image.
+//
+// missing will have the components that are part of required but not available
+// in the provider.
+//
+// If there is a problem resolving content, an error will be returned.
+func Check(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform platforms.MatchComparer) (available bool, required, present, missing []ocispec.Descriptor, err error) {
+ mfst, err := Manifest(ctx, provider, image, platform)
+ if err != nil {
+ if errdefs.IsNotFound(err) {
+ return false, []ocispec.Descriptor{image}, nil, []ocispec.Descriptor{image}, nil
+ }
+
+ return false, nil, nil, nil, fmt.Errorf("failed to check image %v: %w", image.Digest, err)
+ }
+
+ // TODO(stevvooe): It is possible that referenced components could have
+ // children, but this is rare. For now, we ignore this and only verify
+ // that manifest components are present.
+ required = append([]ocispec.Descriptor{mfst.Config}, mfst.Layers...)
+
+ for _, desc := range required {
+ ra, err := provider.ReaderAt(ctx, desc)
+ if err != nil {
+ if errdefs.IsNotFound(err) {
+ missing = append(missing, desc)
+ continue
+ } else {
+ return false, nil, nil, nil, fmt.Errorf("failed to check image %v: %w", desc.Digest, err)
+ }
+ }
+ ra.Close()
+ present = append(present, desc)
+
+ }
+
+ return true, required, present, missing, nil
+}
+
+// Children returns the immediate children of content described by the descriptor.
+func Children(ctx context.Context, provider content.Provider, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ var descs []ocispec.Descriptor
+ switch desc.MediaType {
+ case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
+ p, err := content.ReadBlob(ctx, provider, desc)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := validateMediaType(p, desc.MediaType); err != nil {
+ return nil, fmt.Errorf("children: invalid desc %s: %w", desc.Digest, err)
+ }
+
+ // TODO(stevvooe): We just assume oci manifest, for now. There may be
+ // subtle differences from the docker version.
+ var manifest ocispec.Manifest
+ if err := json.Unmarshal(p, &manifest); err != nil {
+ return nil, err
+ }
+
+ descs = append(descs, manifest.Config)
+ descs = append(descs, manifest.Layers...)
+ case MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
+ p, err := content.ReadBlob(ctx, provider, desc)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := validateMediaType(p, desc.MediaType); err != nil {
+ return nil, fmt.Errorf("children: invalid desc %s: %w", desc.Digest, err)
+ }
+
+ var index ocispec.Index
+ if err := json.Unmarshal(p, &index); err != nil {
+ return nil, err
+ }
+
+ descs = append(descs, index.Manifests...)
+ default:
+ if IsLayerType(desc.MediaType) || IsKnownConfig(desc.MediaType) || IsAttestationType(desc.MediaType) {
+ // childless data types.
+ return nil, nil
+ }
+ log.G(ctx).Debugf("encountered unknown type %v; children may not be fetched", desc.MediaType)
+ }
+
+ return descs, nil
+}
+
+// unknownDocument represents a manifest, manifest list, or index that has not
+// yet been validated.
+type unknownDocument struct {
+ MediaType string `json:"mediaType,omitempty"`
+ Config json.RawMessage `json:"config,omitempty"`
+ Layers json.RawMessage `json:"layers,omitempty"`
+ Manifests json.RawMessage `json:"manifests,omitempty"`
+ FSLayers json.RawMessage `json:"fsLayers,omitempty"` // schema 1
+}
+
+// validateMediaType returns an error if the byte slice is invalid JSON or if
+// the media type identifies the blob as one format but it contains elements of
+// another format.
+func validateMediaType(b []byte, mt string) error {
+ var doc unknownDocument
+ if err := json.Unmarshal(b, &doc); err != nil {
+ return err
+ }
+ if len(doc.FSLayers) != 0 {
+ return fmt.Errorf("media-type: schema 1 not supported")
+ }
+ switch mt {
+ case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
+ if len(doc.Manifests) != 0 ||
+ doc.MediaType == MediaTypeDockerSchema2ManifestList ||
+ doc.MediaType == ocispec.MediaTypeImageIndex {
+ return fmt.Errorf("media-type: expected manifest but found index (%s)", mt)
+ }
+ case MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
+ if len(doc.Config) != 0 || len(doc.Layers) != 0 ||
+ doc.MediaType == MediaTypeDockerSchema2Manifest ||
+ doc.MediaType == ocispec.MediaTypeImageManifest {
+ return fmt.Errorf("media-type: expected index but found manifest (%s)", mt)
+ }
+ }
+ return nil
+}
+
+// RootFS returns the unpacked diffids that make up and images rootfs.
+//
+// These are used to verify that a set of layers unpacked to the expected
+// values.
+func RootFS(ctx context.Context, provider content.Provider, configDesc ocispec.Descriptor) ([]digest.Digest, error) {
+ p, err := content.ReadBlob(ctx, provider, configDesc)
+ if err != nil {
+ return nil, err
+ }
+
+ var config ocispec.Image
+ if err := json.Unmarshal(p, &config); err != nil {
+ return nil, err
+ }
+ return config.RootFS.DiffIDs, nil
+}
diff --git a/vendor/github.com/containerd/containerd/images/importexport.go b/vendor/github.com/containerd/containerd/images/importexport.go
new file mode 100644
index 0000000000..843adcadc7
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/images/importexport.go
@@ -0,0 +1,37 @@
+/*
+ Copyright The containerd 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 images
+
+import (
+ "context"
+ "io"
+
+ "github.com/containerd/containerd/content"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// Importer is the interface for image importer.
+type Importer interface {
+ // Import imports an image from a tar stream.
+ Import(ctx context.Context, store content.Store, reader io.Reader) (ocispec.Descriptor, error)
+}
+
+// Exporter is the interface for image exporter.
+type Exporter interface {
+ // Export exports an image to a tar stream.
+ Export(ctx context.Context, store content.Provider, desc ocispec.Descriptor, writer io.Writer) error
+}
diff --git a/vendor/github.com/containerd/containerd/images/labels.go b/vendor/github.com/containerd/containerd/images/labels.go
new file mode 100644
index 0000000000..06dfed572d
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/images/labels.go
@@ -0,0 +1,21 @@
+/*
+ Copyright The containerd 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 images
+
+const (
+ ConvertedDockerSchema1LabelKey = "io.containerd.image/converted-docker-schema1"
+)
diff --git a/vendor/github.com/containerd/containerd/images/mediatypes.go b/vendor/github.com/containerd/containerd/images/mediatypes.go
new file mode 100644
index 0000000000..49d2a5b1c5
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/images/mediatypes.go
@@ -0,0 +1,228 @@
+/*
+ Copyright The containerd 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 images
+
+import (
+ "context"
+ "fmt"
+ "sort"
+ "strings"
+
+ "github.com/containerd/containerd/errdefs"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// mediatype definitions for image components handled in containerd.
+//
+// oci components are generally referenced directly, although we may centralize
+// here for clarity.
+const (
+ MediaTypeDockerSchema2Layer = "application/vnd.docker.image.rootfs.diff.tar"
+ MediaTypeDockerSchema2LayerForeign = "application/vnd.docker.image.rootfs.foreign.diff.tar"
+ MediaTypeDockerSchema2LayerGzip = "application/vnd.docker.image.rootfs.diff.tar.gzip"
+ MediaTypeDockerSchema2LayerForeignGzip = "application/vnd.docker.image.rootfs.foreign.diff.tar.gzip"
+ MediaTypeDockerSchema2Config = "application/vnd.docker.container.image.v1+json"
+ MediaTypeDockerSchema2Manifest = "application/vnd.docker.distribution.manifest.v2+json"
+ MediaTypeDockerSchema2ManifestList = "application/vnd.docker.distribution.manifest.list.v2+json"
+
+ // Checkpoint/Restore Media Types
+
+ MediaTypeContainerd1Checkpoint = "application/vnd.containerd.container.criu.checkpoint.criu.tar"
+ MediaTypeContainerd1CheckpointPreDump = "application/vnd.containerd.container.criu.checkpoint.predump.tar"
+ MediaTypeContainerd1Resource = "application/vnd.containerd.container.resource.tar"
+ MediaTypeContainerd1RW = "application/vnd.containerd.container.rw.tar"
+ MediaTypeContainerd1CheckpointConfig = "application/vnd.containerd.container.checkpoint.config.v1+proto"
+ MediaTypeContainerd1CheckpointOptions = "application/vnd.containerd.container.checkpoint.options.v1+proto"
+ MediaTypeContainerd1CheckpointRuntimeName = "application/vnd.containerd.container.checkpoint.runtime.name"
+ MediaTypeContainerd1CheckpointRuntimeOptions = "application/vnd.containerd.container.checkpoint.runtime.options+proto"
+
+ // MediaTypeDockerSchema1Manifest is the legacy Docker schema1 manifest
+ MediaTypeDockerSchema1Manifest = "application/vnd.docker.distribution.manifest.v1+prettyjws"
+
+ // Encrypted media types
+
+ MediaTypeImageLayerEncrypted = ocispec.MediaTypeImageLayer + "+encrypted"
+ MediaTypeImageLayerGzipEncrypted = ocispec.MediaTypeImageLayerGzip + "+encrypted"
+
+ // In-toto attestation
+ MediaTypeInToto = "application/vnd.in-toto+json"
+)
+
+// DiffCompression returns the compression as defined by the layer diff media
+// type. For Docker media types without compression, "unknown" is returned to
+// indicate that the media type may be compressed. If the media type is not
+// recognized as a layer diff, then it returns errdefs.ErrNotImplemented
+func DiffCompression(ctx context.Context, mediaType string) (string, error) {
+ base, ext := parseMediaTypes(mediaType)
+ switch base {
+ case MediaTypeDockerSchema2Layer, MediaTypeDockerSchema2LayerForeign:
+ if len(ext) > 0 {
+ // Type is wrapped
+ return "", nil
+ }
+ // These media types may have been compressed but failed to
+ // use the correct media type. The decompression function
+ // should detect and handle this case.
+ return "unknown", nil
+ case MediaTypeDockerSchema2LayerGzip, MediaTypeDockerSchema2LayerForeignGzip:
+ if len(ext) > 0 {
+ // Type is wrapped
+ return "", nil
+ }
+ return "gzip", nil
+ case ocispec.MediaTypeImageLayer, ocispec.MediaTypeImageLayerNonDistributable: //nolint:staticcheck // Non-distributable layers are deprecated
+ if len(ext) > 0 {
+ switch ext[len(ext)-1] {
+ case "gzip":
+ return "gzip", nil
+ case "zstd":
+ return "zstd", nil
+ }
+ }
+ return "", nil
+ default:
+ return "", fmt.Errorf("unrecognised mediatype %s: %w", mediaType, errdefs.ErrNotImplemented)
+ }
+}
+
+// parseMediaTypes splits the media type into the base type and
+// an array of sorted extensions
+func parseMediaTypes(mt string) (mediaType string, suffixes []string) {
+ if mt == "" {
+ return "", []string{}
+ }
+ mediaType, ext, ok := strings.Cut(mt, "+")
+ if !ok {
+ return mediaType, []string{}
+ }
+
+ // Splitting the extensions following the mediatype "(+)gzip+encrypted".
+ // We expect this to be a limited list, so add an arbitrary limit (50).
+ //
+ // Note that DiffCompression is only using the last element, so perhaps we
+ // should split on the last "+" only.
+ suffixes = strings.SplitN(ext, "+", 50)
+ sort.Strings(suffixes)
+ return mediaType, suffixes
+}
+
+// IsNonDistributable returns true if the media type is non-distributable.
+func IsNonDistributable(mt string) bool {
+ return strings.HasPrefix(mt, "application/vnd.oci.image.layer.nondistributable.") ||
+ strings.HasPrefix(mt, "application/vnd.docker.image.rootfs.foreign.")
+}
+
+// IsLayerType returns true if the media type is a layer
+func IsLayerType(mt string) bool {
+ if strings.HasPrefix(mt, "application/vnd.oci.image.layer.") {
+ return true
+ }
+
+ // Parse Docker media types, strip off any + suffixes first
+ switch base, _ := parseMediaTypes(mt); base {
+ case MediaTypeDockerSchema2Layer, MediaTypeDockerSchema2LayerGzip,
+ MediaTypeDockerSchema2LayerForeign, MediaTypeDockerSchema2LayerForeignGzip:
+ return true
+ }
+ return false
+}
+
+// IsDockerType returns true if the media type has "application/vnd.docker." prefix
+func IsDockerType(mt string) bool {
+ return strings.HasPrefix(mt, "application/vnd.docker.")
+}
+
+// IsManifestType returns true if the media type is an OCI-compatible manifest.
+// No support for schema1 manifest.
+func IsManifestType(mt string) bool {
+ switch mt {
+ case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
+ return true
+ default:
+ return false
+ }
+}
+
+// IsIndexType returns true if the media type is an OCI-compatible index.
+func IsIndexType(mt string) bool {
+ switch mt {
+ case ocispec.MediaTypeImageIndex, MediaTypeDockerSchema2ManifestList:
+ return true
+ default:
+ return false
+ }
+}
+
+// IsConfigType returns true if the media type is an OCI-compatible image config.
+// No support for containerd checkpoint configs.
+func IsConfigType(mt string) bool {
+ switch mt {
+ case MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig:
+ return true
+ default:
+ return false
+ }
+}
+
+// IsKnownConfig returns true if the media type is a known config type,
+// including containerd checkpoint configs
+func IsKnownConfig(mt string) bool {
+ switch mt {
+ case MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig,
+ MediaTypeContainerd1Checkpoint, MediaTypeContainerd1CheckpointConfig:
+ return true
+ }
+ return false
+}
+
+// IsAttestationType returns true if the media type is an attestation type
+func IsAttestationType(mt string) bool {
+ switch mt {
+ case MediaTypeInToto:
+ return true
+ default:
+ return false
+ }
+}
+
+// ChildGCLabels returns the label for a given descriptor to reference it
+func ChildGCLabels(desc ocispec.Descriptor) []string {
+ mt := desc.MediaType
+ if IsKnownConfig(mt) {
+ return []string{"containerd.io/gc.ref.content.config"}
+ }
+
+ switch mt {
+ case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
+ return []string{"containerd.io/gc.ref.content.m."}
+ }
+
+ if IsLayerType(mt) {
+ return []string{"containerd.io/gc.ref.content.l."}
+ }
+
+ return []string{"containerd.io/gc.ref.content."}
+}
+
+// ChildGCLabelsFilterLayers returns the labels for a given descriptor to
+// reference it, skipping layer media types
+func ChildGCLabelsFilterLayers(desc ocispec.Descriptor) []string {
+ if IsLayerType(desc.MediaType) {
+ return nil
+ }
+ return ChildGCLabels(desc)
+}
diff --git a/vendor/github.com/containerd/containerd/labels/labels.go b/vendor/github.com/containerd/containerd/labels/labels.go
new file mode 100644
index 0000000000..0f9bab5c5d
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/labels/labels.go
@@ -0,0 +1,29 @@
+/*
+ Copyright The containerd 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 labels
+
+// LabelUncompressed is added to compressed layer contents.
+// The value is digest of the uncompressed content.
+const LabelUncompressed = "containerd.io/uncompressed"
+
+// LabelSharedNamespace is added to a namespace to allow that namespaces
+// contents to be shared.
+const LabelSharedNamespace = "containerd.io/namespace.shareable"
+
+// LabelDistributionSource is added to content to indicate its origin.
+// e.g., "containerd.io/distribution.source.docker.io=library/redis"
+const LabelDistributionSource = "containerd.io/distribution.source"
diff --git a/vendor/github.com/containerd/containerd/labels/validate.go b/vendor/github.com/containerd/containerd/labels/validate.go
new file mode 100644
index 0000000000..f83b5dde29
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/labels/validate.go
@@ -0,0 +1,41 @@
+/*
+ Copyright The containerd 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 labels
+
+import (
+ "fmt"
+
+ "github.com/containerd/containerd/errdefs"
+)
+
+const (
+ maxSize = 4096
+ // maximum length of key portion of error message if len of key + len of value > maxSize
+ keyMaxLen = 64
+)
+
+// Validate a label's key and value are under 4096 bytes
+func Validate(k, v string) error {
+ total := len(k) + len(v)
+ if total > maxSize {
+ if len(k) > keyMaxLen {
+ k = k[:keyMaxLen]
+ }
+ return fmt.Errorf("label key and value length (%d bytes) greater than maximum size (%d bytes), key: %s: %w", total, maxSize, k, errdefs.ErrInvalidArgument)
+ }
+ return nil
+}
diff --git a/vendor/github.com/containerd/containerd/pkg/randutil/randutil.go b/vendor/github.com/containerd/containerd/pkg/randutil/randutil.go
new file mode 100644
index 0000000000..f4b657d7dd
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/pkg/randutil/randutil.go
@@ -0,0 +1,48 @@
+/*
+ Copyright The containerd 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 randutil provides utilities for [cyrpto/rand].
+package randutil
+
+import (
+ "crypto/rand"
+ "math"
+ "math/big"
+)
+
+// Int63n is similar to [math/rand.Int63n] but uses [crypto/rand.Reader] under the hood.
+func Int63n(n int64) int64 {
+ b, err := rand.Int(rand.Reader, big.NewInt(n))
+ if err != nil {
+ panic(err)
+ }
+ return b.Int64()
+}
+
+// Int63 is similar to [math/rand.Int63] but uses [crypto/rand.Reader] under the hood.
+func Int63() int64 {
+ return Int63n(math.MaxInt64)
+}
+
+// Intn is similar to [math/rand.Intn] but uses [crypto/rand.Reader] under the hood.
+func Intn(n int) int {
+ return int(Int63n(int64(n)))
+}
+
+// Int is similar to [math/rand.Int] but uses [crypto/rand.Reader] under the hood.
+func Int() int {
+ return int(Int63())
+}
diff --git a/vendor/github.com/containerd/containerd/remotes/handlers.go b/vendor/github.com/containerd/containerd/remotes/handlers.go
new file mode 100644
index 0000000000..14af02769c
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/remotes/handlers.go
@@ -0,0 +1,416 @@
+/*
+ Copyright The containerd 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 remotes
+
+import (
+ "bytes"
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "strings"
+ "sync"
+
+ "github.com/containerd/log"
+ "github.com/containerd/platforms"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+ "golang.org/x/sync/semaphore"
+
+ "github.com/containerd/containerd/content"
+ "github.com/containerd/containerd/errdefs"
+ "github.com/containerd/containerd/images"
+ "github.com/containerd/containerd/labels"
+)
+
+type refKeyPrefix struct{}
+
+// WithMediaTypeKeyPrefix adds a custom key prefix for a media type which is used when storing
+// data in the content store from the FetchHandler.
+//
+// Used in `MakeRefKey` to determine what the key prefix should be.
+func WithMediaTypeKeyPrefix(ctx context.Context, mediaType, prefix string) context.Context {
+ var values map[string]string
+ if v := ctx.Value(refKeyPrefix{}); v != nil {
+ values = v.(map[string]string)
+ } else {
+ values = make(map[string]string)
+ }
+
+ values[mediaType] = prefix
+ return context.WithValue(ctx, refKeyPrefix{}, values)
+}
+
+// MakeRefKey returns a unique reference for the descriptor. This reference can be
+// used to lookup ongoing processes related to the descriptor. This function
+// may look to the context to namespace the reference appropriately.
+func MakeRefKey(ctx context.Context, desc ocispec.Descriptor) string {
+ key := desc.Digest.String()
+ if desc.Annotations != nil {
+ if name, ok := desc.Annotations[ocispec.AnnotationRefName]; ok {
+ key = fmt.Sprintf("%s@%s", name, desc.Digest.String())
+ }
+ }
+
+ if v := ctx.Value(refKeyPrefix{}); v != nil {
+ values := v.(map[string]string)
+ if prefix := values[desc.MediaType]; prefix != "" {
+ return prefix + "-" + key
+ }
+ }
+
+ switch mt := desc.MediaType; {
+ case mt == images.MediaTypeDockerSchema2Manifest || mt == ocispec.MediaTypeImageManifest:
+ return "manifest-" + key
+ case mt == images.MediaTypeDockerSchema2ManifestList || mt == ocispec.MediaTypeImageIndex:
+ return "index-" + key
+ case images.IsLayerType(mt):
+ return "layer-" + key
+ case images.IsKnownConfig(mt):
+ return "config-" + key
+ case images.IsAttestationType(desc.MediaType):
+ return "attestation-" + key
+ default:
+ log.G(ctx).Warnf("reference for unknown type: %s", mt)
+ return "unknown-" + key
+ }
+}
+
+// FetchHandler returns a handler that will fetch all content into the ingester
+// discovered in a call to Dispatch. Use with ChildrenHandler to do a full
+// recursive fetch.
+func FetchHandler(ingester content.Ingester, fetcher Fetcher) images.HandlerFunc {
+ return func(ctx context.Context, desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error) {
+ ctx = log.WithLogger(ctx, log.G(ctx).WithFields(log.Fields{
+ "digest": desc.Digest,
+ "mediatype": desc.MediaType,
+ "size": desc.Size,
+ }))
+
+ switch desc.MediaType {
+ case images.MediaTypeDockerSchema1Manifest:
+ return nil, fmt.Errorf("%v not supported", desc.MediaType)
+ default:
+ err := Fetch(ctx, ingester, fetcher, desc)
+ if errdefs.IsAlreadyExists(err) {
+ return nil, nil
+ }
+ return nil, err
+ }
+ }
+}
+
+// Fetch fetches the given digest into the provided ingester
+func Fetch(ctx context.Context, ingester content.Ingester, fetcher Fetcher, desc ocispec.Descriptor) error {
+ log.G(ctx).Debug("fetch")
+
+ cw, err := content.OpenWriter(ctx, ingester, content.WithRef(MakeRefKey(ctx, desc)), content.WithDescriptor(desc))
+ if err != nil {
+ return err
+ }
+ defer cw.Close()
+
+ ws, err := cw.Status()
+ if err != nil {
+ return err
+ }
+
+ if desc.Size == 0 {
+ // most likely a poorly configured registry/web front end which responded with no
+ // Content-Length header; unable (not to mention useless) to commit a 0-length entry
+ // into the content store. Error out here otherwise the error sent back is confusing
+ return fmt.Errorf("unable to fetch descriptor (%s) which reports content size of zero: %w", desc.Digest, errdefs.ErrInvalidArgument)
+ }
+ if ws.Offset == desc.Size {
+ // If writer is already complete, commit and return
+ err := cw.Commit(ctx, desc.Size, desc.Digest)
+ if err != nil && !errdefs.IsAlreadyExists(err) {
+ return fmt.Errorf("failed commit on ref %q: %w", ws.Ref, err)
+ }
+ return err
+ }
+
+ if desc.Size == int64(len(desc.Data)) {
+ return content.Copy(ctx, cw, bytes.NewReader(desc.Data), desc.Size, desc.Digest)
+ }
+
+ rc, err := fetcher.Fetch(ctx, desc)
+ if err != nil {
+ return err
+ }
+ defer rc.Close()
+
+ return content.Copy(ctx, cw, rc, desc.Size, desc.Digest)
+}
+
+// PushHandler returns a handler that will push all content from the provider
+// using a writer from the pusher.
+func PushHandler(pusher Pusher, provider content.Provider) images.HandlerFunc {
+ return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ ctx = log.WithLogger(ctx, log.G(ctx).WithFields(log.Fields{
+ "digest": desc.Digest,
+ "mediatype": desc.MediaType,
+ "size": desc.Size,
+ }))
+
+ err := push(ctx, provider, pusher, desc)
+ return nil, err
+ }
+}
+
+func push(ctx context.Context, provider content.Provider, pusher Pusher, desc ocispec.Descriptor) error {
+ log.G(ctx).Debug("push")
+
+ var (
+ cw content.Writer
+ err error
+ )
+ if cs, ok := pusher.(content.Ingester); ok {
+ cw, err = content.OpenWriter(ctx, cs, content.WithRef(MakeRefKey(ctx, desc)), content.WithDescriptor(desc))
+ } else {
+ cw, err = pusher.Push(ctx, desc)
+ }
+ if err != nil {
+ if !errdefs.IsAlreadyExists(err) {
+ return err
+ }
+
+ return nil
+ }
+ defer cw.Close()
+
+ ra, err := provider.ReaderAt(ctx, desc)
+ if err != nil {
+ return err
+ }
+ defer ra.Close()
+
+ rd := io.NewSectionReader(ra, 0, desc.Size)
+ return content.Copy(ctx, cw, rd, desc.Size, desc.Digest)
+}
+
+// PushContent pushes content specified by the descriptor from the provider.
+//
+// Base handlers can be provided which will be called before any push specific
+// handlers.
+//
+// If the passed in content.Provider is also a content.InfoProvider (such as
+// content.Manager) then this will also annotate the distribution sources using
+// labels prefixed with "containerd.io/distribution.source".
+func PushContent(ctx context.Context, pusher Pusher, desc ocispec.Descriptor, store content.Provider, limiter *semaphore.Weighted, platform platforms.MatchComparer, wrapper func(h images.Handler) images.Handler) error {
+
+ var m sync.Mutex
+ manifests := []ocispec.Descriptor{}
+ indexStack := []ocispec.Descriptor{}
+
+ filterHandler := images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ switch desc.MediaType {
+ case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
+ m.Lock()
+ manifests = append(manifests, desc)
+ m.Unlock()
+ return nil, images.ErrStopHandler
+ case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
+ m.Lock()
+ indexStack = append(indexStack, desc)
+ m.Unlock()
+ return nil, images.ErrStopHandler
+ default:
+ return nil, nil
+ }
+ })
+
+ pushHandler := PushHandler(pusher, store)
+
+ platformFilterhandler := images.FilterPlatforms(images.ChildrenHandler(store), platform)
+
+ var handler images.Handler
+ if m, ok := store.(content.InfoProvider); ok {
+ annotateHandler := annotateDistributionSourceHandler(platformFilterhandler, m)
+ handler = images.Handlers(annotateHandler, filterHandler, pushHandler)
+ } else {
+ handler = images.Handlers(platformFilterhandler, filterHandler, pushHandler)
+ }
+
+ if wrapper != nil {
+ handler = wrapper(handler)
+ }
+
+ if err := images.Dispatch(ctx, handler, limiter, desc); err != nil {
+ return err
+ }
+
+ if err := images.Dispatch(ctx, pushHandler, limiter, manifests...); err != nil {
+ return err
+ }
+
+ // Iterate in reverse order as seen, parent always uploaded after child
+ for i := len(indexStack) - 1; i >= 0; i-- {
+ err := images.Dispatch(ctx, pushHandler, limiter, indexStack[i])
+ if err != nil {
+ // TODO(estesp): until we have a more complete method for index push, we need to report
+ // missing dependencies in an index/manifest list by sensing the "400 Bad Request"
+ // as a marker for this problem
+ if errors.Unwrap(err) != nil && strings.Contains(errors.Unwrap(err).Error(), "400 Bad Request") {
+ return fmt.Errorf("manifest list/index references to blobs and/or manifests are missing in your target registry: %w", err)
+ }
+ return err
+ }
+ }
+
+ return nil
+}
+
+// SkipNonDistributableBlobs returns a handler that skips blobs that have a media type that is "non-distributeable".
+// An example of this kind of content would be a Windows base layer, which is not supposed to be redistributed.
+//
+// This is based on the media type of the content:
+// - application/vnd.oci.image.layer.nondistributable
+// - application/vnd.docker.image.rootfs.foreign
+func SkipNonDistributableBlobs(f images.HandlerFunc) images.HandlerFunc {
+ return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ if images.IsNonDistributable(desc.MediaType) {
+ log.G(ctx).WithField("digest", desc.Digest).WithField("mediatype", desc.MediaType).Debug("Skipping non-distributable blob")
+ return nil, images.ErrSkipDesc
+ }
+
+ if images.IsLayerType(desc.MediaType) {
+ return nil, nil
+ }
+
+ children, err := f(ctx, desc)
+ if err != nil {
+ return nil, err
+ }
+ if len(children) == 0 {
+ return nil, nil
+ }
+
+ out := make([]ocispec.Descriptor, 0, len(children))
+ for _, child := range children {
+ if !images.IsNonDistributable(child.MediaType) {
+ out = append(out, child)
+ } else {
+ log.G(ctx).WithField("digest", child.Digest).WithField("mediatype", child.MediaType).Debug("Skipping non-distributable blob")
+ }
+ }
+ return out, nil
+ }
+}
+
+// FilterManifestByPlatformHandler allows Handler to handle non-target
+// platform's manifest and configuration data.
+func FilterManifestByPlatformHandler(f images.HandlerFunc, m platforms.Matcher) images.HandlerFunc {
+ return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ children, err := f(ctx, desc)
+ if err != nil {
+ return nil, err
+ }
+
+ // no platform information
+ if desc.Platform == nil || m == nil {
+ return children, nil
+ }
+
+ var descs []ocispec.Descriptor
+ switch desc.MediaType {
+ case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
+ if m.Match(*desc.Platform) {
+ descs = children
+ } else {
+ for _, child := range children {
+ if child.MediaType == images.MediaTypeDockerSchema2Config ||
+ child.MediaType == ocispec.MediaTypeImageConfig {
+
+ descs = append(descs, child)
+ }
+ }
+ }
+ default:
+ descs = children
+ }
+ return descs, nil
+ }
+}
+
+// annotateDistributionSourceHandler add distribution source label into
+// annotation of config or blob descriptor.
+func annotateDistributionSourceHandler(f images.HandlerFunc, provider content.InfoProvider) images.HandlerFunc {
+ return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
+ children, err := f(ctx, desc)
+ if err != nil {
+ return nil, err
+ }
+
+ // Distribution source is only used for config or blob but may be inherited from
+ // a manifest or manifest list
+ switch desc.MediaType {
+ case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest,
+ images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
+ default:
+ return children, nil
+ }
+
+ parentSourceAnnotations := desc.Annotations
+ var parentLabels map[string]string
+ if pi, err := provider.Info(ctx, desc.Digest); err != nil {
+ if !errdefs.IsNotFound(err) {
+ return nil, err
+ }
+ } else {
+ parentLabels = pi.Labels
+ }
+
+ for i := range children {
+ child := children[i]
+
+ info, err := provider.Info(ctx, child.Digest)
+ if err != nil {
+ if !errdefs.IsNotFound(err) {
+ return nil, err
+ }
+ }
+ copyDistributionSourceLabels(info.Labels, &child)
+
+ // Annotate with parent labels for cross repo mount or fetch.
+ // Parent sources may apply to all children since most registries
+ // enforce that children exist before the manifests.
+ copyDistributionSourceLabels(parentSourceAnnotations, &child)
+ copyDistributionSourceLabels(parentLabels, &child)
+
+ children[i] = child
+ }
+ return children, nil
+ }
+}
+
+func copyDistributionSourceLabels(from map[string]string, to *ocispec.Descriptor) {
+ for k, v := range from {
+ if !strings.HasPrefix(k, labels.LabelDistributionSource+".") {
+ continue
+ }
+
+ if to.Annotations == nil {
+ to.Annotations = make(map[string]string)
+ } else {
+ // Only propagate the parent label if the child doesn't already have it.
+ if _, has := to.Annotations[k]; has {
+ continue
+ }
+ }
+ to.Annotations[k] = v
+ }
+}
diff --git a/vendor/github.com/containerd/containerd/remotes/resolver.go b/vendor/github.com/containerd/containerd/remotes/resolver.go
new file mode 100644
index 0000000000..f200c84bc7
--- /dev/null
+++ b/vendor/github.com/containerd/containerd/remotes/resolver.go
@@ -0,0 +1,94 @@
+/*
+ Copyright The containerd 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 remotes
+
+import (
+ "context"
+ "io"
+
+ "github.com/containerd/containerd/content"
+ "github.com/opencontainers/go-digest"
+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// Resolver provides remotes based on a locator.
+type Resolver interface {
+ // Resolve attempts to resolve the reference into a name and descriptor.
+ //
+ // The argument `ref` should be a scheme-less URI representing the remote.
+ // Structurally, it has a host and path. The "host" can be used to directly
+ // reference a specific host or be matched against a specific handler.
+ //
+ // The returned name should be used to identify the referenced entity.
+ // Depending on the remote namespace, this may be immutable or mutable.
+ // While the name may differ from ref, it should itself be a valid ref.
+ //
+ // If the resolution fails, an error will be returned.
+ Resolve(ctx context.Context, ref string) (name string, desc ocispec.Descriptor, err error)
+
+ // Fetcher returns a new fetcher for the provided reference.
+ // All content fetched from the returned fetcher will be
+ // from the namespace referred to by ref.
+ Fetcher(ctx context.Context, ref string) (Fetcher, error)
+
+ // Pusher returns a new pusher for the provided reference
+ // The returned Pusher should satisfy content.Ingester and concurrent attempts
+ // to push the same blob using the Ingester API should result in ErrUnavailable.
+ Pusher(ctx context.Context, ref string) (Pusher, error)
+}
+
+// Fetcher fetches content.
+// A fetcher implementation may implement the FetcherByDigest interface too.
+type Fetcher interface {
+ // Fetch the resource identified by the descriptor.
+ Fetch(ctx context.Context, desc ocispec.Descriptor) (io.ReadCloser, error)
+}
+
+// FetcherByDigest fetches content by the digest.
+type FetcherByDigest interface {
+ // FetchByDigest fetches the resource identified by the digest.
+ //
+ // FetcherByDigest usually returns an incomplete descriptor.
+ // Typically, the media type is always set to "application/octet-stream",
+ // and the annotations are unset.
+ FetchByDigest(ctx context.Context, dgst digest.Digest) (io.ReadCloser, ocispec.Descriptor, error)
+}
+
+// Pusher pushes content
+type Pusher interface {
+ // Push returns a content writer for the given resource identified
+ // by the descriptor.
+ Push(ctx context.Context, d ocispec.Descriptor) (content.Writer, error)
+}
+
+// FetcherFunc allows package users to implement a Fetcher with just a
+// function.
+type FetcherFunc func(ctx context.Context, desc ocispec.Descriptor) (io.ReadCloser, error)
+
+// Fetch content
+func (fn FetcherFunc) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.ReadCloser, error) {
+ return fn(ctx, desc)
+}
+
+// PusherFunc allows package users to implement a Pusher with just a
+// function.
+type PusherFunc func(ctx context.Context, desc ocispec.Descriptor) (content.Writer, error)
+
+// Push content
+func (fn PusherFunc) Push(ctx context.Context, desc ocispec.Descriptor) (content.Writer, error) {
+ return fn(ctx, desc)
+}
diff --git a/vendor/github.com/containerd/errdefs/LICENSE b/vendor/github.com/containerd/errdefs/LICENSE
new file mode 100644
index 0000000000..584149b6ee
--- /dev/null
+++ b/vendor/github.com/containerd/errdefs/LICENSE
@@ -0,0 +1,191 @@
+
+ Apache License
+ Version 2.0, January 2004
+ https://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ Copyright The containerd 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
+
+ https://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.
diff --git a/vendor/github.com/containerd/errdefs/README.md b/vendor/github.com/containerd/errdefs/README.md
new file mode 100644
index 0000000000..bd418c63f9
--- /dev/null
+++ b/vendor/github.com/containerd/errdefs/README.md
@@ -0,0 +1,13 @@
+# errdefs
+
+A Go package for defining and checking common containerd errors.
+
+## Project details
+
+**errdefs** is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
+As a containerd sub-project, you will find the:
+ * [Project governance](https://github.com/containerd/project/blob/main/GOVERNANCE.md),
+ * [Maintainers](https://github.com/containerd/project/blob/main/MAINTAINERS),
+ * and [Contributing guidelines](https://github.com/containerd/project/blob/main/CONTRIBUTING.md)
+
+information in our [`containerd/project`](https://github.com/containerd/project) repository.
diff --git a/vendor/github.com/containerd/errdefs/errors.go b/vendor/github.com/containerd/errdefs/errors.go
new file mode 100644
index 0000000000..f654d19649
--- /dev/null
+++ b/vendor/github.com/containerd/errdefs/errors.go
@@ -0,0 +1,443 @@
+/*
+ Copyright The containerd 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 errdefs defines the common errors used throughout containerd
+// packages.
+//
+// Use with fmt.Errorf to add context to an error.
+//
+// To detect an error class, use the IsXXX functions to tell whether an error
+// is of a certain type.
+package errdefs
+
+import (
+ "context"
+ "errors"
+)
+
+// Definitions of common error types used throughout containerd. All containerd
+// errors returned by most packages will map into one of these errors classes.
+// Packages should return errors of these types when they want to instruct a
+// client to take a particular action.
+//
+// These errors map closely to grpc errors.
+var (
+ ErrUnknown = errUnknown{}
+ ErrInvalidArgument = errInvalidArgument{}
+ ErrNotFound = errNotFound{}
+ ErrAlreadyExists = errAlreadyExists{}
+ ErrPermissionDenied = errPermissionDenied{}
+ ErrResourceExhausted = errResourceExhausted{}
+ ErrFailedPrecondition = errFailedPrecondition{}
+ ErrConflict = errConflict{}
+ ErrNotModified = errNotModified{}
+ ErrAborted = errAborted{}
+ ErrOutOfRange = errOutOfRange{}
+ ErrNotImplemented = errNotImplemented{}
+ ErrInternal = errInternal{}
+ ErrUnavailable = errUnavailable{}
+ ErrDataLoss = errDataLoss{}
+ ErrUnauthenticated = errUnauthorized{}
+)
+
+// cancelled maps to Moby's "ErrCancelled"
+type cancelled interface {
+ Cancelled()
+}
+
+// IsCanceled returns true if the error is due to `context.Canceled`.
+func IsCanceled(err error) bool {
+ return errors.Is(err, context.Canceled) || isInterface[cancelled](err)
+}
+
+type errUnknown struct{}
+
+func (errUnknown) Error() string { return "unknown" }
+
+func (errUnknown) Unknown() {}
+
+func (e errUnknown) WithMessage(msg string) error {
+ return customMessage{e, msg}
+}
+
+// unknown maps to Moby's "ErrUnknown"
+type unknown interface {
+ Unknown()
+}
+
+// IsUnknown returns true if the error is due to an unknown error,
+// unhandled condition or unexpected response.
+func IsUnknown(err error) bool {
+ return errors.Is(err, errUnknown{}) || isInterface[unknown](err)
+}
+
+type errInvalidArgument struct{}
+
+func (errInvalidArgument) Error() string { return "invalid argument" }
+
+func (errInvalidArgument) InvalidParameter() {}
+
+func (e errInvalidArgument) WithMessage(msg string) error {
+ return customMessage{e, msg}
+}
+
+// invalidParameter maps to Moby's "ErrInvalidParameter"
+type invalidParameter interface {
+ InvalidParameter()
+}
+
+// IsInvalidArgument returns true if the error is due to an invalid argument
+func IsInvalidArgument(err error) bool {
+ return errors.Is(err, ErrInvalidArgument) || isInterface[invalidParameter](err)
+}
+
+// deadlineExceed maps to Moby's "ErrDeadline"
+type deadlineExceeded interface {
+ DeadlineExceeded()
+}
+
+// IsDeadlineExceeded returns true if the error is due to
+// `context.DeadlineExceeded`.
+func IsDeadlineExceeded(err error) bool {
+ return errors.Is(err, context.DeadlineExceeded) || isInterface[deadlineExceeded](err)
+}
+
+type errNotFound struct{}
+
+func (errNotFound) Error() string { return "not found" }
+
+func (errNotFound) NotFound() {}
+
+func (e errNotFound) WithMessage(msg string) error {
+ return customMessage{e, msg}
+}
+
+// notFound maps to Moby's "ErrNotFound"
+type notFound interface {
+ NotFound()
+}
+
+// IsNotFound returns true if the error is due to a missing object
+func IsNotFound(err error) bool {
+ return errors.Is(err, ErrNotFound) || isInterface[notFound](err)
+}
+
+type errAlreadyExists struct{}
+
+func (errAlreadyExists) Error() string { return "already exists" }
+
+func (errAlreadyExists) AlreadyExists() {}
+
+func (e errAlreadyExists) WithMessage(msg string) error {
+ return customMessage{e, msg}
+}
+
+type alreadyExists interface {
+ AlreadyExists()
+}
+
+// IsAlreadyExists returns true if the error is due to an already existing
+// metadata item
+func IsAlreadyExists(err error) bool {
+ return errors.Is(err, ErrAlreadyExists) || isInterface[alreadyExists](err)
+}
+
+type errPermissionDenied struct{}
+
+func (errPermissionDenied) Error() string { return "permission denied" }
+
+func (errPermissionDenied) Forbidden() {}
+
+func (e errPermissionDenied) WithMessage(msg string) error {
+ return customMessage{e, msg}
+}
+
+// forbidden maps to Moby's "ErrForbidden"
+type forbidden interface {
+ Forbidden()
+}
+
+// IsPermissionDenied returns true if the error is due to permission denied
+// or forbidden (403) response
+func IsPermissionDenied(err error) bool {
+ return errors.Is(err, ErrPermissionDenied) || isInterface[forbidden](err)
+}
+
+type errResourceExhausted struct{}
+
+func (errResourceExhausted) Error() string { return "resource exhausted" }
+
+func (errResourceExhausted) ResourceExhausted() {}
+
+func (e errResourceExhausted) WithMessage(msg string) error {
+ return customMessage{e, msg}
+}
+
+type resourceExhausted interface {
+ ResourceExhausted()
+}
+
+// IsResourceExhausted returns true if the error is due to
+// a lack of resources or too many attempts.
+func IsResourceExhausted(err error) bool {
+ return errors.Is(err, errResourceExhausted{}) || isInterface[resourceExhausted](err)
+}
+
+type errFailedPrecondition struct{}
+
+func (e errFailedPrecondition) Error() string { return "failed precondition" }
+
+func (errFailedPrecondition) FailedPrecondition() {}
+
+func (e errFailedPrecondition) WithMessage(msg string) error {
+ return customMessage{e, msg}
+}
+
+type failedPrecondition interface {
+ FailedPrecondition()
+}
+
+// IsFailedPrecondition returns true if an operation could not proceed due to
+// the lack of a particular condition
+func IsFailedPrecondition(err error) bool {
+ return errors.Is(err, errFailedPrecondition{}) || isInterface[failedPrecondition](err)
+}
+
+type errConflict struct{}
+
+func (errConflict) Error() string { return "conflict" }
+
+func (errConflict) Conflict() {}
+
+func (e errConflict) WithMessage(msg string) error {
+ return customMessage{e, msg}
+}
+
+// conflict maps to Moby's "ErrConflict"
+type conflict interface {
+ Conflict()
+}
+
+// IsConflict returns true if an operation could not proceed due to
+// a conflict.
+func IsConflict(err error) bool {
+ return errors.Is(err, errConflict{}) || isInterface[conflict](err)
+}
+
+type errNotModified struct{}
+
+func (errNotModified) Error() string { return "not modified" }
+
+func (errNotModified) NotModified() {}
+
+func (e errNotModified) WithMessage(msg string) error {
+ return customMessage{e, msg}
+}
+
+// notModified maps to Moby's "ErrNotModified"
+type notModified interface {
+ NotModified()
+}
+
+// IsNotModified returns true if an operation could not proceed due
+// to an object not modified from a previous state.
+func IsNotModified(err error) bool {
+ return errors.Is(err, errNotModified{}) || isInterface[notModified](err)
+}
+
+type errAborted struct{}
+
+func (errAborted) Error() string { return "aborted" }
+
+func (errAborted) Aborted() {}
+
+func (e errAborted) WithMessage(msg string) error {
+ return customMessage{e, msg}
+}
+
+type aborted interface {
+ Aborted()
+}
+
+// IsAborted returns true if an operation was aborted.
+func IsAborted(err error) bool {
+ return errors.Is(err, errAborted{}) || isInterface[aborted](err)
+}
+
+type errOutOfRange struct{}
+
+func (errOutOfRange) Error() string { return "out of range" }
+
+func (errOutOfRange) OutOfRange() {}
+
+func (e errOutOfRange) WithMessage(msg string) error {
+ return customMessage{e, msg}
+}
+
+type outOfRange interface {
+ OutOfRange()
+}
+
+// IsOutOfRange returns true if an operation could not proceed due
+// to data being out of the expected range.
+func IsOutOfRange(err error) bool {
+ return errors.Is(err, errOutOfRange{}) || isInterface[outOfRange](err)
+}
+
+type errNotImplemented struct{}
+
+func (errNotImplemented) Error() string { return "not implemented" }
+
+func (errNotImplemented) NotImplemented() {}
+
+func (e errNotImplemented) WithMessage(msg string) error {
+ return customMessage{e, msg}
+}
+
+// notImplemented maps to Moby's "ErrNotImplemented"
+type notImplemented interface {
+ NotImplemented()
+}
+
+// IsNotImplemented returns true if the error is due to not being implemented
+func IsNotImplemented(err error) bool {
+ return errors.Is(err, errNotImplemented{}) || isInterface[notImplemented](err)
+}
+
+type errInternal struct{}
+
+func (errInternal) Error() string { return "internal" }
+
+func (errInternal) System() {}
+
+func (e errInternal) WithMessage(msg string) error {
+ return customMessage{e, msg}
+}
+
+// system maps to Moby's "ErrSystem"
+type system interface {
+ System()
+}
+
+// IsInternal returns true if the error returns to an internal or system error
+func IsInternal(err error) bool {
+ return errors.Is(err, errInternal{}) || isInterface[system](err)
+}
+
+type errUnavailable struct{}
+
+func (errUnavailable) Error() string { return "unavailable" }
+
+func (errUnavailable) Unavailable() {}
+
+func (e errUnavailable) WithMessage(msg string) error {
+ return customMessage{e, msg}
+}
+
+// unavailable maps to Moby's "ErrUnavailable"
+type unavailable interface {
+ Unavailable()
+}
+
+// IsUnavailable returns true if the error is due to a resource being unavailable
+func IsUnavailable(err error) bool {
+ return errors.Is(err, errUnavailable{}) || isInterface[unavailable](err)
+}
+
+type errDataLoss struct{}
+
+func (errDataLoss) Error() string { return "data loss" }
+
+func (errDataLoss) DataLoss() {}
+
+func (e errDataLoss) WithMessage(msg string) error {
+ return customMessage{e, msg}
+}
+
+// dataLoss maps to Moby's "ErrDataLoss"
+type dataLoss interface {
+ DataLoss()
+}
+
+// IsDataLoss returns true if data during an operation was lost or corrupted
+func IsDataLoss(err error) bool {
+ return errors.Is(err, errDataLoss{}) || isInterface[dataLoss](err)
+}
+
+type errUnauthorized struct{}
+
+func (errUnauthorized) Error() string { return "unauthorized" }
+
+func (errUnauthorized) Unauthorized() {}
+
+func (e errUnauthorized) WithMessage(msg string) error {
+ return customMessage{e, msg}
+}
+
+// unauthorized maps to Moby's "ErrUnauthorized"
+type unauthorized interface {
+ Unauthorized()
+}
+
+// IsUnauthorized returns true if the error indicates that the user was
+// unauthenticated or unauthorized.
+func IsUnauthorized(err error) bool {
+ return errors.Is(err, errUnauthorized{}) || isInterface[unauthorized](err)
+}
+
+func isInterface[T any](err error) bool {
+ for {
+ switch x := err.(type) {
+ case T:
+ return true
+ case customMessage:
+ err = x.err
+ case interface{ Unwrap() error }:
+ err = x.Unwrap()
+ if err == nil {
+ return false
+ }
+ case interface{ Unwrap() []error }:
+ for _, err := range x.Unwrap() {
+ if isInterface[T](err) {
+ return true
+ }
+ }
+ return false
+ default:
+ return false
+ }
+ }
+}
+
+// customMessage is used to provide a defined error with a custom message.
+// The message is not wrapped but can be compared by the `Is(error) bool` interface.
+type customMessage struct {
+ err error
+ msg string
+}
+
+func (c customMessage) Is(err error) bool {
+ return c.err == err
+}
+
+func (c customMessage) As(target any) bool {
+ return errors.As(c.err, target)
+}
+
+func (c customMessage) Error() string {
+ return c.msg
+}
diff --git a/vendor/github.com/containerd/errdefs/resolve.go b/vendor/github.com/containerd/errdefs/resolve.go
new file mode 100644
index 0000000000..c02d4a73f4
--- /dev/null
+++ b/vendor/github.com/containerd/errdefs/resolve.go
@@ -0,0 +1,147 @@
+/*
+ Copyright The containerd 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 errdefs
+
+import "context"
+
+// Resolve returns the first error found in the error chain which matches an
+// error defined in this package or context error. A raw, unwrapped error is
+// returned or ErrUnknown if no matching error is found.
+//
+// This is useful for determining a response code based on the outermost wrapped
+// error rather than the original cause. For example, a not found error deep
+// in the code may be wrapped as an invalid argument. When determining status
+// code from Is* functions, the depth or ordering of the error is not
+// considered.
+//
+// The search order is depth first, a wrapped error returned from any part of
+// the chain from `Unwrap() error` will be returned before any joined errors
+// as returned by `Unwrap() []error`.
+func Resolve(err error) error {
+ if err == nil {
+ return nil
+ }
+ err = firstError(err)
+ if err == nil {
+ err = ErrUnknown
+ }
+ return err
+}
+
+func firstError(err error) error {
+ for {
+ switch err {
+ case ErrUnknown,
+ ErrInvalidArgument,
+ ErrNotFound,
+ ErrAlreadyExists,
+ ErrPermissionDenied,
+ ErrResourceExhausted,
+ ErrFailedPrecondition,
+ ErrConflict,
+ ErrNotModified,
+ ErrAborted,
+ ErrOutOfRange,
+ ErrNotImplemented,
+ ErrInternal,
+ ErrUnavailable,
+ ErrDataLoss,
+ ErrUnauthenticated,
+ context.DeadlineExceeded,
+ context.Canceled:
+ return err
+ }
+ switch e := err.(type) {
+ case customMessage:
+ err = e.err
+ case unknown:
+ return ErrUnknown
+ case invalidParameter:
+ return ErrInvalidArgument
+ case notFound:
+ return ErrNotFound
+ case alreadyExists:
+ return ErrAlreadyExists
+ case forbidden:
+ return ErrPermissionDenied
+ case resourceExhausted:
+ return ErrResourceExhausted
+ case failedPrecondition:
+ return ErrFailedPrecondition
+ case conflict:
+ return ErrConflict
+ case notModified:
+ return ErrNotModified
+ case aborted:
+ return ErrAborted
+ case errOutOfRange:
+ return ErrOutOfRange
+ case notImplemented:
+ return ErrNotImplemented
+ case system:
+ return ErrInternal
+ case unavailable:
+ return ErrUnavailable
+ case dataLoss:
+ return ErrDataLoss
+ case unauthorized:
+ return ErrUnauthenticated
+ case deadlineExceeded:
+ return context.DeadlineExceeded
+ case cancelled:
+ return context.Canceled
+ case interface{ Unwrap() error }:
+ err = e.Unwrap()
+ if err == nil {
+ return nil
+ }
+ case interface{ Unwrap() []error }:
+ for _, ue := range e.Unwrap() {
+ if fe := firstError(ue); fe != nil {
+ return fe
+ }
+ }
+ return nil
+ case interface{ Is(error) bool }:
+ for _, target := range []error{ErrUnknown,
+ ErrInvalidArgument,
+ ErrNotFound,
+ ErrAlreadyExists,
+ ErrPermissionDenied,
+ ErrResourceExhausted,
+ ErrFailedPrecondition,
+ ErrConflict,
+ ErrNotModified,
+ ErrAborted,
+ ErrOutOfRange,
+ ErrNotImplemented,
+ ErrInternal,
+ ErrUnavailable,
+ ErrDataLoss,
+ ErrUnauthenticated,
+ context.DeadlineExceeded,
+ context.Canceled} {
+ if e.Is(target) {
+ return target
+ }
+ }
+ return nil
+ default:
+ return nil
+ }
+ }
+}
diff --git a/vendor/github.com/containerd/log/.golangci.yml b/vendor/github.com/containerd/log/.golangci.yml
new file mode 100644
index 0000000000..a695775df4
--- /dev/null
+++ b/vendor/github.com/containerd/log/.golangci.yml
@@ -0,0 +1,30 @@
+linters:
+ enable:
+ - exportloopref # Checks for pointers to enclosing loop variables
+ - gofmt
+ - goimports
+ - gosec
+ - ineffassign
+ - misspell
+ - nolintlint
+ - revive
+ - staticcheck
+ - tenv # Detects using os.Setenv instead of t.Setenv since Go 1.17
+ - unconvert
+ - unused
+ - vet
+ - dupword # Checks for duplicate words in the source code
+ disable:
+ - errcheck
+
+run:
+ timeout: 5m
+ skip-dirs:
+ - api
+ - cluster
+ - design
+ - docs
+ - docs/man
+ - releases
+ - reports
+ - test # e2e scripts
diff --git a/vendor/github.com/containerd/log/LICENSE b/vendor/github.com/containerd/log/LICENSE
new file mode 100644
index 0000000000..584149b6ee
--- /dev/null
+++ b/vendor/github.com/containerd/log/LICENSE
@@ -0,0 +1,191 @@
+
+ Apache License
+ Version 2.0, January 2004
+ https://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ Copyright The containerd 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
+
+ https://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.
diff --git a/vendor/github.com/containerd/log/README.md b/vendor/github.com/containerd/log/README.md
new file mode 100644
index 0000000000..00e0849880
--- /dev/null
+++ b/vendor/github.com/containerd/log/README.md
@@ -0,0 +1,17 @@
+# log
+
+A Go package providing a common logging interface across containerd repositories and a way for clients to use and configure logging in containerd packages.
+
+This package is not intended to be used as a standalone logging package outside of the containerd ecosystem and is intended as an interface wrapper around a logging implementation.
+In the future this package may be replaced with a common go logging interface.
+
+## Project details
+
+**log** is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
+As a containerd sub-project, you will find the:
+ * [Project governance](https://github.com/containerd/project/blob/main/GOVERNANCE.md),
+ * [Maintainers](https://github.com/containerd/project/blob/main/MAINTAINERS),
+ * and [Contributing guidelines](https://github.com/containerd/project/blob/main/CONTRIBUTING.md)
+
+information in our [`containerd/project`](https://github.com/containerd/project) repository.
+
diff --git a/vendor/github.com/containerd/log/context.go b/vendor/github.com/containerd/log/context.go
new file mode 100644
index 0000000000..20153066f3
--- /dev/null
+++ b/vendor/github.com/containerd/log/context.go
@@ -0,0 +1,182 @@
+/*
+ Copyright The containerd 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 log provides types and functions related to logging, passing
+// loggers through a context, and attaching context to the logger.
+//
+// # Transitional types
+//
+// This package contains various types that are aliases for types in [logrus].
+// These aliases are intended for transitioning away from hard-coding logrus
+// as logging implementation. Consumers of this package are encouraged to use
+// the type-aliases from this package instead of directly using their logrus
+// equivalent.
+//
+// The intent is to replace these aliases with locally defined types and
+// interfaces once all consumers are no longer directly importing logrus
+// types.
+//
+// IMPORTANT: due to the transitional purpose of this package, it is not
+// guaranteed for the full logrus API to be provided in the future. As
+// outlined, these aliases are provided as a step to transition away from
+// a specific implementation which, as a result, exposes the full logrus API.
+// While no decisions have been made on the ultimate design and interface
+// provided by this package, we do not expect carrying "less common" features.
+package log
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/sirupsen/logrus"
+)
+
+// G is a shorthand for [GetLogger].
+//
+// We may want to define this locally to a package to get package tagged log
+// messages.
+var G = GetLogger
+
+// L is an alias for the standard logger.
+var L = &Entry{
+ Logger: logrus.StandardLogger(),
+ // Default is three fields plus a little extra room.
+ Data: make(Fields, 6),
+}
+
+type loggerKey struct{}
+
+// Fields type to pass to "WithFields".
+type Fields = map[string]any
+
+// Entry is a logging entry. It contains all the fields passed with
+// [Entry.WithFields]. It's finally logged when Trace, Debug, Info, Warn,
+// Error, Fatal or Panic is called on it. These objects can be reused and
+// passed around as much as you wish to avoid field duplication.
+//
+// Entry is a transitional type, and currently an alias for [logrus.Entry].
+type Entry = logrus.Entry
+
+// RFC3339NanoFixed is [time.RFC3339Nano] with nanoseconds padded using
+// zeros to ensure the formatted time is always the same number of
+// characters.
+const RFC3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00"
+
+// Level is a logging level.
+type Level = logrus.Level
+
+// Supported log levels.
+const (
+ // TraceLevel level. Designates finer-grained informational events
+ // than [DebugLevel].
+ TraceLevel Level = logrus.TraceLevel
+
+ // DebugLevel level. Usually only enabled when debugging. Very verbose
+ // logging.
+ DebugLevel Level = logrus.DebugLevel
+
+ // InfoLevel level. General operational entries about what's going on
+ // inside the application.
+ InfoLevel Level = logrus.InfoLevel
+
+ // WarnLevel level. Non-critical entries that deserve eyes.
+ WarnLevel Level = logrus.WarnLevel
+
+ // ErrorLevel level. Logs errors that should definitely be noted.
+ // Commonly used for hooks to send errors to an error tracking service.
+ ErrorLevel Level = logrus.ErrorLevel
+
+ // FatalLevel level. Logs and then calls "logger.Exit(1)". It exits
+ // even if the logging level is set to Panic.
+ FatalLevel Level = logrus.FatalLevel
+
+ // PanicLevel level. This is the highest level of severity. Logs and
+ // then calls panic with the message passed to Debug, Info, ...
+ PanicLevel Level = logrus.PanicLevel
+)
+
+// SetLevel sets log level globally. It returns an error if the given
+// level is not supported.
+//
+// level can be one of:
+//
+// - "trace" ([TraceLevel])
+// - "debug" ([DebugLevel])
+// - "info" ([InfoLevel])
+// - "warn" ([WarnLevel])
+// - "error" ([ErrorLevel])
+// - "fatal" ([FatalLevel])
+// - "panic" ([PanicLevel])
+func SetLevel(level string) error {
+ lvl, err := logrus.ParseLevel(level)
+ if err != nil {
+ return err
+ }
+
+ L.Logger.SetLevel(lvl)
+ return nil
+}
+
+// GetLevel returns the current log level.
+func GetLevel() Level {
+ return L.Logger.GetLevel()
+}
+
+// OutputFormat specifies a log output format.
+type OutputFormat string
+
+// Supported log output formats.
+const (
+ // TextFormat represents the text logging format.
+ TextFormat OutputFormat = "text"
+
+ // JSONFormat represents the JSON logging format.
+ JSONFormat OutputFormat = "json"
+)
+
+// SetFormat sets the log output format ([TextFormat] or [JSONFormat]).
+func SetFormat(format OutputFormat) error {
+ switch format {
+ case TextFormat:
+ L.Logger.SetFormatter(&logrus.TextFormatter{
+ TimestampFormat: RFC3339NanoFixed,
+ FullTimestamp: true,
+ })
+ return nil
+ case JSONFormat:
+ L.Logger.SetFormatter(&logrus.JSONFormatter{
+ TimestampFormat: RFC3339NanoFixed,
+ })
+ return nil
+ default:
+ return fmt.Errorf("unknown log format: %s", format)
+ }
+}
+
+// WithLogger returns a new context with the provided logger. Use in
+// combination with logger.WithField(s) for great effect.
+func WithLogger(ctx context.Context, logger *Entry) context.Context {
+ return context.WithValue(ctx, loggerKey{}, logger.WithContext(ctx))
+}
+
+// GetLogger retrieves the current logger from the context. If no logger is
+// available, the default logger is returned.
+func GetLogger(ctx context.Context) *Entry {
+ if logger := ctx.Value(loggerKey{}); logger != nil {
+ return logger.(*Entry)
+ }
+ return L.WithContext(ctx)
+}
diff --git a/vendor/github.com/containerd/platforms/.gitattributes b/vendor/github.com/containerd/platforms/.gitattributes
new file mode 100644
index 0000000000..a0717e4b3b
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/.gitattributes
@@ -0,0 +1 @@
+*.go text eol=lf
\ No newline at end of file
diff --git a/vendor/github.com/containerd/platforms/.golangci.yml b/vendor/github.com/containerd/platforms/.golangci.yml
new file mode 100644
index 0000000000..a695775df4
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/.golangci.yml
@@ -0,0 +1,30 @@
+linters:
+ enable:
+ - exportloopref # Checks for pointers to enclosing loop variables
+ - gofmt
+ - goimports
+ - gosec
+ - ineffassign
+ - misspell
+ - nolintlint
+ - revive
+ - staticcheck
+ - tenv # Detects using os.Setenv instead of t.Setenv since Go 1.17
+ - unconvert
+ - unused
+ - vet
+ - dupword # Checks for duplicate words in the source code
+ disable:
+ - errcheck
+
+run:
+ timeout: 5m
+ skip-dirs:
+ - api
+ - cluster
+ - design
+ - docs
+ - docs/man
+ - releases
+ - reports
+ - test # e2e scripts
diff --git a/vendor/github.com/containerd/platforms/LICENSE b/vendor/github.com/containerd/platforms/LICENSE
new file mode 100644
index 0000000000..584149b6ee
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/LICENSE
@@ -0,0 +1,191 @@
+
+ Apache License
+ Version 2.0, January 2004
+ https://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ Copyright The containerd 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
+
+ https://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.
diff --git a/vendor/github.com/containerd/platforms/README.md b/vendor/github.com/containerd/platforms/README.md
new file mode 100644
index 0000000000..2059de771c
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/README.md
@@ -0,0 +1,32 @@
+# platforms
+
+A Go package for formatting, normalizing and matching container platforms.
+
+This package is based on the Open Containers Image Spec definition of a [platform](https://github.com/opencontainers/image-spec/blob/main/specs-go/v1/descriptor.go#L52).
+
+## Platform Specifier
+
+While the OCI platform specifications provide a tool for components to
+specify structured information, user input typically doesn't need the full
+context and much can be inferred. To solve this problem, this package introduces
+"specifiers". A specifier has the format
+`||/[/]`. The user can provide either the
+operating system or the architecture or both.
+
+An example of a common specifier is `linux/amd64`. If the host has a default
+runtime that matches this, the user can simply provide the component that
+matters. For example, if an image provides `amd64` and `arm64` support, the
+operating system, `linux` can be inferred, so they only have to provide
+`arm64` or `amd64`. Similar behavior is implemented for operating systems,
+where the architecture may be known but a runtime may support images from
+different operating systems.
+
+## Project details
+
+**platforms** is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
+As a containerd sub-project, you will find the:
+ * [Project governance](https://github.com/containerd/project/blob/main/GOVERNANCE.md),
+ * [Maintainers](https://github.com/containerd/project/blob/main/MAINTAINERS),
+ * and [Contributing guidelines](https://github.com/containerd/project/blob/main/CONTRIBUTING.md)
+
+information in our [`containerd/project`](https://github.com/containerd/project) repository.
\ No newline at end of file
diff --git a/vendor/github.com/containerd/platforms/compare.go b/vendor/github.com/containerd/platforms/compare.go
new file mode 100644
index 0000000000..3913ef6637
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/compare.go
@@ -0,0 +1,203 @@
+/*
+ Copyright The containerd 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 platforms
+
+import (
+ "strconv"
+ "strings"
+
+ specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// MatchComparer is able to match and compare platforms to
+// filter and sort platforms.
+type MatchComparer interface {
+ Matcher
+
+ Less(specs.Platform, specs.Platform) bool
+}
+
+// platformVector returns an (ordered) vector of appropriate specs.Platform
+// objects to try matching for the given platform object (see platforms.Only).
+func platformVector(platform specs.Platform) []specs.Platform {
+ vector := []specs.Platform{platform}
+
+ switch platform.Architecture {
+ case "amd64":
+ if amd64Version, err := strconv.Atoi(strings.TrimPrefix(platform.Variant, "v")); err == nil && amd64Version > 1 {
+ for amd64Version--; amd64Version >= 1; amd64Version-- {
+ vector = append(vector, specs.Platform{
+ Architecture: platform.Architecture,
+ OS: platform.OS,
+ OSVersion: platform.OSVersion,
+ OSFeatures: platform.OSFeatures,
+ Variant: "v" + strconv.Itoa(amd64Version),
+ })
+ }
+ }
+ vector = append(vector, specs.Platform{
+ Architecture: "386",
+ OS: platform.OS,
+ OSVersion: platform.OSVersion,
+ OSFeatures: platform.OSFeatures,
+ })
+ case "arm":
+ if armVersion, err := strconv.Atoi(strings.TrimPrefix(platform.Variant, "v")); err == nil && armVersion > 5 {
+ for armVersion--; armVersion >= 5; armVersion-- {
+ vector = append(vector, specs.Platform{
+ Architecture: platform.Architecture,
+ OS: platform.OS,
+ OSVersion: platform.OSVersion,
+ OSFeatures: platform.OSFeatures,
+ Variant: "v" + strconv.Itoa(armVersion),
+ })
+ }
+ }
+ case "arm64":
+ variant := platform.Variant
+ if variant == "" {
+ variant = "v8"
+ }
+ vector = append(vector, platformVector(specs.Platform{
+ Architecture: "arm",
+ OS: platform.OS,
+ OSVersion: platform.OSVersion,
+ OSFeatures: platform.OSFeatures,
+ Variant: variant,
+ })...)
+ }
+
+ return vector
+}
+
+// Only returns a match comparer for a single platform
+// using default resolution logic for the platform.
+//
+// For arm/v8, will also match arm/v7, arm/v6 and arm/v5
+// For arm/v7, will also match arm/v6 and arm/v5
+// For arm/v6, will also match arm/v5
+// For amd64, will also match 386
+func Only(platform specs.Platform) MatchComparer {
+ return Ordered(platformVector(Normalize(platform))...)
+}
+
+// OnlyStrict returns a match comparer for a single platform.
+//
+// Unlike Only, OnlyStrict does not match sub platforms.
+// So, "arm/vN" will not match "arm/vM" where M < N,
+// and "amd64" will not also match "386".
+//
+// OnlyStrict matches non-canonical forms.
+// So, "arm64" matches "arm/64/v8".
+func OnlyStrict(platform specs.Platform) MatchComparer {
+ return Ordered(Normalize(platform))
+}
+
+// Ordered returns a platform MatchComparer which matches any of the platforms
+// but orders them in order they are provided.
+func Ordered(platforms ...specs.Platform) MatchComparer {
+ matchers := make([]Matcher, len(platforms))
+ for i := range platforms {
+ matchers[i] = NewMatcher(platforms[i])
+ }
+ return orderedPlatformComparer{
+ matchers: matchers,
+ }
+}
+
+// Any returns a platform MatchComparer which matches any of the platforms
+// with no preference for ordering.
+func Any(platforms ...specs.Platform) MatchComparer {
+ matchers := make([]Matcher, len(platforms))
+ for i := range platforms {
+ matchers[i] = NewMatcher(platforms[i])
+ }
+ return anyPlatformComparer{
+ matchers: matchers,
+ }
+}
+
+// All is a platform MatchComparer which matches all platforms
+// with preference for ordering.
+var All MatchComparer = allPlatformComparer{}
+
+type orderedPlatformComparer struct {
+ matchers []Matcher
+}
+
+func (c orderedPlatformComparer) Match(platform specs.Platform) bool {
+ for _, m := range c.matchers {
+ if m.Match(platform) {
+ return true
+ }
+ }
+ return false
+}
+
+func (c orderedPlatformComparer) Less(p1 specs.Platform, p2 specs.Platform) bool {
+ for _, m := range c.matchers {
+ p1m := m.Match(p1)
+ p2m := m.Match(p2)
+ if p1m && !p2m {
+ return true
+ }
+ if p1m || p2m {
+ return false
+ }
+ }
+ return false
+}
+
+type anyPlatformComparer struct {
+ matchers []Matcher
+}
+
+func (c anyPlatformComparer) Match(platform specs.Platform) bool {
+ for _, m := range c.matchers {
+ if m.Match(platform) {
+ return true
+ }
+ }
+ return false
+}
+
+func (c anyPlatformComparer) Less(p1, p2 specs.Platform) bool {
+ var p1m, p2m bool
+ for _, m := range c.matchers {
+ if !p1m && m.Match(p1) {
+ p1m = true
+ }
+ if !p2m && m.Match(p2) {
+ p2m = true
+ }
+ if p1m && p2m {
+ return false
+ }
+ }
+ // If one matches, and the other does, sort match first
+ return p1m && !p2m
+}
+
+type allPlatformComparer struct{}
+
+func (allPlatformComparer) Match(specs.Platform) bool {
+ return true
+}
+
+func (allPlatformComparer) Less(specs.Platform, specs.Platform) bool {
+ return false
+}
diff --git a/vendor/github.com/containerd/platforms/cpuinfo.go b/vendor/github.com/containerd/platforms/cpuinfo.go
new file mode 100644
index 0000000000..91f50e8c88
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/cpuinfo.go
@@ -0,0 +1,43 @@
+/*
+ Copyright The containerd 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 platforms
+
+import (
+ "runtime"
+ "sync"
+
+ "github.com/containerd/log"
+)
+
+// Present the ARM instruction set architecture, eg: v7, v8
+// Don't use this value directly; call cpuVariant() instead.
+var cpuVariantValue string
+
+var cpuVariantOnce sync.Once
+
+func cpuVariant() string {
+ cpuVariantOnce.Do(func() {
+ if isArmArch(runtime.GOARCH) {
+ var err error
+ cpuVariantValue, err = getCPUVariant()
+ if err != nil {
+ log.L.Errorf("Error getCPUVariant for OS %s: %v", runtime.GOOS, err)
+ }
+ }
+ })
+ return cpuVariantValue
+}
diff --git a/vendor/github.com/containerd/platforms/cpuinfo_linux.go b/vendor/github.com/containerd/platforms/cpuinfo_linux.go
new file mode 100644
index 0000000000..98c7001f93
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/cpuinfo_linux.go
@@ -0,0 +1,160 @@
+/*
+ Copyright The containerd 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 platforms
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "fmt"
+ "os"
+ "runtime"
+ "strings"
+
+ "golang.org/x/sys/unix"
+)
+
+// getMachineArch retrieves the machine architecture through system call
+func getMachineArch() (string, error) {
+ var uname unix.Utsname
+ err := unix.Uname(&uname)
+ if err != nil {
+ return "", err
+ }
+
+ arch := string(uname.Machine[:bytes.IndexByte(uname.Machine[:], 0)])
+
+ return arch, nil
+}
+
+// For Linux, the kernel has already detected the ABI, ISA and Features.
+// So we don't need to access the ARM registers to detect platform information
+// by ourselves. We can just parse these information from /proc/cpuinfo
+func getCPUInfo(pattern string) (info string, err error) {
+
+ cpuinfo, err := os.Open("/proc/cpuinfo")
+ if err != nil {
+ return "", err
+ }
+ defer cpuinfo.Close()
+
+ // Start to Parse the Cpuinfo line by line. For SMP SoC, we parse
+ // the first core is enough.
+ scanner := bufio.NewScanner(cpuinfo)
+ for scanner.Scan() {
+ newline := scanner.Text()
+ list := strings.Split(newline, ":")
+
+ if len(list) > 1 && strings.EqualFold(strings.TrimSpace(list[0]), pattern) {
+ return strings.TrimSpace(list[1]), nil
+ }
+ }
+
+ // Check whether the scanner encountered errors
+ err = scanner.Err()
+ if err != nil {
+ return "", err
+ }
+
+ return "", fmt.Errorf("getCPUInfo for pattern %s: %w", pattern, errNotFound)
+}
+
+// getCPUVariantFromArch get CPU variant from arch through a system call
+func getCPUVariantFromArch(arch string) (string, error) {
+
+ var variant string
+
+ arch = strings.ToLower(arch)
+
+ if arch == "aarch64" {
+ variant = "8"
+ } else if arch[0:4] == "armv" && len(arch) >= 5 {
+ // Valid arch format is in form of armvXx
+ switch arch[3:5] {
+ case "v8":
+ variant = "8"
+ case "v7":
+ variant = "7"
+ case "v6":
+ variant = "6"
+ case "v5":
+ variant = "5"
+ case "v4":
+ variant = "4"
+ case "v3":
+ variant = "3"
+ default:
+ variant = "unknown"
+ }
+ } else {
+ return "", fmt.Errorf("getCPUVariantFromArch invalid arch: %s, %w", arch, errInvalidArgument)
+ }
+ return variant, nil
+}
+
+// getCPUVariant returns cpu variant for ARM
+// We first try reading "Cpu architecture" field from /proc/cpuinfo
+// If we can't find it, then fall back using a system call
+// This is to cover running ARM in emulated environment on x86 host as this field in /proc/cpuinfo
+// was not present.
+func getCPUVariant() (string, error) {
+ variant, err := getCPUInfo("Cpu architecture")
+ if err != nil {
+ if errors.Is(err, errNotFound) {
+ // Let's try getting CPU variant from machine architecture
+ arch, err := getMachineArch()
+ if err != nil {
+ return "", fmt.Errorf("failure getting machine architecture: %v", err)
+ }
+
+ variant, err = getCPUVariantFromArch(arch)
+ if err != nil {
+ return "", fmt.Errorf("failure getting CPU variant from machine architecture: %v", err)
+ }
+ } else {
+ return "", fmt.Errorf("failure getting CPU variant: %v", err)
+ }
+ }
+
+ // handle edge case for Raspberry Pi ARMv6 devices (which due to a kernel quirk, report "CPU architecture: 7")
+ // https://www.raspberrypi.org/forums/viewtopic.php?t=12614
+ if runtime.GOARCH == "arm" && variant == "7" {
+ model, err := getCPUInfo("model name")
+ if err == nil && strings.HasPrefix(strings.ToLower(model), "armv6-compatible") {
+ variant = "6"
+ }
+ }
+
+ switch strings.ToLower(variant) {
+ case "8", "aarch64":
+ variant = "v8"
+ case "7", "7m", "?(12)", "?(13)", "?(14)", "?(15)", "?(16)", "?(17)":
+ variant = "v7"
+ case "6", "6tej":
+ variant = "v6"
+ case "5", "5t", "5te", "5tej":
+ variant = "v5"
+ case "4", "4t":
+ variant = "v4"
+ case "3":
+ variant = "v3"
+ default:
+ variant = "unknown"
+ }
+
+ return variant, nil
+}
diff --git a/vendor/github.com/containerd/platforms/cpuinfo_other.go b/vendor/github.com/containerd/platforms/cpuinfo_other.go
new file mode 100644
index 0000000000..97a1fe8a3e
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/cpuinfo_other.go
@@ -0,0 +1,55 @@
+//go:build !linux
+
+/*
+ Copyright The containerd 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 platforms
+
+import (
+ "fmt"
+ "runtime"
+)
+
+func getCPUVariant() (string, error) {
+
+ var variant string
+
+ if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
+ // Windows/Darwin only supports v7 for ARM32 and v8 for ARM64 and so we can use
+ // runtime.GOARCH to determine the variants
+ switch runtime.GOARCH {
+ case "arm64":
+ variant = "v8"
+ case "arm":
+ variant = "v7"
+ default:
+ variant = "unknown"
+ }
+ } else if runtime.GOOS == "freebsd" {
+ // FreeBSD supports ARMv6 and ARMv7 as well as ARMv4 and ARMv5 (though deprecated)
+ // detecting those variants is currently unimplemented
+ switch runtime.GOARCH {
+ case "arm64":
+ variant = "v8"
+ default:
+ variant = "unknown"
+ }
+ } else {
+ return "", fmt.Errorf("getCPUVariant for OS %s: %v", runtime.GOOS, errNotImplemented)
+ }
+
+ return variant, nil
+}
diff --git a/vendor/github.com/containerd/platforms/database.go b/vendor/github.com/containerd/platforms/database.go
new file mode 100644
index 0000000000..2e26fd3b4f
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/database.go
@@ -0,0 +1,109 @@
+/*
+ Copyright The containerd 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 platforms
+
+import (
+ "runtime"
+ "strings"
+)
+
+// These function are generated from https://golang.org/src/go/build/syslist.go.
+//
+// We use switch statements because they are slightly faster than map lookups
+// and use a little less memory.
+
+// isKnownOS returns true if we know about the operating system.
+//
+// The OS value should be normalized before calling this function.
+func isKnownOS(os string) bool {
+ switch os {
+ case "aix", "android", "darwin", "dragonfly", "freebsd", "hurd", "illumos", "ios", "js", "linux", "nacl", "netbsd", "openbsd", "plan9", "solaris", "windows", "zos":
+ return true
+ }
+ return false
+}
+
+// isArmArch returns true if the architecture is ARM.
+//
+// The arch value should be normalized before being passed to this function.
+func isArmArch(arch string) bool {
+ switch arch {
+ case "arm", "arm64":
+ return true
+ }
+ return false
+}
+
+// isKnownArch returns true if we know about the architecture.
+//
+// The arch value should be normalized before being passed to this function.
+func isKnownArch(arch string) bool {
+ switch arch {
+ case "386", "amd64", "amd64p32", "arm", "armbe", "arm64", "arm64be", "ppc64", "ppc64le", "loong64", "mips", "mipsle", "mips64", "mips64le", "mips64p32", "mips64p32le", "ppc", "riscv", "riscv64", "s390", "s390x", "sparc", "sparc64", "wasm":
+ return true
+ }
+ return false
+}
+
+func normalizeOS(os string) string {
+ if os == "" {
+ return runtime.GOOS
+ }
+ os = strings.ToLower(os)
+
+ switch os {
+ case "macos":
+ os = "darwin"
+ }
+ return os
+}
+
+// normalizeArch normalizes the architecture.
+func normalizeArch(arch, variant string) (string, string) {
+ arch, variant = strings.ToLower(arch), strings.ToLower(variant)
+ switch arch {
+ case "i386":
+ arch = "386"
+ variant = ""
+ case "x86_64", "x86-64", "amd64":
+ arch = "amd64"
+ if variant == "v1" {
+ variant = ""
+ }
+ case "aarch64", "arm64":
+ arch = "arm64"
+ switch variant {
+ case "8", "v8":
+ variant = ""
+ }
+ case "armhf":
+ arch = "arm"
+ variant = "v7"
+ case "armel":
+ arch = "arm"
+ variant = "v6"
+ case "arm":
+ switch variant {
+ case "", "7":
+ variant = "v7"
+ case "5", "6", "8":
+ variant = "v" + variant
+ }
+ }
+
+ return arch, variant
+}
diff --git a/vendor/github.com/containerd/platforms/defaults.go b/vendor/github.com/containerd/platforms/defaults.go
new file mode 100644
index 0000000000..9d898d60e6
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/defaults.go
@@ -0,0 +1,29 @@
+/*
+ Copyright The containerd 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 platforms
+
+// DefaultString returns the default string specifier for the platform,
+// with [PR#6](https://github.com/containerd/platforms/pull/6) the result
+// may now also include the OSVersion from the provided platform specification.
+func DefaultString() string {
+ return FormatAll(DefaultSpec())
+}
+
+// DefaultStrict returns strict form of Default.
+func DefaultStrict() MatchComparer {
+ return OnlyStrict(DefaultSpec())
+}
diff --git a/vendor/github.com/containerd/platforms/defaults_darwin.go b/vendor/github.com/containerd/platforms/defaults_darwin.go
new file mode 100644
index 0000000000..72355ca85f
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/defaults_darwin.go
@@ -0,0 +1,44 @@
+//go:build darwin
+
+/*
+ Copyright The containerd 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 platforms
+
+import (
+ "runtime"
+
+ specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// DefaultSpec returns the current platform's default platform specification.
+func DefaultSpec() specs.Platform {
+ return specs.Platform{
+ OS: runtime.GOOS,
+ Architecture: runtime.GOARCH,
+ // The Variant field will be empty if arch != ARM.
+ Variant: cpuVariant(),
+ }
+}
+
+// Default returns the default matcher for the platform.
+func Default() MatchComparer {
+ return Ordered(DefaultSpec(), specs.Platform{
+ // darwin runtime also supports Linux binary via runu/LKL
+ OS: "linux",
+ Architecture: runtime.GOARCH,
+ })
+}
diff --git a/vendor/github.com/containerd/platforms/defaults_freebsd.go b/vendor/github.com/containerd/platforms/defaults_freebsd.go
new file mode 100644
index 0000000000..d3fe89e076
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/defaults_freebsd.go
@@ -0,0 +1,43 @@
+/*
+ Copyright The containerd 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 platforms
+
+import (
+ "runtime"
+
+ specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// DefaultSpec returns the current platform's default platform specification.
+func DefaultSpec() specs.Platform {
+ return specs.Platform{
+ OS: runtime.GOOS,
+ Architecture: runtime.GOARCH,
+ // The Variant field will be empty if arch != ARM.
+ Variant: cpuVariant(),
+ }
+}
+
+// Default returns the default matcher for the platform.
+func Default() MatchComparer {
+ return Ordered(DefaultSpec(), specs.Platform{
+ OS: "linux",
+ Architecture: runtime.GOARCH,
+ // The Variant field will be empty if arch != ARM.
+ Variant: cpuVariant(),
+ })
+}
diff --git a/vendor/github.com/containerd/platforms/defaults_unix.go b/vendor/github.com/containerd/platforms/defaults_unix.go
new file mode 100644
index 0000000000..44acc47eb3
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/defaults_unix.go
@@ -0,0 +1,40 @@
+//go:build !windows && !darwin && !freebsd
+
+/*
+ Copyright The containerd 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 platforms
+
+import (
+ "runtime"
+
+ specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// DefaultSpec returns the current platform's default platform specification.
+func DefaultSpec() specs.Platform {
+ return specs.Platform{
+ OS: runtime.GOOS,
+ Architecture: runtime.GOARCH,
+ // The Variant field will be empty if arch != ARM.
+ Variant: cpuVariant(),
+ }
+}
+
+// Default returns the default matcher for the platform.
+func Default() MatchComparer {
+ return Only(DefaultSpec())
+}
diff --git a/vendor/github.com/containerd/platforms/defaults_windows.go b/vendor/github.com/containerd/platforms/defaults_windows.go
new file mode 100644
index 0000000000..427ed72eb6
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/defaults_windows.go
@@ -0,0 +1,118 @@
+/*
+ Copyright The containerd 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 platforms
+
+import (
+ "fmt"
+ "runtime"
+ "strconv"
+ "strings"
+
+ specs "github.com/opencontainers/image-spec/specs-go/v1"
+ "golang.org/x/sys/windows"
+)
+
+// DefaultSpec returns the current platform's default platform specification.
+func DefaultSpec() specs.Platform {
+ major, minor, build := windows.RtlGetNtVersionNumbers()
+ return specs.Platform{
+ OS: runtime.GOOS,
+ Architecture: runtime.GOARCH,
+ OSVersion: fmt.Sprintf("%d.%d.%d", major, minor, build),
+ // The Variant field will be empty if arch != ARM.
+ Variant: cpuVariant(),
+ }
+}
+
+type windowsmatcher struct {
+ specs.Platform
+ osVersionPrefix string
+ defaultMatcher Matcher
+}
+
+// Match matches platform with the same windows major, minor
+// and build version.
+func (m windowsmatcher) Match(p specs.Platform) bool {
+ match := m.defaultMatcher.Match(p)
+
+ if match && m.OS == "windows" {
+ // HPC containers do not have OS version filled
+ if m.OSVersion == "" || p.OSVersion == "" {
+ return true
+ }
+
+ hostOsVersion := getOSVersion(m.osVersionPrefix)
+ ctrOsVersion := getOSVersion(p.OSVersion)
+ return checkHostAndContainerCompat(hostOsVersion, ctrOsVersion)
+ }
+
+ return match
+}
+
+func getOSVersion(osVersionPrefix string) osVersion {
+ parts := strings.Split(osVersionPrefix, ".")
+ if len(parts) < 3 {
+ return osVersion{}
+ }
+
+ majorVersion, _ := strconv.Atoi(parts[0])
+ minorVersion, _ := strconv.Atoi(parts[1])
+ buildNumber, _ := strconv.Atoi(parts[2])
+
+ return osVersion{
+ MajorVersion: uint8(majorVersion),
+ MinorVersion: uint8(minorVersion),
+ Build: uint16(buildNumber),
+ }
+}
+
+// Less sorts matched platforms in front of other platforms.
+// For matched platforms, it puts platforms with larger revision
+// number in front.
+func (m windowsmatcher) Less(p1, p2 specs.Platform) bool {
+ m1, m2 := m.Match(p1), m.Match(p2)
+ if m1 && m2 {
+ r1, r2 := revision(p1.OSVersion), revision(p2.OSVersion)
+ return r1 > r2
+ }
+ return m1 && !m2
+}
+
+func revision(v string) int {
+ parts := strings.Split(v, ".")
+ if len(parts) < 4 {
+ return 0
+ }
+ r, err := strconv.Atoi(parts[3])
+ if err != nil {
+ return 0
+ }
+ return r
+}
+
+func prefix(v string) string {
+ parts := strings.Split(v, ".")
+ if len(parts) < 4 {
+ return v
+ }
+ return strings.Join(parts[0:3], ".")
+}
+
+// Default returns the current platform's default platform specification.
+func Default() MatchComparer {
+ return Only(DefaultSpec())
+}
diff --git a/vendor/github.com/containerd/platforms/errors.go b/vendor/github.com/containerd/platforms/errors.go
new file mode 100644
index 0000000000..5ad721e779
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/errors.go
@@ -0,0 +1,30 @@
+/*
+ Copyright The containerd 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 platforms
+
+import "errors"
+
+// These errors mirror the errors defined in [github.com/containerd/containerd/errdefs],
+// however, they are not exported as they are not expected to be used as sentinel
+// errors by consumers of this package.
+//
+//nolint:unused // not all errors are used on all platforms.
+var (
+ errNotFound = errors.New("not found")
+ errInvalidArgument = errors.New("invalid argument")
+ errNotImplemented = errors.New("not implemented")
+)
diff --git a/vendor/github.com/containerd/platforms/platform_compat_windows.go b/vendor/github.com/containerd/platforms/platform_compat_windows.go
new file mode 100644
index 0000000000..89e66f0c09
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/platform_compat_windows.go
@@ -0,0 +1,78 @@
+/*
+ Copyright The containerd 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 platforms
+
+// osVersion is a wrapper for Windows version information
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx
+type osVersion struct {
+ Version uint32
+ MajorVersion uint8
+ MinorVersion uint8
+ Build uint16
+}
+
+// Windows Client and Server build numbers.
+//
+// See:
+// https://learn.microsoft.com/en-us/windows/release-health/release-information
+// https://learn.microsoft.com/en-us/windows/release-health/windows-server-release-info
+// https://learn.microsoft.com/en-us/windows/release-health/windows11-release-information
+const (
+ // rs5 (version 1809, codename "Redstone 5") corresponds to Windows Server
+ // 2019 (ltsc2019), and Windows 10 (October 2018 Update).
+ rs5 = 17763
+
+ // v21H2Server corresponds to Windows Server 2022 (ltsc2022).
+ v21H2Server = 20348
+
+ // v22H2Win11 corresponds to Windows 11 (2022 Update).
+ v22H2Win11 = 22621
+)
+
+// List of stable ABI compliant ltsc releases
+// Note: List must be sorted in ascending order
+var compatLTSCReleases = []uint16{
+ v21H2Server,
+}
+
+// CheckHostAndContainerCompat checks if given host and container
+// OS versions are compatible.
+// It includes support for stable ABI compliant versions as well.
+// Every release after WS 2022 will support the previous ltsc
+// container image. Stable ABI is in preview mode for windows 11 client.
+// Refer: https://learn.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/version-compatibility?tabs=windows-server-2022%2Cwindows-10#windows-server-host-os-compatibility
+func checkHostAndContainerCompat(host, ctr osVersion) bool {
+ // check major minor versions of host and guest
+ if host.MajorVersion != ctr.MajorVersion ||
+ host.MinorVersion != ctr.MinorVersion {
+ return false
+ }
+
+ // If host is < WS 2022, exact version match is required
+ if host.Build < v21H2Server {
+ return host.Build == ctr.Build
+ }
+
+ var supportedLtscRelease uint16
+ for i := len(compatLTSCReleases) - 1; i >= 0; i-- {
+ if host.Build >= compatLTSCReleases[i] {
+ supportedLtscRelease = compatLTSCReleases[i]
+ break
+ }
+ }
+ return ctr.Build >= supportedLtscRelease && ctr.Build <= host.Build
+}
diff --git a/vendor/github.com/containerd/platforms/platforms.go b/vendor/github.com/containerd/platforms/platforms.go
new file mode 100644
index 0000000000..1bbbdb91db
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/platforms.go
@@ -0,0 +1,308 @@
+/*
+ Copyright The containerd 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 platforms provides a toolkit for normalizing, matching and
+// specifying container platforms.
+//
+// Centered around OCI platform specifications, we define a string-based
+// specifier syntax that can be used for user input. With a specifier, users
+// only need to specify the parts of the platform that are relevant to their
+// context, providing an operating system or architecture or both.
+//
+// How do I use this package?
+//
+// The vast majority of use cases should simply use the match function with
+// user input. The first step is to parse a specifier into a matcher:
+//
+// m, err := Parse("linux")
+// if err != nil { ... }
+//
+// Once you have a matcher, use it to match against the platform declared by a
+// component, typically from an image or runtime. Since extracting an images
+// platform is a little more involved, we'll use an example against the
+// platform default:
+//
+// if ok := m.Match(Default()); !ok { /* doesn't match */ }
+//
+// This can be composed in loops for resolving runtimes or used as a filter for
+// fetch and select images.
+//
+// More details of the specifier syntax and platform spec follow.
+//
+// # Declaring Platform Support
+//
+// Components that have strict platform requirements should use the OCI
+// platform specification to declare their support. Typically, this will be
+// images and runtimes that should make these declaring which platform they
+// support specifically. This looks roughly as follows:
+//
+// type Platform struct {
+// Architecture string
+// OS string
+// Variant string
+// }
+//
+// Most images and runtimes should at least set Architecture and OS, according
+// to their GOARCH and GOOS values, respectively (follow the OCI image
+// specification when in doubt). ARM should set variant under certain
+// discussions, which are outlined below.
+//
+// # Platform Specifiers
+//
+// While the OCI platform specifications provide a tool for components to
+// specify structured information, user input typically doesn't need the full
+// context and much can be inferred. To solve this problem, we introduced
+// "specifiers". A specifier has the format
+// `||/[/]`. The user can provide either the
+// operating system or the architecture or both.
+//
+// An example of a common specifier is `linux/amd64`. If the host has a default
+// of runtime that matches this, the user can simply provide the component that
+// matters. For example, if a image provides amd64 and arm64 support, the
+// operating system, `linux` can be inferred, so they only have to provide
+// `arm64` or `amd64`. Similar behavior is implemented for operating systems,
+// where the architecture may be known but a runtime may support images from
+// different operating systems.
+//
+// # Normalization
+//
+// Because not all users are familiar with the way the Go runtime represents
+// platforms, several normalizations have been provided to make this package
+// easier to user.
+//
+// The following are performed for architectures:
+//
+// Value Normalized
+// aarch64 arm64
+// armhf arm
+// armel arm/v6
+// i386 386
+// x86_64 amd64
+// x86-64 amd64
+//
+// We also normalize the operating system `macos` to `darwin`.
+//
+// # ARM Support
+//
+// To qualify ARM architecture, the Variant field is used to qualify the arm
+// version. The most common arm version, v7, is represented without the variant
+// unless it is explicitly provided. This is treated as equivalent to armhf. A
+// previous architecture, armel, will be normalized to arm/v6.
+//
+// Similarly, the most common arm64 version v8, and most common amd64 version v1
+// are represented without the variant.
+//
+// While these normalizations are provided, their support on arm platforms has
+// not yet been fully implemented and tested.
+package platforms
+
+import (
+ "fmt"
+ "path"
+ "regexp"
+ "runtime"
+ "strconv"
+ "strings"
+
+ specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+var (
+ specifierRe = regexp.MustCompile(`^[A-Za-z0-9_-]+$`)
+ osAndVersionRe = regexp.MustCompile(`^([A-Za-z0-9_-]+)(?:\(([A-Za-z0-9_.-]*)\))?$`)
+)
+
+const osAndVersionFormat = "%s(%s)"
+
+// Platform is a type alias for convenience, so there is no need to import image-spec package everywhere.
+type Platform = specs.Platform
+
+// Matcher matches platforms specifications, provided by an image or runtime.
+type Matcher interface {
+ Match(platform specs.Platform) bool
+}
+
+// NewMatcher returns a simple matcher based on the provided platform
+// specification. The returned matcher only looks for equality based on os,
+// architecture and variant.
+//
+// One may implement their own matcher if this doesn't provide the required
+// functionality.
+//
+// Applications should opt to use `Match` over directly parsing specifiers.
+func NewMatcher(platform specs.Platform) Matcher {
+ return newDefaultMatcher(platform)
+}
+
+type matcher struct {
+ specs.Platform
+}
+
+func (m *matcher) Match(platform specs.Platform) bool {
+ normalized := Normalize(platform)
+ return m.OS == normalized.OS &&
+ m.Architecture == normalized.Architecture &&
+ m.Variant == normalized.Variant
+}
+
+func (m *matcher) String() string {
+ return FormatAll(m.Platform)
+}
+
+// ParseAll parses a list of platform specifiers into a list of platform.
+func ParseAll(specifiers []string) ([]specs.Platform, error) {
+ platforms := make([]specs.Platform, len(specifiers))
+ for i, s := range specifiers {
+ p, err := Parse(s)
+ if err != nil {
+ return nil, fmt.Errorf("invalid platform %s: %w", s, err)
+ }
+ platforms[i] = p
+ }
+ return platforms, nil
+}
+
+// Parse parses the platform specifier syntax into a platform declaration.
+//
+// Platform specifiers are in the format `[()]||[()]/[/]`.
+// The minimum required information for a platform specifier is the operating
+// system or architecture. The OSVersion can be part of the OS like `windows(10.0.17763)`
+// When an OSVersion is specified, then specs.Platform.OSVersion is populated with that value,
+// and an empty string otherwise.
+// If there is only a single string (no slashes), the
+// value will be matched against the known set of operating systems, then fall
+// back to the known set of architectures. The missing component will be
+// inferred based on the local environment.
+func Parse(specifier string) (specs.Platform, error) {
+ if strings.Contains(specifier, "*") {
+ // TODO(stevvooe): need to work out exact wildcard handling
+ return specs.Platform{}, fmt.Errorf("%q: wildcards not yet supported: %w", specifier, errInvalidArgument)
+ }
+
+ // Limit to 4 elements to prevent unbounded split
+ parts := strings.SplitN(specifier, "/", 4)
+
+ var p specs.Platform
+ for i, part := range parts {
+ if i == 0 {
+ // First element is [()]
+ osVer := osAndVersionRe.FindStringSubmatch(part)
+ if osVer == nil {
+ return specs.Platform{}, fmt.Errorf("%q is an invalid OS component of %q: OSAndVersion specifier component must match %q: %w", part, specifier, osAndVersionRe.String(), errInvalidArgument)
+ }
+
+ p.OS = normalizeOS(osVer[1])
+ p.OSVersion = osVer[2]
+ } else {
+ if !specifierRe.MatchString(part) {
+ return specs.Platform{}, fmt.Errorf("%q is an invalid component of %q: platform specifier component must match %q: %w", part, specifier, specifierRe.String(), errInvalidArgument)
+ }
+ }
+ }
+
+ switch len(parts) {
+ case 1:
+ // in this case, we will test that the value might be an OS (with or
+ // without the optional OSVersion specified) and look it up.
+ // If it is not known, we'll treat it as an architecture. Since
+ // we have very little information about the platform here, we are
+ // going to be a little more strict if we don't know about the argument
+ // value.
+ if isKnownOS(p.OS) {
+ // picks a default architecture
+ p.Architecture = runtime.GOARCH
+ if p.Architecture == "arm" && cpuVariant() != "v7" {
+ p.Variant = cpuVariant()
+ }
+
+ return p, nil
+ }
+
+ p.Architecture, p.Variant = normalizeArch(parts[0], "")
+ if p.Architecture == "arm" && p.Variant == "v7" {
+ p.Variant = ""
+ }
+ if isKnownArch(p.Architecture) {
+ p.OS = runtime.GOOS
+ return p, nil
+ }
+
+ return specs.Platform{}, fmt.Errorf("%q: unknown operating system or architecture: %w", specifier, errInvalidArgument)
+ case 2:
+ // In this case, we treat as a regular OS[(OSVersion)]/arch pair. We don't care
+ // about whether or not we know of the platform.
+ p.Architecture, p.Variant = normalizeArch(parts[1], "")
+ if p.Architecture == "arm" && p.Variant == "v7" {
+ p.Variant = ""
+ }
+
+ return p, nil
+ case 3:
+ // we have a fully specified variant, this is rare
+ p.Architecture, p.Variant = normalizeArch(parts[1], parts[2])
+ if p.Architecture == "arm64" && p.Variant == "" {
+ p.Variant = "v8"
+ }
+
+ return p, nil
+ }
+
+ return specs.Platform{}, fmt.Errorf("%q: cannot parse platform specifier: %w", specifier, errInvalidArgument)
+}
+
+// MustParse is like Parses but panics if the specifier cannot be parsed.
+// Simplifies initialization of global variables.
+func MustParse(specifier string) specs.Platform {
+ p, err := Parse(specifier)
+ if err != nil {
+ panic("platform: Parse(" + strconv.Quote(specifier) + "): " + err.Error())
+ }
+ return p
+}
+
+// Format returns a string specifier from the provided platform specification.
+func Format(platform specs.Platform) string {
+ if platform.OS == "" {
+ return "unknown"
+ }
+
+ return path.Join(platform.OS, platform.Architecture, platform.Variant)
+}
+
+// FormatAll returns a string specifier that also includes the OSVersion from the
+// provided platform specification.
+func FormatAll(platform specs.Platform) string {
+ if platform.OS == "" {
+ return "unknown"
+ }
+
+ if platform.OSVersion != "" {
+ OSAndVersion := fmt.Sprintf(osAndVersionFormat, platform.OS, platform.OSVersion)
+ return path.Join(OSAndVersion, platform.Architecture, platform.Variant)
+ }
+ return path.Join(platform.OS, platform.Architecture, platform.Variant)
+}
+
+// Normalize validates and translate the platform to the canonical value.
+//
+// For example, if "Aarch64" is encountered, we change it to "arm64" or if
+// "x86_64" is encountered, it becomes "amd64".
+func Normalize(platform specs.Platform) specs.Platform {
+ platform.OS = normalizeOS(platform.OS)
+ platform.Architecture, platform.Variant = normalizeArch(platform.Architecture, platform.Variant)
+
+ return platform
+}
diff --git a/vendor/github.com/containerd/platforms/platforms_other.go b/vendor/github.com/containerd/platforms/platforms_other.go
new file mode 100644
index 0000000000..03f4dcd998
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/platforms_other.go
@@ -0,0 +1,30 @@
+//go:build !windows
+
+/*
+ Copyright The containerd 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 platforms
+
+import (
+ specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// NewMatcher returns the default Matcher for containerd
+func newDefaultMatcher(platform specs.Platform) Matcher {
+ return &matcher{
+ Platform: Normalize(platform),
+ }
+}
diff --git a/vendor/github.com/containerd/platforms/platforms_windows.go b/vendor/github.com/containerd/platforms/platforms_windows.go
new file mode 100644
index 0000000000..950e2a2ddb
--- /dev/null
+++ b/vendor/github.com/containerd/platforms/platforms_windows.go
@@ -0,0 +1,34 @@
+/*
+ Copyright The containerd 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 platforms
+
+import (
+ specs "github.com/opencontainers/image-spec/specs-go/v1"
+)
+
+// NewMatcher returns a Windows matcher that will match on osVersionPrefix if
+// the platform is Windows otherwise use the default matcher
+func newDefaultMatcher(platform specs.Platform) Matcher {
+ prefix := prefix(platform.OSVersion)
+ return windowsmatcher{
+ Platform: platform,
+ osVersionPrefix: prefix,
+ defaultMatcher: &matcher{
+ Platform: Normalize(platform),
+ },
+ }
+}
diff --git a/vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md b/vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md
new file mode 100644
index 0000000000..ca0e3c62c7
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md
@@ -0,0 +1,256 @@
+# Changelog #
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/)
+and this project adheres to [Semantic Versioning](http://semver.org/).
+
+## [Unreleased] ##
+
+## [0.4.1] - 2025-01-28 ##
+
+### Fixed ###
+- The restrictions added for `root` paths passed to `SecureJoin` in 0.4.0 was
+ found to be too strict and caused some regressions when folks tried to
+ update, so this restriction has been relaxed to only return an error if the
+ path contains a `..` component. We still recommend users use `filepath.Clean`
+ (and even `filepath.EvalSymlinks`) on the `root` path they are using, but at
+ least you will no longer be punished for "trivial" unclean paths.
+
+## [0.4.0] - 2025-01-13 ##
+
+### Breaking ####
+- `SecureJoin(VFS)` will now return an error if the provided `root` is not a
+ `filepath.Clean`'d path.
+
+ While it is ultimately the responsibility of the caller to ensure the root is
+ a safe path to use, passing a path like `/symlink/..` as a root would result
+ in the `SecureJoin`'d path being placed in `/` even though `/symlink/..`
+ might be a different directory, and so we should more strongly discourage
+ such usage.
+
+ All major users of `securejoin.SecureJoin` already ensure that the paths they
+ provide are safe (and this is ultimately a question of user error), but
+ removing this foot-gun is probably a good idea. Of course, this is
+ necessarily a breaking API change (though we expect no real users to be
+ affected by it).
+
+ Thanks to [Erik Sjölund](https://github.com/eriksjolund), who initially
+ reported this issue as a possible security issue.
+
+- `MkdirAll` and `MkdirHandle` now take an `os.FileMode`-style mode argument
+ instead of a raw `unix.S_*`-style mode argument, which may cause compile-time
+ type errors depending on how you use `filepath-securejoin`. For most users,
+ there will be no change in behaviour aside from the type change (as the
+ bottom `0o777` bits are the same in both formats, and most users are probably
+ only using those bits).
+
+ However, if you were using `unix.S_ISVTX` to set the sticky bit with
+ `MkdirAll(Handle)` you will need to switch to `os.ModeSticky` otherwise you
+ will get a runtime error with this update. In addition, the error message you
+ will get from passing `unix.S_ISUID` and `unix.S_ISGID` will be different as
+ they are treated as invalid bits now (note that previously passing said bits
+ was also an error).
+
+## [0.3.6] - 2024-12-17 ##
+
+### Compatibility ###
+- The minimum Go version requirement for `filepath-securejoin` is now Go 1.18
+ (we use generics internally).
+
+ For reference, `filepath-securejoin@v0.3.0` somewhat-arbitrarily bumped the
+ Go version requirement to 1.21.
+
+ While we did make some use of Go 1.21 stdlib features (and in principle Go
+ versions <= 1.21 are no longer even supported by upstream anymore), some
+ downstreams have complained that the version bump has meant that they have to
+ do workarounds when backporting fixes that use the new `filepath-securejoin`
+ API onto old branches. This is not an ideal situation, but since using this
+ library is probably better for most downstreams than a hand-rolled
+ workaround, we now have compatibility shims that allow us to build on older
+ Go versions.
+- Lower minimum version requirement for `golang.org/x/sys` to `v0.18.0` (we
+ need the wrappers for `fsconfig(2)`), which should also make backporting
+ patches to older branches easier.
+
+## [0.3.5] - 2024-12-06 ##
+
+### Fixed ###
+- `MkdirAll` will now no longer return an `EEXIST` error if two racing
+ processes are creating the same directory. We will still verify that the path
+ is a directory, but this will avoid spurious errors when multiple threads or
+ programs are trying to `MkdirAll` the same path. opencontainers/runc#4543
+
+## [0.3.4] - 2024-10-09 ##
+
+### Fixed ###
+- Previously, some testing mocks we had resulted in us doing `import "testing"`
+ in non-`_test.go` code, which made some downstreams like Kubernetes unhappy.
+ This has been fixed. (#32)
+
+## [0.3.3] - 2024-09-30 ##
+
+### Fixed ###
+- The mode and owner verification logic in `MkdirAll` has been removed. This
+ was originally intended to protect against some theoretical attacks but upon
+ further consideration these protections don't actually buy us anything and
+ they were causing spurious errors with more complicated filesystem setups.
+- The "is the created directory empty" logic in `MkdirAll` has also been
+ removed. This was not causing us issues yet, but some pseudofilesystems (such
+ as `cgroup`) create non-empty directories and so this logic would've been
+ wrong for such cases.
+
+## [0.3.2] - 2024-09-13 ##
+
+### Changed ###
+- Passing the `S_ISUID` or `S_ISGID` modes to `MkdirAllInRoot` will now return
+ an explicit error saying that those bits are ignored by `mkdirat(2)`. In the
+ past a different error was returned, but since the silent ignoring behaviour
+ is codified in the man pages a more explicit error seems apt. While silently
+ ignoring these bits would be the most compatible option, it could lead to
+ users thinking their code sets these bits when it doesn't. Programs that need
+ to deal with compatibility can mask the bits themselves. (#23, #25)
+
+### Fixed ###
+- If a directory has `S_ISGID` set, then all child directories will have
+ `S_ISGID` set when created and a different gid will be used for any inode
+ created under the directory. Previously, the "expected owner and mode"
+ validation in `securejoin.MkdirAll` did not correctly handle this. We now
+ correctly handle this case. (#24, #25)
+
+## [0.3.1] - 2024-07-23 ##
+
+### Changed ###
+- By allowing `Open(at)InRoot` to opt-out of the extra work done by `MkdirAll`
+ to do the necessary "partial lookups", `Open(at)InRoot` now does less work
+ for both implementations (resulting in a many-fold decrease in the number of
+ operations for `openat2`, and a modest improvement for non-`openat2`) and is
+ far more guaranteed to match the correct `openat2(RESOLVE_IN_ROOT)`
+ behaviour.
+- We now use `readlinkat(fd, "")` where possible. For `Open(at)InRoot` this
+ effectively just means that we no longer risk getting spurious errors during
+ rename races. However, for our hardened procfs handler, this in theory should
+ prevent mount attacks from tricking us when doing magic-link readlinks (even
+ when using the unsafe host `/proc` handle). Unfortunately `Reopen` is still
+ potentially vulnerable to those kinds of somewhat-esoteric attacks.
+
+ Technically this [will only work on post-2.6.39 kernels][linux-readlinkat-emptypath]
+ but it seems incredibly unlikely anyone is using `filepath-securejoin` on a
+ pre-2011 kernel.
+
+### Fixed ###
+- Several improvements were made to the errors returned by `Open(at)InRoot` and
+ `MkdirAll` when dealing with invalid paths under the emulated (ie.
+ non-`openat2`) implementation. Previously, some paths would return the wrong
+ error (`ENOENT` when the last component was a non-directory), and other paths
+ would be returned as though they were acceptable (trailing-slash components
+ after a non-directory would be ignored by `Open(at)InRoot`).
+
+ These changes were done to match `openat2`'s behaviour and purely is a
+ consistency fix (most users are going to be using `openat2` anyway).
+
+[linux-readlinkat-emptypath]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=65cfc6722361570bfe255698d9cd4dccaf47570d
+
+## [0.3.0] - 2024-07-11 ##
+
+### Added ###
+- A new set of `*os.File`-based APIs have been added. These are adapted from
+ [libpathrs][] and we strongly suggest using them if possible (as they provide
+ far more protection against attacks than `SecureJoin`):
+
+ - `Open(at)InRoot` resolves a path inside a rootfs and returns an `*os.File`
+ handle to the path. Note that the handle returned is an `O_PATH` handle,
+ which cannot be used for reading or writing (as well as some other
+ operations -- [see open(2) for more details][open.2])
+
+ - `Reopen` takes an `O_PATH` file handle and safely re-opens it to upgrade
+ it to a regular handle. This can also be used with non-`O_PATH` handles,
+ but `O_PATH` is the most obvious application.
+
+ - `MkdirAll` is an implementation of `os.MkdirAll` that is safe to use to
+ create a directory tree within a rootfs.
+
+ As these are new APIs, they may change in the future. However, they should be
+ safe to start migrating to as we have extensive tests ensuring they behave
+ correctly and are safe against various races and other attacks.
+
+[libpathrs]: https://github.com/openSUSE/libpathrs
+[open.2]: https://www.man7.org/linux/man-pages/man2/open.2.html
+
+## [0.2.5] - 2024-05-03 ##
+
+### Changed ###
+- Some minor changes were made to how lexical components (like `..` and `.`)
+ are handled during path generation in `SecureJoin`. There is no behaviour
+ change as a result of this fix (the resulting paths are the same).
+
+### Fixed ###
+- The error returned when we hit a symlink loop now references the correct
+ path. (#10)
+
+## [0.2.4] - 2023-09-06 ##
+
+### Security ###
+- This release fixes a potential security issue in filepath-securejoin when
+ used on Windows ([GHSA-6xv5-86q9-7xr8][], which could be used to generate
+ paths outside of the provided rootfs in certain cases), as well as improving
+ the overall behaviour of filepath-securejoin when dealing with Windows paths
+ that contain volume names. Thanks to Paulo Gomes for discovering and fixing
+ these issues.
+
+### Fixed ###
+- Switch to GitHub Actions for CI so we can test on Windows as well as Linux
+ and MacOS.
+
+[GHSA-6xv5-86q9-7xr8]: https://github.com/advisories/GHSA-6xv5-86q9-7xr8
+
+## [0.2.3] - 2021-06-04 ##
+
+### Changed ###
+- Switch to Go 1.13-style `%w` error wrapping, letting us drop the dependency
+ on `github.com/pkg/errors`.
+
+## [0.2.2] - 2018-09-05 ##
+
+### Changed ###
+- Use `syscall.ELOOP` as the base error for symlink loops, rather than our own
+ (internal) error. This allows callers to more easily use `errors.Is` to check
+ for this case.
+
+## [0.2.1] - 2018-09-05 ##
+
+### Fixed ###
+- Use our own `IsNotExist` implementation, which lets us handle `ENOTDIR`
+ properly within `SecureJoin`.
+
+## [0.2.0] - 2017-07-19 ##
+
+We now have 100% test coverage!
+
+### Added ###
+- Add a `SecureJoinVFS` API that can be used for mocking (as we do in our new
+ tests) or for implementing custom handling of lookup operations (such as for
+ rootless containers, where work is necessary to access directories with weird
+ modes because we don't have `CAP_DAC_READ_SEARCH` or `CAP_DAC_OVERRIDE`).
+
+## 0.1.0 - 2017-07-19
+
+This is our first release of `github.com/cyphar/filepath-securejoin`,
+containing a full implementation with a coverage of 93.5% (the only missing
+cases are the error cases, which are hard to mocktest at the moment).
+
+[Unreleased]: https://github.com/cyphar/filepath-securejoin/compare/v0.4.1...HEAD
+[0.4.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.4.0...v0.4.1
+[0.4.0]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.6...v0.4.0
+[0.3.6]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.5...v0.3.6
+[0.3.5]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.4...v0.3.5
+[0.3.4]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.3...v0.3.4
+[0.3.3]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.2...v0.3.3
+[0.3.2]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.1...v0.3.2
+[0.3.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.0...v0.3.1
+[0.3.0]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.5...v0.3.0
+[0.2.5]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.4...v0.2.5
+[0.2.4]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.3...v0.2.4
+[0.2.3]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.2...v0.2.3
+[0.2.2]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.1...v0.2.2
+[0.2.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.2.0...v0.2.1
+[0.2.0]: https://github.com/cyphar/filepath-securejoin/compare/v0.1.0...v0.2.0
diff --git a/vendor/github.com/cyphar/filepath-securejoin/LICENSE b/vendor/github.com/cyphar/filepath-securejoin/LICENSE
new file mode 100644
index 0000000000..cb1ab88da0
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/LICENSE
@@ -0,0 +1,28 @@
+Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved.
+Copyright (C) 2017-2024 SUSE LLC. 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.
diff --git a/vendor/github.com/cyphar/filepath-securejoin/README.md b/vendor/github.com/cyphar/filepath-securejoin/README.md
new file mode 100644
index 0000000000..eaeb53fcd0
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/README.md
@@ -0,0 +1,169 @@
+## `filepath-securejoin` ##
+
+[](https://pkg.go.dev/github.com/cyphar/filepath-securejoin)
+[](https://github.com/cyphar/filepath-securejoin/actions/workflows/ci.yml)
+
+### Old API ###
+
+This library was originally just an implementation of `SecureJoin` which was
+[intended to be included in the Go standard library][go#20126] as a safer
+`filepath.Join` that would restrict the path lookup to be inside a root
+directory.
+
+The implementation was based on code that existed in several container
+runtimes. Unfortunately, this API is **fundamentally unsafe** against attackers
+that can modify path components after `SecureJoin` returns and before the
+caller uses the path, allowing for some fairly trivial TOCTOU attacks.
+
+`SecureJoin` (and `SecureJoinVFS`) are still provided by this library to
+support legacy users, but new users are strongly suggested to avoid using
+`SecureJoin` and instead use the [new api](#new-api) or switch to
+[libpathrs][libpathrs].
+
+With the above limitations in mind, this library guarantees the following:
+
+* If no error is set, the resulting string **must** be a child path of
+ `root` and will not contain any symlink path components (they will all be
+ expanded).
+
+* When expanding symlinks, all symlink path components **must** be resolved
+ relative to the provided root. In particular, this can be considered a
+ userspace implementation of how `chroot(2)` operates on file paths. Note that
+ these symlinks will **not** be expanded lexically (`filepath.Clean` is not
+ called on the input before processing).
+
+* Non-existent path components are unaffected by `SecureJoin` (similar to
+ `filepath.EvalSymlinks`'s semantics).
+
+* The returned path will always be `filepath.Clean`ed and thus not contain any
+ `..` components.
+
+A (trivial) implementation of this function on GNU/Linux systems could be done
+with the following (note that this requires root privileges and is far more
+opaque than the implementation in this library, and also requires that
+`readlink` is inside the `root` path and is trustworthy):
+
+```go
+package securejoin
+
+import (
+ "os/exec"
+ "path/filepath"
+)
+
+func SecureJoin(root, unsafePath string) (string, error) {
+ unsafePath = string(filepath.Separator) + unsafePath
+ cmd := exec.Command("chroot", root,
+ "readlink", "--canonicalize-missing", "--no-newline", unsafePath)
+ output, err := cmd.CombinedOutput()
+ if err != nil {
+ return "", err
+ }
+ expanded := string(output)
+ return filepath.Join(root, expanded), nil
+}
+```
+
+[libpathrs]: https://github.com/openSUSE/libpathrs
+[go#20126]: https://github.com/golang/go/issues/20126
+
+### New API ###
+
+While we recommend users switch to [libpathrs][libpathrs] as soon as it has a
+stable release, some methods implemented by libpathrs have been ported to this
+library to ease the transition. These APIs are only supported on Linux.
+
+These APIs are implemented such that `filepath-securejoin` will
+opportunistically use certain newer kernel APIs that make these operations far
+more secure. In particular:
+
+* All of the lookup operations will use [`openat2`][openat2.2] on new enough
+ kernels (Linux 5.6 or later) to restrict lookups through magic-links and
+ bind-mounts (for certain operations) and to make use of `RESOLVE_IN_ROOT` to
+ efficiently resolve symlinks within a rootfs.
+
+* The APIs provide hardening against a malicious `/proc` mount to either detect
+ or avoid being tricked by a `/proc` that is not legitimate. This is done
+ using [`openat2`][openat2.2] for all users, and privileged users will also be
+ further protected by using [`fsopen`][fsopen.2] and [`open_tree`][open_tree.2]
+ (Linux 5.2 or later).
+
+[openat2.2]: https://www.man7.org/linux/man-pages/man2/openat2.2.html
+[fsopen.2]: https://github.com/brauner/man-pages-md/blob/main/fsopen.md
+[open_tree.2]: https://github.com/brauner/man-pages-md/blob/main/open_tree.md
+
+#### `OpenInRoot` ####
+
+```go
+func OpenInRoot(root, unsafePath string) (*os.File, error)
+func OpenatInRoot(root *os.File, unsafePath string) (*os.File, error)
+func Reopen(handle *os.File, flags int) (*os.File, error)
+```
+
+`OpenInRoot` is a much safer version of
+
+```go
+path, err := securejoin.SecureJoin(root, unsafePath)
+file, err := os.OpenFile(path, unix.O_PATH|unix.O_CLOEXEC)
+```
+
+that protects against various race attacks that could lead to serious security
+issues, depending on the application. Note that the returned `*os.File` is an
+`O_PATH` file descriptor, which is quite restricted. Callers will probably need
+to use `Reopen` to get a more usable handle (this split is done to provide
+useful features like PTY spawning and to avoid users accidentally opening bad
+inodes that could cause a DoS).
+
+Callers need to be careful in how they use the returned `*os.File`. Usually it
+is only safe to operate on the handle directly, and it is very easy to create a
+security issue. [libpathrs][libpathrs] provides far more helpers to make using
+these handles safer -- there is currently no plan to port them to
+`filepath-securejoin`.
+
+`OpenatInRoot` is like `OpenInRoot` except that the root is provided using an
+`*os.File`. This allows you to ensure that multiple `OpenatInRoot` (or
+`MkdirAllHandle`) calls are operating on the same rootfs.
+
+> **NOTE**: Unlike `SecureJoin`, `OpenInRoot` will error out as soon as it hits
+> a dangling symlink or non-existent path. This is in contrast to `SecureJoin`
+> which treated non-existent components as though they were real directories,
+> and would allow for partial resolution of dangling symlinks. These behaviours
+> are at odds with how Linux treats non-existent paths and dangling symlinks,
+> and so these are no longer allowed.
+
+#### `MkdirAll` ####
+
+```go
+func MkdirAll(root, unsafePath string, mode int) error
+func MkdirAllHandle(root *os.File, unsafePath string, mode int) (*os.File, error)
+```
+
+`MkdirAll` is a much safer version of
+
+```go
+path, err := securejoin.SecureJoin(root, unsafePath)
+err = os.MkdirAll(path, mode)
+```
+
+that protects against the same kinds of races that `OpenInRoot` protects
+against.
+
+`MkdirAllHandle` is like `MkdirAll` except that the root is provided using an
+`*os.File` (the reason for this is the same as with `OpenatInRoot`) and an
+`*os.File` of the final created directory is returned (this directory is
+guaranteed to be effectively identical to the directory created by
+`MkdirAllHandle`, which is not possible to ensure by just using `OpenatInRoot`
+after `MkdirAll`).
+
+> **NOTE**: Unlike `SecureJoin`, `MkdirAll` will error out as soon as it hits
+> a dangling symlink or non-existent path. This is in contrast to `SecureJoin`
+> which treated non-existent components as though they were real directories,
+> and would allow for partial resolution of dangling symlinks. These behaviours
+> are at odds with how Linux treats non-existent paths and dangling symlinks,
+> and so these are no longer allowed. This means that `MkdirAll` will not
+> create non-existent directories referenced by a dangling symlink.
+
+### License ###
+
+The license of this project is the same as Go, which is a BSD 3-clause license
+available in the `LICENSE` file.
diff --git a/vendor/github.com/cyphar/filepath-securejoin/VERSION b/vendor/github.com/cyphar/filepath-securejoin/VERSION
new file mode 100644
index 0000000000..267577d47e
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/VERSION
@@ -0,0 +1 @@
+0.4.1
diff --git a/vendor/github.com/cyphar/filepath-securejoin/doc.go b/vendor/github.com/cyphar/filepath-securejoin/doc.go
new file mode 100644
index 0000000000..1ec7d065ef
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/doc.go
@@ -0,0 +1,39 @@
+// Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved.
+// Copyright (C) 2017-2024 SUSE LLC. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package securejoin implements a set of helpers to make it easier to write Go
+// code that is safe against symlink-related escape attacks. The primary idea
+// is to let you resolve a path within a rootfs directory as if the rootfs was
+// a chroot.
+//
+// securejoin has two APIs, a "legacy" API and a "modern" API.
+//
+// The legacy API is [SecureJoin] and [SecureJoinVFS]. These methods are
+// **not** safe against race conditions where an attacker changes the
+// filesystem after (or during) the [SecureJoin] operation.
+//
+// The new API is made up of [OpenInRoot] and [MkdirAll] (and derived
+// functions). These are safe against racing attackers and have several other
+// protections that are not provided by the legacy API. There are many more
+// operations that most programs expect to be able to do safely, but we do not
+// provide explicit support for them because we want to encourage users to
+// switch to [libpathrs](https://github.com/openSUSE/libpathrs) which is a
+// cross-language next-generation library that is entirely designed around
+// operating on paths safely.
+//
+// securejoin has been used by several container runtimes (Docker, runc,
+// Kubernetes, etc) for quite a few years as a de-facto standard for operating
+// on container filesystem paths "safely". However, most users still use the
+// legacy API which is unsafe against various attacks (there is a fairly long
+// history of CVEs in dependent as a result). Users should switch to the modern
+// API as soon as possible (or even better, switch to libpathrs).
+//
+// This project was initially intended to be included in the Go standard
+// library, but [it was rejected](https://go.dev/issue/20126). There is now a
+// [new Go proposal](https://go.dev/issue/67002) for a safe path resolution API
+// that shares some of the goals of filepath-securejoin. However, that design
+// is intended to work like `openat2(RESOLVE_BENEATH)` which does not fit the
+// usecase of container runtimes and most system tools.
+package securejoin
diff --git a/vendor/github.com/cyphar/filepath-securejoin/gocompat_errors_go120.go b/vendor/github.com/cyphar/filepath-securejoin/gocompat_errors_go120.go
new file mode 100644
index 0000000000..42452bbf9b
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/gocompat_errors_go120.go
@@ -0,0 +1,18 @@
+//go:build linux && go1.20
+
+// Copyright (C) 2024 SUSE LLC. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package securejoin
+
+import (
+ "fmt"
+)
+
+// wrapBaseError is a helper that is equivalent to fmt.Errorf("%w: %w"), except
+// that on pre-1.20 Go versions only errors.Is() works properly (errors.Unwrap)
+// is only guaranteed to give you baseErr.
+func wrapBaseError(baseErr, extraErr error) error {
+ return fmt.Errorf("%w: %w", extraErr, baseErr)
+}
diff --git a/vendor/github.com/cyphar/filepath-securejoin/gocompat_errors_unsupported.go b/vendor/github.com/cyphar/filepath-securejoin/gocompat_errors_unsupported.go
new file mode 100644
index 0000000000..e7adca3fd1
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/gocompat_errors_unsupported.go
@@ -0,0 +1,38 @@
+//go:build linux && !go1.20
+
+// Copyright (C) 2024 SUSE LLC. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package securejoin
+
+import (
+ "fmt"
+)
+
+type wrappedError struct {
+ inner error
+ isError error
+}
+
+func (err wrappedError) Is(target error) bool {
+ return err.isError == target
+}
+
+func (err wrappedError) Unwrap() error {
+ return err.inner
+}
+
+func (err wrappedError) Error() string {
+ return fmt.Sprintf("%v: %v", err.isError, err.inner)
+}
+
+// wrapBaseError is a helper that is equivalent to fmt.Errorf("%w: %w"), except
+// that on pre-1.20 Go versions only errors.Is() works properly (errors.Unwrap)
+// is only guaranteed to give you baseErr.
+func wrapBaseError(baseErr, extraErr error) error {
+ return wrappedError{
+ inner: baseErr,
+ isError: extraErr,
+ }
+}
diff --git a/vendor/github.com/cyphar/filepath-securejoin/gocompat_generics_go121.go b/vendor/github.com/cyphar/filepath-securejoin/gocompat_generics_go121.go
new file mode 100644
index 0000000000..ddd6fa9a41
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/gocompat_generics_go121.go
@@ -0,0 +1,32 @@
+//go:build linux && go1.21
+
+// Copyright (C) 2024 SUSE LLC. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package securejoin
+
+import (
+ "slices"
+ "sync"
+)
+
+func slices_DeleteFunc[S ~[]E, E any](slice S, delFn func(E) bool) S {
+ return slices.DeleteFunc(slice, delFn)
+}
+
+func slices_Contains[S ~[]E, E comparable](slice S, val E) bool {
+ return slices.Contains(slice, val)
+}
+
+func slices_Clone[S ~[]E, E any](slice S) S {
+ return slices.Clone(slice)
+}
+
+func sync_OnceValue[T any](f func() T) func() T {
+ return sync.OnceValue(f)
+}
+
+func sync_OnceValues[T1, T2 any](f func() (T1, T2)) func() (T1, T2) {
+ return sync.OnceValues(f)
+}
diff --git a/vendor/github.com/cyphar/filepath-securejoin/gocompat_generics_unsupported.go b/vendor/github.com/cyphar/filepath-securejoin/gocompat_generics_unsupported.go
new file mode 100644
index 0000000000..f1e6fe7e71
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/gocompat_generics_unsupported.go
@@ -0,0 +1,124 @@
+//go:build linux && !go1.21
+
+// Copyright (C) 2024 SUSE LLC. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package securejoin
+
+import (
+ "sync"
+)
+
+// These are very minimal implementations of functions that appear in Go 1.21's
+// stdlib, included so that we can build on older Go versions. Most are
+// borrowed directly from the stdlib, and a few are modified to be "obviously
+// correct" without needing to copy too many other helpers.
+
+// clearSlice is equivalent to the builtin clear from Go 1.21.
+// Copied from the Go 1.24 stdlib implementation.
+func clearSlice[S ~[]E, E any](slice S) {
+ var zero E
+ for i := range slice {
+ slice[i] = zero
+ }
+}
+
+// Copied from the Go 1.24 stdlib implementation.
+func slices_IndexFunc[S ~[]E, E any](s S, f func(E) bool) int {
+ for i := range s {
+ if f(s[i]) {
+ return i
+ }
+ }
+ return -1
+}
+
+// Copied from the Go 1.24 stdlib implementation.
+func slices_DeleteFunc[S ~[]E, E any](s S, del func(E) bool) S {
+ i := slices_IndexFunc(s, del)
+ if i == -1 {
+ return s
+ }
+ // Don't start copying elements until we find one to delete.
+ for j := i + 1; j < len(s); j++ {
+ if v := s[j]; !del(v) {
+ s[i] = v
+ i++
+ }
+ }
+ clearSlice(s[i:]) // zero/nil out the obsolete elements, for GC
+ return s[:i]
+}
+
+// Similar to the stdlib slices.Contains, except that we don't have
+// slices.Index so we need to use slices.IndexFunc for this non-Func helper.
+func slices_Contains[S ~[]E, E comparable](s S, v E) bool {
+ return slices_IndexFunc(s, func(e E) bool { return e == v }) >= 0
+}
+
+// Copied from the Go 1.24 stdlib implementation.
+func slices_Clone[S ~[]E, E any](s S) S {
+ // Preserve nil in case it matters.
+ if s == nil {
+ return nil
+ }
+ return append(S([]E{}), s...)
+}
+
+// Copied from the Go 1.24 stdlib implementation.
+func sync_OnceValue[T any](f func() T) func() T {
+ var (
+ once sync.Once
+ valid bool
+ p any
+ result T
+ )
+ g := func() {
+ defer func() {
+ p = recover()
+ if !valid {
+ panic(p)
+ }
+ }()
+ result = f()
+ f = nil
+ valid = true
+ }
+ return func() T {
+ once.Do(g)
+ if !valid {
+ panic(p)
+ }
+ return result
+ }
+}
+
+// Copied from the Go 1.24 stdlib implementation.
+func sync_OnceValues[T1, T2 any](f func() (T1, T2)) func() (T1, T2) {
+ var (
+ once sync.Once
+ valid bool
+ p any
+ r1 T1
+ r2 T2
+ )
+ g := func() {
+ defer func() {
+ p = recover()
+ if !valid {
+ panic(p)
+ }
+ }()
+ r1, r2 = f()
+ f = nil
+ valid = true
+ }
+ return func() (T1, T2) {
+ once.Do(g)
+ if !valid {
+ panic(p)
+ }
+ return r1, r2
+ }
+}
diff --git a/vendor/github.com/cyphar/filepath-securejoin/join.go b/vendor/github.com/cyphar/filepath-securejoin/join.go
new file mode 100644
index 0000000000..e6634d4778
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/join.go
@@ -0,0 +1,166 @@
+// Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved.
+// Copyright (C) 2017-2025 SUSE LLC. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package securejoin
+
+import (
+ "errors"
+ "os"
+ "path/filepath"
+ "strings"
+ "syscall"
+)
+
+const maxSymlinkLimit = 255
+
+// IsNotExist tells you if err is an error that implies that either the path
+// accessed does not exist (or path components don't exist). This is
+// effectively a more broad version of [os.IsNotExist].
+func IsNotExist(err error) bool {
+ // Check that it's not actually an ENOTDIR, which in some cases is a more
+ // convoluted case of ENOENT (usually involving weird paths).
+ return errors.Is(err, os.ErrNotExist) || errors.Is(err, syscall.ENOTDIR) || errors.Is(err, syscall.ENOENT)
+}
+
+// errUnsafeRoot is returned if the user provides SecureJoinVFS with a path
+// that contains ".." components.
+var errUnsafeRoot = errors.New("root path provided to SecureJoin contains '..' components")
+
+// stripVolume just gets rid of the Windows volume included in a path. Based on
+// some godbolt tests, the Go compiler is smart enough to make this a no-op on
+// Linux.
+func stripVolume(path string) string {
+ return path[len(filepath.VolumeName(path)):]
+}
+
+// hasDotDot checks if the path contains ".." components in a platform-agnostic
+// way.
+func hasDotDot(path string) bool {
+ // If we are on Windows, strip any volume letters. It turns out that
+ // C:..\foo may (or may not) be a valid pathname and we need to handle that
+ // leading "..".
+ path = stripVolume(path)
+ // Look for "/../" in the path, but we need to handle leading and trailing
+ // ".."s by adding separators. Doing this with filepath.Separator is ugly
+ // so just convert to Unix-style "/" first.
+ path = filepath.ToSlash(path)
+ return strings.Contains("/"+path+"/", "/../")
+}
+
+// SecureJoinVFS joins the two given path components (similar to [filepath.Join]) except
+// that the returned path is guaranteed to be scoped inside the provided root
+// path (when evaluated). Any symbolic links in the path are evaluated with the
+// given root treated as the root of the filesystem, similar to a chroot. The
+// filesystem state is evaluated through the given [VFS] interface (if nil, the
+// standard [os].* family of functions are used).
+//
+// Note that the guarantees provided by this function only apply if the path
+// components in the returned string are not modified (in other words are not
+// replaced with symlinks on the filesystem) after this function has returned.
+// Such a symlink race is necessarily out-of-scope of SecureJoinVFS.
+//
+// NOTE: Due to the above limitation, Linux users are strongly encouraged to
+// use [OpenInRoot] instead, which does safely protect against these kinds of
+// attacks. There is no way to solve this problem with SecureJoinVFS because
+// the API is fundamentally wrong (you cannot return a "safe" path string and
+// guarantee it won't be modified afterwards).
+//
+// Volume names in unsafePath are always discarded, regardless if they are
+// provided via direct input or when evaluating symlinks. Therefore:
+//
+// "C:\Temp" + "D:\path\to\file.txt" results in "C:\Temp\path\to\file.txt"
+//
+// If the provided root is not [filepath.Clean] then an error will be returned,
+// as such root paths are bordering on somewhat unsafe and using such paths is
+// not best practice. We also strongly suggest that any root path is first
+// fully resolved using [filepath.EvalSymlinks] or otherwise constructed to
+// avoid containing symlink components. Of course, the root also *must not* be
+// attacker-controlled.
+func SecureJoinVFS(root, unsafePath string, vfs VFS) (string, error) {
+ // The root path must not contain ".." components, otherwise when we join
+ // the subpath we will end up with a weird path. We could work around this
+ // in other ways but users shouldn't be giving us non-lexical root paths in
+ // the first place.
+ if hasDotDot(root) {
+ return "", errUnsafeRoot
+ }
+
+ // Use the os.* VFS implementation if none was specified.
+ if vfs == nil {
+ vfs = osVFS{}
+ }
+
+ unsafePath = filepath.FromSlash(unsafePath)
+ var (
+ currentPath string
+ remainingPath = unsafePath
+ linksWalked int
+ )
+ for remainingPath != "" {
+ // On Windows, if we managed to end up at a path referencing a volume,
+ // drop the volume to make sure we don't end up with broken paths or
+ // escaping the root volume.
+ remainingPath = stripVolume(remainingPath)
+
+ // Get the next path component.
+ var part string
+ if i := strings.IndexRune(remainingPath, filepath.Separator); i == -1 {
+ part, remainingPath = remainingPath, ""
+ } else {
+ part, remainingPath = remainingPath[:i], remainingPath[i+1:]
+ }
+
+ // Apply the component lexically to the path we are building.
+ // currentPath does not contain any symlinks, and we are lexically
+ // dealing with a single component, so it's okay to do a filepath.Clean
+ // here.
+ nextPath := filepath.Join(string(filepath.Separator), currentPath, part)
+ if nextPath == string(filepath.Separator) {
+ currentPath = ""
+ continue
+ }
+ fullPath := root + string(filepath.Separator) + nextPath
+
+ // Figure out whether the path is a symlink.
+ fi, err := vfs.Lstat(fullPath)
+ if err != nil && !IsNotExist(err) {
+ return "", err
+ }
+ // Treat non-existent path components the same as non-symlinks (we
+ // can't do any better here).
+ if IsNotExist(err) || fi.Mode()&os.ModeSymlink == 0 {
+ currentPath = nextPath
+ continue
+ }
+
+ // It's a symlink, so get its contents and expand it by prepending it
+ // to the yet-unparsed path.
+ linksWalked++
+ if linksWalked > maxSymlinkLimit {
+ return "", &os.PathError{Op: "SecureJoin", Path: root + string(filepath.Separator) + unsafePath, Err: syscall.ELOOP}
+ }
+
+ dest, err := vfs.Readlink(fullPath)
+ if err != nil {
+ return "", err
+ }
+ remainingPath = dest + string(filepath.Separator) + remainingPath
+ // Absolute symlinks reset any work we've already done.
+ if filepath.IsAbs(dest) {
+ currentPath = ""
+ }
+ }
+
+ // There should be no lexical components like ".." left in the path here,
+ // but for safety clean up the path before joining it to the root.
+ finalPath := filepath.Join(string(filepath.Separator), currentPath)
+ return filepath.Join(root, finalPath), nil
+}
+
+// SecureJoin is a wrapper around [SecureJoinVFS] that just uses the [os].* library
+// of functions as the [VFS]. If in doubt, use this function over [SecureJoinVFS].
+func SecureJoin(root, unsafePath string) (string, error) {
+ return SecureJoinVFS(root, unsafePath, nil)
+}
diff --git a/vendor/github.com/cyphar/filepath-securejoin/lookup_linux.go b/vendor/github.com/cyphar/filepath-securejoin/lookup_linux.go
new file mode 100644
index 0000000000..be81e498d7
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/lookup_linux.go
@@ -0,0 +1,388 @@
+//go:build linux
+
+// Copyright (C) 2024 SUSE LLC. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package securejoin
+
+import (
+ "errors"
+ "fmt"
+ "os"
+ "path"
+ "path/filepath"
+ "strings"
+
+ "golang.org/x/sys/unix"
+)
+
+type symlinkStackEntry struct {
+ // (dir, remainingPath) is what we would've returned if the link didn't
+ // exist. This matches what openat2(RESOLVE_IN_ROOT) would return in
+ // this case.
+ dir *os.File
+ remainingPath string
+ // linkUnwalked is the remaining path components from the original
+ // Readlink which we have yet to walk. When this slice is empty, we
+ // drop the link from the stack.
+ linkUnwalked []string
+}
+
+func (se symlinkStackEntry) String() string {
+ return fmt.Sprintf("<%s>/%s [->%s]", se.dir.Name(), se.remainingPath, strings.Join(se.linkUnwalked, "/"))
+}
+
+func (se symlinkStackEntry) Close() {
+ _ = se.dir.Close()
+}
+
+type symlinkStack []*symlinkStackEntry
+
+func (s *symlinkStack) IsEmpty() bool {
+ return s == nil || len(*s) == 0
+}
+
+func (s *symlinkStack) Close() {
+ if s != nil {
+ for _, link := range *s {
+ link.Close()
+ }
+ // TODO: Switch to clear once we switch to Go 1.21.
+ *s = nil
+ }
+}
+
+var (
+ errEmptyStack = errors.New("[internal] stack is empty")
+ errBrokenSymlinkStack = errors.New("[internal error] broken symlink stack")
+)
+
+func (s *symlinkStack) popPart(part string) error {
+ if s == nil || s.IsEmpty() {
+ // If there is nothing in the symlink stack, then the part was from the
+ // real path provided by the user, and this is a no-op.
+ return errEmptyStack
+ }
+ if part == "." {
+ // "." components are no-ops -- we drop them when doing SwapLink.
+ return nil
+ }
+
+ tailEntry := (*s)[len(*s)-1]
+
+ // Double-check that we are popping the component we expect.
+ if len(tailEntry.linkUnwalked) == 0 {
+ return fmt.Errorf("%w: trying to pop component %q of empty stack entry %s", errBrokenSymlinkStack, part, tailEntry)
+ }
+ headPart := tailEntry.linkUnwalked[0]
+ if headPart != part {
+ return fmt.Errorf("%w: trying to pop component %q but the last stack entry is %s (%q)", errBrokenSymlinkStack, part, tailEntry, headPart)
+ }
+
+ // Drop the component, but keep the entry around in case we are dealing
+ // with a "tail-chained" symlink.
+ tailEntry.linkUnwalked = tailEntry.linkUnwalked[1:]
+ return nil
+}
+
+func (s *symlinkStack) PopPart(part string) error {
+ if err := s.popPart(part); err != nil {
+ if errors.Is(err, errEmptyStack) {
+ // Skip empty stacks.
+ err = nil
+ }
+ return err
+ }
+
+ // Clean up any of the trailing stack entries that are empty.
+ for lastGood := len(*s) - 1; lastGood >= 0; lastGood-- {
+ entry := (*s)[lastGood]
+ if len(entry.linkUnwalked) > 0 {
+ break
+ }
+ entry.Close()
+ (*s) = (*s)[:lastGood]
+ }
+ return nil
+}
+
+func (s *symlinkStack) push(dir *os.File, remainingPath, linkTarget string) error {
+ if s == nil {
+ return nil
+ }
+ // Split the link target and clean up any "" parts.
+ linkTargetParts := slices_DeleteFunc(
+ strings.Split(linkTarget, "/"),
+ func(part string) bool { return part == "" || part == "." })
+
+ // Copy the directory so the caller doesn't close our copy.
+ dirCopy, err := dupFile(dir)
+ if err != nil {
+ return err
+ }
+
+ // Add to the stack.
+ *s = append(*s, &symlinkStackEntry{
+ dir: dirCopy,
+ remainingPath: remainingPath,
+ linkUnwalked: linkTargetParts,
+ })
+ return nil
+}
+
+func (s *symlinkStack) SwapLink(linkPart string, dir *os.File, remainingPath, linkTarget string) error {
+ // If we are currently inside a symlink resolution, remove the symlink
+ // component from the last symlink entry, but don't remove the entry even
+ // if it's empty. If we are a "tail-chained" symlink (a trailing symlink we
+ // hit during a symlink resolution) we need to keep the old symlink until
+ // we finish the resolution.
+ if err := s.popPart(linkPart); err != nil {
+ if !errors.Is(err, errEmptyStack) {
+ return err
+ }
+ // Push the component regardless of whether the stack was empty.
+ }
+ return s.push(dir, remainingPath, linkTarget)
+}
+
+func (s *symlinkStack) PopTopSymlink() (*os.File, string, bool) {
+ if s == nil || s.IsEmpty() {
+ return nil, "", false
+ }
+ tailEntry := (*s)[0]
+ *s = (*s)[1:]
+ return tailEntry.dir, tailEntry.remainingPath, true
+}
+
+// partialLookupInRoot tries to lookup as much of the request path as possible
+// within the provided root (a-la RESOLVE_IN_ROOT) and opens the final existing
+// component of the requested path, returning a file handle to the final
+// existing component and a string containing the remaining path components.
+func partialLookupInRoot(root *os.File, unsafePath string) (*os.File, string, error) {
+ return lookupInRoot(root, unsafePath, true)
+}
+
+func completeLookupInRoot(root *os.File, unsafePath string) (*os.File, error) {
+ handle, remainingPath, err := lookupInRoot(root, unsafePath, false)
+ if remainingPath != "" && err == nil {
+ // should never happen
+ err = fmt.Errorf("[bug] non-empty remaining path when doing a non-partial lookup: %q", remainingPath)
+ }
+ // lookupInRoot(partial=false) will always close the handle if an error is
+ // returned, so no need to double-check here.
+ return handle, err
+}
+
+func lookupInRoot(root *os.File, unsafePath string, partial bool) (Handle *os.File, _ string, _ error) {
+ unsafePath = filepath.ToSlash(unsafePath) // noop
+
+ // This is very similar to SecureJoin, except that we operate on the
+ // components using file descriptors. We then return the last component we
+ // managed open, along with the remaining path components not opened.
+
+ // Try to use openat2 if possible.
+ if hasOpenat2() {
+ return lookupOpenat2(root, unsafePath, partial)
+ }
+
+ // Get the "actual" root path from /proc/self/fd. This is necessary if the
+ // root is some magic-link like /proc/$pid/root, in which case we want to
+ // make sure when we do checkProcSelfFdPath that we are using the correct
+ // root path.
+ logicalRootPath, err := procSelfFdReadlink(root)
+ if err != nil {
+ return nil, "", fmt.Errorf("get real root path: %w", err)
+ }
+
+ currentDir, err := dupFile(root)
+ if err != nil {
+ return nil, "", fmt.Errorf("clone root fd: %w", err)
+ }
+ defer func() {
+ // If a handle is not returned, close the internal handle.
+ if Handle == nil {
+ _ = currentDir.Close()
+ }
+ }()
+
+ // symlinkStack is used to emulate how openat2(RESOLVE_IN_ROOT) treats
+ // dangling symlinks. If we hit a non-existent path while resolving a
+ // symlink, we need to return the (dir, remainingPath) that we had when we
+ // hit the symlink (treating the symlink as though it were a regular file).
+ // The set of (dir, remainingPath) sets is stored within the symlinkStack
+ // and we add and remove parts when we hit symlink and non-symlink
+ // components respectively. We need a stack because of recursive symlinks
+ // (symlinks that contain symlink components in their target).
+ //
+ // Note that the stack is ONLY used for book-keeping. All of the actual
+ // path walking logic is still based on currentPath/remainingPath and
+ // currentDir (as in SecureJoin).
+ var symStack *symlinkStack
+ if partial {
+ symStack = new(symlinkStack)
+ defer symStack.Close()
+ }
+
+ var (
+ linksWalked int
+ currentPath string
+ remainingPath = unsafePath
+ )
+ for remainingPath != "" {
+ // Save the current remaining path so if the part is not real we can
+ // return the path including the component.
+ oldRemainingPath := remainingPath
+
+ // Get the next path component.
+ var part string
+ if i := strings.IndexByte(remainingPath, '/'); i == -1 {
+ part, remainingPath = remainingPath, ""
+ } else {
+ part, remainingPath = remainingPath[:i], remainingPath[i+1:]
+ }
+ // If we hit an empty component, we need to treat it as though it is
+ // "." so that trailing "/" and "//" components on a non-directory
+ // correctly return the right error code.
+ if part == "" {
+ part = "."
+ }
+
+ // Apply the component lexically to the path we are building.
+ // currentPath does not contain any symlinks, and we are lexically
+ // dealing with a single component, so it's okay to do a filepath.Clean
+ // here.
+ nextPath := path.Join("/", currentPath, part)
+ // If we logically hit the root, just clone the root rather than
+ // opening the part and doing all of the other checks.
+ if nextPath == "/" {
+ if err := symStack.PopPart(part); err != nil {
+ return nil, "", fmt.Errorf("walking into root with part %q failed: %w", part, err)
+ }
+ // Jump to root.
+ rootClone, err := dupFile(root)
+ if err != nil {
+ return nil, "", fmt.Errorf("clone root fd: %w", err)
+ }
+ _ = currentDir.Close()
+ currentDir = rootClone
+ currentPath = nextPath
+ continue
+ }
+
+ // Try to open the next component.
+ nextDir, err := openatFile(currentDir, part, unix.O_PATH|unix.O_NOFOLLOW|unix.O_CLOEXEC, 0)
+ switch {
+ case err == nil:
+ st, err := nextDir.Stat()
+ if err != nil {
+ _ = nextDir.Close()
+ return nil, "", fmt.Errorf("stat component %q: %w", part, err)
+ }
+
+ switch st.Mode() & os.ModeType {
+ case os.ModeSymlink:
+ // readlinkat implies AT_EMPTY_PATH since Linux 2.6.39. See
+ // Linux commit 65cfc6722361 ("readlinkat(), fchownat() and
+ // fstatat() with empty relative pathnames").
+ linkDest, err := readlinkatFile(nextDir, "")
+ // We don't need the handle anymore.
+ _ = nextDir.Close()
+ if err != nil {
+ return nil, "", err
+ }
+
+ linksWalked++
+ if linksWalked > maxSymlinkLimit {
+ return nil, "", &os.PathError{Op: "securejoin.lookupInRoot", Path: logicalRootPath + "/" + unsafePath, Err: unix.ELOOP}
+ }
+
+ // Swap out the symlink's component for the link entry itself.
+ if err := symStack.SwapLink(part, currentDir, oldRemainingPath, linkDest); err != nil {
+ return nil, "", fmt.Errorf("walking into symlink %q failed: push symlink: %w", part, err)
+ }
+
+ // Update our logical remaining path.
+ remainingPath = linkDest + "/" + remainingPath
+ // Absolute symlinks reset any work we've already done.
+ if path.IsAbs(linkDest) {
+ // Jump to root.
+ rootClone, err := dupFile(root)
+ if err != nil {
+ return nil, "", fmt.Errorf("clone root fd: %w", err)
+ }
+ _ = currentDir.Close()
+ currentDir = rootClone
+ currentPath = "/"
+ }
+
+ default:
+ // If we are dealing with a directory, simply walk into it.
+ _ = currentDir.Close()
+ currentDir = nextDir
+ currentPath = nextPath
+
+ // The part was real, so drop it from the symlink stack.
+ if err := symStack.PopPart(part); err != nil {
+ return nil, "", fmt.Errorf("walking into directory %q failed: %w", part, err)
+ }
+
+ // If we are operating on a .., make sure we haven't escaped.
+ // We only have to check for ".." here because walking down
+ // into a regular component component cannot cause you to
+ // escape. This mirrors the logic in RESOLVE_IN_ROOT, except we
+ // have to check every ".." rather than only checking after a
+ // rename or mount on the system.
+ if part == ".." {
+ // Make sure the root hasn't moved.
+ if err := checkProcSelfFdPath(logicalRootPath, root); err != nil {
+ return nil, "", fmt.Errorf("root path moved during lookup: %w", err)
+ }
+ // Make sure the path is what we expect.
+ fullPath := logicalRootPath + nextPath
+ if err := checkProcSelfFdPath(fullPath, currentDir); err != nil {
+ return nil, "", fmt.Errorf("walking into %q had unexpected result: %w", part, err)
+ }
+ }
+ }
+
+ default:
+ if !partial {
+ return nil, "", err
+ }
+ // If there are any remaining components in the symlink stack, we
+ // are still within a symlink resolution and thus we hit a dangling
+ // symlink. So pretend that the first symlink in the stack we hit
+ // was an ENOENT (to match openat2).
+ if oldDir, remainingPath, ok := symStack.PopTopSymlink(); ok {
+ _ = currentDir.Close()
+ return oldDir, remainingPath, err
+ }
+ // We have hit a final component that doesn't exist, so we have our
+ // partial open result. Note that we have to use the OLD remaining
+ // path, since the lookup failed.
+ return currentDir, oldRemainingPath, err
+ }
+ }
+
+ // If the unsafePath had a trailing slash, we need to make sure we try to
+ // do a relative "." open so that we will correctly return an error when
+ // the final component is a non-directory (to match openat2). In the
+ // context of openat2, a trailing slash and a trailing "/." are completely
+ // equivalent.
+ if strings.HasSuffix(unsafePath, "/") {
+ nextDir, err := openatFile(currentDir, ".", unix.O_PATH|unix.O_NOFOLLOW|unix.O_CLOEXEC, 0)
+ if err != nil {
+ if !partial {
+ _ = currentDir.Close()
+ currentDir = nil
+ }
+ return currentDir, "", err
+ }
+ _ = currentDir.Close()
+ currentDir = nextDir
+ }
+
+ // All of the components existed!
+ return currentDir, "", nil
+}
diff --git a/vendor/github.com/cyphar/filepath-securejoin/mkdir_linux.go b/vendor/github.com/cyphar/filepath-securejoin/mkdir_linux.go
new file mode 100644
index 0000000000..a17ae3b038
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/mkdir_linux.go
@@ -0,0 +1,236 @@
+//go:build linux
+
+// Copyright (C) 2024 SUSE LLC. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package securejoin
+
+import (
+ "errors"
+ "fmt"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "golang.org/x/sys/unix"
+)
+
+var (
+ errInvalidMode = errors.New("invalid permission mode")
+ errPossibleAttack = errors.New("possible attack detected")
+)
+
+// modePermExt is like os.ModePerm except that it also includes the set[ug]id
+// and sticky bits.
+const modePermExt = os.ModePerm | os.ModeSetuid | os.ModeSetgid | os.ModeSticky
+
+//nolint:cyclop // this function needs to handle a lot of cases
+func toUnixMode(mode os.FileMode) (uint32, error) {
+ sysMode := uint32(mode.Perm())
+ if mode&os.ModeSetuid != 0 {
+ sysMode |= unix.S_ISUID
+ }
+ if mode&os.ModeSetgid != 0 {
+ sysMode |= unix.S_ISGID
+ }
+ if mode&os.ModeSticky != 0 {
+ sysMode |= unix.S_ISVTX
+ }
+ // We don't allow file type bits.
+ if mode&os.ModeType != 0 {
+ return 0, fmt.Errorf("%w %+.3o (%s): type bits not permitted", errInvalidMode, mode, mode)
+ }
+ // We don't allow other unknown modes.
+ if mode&^modePermExt != 0 || sysMode&unix.S_IFMT != 0 {
+ return 0, fmt.Errorf("%w %+.3o (%s): unknown mode bits", errInvalidMode, mode, mode)
+ }
+ return sysMode, nil
+}
+
+// MkdirAllHandle is equivalent to [MkdirAll], except that it is safer to use
+// in two respects:
+//
+// - The caller provides the root directory as an *[os.File] (preferably O_PATH)
+// handle. This means that the caller can be sure which root directory is
+// being used. Note that this can be emulated by using /proc/self/fd/... as
+// the root path with [os.MkdirAll].
+//
+// - Once all of the directories have been created, an *[os.File] O_PATH handle
+// to the directory at unsafePath is returned to the caller. This is done in
+// an effectively-race-free way (an attacker would only be able to swap the
+// final directory component), which is not possible to emulate with
+// [MkdirAll].
+//
+// In addition, the returned handle is obtained far more efficiently than doing
+// a brand new lookup of unsafePath (such as with [SecureJoin] or openat2) after
+// doing [MkdirAll]. If you intend to open the directory after creating it, you
+// should use MkdirAllHandle.
+func MkdirAllHandle(root *os.File, unsafePath string, mode os.FileMode) (_ *os.File, Err error) {
+ unixMode, err := toUnixMode(mode)
+ if err != nil {
+ return nil, err
+ }
+ // On Linux, mkdirat(2) (and os.Mkdir) silently ignore the suid and sgid
+ // bits. We could also silently ignore them but since we have very few
+ // users it seems more prudent to return an error so users notice that
+ // these bits will not be set.
+ if unixMode&^0o1777 != 0 {
+ return nil, fmt.Errorf("%w for mkdir %+.3o: suid and sgid are ignored by mkdir", errInvalidMode, mode)
+ }
+
+ // Try to open as much of the path as possible.
+ currentDir, remainingPath, err := partialLookupInRoot(root, unsafePath)
+ defer func() {
+ if Err != nil {
+ _ = currentDir.Close()
+ }
+ }()
+ if err != nil && !errors.Is(err, unix.ENOENT) {
+ return nil, fmt.Errorf("find existing subpath of %q: %w", unsafePath, err)
+ }
+
+ // If there is an attacker deleting directories as we walk into them,
+ // detect this proactively. Note this is guaranteed to detect if the
+ // attacker deleted any part of the tree up to currentDir.
+ //
+ // Once we walk into a dead directory, partialLookupInRoot would not be
+ // able to walk further down the tree (directories must be empty before
+ // they are deleted), and if the attacker has removed the entire tree we
+ // can be sure that anything that was originally inside a dead directory
+ // must also be deleted and thus is a dead directory in its own right.
+ //
+ // This is mostly a quality-of-life check, because mkdir will simply fail
+ // later if the attacker deletes the tree after this check.
+ if err := isDeadInode(currentDir); err != nil {
+ return nil, fmt.Errorf("finding existing subpath of %q: %w", unsafePath, err)
+ }
+
+ // Re-open the path to match the O_DIRECTORY reopen loop later (so that we
+ // always return a non-O_PATH handle). We also check that we actually got a
+ // directory.
+ if reopenDir, err := Reopen(currentDir, unix.O_DIRECTORY|unix.O_CLOEXEC); errors.Is(err, unix.ENOTDIR) {
+ return nil, fmt.Errorf("cannot create subdirectories in %q: %w", currentDir.Name(), unix.ENOTDIR)
+ } else if err != nil {
+ return nil, fmt.Errorf("re-opening handle to %q: %w", currentDir.Name(), err)
+ } else {
+ _ = currentDir.Close()
+ currentDir = reopenDir
+ }
+
+ remainingParts := strings.Split(remainingPath, string(filepath.Separator))
+ if slices_Contains(remainingParts, "..") {
+ // The path contained ".." components after the end of the "real"
+ // components. We could try to safely resolve ".." here but that would
+ // add a bunch of extra logic for something that it's not clear even
+ // needs to be supported. So just return an error.
+ //
+ // If we do filepath.Clean(remainingPath) then we end up with the
+ // problem that ".." can erase a trailing dangling symlink and produce
+ // a path that doesn't quite match what the user asked for.
+ return nil, fmt.Errorf("%w: yet-to-be-created path %q contains '..' components", unix.ENOENT, remainingPath)
+ }
+
+ // Create the remaining components.
+ for _, part := range remainingParts {
+ switch part {
+ case "", ".":
+ // Skip over no-op paths.
+ continue
+ }
+
+ // NOTE: mkdir(2) will not follow trailing symlinks, so we can safely
+ // create the final component without worrying about symlink-exchange
+ // attacks.
+ //
+ // If we get -EEXIST, it's possible that another program created the
+ // directory at the same time as us. In that case, just continue on as
+ // if we created it (if the created inode is not a directory, the
+ // following open call will fail).
+ if err := unix.Mkdirat(int(currentDir.Fd()), part, unixMode); err != nil && !errors.Is(err, unix.EEXIST) {
+ err = &os.PathError{Op: "mkdirat", Path: currentDir.Name() + "/" + part, Err: err}
+ // Make the error a bit nicer if the directory is dead.
+ if deadErr := isDeadInode(currentDir); deadErr != nil {
+ // TODO: Once we bump the minimum Go version to 1.20, we can use
+ // multiple %w verbs for this wrapping. For now we need to use a
+ // compatibility shim for older Go versions.
+ //err = fmt.Errorf("%w (%w)", err, deadErr)
+ err = wrapBaseError(err, deadErr)
+ }
+ return nil, err
+ }
+
+ // Get a handle to the next component. O_DIRECTORY means we don't need
+ // to use O_PATH.
+ var nextDir *os.File
+ if hasOpenat2() {
+ nextDir, err = openat2File(currentDir, part, &unix.OpenHow{
+ Flags: unix.O_NOFOLLOW | unix.O_DIRECTORY | unix.O_CLOEXEC,
+ Resolve: unix.RESOLVE_BENEATH | unix.RESOLVE_NO_SYMLINKS | unix.RESOLVE_NO_XDEV,
+ })
+ } else {
+ nextDir, err = openatFile(currentDir, part, unix.O_NOFOLLOW|unix.O_DIRECTORY|unix.O_CLOEXEC, 0)
+ }
+ if err != nil {
+ return nil, err
+ }
+ _ = currentDir.Close()
+ currentDir = nextDir
+
+ // It's possible that the directory we just opened was swapped by an
+ // attacker. Unfortunately there isn't much we can do to protect
+ // against this, and MkdirAll's behaviour is that we will reuse
+ // existing directories anyway so the need to protect against this is
+ // incredibly limited (and arguably doesn't even deserve mention here).
+ //
+ // Ideally we might want to check that the owner and mode match what we
+ // would've created -- unfortunately, it is non-trivial to verify that
+ // the owner and mode of the created directory match. While plain Unix
+ // DAC rules seem simple enough to emulate, there are a bunch of other
+ // factors that can change the mode or owner of created directories
+ // (default POSIX ACLs, mount options like uid=1,gid=2,umask=0 on
+ // filesystems like vfat, etc etc). We used to try to verify this but
+ // it just lead to a series of spurious errors.
+ //
+ // We could also check that the directory is non-empty, but
+ // unfortunately some pseduofilesystems (like cgroupfs) create
+ // non-empty directories, which would result in different spurious
+ // errors.
+ }
+ return currentDir, nil
+}
+
+// MkdirAll is a race-safe alternative to the [os.MkdirAll] function,
+// where the new directory is guaranteed to be within the root directory (if an
+// attacker can move directories from inside the root to outside the root, the
+// created directory tree might be outside of the root but the key constraint
+// is that at no point will we walk outside of the directory tree we are
+// creating).
+//
+// Effectively, MkdirAll(root, unsafePath, mode) is equivalent to
+//
+// path, _ := securejoin.SecureJoin(root, unsafePath)
+// err := os.MkdirAll(path, mode)
+//
+// But is much safer. The above implementation is unsafe because if an attacker
+// can modify the filesystem tree between [SecureJoin] and [os.MkdirAll], it is
+// possible for MkdirAll to resolve unsafe symlink components and create
+// directories outside of the root.
+//
+// If you plan to open the directory after you have created it or want to use
+// an open directory handle as the root, you should use [MkdirAllHandle] instead.
+// This function is a wrapper around [MkdirAllHandle].
+func MkdirAll(root, unsafePath string, mode os.FileMode) error {
+ rootDir, err := os.OpenFile(root, unix.O_PATH|unix.O_DIRECTORY|unix.O_CLOEXEC, 0)
+ if err != nil {
+ return err
+ }
+ defer rootDir.Close()
+
+ f, err := MkdirAllHandle(rootDir, unsafePath, mode)
+ if err != nil {
+ return err
+ }
+ _ = f.Close()
+ return nil
+}
diff --git a/vendor/github.com/cyphar/filepath-securejoin/open_linux.go b/vendor/github.com/cyphar/filepath-securejoin/open_linux.go
new file mode 100644
index 0000000000..230be73f0e
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/open_linux.go
@@ -0,0 +1,103 @@
+//go:build linux
+
+// Copyright (C) 2024 SUSE LLC. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package securejoin
+
+import (
+ "fmt"
+ "os"
+ "strconv"
+
+ "golang.org/x/sys/unix"
+)
+
+// OpenatInRoot is equivalent to [OpenInRoot], except that the root is provided
+// using an *[os.File] handle, to ensure that the correct root directory is used.
+func OpenatInRoot(root *os.File, unsafePath string) (*os.File, error) {
+ handle, err := completeLookupInRoot(root, unsafePath)
+ if err != nil {
+ return nil, &os.PathError{Op: "securejoin.OpenInRoot", Path: unsafePath, Err: err}
+ }
+ return handle, nil
+}
+
+// OpenInRoot safely opens the provided unsafePath within the root.
+// Effectively, OpenInRoot(root, unsafePath) is equivalent to
+//
+// path, _ := securejoin.SecureJoin(root, unsafePath)
+// handle, err := os.OpenFile(path, unix.O_PATH|unix.O_CLOEXEC)
+//
+// But is much safer. The above implementation is unsafe because if an attacker
+// can modify the filesystem tree between [SecureJoin] and [os.OpenFile], it is
+// possible for the returned file to be outside of the root.
+//
+// Note that the returned handle is an O_PATH handle, meaning that only a very
+// limited set of operations will work on the handle. This is done to avoid
+// accidentally opening an untrusted file that could cause issues (such as a
+// disconnected TTY that could cause a DoS, or some other issue). In order to
+// use the returned handle, you can "upgrade" it to a proper handle using
+// [Reopen].
+func OpenInRoot(root, unsafePath string) (*os.File, error) {
+ rootDir, err := os.OpenFile(root, unix.O_PATH|unix.O_DIRECTORY|unix.O_CLOEXEC, 0)
+ if err != nil {
+ return nil, err
+ }
+ defer rootDir.Close()
+ return OpenatInRoot(rootDir, unsafePath)
+}
+
+// Reopen takes an *[os.File] handle and re-opens it through /proc/self/fd.
+// Reopen(file, flags) is effectively equivalent to
+//
+// fdPath := fmt.Sprintf("/proc/self/fd/%d", file.Fd())
+// os.OpenFile(fdPath, flags|unix.O_CLOEXEC)
+//
+// But with some extra hardenings to ensure that we are not tricked by a
+// maliciously-configured /proc mount. While this attack scenario is not
+// common, in container runtimes it is possible for higher-level runtimes to be
+// tricked into configuring an unsafe /proc that can be used to attack file
+// operations. See [CVE-2019-19921] for more details.
+//
+// [CVE-2019-19921]: https://github.com/advisories/GHSA-fh74-hm69-rqjw
+func Reopen(handle *os.File, flags int) (*os.File, error) {
+ procRoot, err := getProcRoot()
+ if err != nil {
+ return nil, err
+ }
+
+ // We can't operate on /proc/thread-self/fd/$n directly when doing a
+ // re-open, so we need to open /proc/thread-self/fd and then open a single
+ // final component.
+ procFdDir, closer, err := procThreadSelf(procRoot, "fd/")
+ if err != nil {
+ return nil, fmt.Errorf("get safe /proc/thread-self/fd handle: %w", err)
+ }
+ defer procFdDir.Close()
+ defer closer()
+
+ // Try to detect if there is a mount on top of the magic-link we are about
+ // to open. If we are using unsafeHostProcRoot(), this could change after
+ // we check it (and there's nothing we can do about that) but for
+ // privateProcRoot() this should be guaranteed to be safe (at least since
+ // Linux 5.12[1], when anonymous mount namespaces were completely isolated
+ // from external mounts including mount propagation events).
+ //
+ // [1]: Linux commit ee2e3f50629f ("mount: fix mounting of detached mounts
+ // onto targets that reside on shared mounts").
+ fdStr := strconv.Itoa(int(handle.Fd()))
+ if err := checkSymlinkOvermount(procRoot, procFdDir, fdStr); err != nil {
+ return nil, fmt.Errorf("check safety of /proc/thread-self/fd/%s magiclink: %w", fdStr, err)
+ }
+
+ flags |= unix.O_CLOEXEC
+ // Rather than just wrapping openatFile, open-code it so we can copy
+ // handle.Name().
+ reopenFd, err := unix.Openat(int(procFdDir.Fd()), fdStr, flags, 0)
+ if err != nil {
+ return nil, fmt.Errorf("reopen fd %d: %w", handle.Fd(), err)
+ }
+ return os.NewFile(uintptr(reopenFd), handle.Name()), nil
+}
diff --git a/vendor/github.com/cyphar/filepath-securejoin/openat2_linux.go b/vendor/github.com/cyphar/filepath-securejoin/openat2_linux.go
new file mode 100644
index 0000000000..f7a13e69ce
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/openat2_linux.go
@@ -0,0 +1,127 @@
+//go:build linux
+
+// Copyright (C) 2024 SUSE LLC. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package securejoin
+
+import (
+ "errors"
+ "fmt"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "golang.org/x/sys/unix"
+)
+
+var hasOpenat2 = sync_OnceValue(func() bool {
+ fd, err := unix.Openat2(unix.AT_FDCWD, ".", &unix.OpenHow{
+ Flags: unix.O_PATH | unix.O_CLOEXEC,
+ Resolve: unix.RESOLVE_NO_SYMLINKS | unix.RESOLVE_IN_ROOT,
+ })
+ if err != nil {
+ return false
+ }
+ _ = unix.Close(fd)
+ return true
+})
+
+func scopedLookupShouldRetry(how *unix.OpenHow, err error) bool {
+ // RESOLVE_IN_ROOT (and RESOLVE_BENEATH) can return -EAGAIN if we resolve
+ // ".." while a mount or rename occurs anywhere on the system. This could
+ // happen spuriously, or as the result of an attacker trying to mess with
+ // us during lookup.
+ //
+ // In addition, scoped lookups have a "safety check" at the end of
+ // complete_walk which will return -EXDEV if the final path is not in the
+ // root.
+ return how.Resolve&(unix.RESOLVE_IN_ROOT|unix.RESOLVE_BENEATH) != 0 &&
+ (errors.Is(err, unix.EAGAIN) || errors.Is(err, unix.EXDEV))
+}
+
+const scopedLookupMaxRetries = 10
+
+func openat2File(dir *os.File, path string, how *unix.OpenHow) (*os.File, error) {
+ fullPath := dir.Name() + "/" + path
+ // Make sure we always set O_CLOEXEC.
+ how.Flags |= unix.O_CLOEXEC
+ var tries int
+ for tries < scopedLookupMaxRetries {
+ fd, err := unix.Openat2(int(dir.Fd()), path, how)
+ if err != nil {
+ if scopedLookupShouldRetry(how, err) {
+ // We retry a couple of times to avoid the spurious errors, and
+ // if we are being attacked then returning -EAGAIN is the best
+ // we can do.
+ tries++
+ continue
+ }
+ return nil, &os.PathError{Op: "openat2", Path: fullPath, Err: err}
+ }
+ // If we are using RESOLVE_IN_ROOT, the name we generated may be wrong.
+ // NOTE: The procRoot code MUST NOT use RESOLVE_IN_ROOT, otherwise
+ // you'll get infinite recursion here.
+ if how.Resolve&unix.RESOLVE_IN_ROOT == unix.RESOLVE_IN_ROOT {
+ if actualPath, err := rawProcSelfFdReadlink(fd); err == nil {
+ fullPath = actualPath
+ }
+ }
+ return os.NewFile(uintptr(fd), fullPath), nil
+ }
+ return nil, &os.PathError{Op: "openat2", Path: fullPath, Err: errPossibleAttack}
+}
+
+func lookupOpenat2(root *os.File, unsafePath string, partial bool) (*os.File, string, error) {
+ if !partial {
+ file, err := openat2File(root, unsafePath, &unix.OpenHow{
+ Flags: unix.O_PATH | unix.O_CLOEXEC,
+ Resolve: unix.RESOLVE_IN_ROOT | unix.RESOLVE_NO_MAGICLINKS,
+ })
+ return file, "", err
+ }
+ return partialLookupOpenat2(root, unsafePath)
+}
+
+// partialLookupOpenat2 is an alternative implementation of
+// partialLookupInRoot, using openat2(RESOLVE_IN_ROOT) to more safely get a
+// handle to the deepest existing child of the requested path within the root.
+func partialLookupOpenat2(root *os.File, unsafePath string) (*os.File, string, error) {
+ // TODO: Implement this as a git-bisect-like binary search.
+
+ unsafePath = filepath.ToSlash(unsafePath) // noop
+ endIdx := len(unsafePath)
+ var lastError error
+ for endIdx > 0 {
+ subpath := unsafePath[:endIdx]
+
+ handle, err := openat2File(root, subpath, &unix.OpenHow{
+ Flags: unix.O_PATH | unix.O_CLOEXEC,
+ Resolve: unix.RESOLVE_IN_ROOT | unix.RESOLVE_NO_MAGICLINKS,
+ })
+ if err == nil {
+ // Jump over the slash if we have a non-"" remainingPath.
+ if endIdx < len(unsafePath) {
+ endIdx += 1
+ }
+ // We found a subpath!
+ return handle, unsafePath[endIdx:], lastError
+ }
+ if errors.Is(err, unix.ENOENT) || errors.Is(err, unix.ENOTDIR) {
+ // That path doesn't exist, let's try the next directory up.
+ endIdx = strings.LastIndexByte(subpath, '/')
+ lastError = err
+ continue
+ }
+ return nil, "", fmt.Errorf("open subpath: %w", err)
+ }
+ // If we couldn't open anything, the whole subpath is missing. Return a
+ // copy of the root fd so that the caller doesn't close this one by
+ // accident.
+ rootClone, err := dupFile(root)
+ if err != nil {
+ return nil, "", err
+ }
+ return rootClone, unsafePath, lastError
+}
diff --git a/vendor/github.com/cyphar/filepath-securejoin/openat_linux.go b/vendor/github.com/cyphar/filepath-securejoin/openat_linux.go
new file mode 100644
index 0000000000..949fb5f2d8
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/openat_linux.go
@@ -0,0 +1,59 @@
+//go:build linux
+
+// Copyright (C) 2024 SUSE LLC. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package securejoin
+
+import (
+ "os"
+ "path/filepath"
+
+ "golang.org/x/sys/unix"
+)
+
+func dupFile(f *os.File) (*os.File, error) {
+ fd, err := unix.FcntlInt(f.Fd(), unix.F_DUPFD_CLOEXEC, 0)
+ if err != nil {
+ return nil, os.NewSyscallError("fcntl(F_DUPFD_CLOEXEC)", err)
+ }
+ return os.NewFile(uintptr(fd), f.Name()), nil
+}
+
+func openatFile(dir *os.File, path string, flags int, mode int) (*os.File, error) {
+ // Make sure we always set O_CLOEXEC.
+ flags |= unix.O_CLOEXEC
+ fd, err := unix.Openat(int(dir.Fd()), path, flags, uint32(mode))
+ if err != nil {
+ return nil, &os.PathError{Op: "openat", Path: dir.Name() + "/" + path, Err: err}
+ }
+ // All of the paths we use with openatFile(2) are guaranteed to be
+ // lexically safe, so we can use path.Join here.
+ fullPath := filepath.Join(dir.Name(), path)
+ return os.NewFile(uintptr(fd), fullPath), nil
+}
+
+func fstatatFile(dir *os.File, path string, flags int) (unix.Stat_t, error) {
+ var stat unix.Stat_t
+ if err := unix.Fstatat(int(dir.Fd()), path, &stat, flags); err != nil {
+ return stat, &os.PathError{Op: "fstatat", Path: dir.Name() + "/" + path, Err: err}
+ }
+ return stat, nil
+}
+
+func readlinkatFile(dir *os.File, path string) (string, error) {
+ size := 4096
+ for {
+ linkBuf := make([]byte, size)
+ n, err := unix.Readlinkat(int(dir.Fd()), path, linkBuf)
+ if err != nil {
+ return "", &os.PathError{Op: "readlinkat", Path: dir.Name() + "/" + path, Err: err}
+ }
+ if n != size {
+ return string(linkBuf[:n]), nil
+ }
+ // Possible truncation, resize the buffer.
+ size *= 2
+ }
+}
diff --git a/vendor/github.com/cyphar/filepath-securejoin/procfs_linux.go b/vendor/github.com/cyphar/filepath-securejoin/procfs_linux.go
new file mode 100644
index 0000000000..809a579cbd
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/procfs_linux.go
@@ -0,0 +1,452 @@
+//go:build linux
+
+// Copyright (C) 2024 SUSE LLC. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package securejoin
+
+import (
+ "errors"
+ "fmt"
+ "os"
+ "runtime"
+ "strconv"
+
+ "golang.org/x/sys/unix"
+)
+
+func fstat(f *os.File) (unix.Stat_t, error) {
+ var stat unix.Stat_t
+ if err := unix.Fstat(int(f.Fd()), &stat); err != nil {
+ return stat, &os.PathError{Op: "fstat", Path: f.Name(), Err: err}
+ }
+ return stat, nil
+}
+
+func fstatfs(f *os.File) (unix.Statfs_t, error) {
+ var statfs unix.Statfs_t
+ if err := unix.Fstatfs(int(f.Fd()), &statfs); err != nil {
+ return statfs, &os.PathError{Op: "fstatfs", Path: f.Name(), Err: err}
+ }
+ return statfs, nil
+}
+
+// The kernel guarantees that the root inode of a procfs mount has an
+// f_type of PROC_SUPER_MAGIC and st_ino of PROC_ROOT_INO.
+const (
+ procSuperMagic = 0x9fa0 // PROC_SUPER_MAGIC
+ procRootIno = 1 // PROC_ROOT_INO
+)
+
+func verifyProcRoot(procRoot *os.File) error {
+ if statfs, err := fstatfs(procRoot); err != nil {
+ return err
+ } else if statfs.Type != procSuperMagic {
+ return fmt.Errorf("%w: incorrect procfs root filesystem type 0x%x", errUnsafeProcfs, statfs.Type)
+ }
+ if stat, err := fstat(procRoot); err != nil {
+ return err
+ } else if stat.Ino != procRootIno {
+ return fmt.Errorf("%w: incorrect procfs root inode number %d", errUnsafeProcfs, stat.Ino)
+ }
+ return nil
+}
+
+var hasNewMountApi = sync_OnceValue(func() bool {
+ // All of the pieces of the new mount API we use (fsopen, fsconfig,
+ // fsmount, open_tree) were added together in Linux 5.1[1,2], so we can
+ // just check for one of the syscalls and the others should also be
+ // available.
+ //
+ // Just try to use open_tree(2) to open a file without OPEN_TREE_CLONE.
+ // This is equivalent to openat(2), but tells us if open_tree is
+ // available (and thus all of the other basic new mount API syscalls).
+ // open_tree(2) is most light-weight syscall to test here.
+ //
+ // [1]: merge commit 400913252d09
+ // [2]:
+ fd, err := unix.OpenTree(-int(unix.EBADF), "/", unix.OPEN_TREE_CLOEXEC)
+ if err != nil {
+ return false
+ }
+ _ = unix.Close(fd)
+ return true
+})
+
+func fsopen(fsName string, flags int) (*os.File, error) {
+ // Make sure we always set O_CLOEXEC.
+ flags |= unix.FSOPEN_CLOEXEC
+ fd, err := unix.Fsopen(fsName, flags)
+ if err != nil {
+ return nil, os.NewSyscallError("fsopen "+fsName, err)
+ }
+ return os.NewFile(uintptr(fd), "fscontext:"+fsName), nil
+}
+
+func fsmount(ctx *os.File, flags, mountAttrs int) (*os.File, error) {
+ // Make sure we always set O_CLOEXEC.
+ flags |= unix.FSMOUNT_CLOEXEC
+ fd, err := unix.Fsmount(int(ctx.Fd()), flags, mountAttrs)
+ if err != nil {
+ return nil, os.NewSyscallError("fsmount "+ctx.Name(), err)
+ }
+ return os.NewFile(uintptr(fd), "fsmount:"+ctx.Name()), nil
+}
+
+func newPrivateProcMount() (*os.File, error) {
+ procfsCtx, err := fsopen("proc", unix.FSOPEN_CLOEXEC)
+ if err != nil {
+ return nil, err
+ }
+ defer procfsCtx.Close()
+
+ // Try to configure hidepid=ptraceable,subset=pid if possible, but ignore errors.
+ _ = unix.FsconfigSetString(int(procfsCtx.Fd()), "hidepid", "ptraceable")
+ _ = unix.FsconfigSetString(int(procfsCtx.Fd()), "subset", "pid")
+
+ // Get an actual handle.
+ if err := unix.FsconfigCreate(int(procfsCtx.Fd())); err != nil {
+ return nil, os.NewSyscallError("fsconfig create procfs", err)
+ }
+ return fsmount(procfsCtx, unix.FSMOUNT_CLOEXEC, unix.MS_RDONLY|unix.MS_NODEV|unix.MS_NOEXEC|unix.MS_NOSUID)
+}
+
+func openTree(dir *os.File, path string, flags uint) (*os.File, error) {
+ dirFd := -int(unix.EBADF)
+ dirName := "."
+ if dir != nil {
+ dirFd = int(dir.Fd())
+ dirName = dir.Name()
+ }
+ // Make sure we always set O_CLOEXEC.
+ flags |= unix.OPEN_TREE_CLOEXEC
+ fd, err := unix.OpenTree(dirFd, path, flags)
+ if err != nil {
+ return nil, &os.PathError{Op: "open_tree", Path: path, Err: err}
+ }
+ return os.NewFile(uintptr(fd), dirName+"/"+path), nil
+}
+
+func clonePrivateProcMount() (_ *os.File, Err error) {
+ // Try to make a clone without using AT_RECURSIVE if we can. If this works,
+ // we can be sure there are no over-mounts and so if the root is valid then
+ // we're golden. Otherwise, we have to deal with over-mounts.
+ procfsHandle, err := openTree(nil, "/proc", unix.OPEN_TREE_CLONE)
+ if err != nil || hookForcePrivateProcRootOpenTreeAtRecursive(procfsHandle) {
+ procfsHandle, err = openTree(nil, "/proc", unix.OPEN_TREE_CLONE|unix.AT_RECURSIVE)
+ }
+ if err != nil {
+ return nil, fmt.Errorf("creating a detached procfs clone: %w", err)
+ }
+ defer func() {
+ if Err != nil {
+ _ = procfsHandle.Close()
+ }
+ }()
+ if err := verifyProcRoot(procfsHandle); err != nil {
+ return nil, err
+ }
+ return procfsHandle, nil
+}
+
+func privateProcRoot() (*os.File, error) {
+ if !hasNewMountApi() || hookForceGetProcRootUnsafe() {
+ return nil, fmt.Errorf("new mount api: %w", unix.ENOTSUP)
+ }
+ // Try to create a new procfs mount from scratch if we can. This ensures we
+ // can get a procfs mount even if /proc is fake (for whatever reason).
+ procRoot, err := newPrivateProcMount()
+ if err != nil || hookForcePrivateProcRootOpenTree(procRoot) {
+ // Try to clone /proc then...
+ procRoot, err = clonePrivateProcMount()
+ }
+ return procRoot, err
+}
+
+func unsafeHostProcRoot() (_ *os.File, Err error) {
+ procRoot, err := os.OpenFile("/proc", unix.O_PATH|unix.O_NOFOLLOW|unix.O_DIRECTORY|unix.O_CLOEXEC, 0)
+ if err != nil {
+ return nil, err
+ }
+ defer func() {
+ if Err != nil {
+ _ = procRoot.Close()
+ }
+ }()
+ if err := verifyProcRoot(procRoot); err != nil {
+ return nil, err
+ }
+ return procRoot, nil
+}
+
+func doGetProcRoot() (*os.File, error) {
+ procRoot, err := privateProcRoot()
+ if err != nil {
+ // Fall back to using a /proc handle if making a private mount failed.
+ // If we have openat2, at least we can avoid some kinds of over-mount
+ // attacks, but without openat2 there's not much we can do.
+ procRoot, err = unsafeHostProcRoot()
+ }
+ return procRoot, err
+}
+
+var getProcRoot = sync_OnceValues(func() (*os.File, error) {
+ return doGetProcRoot()
+})
+
+var hasProcThreadSelf = sync_OnceValue(func() bool {
+ return unix.Access("/proc/thread-self/", unix.F_OK) == nil
+})
+
+var errUnsafeProcfs = errors.New("unsafe procfs detected")
+
+type procThreadSelfCloser func()
+
+// procThreadSelf returns a handle to /proc/thread-self/ (or an
+// equivalent handle on older kernels where /proc/thread-self doesn't exist).
+// Once finished with the handle, you must call the returned closer function
+// (runtime.UnlockOSThread). You must not pass the returned *os.File to other
+// Go threads or use the handle after calling the closer.
+//
+// This is similar to ProcThreadSelf from runc, but with extra hardening
+// applied and using *os.File.
+func procThreadSelf(procRoot *os.File, subpath string) (_ *os.File, _ procThreadSelfCloser, Err error) {
+ // We need to lock our thread until the caller is done with the handle
+ // because between getting the handle and using it we could get interrupted
+ // by the Go runtime and hit the case where the underlying thread is
+ // swapped out and the original thread is killed, resulting in
+ // pull-your-hair-out-hard-to-debug issues in the caller.
+ runtime.LockOSThread()
+ defer func() {
+ if Err != nil {
+ runtime.UnlockOSThread()
+ }
+ }()
+
+ // Figure out what prefix we want to use.
+ threadSelf := "thread-self/"
+ if !hasProcThreadSelf() || hookForceProcSelfTask() {
+ /// Pre-3.17 kernels don't have /proc/thread-self, so do it manually.
+ threadSelf = "self/task/" + strconv.Itoa(unix.Gettid()) + "/"
+ if _, err := fstatatFile(procRoot, threadSelf, unix.AT_SYMLINK_NOFOLLOW); err != nil || hookForceProcSelf() {
+ // In this case, we running in a pid namespace that doesn't match
+ // the /proc mount we have. This can happen inside runc.
+ //
+ // Unfortunately, there is no nice way to get the correct TID to
+ // use here because of the age of the kernel, so we have to just
+ // use /proc/self and hope that it works.
+ threadSelf = "self/"
+ }
+ }
+
+ // Grab the handle.
+ var (
+ handle *os.File
+ err error
+ )
+ if hasOpenat2() {
+ // We prefer being able to use RESOLVE_NO_XDEV if we can, to be
+ // absolutely sure we are operating on a clean /proc handle that
+ // doesn't have any cheeky overmounts that could trick us (including
+ // symlink mounts on top of /proc/thread-self). RESOLVE_BENEATH isn't
+ // strictly needed, but just use it since we have it.
+ //
+ // NOTE: /proc/self is technically a magic-link (the contents of the
+ // symlink are generated dynamically), but it doesn't use
+ // nd_jump_link() so RESOLVE_NO_MAGICLINKS allows it.
+ //
+ // NOTE: We MUST NOT use RESOLVE_IN_ROOT here, as openat2File uses
+ // procSelfFdReadlink to clean up the returned f.Name() if we use
+ // RESOLVE_IN_ROOT (which would lead to an infinite recursion).
+ handle, err = openat2File(procRoot, threadSelf+subpath, &unix.OpenHow{
+ Flags: unix.O_PATH | unix.O_NOFOLLOW | unix.O_CLOEXEC,
+ Resolve: unix.RESOLVE_BENEATH | unix.RESOLVE_NO_XDEV | unix.RESOLVE_NO_MAGICLINKS,
+ })
+ if err != nil {
+ // TODO: Once we bump the minimum Go version to 1.20, we can use
+ // multiple %w verbs for this wrapping. For now we need to use a
+ // compatibility shim for older Go versions.
+ //err = fmt.Errorf("%w: %w", errUnsafeProcfs, err)
+ return nil, nil, wrapBaseError(err, errUnsafeProcfs)
+ }
+ } else {
+ handle, err = openatFile(procRoot, threadSelf+subpath, unix.O_PATH|unix.O_NOFOLLOW|unix.O_CLOEXEC, 0)
+ if err != nil {
+ // TODO: Once we bump the minimum Go version to 1.20, we can use
+ // multiple %w verbs for this wrapping. For now we need to use a
+ // compatibility shim for older Go versions.
+ //err = fmt.Errorf("%w: %w", errUnsafeProcfs, err)
+ return nil, nil, wrapBaseError(err, errUnsafeProcfs)
+ }
+ defer func() {
+ if Err != nil {
+ _ = handle.Close()
+ }
+ }()
+ // We can't detect bind-mounts of different parts of procfs on top of
+ // /proc (a-la RESOLVE_NO_XDEV), but we can at least be sure that we
+ // aren't on the wrong filesystem here.
+ if statfs, err := fstatfs(handle); err != nil {
+ return nil, nil, err
+ } else if statfs.Type != procSuperMagic {
+ return nil, nil, fmt.Errorf("%w: incorrect /proc/self/fd filesystem type 0x%x", errUnsafeProcfs, statfs.Type)
+ }
+ }
+ return handle, runtime.UnlockOSThread, nil
+}
+
+// STATX_MNT_ID_UNIQUE is provided in golang.org/x/sys@v0.20.0, but in order to
+// avoid bumping the requirement for a single constant we can just define it
+// ourselves.
+const STATX_MNT_ID_UNIQUE = 0x4000
+
+var hasStatxMountId = sync_OnceValue(func() bool {
+ var (
+ stx unix.Statx_t
+ // We don't care which mount ID we get. The kernel will give us the
+ // unique one if it is supported.
+ wantStxMask uint32 = STATX_MNT_ID_UNIQUE | unix.STATX_MNT_ID
+ )
+ err := unix.Statx(-int(unix.EBADF), "/", 0, int(wantStxMask), &stx)
+ return err == nil && stx.Mask&wantStxMask != 0
+})
+
+func getMountId(dir *os.File, path string) (uint64, error) {
+ // If we don't have statx(STATX_MNT_ID*) support, we can't do anything.
+ if !hasStatxMountId() {
+ return 0, nil
+ }
+
+ var (
+ stx unix.Statx_t
+ // We don't care which mount ID we get. The kernel will give us the
+ // unique one if it is supported.
+ wantStxMask uint32 = STATX_MNT_ID_UNIQUE | unix.STATX_MNT_ID
+ )
+
+ err := unix.Statx(int(dir.Fd()), path, unix.AT_EMPTY_PATH|unix.AT_SYMLINK_NOFOLLOW, int(wantStxMask), &stx)
+ if stx.Mask&wantStxMask == 0 {
+ // It's not a kernel limitation, for some reason we couldn't get a
+ // mount ID. Assume it's some kind of attack.
+ err = fmt.Errorf("%w: could not get mount id", errUnsafeProcfs)
+ }
+ if err != nil {
+ return 0, &os.PathError{Op: "statx(STATX_MNT_ID_...)", Path: dir.Name() + "/" + path, Err: err}
+ }
+ return stx.Mnt_id, nil
+}
+
+func checkSymlinkOvermount(procRoot *os.File, dir *os.File, path string) error {
+ // Get the mntId of our procfs handle.
+ expectedMountId, err := getMountId(procRoot, "")
+ if err != nil {
+ return err
+ }
+ // Get the mntId of the target magic-link.
+ gotMountId, err := getMountId(dir, path)
+ if err != nil {
+ return err
+ }
+ // As long as the directory mount is alive, even with wrapping mount IDs,
+ // we would expect to see a different mount ID here. (Of course, if we're
+ // using unsafeHostProcRoot() then an attaker could change this after we
+ // did this check.)
+ if expectedMountId != gotMountId {
+ return fmt.Errorf("%w: symlink %s/%s has an overmount obscuring the real link (mount ids do not match %d != %d)", errUnsafeProcfs, dir.Name(), path, expectedMountId, gotMountId)
+ }
+ return nil
+}
+
+func doRawProcSelfFdReadlink(procRoot *os.File, fd int) (string, error) {
+ fdPath := fmt.Sprintf("fd/%d", fd)
+ procFdLink, closer, err := procThreadSelf(procRoot, fdPath)
+ if err != nil {
+ return "", fmt.Errorf("get safe /proc/thread-self/%s handle: %w", fdPath, err)
+ }
+ defer procFdLink.Close()
+ defer closer()
+
+ // Try to detect if there is a mount on top of the magic-link. Since we use the handle directly
+ // provide to the closure. If the closure uses the handle directly, this
+ // should be safe in general (a mount on top of the path afterwards would
+ // not affect the handle itself) and will definitely be safe if we are
+ // using privateProcRoot() (at least since Linux 5.12[1], when anonymous
+ // mount namespaces were completely isolated from external mounts including
+ // mount propagation events).
+ //
+ // [1]: Linux commit ee2e3f50629f ("mount: fix mounting of detached mounts
+ // onto targets that reside on shared mounts").
+ if err := checkSymlinkOvermount(procRoot, procFdLink, ""); err != nil {
+ return "", fmt.Errorf("check safety of /proc/thread-self/fd/%d magiclink: %w", fd, err)
+ }
+
+ // readlinkat implies AT_EMPTY_PATH since Linux 2.6.39. See Linux commit
+ // 65cfc6722361 ("readlinkat(), fchownat() and fstatat() with empty
+ // relative pathnames").
+ return readlinkatFile(procFdLink, "")
+}
+
+func rawProcSelfFdReadlink(fd int) (string, error) {
+ procRoot, err := getProcRoot()
+ if err != nil {
+ return "", err
+ }
+ return doRawProcSelfFdReadlink(procRoot, fd)
+}
+
+func procSelfFdReadlink(f *os.File) (string, error) {
+ return rawProcSelfFdReadlink(int(f.Fd()))
+}
+
+var (
+ errPossibleBreakout = errors.New("possible breakout detected")
+ errInvalidDirectory = errors.New("wandered into deleted directory")
+ errDeletedInode = errors.New("cannot verify path of deleted inode")
+)
+
+func isDeadInode(file *os.File) error {
+ // If the nlink of a file drops to 0, there is an attacker deleting
+ // directories during our walk, which could result in weird /proc values.
+ // It's better to error out in this case.
+ stat, err := fstat(file)
+ if err != nil {
+ return fmt.Errorf("check for dead inode: %w", err)
+ }
+ if stat.Nlink == 0 {
+ err := errDeletedInode
+ if stat.Mode&unix.S_IFMT == unix.S_IFDIR {
+ err = errInvalidDirectory
+ }
+ return fmt.Errorf("%w %q", err, file.Name())
+ }
+ return nil
+}
+
+func checkProcSelfFdPath(path string, file *os.File) error {
+ if err := isDeadInode(file); err != nil {
+ return err
+ }
+ actualPath, err := procSelfFdReadlink(file)
+ if err != nil {
+ return fmt.Errorf("get path of handle: %w", err)
+ }
+ if actualPath != path {
+ return fmt.Errorf("%w: handle path %q doesn't match expected path %q", errPossibleBreakout, actualPath, path)
+ }
+ return nil
+}
+
+// Test hooks used in the procfs tests to verify that the fallback logic works.
+// See testing_mocks_linux_test.go and procfs_linux_test.go for more details.
+var (
+ hookForcePrivateProcRootOpenTree = hookDummyFile
+ hookForcePrivateProcRootOpenTreeAtRecursive = hookDummyFile
+ hookForceGetProcRootUnsafe = hookDummy
+
+ hookForceProcSelfTask = hookDummy
+ hookForceProcSelf = hookDummy
+)
+
+func hookDummy() bool { return false }
+func hookDummyFile(_ *os.File) bool { return false }
diff --git a/vendor/github.com/cyphar/filepath-securejoin/vfs.go b/vendor/github.com/cyphar/filepath-securejoin/vfs.go
new file mode 100644
index 0000000000..36373f8c51
--- /dev/null
+++ b/vendor/github.com/cyphar/filepath-securejoin/vfs.go
@@ -0,0 +1,35 @@
+// Copyright (C) 2017-2024 SUSE LLC. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package securejoin
+
+import "os"
+
+// In future this should be moved into a separate package, because now there
+// are several projects (umoci and go-mtree) that are using this sort of
+// interface.
+
+// VFS is the minimal interface necessary to use [SecureJoinVFS]. A nil VFS is
+// equivalent to using the standard [os].* family of functions. This is mainly
+// used for the purposes of mock testing, but also can be used to otherwise use
+// [SecureJoinVFS] with VFS-like system.
+type VFS interface {
+ // Lstat returns an [os.FileInfo] describing the named file. If the
+ // file is a symbolic link, the returned [os.FileInfo] describes the
+ // symbolic link. Lstat makes no attempt to follow the link.
+ // The semantics are identical to [os.Lstat].
+ Lstat(name string) (os.FileInfo, error)
+
+ // Readlink returns the destination of the named symbolic link.
+ // The semantics are identical to [os.Readlink].
+ Readlink(name string) (string, error)
+}
+
+// osVFS is the "nil" VFS, in that it just passes everything through to the os
+// module.
+type osVFS struct{}
+
+func (o osVFS) Lstat(name string) (os.FileInfo, error) { return os.Lstat(name) }
+
+func (o osVFS) Readlink(name string) (string, error) { return os.Readlink(name) }
diff --git a/vendor/github.com/envoyproxy/protoc-gen-validate/validate/BUILD b/vendor/github.com/envoyproxy/protoc-gen-validate/validate/BUILD
index ef634dd812..368eb571d1 100644
--- a/vendor/github.com/envoyproxy/protoc-gen-validate/validate/BUILD
+++ b/vendor/github.com/envoyproxy/protoc-gen-validate/validate/BUILD
@@ -1,10 +1,10 @@
load("@com_google_protobuf//bazel:cc_proto_library.bzl", "cc_proto_library")
+load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library")
+load("@com_google_protobuf//bazel:py_proto_library.bzl", "py_proto_library")
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
load("@rules_cc//cc:defs.bzl", "cc_library")
load("@rules_java//java:defs.bzl", "java_proto_library")
-load("@rules_proto//proto:defs.bzl", "proto_library")
-load("@rules_python//python:proto.bzl", "py_proto_library")
package(
default_visibility =
diff --git a/vendor/github.com/evanphx/json-patch/.gitignore b/vendor/github.com/evanphx/json-patch/.gitignore
new file mode 100644
index 0000000000..b7ed7f956d
--- /dev/null
+++ b/vendor/github.com/evanphx/json-patch/.gitignore
@@ -0,0 +1,6 @@
+# editor and IDE paraphernalia
+.idea
+.vscode
+
+# macOS paraphernalia
+.DS_Store
diff --git a/vendor/github.com/evanphx/json-patch/LICENSE b/vendor/github.com/evanphx/json-patch/LICENSE
new file mode 100644
index 0000000000..df76d7d771
--- /dev/null
+++ b/vendor/github.com/evanphx/json-patch/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2014, Evan Phoenix
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+* Neither the name of the Evan Phoenix 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.
diff --git a/vendor/github.com/evanphx/json-patch/README.md b/vendor/github.com/evanphx/json-patch/README.md
new file mode 100644
index 0000000000..86fefd5bf7
--- /dev/null
+++ b/vendor/github.com/evanphx/json-patch/README.md
@@ -0,0 +1,315 @@
+# JSON-Patch
+`jsonpatch` is a library which provides functionality for both applying
+[RFC6902 JSON patches](http://tools.ietf.org/html/rfc6902) against documents, as
+well as for calculating & applying [RFC7396 JSON merge patches](https://tools.ietf.org/html/rfc7396).
+
+[](http://godoc.org/github.com/evanphx/json-patch)
+[](https://github.com/evanphx/json-patch/actions/workflows/go.yml)
+[](https://goreportcard.com/report/github.com/evanphx/json-patch)
+
+# Get It!
+
+**Latest and greatest**:
+```bash
+go get -u github.com/evanphx/json-patch/v5
+```
+
+If you need version 4, use `go get -u gopkg.in/evanphx/json-patch.v4`
+
+(previous versions below `v3` are unavailable)
+
+# Use It!
+* [Create and apply a merge patch](#create-and-apply-a-merge-patch)
+* [Create and apply a JSON Patch](#create-and-apply-a-json-patch)
+* [Comparing JSON documents](#comparing-json-documents)
+* [Combine merge patches](#combine-merge-patches)
+
+
+# Configuration
+
+* There is a global configuration variable `jsonpatch.SupportNegativeIndices`.
+ This defaults to `true` and enables the non-standard practice of allowing
+ negative indices to mean indices starting at the end of an array. This
+ functionality can be disabled by setting `jsonpatch.SupportNegativeIndices =
+ false`.
+
+* There is a global configuration variable `jsonpatch.AccumulatedCopySizeLimit`,
+ which limits the total size increase in bytes caused by "copy" operations in a
+ patch. It defaults to 0, which means there is no limit.
+
+These global variables control the behavior of `jsonpatch.Apply`.
+
+An alternative to `jsonpatch.Apply` is `jsonpatch.ApplyWithOptions` whose behavior
+is controlled by an `options` parameter of type `*jsonpatch.ApplyOptions`.
+
+Structure `jsonpatch.ApplyOptions` includes the configuration options above
+and adds two new options: `AllowMissingPathOnRemove` and `EnsurePathExistsOnAdd`.
+
+When `AllowMissingPathOnRemove` is set to `true`, `jsonpatch.ApplyWithOptions` will ignore
+`remove` operations whose `path` points to a non-existent location in the JSON document.
+`AllowMissingPathOnRemove` defaults to `false` which will lead to `jsonpatch.ApplyWithOptions`
+returning an error when hitting a missing `path` on `remove`.
+
+When `EnsurePathExistsOnAdd` is set to `true`, `jsonpatch.ApplyWithOptions` will make sure
+that `add` operations produce all the `path` elements that are missing from the target object.
+
+Use `jsonpatch.NewApplyOptions` to create an instance of `jsonpatch.ApplyOptions`
+whose values are populated from the global configuration variables.
+
+## Create and apply a merge patch
+Given both an original JSON document and a modified JSON document, you can create
+a [Merge Patch](https://tools.ietf.org/html/rfc7396) document.
+
+It can describe the changes needed to convert from the original to the
+modified JSON document.
+
+Once you have a merge patch, you can apply it to other JSON documents using the
+`jsonpatch.MergePatch(document, patch)` function.
+
+```go
+package main
+
+import (
+ "fmt"
+
+ jsonpatch "github.com/evanphx/json-patch"
+)
+
+func main() {
+ // Let's create a merge patch from these two documents...
+ original := []byte(`{"name": "John", "age": 24, "height": 3.21}`)
+ target := []byte(`{"name": "Jane", "age": 24}`)
+
+ patch, err := jsonpatch.CreateMergePatch(original, target)
+ if err != nil {
+ panic(err)
+ }
+
+ // Now lets apply the patch against a different JSON document...
+
+ alternative := []byte(`{"name": "Tina", "age": 28, "height": 3.75}`)
+ modifiedAlternative, err := jsonpatch.MergePatch(alternative, patch)
+
+ fmt.Printf("patch document: %s\n", patch)
+ fmt.Printf("updated alternative doc: %s\n", modifiedAlternative)
+}
+```
+
+When ran, you get the following output:
+
+```bash
+$ go run main.go
+patch document: {"height":null,"name":"Jane"}
+updated alternative doc: {"age":28,"name":"Jane"}
+```
+
+## Create and apply a JSON Patch
+You can create patch objects using `DecodePatch([]byte)`, which can then
+be applied against JSON documents.
+
+The following is an example of creating a patch from two operations, and
+applying it against a JSON document.
+
+```go
+package main
+
+import (
+ "fmt"
+
+ jsonpatch "github.com/evanphx/json-patch"
+)
+
+func main() {
+ original := []byte(`{"name": "John", "age": 24, "height": 3.21}`)
+ patchJSON := []byte(`[
+ {"op": "replace", "path": "/name", "value": "Jane"},
+ {"op": "remove", "path": "/height"}
+ ]`)
+
+ patch, err := jsonpatch.DecodePatch(patchJSON)
+ if err != nil {
+ panic(err)
+ }
+
+ modified, err := patch.Apply(original)
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Printf("Original document: %s\n", original)
+ fmt.Printf("Modified document: %s\n", modified)
+}
+```
+
+When ran, you get the following output:
+
+```bash
+$ go run main.go
+Original document: {"name": "John", "age": 24, "height": 3.21}
+Modified document: {"age":24,"name":"Jane"}
+```
+
+## Comparing JSON documents
+Due to potential whitespace and ordering differences, one cannot simply compare
+JSON strings or byte-arrays directly.
+
+As such, you can instead use `jsonpatch.Equal(document1, document2)` to
+determine if two JSON documents are _structurally_ equal. This ignores
+whitespace differences, and key-value ordering.
+
+```go
+package main
+
+import (
+ "fmt"
+
+ jsonpatch "github.com/evanphx/json-patch"
+)
+
+func main() {
+ original := []byte(`{"name": "John", "age": 24, "height": 3.21}`)
+ similar := []byte(`
+ {
+ "age": 24,
+ "height": 3.21,
+ "name": "John"
+ }
+ `)
+ different := []byte(`{"name": "Jane", "age": 20, "height": 3.37}`)
+
+ if jsonpatch.Equal(original, similar) {
+ fmt.Println(`"original" is structurally equal to "similar"`)
+ }
+
+ if !jsonpatch.Equal(original, different) {
+ fmt.Println(`"original" is _not_ structurally equal to "different"`)
+ }
+}
+```
+
+When ran, you get the following output:
+```bash
+$ go run main.go
+"original" is structurally equal to "similar"
+"original" is _not_ structurally equal to "different"
+```
+
+## Combine merge patches
+Given two JSON merge patch documents, it is possible to combine them into a
+single merge patch which can describe both set of changes.
+
+The resulting merge patch can be used such that applying it results in a
+document structurally similar as merging each merge patch to the document
+in succession.
+
+```go
+package main
+
+import (
+ "fmt"
+
+ jsonpatch "github.com/evanphx/json-patch"
+)
+
+func main() {
+ original := []byte(`{"name": "John", "age": 24, "height": 3.21}`)
+
+ nameAndHeight := []byte(`{"height":null,"name":"Jane"}`)
+ ageAndEyes := []byte(`{"age":4.23,"eyes":"blue"}`)
+
+ // Let's combine these merge patch documents...
+ combinedPatch, err := jsonpatch.MergeMergePatches(nameAndHeight, ageAndEyes)
+ if err != nil {
+ panic(err)
+ }
+
+ // Apply each patch individual against the original document
+ withoutCombinedPatch, err := jsonpatch.MergePatch(original, nameAndHeight)
+ if err != nil {
+ panic(err)
+ }
+
+ withoutCombinedPatch, err = jsonpatch.MergePatch(withoutCombinedPatch, ageAndEyes)
+ if err != nil {
+ panic(err)
+ }
+
+ // Apply the combined patch against the original document
+
+ withCombinedPatch, err := jsonpatch.MergePatch(original, combinedPatch)
+ if err != nil {
+ panic(err)
+ }
+
+ // Do both result in the same thing? They should!
+ if jsonpatch.Equal(withCombinedPatch, withoutCombinedPatch) {
+ fmt.Println("Both JSON documents are structurally the same!")
+ }
+
+ fmt.Printf("combined merge patch: %s", combinedPatch)
+}
+```
+
+When ran, you get the following output:
+```bash
+$ go run main.go
+Both JSON documents are structurally the same!
+combined merge patch: {"age":4.23,"eyes":"blue","height":null,"name":"Jane"}
+```
+
+# CLI for comparing JSON documents
+You can install the commandline program `json-patch`.
+
+This program can take multiple JSON patch documents as arguments,
+and fed a JSON document from `stdin`. It will apply the patch(es) against
+the document and output the modified doc.
+
+**patch.1.json**
+```json
+[
+ {"op": "replace", "path": "/name", "value": "Jane"},
+ {"op": "remove", "path": "/height"}
+]
+```
+
+**patch.2.json**
+```json
+[
+ {"op": "add", "path": "/address", "value": "123 Main St"},
+ {"op": "replace", "path": "/age", "value": "21"}
+]
+```
+
+**document.json**
+```json
+{
+ "name": "John",
+ "age": 24,
+ "height": 3.21
+}
+```
+
+You can then run:
+
+```bash
+$ go install github.com/evanphx/json-patch/cmd/json-patch
+$ cat document.json | json-patch -p patch.1.json -p patch.2.json
+{"address":"123 Main St","age":"21","name":"Jane"}
+```
+
+# Help It!
+Contributions are welcomed! Leave [an issue](https://github.com/evanphx/json-patch/issues)
+or [create a PR](https://github.com/evanphx/json-patch/compare).
+
+
+Before creating a pull request, we'd ask that you make sure tests are passing
+and that you have added new tests when applicable.
+
+Contributors can run tests using:
+
+```bash
+go test -cover ./...
+```
+
+Builds for pull requests are tested automatically
+using [GitHub Actions](https://github.com/evanphx/json-patch/actions/workflows/go.yml).
diff --git a/vendor/github.com/evanphx/json-patch/errors.go b/vendor/github.com/evanphx/json-patch/errors.go
new file mode 100644
index 0000000000..75304b4437
--- /dev/null
+++ b/vendor/github.com/evanphx/json-patch/errors.go
@@ -0,0 +1,38 @@
+package jsonpatch
+
+import "fmt"
+
+// AccumulatedCopySizeError is an error type returned when the accumulated size
+// increase caused by copy operations in a patch operation has exceeded the
+// limit.
+type AccumulatedCopySizeError struct {
+ limit int64
+ accumulated int64
+}
+
+// NewAccumulatedCopySizeError returns an AccumulatedCopySizeError.
+func NewAccumulatedCopySizeError(l, a int64) *AccumulatedCopySizeError {
+ return &AccumulatedCopySizeError{limit: l, accumulated: a}
+}
+
+// Error implements the error interface.
+func (a *AccumulatedCopySizeError) Error() string {
+ return fmt.Sprintf("Unable to complete the copy, the accumulated size increase of copy is %d, exceeding the limit %d", a.accumulated, a.limit)
+}
+
+// ArraySizeError is an error type returned when the array size has exceeded
+// the limit.
+type ArraySizeError struct {
+ limit int
+ size int
+}
+
+// NewArraySizeError returns an ArraySizeError.
+func NewArraySizeError(l, s int) *ArraySizeError {
+ return &ArraySizeError{limit: l, size: s}
+}
+
+// Error implements the error interface.
+func (a *ArraySizeError) Error() string {
+ return fmt.Sprintf("Unable to create array of size %d, limit is %d", a.size, a.limit)
+}
diff --git a/vendor/github.com/evanphx/json-patch/merge.go b/vendor/github.com/evanphx/json-patch/merge.go
new file mode 100644
index 0000000000..ad88d40181
--- /dev/null
+++ b/vendor/github.com/evanphx/json-patch/merge.go
@@ -0,0 +1,389 @@
+package jsonpatch
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "reflect"
+)
+
+func merge(cur, patch *lazyNode, mergeMerge bool) *lazyNode {
+ curDoc, err := cur.intoDoc()
+
+ if err != nil {
+ pruneNulls(patch)
+ return patch
+ }
+
+ patchDoc, err := patch.intoDoc()
+
+ if err != nil {
+ return patch
+ }
+
+ mergeDocs(curDoc, patchDoc, mergeMerge)
+
+ return cur
+}
+
+func mergeDocs(doc, patch *partialDoc, mergeMerge bool) {
+ for k, v := range *patch {
+ if v == nil {
+ if mergeMerge {
+ (*doc)[k] = nil
+ } else {
+ delete(*doc, k)
+ }
+ } else {
+ cur, ok := (*doc)[k]
+
+ if !ok || cur == nil {
+ if !mergeMerge {
+ pruneNulls(v)
+ }
+
+ (*doc)[k] = v
+ } else {
+ (*doc)[k] = merge(cur, v, mergeMerge)
+ }
+ }
+ }
+}
+
+func pruneNulls(n *lazyNode) {
+ sub, err := n.intoDoc()
+
+ if err == nil {
+ pruneDocNulls(sub)
+ } else {
+ ary, err := n.intoAry()
+
+ if err == nil {
+ pruneAryNulls(ary)
+ }
+ }
+}
+
+func pruneDocNulls(doc *partialDoc) *partialDoc {
+ for k, v := range *doc {
+ if v == nil {
+ delete(*doc, k)
+ } else {
+ pruneNulls(v)
+ }
+ }
+
+ return doc
+}
+
+func pruneAryNulls(ary *partialArray) *partialArray {
+ newAry := []*lazyNode{}
+
+ for _, v := range *ary {
+ if v != nil {
+ pruneNulls(v)
+ }
+ newAry = append(newAry, v)
+ }
+
+ *ary = newAry
+
+ return ary
+}
+
+var ErrBadJSONDoc = fmt.Errorf("Invalid JSON Document")
+var ErrBadJSONPatch = fmt.Errorf("Invalid JSON Patch")
+var errBadMergeTypes = fmt.Errorf("Mismatched JSON Documents")
+
+// MergeMergePatches merges two merge patches together, such that
+// applying this resulting merged merge patch to a document yields the same
+// as merging each merge patch to the document in succession.
+func MergeMergePatches(patch1Data, patch2Data []byte) ([]byte, error) {
+ return doMergePatch(patch1Data, patch2Data, true)
+}
+
+// MergePatch merges the patchData into the docData.
+func MergePatch(docData, patchData []byte) ([]byte, error) {
+ return doMergePatch(docData, patchData, false)
+}
+
+func doMergePatch(docData, patchData []byte, mergeMerge bool) ([]byte, error) {
+ doc := &partialDoc{}
+
+ docErr := json.Unmarshal(docData, doc)
+
+ patch := &partialDoc{}
+
+ patchErr := json.Unmarshal(patchData, patch)
+
+ if _, ok := docErr.(*json.SyntaxError); ok {
+ return nil, ErrBadJSONDoc
+ }
+
+ if _, ok := patchErr.(*json.SyntaxError); ok {
+ return nil, ErrBadJSONPatch
+ }
+
+ if docErr == nil && *doc == nil {
+ return nil, ErrBadJSONDoc
+ }
+
+ if patchErr == nil && *patch == nil {
+ return nil, ErrBadJSONPatch
+ }
+
+ if docErr != nil || patchErr != nil {
+ // Not an error, just not a doc, so we turn straight into the patch
+ if patchErr == nil {
+ if mergeMerge {
+ doc = patch
+ } else {
+ doc = pruneDocNulls(patch)
+ }
+ } else {
+ patchAry := &partialArray{}
+ patchErr = json.Unmarshal(patchData, patchAry)
+
+ if patchErr != nil {
+ return nil, ErrBadJSONPatch
+ }
+
+ pruneAryNulls(patchAry)
+
+ out, patchErr := json.Marshal(patchAry)
+
+ if patchErr != nil {
+ return nil, ErrBadJSONPatch
+ }
+
+ return out, nil
+ }
+ } else {
+ mergeDocs(doc, patch, mergeMerge)
+ }
+
+ return json.Marshal(doc)
+}
+
+// resemblesJSONArray indicates whether the byte-slice "appears" to be
+// a JSON array or not.
+// False-positives are possible, as this function does not check the internal
+// structure of the array. It only checks that the outer syntax is present and
+// correct.
+func resemblesJSONArray(input []byte) bool {
+ input = bytes.TrimSpace(input)
+
+ hasPrefix := bytes.HasPrefix(input, []byte("["))
+ hasSuffix := bytes.HasSuffix(input, []byte("]"))
+
+ return hasPrefix && hasSuffix
+}
+
+// CreateMergePatch will return a merge patch document capable of converting
+// the original document(s) to the modified document(s).
+// The parameters can be bytes of either two JSON Documents, or two arrays of
+// JSON documents.
+// The merge patch returned follows the specification defined at http://tools.ietf.org/html/draft-ietf-appsawg-json-merge-patch-07
+func CreateMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) {
+ originalResemblesArray := resemblesJSONArray(originalJSON)
+ modifiedResemblesArray := resemblesJSONArray(modifiedJSON)
+
+ // Do both byte-slices seem like JSON arrays?
+ if originalResemblesArray && modifiedResemblesArray {
+ return createArrayMergePatch(originalJSON, modifiedJSON)
+ }
+
+ // Are both byte-slices are not arrays? Then they are likely JSON objects...
+ if !originalResemblesArray && !modifiedResemblesArray {
+ return createObjectMergePatch(originalJSON, modifiedJSON)
+ }
+
+ // None of the above? Then return an error because of mismatched types.
+ return nil, errBadMergeTypes
+}
+
+// createObjectMergePatch will return a merge-patch document capable of
+// converting the original document to the modified document.
+func createObjectMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) {
+ originalDoc := map[string]interface{}{}
+ modifiedDoc := map[string]interface{}{}
+
+ err := json.Unmarshal(originalJSON, &originalDoc)
+ if err != nil {
+ return nil, ErrBadJSONDoc
+ }
+
+ err = json.Unmarshal(modifiedJSON, &modifiedDoc)
+ if err != nil {
+ return nil, ErrBadJSONDoc
+ }
+
+ dest, err := getDiff(originalDoc, modifiedDoc)
+ if err != nil {
+ return nil, err
+ }
+
+ return json.Marshal(dest)
+}
+
+// createArrayMergePatch will return an array of merge-patch documents capable
+// of converting the original document to the modified document for each
+// pair of JSON documents provided in the arrays.
+// Arrays of mismatched sizes will result in an error.
+func createArrayMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) {
+ originalDocs := []json.RawMessage{}
+ modifiedDocs := []json.RawMessage{}
+
+ err := json.Unmarshal(originalJSON, &originalDocs)
+ if err != nil {
+ return nil, ErrBadJSONDoc
+ }
+
+ err = json.Unmarshal(modifiedJSON, &modifiedDocs)
+ if err != nil {
+ return nil, ErrBadJSONDoc
+ }
+
+ total := len(originalDocs)
+ if len(modifiedDocs) != total {
+ return nil, ErrBadJSONDoc
+ }
+
+ result := []json.RawMessage{}
+ for i := 0; i < len(originalDocs); i++ {
+ original := originalDocs[i]
+ modified := modifiedDocs[i]
+
+ patch, err := createObjectMergePatch(original, modified)
+ if err != nil {
+ return nil, err
+ }
+
+ result = append(result, json.RawMessage(patch))
+ }
+
+ return json.Marshal(result)
+}
+
+// Returns true if the array matches (must be json types).
+// As is idiomatic for go, an empty array is not the same as a nil array.
+func matchesArray(a, b []interface{}) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ if (a == nil && b != nil) || (a != nil && b == nil) {
+ return false
+ }
+ for i := range a {
+ if !matchesValue(a[i], b[i]) {
+ return false
+ }
+ }
+ return true
+}
+
+// Returns true if the values matches (must be json types)
+// The types of the values must match, otherwise it will always return false
+// If two map[string]interface{} are given, all elements must match.
+func matchesValue(av, bv interface{}) bool {
+ if reflect.TypeOf(av) != reflect.TypeOf(bv) {
+ return false
+ }
+ switch at := av.(type) {
+ case string:
+ bt := bv.(string)
+ if bt == at {
+ return true
+ }
+ case float64:
+ bt := bv.(float64)
+ if bt == at {
+ return true
+ }
+ case bool:
+ bt := bv.(bool)
+ if bt == at {
+ return true
+ }
+ case nil:
+ // Both nil, fine.
+ return true
+ case map[string]interface{}:
+ bt := bv.(map[string]interface{})
+ if len(bt) != len(at) {
+ return false
+ }
+ for key := range bt {
+ av, aOK := at[key]
+ bv, bOK := bt[key]
+ if aOK != bOK {
+ return false
+ }
+ if !matchesValue(av, bv) {
+ return false
+ }
+ }
+ return true
+ case []interface{}:
+ bt := bv.([]interface{})
+ return matchesArray(at, bt)
+ }
+ return false
+}
+
+// getDiff returns the (recursive) difference between a and b as a map[string]interface{}.
+func getDiff(a, b map[string]interface{}) (map[string]interface{}, error) {
+ into := map[string]interface{}{}
+ for key, bv := range b {
+ av, ok := a[key]
+ // value was added
+ if !ok {
+ into[key] = bv
+ continue
+ }
+ // If types have changed, replace completely
+ if reflect.TypeOf(av) != reflect.TypeOf(bv) {
+ into[key] = bv
+ continue
+ }
+ // Types are the same, compare values
+ switch at := av.(type) {
+ case map[string]interface{}:
+ bt := bv.(map[string]interface{})
+ dst := make(map[string]interface{}, len(bt))
+ dst, err := getDiff(at, bt)
+ if err != nil {
+ return nil, err
+ }
+ if len(dst) > 0 {
+ into[key] = dst
+ }
+ case string, float64, bool:
+ if !matchesValue(av, bv) {
+ into[key] = bv
+ }
+ case []interface{}:
+ bt := bv.([]interface{})
+ if !matchesArray(at, bt) {
+ into[key] = bv
+ }
+ case nil:
+ switch bv.(type) {
+ case nil:
+ // Both nil, fine.
+ default:
+ into[key] = bv
+ }
+ default:
+ panic(fmt.Sprintf("Unknown type:%T in key %s", av, key))
+ }
+ }
+ // Now add all deleted values as nil
+ for key := range a {
+ _, found := b[key]
+ if !found {
+ into[key] = nil
+ }
+ }
+ return into, nil
+}
diff --git a/vendor/github.com/evanphx/json-patch/patch.go b/vendor/github.com/evanphx/json-patch/patch.go
new file mode 100644
index 0000000000..95136681ba
--- /dev/null
+++ b/vendor/github.com/evanphx/json-patch/patch.go
@@ -0,0 +1,850 @@
+package jsonpatch
+
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+const (
+ eRaw = iota
+ eDoc
+ eAry
+)
+
+var (
+ // SupportNegativeIndices decides whether to support non-standard practice of
+ // allowing negative indices to mean indices starting at the end of an array.
+ // Default to true.
+ SupportNegativeIndices bool = true
+ // AccumulatedCopySizeLimit limits the total size increase in bytes caused by
+ // "copy" operations in a patch.
+ AccumulatedCopySizeLimit int64 = 0
+)
+
+var (
+ ErrTestFailed = errors.New("test failed")
+ ErrMissing = errors.New("missing value")
+ ErrUnknownType = errors.New("unknown object type")
+ ErrInvalid = errors.New("invalid state detected")
+ ErrInvalidIndex = errors.New("invalid index referenced")
+)
+
+type lazyNode struct {
+ raw *json.RawMessage
+ doc partialDoc
+ ary partialArray
+ which int
+}
+
+// Operation is a single JSON-Patch step, such as a single 'add' operation.
+type Operation map[string]*json.RawMessage
+
+// Patch is an ordered collection of Operations.
+type Patch []Operation
+
+type partialDoc map[string]*lazyNode
+type partialArray []*lazyNode
+
+type container interface {
+ get(key string) (*lazyNode, error)
+ set(key string, val *lazyNode) error
+ add(key string, val *lazyNode) error
+ remove(key string) error
+}
+
+func newLazyNode(raw *json.RawMessage) *lazyNode {
+ return &lazyNode{raw: raw, doc: nil, ary: nil, which: eRaw}
+}
+
+func (n *lazyNode) MarshalJSON() ([]byte, error) {
+ switch n.which {
+ case eRaw:
+ return json.Marshal(n.raw)
+ case eDoc:
+ return json.Marshal(n.doc)
+ case eAry:
+ return json.Marshal(n.ary)
+ default:
+ return nil, ErrUnknownType
+ }
+}
+
+func (n *lazyNode) UnmarshalJSON(data []byte) error {
+ dest := make(json.RawMessage, len(data))
+ copy(dest, data)
+ n.raw = &dest
+ n.which = eRaw
+ return nil
+}
+
+func deepCopy(src *lazyNode) (*lazyNode, int, error) {
+ if src == nil {
+ return nil, 0, nil
+ }
+ a, err := src.MarshalJSON()
+ if err != nil {
+ return nil, 0, err
+ }
+ sz := len(a)
+ ra := make(json.RawMessage, sz)
+ copy(ra, a)
+ return newLazyNode(&ra), sz, nil
+}
+
+func (n *lazyNode) intoDoc() (*partialDoc, error) {
+ if n.which == eDoc {
+ return &n.doc, nil
+ }
+
+ if n.raw == nil {
+ return nil, ErrInvalid
+ }
+
+ err := json.Unmarshal(*n.raw, &n.doc)
+
+ if err != nil {
+ return nil, err
+ }
+
+ n.which = eDoc
+ return &n.doc, nil
+}
+
+func (n *lazyNode) intoAry() (*partialArray, error) {
+ if n.which == eAry {
+ return &n.ary, nil
+ }
+
+ if n.raw == nil {
+ return nil, ErrInvalid
+ }
+
+ err := json.Unmarshal(*n.raw, &n.ary)
+
+ if err != nil {
+ return nil, err
+ }
+
+ n.which = eAry
+ return &n.ary, nil
+}
+
+func (n *lazyNode) compact() []byte {
+ buf := &bytes.Buffer{}
+
+ if n.raw == nil {
+ return nil
+ }
+
+ err := json.Compact(buf, *n.raw)
+
+ if err != nil {
+ return *n.raw
+ }
+
+ return buf.Bytes()
+}
+
+func (n *lazyNode) tryDoc() bool {
+ if n.raw == nil {
+ return false
+ }
+
+ err := json.Unmarshal(*n.raw, &n.doc)
+
+ if err != nil {
+ return false
+ }
+
+ n.which = eDoc
+ return true
+}
+
+func (n *lazyNode) tryAry() bool {
+ if n.raw == nil {
+ return false
+ }
+
+ err := json.Unmarshal(*n.raw, &n.ary)
+
+ if err != nil {
+ return false
+ }
+
+ n.which = eAry
+ return true
+}
+
+func (n *lazyNode) equal(o *lazyNode) bool {
+ if n.which == eRaw {
+ if !n.tryDoc() && !n.tryAry() {
+ if o.which != eRaw {
+ return false
+ }
+
+ return bytes.Equal(n.compact(), o.compact())
+ }
+ }
+
+ if n.which == eDoc {
+ if o.which == eRaw {
+ if !o.tryDoc() {
+ return false
+ }
+ }
+
+ if o.which != eDoc {
+ return false
+ }
+
+ if len(n.doc) != len(o.doc) {
+ return false
+ }
+
+ for k, v := range n.doc {
+ ov, ok := o.doc[k]
+
+ if !ok {
+ return false
+ }
+
+ if (v == nil) != (ov == nil) {
+ return false
+ }
+
+ if v == nil && ov == nil {
+ continue
+ }
+
+ if !v.equal(ov) {
+ return false
+ }
+ }
+
+ return true
+ }
+
+ if o.which != eAry && !o.tryAry() {
+ return false
+ }
+
+ if len(n.ary) != len(o.ary) {
+ return false
+ }
+
+ for idx, val := range n.ary {
+ if !val.equal(o.ary[idx]) {
+ return false
+ }
+ }
+
+ return true
+}
+
+// Kind reads the "op" field of the Operation.
+func (o Operation) Kind() string {
+ if obj, ok := o["op"]; ok && obj != nil {
+ var op string
+
+ err := json.Unmarshal(*obj, &op)
+
+ if err != nil {
+ return "unknown"
+ }
+
+ return op
+ }
+
+ return "unknown"
+}
+
+// Path reads the "path" field of the Operation.
+func (o Operation) Path() (string, error) {
+ if obj, ok := o["path"]; ok && obj != nil {
+ var op string
+
+ err := json.Unmarshal(*obj, &op)
+
+ if err != nil {
+ return "unknown", err
+ }
+
+ return op, nil
+ }
+
+ return "unknown", fmt.Errorf("operation missing path field: %w", ErrMissing)
+}
+
+// From reads the "from" field of the Operation.
+func (o Operation) From() (string, error) {
+ if obj, ok := o["from"]; ok && obj != nil {
+ var op string
+
+ err := json.Unmarshal(*obj, &op)
+
+ if err != nil {
+ return "unknown", err
+ }
+
+ return op, nil
+ }
+
+ return "unknown", fmt.Errorf("operation, missing from field: %w", ErrMissing)
+}
+
+func (o Operation) value() *lazyNode {
+ if obj, ok := o["value"]; ok {
+ return newLazyNode(obj)
+ }
+
+ return nil
+}
+
+// ValueInterface decodes the operation value into an interface.
+func (o Operation) ValueInterface() (interface{}, error) {
+ if obj, ok := o["value"]; ok && obj != nil {
+ var v interface{}
+
+ err := json.Unmarshal(*obj, &v)
+
+ if err != nil {
+ return nil, err
+ }
+
+ return v, nil
+ }
+
+ return nil, fmt.Errorf("operation, missing value field: %w", ErrMissing)
+}
+
+func isArray(buf []byte) bool {
+Loop:
+ for _, c := range buf {
+ switch c {
+ case ' ':
+ case '\n':
+ case '\t':
+ continue
+ case '[':
+ return true
+ default:
+ break Loop
+ }
+ }
+
+ return false
+}
+
+func findObject(pd *container, path string) (container, string) {
+ doc := *pd
+
+ split := strings.Split(path, "/")
+
+ if len(split) < 2 {
+ return nil, ""
+ }
+
+ parts := split[1 : len(split)-1]
+
+ key := split[len(split)-1]
+
+ var err error
+
+ for _, part := range parts {
+
+ next, ok := doc.get(decodePatchKey(part))
+
+ if next == nil || ok != nil || next.raw == nil {
+ return nil, ""
+ }
+
+ if isArray(*next.raw) {
+ doc, err = next.intoAry()
+
+ if err != nil {
+ return nil, ""
+ }
+ } else {
+ doc, err = next.intoDoc()
+
+ if err != nil {
+ return nil, ""
+ }
+ }
+ }
+
+ return doc, decodePatchKey(key)
+}
+
+func (d *partialDoc) set(key string, val *lazyNode) error {
+ (*d)[key] = val
+ return nil
+}
+
+func (d *partialDoc) add(key string, val *lazyNode) error {
+ (*d)[key] = val
+ return nil
+}
+
+func (d *partialDoc) get(key string) (*lazyNode, error) {
+ return (*d)[key], nil
+}
+
+func (d *partialDoc) remove(key string) error {
+ _, ok := (*d)[key]
+ if !ok {
+ return fmt.Errorf("Unable to remove nonexistent key: %s: %w", key, ErrMissing)
+ }
+
+ delete(*d, key)
+ return nil
+}
+
+// set should only be used to implement the "replace" operation, so "key" must
+// be an already existing index in "d".
+func (d *partialArray) set(key string, val *lazyNode) error {
+ idx, err := strconv.Atoi(key)
+ if err != nil {
+ return err
+ }
+
+ if idx < 0 {
+ if !SupportNegativeIndices {
+ return fmt.Errorf("Unable to access invalid index: %d: %w", idx, ErrInvalidIndex)
+ }
+ if idx < -len(*d) {
+ return fmt.Errorf("Unable to access invalid index: %d: %w", idx, ErrInvalidIndex)
+ }
+ idx += len(*d)
+ }
+
+ (*d)[idx] = val
+ return nil
+}
+
+func (d *partialArray) add(key string, val *lazyNode) error {
+ if key == "-" {
+ *d = append(*d, val)
+ return nil
+ }
+
+ idx, err := strconv.Atoi(key)
+ if err != nil {
+ return fmt.Errorf("value was not a proper array index: '%s': %w", key, err)
+ }
+
+ sz := len(*d) + 1
+
+ ary := make([]*lazyNode, sz)
+
+ cur := *d
+
+ if idx >= len(ary) {
+ return fmt.Errorf("Unable to access invalid index: %d: %w", idx, ErrInvalidIndex)
+ }
+
+ if idx < 0 {
+ if !SupportNegativeIndices {
+ return fmt.Errorf("Unable to access invalid index: %d: %w", idx, ErrInvalidIndex)
+ }
+ if idx < -len(ary) {
+ return fmt.Errorf("Unable to access invalid index: %d: %w", idx, ErrInvalidIndex)
+ }
+ idx += len(ary)
+ }
+
+ copy(ary[0:idx], cur[0:idx])
+ ary[idx] = val
+ copy(ary[idx+1:], cur[idx:])
+
+ *d = ary
+ return nil
+}
+
+func (d *partialArray) get(key string) (*lazyNode, error) {
+ idx, err := strconv.Atoi(key)
+
+ if err != nil {
+ return nil, err
+ }
+
+ if idx < 0 {
+ if !SupportNegativeIndices {
+ return nil, fmt.Errorf("Unable to access invalid index: %d: %w", idx, ErrInvalidIndex)
+ }
+ if idx < -len(*d) {
+ return nil, fmt.Errorf("Unable to access invalid index: %d: %w", idx, ErrInvalidIndex)
+ }
+ idx += len(*d)
+ }
+
+ if idx >= len(*d) {
+ return nil, fmt.Errorf("Unable to access invalid index: %d: %w", idx, ErrInvalidIndex)
+ }
+
+ return (*d)[idx], nil
+}
+
+func (d *partialArray) remove(key string) error {
+ idx, err := strconv.Atoi(key)
+ if err != nil {
+ return err
+ }
+
+ cur := *d
+
+ if idx >= len(cur) {
+ return fmt.Errorf("Unable to access invalid index: %d: %w", idx, ErrInvalidIndex)
+ }
+
+ if idx < 0 {
+ if !SupportNegativeIndices {
+ return fmt.Errorf("Unable to access invalid index: %d: %w", idx, ErrInvalidIndex)
+ }
+ if idx < -len(cur) {
+ return fmt.Errorf("Unable to access invalid index: %d: %w", idx, ErrInvalidIndex)
+ }
+ idx += len(cur)
+ }
+
+ ary := make([]*lazyNode, len(cur)-1)
+
+ copy(ary[0:idx], cur[0:idx])
+ copy(ary[idx:], cur[idx+1:])
+
+ *d = ary
+ return nil
+
+}
+
+func (p Patch) add(doc *container, op Operation) error {
+ path, err := op.Path()
+ if err != nil {
+ return fmt.Errorf("add operation failed to decode path: %w", ErrMissing)
+ }
+
+ con, key := findObject(doc, path)
+
+ if con == nil {
+ return fmt.Errorf("add operation does not apply: doc is missing path: \"%s\": %w", path, ErrMissing)
+ }
+
+ err = con.add(key, op.value())
+ if err != nil {
+ return fmt.Errorf("error in add for path: '%s': %w", path, err)
+ }
+
+ return nil
+}
+
+func (p Patch) remove(doc *container, op Operation) error {
+ path, err := op.Path()
+ if err != nil {
+ return fmt.Errorf("remove operation failed to decode path: %w", ErrMissing)
+ }
+
+ con, key := findObject(doc, path)
+
+ if con == nil {
+ return fmt.Errorf("remove operation does not apply: doc is missing path: \"%s\": %w", path, ErrMissing)
+ }
+
+ err = con.remove(key)
+ if err != nil {
+ return fmt.Errorf("error in remove for path: '%s': %w", path, err)
+ }
+
+ return nil
+}
+
+func (p Patch) replace(doc *container, op Operation) error {
+ path, err := op.Path()
+ if err != nil {
+ return fmt.Errorf("replace operation failed to decode path: %w", err)
+ }
+
+ if path == "" {
+ val := op.value()
+
+ if val.which == eRaw {
+ if !val.tryDoc() {
+ if !val.tryAry() {
+ return fmt.Errorf("replace operation value must be object or array: %w", err)
+ }
+ }
+ }
+
+ switch val.which {
+ case eAry:
+ *doc = &val.ary
+ case eDoc:
+ *doc = &val.doc
+ case eRaw:
+ return fmt.Errorf("replace operation hit impossible case: %w", err)
+ }
+
+ return nil
+ }
+
+ con, key := findObject(doc, path)
+
+ if con == nil {
+ return fmt.Errorf("replace operation does not apply: doc is missing path: %s: %w", path, ErrMissing)
+ }
+
+ _, ok := con.get(key)
+ if ok != nil {
+ return fmt.Errorf("replace operation does not apply: doc is missing key: %s: %w", path, ErrMissing)
+ }
+
+ err = con.set(key, op.value())
+ if err != nil {
+ return fmt.Errorf("error in remove for path: '%s': %w", path, err)
+ }
+
+ return nil
+}
+
+func (p Patch) move(doc *container, op Operation) error {
+ from, err := op.From()
+ if err != nil {
+ return fmt.Errorf("move operation failed to decode from: %w", err)
+ }
+
+ con, key := findObject(doc, from)
+
+ if con == nil {
+ return fmt.Errorf("move operation does not apply: doc is missing from path: %s: %w", from, ErrMissing)
+ }
+
+ val, err := con.get(key)
+ if err != nil {
+ return fmt.Errorf("error in move for path: '%s': %w", key, err)
+ }
+
+ err = con.remove(key)
+ if err != nil {
+ return fmt.Errorf("error in move for path: '%s': %w", key, err)
+ }
+
+ path, err := op.Path()
+ if err != nil {
+ return fmt.Errorf("move operation failed to decode path: %w", err)
+ }
+
+ con, key = findObject(doc, path)
+
+ if con == nil {
+ return fmt.Errorf("move operation does not apply: doc is missing destination path: %s: %w", path, ErrMissing)
+ }
+
+ err = con.add(key, val)
+ if err != nil {
+ return fmt.Errorf("error in move for path: '%s': %w", path, err)
+ }
+
+ return nil
+}
+
+func (p Patch) test(doc *container, op Operation) error {
+ path, err := op.Path()
+ if err != nil {
+ return fmt.Errorf("test operation failed to decode path: %w", err)
+ }
+
+ if path == "" {
+ var self lazyNode
+
+ switch sv := (*doc).(type) {
+ case *partialDoc:
+ self.doc = *sv
+ self.which = eDoc
+ case *partialArray:
+ self.ary = *sv
+ self.which = eAry
+ }
+
+ if self.equal(op.value()) {
+ return nil
+ }
+
+ return fmt.Errorf("testing value %s failed: %w", path, ErrTestFailed)
+ }
+
+ con, key := findObject(doc, path)
+
+ if con == nil {
+ return fmt.Errorf("test operation does not apply: is missing path: %s: %w", path, ErrMissing)
+ }
+
+ val, err := con.get(key)
+ if err != nil {
+ return fmt.Errorf("error in test for path: '%s': %w", path, err)
+ }
+
+ if val == nil {
+ if op.value() == nil || op.value().raw == nil {
+ return nil
+ }
+ return fmt.Errorf("testing value %s failed: %w", path, ErrTestFailed)
+ } else if op.value() == nil {
+ return fmt.Errorf("testing value %s failed: %w", path, ErrTestFailed)
+ }
+
+ if val.equal(op.value()) {
+ return nil
+ }
+
+ return fmt.Errorf("testing value %s failed: %w", path, ErrTestFailed)
+}
+
+func (p Patch) copy(doc *container, op Operation, accumulatedCopySize *int64) error {
+ from, err := op.From()
+ if err != nil {
+ return fmt.Errorf("copy operation failed to decode from: %w", err)
+ }
+
+ con, key := findObject(doc, from)
+
+ if con == nil {
+ return fmt.Errorf("copy operation does not apply: doc is missing from path: %s: %w", from, ErrMissing)
+ }
+
+ val, err := con.get(key)
+ if err != nil {
+ return fmt.Errorf("error in copy for from: '%s': %w", from, err)
+ }
+
+ path, err := op.Path()
+ if err != nil {
+ return fmt.Errorf("copy operation failed to decode path: %w", ErrMissing)
+ }
+
+ con, key = findObject(doc, path)
+
+ if con == nil {
+ return fmt.Errorf("copy operation does not apply: doc is missing destination path: %s: %w", path, ErrMissing)
+ }
+
+ valCopy, sz, err := deepCopy(val)
+ if err != nil {
+ return fmt.Errorf("error while performing deep copy: %w", err)
+ }
+
+ (*accumulatedCopySize) += int64(sz)
+ if AccumulatedCopySizeLimit > 0 && *accumulatedCopySize > AccumulatedCopySizeLimit {
+ return NewAccumulatedCopySizeError(AccumulatedCopySizeLimit, *accumulatedCopySize)
+ }
+
+ err = con.add(key, valCopy)
+ if err != nil {
+ return fmt.Errorf("error while adding value during copy: %w", err)
+ }
+
+ return nil
+}
+
+// Equal indicates if 2 JSON documents have the same structural equality.
+func Equal(a, b []byte) bool {
+ ra := make(json.RawMessage, len(a))
+ copy(ra, a)
+ la := newLazyNode(&ra)
+
+ rb := make(json.RawMessage, len(b))
+ copy(rb, b)
+ lb := newLazyNode(&rb)
+
+ return la.equal(lb)
+}
+
+// DecodePatch decodes the passed JSON document as an RFC 6902 patch.
+func DecodePatch(buf []byte) (Patch, error) {
+ var p Patch
+
+ err := json.Unmarshal(buf, &p)
+
+ if err != nil {
+ return nil, err
+ }
+
+ return p, nil
+}
+
+// Apply mutates a JSON document according to the patch, and returns the new
+// document.
+func (p Patch) Apply(doc []byte) ([]byte, error) {
+ return p.ApplyIndent(doc, "")
+}
+
+// ApplyIndent mutates a JSON document according to the patch, and returns the new
+// document indented.
+func (p Patch) ApplyIndent(doc []byte, indent string) ([]byte, error) {
+ if len(doc) == 0 {
+ return doc, nil
+ }
+
+ var pd container
+ if doc[0] == '[' {
+ pd = &partialArray{}
+ } else {
+ pd = &partialDoc{}
+ }
+
+ err := json.Unmarshal(doc, pd)
+
+ if err != nil {
+ return nil, err
+ }
+
+ err = nil
+
+ var accumulatedCopySize int64
+
+ for _, op := range p {
+ switch op.Kind() {
+ case "add":
+ err = p.add(&pd, op)
+ case "remove":
+ err = p.remove(&pd, op)
+ case "replace":
+ err = p.replace(&pd, op)
+ case "move":
+ err = p.move(&pd, op)
+ case "test":
+ err = p.test(&pd, op)
+ case "copy":
+ err = p.copy(&pd, op, &accumulatedCopySize)
+ default:
+ err = fmt.Errorf("Unexpected kind: %s", op.Kind())
+ }
+
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if indent != "" {
+ return json.MarshalIndent(pd, "", indent)
+ }
+
+ return json.Marshal(pd)
+}
+
+// From http://tools.ietf.org/html/rfc6901#section-4 :
+//
+// Evaluation of each reference token begins by decoding any escaped
+// character sequence. This is performed by first transforming any
+// occurrence of the sequence '~1' to '/', and then transforming any
+// occurrence of the sequence '~0' to '~'.
+
+var (
+ rfc6901Decoder = strings.NewReplacer("~1", "/", "~0", "~")
+)
+
+func decodePatchKey(k string) string {
+ return rfc6901Decoder.Replace(k)
+}
diff --git a/vendor/github.com/exponent-io/jsonpath/.gitignore b/vendor/github.com/exponent-io/jsonpath/.gitignore
new file mode 100644
index 0000000000..daf913b1b3
--- /dev/null
+++ b/vendor/github.com/exponent-io/jsonpath/.gitignore
@@ -0,0 +1,24 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
diff --git a/vendor/github.com/exponent-io/jsonpath/.travis.yml b/vendor/github.com/exponent-io/jsonpath/.travis.yml
new file mode 100644
index 0000000000..53bb8b3f95
--- /dev/null
+++ b/vendor/github.com/exponent-io/jsonpath/.travis.yml
@@ -0,0 +1,7 @@
+language: go
+arch:
+ - amd64
+ - ppc64le
+go:
+ - 1.15
+ - tip
diff --git a/vendor/github.com/exponent-io/jsonpath/LICENSE b/vendor/github.com/exponent-io/jsonpath/LICENSE
new file mode 100644
index 0000000000..5419772507
--- /dev/null
+++ b/vendor/github.com/exponent-io/jsonpath/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Exponent Labs LLC
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/exponent-io/jsonpath/README.md b/vendor/github.com/exponent-io/jsonpath/README.md
new file mode 100644
index 0000000000..382fb3138c
--- /dev/null
+++ b/vendor/github.com/exponent-io/jsonpath/README.md
@@ -0,0 +1,66 @@
+[](https://godoc.org/github.com/exponent-io/jsonpath)
+[](https://travis-ci.org/exponent-io/jsonpath)
+
+# jsonpath
+
+This package extends the [json.Decoder](https://golang.org/pkg/encoding/json/#Decoder) to support navigating a stream of JSON tokens. You should be able to use this extended Decoder places where a json.Decoder would have been used.
+
+This Decoder has the following enhancements...
+ * The [Scan](https://godoc.org/github.com/exponent-io/jsonpath/#Decoder.Scan) method supports scanning a JSON stream while extracting particular values along the way using [PathActions](https://godoc.org/github.com/exponent-io/jsonpath#PathActions).
+ * The [SeekTo](https://godoc.org/github.com/exponent-io/jsonpath#Decoder.SeekTo) method supports seeking forward in a JSON token stream to a particular path.
+ * The [Path](https://godoc.org/github.com/exponent-io/jsonpath#Decoder.Path) method returns the path of the most recently parsed token.
+ * The [Token](https://godoc.org/github.com/exponent-io/jsonpath#Decoder.Token) method has been modified to distinguish between strings that are object keys and strings that are values. Object key strings are returned as the [KeyString](https://godoc.org/github.com/exponent-io/jsonpath#KeyString) type rather than a native string.
+
+## Installation
+
+ go get -u github.com/exponent-io/jsonpath
+
+## Example Usage
+
+#### SeekTo
+
+```go
+import "github.com/exponent-io/jsonpath"
+
+var j = []byte(`[
+ {"Space": "YCbCr", "Point": {"Y": 255, "Cb": 0, "Cr": -10}},
+ {"Space": "RGB", "Point": {"R": 98, "G": 218, "B": 255}}
+]`)
+
+w := json.NewDecoder(bytes.NewReader(j))
+var v interface{}
+
+w.SeekTo(1, "Point", "G")
+w.Decode(&v) // v is 218
+```
+
+#### Scan with PathActions
+
+```go
+var j = []byte(`{"colors":[
+ {"Space": "YCbCr", "Point": {"Y": 255, "Cb": 0, "Cr": -10, "A": 58}},
+ {"Space": "RGB", "Point": {"R": 98, "G": 218, "B": 255, "A": 231}}
+]}`)
+
+var actions PathActions
+
+// Extract the value at Point.A
+actions.Add(func(d *Decoder) error {
+ var alpha int
+ err := d.Decode(&alpha)
+ fmt.Printf("Alpha: %v\n", alpha)
+ return err
+}, "Point", "A")
+
+w := NewDecoder(bytes.NewReader(j))
+w.SeekTo("colors", 0)
+
+var ok = true
+var err error
+for ok {
+ ok, err = w.Scan(&actions)
+ if err != nil && err != io.EOF {
+ panic(err)
+ }
+}
+```
diff --git a/vendor/github.com/exponent-io/jsonpath/decoder.go b/vendor/github.com/exponent-io/jsonpath/decoder.go
new file mode 100644
index 0000000000..5e3a06548a
--- /dev/null
+++ b/vendor/github.com/exponent-io/jsonpath/decoder.go
@@ -0,0 +1,209 @@
+package jsonpath
+
+import (
+ "encoding/json"
+ "io"
+)
+
+// KeyString is returned from Decoder.Token to represent each key in a JSON object value.
+type KeyString string
+
+// Decoder extends the Go runtime's encoding/json.Decoder to support navigating in a stream of JSON tokens.
+type Decoder struct {
+ json.Decoder
+
+ path JsonPath
+ context jsonContext
+}
+
+// NewDecoder creates a new instance of the extended JSON Decoder.
+func NewDecoder(r io.Reader) *Decoder {
+ return &Decoder{Decoder: *json.NewDecoder(r)}
+}
+
+// SeekTo causes the Decoder to move forward to a given path in the JSON structure.
+//
+// The path argument must consist of strings or integers. Each string specifies an JSON object key, and
+// each integer specifies an index into a JSON array.
+//
+// Consider the JSON structure
+//
+// { "a": [0,"s",12e4,{"b":0,"v":35} ] }
+//
+// SeekTo("a",3,"v") will move to the value referenced by the "a" key in the current object,
+// followed by a move to the 4th value (index 3) in the array, followed by a move to the value at key "v".
+// In this example, a subsequent call to the decoder's Decode() would unmarshal the value 35.
+//
+// SeekTo returns a boolean value indicating whether a match was found.
+//
+// Decoder is intended to be used with a stream of tokens. As a result it navigates forward only.
+func (d *Decoder) SeekTo(path ...interface{}) (bool, error) {
+
+ if len(path) > 0 {
+ last := len(path) - 1
+ if i, ok := path[last].(int); ok {
+ path[last] = i - 1
+ }
+ }
+
+ for {
+ if len(path) == len(d.path) && d.path.Equal(path) {
+ return true, nil
+ }
+ _, err := d.Token()
+ if err == io.EOF {
+ return false, nil
+ } else if err != nil {
+ return false, err
+ }
+ }
+}
+
+// Decode reads the next JSON-encoded value from its input and stores it in the value pointed to by v. This is
+// equivalent to encoding/json.Decode().
+func (d *Decoder) Decode(v interface{}) error {
+ switch d.context {
+ case objValue:
+ d.context = objKey
+ break
+ case arrValue:
+ d.path.incTop()
+ break
+ }
+ return d.Decoder.Decode(v)
+}
+
+// Path returns a slice of string and/or int values representing the path from the root of the JSON object to the
+// position of the most-recently parsed token.
+func (d *Decoder) Path() JsonPath {
+ p := make(JsonPath, len(d.path))
+ copy(p, d.path)
+ return p
+}
+
+// Token is equivalent to the Token() method on json.Decoder. The primary difference is that it distinguishes
+// between strings that are keys and and strings that are values. String tokens that are object keys are returned as a
+// KeyString rather than as a native string.
+func (d *Decoder) Token() (json.Token, error) {
+ t, err := d.Decoder.Token()
+ if err != nil {
+ return t, err
+ }
+
+ if t == nil {
+ switch d.context {
+ case objValue:
+ d.context = objKey
+ break
+ case arrValue:
+ d.path.incTop()
+ break
+ }
+ return t, err
+ }
+
+ switch t := t.(type) {
+ case json.Delim:
+ switch t {
+ case json.Delim('{'):
+ if d.context == arrValue {
+ d.path.incTop()
+ }
+ d.path.push("")
+ d.context = objKey
+ break
+ case json.Delim('}'):
+ d.path.pop()
+ d.context = d.path.inferContext()
+ break
+ case json.Delim('['):
+ if d.context == arrValue {
+ d.path.incTop()
+ }
+ d.path.push(-1)
+ d.context = arrValue
+ break
+ case json.Delim(']'):
+ d.path.pop()
+ d.context = d.path.inferContext()
+ break
+ }
+ case float64, json.Number, bool:
+ switch d.context {
+ case objValue:
+ d.context = objKey
+ break
+ case arrValue:
+ d.path.incTop()
+ break
+ }
+ break
+ case string:
+ switch d.context {
+ case objKey:
+ d.path.nameTop(t)
+ d.context = objValue
+ return KeyString(t), err
+ case objValue:
+ d.context = objKey
+ case arrValue:
+ d.path.incTop()
+ }
+ break
+ }
+
+ return t, err
+}
+
+// Scan moves forward over the JSON stream consuming all the tokens at the current level (current object, current array)
+// invoking each matching PathAction along the way.
+//
+// Scan returns true if there are more contiguous values to scan (for example in an array).
+func (d *Decoder) Scan(ext *PathActions) (bool, error) {
+
+ rootPath := d.Path()
+
+ // If this is an array path, increment the root path in our local copy.
+ if rootPath.inferContext() == arrValue {
+ rootPath.incTop()
+ }
+
+ for {
+ // advance the token position
+ _, err := d.Token()
+ if err != nil {
+ return false, err
+ }
+
+ match:
+ var relPath JsonPath
+
+ // capture the new JSON path
+ path := d.Path()
+
+ if len(path) > len(rootPath) {
+ // capture the path relative to where the scan started
+ relPath = path[len(rootPath):]
+ } else {
+ // if the path is not longer than the root, then we are done with this scan
+ // return boolean flag indicating if there are more items to scan at the same level
+ return d.Decoder.More(), nil
+ }
+
+ // match the relative path against the path actions
+ if node := ext.node.match(relPath); node != nil {
+ if node.action != nil {
+ // we have a match so execute the action
+ err = node.action(d)
+ if err != nil {
+ return d.Decoder.More(), err
+ }
+ // The action may have advanced the decoder. If we are in an array, advancing it further would
+ // skip tokens. So, if we are scanning an array, jump to the top without advancing the token.
+ if d.path.inferContext() == arrValue && d.Decoder.More() {
+ goto match
+ }
+ }
+ }
+ }
+}
diff --git a/vendor/github.com/exponent-io/jsonpath/path.go b/vendor/github.com/exponent-io/jsonpath/path.go
new file mode 100644
index 0000000000..d7db2ad336
--- /dev/null
+++ b/vendor/github.com/exponent-io/jsonpath/path.go
@@ -0,0 +1,67 @@
+// Extends the Go runtime's json.Decoder enabling navigation of a stream of json tokens.
+package jsonpath
+
+import "fmt"
+
+type jsonContext int
+
+const (
+ none jsonContext = iota
+ objKey
+ objValue
+ arrValue
+)
+
+// AnyIndex can be used in a pattern to match any array index.
+const AnyIndex = -2
+
+// JsonPath is a slice of strings and/or integers. Each string specifies an JSON object key, and
+// each integer specifies an index into a JSON array.
+type JsonPath []interface{}
+
+func (p *JsonPath) push(n interface{}) { *p = append(*p, n) }
+func (p *JsonPath) pop() { *p = (*p)[:len(*p)-1] }
+
+// increment the index at the top of the stack (must be an array index)
+func (p *JsonPath) incTop() { (*p)[len(*p)-1] = (*p)[len(*p)-1].(int) + 1 }
+
+// name the key at the top of the stack (must be an object key)
+func (p *JsonPath) nameTop(n string) { (*p)[len(*p)-1] = n }
+
+// infer the context from the item at the top of the stack
+func (p *JsonPath) inferContext() jsonContext {
+ if len(*p) == 0 {
+ return none
+ }
+ t := (*p)[len(*p)-1]
+ switch t.(type) {
+ case string:
+ return objKey
+ case int:
+ return arrValue
+ default:
+ panic(fmt.Sprintf("Invalid stack type %T", t))
+ }
+}
+
+// Equal tests for equality between two JsonPath types.
+func (p *JsonPath) Equal(o JsonPath) bool {
+ if len(*p) != len(o) {
+ return false
+ }
+ for i, v := range *p {
+ if v != o[i] {
+ return false
+ }
+ }
+ return true
+}
+
+func (p *JsonPath) HasPrefix(o JsonPath) bool {
+ for i, v := range o {
+ if v != (*p)[i] {
+ return false
+ }
+ }
+ return true
+}
diff --git a/vendor/github.com/exponent-io/jsonpath/pathaction.go b/vendor/github.com/exponent-io/jsonpath/pathaction.go
new file mode 100644
index 0000000000..497ed686ca
--- /dev/null
+++ b/vendor/github.com/exponent-io/jsonpath/pathaction.go
@@ -0,0 +1,61 @@
+package jsonpath
+
+// pathNode is used to construct a trie of paths to be matched
+type pathNode struct {
+ matchOn interface{} // string, or integer
+ childNodes []pathNode
+ action DecodeAction
+}
+
+// match climbs the trie to find a node that matches the given JSON path.
+func (n *pathNode) match(path JsonPath) *pathNode {
+ var node *pathNode = n
+ for _, ps := range path {
+ found := false
+ for i, n := range node.childNodes {
+ if n.matchOn == ps {
+ node = &node.childNodes[i]
+ found = true
+ break
+ } else if _, ok := ps.(int); ok && n.matchOn == AnyIndex {
+ node = &node.childNodes[i]
+ found = true
+ break
+ }
+ }
+ if !found {
+ return nil
+ }
+ }
+ return node
+}
+
+// PathActions represents a collection of DecodeAction functions that should be called at certain path positions
+// when scanning the JSON stream. PathActions can be created once and used many times in one or more JSON streams.
+type PathActions struct {
+ node pathNode
+}
+
+// DecodeAction handlers are called by the Decoder when scanning objects. See PathActions.Add for more detail.
+type DecodeAction func(d *Decoder) error
+
+// Add specifies an action to call on the Decoder when the specified path is encountered.
+func (je *PathActions) Add(action DecodeAction, path ...interface{}) {
+
+ var node *pathNode = &je.node
+ for _, ps := range path {
+ found := false
+ for i, n := range node.childNodes {
+ if n.matchOn == ps {
+ node = &node.childNodes[i]
+ found = true
+ break
+ }
+ }
+ if !found {
+ node.childNodes = append(node.childNodes, pathNode{matchOn: ps})
+ node = &node.childNodes[len(node.childNodes)-1]
+ }
+ }
+ node.action = action
+}
diff --git a/vendor/github.com/go-errors/errors/.travis.yml b/vendor/github.com/go-errors/errors/.travis.yml
new file mode 100644
index 0000000000..1dc296026a
--- /dev/null
+++ b/vendor/github.com/go-errors/errors/.travis.yml
@@ -0,0 +1,7 @@
+language: go
+
+go:
+ - "1.8.x"
+ - "1.11.x"
+ - "1.16.x"
+ - "1.21.x"
diff --git a/vendor/github.com/go-errors/errors/LICENSE.MIT b/vendor/github.com/go-errors/errors/LICENSE.MIT
new file mode 100644
index 0000000000..c9a5b2eeb7
--- /dev/null
+++ b/vendor/github.com/go-errors/errors/LICENSE.MIT
@@ -0,0 +1,7 @@
+Copyright (c) 2015 Conrad Irwin
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/go-errors/errors/README.md b/vendor/github.com/go-errors/errors/README.md
new file mode 100644
index 0000000000..558bc883ef
--- /dev/null
+++ b/vendor/github.com/go-errors/errors/README.md
@@ -0,0 +1,84 @@
+go-errors/errors
+================
+
+[](https://travis-ci.org/go-errors/errors)
+
+Package errors adds stacktrace support to errors in go.
+
+This is particularly useful when you want to understand the state of execution
+when an error was returned unexpectedly.
+
+It provides the type \*Error which implements the standard golang error
+interface, so you can use this library interchangeably with code that is
+expecting a normal error return.
+
+Usage
+-----
+
+Full documentation is available on
+[godoc](https://godoc.org/github.com/go-errors/errors), but here's a simple
+example:
+
+```go
+package crashy
+
+import "github.com/go-errors/errors"
+
+var Crashed = errors.Errorf("oh dear")
+
+func Crash() error {
+ return errors.New(Crashed)
+}
+```
+
+This can be called as follows:
+
+```go
+package main
+
+import (
+ "crashy"
+ "fmt"
+ "github.com/go-errors/errors"
+)
+
+func main() {
+ err := crashy.Crash()
+ if err != nil {
+ if errors.Is(err, crashy.Crashed) {
+ fmt.Println(err.(*errors.Error).ErrorStack())
+ } else {
+ panic(err)
+ }
+ }
+}
+```
+
+Meta-fu
+-------
+
+This package was original written to allow reporting to
+[Bugsnag](https://bugsnag.com/) from
+[bugsnag-go](https://github.com/bugsnag/bugsnag-go), but after I found similar
+packages by Facebook and Dropbox, it was moved to one canonical location so
+everyone can benefit.
+
+This package is licensed under the MIT license, see LICENSE.MIT for details.
+
+
+## Changelog
+* v1.1.0 updated to use go1.13's standard-library errors.Is method instead of == in errors.Is
+* v1.2.0 added `errors.As` from the standard library.
+* v1.3.0 *BREAKING* updated error methods to return `error` instead of `*Error`.
+> Code that needs access to the underlying `*Error` can use the new errors.AsError(e)
+> ```
+> // before
+> errors.New(err).ErrorStack()
+> // after
+>. errors.AsError(errors.Wrap(err)).ErrorStack()
+> ```
+* v1.4.0 *BREAKING* v1.4.0 reverted all changes from v1.3.0 and is identical to v1.2.0
+* v1.4.1 no code change, but now without an unnecessary cover.out file.
+* v1.4.2 performance improvement to ErrorStack() to avoid unnecessary work https://github.com/go-errors/errors/pull/40
+* v1.5.0 add errors.Join() and errors.Unwrap() copying the stdlib https://github.com/go-errors/errors/pull/40
+* v1.5.1 fix build on go1.13..go1.19 (broken by adding Join and Unwrap with wrong build constraints)
diff --git a/vendor/github.com/go-errors/errors/error.go b/vendor/github.com/go-errors/errors/error.go
new file mode 100644
index 0000000000..ccbc2e4272
--- /dev/null
+++ b/vendor/github.com/go-errors/errors/error.go
@@ -0,0 +1,209 @@
+// Package errors provides errors that have stack-traces.
+//
+// This is particularly useful when you want to understand the
+// state of execution when an error was returned unexpectedly.
+//
+// It provides the type *Error which implements the standard
+// golang error interface, so you can use this library interchangably
+// with code that is expecting a normal error return.
+//
+// For example:
+//
+// package crashy
+//
+// import "github.com/go-errors/errors"
+//
+// var Crashed = errors.Errorf("oh dear")
+//
+// func Crash() error {
+// return errors.New(Crashed)
+// }
+//
+// This can be called as follows:
+//
+// package main
+//
+// import (
+// "crashy"
+// "fmt"
+// "github.com/go-errors/errors"
+// )
+//
+// func main() {
+// err := crashy.Crash()
+// if err != nil {
+// if errors.Is(err, crashy.Crashed) {
+// fmt.Println(err.(*errors.Error).ErrorStack())
+// } else {
+// panic(err)
+// }
+// }
+// }
+//
+// This package was original written to allow reporting to Bugsnag,
+// but after I found similar packages by Facebook and Dropbox, it
+// was moved to one canonical location so everyone can benefit.
+package errors
+
+import (
+ "bytes"
+ "fmt"
+ "reflect"
+ "runtime"
+)
+
+// The maximum number of stackframes on any error.
+var MaxStackDepth = 50
+
+// Error is an error with an attached stacktrace. It can be used
+// wherever the builtin error interface is expected.
+type Error struct {
+ Err error
+ stack []uintptr
+ frames []StackFrame
+ prefix string
+}
+
+// New makes an Error from the given value. If that value is already an
+// error then it will be used directly, if not, it will be passed to
+// fmt.Errorf("%v"). The stacktrace will point to the line of code that
+// called New.
+func New(e interface{}) *Error {
+ var err error
+
+ switch e := e.(type) {
+ case error:
+ err = e
+ default:
+ err = fmt.Errorf("%v", e)
+ }
+
+ stack := make([]uintptr, MaxStackDepth)
+ length := runtime.Callers(2, stack[:])
+ return &Error{
+ Err: err,
+ stack: stack[:length],
+ }
+}
+
+// Wrap makes an Error from the given value. If that value is already an
+// error then it will be used directly, if not, it will be passed to
+// fmt.Errorf("%v"). The skip parameter indicates how far up the stack
+// to start the stacktrace. 0 is from the current call, 1 from its caller, etc.
+func Wrap(e interface{}, skip int) *Error {
+ if e == nil {
+ return nil
+ }
+
+ var err error
+
+ switch e := e.(type) {
+ case *Error:
+ return e
+ case error:
+ err = e
+ default:
+ err = fmt.Errorf("%v", e)
+ }
+
+ stack := make([]uintptr, MaxStackDepth)
+ length := runtime.Callers(2+skip, stack[:])
+ return &Error{
+ Err: err,
+ stack: stack[:length],
+ }
+}
+
+// WrapPrefix makes an Error from the given value. If that value is already an
+// error then it will be used directly, if not, it will be passed to
+// fmt.Errorf("%v"). The prefix parameter is used to add a prefix to the
+// error message when calling Error(). The skip parameter indicates how far
+// up the stack to start the stacktrace. 0 is from the current call,
+// 1 from its caller, etc.
+func WrapPrefix(e interface{}, prefix string, skip int) *Error {
+ if e == nil {
+ return nil
+ }
+
+ err := Wrap(e, 1+skip)
+
+ if err.prefix != "" {
+ prefix = fmt.Sprintf("%s: %s", prefix, err.prefix)
+ }
+
+ return &Error{
+ Err: err.Err,
+ stack: err.stack,
+ prefix: prefix,
+ }
+
+}
+
+// Errorf creates a new error with the given message. You can use it
+// as a drop-in replacement for fmt.Errorf() to provide descriptive
+// errors in return values.
+func Errorf(format string, a ...interface{}) *Error {
+ return Wrap(fmt.Errorf(format, a...), 1)
+}
+
+// Error returns the underlying error's message.
+func (err *Error) Error() string {
+
+ msg := err.Err.Error()
+ if err.prefix != "" {
+ msg = fmt.Sprintf("%s: %s", err.prefix, msg)
+ }
+
+ return msg
+}
+
+// Stack returns the callstack formatted the same way that go does
+// in runtime/debug.Stack()
+func (err *Error) Stack() []byte {
+ buf := bytes.Buffer{}
+
+ for _, frame := range err.StackFrames() {
+ buf.WriteString(frame.String())
+ }
+
+ return buf.Bytes()
+}
+
+// Callers satisfies the bugsnag ErrorWithCallerS() interface
+// so that the stack can be read out.
+func (err *Error) Callers() []uintptr {
+ return err.stack
+}
+
+// ErrorStack returns a string that contains both the
+// error message and the callstack.
+func (err *Error) ErrorStack() string {
+ return err.TypeName() + " " + err.Error() + "\n" + string(err.Stack())
+}
+
+// StackFrames returns an array of frames containing information about the
+// stack.
+func (err *Error) StackFrames() []StackFrame {
+ if err.frames == nil {
+ err.frames = make([]StackFrame, len(err.stack))
+
+ for i, pc := range err.stack {
+ err.frames[i] = NewStackFrame(pc)
+ }
+ }
+
+ return err.frames
+}
+
+// TypeName returns the type this error. e.g. *errors.stringError.
+func (err *Error) TypeName() string {
+ if _, ok := err.Err.(uncaughtPanic); ok {
+ return "panic"
+ }
+ return reflect.TypeOf(err.Err).String()
+}
+
+// Return the wrapped error (implements api for As function).
+func (err *Error) Unwrap() error {
+ return err.Err
+}
diff --git a/vendor/github.com/go-errors/errors/error_1_13.go b/vendor/github.com/go-errors/errors/error_1_13.go
new file mode 100644
index 0000000000..34ab3e00eb
--- /dev/null
+++ b/vendor/github.com/go-errors/errors/error_1_13.go
@@ -0,0 +1,35 @@
+//go:build go1.13
+// +build go1.13
+
+package errors
+
+import (
+ baseErrors "errors"
+)
+
+// As finds the first error in err's tree that matches target, and if one is found, sets
+// target to that error value and returns true. Otherwise, it returns false.
+//
+// For more information see stdlib errors.As.
+func As(err error, target interface{}) bool {
+ return baseErrors.As(err, target)
+}
+
+// Is detects whether the error is equal to a given error. Errors
+// are considered equal by this function if they are matched by errors.Is
+// or if their contained errors are matched through errors.Is.
+func Is(e error, original error) bool {
+ if baseErrors.Is(e, original) {
+ return true
+ }
+
+ if e, ok := e.(*Error); ok {
+ return Is(e.Err, original)
+ }
+
+ if original, ok := original.(*Error); ok {
+ return Is(e, original.Err)
+ }
+
+ return false
+}
diff --git a/vendor/github.com/go-errors/errors/error_backward.go b/vendor/github.com/go-errors/errors/error_backward.go
new file mode 100644
index 0000000000..ff14c4bfa2
--- /dev/null
+++ b/vendor/github.com/go-errors/errors/error_backward.go
@@ -0,0 +1,125 @@
+//go:build !go1.13
+// +build !go1.13
+
+package errors
+
+import (
+ "reflect"
+)
+
+type unwrapper interface {
+ Unwrap() error
+}
+
+// As assigns error or any wrapped error to the value target points
+// to. If there is no value of the target type of target As returns
+// false.
+func As(err error, target interface{}) bool {
+ targetType := reflect.TypeOf(target)
+
+ for {
+ errType := reflect.TypeOf(err)
+
+ if errType == nil {
+ return false
+ }
+
+ if reflect.PtrTo(errType) == targetType {
+ reflect.ValueOf(target).Elem().Set(reflect.ValueOf(err))
+ return true
+ }
+
+ wrapped, ok := err.(unwrapper)
+ if ok {
+ err = wrapped.Unwrap()
+ } else {
+ return false
+ }
+ }
+}
+
+// Is detects whether the error is equal to a given error. Errors
+// are considered equal by this function if they are the same object,
+// or if they both contain the same error inside an errors.Error.
+func Is(e error, original error) bool {
+ if e == original {
+ return true
+ }
+
+ if e, ok := e.(*Error); ok {
+ return Is(e.Err, original)
+ }
+
+ if original, ok := original.(*Error); ok {
+ return Is(e, original.Err)
+ }
+
+ return false
+}
+
+// Disclaimer: functions Join and Unwrap are copied from the stdlib errors
+// package v1.21.0.
+
+// Join returns an error that wraps the given errors.
+// Any nil error values are discarded.
+// Join returns nil if every value in errs is nil.
+// The error formats as the concatenation of the strings obtained
+// by calling the Error method of each element of errs, with a newline
+// between each string.
+//
+// A non-nil error returned by Join implements the Unwrap() []error method.
+func Join(errs ...error) error {
+ n := 0
+ for _, err := range errs {
+ if err != nil {
+ n++
+ }
+ }
+ if n == 0 {
+ return nil
+ }
+ e := &joinError{
+ errs: make([]error, 0, n),
+ }
+ for _, err := range errs {
+ if err != nil {
+ e.errs = append(e.errs, err)
+ }
+ }
+ return e
+}
+
+type joinError struct {
+ errs []error
+}
+
+func (e *joinError) Error() string {
+ var b []byte
+ for i, err := range e.errs {
+ if i > 0 {
+ b = append(b, '\n')
+ }
+ b = append(b, err.Error()...)
+ }
+ return string(b)
+}
+
+func (e *joinError) Unwrap() []error {
+ return e.errs
+}
+
+// Unwrap returns the result of calling the Unwrap method on err, if err's
+// type contains an Unwrap method returning error.
+// Otherwise, Unwrap returns nil.
+//
+// Unwrap only calls a method of the form "Unwrap() error".
+// In particular Unwrap does not unwrap errors returned by [Join].
+func Unwrap(err error) error {
+ u, ok := err.(interface {
+ Unwrap() error
+ })
+ if !ok {
+ return nil
+ }
+ return u.Unwrap()
+}
diff --git a/vendor/github.com/go-errors/errors/join_unwrap_1_20.go b/vendor/github.com/go-errors/errors/join_unwrap_1_20.go
new file mode 100644
index 0000000000..44df35ece9
--- /dev/null
+++ b/vendor/github.com/go-errors/errors/join_unwrap_1_20.go
@@ -0,0 +1,32 @@
+//go:build go1.20
+// +build go1.20
+
+package errors
+
+import baseErrors "errors"
+
+// Join returns an error that wraps the given errors.
+// Any nil error values are discarded.
+// Join returns nil if every value in errs is nil.
+// The error formats as the concatenation of the strings obtained
+// by calling the Error method of each element of errs, with a newline
+// between each string.
+//
+// A non-nil error returned by Join implements the Unwrap() []error method.
+//
+// For more information see stdlib errors.Join.
+func Join(errs ...error) error {
+ return baseErrors.Join(errs...)
+}
+
+// Unwrap returns the result of calling the Unwrap method on err, if err's
+// type contains an Unwrap method returning error.
+// Otherwise, Unwrap returns nil.
+//
+// Unwrap only calls a method of the form "Unwrap() error".
+// In particular Unwrap does not unwrap errors returned by [Join].
+//
+// For more information see stdlib errors.Unwrap.
+func Unwrap(err error) error {
+ return baseErrors.Unwrap(err)
+}
diff --git a/vendor/github.com/go-errors/errors/join_unwrap_backward.go b/vendor/github.com/go-errors/errors/join_unwrap_backward.go
new file mode 100644
index 0000000000..50c766976c
--- /dev/null
+++ b/vendor/github.com/go-errors/errors/join_unwrap_backward.go
@@ -0,0 +1,71 @@
+//go:build !go1.20
+// +build !go1.20
+
+package errors
+
+// Disclaimer: functions Join and Unwrap are copied from the stdlib errors
+// package v1.21.0.
+
+// Join returns an error that wraps the given errors.
+// Any nil error values are discarded.
+// Join returns nil if every value in errs is nil.
+// The error formats as the concatenation of the strings obtained
+// by calling the Error method of each element of errs, with a newline
+// between each string.
+//
+// A non-nil error returned by Join implements the Unwrap() []error method.
+func Join(errs ...error) error {
+ n := 0
+ for _, err := range errs {
+ if err != nil {
+ n++
+ }
+ }
+ if n == 0 {
+ return nil
+ }
+ e := &joinError{
+ errs: make([]error, 0, n),
+ }
+ for _, err := range errs {
+ if err != nil {
+ e.errs = append(e.errs, err)
+ }
+ }
+ return e
+}
+
+type joinError struct {
+ errs []error
+}
+
+func (e *joinError) Error() string {
+ var b []byte
+ for i, err := range e.errs {
+ if i > 0 {
+ b = append(b, '\n')
+ }
+ b = append(b, err.Error()...)
+ }
+ return string(b)
+}
+
+func (e *joinError) Unwrap() []error {
+ return e.errs
+}
+
+// Unwrap returns the result of calling the Unwrap method on err, if err's
+// type contains an Unwrap method returning error.
+// Otherwise, Unwrap returns nil.
+//
+// Unwrap only calls a method of the form "Unwrap() error".
+// In particular Unwrap does not unwrap errors returned by [Join].
+func Unwrap(err error) error {
+ u, ok := err.(interface {
+ Unwrap() error
+ })
+ if !ok {
+ return nil
+ }
+ return u.Unwrap()
+}
diff --git a/vendor/github.com/go-errors/errors/parse_panic.go b/vendor/github.com/go-errors/errors/parse_panic.go
new file mode 100644
index 0000000000..cc37052d78
--- /dev/null
+++ b/vendor/github.com/go-errors/errors/parse_panic.go
@@ -0,0 +1,127 @@
+package errors
+
+import (
+ "strconv"
+ "strings"
+)
+
+type uncaughtPanic struct{ message string }
+
+func (p uncaughtPanic) Error() string {
+ return p.message
+}
+
+// ParsePanic allows you to get an error object from the output of a go program
+// that panicked. This is particularly useful with https://github.com/mitchellh/panicwrap.
+func ParsePanic(text string) (*Error, error) {
+ lines := strings.Split(text, "\n")
+
+ state := "start"
+
+ var message string
+ var stack []StackFrame
+
+ for i := 0; i < len(lines); i++ {
+ line := lines[i]
+
+ if state == "start" {
+ if strings.HasPrefix(line, "panic: ") {
+ message = strings.TrimPrefix(line, "panic: ")
+ state = "seek"
+ } else {
+ return nil, Errorf("bugsnag.panicParser: Invalid line (no prefix): %s", line)
+ }
+
+ } else if state == "seek" {
+ if strings.HasPrefix(line, "goroutine ") && strings.HasSuffix(line, "[running]:") {
+ state = "parsing"
+ }
+
+ } else if state == "parsing" {
+ if line == "" {
+ state = "done"
+ break
+ }
+ createdBy := false
+ if strings.HasPrefix(line, "created by ") {
+ line = strings.TrimPrefix(line, "created by ")
+ createdBy = true
+ }
+
+ i++
+
+ if i >= len(lines) {
+ return nil, Errorf("bugsnag.panicParser: Invalid line (unpaired): %s", line)
+ }
+
+ frame, err := parsePanicFrame(line, lines[i], createdBy)
+ if err != nil {
+ return nil, err
+ }
+
+ stack = append(stack, *frame)
+ if createdBy {
+ state = "done"
+ break
+ }
+ }
+ }
+
+ if state == "done" || state == "parsing" {
+ return &Error{Err: uncaughtPanic{message}, frames: stack}, nil
+ }
+ return nil, Errorf("could not parse panic: %v", text)
+}
+
+// The lines we're passing look like this:
+//
+// main.(*foo).destruct(0xc208067e98)
+// /0/go/src/github.com/bugsnag/bugsnag-go/pan/main.go:22 +0x151
+func parsePanicFrame(name string, line string, createdBy bool) (*StackFrame, error) {
+ idx := strings.LastIndex(name, "(")
+ if idx == -1 && !createdBy {
+ return nil, Errorf("bugsnag.panicParser: Invalid line (no call): %s", name)
+ }
+ if idx != -1 {
+ name = name[:idx]
+ }
+ pkg := ""
+
+ if lastslash := strings.LastIndex(name, "/"); lastslash >= 0 {
+ pkg += name[:lastslash] + "/"
+ name = name[lastslash+1:]
+ }
+ if period := strings.Index(name, "."); period >= 0 {
+ pkg += name[:period]
+ name = name[period+1:]
+ }
+
+ name = strings.Replace(name, "·", ".", -1)
+
+ if !strings.HasPrefix(line, "\t") {
+ return nil, Errorf("bugsnag.panicParser: Invalid line (no tab): %s", line)
+ }
+
+ idx = strings.LastIndex(line, ":")
+ if idx == -1 {
+ return nil, Errorf("bugsnag.panicParser: Invalid line (no line number): %s", line)
+ }
+ file := line[1:idx]
+
+ number := line[idx+1:]
+ if idx = strings.Index(number, " +"); idx > -1 {
+ number = number[:idx]
+ }
+
+ lno, err := strconv.ParseInt(number, 10, 32)
+ if err != nil {
+ return nil, Errorf("bugsnag.panicParser: Invalid line (bad line number): %s", line)
+ }
+
+ return &StackFrame{
+ File: file,
+ LineNumber: int(lno),
+ Package: pkg,
+ Name: name,
+ }, nil
+}
diff --git a/vendor/github.com/go-errors/errors/stackframe.go b/vendor/github.com/go-errors/errors/stackframe.go
new file mode 100644
index 0000000000..ef4a8b3f3b
--- /dev/null
+++ b/vendor/github.com/go-errors/errors/stackframe.go
@@ -0,0 +1,122 @@
+package errors
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "os"
+ "runtime"
+ "strings"
+)
+
+// A StackFrame contains all necessary information about to generate a line
+// in a callstack.
+type StackFrame struct {
+ // The path to the file containing this ProgramCounter
+ File string
+ // The LineNumber in that file
+ LineNumber int
+ // The Name of the function that contains this ProgramCounter
+ Name string
+ // The Package that contains this function
+ Package string
+ // The underlying ProgramCounter
+ ProgramCounter uintptr
+}
+
+// NewStackFrame popoulates a stack frame object from the program counter.
+func NewStackFrame(pc uintptr) (frame StackFrame) {
+
+ frame = StackFrame{ProgramCounter: pc}
+ if frame.Func() == nil {
+ return
+ }
+ frame.Package, frame.Name = packageAndName(frame.Func())
+
+ // pc -1 because the program counters we use are usually return addresses,
+ // and we want to show the line that corresponds to the function call
+ frame.File, frame.LineNumber = frame.Func().FileLine(pc - 1)
+ return
+
+}
+
+// Func returns the function that contained this frame.
+func (frame *StackFrame) Func() *runtime.Func {
+ if frame.ProgramCounter == 0 {
+ return nil
+ }
+ return runtime.FuncForPC(frame.ProgramCounter)
+}
+
+// String returns the stackframe formatted in the same way as go does
+// in runtime/debug.Stack()
+func (frame *StackFrame) String() string {
+ str := fmt.Sprintf("%s:%d (0x%x)\n", frame.File, frame.LineNumber, frame.ProgramCounter)
+
+ source, err := frame.sourceLine()
+ if err != nil {
+ return str
+ }
+
+ return str + fmt.Sprintf("\t%s: %s\n", frame.Name, source)
+}
+
+// SourceLine gets the line of code (from File and Line) of the original source if possible.
+func (frame *StackFrame) SourceLine() (string, error) {
+ source, err := frame.sourceLine()
+ if err != nil {
+ return source, New(err)
+ }
+ return source, err
+}
+
+func (frame *StackFrame) sourceLine() (string, error) {
+ if frame.LineNumber <= 0 {
+ return "???", nil
+ }
+
+ file, err := os.Open(frame.File)
+ if err != nil {
+ return "", err
+ }
+ defer file.Close()
+
+ scanner := bufio.NewScanner(file)
+ currentLine := 1
+ for scanner.Scan() {
+ if currentLine == frame.LineNumber {
+ return string(bytes.Trim(scanner.Bytes(), " \t")), nil
+ }
+ currentLine++
+ }
+ if err := scanner.Err(); err != nil {
+ return "", err
+ }
+
+ return "???", nil
+}
+
+func packageAndName(fn *runtime.Func) (string, string) {
+ name := fn.Name()
+ pkg := ""
+
+ // The name includes the path name to the package, which is unnecessary
+ // since the file name is already included. Plus, it has center dots.
+ // That is, we see
+ // runtime/debug.*T·ptrmethod
+ // and want
+ // *T.ptrmethod
+ // Since the package path might contains dots (e.g. code.google.com/...),
+ // we first remove the path prefix if there is one.
+ if lastslash := strings.LastIndex(name, "/"); lastslash >= 0 {
+ pkg += name[:lastslash] + "/"
+ name = name[lastslash+1:]
+ }
+ if period := strings.Index(name, "."); period >= 0 {
+ pkg += name[:period]
+ name = name[period+1:]
+ }
+
+ name = strings.Replace(name, "·", ".", -1)
+ return pkg, name
+}
diff --git a/vendor/github.com/go-gorp/gorp/v3/.gitignore b/vendor/github.com/go-gorp/gorp/v3/.gitignore
new file mode 100644
index 0000000000..a96e5fec57
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/.gitignore
@@ -0,0 +1,11 @@
+_test
+*.test
+_testmain.go
+_obj
+*~
+*.6
+6.out
+gorptest.bin
+tmp
+.idea
+coverage.out
diff --git a/vendor/github.com/go-gorp/gorp/v3/.travis.yml b/vendor/github.com/go-gorp/gorp/v3/.travis.yml
new file mode 100644
index 0000000000..958d260ace
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/.travis.yml
@@ -0,0 +1,36 @@
+language: go
+go:
+- "1.15.x"
+- "1.16.x"
+- tip
+
+matrix:
+ allow_failures:
+ - go: tip
+
+services:
+- mysql
+- postgresql
+- sqlite3
+
+env:
+ global:
+ - secure: RriLxF6+2yMl67hdVv8ImXlu0h62mhcpqjaOgYNU+IEbUQ7hx96CKY6gkpYubW3BgApvF5RH6j3+HKvh2kGp0XhDOYOQCODfBSaSipZ5Aa5RKjsEYLtuVIobvJ80awR9hUeql69+WXs0/s72WThG0qTbOUY4pqHWfteeY235hWM=
+
+install:
+ - go get -t -d
+ - go get -t -d -tags integration
+
+before_script:
+- mysql -e "CREATE DATABASE gorptest;"
+- mysql -u root -e "GRANT ALL ON gorptest.* TO gorptest@localhost IDENTIFIED BY 'gorptest'"
+- psql -c "CREATE DATABASE gorptest;" -U postgres
+- psql -c "CREATE USER "gorptest" WITH SUPERUSER PASSWORD 'gorptest';" -U postgres
+- go get github.com/lib/pq
+- go get github.com/mattn/go-sqlite3
+- go get github.com/ziutek/mymysql/godrv
+- go get github.com/go-sql-driver/mysql
+- go get golang.org/x/tools/cmd/cover
+- go get github.com/mattn/goveralls
+
+script: ./test_all.sh
diff --git a/vendor/github.com/go-gorp/gorp/v3/CONTRIBUTING.md b/vendor/github.com/go-gorp/gorp/v3/CONTRIBUTING.md
new file mode 100644
index 0000000000..7bc145fd7c
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/CONTRIBUTING.md
@@ -0,0 +1,34 @@
+# Contributions are very welcome!
+
+## First: Create an Issue
+
+Even if your fix is simple, we'd like to have an issue to relate to
+the PR. Discussion about the architecture and value can go on the
+issue, leaving PR comments exclusively for coding style.
+
+## Second: Make Your PR
+
+- Fork the `master` branch
+- Make your change
+- Make a PR against the `master` branch
+
+You don't need to wait for comments on the issue before making your
+PR. If you do wait for comments, you'll have a better chance of
+getting your PR accepted the first time around, but it's not
+necessary.
+
+## Third: Be Patient
+
+- If your change breaks backward compatibility, this becomes
+ especially true.
+
+We all have lives and jobs, and many of us are no longer on projects
+that make use of `gorp`. We will get back to you, but it might take a
+while.
+
+## Fourth: Consider Becoming a Maintainer
+
+We really do need help. We will likely ask you for help after a good
+PR, but if we don't, please create an issue requesting maintainership.
+Considering how few of us are currently active, we are unlikely to
+refuse good help.
diff --git a/vendor/github.com/go-gorp/gorp/v3/LICENSE b/vendor/github.com/go-gorp/gorp/v3/LICENSE
new file mode 100644
index 0000000000..b661111d0a
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/LICENSE
@@ -0,0 +1,22 @@
+(The MIT License)
+
+Copyright (c) 2012 James Cooper
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/go-gorp/gorp/v3/README.md b/vendor/github.com/go-gorp/gorp/v3/README.md
new file mode 100644
index 0000000000..983fe4343b
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/README.md
@@ -0,0 +1,809 @@
+# Go Relational Persistence
+
+[](https://github.com/go-gorp/gorp/actions)
+[](https://github.com/go-gorp/gorp/issues)
+[](https://pkg.go.dev/github.com/go-gorp/gorp/v3)
+
+### Update 2016-11-13: Future versions
+
+As many of the maintainers have become busy with other projects,
+progress toward the ever-elusive v2 has slowed to the point that we're
+only occasionally making progress outside of merging pull requests.
+In the interest of continuing to release, I'd like to lean toward a
+more maintainable path forward.
+
+For the moment, I am releasing a v2 tag with the current feature set
+from master, as some of those features have been actively used and
+relied on by more than one project. Our next goal is to continue
+cleaning up the code base with non-breaking changes as much as
+possible, but if/when a breaking change is needed, we'll just release
+new versions. This allows us to continue development at whatever pace
+we're capable of, without delaying the release of features or refusing
+PRs.
+
+## Introduction
+
+I hesitate to call gorp an ORM. Go doesn't really have objects, at
+least not in the classic Smalltalk/Java sense. There goes the "O".
+gorp doesn't know anything about the relationships between your
+structs (at least not yet). So the "R" is questionable too (but I use
+it in the name because, well, it seemed more clever).
+
+The "M" is alive and well. Given some Go structs and a database, gorp
+should remove a fair amount of boilerplate busy-work from your code.
+
+I hope that gorp saves you time, minimizes the drudgery of getting
+data in and out of your database, and helps your code focus on
+algorithms, not infrastructure.
+
+* Bind struct fields to table columns via API or tag
+* Support for embedded structs
+* Support for transactions
+* Forward engineer db schema from structs (great for unit tests)
+* Pre/post insert/update/delete hooks
+* Automatically generate insert/update/delete statements for a struct
+* Automatic binding of auto increment PKs back to struct after insert
+* Delete by primary key(s)
+* Select by primary key(s)
+* Optional trace sql logging
+* Bind arbitrary SQL queries to a struct
+* Bind slice to SELECT query results without type assertions
+* Use positional or named bind parameters in custom SELECT queries
+* Optional optimistic locking using a version column (for
+ update/deletes)
+
+## Installation
+
+Use `go get` or your favorite vendoring tool, using whichever import
+path you'd like.
+
+## Versioning
+
+We use semantic version tags. Feel free to import through `gopkg.in`
+(e.g. `gopkg.in/gorp.v2`) to get the latest tag for a major version,
+or check out the tag using your favorite vendoring tool.
+
+Development is not very active right now, but we have plans to
+restructure `gorp` as we continue to move toward a more extensible
+system. Whenever a breaking change is needed, the major version will
+be bumped.
+
+The `master` branch is where all development is done, and breaking
+changes may happen from time to time. That said, if you want to live
+on the bleeding edge and are comfortable updating your code when we
+make a breaking change, you may use `github.com/go-gorp/gorp` as your
+import path.
+
+Check the version tags to see what's available. We'll make a good
+faith effort to add badges for new versions, but we make no
+guarantees.
+
+## Supported Go versions
+
+This package is guaranteed to be compatible with the latest 2 major
+versions of Go.
+
+Any earlier versions are only supported on a best effort basis and can
+be dropped any time. Go has a great compatibility promise. Upgrading
+your program to a newer version of Go should never really be a
+problem.
+
+## Migration guide
+
+#### Pre-v2 to v2
+Automatic mapping of the version column used in optimistic locking has
+been removed as it could cause problems if the type was not int. The
+version column must now explicitly be set with
+`tablemap.SetVersionCol()`.
+
+## Help/Support
+
+Use our [`gitter` channel](https://gitter.im/go-gorp/gorp). We used
+to use IRC, but with most of us being pulled in many directions, we
+often need the email notifications from `gitter` to yell at us to sign
+in.
+
+## Quickstart
+
+```go
+package main
+
+import (
+ "database/sql"
+ "gopkg.in/gorp.v1"
+ _ "github.com/mattn/go-sqlite3"
+ "log"
+ "time"
+)
+
+func main() {
+ // initialize the DbMap
+ dbmap := initDb()
+ defer dbmap.Db.Close()
+
+ // delete any existing rows
+ err := dbmap.TruncateTables()
+ checkErr(err, "TruncateTables failed")
+
+ // create two posts
+ p1 := newPost("Go 1.1 released!", "Lorem ipsum lorem ipsum")
+ p2 := newPost("Go 1.2 released!", "Lorem ipsum lorem ipsum")
+
+ // insert rows - auto increment PKs will be set properly after the insert
+ err = dbmap.Insert(&p1, &p2)
+ checkErr(err, "Insert failed")
+
+ // use convenience SelectInt
+ count, err := dbmap.SelectInt("select count(*) from posts")
+ checkErr(err, "select count(*) failed")
+ log.Println("Rows after inserting:", count)
+
+ // update a row
+ p2.Title = "Go 1.2 is better than ever"
+ count, err = dbmap.Update(&p2)
+ checkErr(err, "Update failed")
+ log.Println("Rows updated:", count)
+
+ // fetch one row - note use of "post_id" instead of "Id" since column is aliased
+ //
+ // Postgres users should use $1 instead of ? placeholders
+ // See 'Known Issues' below
+ //
+ err = dbmap.SelectOne(&p2, "select * from posts where post_id=?", p2.Id)
+ checkErr(err, "SelectOne failed")
+ log.Println("p2 row:", p2)
+
+ // fetch all rows
+ var posts []Post
+ _, err = dbmap.Select(&posts, "select * from posts order by post_id")
+ checkErr(err, "Select failed")
+ log.Println("All rows:")
+ for x, p := range posts {
+ log.Printf(" %d: %v\n", x, p)
+ }
+
+ // delete row by PK
+ count, err = dbmap.Delete(&p1)
+ checkErr(err, "Delete failed")
+ log.Println("Rows deleted:", count)
+
+ // delete row manually via Exec
+ _, err = dbmap.Exec("delete from posts where post_id=?", p2.Id)
+ checkErr(err, "Exec failed")
+
+ // confirm count is zero
+ count, err = dbmap.SelectInt("select count(*) from posts")
+ checkErr(err, "select count(*) failed")
+ log.Println("Row count - should be zero:", count)
+
+ log.Println("Done!")
+}
+
+type Post struct {
+ // db tag lets you specify the column name if it differs from the struct field
+ Id int64 `db:"post_id"`
+ Created int64
+ Title string `db:",size:50"` // Column size set to 50
+ Body string `db:"article_body,size:1024"` // Set both column name and size
+}
+
+func newPost(title, body string) Post {
+ return Post{
+ Created: time.Now().UnixNano(),
+ Title: title,
+ Body: body,
+ }
+}
+
+func initDb() *gorp.DbMap {
+ // connect to db using standard Go database/sql API
+ // use whatever database/sql driver you wish
+ db, err := sql.Open("sqlite3", "/tmp/post_db.bin")
+ checkErr(err, "sql.Open failed")
+
+ // construct a gorp DbMap
+ dbmap := &gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}
+
+ // add a table, setting the table name to 'posts' and
+ // specifying that the Id property is an auto incrementing PK
+ dbmap.AddTableWithName(Post{}, "posts").SetKeys(true, "Id")
+
+ // create the table. in a production system you'd generally
+ // use a migration tool, or create the tables via scripts
+ err = dbmap.CreateTablesIfNotExists()
+ checkErr(err, "Create tables failed")
+
+ return dbmap
+}
+
+func checkErr(err error, msg string) {
+ if err != nil {
+ log.Fatalln(msg, err)
+ }
+}
+```
+
+## Examples
+
+### Mapping structs to tables
+
+First define some types:
+
+```go
+type Invoice struct {
+ Id int64
+ Created int64
+ Updated int64
+ Memo string
+ PersonId int64
+}
+
+type Person struct {
+ Id int64
+ Created int64
+ Updated int64
+ FName string
+ LName string
+}
+
+// Example of using tags to alias fields to column names
+// The 'db' value is the column name
+//
+// A hyphen will cause gorp to skip this field, similar to the
+// Go json package.
+//
+// This is equivalent to using the ColMap methods:
+//
+// table := dbmap.AddTableWithName(Product{}, "product")
+// table.ColMap("Id").Rename("product_id")
+// table.ColMap("Price").Rename("unit_price")
+// table.ColMap("IgnoreMe").SetTransient(true)
+//
+// You can optionally declare the field to be a primary key and/or autoincrement
+//
+type Product struct {
+ Id int64 `db:"product_id, primarykey, autoincrement"`
+ Price int64 `db:"unit_price"`
+ IgnoreMe string `db:"-"`
+}
+```
+
+Then create a mapper, typically you'd do this one time at app startup:
+
+```go
+// connect to db using standard Go database/sql API
+// use whatever database/sql driver you wish
+db, err := sql.Open("mymysql", "tcp:localhost:3306*mydb/myuser/mypassword")
+
+// construct a gorp DbMap
+dbmap := &gorp.DbMap{Db: db, Dialect: gorp.MySQLDialect{"InnoDB", "UTF8"}}
+
+// register the structs you wish to use with gorp
+// you can also use the shorter dbmap.AddTable() if you
+// don't want to override the table name
+//
+// SetKeys(true) means we have a auto increment primary key, which
+// will get automatically bound to your struct post-insert
+//
+t1 := dbmap.AddTableWithName(Invoice{}, "invoice_test").SetKeys(true, "Id")
+t2 := dbmap.AddTableWithName(Person{}, "person_test").SetKeys(true, "Id")
+t3 := dbmap.AddTableWithName(Product{}, "product_test").SetKeys(true, "Id")
+```
+
+### Struct Embedding
+
+gorp supports embedding structs. For example:
+
+```go
+type Names struct {
+ FirstName string
+ LastName string
+}
+
+type WithEmbeddedStruct struct {
+ Id int64
+ Names
+}
+
+es := &WithEmbeddedStruct{-1, Names{FirstName: "Alice", LastName: "Smith"}}
+err := dbmap.Insert(es)
+```
+
+See the `TestWithEmbeddedStruct` function in `gorp_test.go` for a full example.
+
+### Create/Drop Tables ###
+
+Automatically create / drop registered tables. This is useful for unit tests
+but is entirely optional. You can of course use gorp with tables created manually,
+or with a separate migration tool (like [sql-migrate](https://github.com/rubenv/sql-migrate), [goose](https://bitbucket.org/liamstask/goose) or [migrate](https://github.com/mattes/migrate)).
+
+```go
+// create all registered tables
+dbmap.CreateTables()
+
+// same as above, but uses "if not exists" clause to skip tables that are
+// already defined
+dbmap.CreateTablesIfNotExists()
+
+// drop
+dbmap.DropTables()
+```
+
+### SQL Logging
+
+Optionally you can pass in a logger to trace all SQL statements.
+I recommend enabling this initially while you're getting the feel for what
+gorp is doing on your behalf.
+
+Gorp defines a `GorpLogger` interface that Go's built in `log.Logger` satisfies.
+However, you can write your own `GorpLogger` implementation, or use a package such
+as `glog` if you want more control over how statements are logged.
+
+```go
+// Will log all SQL statements + args as they are run
+// The first arg is a string prefix to prepend to all log messages
+dbmap.TraceOn("[gorp]", log.New(os.Stdout, "myapp:", log.Lmicroseconds))
+
+// Turn off tracing
+dbmap.TraceOff()
+```
+
+### Insert
+
+```go
+// Must declare as pointers so optional callback hooks
+// can operate on your data, not copies
+inv1 := &Invoice{0, 100, 200, "first order", 0}
+inv2 := &Invoice{0, 100, 200, "second order", 0}
+
+// Insert your rows
+err := dbmap.Insert(inv1, inv2)
+
+// Because we called SetKeys(true) on Invoice, the Id field
+// will be populated after the Insert() automatically
+fmt.Printf("inv1.Id=%d inv2.Id=%d\n", inv1.Id, inv2.Id)
+```
+
+### Update
+
+Continuing the above example, use the `Update` method to modify an Invoice:
+
+```go
+// count is the # of rows updated, which should be 1 in this example
+count, err := dbmap.Update(inv1)
+```
+
+### Delete
+
+If you have primary key(s) defined for a struct, you can use the `Delete`
+method to remove rows:
+
+```go
+count, err := dbmap.Delete(inv1)
+```
+
+### Select by Key
+
+Use the `Get` method to fetch a single row by primary key. It returns
+nil if no row is found.
+
+```go
+// fetch Invoice with Id=99
+obj, err := dbmap.Get(Invoice{}, 99)
+inv := obj.(*Invoice)
+```
+
+### Ad Hoc SQL
+
+#### SELECT
+
+`Select()` and `SelectOne()` provide a simple way to bind arbitrary queries to a slice
+or a single struct.
+
+```go
+// Select a slice - first return value is not needed when a slice pointer is passed to Select()
+var posts []Post
+_, err := dbmap.Select(&posts, "select * from post order by id")
+
+// You can also use primitive types
+var ids []string
+_, err := dbmap.Select(&ids, "select id from post")
+
+// Select a single row.
+// Returns an error if no row found, or if more than one row is found
+var post Post
+err := dbmap.SelectOne(&post, "select * from post where id=?", id)
+```
+
+Want to do joins? Just write the SQL and the struct. gorp will bind them:
+
+```go
+// Define a type for your join
+// It *must* contain all the columns in your SELECT statement
+//
+// The names here should match the aliased column names you specify
+// in your SQL - no additional binding work required. simple.
+//
+type InvoicePersonView struct {
+ InvoiceId int64
+ PersonId int64
+ Memo string
+ FName string
+}
+
+// Create some rows
+p1 := &Person{0, 0, 0, "bob", "smith"}
+err = dbmap.Insert(p1)
+checkErr(err, "Insert failed")
+
+// notice how we can wire up p1.Id to the invoice easily
+inv1 := &Invoice{0, 0, 0, "xmas order", p1.Id}
+err = dbmap.Insert(inv1)
+checkErr(err, "Insert failed")
+
+// Run your query
+query := "select i.Id InvoiceId, p.Id PersonId, i.Memo, p.FName " +
+ "from invoice_test i, person_test p " +
+ "where i.PersonId = p.Id"
+
+// pass a slice to Select()
+var list []InvoicePersonView
+_, err := dbmap.Select(&list, query)
+
+// this should test true
+expected := InvoicePersonView{inv1.Id, p1.Id, inv1.Memo, p1.FName}
+if reflect.DeepEqual(list[0], expected) {
+ fmt.Println("Woot! My join worked!")
+}
+```
+
+#### SELECT string or int64
+
+gorp provides a few convenience methods for selecting a single string or int64.
+
+```go
+// select single int64 from db (use $1 instead of ? for postgresql)
+i64, err := dbmap.SelectInt("select count(*) from foo where blah=?", blahVal)
+
+// select single string from db:
+s, err := dbmap.SelectStr("select name from foo where blah=?", blahVal)
+
+```
+
+#### Named bind parameters
+
+You may use a map or struct to bind parameters by name. This is currently
+only supported in SELECT queries.
+
+```go
+_, err := dbm.Select(&dest, "select * from Foo where name = :name and age = :age", map[string]interface{}{
+ "name": "Rob",
+ "age": 31,
+})
+```
+
+#### UPDATE / DELETE
+
+You can execute raw SQL if you wish. Particularly good for batch operations.
+
+```go
+res, err := dbmap.Exec("delete from invoice_test where PersonId=?", 10)
+```
+
+### Transactions
+
+You can batch operations into a transaction:
+
+```go
+func InsertInv(dbmap *DbMap, inv *Invoice, per *Person) error {
+ // Start a new transaction
+ trans, err := dbmap.Begin()
+ if err != nil {
+ return err
+ }
+
+ err = trans.Insert(per)
+ checkErr(err, "Insert failed")
+
+ inv.PersonId = per.Id
+ err = trans.Insert(inv)
+ checkErr(err, "Insert failed")
+
+ // if the commit is successful, a nil error is returned
+ return trans.Commit()
+}
+```
+
+### Hooks
+
+Use hooks to update data before/after saving to the db. Good for timestamps:
+
+```go
+// implement the PreInsert and PreUpdate hooks
+func (i *Invoice) PreInsert(s gorp.SqlExecutor) error {
+ i.Created = time.Now().UnixNano()
+ i.Updated = i.Created
+ return nil
+}
+
+func (i *Invoice) PreUpdate(s gorp.SqlExecutor) error {
+ i.Updated = time.Now().UnixNano()
+ return nil
+}
+
+// You can use the SqlExecutor to cascade additional SQL
+// Take care to avoid cycles. gorp won't prevent them.
+//
+// Here's an example of a cascading delete
+//
+func (p *Person) PreDelete(s gorp.SqlExecutor) error {
+ query := "delete from invoice_test where PersonId=?"
+
+ _, err := s.Exec(query, p.Id)
+
+ if err != nil {
+ return err
+ }
+ return nil
+}
+```
+
+Full list of hooks that you can implement:
+
+ PostGet
+ PreInsert
+ PostInsert
+ PreUpdate
+ PostUpdate
+ PreDelete
+ PostDelete
+
+ All have the same signature. for example:
+
+ func (p *MyStruct) PostUpdate(s gorp.SqlExecutor) error
+
+### Optimistic Locking
+
+#### Note that this behaviour has changed in v2. See [Migration Guide](#migration-guide).
+
+gorp provides a simple optimistic locking feature, similar to Java's
+JPA, that will raise an error if you try to update/delete a row whose
+`version` column has a value different than the one in memory. This
+provides a safe way to do "select then update" style operations
+without explicit read and write locks.
+
+```go
+// Version is an auto-incremented number, managed by gorp
+// If this property is present on your struct, update
+// operations will be constrained
+//
+// For example, say we defined Person as:
+
+type Person struct {
+ Id int64
+ Created int64
+ Updated int64
+ FName string
+ LName string
+
+ // automatically used as the Version col
+ // use table.SetVersionCol("columnName") to map a different
+ // struct field as the version field
+ Version int64
+}
+
+p1 := &Person{0, 0, 0, "Bob", "Smith", 0}
+err = dbmap.Insert(p1) // Version is now 1
+checkErr(err, "Insert failed")
+
+obj, err := dbmap.Get(Person{}, p1.Id)
+p2 := obj.(*Person)
+p2.LName = "Edwards"
+_,err = dbmap.Update(p2) // Version is now 2
+checkErr(err, "Update failed")
+
+p1.LName = "Howard"
+
+// Raises error because p1.Version == 1, which is out of date
+count, err := dbmap.Update(p1)
+_, ok := err.(gorp.OptimisticLockError)
+if ok {
+ // should reach this statement
+
+ // in a real app you might reload the row and retry, or
+ // you might propegate this to the user, depending on the desired
+ // semantics
+ fmt.Printf("Tried to update row with stale data: %v\n", err)
+} else {
+ // some other db error occurred - log or return up the stack
+ fmt.Printf("Unknown db err: %v\n", err)
+}
+```
+### Adding INDEX(es) on column(s) beyond the primary key ###
+
+Indexes are frequently critical for performance. Here is how to add
+them to your tables.
+
+NB: SqlServer and Oracle need testing and possible adjustment to the
+CreateIndexSuffix() and DropIndexSuffix() methods to make AddIndex()
+work for them.
+
+In the example below we put an index both on the Id field, and on the
+AcctId field.
+
+```
+type Account struct {
+ Id int64
+ AcctId string // e.g. this might be a long uuid for portability
+}
+
+// indexType (the 2nd param to AddIndex call) is "Btree" or "Hash" for MySQL.
+// demonstrate adding a second index on AcctId, and constrain that field to have unique values.
+dbm.AddTable(iptab.Account{}).SetKeys(true, "Id").AddIndex("AcctIdIndex", "Btree", []string{"AcctId"}).SetUnique(true)
+
+err = dbm.CreateTablesIfNotExists()
+checkErr(err, "CreateTablesIfNotExists failed")
+
+err = dbm.CreateIndex()
+checkErr(err, "CreateIndex failed")
+
+```
+Check the effect of the CreateIndex() call in mysql:
+```
+$ mysql
+
+MariaDB [test]> show create table Account;
++---------+--------------------------+
+| Account | CREATE TABLE `Account` (
+ `Id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `AcctId` varchar(255) DEFAULT NULL,
+ PRIMARY KEY (`Id`),
+ UNIQUE KEY `AcctIdIndex` (`AcctId`) USING BTREE <<<--- yes! index added.
+) ENGINE=InnoDB DEFAULT CHARSET=utf8
++---------+--------------------------+
+
+```
+
+
+## Database Drivers
+
+gorp uses the Go 1 `database/sql` package. A full list of compliant
+drivers is available here:
+
+http://code.google.com/p/go-wiki/wiki/SQLDrivers
+
+Sadly, SQL databases differ on various issues. gorp provides a Dialect
+interface that should be implemented per database vendor. Dialects
+are provided for:
+
+* MySQL
+* PostgreSQL
+* sqlite3
+
+Each of these three databases pass the test suite. See `gorp_test.go`
+for example DSNs for these three databases.
+
+Support is also provided for:
+
+* Oracle (contributed by @klaidliadon)
+* SQL Server (contributed by @qrawl) - use driver:
+ github.com/denisenkom/go-mssqldb
+
+Note that these databases are not covered by CI and I (@coopernurse)
+have no good way to test them locally. So please try them and send
+patches as needed, but expect a bit more unpredicability.
+
+## Sqlite3 Extensions
+
+In order to use sqlite3 extensions you need to first register a custom driver:
+
+```go
+import (
+ "database/sql"
+
+ // use whatever database/sql driver you wish
+ sqlite "github.com/mattn/go-sqlite3"
+)
+
+func customDriver() (*sql.DB, error) {
+
+ // create custom driver with extensions defined
+ sql.Register("sqlite3-custom", &sqlite.SQLiteDriver{
+ Extensions: []string{
+ "mod_spatialite",
+ },
+ })
+
+ // now you can then connect using the 'sqlite3-custom' driver instead of 'sqlite3'
+ return sql.Open("sqlite3-custom", "/tmp/post_db.bin")
+}
+```
+
+## Known Issues
+
+### SQL placeholder portability
+
+Different databases use different strings to indicate variable
+placeholders in prepared SQL statements. Unlike some database
+abstraction layers (such as JDBC), Go's `database/sql` does not
+standardize this.
+
+SQL generated by gorp in the `Insert`, `Update`, `Delete`, and `Get`
+methods delegates to a Dialect implementation for each database, and
+will generate portable SQL.
+
+Raw SQL strings passed to `Exec`, `Select`, `SelectOne`, `SelectInt`,
+etc will not be parsed. Consequently you may have portability issues
+if you write a query like this:
+
+```go
+// works on MySQL and Sqlite3, but not with Postgresql err :=
+dbmap.SelectOne(&val, "select * from foo where id = ?", 30)
+```
+
+In `Select` and `SelectOne` you can use named parameters to work
+around this. The following is portable:
+
+```go
+err := dbmap.SelectOne(&val, "select * from foo where id = :id",
+map[string]interface{} { "id": 30})
+```
+
+Additionally, when using Postgres as your database, you should utilize
+`$1` instead of `?` placeholders as utilizing `?` placeholders when
+querying Postgres will result in `pq: operator does not exist`
+errors. Alternatively, use `dbMap.Dialect.BindVar(varIdx)` to get the
+proper variable binding for your dialect.
+
+### time.Time and time zones
+
+gorp will pass `time.Time` fields through to the `database/sql`
+driver, but note that the behavior of this type varies across database
+drivers.
+
+MySQL users should be especially cautious. See:
+https://github.com/ziutek/mymysql/pull/77
+
+To avoid any potential issues with timezone/DST, consider:
+
+- Using an integer field for time data and storing UNIX time.
+- Using a custom time type that implements some SQL types:
+ - [`"database/sql".Scanner`](https://golang.org/pkg/database/sql/#Scanner)
+ - [`"database/sql/driver".Valuer`](https://golang.org/pkg/database/sql/driver/#Valuer)
+
+## Running the tests
+
+The included tests may be run against MySQL, Postgresql, or sqlite3.
+You must set two environment variables so the test code knows which
+driver to use, and how to connect to your database.
+
+```sh
+# MySQL example:
+export GORP_TEST_DSN=gomysql_test/gomysql_test/abc123
+export GORP_TEST_DIALECT=mysql
+
+# run the tests
+go test
+
+# run the tests and benchmarks
+go test -bench="Bench" -benchtime 10
+```
+
+Valid `GORP_TEST_DIALECT` values are: "mysql"(for mymysql),
+"gomysql"(for go-sql-driver), "postgres", "sqlite" See the
+`test_all.sh` script for examples of all 3 databases. This is the
+script I run locally to test the library.
+
+## Performance
+
+gorp uses reflection to construct SQL queries and bind parameters.
+See the BenchmarkNativeCrud vs BenchmarkGorpCrud in gorp_test.go for a
+simple perf test. On my MacBook Pro gorp is about 2-3% slower than
+hand written SQL.
+
+
+## Contributors
+
+* matthias-margush - column aliasing via tags
+* Rob Figueiredo - @robfig
+* Quinn Slack - @sqs
diff --git a/vendor/github.com/go-gorp/gorp/v3/column.go b/vendor/github.com/go-gorp/gorp/v3/column.go
new file mode 100644
index 0000000000..383e9efb65
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/column.go
@@ -0,0 +1,76 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package gorp
+
+import "reflect"
+
+// ColumnMap represents a mapping between a Go struct field and a single
+// column in a table.
+// Unique and MaxSize only inform the
+// CreateTables() function and are not used by Insert/Update/Delete/Get.
+type ColumnMap struct {
+ // Column name in db table
+ ColumnName string
+
+ // If true, this column is skipped in generated SQL statements
+ Transient bool
+
+ // If true, " unique" is added to create table statements.
+ // Not used elsewhere
+ Unique bool
+
+ // Query used for getting generated id after insert
+ GeneratedIdQuery string
+
+ // Passed to Dialect.ToSqlType() to assist in informing the
+ // correct column type to map to in CreateTables()
+ MaxSize int
+
+ DefaultValue string
+
+ fieldName string
+ gotype reflect.Type
+ isPK bool
+ isAutoIncr bool
+ isNotNull bool
+}
+
+// Rename allows you to specify the column name in the table
+//
+// Example: table.ColMap("Updated").Rename("date_updated")
+//
+func (c *ColumnMap) Rename(colname string) *ColumnMap {
+ c.ColumnName = colname
+ return c
+}
+
+// SetTransient allows you to mark the column as transient. If true
+// this column will be skipped when SQL statements are generated
+func (c *ColumnMap) SetTransient(b bool) *ColumnMap {
+ c.Transient = b
+ return c
+}
+
+// SetUnique adds "unique" to the create table statements for this
+// column, if b is true.
+func (c *ColumnMap) SetUnique(b bool) *ColumnMap {
+ c.Unique = b
+ return c
+}
+
+// SetNotNull adds "not null" to the create table statements for this
+// column, if nn is true.
+func (c *ColumnMap) SetNotNull(nn bool) *ColumnMap {
+ c.isNotNull = nn
+ return c
+}
+
+// SetMaxSize specifies the max length of values of this column. This is
+// passed to the dialect.ToSqlType() function, which can use the value
+// to alter the generated type for "create table" statements
+func (c *ColumnMap) SetMaxSize(size int) *ColumnMap {
+ c.MaxSize = size
+ return c
+}
diff --git a/vendor/github.com/go-gorp/gorp/v3/db.go b/vendor/github.com/go-gorp/gorp/v3/db.go
new file mode 100644
index 0000000000..d78062e5b1
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/db.go
@@ -0,0 +1,985 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package gorp
+
+import (
+ "bytes"
+ "context"
+ "database/sql"
+ "database/sql/driver"
+ "errors"
+ "fmt"
+ "log"
+ "reflect"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// DbMap is the root gorp mapping object. Create one of these for each
+// database schema you wish to map. Each DbMap contains a list of
+// mapped tables.
+//
+// Example:
+//
+// dialect := gorp.MySQLDialect{"InnoDB", "UTF8"}
+// dbmap := &gorp.DbMap{Db: db, Dialect: dialect}
+//
+type DbMap struct {
+ ctx context.Context
+
+ // Db handle to use with this map
+ Db *sql.DB
+
+ // Dialect implementation to use with this map
+ Dialect Dialect
+
+ TypeConverter TypeConverter
+
+ // ExpandSlices when enabled will convert slice arguments in mappers into flat
+ // values. It will modify the query, adding more placeholders, and the mapper,
+ // adding each item of the slice as a new unique entry in the mapper. For
+ // example, given the scenario bellow:
+ //
+ // dbmap.Select(&output, "SELECT 1 FROM example WHERE id IN (:IDs)", map[string]interface{}{
+ // "IDs": []int64{1, 2, 3},
+ // })
+ //
+ // The executed query would be:
+ //
+ // SELECT 1 FROM example WHERE id IN (:IDs0,:IDs1,:IDs2)
+ //
+ // With the mapper:
+ //
+ // map[string]interface{}{
+ // "IDs": []int64{1, 2, 3},
+ // "IDs0": int64(1),
+ // "IDs1": int64(2),
+ // "IDs2": int64(3),
+ // }
+ //
+ // It is also flexible for custom slice types. The value just need to
+ // implement stringer or numberer interfaces.
+ //
+ // type CustomValue string
+ //
+ // const (
+ // CustomValueHey CustomValue = "hey"
+ // CustomValueOh CustomValue = "oh"
+ // )
+ //
+ // type CustomValues []CustomValue
+ //
+ // func (c CustomValues) ToStringSlice() []string {
+ // values := make([]string, len(c))
+ // for i := range c {
+ // values[i] = string(c[i])
+ // }
+ // return values
+ // }
+ //
+ // func query() {
+ // // ...
+ // result, err := dbmap.Select(&output, "SELECT 1 FROM example WHERE value IN (:Values)", map[string]interface{}{
+ // "Values": CustomValues([]CustomValue{CustomValueHey}),
+ // })
+ // // ...
+ // }
+ ExpandSliceArgs bool
+
+ tables []*TableMap
+ tablesDynamic map[string]*TableMap // tables that use same go-struct and different db table names
+ logger GorpLogger
+ logPrefix string
+}
+
+func (m *DbMap) dynamicTableAdd(tableName string, tbl *TableMap) {
+ if m.tablesDynamic == nil {
+ m.tablesDynamic = make(map[string]*TableMap)
+ }
+ m.tablesDynamic[tableName] = tbl
+}
+
+func (m *DbMap) dynamicTableFind(tableName string) (*TableMap, bool) {
+ if m.tablesDynamic == nil {
+ return nil, false
+ }
+ tbl, found := m.tablesDynamic[tableName]
+ return tbl, found
+}
+
+func (m *DbMap) dynamicTableMap() map[string]*TableMap {
+ if m.tablesDynamic == nil {
+ m.tablesDynamic = make(map[string]*TableMap)
+ }
+ return m.tablesDynamic
+}
+
+func (m *DbMap) WithContext(ctx context.Context) SqlExecutor {
+ copy := &DbMap{}
+ *copy = *m
+ copy.ctx = ctx
+ return copy
+}
+
+func (m *DbMap) CreateIndex() error {
+ var err error
+ dialect := reflect.TypeOf(m.Dialect)
+ for _, table := range m.tables {
+ for _, index := range table.indexes {
+ err = m.createIndexImpl(dialect, table, index)
+ if err != nil {
+ break
+ }
+ }
+ }
+
+ for _, table := range m.dynamicTableMap() {
+ for _, index := range table.indexes {
+ err = m.createIndexImpl(dialect, table, index)
+ if err != nil {
+ break
+ }
+ }
+ }
+
+ return err
+}
+
+func (m *DbMap) createIndexImpl(dialect reflect.Type,
+ table *TableMap,
+ index *IndexMap) error {
+ s := bytes.Buffer{}
+ s.WriteString("create")
+ if index.Unique {
+ s.WriteString(" unique")
+ }
+ s.WriteString(" index")
+ s.WriteString(fmt.Sprintf(" %s on %s", index.IndexName, table.TableName))
+ if dname := dialect.Name(); dname == "PostgresDialect" && index.IndexType != "" {
+ s.WriteString(fmt.Sprintf(" %s %s", m.Dialect.CreateIndexSuffix(), index.IndexType))
+ }
+ s.WriteString(" (")
+ for x, col := range index.columns {
+ if x > 0 {
+ s.WriteString(", ")
+ }
+ s.WriteString(m.Dialect.QuoteField(col))
+ }
+ s.WriteString(")")
+
+ if dname := dialect.Name(); dname == "MySQLDialect" && index.IndexType != "" {
+ s.WriteString(fmt.Sprintf(" %s %s", m.Dialect.CreateIndexSuffix(), index.IndexType))
+ }
+ s.WriteString(";")
+ _, err := m.Exec(s.String())
+ return err
+}
+
+func (t *TableMap) DropIndex(name string) error {
+
+ var err error
+ dialect := reflect.TypeOf(t.dbmap.Dialect)
+ for _, idx := range t.indexes {
+ if idx.IndexName == name {
+ s := bytes.Buffer{}
+ s.WriteString(fmt.Sprintf("DROP INDEX %s", idx.IndexName))
+
+ if dname := dialect.Name(); dname == "MySQLDialect" {
+ s.WriteString(fmt.Sprintf(" %s %s", t.dbmap.Dialect.DropIndexSuffix(), t.TableName))
+ }
+ s.WriteString(";")
+ _, e := t.dbmap.Exec(s.String())
+ if e != nil {
+ err = e
+ }
+ break
+ }
+ }
+ t.ResetSql()
+ return err
+}
+
+// AddTable registers the given interface type with gorp. The table name
+// will be given the name of the TypeOf(i). You must call this function,
+// or AddTableWithName, for any struct type you wish to persist with
+// the given DbMap.
+//
+// This operation is idempotent. If i's type is already mapped, the
+// existing *TableMap is returned
+func (m *DbMap) AddTable(i interface{}) *TableMap {
+ return m.AddTableWithName(i, "")
+}
+
+// AddTableWithName has the same behavior as AddTable, but sets
+// table.TableName to name.
+func (m *DbMap) AddTableWithName(i interface{}, name string) *TableMap {
+ return m.AddTableWithNameAndSchema(i, "", name)
+}
+
+// AddTableWithNameAndSchema has the same behavior as AddTable, but sets
+// table.TableName to name.
+func (m *DbMap) AddTableWithNameAndSchema(i interface{}, schema string, name string) *TableMap {
+ t := reflect.TypeOf(i)
+ if name == "" {
+ name = t.Name()
+ }
+
+ // check if we have a table for this type already
+ // if so, update the name and return the existing pointer
+ for i := range m.tables {
+ table := m.tables[i]
+ if table.gotype == t {
+ table.TableName = name
+ return table
+ }
+ }
+
+ tmap := &TableMap{gotype: t, TableName: name, SchemaName: schema, dbmap: m}
+ var primaryKey []*ColumnMap
+ tmap.Columns, primaryKey = m.readStructColumns(t)
+ m.tables = append(m.tables, tmap)
+ if len(primaryKey) > 0 {
+ tmap.keys = append(tmap.keys, primaryKey...)
+ }
+
+ return tmap
+}
+
+// AddTableDynamic registers the given interface type with gorp.
+// The table name will be dynamically determined at runtime by
+// using the GetTableName method on DynamicTable interface
+func (m *DbMap) AddTableDynamic(inp DynamicTable, schema string) *TableMap {
+
+ val := reflect.ValueOf(inp)
+ elm := val.Elem()
+ t := elm.Type()
+ name := inp.TableName()
+ if name == "" {
+ panic("Missing table name in DynamicTable instance")
+ }
+
+ // Check if there is another dynamic table with the same name
+ if _, found := m.dynamicTableFind(name); found {
+ panic(fmt.Sprintf("A table with the same name %v already exists", name))
+ }
+
+ tmap := &TableMap{gotype: t, TableName: name, SchemaName: schema, dbmap: m}
+ var primaryKey []*ColumnMap
+ tmap.Columns, primaryKey = m.readStructColumns(t)
+ if len(primaryKey) > 0 {
+ tmap.keys = append(tmap.keys, primaryKey...)
+ }
+
+ m.dynamicTableAdd(name, tmap)
+
+ return tmap
+}
+
+func (m *DbMap) readStructColumns(t reflect.Type) (cols []*ColumnMap, primaryKey []*ColumnMap) {
+ primaryKey = make([]*ColumnMap, 0)
+ n := t.NumField()
+ for i := 0; i < n; i++ {
+ f := t.Field(i)
+ if f.Anonymous && f.Type.Kind() == reflect.Struct {
+ // Recursively add nested fields in embedded structs.
+ subcols, subpk := m.readStructColumns(f.Type)
+ // Don't append nested fields that have the same field
+ // name as an already-mapped field.
+ for _, subcol := range subcols {
+ shouldAppend := true
+ for _, col := range cols {
+ if !subcol.Transient && subcol.fieldName == col.fieldName {
+ shouldAppend = false
+ break
+ }
+ }
+ if shouldAppend {
+ cols = append(cols, subcol)
+ }
+ }
+ if subpk != nil {
+ primaryKey = append(primaryKey, subpk...)
+ }
+ } else {
+ // Tag = Name { ',' Option }
+ // Option = OptionKey [ ':' OptionValue ]
+ cArguments := strings.Split(f.Tag.Get("db"), ",")
+ columnName := cArguments[0]
+ var maxSize int
+ var defaultValue string
+ var isAuto bool
+ var isPK bool
+ var isNotNull bool
+ for _, argString := range cArguments[1:] {
+ argString = strings.TrimSpace(argString)
+ arg := strings.SplitN(argString, ":", 2)
+
+ // check mandatory/unexpected option values
+ switch arg[0] {
+ case "size", "default":
+ // options requiring value
+ if len(arg) == 1 {
+ panic(fmt.Sprintf("missing option value for option %v on field %v", arg[0], f.Name))
+ }
+ default:
+ // options where value is invalid (currently all other options)
+ if len(arg) == 2 {
+ panic(fmt.Sprintf("unexpected option value for option %v on field %v", arg[0], f.Name))
+ }
+ }
+
+ switch arg[0] {
+ case "size":
+ maxSize, _ = strconv.Atoi(arg[1])
+ case "default":
+ defaultValue = arg[1]
+ case "primarykey":
+ isPK = true
+ case "autoincrement":
+ isAuto = true
+ case "notnull":
+ isNotNull = true
+ default:
+ panic(fmt.Sprintf("Unrecognized tag option for field %v: %v", f.Name, arg))
+ }
+ }
+ if columnName == "" {
+ columnName = f.Name
+ }
+
+ gotype := f.Type
+ valueType := gotype
+ if valueType.Kind() == reflect.Ptr {
+ valueType = valueType.Elem()
+ }
+ value := reflect.New(valueType).Interface()
+ if m.TypeConverter != nil {
+ // Make a new pointer to a value of type gotype and
+ // pass it to the TypeConverter's FromDb method to see
+ // if a different type should be used for the column
+ // type during table creation.
+ scanner, useHolder := m.TypeConverter.FromDb(value)
+ if useHolder {
+ value = scanner.Holder
+ gotype = reflect.TypeOf(value)
+ }
+ }
+ if typer, ok := value.(SqlTyper); ok {
+ gotype = reflect.TypeOf(typer.SqlType())
+ } else if typer, ok := value.(legacySqlTyper); ok {
+ log.Printf("Deprecation Warning: update your SqlType methods to return a driver.Value")
+ gotype = reflect.TypeOf(typer.SqlType())
+ } else if valuer, ok := value.(driver.Valuer); ok {
+ // Only check for driver.Valuer if SqlTyper wasn't
+ // found.
+ v, err := valuer.Value()
+ if err == nil && v != nil {
+ gotype = reflect.TypeOf(v)
+ }
+ }
+ cm := &ColumnMap{
+ ColumnName: columnName,
+ DefaultValue: defaultValue,
+ Transient: columnName == "-",
+ fieldName: f.Name,
+ gotype: gotype,
+ isPK: isPK,
+ isAutoIncr: isAuto,
+ isNotNull: isNotNull,
+ MaxSize: maxSize,
+ }
+ if isPK {
+ primaryKey = append(primaryKey, cm)
+ }
+ // Check for nested fields of the same field name and
+ // override them.
+ shouldAppend := true
+ for index, col := range cols {
+ if !col.Transient && col.fieldName == cm.fieldName {
+ cols[index] = cm
+ shouldAppend = false
+ break
+ }
+ }
+ if shouldAppend {
+ cols = append(cols, cm)
+ }
+ }
+
+ }
+ return
+}
+
+// CreateTables iterates through TableMaps registered to this DbMap and
+// executes "create table" statements against the database for each.
+//
+// This is particularly useful in unit tests where you want to create
+// and destroy the schema automatically.
+func (m *DbMap) CreateTables() error {
+ return m.createTables(false)
+}
+
+// CreateTablesIfNotExists is similar to CreateTables, but starts
+// each statement with "create table if not exists" so that existing
+// tables do not raise errors
+func (m *DbMap) CreateTablesIfNotExists() error {
+ return m.createTables(true)
+}
+
+func (m *DbMap) createTables(ifNotExists bool) error {
+ var err error
+ for i := range m.tables {
+ table := m.tables[i]
+ sql := table.SqlForCreate(ifNotExists)
+ _, err = m.Exec(sql)
+ if err != nil {
+ return err
+ }
+ }
+
+ for _, tbl := range m.dynamicTableMap() {
+ sql := tbl.SqlForCreate(ifNotExists)
+ _, err = m.Exec(sql)
+ if err != nil {
+ return err
+ }
+ }
+
+ return err
+}
+
+// DropTable drops an individual table.
+// Returns an error when the table does not exist.
+func (m *DbMap) DropTable(table interface{}) error {
+ t := reflect.TypeOf(table)
+
+ tableName := ""
+ if dyn, ok := table.(DynamicTable); ok {
+ tableName = dyn.TableName()
+ }
+
+ return m.dropTable(t, tableName, false)
+}
+
+// DropTableIfExists drops an individual table when the table exists.
+func (m *DbMap) DropTableIfExists(table interface{}) error {
+ t := reflect.TypeOf(table)
+
+ tableName := ""
+ if dyn, ok := table.(DynamicTable); ok {
+ tableName = dyn.TableName()
+ }
+
+ return m.dropTable(t, tableName, true)
+}
+
+// DropTables iterates through TableMaps registered to this DbMap and
+// executes "drop table" statements against the database for each.
+func (m *DbMap) DropTables() error {
+ return m.dropTables(false)
+}
+
+// DropTablesIfExists is the same as DropTables, but uses the "if exists" clause to
+// avoid errors for tables that do not exist.
+func (m *DbMap) DropTablesIfExists() error {
+ return m.dropTables(true)
+}
+
+// Goes through all the registered tables, dropping them one by one.
+// If an error is encountered, then it is returned and the rest of
+// the tables are not dropped.
+func (m *DbMap) dropTables(addIfExists bool) (err error) {
+ for _, table := range m.tables {
+ err = m.dropTableImpl(table, addIfExists)
+ if err != nil {
+ return err
+ }
+ }
+
+ for _, table := range m.dynamicTableMap() {
+ err = m.dropTableImpl(table, addIfExists)
+ if err != nil {
+ return err
+ }
+ }
+
+ return err
+}
+
+// Implementation of dropping a single table.
+func (m *DbMap) dropTable(t reflect.Type, name string, addIfExists bool) error {
+ table := tableOrNil(m, t, name)
+ if table == nil {
+ return fmt.Errorf("table %s was not registered", table.TableName)
+ }
+
+ return m.dropTableImpl(table, addIfExists)
+}
+
+func (m *DbMap) dropTableImpl(table *TableMap, ifExists bool) (err error) {
+ tableDrop := "drop table"
+ if ifExists {
+ tableDrop = m.Dialect.IfTableExists(tableDrop, table.SchemaName, table.TableName)
+ }
+ _, err = m.Exec(fmt.Sprintf("%s %s;", tableDrop, m.Dialect.QuotedTableForQuery(table.SchemaName, table.TableName)))
+ return err
+}
+
+// TruncateTables iterates through TableMaps registered to this DbMap and
+// executes "truncate table" statements against the database for each, or in the case of
+// sqlite, a "delete from" with no "where" clause, which uses the truncate optimization
+// (http://www.sqlite.org/lang_delete.html)
+func (m *DbMap) TruncateTables() error {
+ var err error
+ for i := range m.tables {
+ table := m.tables[i]
+ _, e := m.Exec(fmt.Sprintf("%s %s;", m.Dialect.TruncateClause(), m.Dialect.QuotedTableForQuery(table.SchemaName, table.TableName)))
+ if e != nil {
+ err = e
+ }
+ }
+
+ for _, table := range m.dynamicTableMap() {
+ _, e := m.Exec(fmt.Sprintf("%s %s;", m.Dialect.TruncateClause(), m.Dialect.QuotedTableForQuery(table.SchemaName, table.TableName)))
+ if e != nil {
+ err = e
+ }
+ }
+
+ return err
+}
+
+// Insert runs a SQL INSERT statement for each element in list. List
+// items must be pointers.
+//
+// Any interface whose TableMap has an auto-increment primary key will
+// have its last insert id bound to the PK field on the struct.
+//
+// The hook functions PreInsert() and/or PostInsert() will be executed
+// before/after the INSERT statement if the interface defines them.
+//
+// Panics if any interface in the list has not been registered with AddTable
+func (m *DbMap) Insert(list ...interface{}) error {
+ return insert(m, m, list...)
+}
+
+// Update runs a SQL UPDATE statement for each element in list. List
+// items must be pointers.
+//
+// The hook functions PreUpdate() and/or PostUpdate() will be executed
+// before/after the UPDATE statement if the interface defines them.
+//
+// Returns the number of rows updated.
+//
+// Returns an error if SetKeys has not been called on the TableMap
+// Panics if any interface in the list has not been registered with AddTable
+func (m *DbMap) Update(list ...interface{}) (int64, error) {
+ return update(m, m, nil, list...)
+}
+
+// UpdateColumns runs a SQL UPDATE statement for each element in list. List
+// items must be pointers.
+//
+// Only the columns accepted by filter are included in the UPDATE.
+//
+// The hook functions PreUpdate() and/or PostUpdate() will be executed
+// before/after the UPDATE statement if the interface defines them.
+//
+// Returns the number of rows updated.
+//
+// Returns an error if SetKeys has not been called on the TableMap
+// Panics if any interface in the list has not been registered with AddTable
+func (m *DbMap) UpdateColumns(filter ColumnFilter, list ...interface{}) (int64, error) {
+ return update(m, m, filter, list...)
+}
+
+// Delete runs a SQL DELETE statement for each element in list. List
+// items must be pointers.
+//
+// The hook functions PreDelete() and/or PostDelete() will be executed
+// before/after the DELETE statement if the interface defines them.
+//
+// Returns the number of rows deleted.
+//
+// Returns an error if SetKeys has not been called on the TableMap
+// Panics if any interface in the list has not been registered with AddTable
+func (m *DbMap) Delete(list ...interface{}) (int64, error) {
+ return delete(m, m, list...)
+}
+
+// Get runs a SQL SELECT to fetch a single row from the table based on the
+// primary key(s)
+//
+// i should be an empty value for the struct to load. keys should be
+// the primary key value(s) for the row to load. If multiple keys
+// exist on the table, the order should match the column order
+// specified in SetKeys() when the table mapping was defined.
+//
+// The hook function PostGet() will be executed after the SELECT
+// statement if the interface defines them.
+//
+// Returns a pointer to a struct that matches or nil if no row is found.
+//
+// Returns an error if SetKeys has not been called on the TableMap
+// Panics if any interface in the list has not been registered with AddTable
+func (m *DbMap) Get(i interface{}, keys ...interface{}) (interface{}, error) {
+ return get(m, m, i, keys...)
+}
+
+// Select runs an arbitrary SQL query, binding the columns in the result
+// to fields on the struct specified by i. args represent the bind
+// parameters for the SQL statement.
+//
+// Column names on the SELECT statement should be aliased to the field names
+// on the struct i. Returns an error if one or more columns in the result
+// do not match. It is OK if fields on i are not part of the SQL
+// statement.
+//
+// The hook function PostGet() will be executed after the SELECT
+// statement if the interface defines them.
+//
+// Values are returned in one of two ways:
+// 1. If i is a struct or a pointer to a struct, returns a slice of pointers to
+// matching rows of type i.
+// 2. If i is a pointer to a slice, the results will be appended to that slice
+// and nil returned.
+//
+// i does NOT need to be registered with AddTable()
+func (m *DbMap) Select(i interface{}, query string, args ...interface{}) ([]interface{}, error) {
+ if m.ExpandSliceArgs {
+ expandSliceArgs(&query, args...)
+ }
+
+ return hookedselect(m, m, i, query, args...)
+}
+
+// Exec runs an arbitrary SQL statement. args represent the bind parameters.
+// This is equivalent to running: Exec() using database/sql
+func (m *DbMap) Exec(query string, args ...interface{}) (sql.Result, error) {
+ if m.ExpandSliceArgs {
+ expandSliceArgs(&query, args...)
+ }
+
+ if m.logger != nil {
+ now := time.Now()
+ defer m.trace(now, query, args...)
+ }
+ return maybeExpandNamedQueryAndExec(m, query, args...)
+}
+
+// SelectInt is a convenience wrapper around the gorp.SelectInt function
+func (m *DbMap) SelectInt(query string, args ...interface{}) (int64, error) {
+ if m.ExpandSliceArgs {
+ expandSliceArgs(&query, args...)
+ }
+
+ return SelectInt(m, query, args...)
+}
+
+// SelectNullInt is a convenience wrapper around the gorp.SelectNullInt function
+func (m *DbMap) SelectNullInt(query string, args ...interface{}) (sql.NullInt64, error) {
+ if m.ExpandSliceArgs {
+ expandSliceArgs(&query, args...)
+ }
+
+ return SelectNullInt(m, query, args...)
+}
+
+// SelectFloat is a convenience wrapper around the gorp.SelectFloat function
+func (m *DbMap) SelectFloat(query string, args ...interface{}) (float64, error) {
+ if m.ExpandSliceArgs {
+ expandSliceArgs(&query, args...)
+ }
+
+ return SelectFloat(m, query, args...)
+}
+
+// SelectNullFloat is a convenience wrapper around the gorp.SelectNullFloat function
+func (m *DbMap) SelectNullFloat(query string, args ...interface{}) (sql.NullFloat64, error) {
+ if m.ExpandSliceArgs {
+ expandSliceArgs(&query, args...)
+ }
+
+ return SelectNullFloat(m, query, args...)
+}
+
+// SelectStr is a convenience wrapper around the gorp.SelectStr function
+func (m *DbMap) SelectStr(query string, args ...interface{}) (string, error) {
+ if m.ExpandSliceArgs {
+ expandSliceArgs(&query, args...)
+ }
+
+ return SelectStr(m, query, args...)
+}
+
+// SelectNullStr is a convenience wrapper around the gorp.SelectNullStr function
+func (m *DbMap) SelectNullStr(query string, args ...interface{}) (sql.NullString, error) {
+ if m.ExpandSliceArgs {
+ expandSliceArgs(&query, args...)
+ }
+
+ return SelectNullStr(m, query, args...)
+}
+
+// SelectOne is a convenience wrapper around the gorp.SelectOne function
+func (m *DbMap) SelectOne(holder interface{}, query string, args ...interface{}) error {
+ if m.ExpandSliceArgs {
+ expandSliceArgs(&query, args...)
+ }
+
+ return SelectOne(m, m, holder, query, args...)
+}
+
+// Begin starts a gorp Transaction
+func (m *DbMap) Begin() (*Transaction, error) {
+ if m.logger != nil {
+ now := time.Now()
+ defer m.trace(now, "begin;")
+ }
+ tx, err := begin(m)
+ if err != nil {
+ return nil, err
+ }
+ return &Transaction{
+ dbmap: m,
+ tx: tx,
+ closed: false,
+ }, nil
+}
+
+// TableFor returns the *TableMap corresponding to the given Go Type
+// If no table is mapped to that type an error is returned.
+// If checkPK is true and the mapped table has no registered PKs, an error is returned.
+func (m *DbMap) TableFor(t reflect.Type, checkPK bool) (*TableMap, error) {
+ table := tableOrNil(m, t, "")
+ if table == nil {
+ return nil, fmt.Errorf("no table found for type: %v", t.Name())
+ }
+
+ if checkPK && len(table.keys) < 1 {
+ e := fmt.Sprintf("gorp: no keys defined for table: %s",
+ table.TableName)
+ return nil, errors.New(e)
+ }
+
+ return table, nil
+}
+
+// DynamicTableFor returns the *TableMap for the dynamic table corresponding
+// to the input tablename
+// If no table is mapped to that tablename an error is returned.
+// If checkPK is true and the mapped table has no registered PKs, an error is returned.
+func (m *DbMap) DynamicTableFor(tableName string, checkPK bool) (*TableMap, error) {
+ table, found := m.dynamicTableFind(tableName)
+ if !found {
+ return nil, fmt.Errorf("gorp: no table found for name: %v", tableName)
+ }
+
+ if checkPK && len(table.keys) < 1 {
+ e := fmt.Sprintf("gorp: no keys defined for table: %s",
+ table.TableName)
+ return nil, errors.New(e)
+ }
+
+ return table, nil
+}
+
+// Prepare creates a prepared statement for later queries or executions.
+// Multiple queries or executions may be run concurrently from the returned statement.
+// This is equivalent to running: Prepare() using database/sql
+func (m *DbMap) Prepare(query string) (*sql.Stmt, error) {
+ if m.logger != nil {
+ now := time.Now()
+ defer m.trace(now, query, nil)
+ }
+ return prepare(m, query)
+}
+
+func tableOrNil(m *DbMap, t reflect.Type, name string) *TableMap {
+ if name != "" {
+ // Search by table name (dynamic tables)
+ if table, found := m.dynamicTableFind(name); found {
+ return table
+ }
+ return nil
+ }
+
+ for i := range m.tables {
+ table := m.tables[i]
+ if table.gotype == t {
+ return table
+ }
+ }
+ return nil
+}
+
+func (m *DbMap) tableForPointer(ptr interface{}, checkPK bool) (*TableMap, reflect.Value, error) {
+ ptrv := reflect.ValueOf(ptr)
+ if ptrv.Kind() != reflect.Ptr {
+ e := fmt.Sprintf("gorp: passed non-pointer: %v (kind=%v)", ptr,
+ ptrv.Kind())
+ return nil, reflect.Value{}, errors.New(e)
+ }
+ elem := ptrv.Elem()
+ ifc := elem.Interface()
+ var t *TableMap
+ var err error
+ tableName := ""
+ if dyn, isDyn := ptr.(DynamicTable); isDyn {
+ tableName = dyn.TableName()
+ t, err = m.DynamicTableFor(tableName, checkPK)
+ } else {
+ etype := reflect.TypeOf(ifc)
+ t, err = m.TableFor(etype, checkPK)
+ }
+
+ if err != nil {
+ return nil, reflect.Value{}, err
+ }
+
+ return t, elem, nil
+}
+
+func (m *DbMap) QueryRow(query string, args ...interface{}) *sql.Row {
+ if m.ExpandSliceArgs {
+ expandSliceArgs(&query, args...)
+ }
+
+ if m.logger != nil {
+ now := time.Now()
+ defer m.trace(now, query, args...)
+ }
+ return queryRow(m, query, args...)
+}
+
+func (m *DbMap) Query(q string, args ...interface{}) (*sql.Rows, error) {
+ if m.ExpandSliceArgs {
+ expandSliceArgs(&q, args...)
+ }
+
+ if m.logger != nil {
+ now := time.Now()
+ defer m.trace(now, q, args...)
+ }
+ return query(m, q, args...)
+}
+
+func (m *DbMap) trace(started time.Time, query string, args ...interface{}) {
+ if m.ExpandSliceArgs {
+ expandSliceArgs(&query, args...)
+ }
+
+ if m.logger != nil {
+ var margs = argsString(args...)
+ m.logger.Printf("%s%s [%s] (%v)", m.logPrefix, query, margs, (time.Now().Sub(started)))
+ }
+}
+
+type stringer interface {
+ ToStringSlice() []string
+}
+
+type numberer interface {
+ ToInt64Slice() []int64
+}
+
+func expandSliceArgs(query *string, args ...interface{}) {
+ for _, arg := range args {
+ mapper, ok := arg.(map[string]interface{})
+ if !ok {
+ continue
+ }
+
+ for key, value := range mapper {
+ var replacements []string
+
+ // add flexibility for any custom type to be convert to one of the
+ // acceptable formats.
+ if v, ok := value.(stringer); ok {
+ value = v.ToStringSlice()
+ }
+ if v, ok := value.(numberer); ok {
+ value = v.ToInt64Slice()
+ }
+
+ switch v := value.(type) {
+ case []string:
+ for id, replace := range v {
+ mapper[fmt.Sprintf("%s%d", key, id)] = replace
+ replacements = append(replacements, fmt.Sprintf(":%s%d", key, id))
+ }
+ case []uint:
+ for id, replace := range v {
+ mapper[fmt.Sprintf("%s%d", key, id)] = replace
+ replacements = append(replacements, fmt.Sprintf(":%s%d", key, id))
+ }
+ case []uint8:
+ for id, replace := range v {
+ mapper[fmt.Sprintf("%s%d", key, id)] = replace
+ replacements = append(replacements, fmt.Sprintf(":%s%d", key, id))
+ }
+ case []uint16:
+ for id, replace := range v {
+ mapper[fmt.Sprintf("%s%d", key, id)] = replace
+ replacements = append(replacements, fmt.Sprintf(":%s%d", key, id))
+ }
+ case []uint32:
+ for id, replace := range v {
+ mapper[fmt.Sprintf("%s%d", key, id)] = replace
+ replacements = append(replacements, fmt.Sprintf(":%s%d", key, id))
+ }
+ case []uint64:
+ for id, replace := range v {
+ mapper[fmt.Sprintf("%s%d", key, id)] = replace
+ replacements = append(replacements, fmt.Sprintf(":%s%d", key, id))
+ }
+ case []int:
+ for id, replace := range v {
+ mapper[fmt.Sprintf("%s%d", key, id)] = replace
+ replacements = append(replacements, fmt.Sprintf(":%s%d", key, id))
+ }
+ case []int8:
+ for id, replace := range v {
+ mapper[fmt.Sprintf("%s%d", key, id)] = replace
+ replacements = append(replacements, fmt.Sprintf(":%s%d", key, id))
+ }
+ case []int16:
+ for id, replace := range v {
+ mapper[fmt.Sprintf("%s%d", key, id)] = replace
+ replacements = append(replacements, fmt.Sprintf(":%s%d", key, id))
+ }
+ case []int32:
+ for id, replace := range v {
+ mapper[fmt.Sprintf("%s%d", key, id)] = replace
+ replacements = append(replacements, fmt.Sprintf(":%s%d", key, id))
+ }
+ case []int64:
+ for id, replace := range v {
+ mapper[fmt.Sprintf("%s%d", key, id)] = replace
+ replacements = append(replacements, fmt.Sprintf(":%s%d", key, id))
+ }
+ case []float32:
+ for id, replace := range v {
+ mapper[fmt.Sprintf("%s%d", key, id)] = replace
+ replacements = append(replacements, fmt.Sprintf(":%s%d", key, id))
+ }
+ case []float64:
+ for id, replace := range v {
+ mapper[fmt.Sprintf("%s%d", key, id)] = replace
+ replacements = append(replacements, fmt.Sprintf(":%s%d", key, id))
+ }
+ default:
+ continue
+ }
+
+ if len(replacements) == 0 {
+ continue
+ }
+
+ *query = strings.Replace(*query, fmt.Sprintf(":%s", key), strings.Join(replacements, ","), -1)
+ }
+ }
+}
diff --git a/vendor/github.com/go-gorp/gorp/v3/dialect.go b/vendor/github.com/go-gorp/gorp/v3/dialect.go
new file mode 100644
index 0000000000..fdea2b203c
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/dialect.go
@@ -0,0 +1,105 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package gorp
+
+import (
+ "reflect"
+)
+
+// The Dialect interface encapsulates behaviors that differ across
+// SQL databases. At present the Dialect is only used by CreateTables()
+// but this could change in the future
+type Dialect interface {
+ // adds a suffix to any query, usually ";"
+ QuerySuffix() string
+
+ // ToSqlType returns the SQL column type to use when creating a
+ // table of the given Go Type. maxsize can be used to switch based on
+ // size. For example, in MySQL []byte could map to BLOB, MEDIUMBLOB,
+ // or LONGBLOB depending on the maxsize
+ ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string
+
+ // string to append to primary key column definitions
+ AutoIncrStr() string
+
+ // string to bind autoincrement columns to. Empty string will
+ // remove reference to those columns in the INSERT statement.
+ AutoIncrBindValue() string
+
+ AutoIncrInsertSuffix(col *ColumnMap) string
+
+ // string to append to "create table" statement for vendor specific
+ // table attributes
+ CreateTableSuffix() string
+
+ // string to append to "create index" statement
+ CreateIndexSuffix() string
+
+ // string to append to "drop index" statement
+ DropIndexSuffix() string
+
+ // string to truncate tables
+ TruncateClause() string
+
+ // bind variable string to use when forming SQL statements
+ // in many dbs it is "?", but Postgres appears to use $1
+ //
+ // i is a zero based index of the bind variable in this statement
+ //
+ BindVar(i int) string
+
+ // Handles quoting of a field name to ensure that it doesn't raise any
+ // SQL parsing exceptions by using a reserved word as a field name.
+ QuoteField(field string) string
+
+ // Handles building up of a schema.database string that is compatible with
+ // the given dialect
+ //
+ // schema - The schema that lives in
+ // table - The table name
+ QuotedTableForQuery(schema string, table string) string
+
+ // Existence clause for table creation / deletion
+ IfSchemaNotExists(command, schema string) string
+ IfTableExists(command, schema, table string) string
+ IfTableNotExists(command, schema, table string) string
+}
+
+// IntegerAutoIncrInserter is implemented by dialects that can perform
+// inserts with automatically incremented integer primary keys. If
+// the dialect can handle automatic assignment of more than just
+// integers, see TargetedAutoIncrInserter.
+type IntegerAutoIncrInserter interface {
+ InsertAutoIncr(exec SqlExecutor, insertSql string, params ...interface{}) (int64, error)
+}
+
+// TargetedAutoIncrInserter is implemented by dialects that can
+// perform automatic assignment of any primary key type (i.e. strings
+// for uuids, integers for serials, etc).
+type TargetedAutoIncrInserter interface {
+ // InsertAutoIncrToTarget runs an insert operation and assigns the
+ // automatically generated primary key directly to the passed in
+ // target. The target should be a pointer to the primary key
+ // field of the value being inserted.
+ InsertAutoIncrToTarget(exec SqlExecutor, insertSql string, target interface{}, params ...interface{}) error
+}
+
+// TargetQueryInserter is implemented by dialects that can perform
+// assignment of integer primary key type by executing a query
+// like "select sequence.currval from dual".
+type TargetQueryInserter interface {
+ // TargetQueryInserter runs an insert operation and assigns the
+ // automatically generated primary key retrived by the query
+ // extracted from the GeneratedIdQuery field of the id column.
+ InsertQueryToTarget(exec SqlExecutor, insertSql, idSql string, target interface{}, params ...interface{}) error
+}
+
+func standardInsertAutoIncr(exec SqlExecutor, insertSql string, params ...interface{}) (int64, error) {
+ res, err := exec.Exec(insertSql, params...)
+ if err != nil {
+ return 0, err
+ }
+ return res.LastInsertId()
+}
diff --git a/vendor/github.com/go-gorp/gorp/v3/dialect_mysql.go b/vendor/github.com/go-gorp/gorp/v3/dialect_mysql.go
new file mode 100644
index 0000000000..d068ebe85e
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/dialect_mysql.go
@@ -0,0 +1,169 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package gorp
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+ "time"
+)
+
+// Implementation of Dialect for MySQL databases.
+type MySQLDialect struct {
+
+ // Engine is the storage engine to use "InnoDB" vs "MyISAM" for example
+ Engine string
+
+ // Encoding is the character encoding to use for created tables
+ Encoding string
+}
+
+func (d MySQLDialect) QuerySuffix() string { return ";" }
+
+func (d MySQLDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string {
+ switch val.Kind() {
+ case reflect.Ptr:
+ return d.ToSqlType(val.Elem(), maxsize, isAutoIncr)
+ case reflect.Bool:
+ return "boolean"
+ case reflect.Int8:
+ return "tinyint"
+ case reflect.Uint8:
+ return "tinyint unsigned"
+ case reflect.Int16:
+ return "smallint"
+ case reflect.Uint16:
+ return "smallint unsigned"
+ case reflect.Int, reflect.Int32:
+ return "int"
+ case reflect.Uint, reflect.Uint32:
+ return "int unsigned"
+ case reflect.Int64:
+ return "bigint"
+ case reflect.Uint64:
+ return "bigint unsigned"
+ case reflect.Float64, reflect.Float32:
+ return "double"
+ case reflect.Slice:
+ if val.Elem().Kind() == reflect.Uint8 {
+ return "mediumblob"
+ }
+ }
+
+ switch val.Name() {
+ case "NullInt64":
+ return "bigint"
+ case "NullFloat64":
+ return "double"
+ case "NullBool":
+ return "tinyint"
+ case "Time":
+ return "datetime"
+ }
+
+ if maxsize < 1 {
+ maxsize = 255
+ }
+
+ /* == About varchar(N) ==
+ * N is number of characters.
+ * A varchar column can store up to 65535 bytes.
+ * Remember that 1 character is 3 bytes in utf-8 charset.
+ * Also remember that each row can store up to 65535 bytes,
+ * and you have some overheads, so it's not possible for a
+ * varchar column to have 65535/3 characters really.
+ * So it would be better to use 'text' type in stead of
+ * large varchar type.
+ */
+ if maxsize < 256 {
+ return fmt.Sprintf("varchar(%d)", maxsize)
+ } else {
+ return "text"
+ }
+}
+
+// Returns auto_increment
+func (d MySQLDialect) AutoIncrStr() string {
+ return "auto_increment"
+}
+
+func (d MySQLDialect) AutoIncrBindValue() string {
+ return "null"
+}
+
+func (d MySQLDialect) AutoIncrInsertSuffix(col *ColumnMap) string {
+ return ""
+}
+
+// Returns engine=%s charset=%s based on values stored on struct
+func (d MySQLDialect) CreateTableSuffix() string {
+ if d.Engine == "" || d.Encoding == "" {
+ msg := "gorp - undefined"
+
+ if d.Engine == "" {
+ msg += " MySQLDialect.Engine"
+ }
+ if d.Engine == "" && d.Encoding == "" {
+ msg += ","
+ }
+ if d.Encoding == "" {
+ msg += " MySQLDialect.Encoding"
+ }
+ msg += ". Check that your MySQLDialect was correctly initialized when declared."
+ panic(msg)
+ }
+
+ return fmt.Sprintf(" engine=%s charset=%s", d.Engine, d.Encoding)
+}
+
+func (d MySQLDialect) CreateIndexSuffix() string {
+ return "using"
+}
+
+func (d MySQLDialect) DropIndexSuffix() string {
+ return "on"
+}
+
+func (d MySQLDialect) TruncateClause() string {
+ return "truncate"
+}
+
+func (d MySQLDialect) SleepClause(s time.Duration) string {
+ return fmt.Sprintf("sleep(%f)", s.Seconds())
+}
+
+// Returns "?"
+func (d MySQLDialect) BindVar(i int) string {
+ return "?"
+}
+
+func (d MySQLDialect) InsertAutoIncr(exec SqlExecutor, insertSql string, params ...interface{}) (int64, error) {
+ return standardInsertAutoIncr(exec, insertSql, params...)
+}
+
+func (d MySQLDialect) QuoteField(f string) string {
+ return "`" + f + "`"
+}
+
+func (d MySQLDialect) QuotedTableForQuery(schema string, table string) string {
+ if strings.TrimSpace(schema) == "" {
+ return d.QuoteField(table)
+ }
+
+ return schema + "." + d.QuoteField(table)
+}
+
+func (d MySQLDialect) IfSchemaNotExists(command, schema string) string {
+ return fmt.Sprintf("%s if not exists", command)
+}
+
+func (d MySQLDialect) IfTableExists(command, schema, table string) string {
+ return fmt.Sprintf("%s if exists", command)
+}
+
+func (d MySQLDialect) IfTableNotExists(command, schema, table string) string {
+ return fmt.Sprintf("%s if not exists", command)
+}
diff --git a/vendor/github.com/go-gorp/gorp/v3/dialect_oracle.go b/vendor/github.com/go-gorp/gorp/v3/dialect_oracle.go
new file mode 100644
index 0000000000..01a99b8a19
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/dialect_oracle.go
@@ -0,0 +1,139 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package gorp
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+)
+
+// Implementation of Dialect for Oracle databases.
+type OracleDialect struct{}
+
+func (d OracleDialect) QuerySuffix() string { return "" }
+
+func (d OracleDialect) CreateIndexSuffix() string { return "" }
+
+func (d OracleDialect) DropIndexSuffix() string { return "" }
+
+func (d OracleDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string {
+ switch val.Kind() {
+ case reflect.Ptr:
+ return d.ToSqlType(val.Elem(), maxsize, isAutoIncr)
+ case reflect.Bool:
+ return "boolean"
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
+ if isAutoIncr {
+ return "serial"
+ }
+ return "integer"
+ case reflect.Int64, reflect.Uint64:
+ if isAutoIncr {
+ return "bigserial"
+ }
+ return "bigint"
+ case reflect.Float64:
+ return "double precision"
+ case reflect.Float32:
+ return "real"
+ case reflect.Slice:
+ if val.Elem().Kind() == reflect.Uint8 {
+ return "bytea"
+ }
+ }
+
+ switch val.Name() {
+ case "NullInt64":
+ return "bigint"
+ case "NullFloat64":
+ return "double precision"
+ case "NullBool":
+ return "boolean"
+ case "NullTime", "Time":
+ return "timestamp with time zone"
+ }
+
+ if maxsize > 0 {
+ return fmt.Sprintf("varchar(%d)", maxsize)
+ } else {
+ return "text"
+ }
+
+}
+
+// Returns empty string
+func (d OracleDialect) AutoIncrStr() string {
+ return ""
+}
+
+func (d OracleDialect) AutoIncrBindValue() string {
+ return "NULL"
+}
+
+func (d OracleDialect) AutoIncrInsertSuffix(col *ColumnMap) string {
+ return ""
+}
+
+// Returns suffix
+func (d OracleDialect) CreateTableSuffix() string {
+ return ""
+}
+
+func (d OracleDialect) TruncateClause() string {
+ return "truncate"
+}
+
+// Returns "$(i+1)"
+func (d OracleDialect) BindVar(i int) string {
+ return fmt.Sprintf(":%d", i+1)
+}
+
+// After executing the insert uses the ColMap IdQuery to get the generated id
+func (d OracleDialect) InsertQueryToTarget(exec SqlExecutor, insertSql, idSql string, target interface{}, params ...interface{}) error {
+ _, err := exec.Exec(insertSql, params...)
+ if err != nil {
+ return err
+ }
+ id, err := exec.SelectInt(idSql)
+ if err != nil {
+ return err
+ }
+ switch target.(type) {
+ case *int64:
+ *(target.(*int64)) = id
+ case *int32:
+ *(target.(*int32)) = int32(id)
+ case int:
+ *(target.(*int)) = int(id)
+ default:
+ return fmt.Errorf("Id field can be int, int32 or int64")
+ }
+ return nil
+}
+
+func (d OracleDialect) QuoteField(f string) string {
+ return `"` + strings.ToUpper(f) + `"`
+}
+
+func (d OracleDialect) QuotedTableForQuery(schema string, table string) string {
+ if strings.TrimSpace(schema) == "" {
+ return d.QuoteField(table)
+ }
+
+ return schema + "." + d.QuoteField(table)
+}
+
+func (d OracleDialect) IfSchemaNotExists(command, schema string) string {
+ return fmt.Sprintf("%s if not exists", command)
+}
+
+func (d OracleDialect) IfTableExists(command, schema, table string) string {
+ return fmt.Sprintf("%s if exists", command)
+}
+
+func (d OracleDialect) IfTableNotExists(command, schema, table string) string {
+ return fmt.Sprintf("%s if not exists", command)
+}
diff --git a/vendor/github.com/go-gorp/gorp/v3/dialect_postgres.go b/vendor/github.com/go-gorp/gorp/v3/dialect_postgres.go
new file mode 100644
index 0000000000..7a9c50bf8a
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/dialect_postgres.go
@@ -0,0 +1,149 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package gorp
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+ "time"
+)
+
+type PostgresDialect struct {
+ suffix string
+ LowercaseFields bool
+}
+
+func (d PostgresDialect) QuerySuffix() string { return ";" }
+
+func (d PostgresDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string {
+ switch val.Kind() {
+ case reflect.Ptr:
+ return d.ToSqlType(val.Elem(), maxsize, isAutoIncr)
+ case reflect.Bool:
+ return "boolean"
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
+ if isAutoIncr {
+ return "serial"
+ }
+ return "integer"
+ case reflect.Int64, reflect.Uint64:
+ if isAutoIncr {
+ return "bigserial"
+ }
+ return "bigint"
+ case reflect.Float64:
+ return "double precision"
+ case reflect.Float32:
+ return "real"
+ case reflect.Slice:
+ if val.Elem().Kind() == reflect.Uint8 {
+ return "bytea"
+ }
+ }
+
+ switch val.Name() {
+ case "NullInt64":
+ return "bigint"
+ case "NullFloat64":
+ return "double precision"
+ case "NullBool":
+ return "boolean"
+ case "Time", "NullTime":
+ return "timestamp with time zone"
+ }
+
+ if maxsize > 0 {
+ return fmt.Sprintf("varchar(%d)", maxsize)
+ } else {
+ return "text"
+ }
+
+}
+
+// Returns empty string
+func (d PostgresDialect) AutoIncrStr() string {
+ return ""
+}
+
+func (d PostgresDialect) AutoIncrBindValue() string {
+ return "default"
+}
+
+func (d PostgresDialect) AutoIncrInsertSuffix(col *ColumnMap) string {
+ return " returning " + d.QuoteField(col.ColumnName)
+}
+
+// Returns suffix
+func (d PostgresDialect) CreateTableSuffix() string {
+ return d.suffix
+}
+
+func (d PostgresDialect) CreateIndexSuffix() string {
+ return "using"
+}
+
+func (d PostgresDialect) DropIndexSuffix() string {
+ return ""
+}
+
+func (d PostgresDialect) TruncateClause() string {
+ return "truncate"
+}
+
+func (d PostgresDialect) SleepClause(s time.Duration) string {
+ return fmt.Sprintf("pg_sleep(%f)", s.Seconds())
+}
+
+// Returns "$(i+1)"
+func (d PostgresDialect) BindVar(i int) string {
+ return fmt.Sprintf("$%d", i+1)
+}
+
+func (d PostgresDialect) InsertAutoIncrToTarget(exec SqlExecutor, insertSql string, target interface{}, params ...interface{}) error {
+ rows, err := exec.Query(insertSql, params...)
+ if err != nil {
+ return err
+ }
+ defer rows.Close()
+
+ if !rows.Next() {
+ return fmt.Errorf("No serial value returned for insert: %s Encountered error: %s", insertSql, rows.Err())
+ }
+ if err := rows.Scan(target); err != nil {
+ return err
+ }
+ if rows.Next() {
+ return fmt.Errorf("more than two serial value returned for insert: %s", insertSql)
+ }
+ return rows.Err()
+}
+
+func (d PostgresDialect) QuoteField(f string) string {
+ if d.LowercaseFields {
+ return `"` + strings.ToLower(f) + `"`
+ }
+ return `"` + f + `"`
+}
+
+func (d PostgresDialect) QuotedTableForQuery(schema string, table string) string {
+ if strings.TrimSpace(schema) == "" {
+ return d.QuoteField(table)
+ }
+
+ return schema + "." + d.QuoteField(table)
+}
+
+func (d PostgresDialect) IfSchemaNotExists(command, schema string) string {
+ return fmt.Sprintf("%s if not exists", command)
+}
+
+func (d PostgresDialect) IfTableExists(command, schema, table string) string {
+ return fmt.Sprintf("%s if exists", command)
+}
+
+func (d PostgresDialect) IfTableNotExists(command, schema, table string) string {
+ return fmt.Sprintf("%s if not exists", command)
+}
diff --git a/vendor/github.com/go-gorp/gorp/v3/dialect_snowflake.go b/vendor/github.com/go-gorp/gorp/v3/dialect_snowflake.go
new file mode 100644
index 0000000000..2e2cb89523
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/dialect_snowflake.go
@@ -0,0 +1,152 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package gorp
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+)
+
+type SnowflakeDialect struct {
+ suffix string
+ LowercaseFields bool
+}
+
+func (d SnowflakeDialect) QuerySuffix() string { return ";" }
+
+func (d SnowflakeDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string {
+ switch val.Kind() {
+ case reflect.Ptr:
+ return d.ToSqlType(val.Elem(), maxsize, isAutoIncr)
+ case reflect.Bool:
+ return "boolean"
+ case reflect.Int,
+ reflect.Int8,
+ reflect.Int16,
+ reflect.Int32,
+ reflect.Uint,
+ reflect.Uint8,
+ reflect.Uint16,
+ reflect.Uint32:
+
+ if isAutoIncr {
+ return "serial"
+ }
+ return "integer"
+ case reflect.Int64, reflect.Uint64:
+ if isAutoIncr {
+ return "bigserial"
+ }
+ return "bigint"
+ case reflect.Float64:
+ return "double precision"
+ case reflect.Float32:
+ return "real"
+ case reflect.Slice:
+ if val.Elem().Kind() == reflect.Uint8 {
+ return "binary"
+ }
+ }
+
+ switch val.Name() {
+ case "NullInt64":
+ return "bigint"
+ case "NullFloat64":
+ return "double precision"
+ case "NullBool":
+ return "boolean"
+ case "Time", "NullTime":
+ return "timestamp with time zone"
+ }
+
+ if maxsize > 0 {
+ return fmt.Sprintf("varchar(%d)", maxsize)
+ } else {
+ return "text"
+ }
+
+}
+
+// Returns empty string
+func (d SnowflakeDialect) AutoIncrStr() string {
+ return ""
+}
+
+func (d SnowflakeDialect) AutoIncrBindValue() string {
+ return "default"
+}
+
+func (d SnowflakeDialect) AutoIncrInsertSuffix(col *ColumnMap) string {
+ return ""
+}
+
+// Returns suffix
+func (d SnowflakeDialect) CreateTableSuffix() string {
+ return d.suffix
+}
+
+func (d SnowflakeDialect) CreateIndexSuffix() string {
+ return ""
+}
+
+func (d SnowflakeDialect) DropIndexSuffix() string {
+ return ""
+}
+
+func (d SnowflakeDialect) TruncateClause() string {
+ return "truncate"
+}
+
+// Returns "$(i+1)"
+func (d SnowflakeDialect) BindVar(i int) string {
+ return "?"
+}
+
+func (d SnowflakeDialect) InsertAutoIncrToTarget(exec SqlExecutor, insertSql string, target interface{}, params ...interface{}) error {
+ rows, err := exec.Query(insertSql, params...)
+ if err != nil {
+ return err
+ }
+ defer rows.Close()
+
+ if !rows.Next() {
+ return fmt.Errorf("No serial value returned for insert: %s Encountered error: %s", insertSql, rows.Err())
+ }
+ if err := rows.Scan(target); err != nil {
+ return err
+ }
+ if rows.Next() {
+ return fmt.Errorf("more than two serial value returned for insert: %s", insertSql)
+ }
+ return rows.Err()
+}
+
+func (d SnowflakeDialect) QuoteField(f string) string {
+ if d.LowercaseFields {
+ return `"` + strings.ToLower(f) + `"`
+ }
+ return `"` + f + `"`
+}
+
+func (d SnowflakeDialect) QuotedTableForQuery(schema string, table string) string {
+ if strings.TrimSpace(schema) == "" {
+ return d.QuoteField(table)
+ }
+
+ return schema + "." + d.QuoteField(table)
+}
+
+func (d SnowflakeDialect) IfSchemaNotExists(command, schema string) string {
+ return fmt.Sprintf("%s if not exists", command)
+}
+
+func (d SnowflakeDialect) IfTableExists(command, schema, table string) string {
+ return fmt.Sprintf("%s if exists", command)
+}
+
+func (d SnowflakeDialect) IfTableNotExists(command, schema, table string) string {
+ return fmt.Sprintf("%s if not exists", command)
+}
diff --git a/vendor/github.com/go-gorp/gorp/v3/dialect_sqlite.go b/vendor/github.com/go-gorp/gorp/v3/dialect_sqlite.go
new file mode 100644
index 0000000000..2296275b95
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/dialect_sqlite.go
@@ -0,0 +1,112 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package gorp
+
+import (
+ "fmt"
+ "reflect"
+)
+
+type SqliteDialect struct {
+ suffix string
+}
+
+func (d SqliteDialect) QuerySuffix() string { return ";" }
+
+func (d SqliteDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string {
+ switch val.Kind() {
+ case reflect.Ptr:
+ return d.ToSqlType(val.Elem(), maxsize, isAutoIncr)
+ case reflect.Bool:
+ return "integer"
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ return "integer"
+ case reflect.Float64, reflect.Float32:
+ return "real"
+ case reflect.Slice:
+ if val.Elem().Kind() == reflect.Uint8 {
+ return "blob"
+ }
+ }
+
+ switch val.Name() {
+ case "NullInt64":
+ return "integer"
+ case "NullFloat64":
+ return "real"
+ case "NullBool":
+ return "integer"
+ case "Time":
+ return "datetime"
+ }
+
+ if maxsize < 1 {
+ maxsize = 255
+ }
+ return fmt.Sprintf("varchar(%d)", maxsize)
+}
+
+// Returns autoincrement
+func (d SqliteDialect) AutoIncrStr() string {
+ return "autoincrement"
+}
+
+func (d SqliteDialect) AutoIncrBindValue() string {
+ return "null"
+}
+
+func (d SqliteDialect) AutoIncrInsertSuffix(col *ColumnMap) string {
+ return ""
+}
+
+// Returns suffix
+func (d SqliteDialect) CreateTableSuffix() string {
+ return d.suffix
+}
+
+func (d SqliteDialect) CreateIndexSuffix() string {
+ return ""
+}
+
+func (d SqliteDialect) DropIndexSuffix() string {
+ return ""
+}
+
+// With sqlite, there technically isn't a TRUNCATE statement,
+// but a DELETE FROM uses a truncate optimization:
+// http://www.sqlite.org/lang_delete.html
+func (d SqliteDialect) TruncateClause() string {
+ return "delete from"
+}
+
+// Returns "?"
+func (d SqliteDialect) BindVar(i int) string {
+ return "?"
+}
+
+func (d SqliteDialect) InsertAutoIncr(exec SqlExecutor, insertSql string, params ...interface{}) (int64, error) {
+ return standardInsertAutoIncr(exec, insertSql, params...)
+}
+
+func (d SqliteDialect) QuoteField(f string) string {
+ return `"` + f + `"`
+}
+
+// sqlite does not have schemas like PostgreSQL does, so just escape it like normal
+func (d SqliteDialect) QuotedTableForQuery(schema string, table string) string {
+ return d.QuoteField(table)
+}
+
+func (d SqliteDialect) IfSchemaNotExists(command, schema string) string {
+ return fmt.Sprintf("%s if not exists", command)
+}
+
+func (d SqliteDialect) IfTableExists(command, schema, table string) string {
+ return fmt.Sprintf("%s if exists", command)
+}
+
+func (d SqliteDialect) IfTableNotExists(command, schema, table string) string {
+ return fmt.Sprintf("%s if not exists", command)
+}
diff --git a/vendor/github.com/go-gorp/gorp/v3/dialect_sqlserver.go b/vendor/github.com/go-gorp/gorp/v3/dialect_sqlserver.go
new file mode 100644
index 0000000000..ec06aed66f
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/dialect_sqlserver.go
@@ -0,0 +1,145 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package gorp
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+)
+
+// Implementation of Dialect for Microsoft SQL Server databases.
+// Use gorp.SqlServerDialect{"2005"} for legacy datatypes.
+// Tested with driver: github.com/denisenkom/go-mssqldb
+
+type SqlServerDialect struct {
+
+ // If set to "2005" legacy datatypes will be used
+ Version string
+}
+
+func (d SqlServerDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string {
+ switch val.Kind() {
+ case reflect.Ptr:
+ return d.ToSqlType(val.Elem(), maxsize, isAutoIncr)
+ case reflect.Bool:
+ return "bit"
+ case reflect.Int8:
+ return "tinyint"
+ case reflect.Uint8:
+ return "smallint"
+ case reflect.Int16:
+ return "smallint"
+ case reflect.Uint16:
+ return "int"
+ case reflect.Int, reflect.Int32:
+ return "int"
+ case reflect.Uint, reflect.Uint32:
+ return "bigint"
+ case reflect.Int64:
+ return "bigint"
+ case reflect.Uint64:
+ return "numeric(20,0)"
+ case reflect.Float32:
+ return "float(24)"
+ case reflect.Float64:
+ return "float(53)"
+ case reflect.Slice:
+ if val.Elem().Kind() == reflect.Uint8 {
+ return "varbinary"
+ }
+ }
+
+ switch val.Name() {
+ case "NullInt64":
+ return "bigint"
+ case "NullFloat64":
+ return "float(53)"
+ case "NullBool":
+ return "bit"
+ case "NullTime", "Time":
+ if d.Version == "2005" {
+ return "datetime"
+ }
+ return "datetime2"
+ }
+
+ if maxsize < 1 {
+ if d.Version == "2005" {
+ maxsize = 255
+ } else {
+ return fmt.Sprintf("nvarchar(max)")
+ }
+ }
+ return fmt.Sprintf("nvarchar(%d)", maxsize)
+}
+
+// Returns auto_increment
+func (d SqlServerDialect) AutoIncrStr() string {
+ return "identity(0,1)"
+}
+
+// Empty string removes autoincrement columns from the INSERT statements.
+func (d SqlServerDialect) AutoIncrBindValue() string {
+ return ""
+}
+
+func (d SqlServerDialect) AutoIncrInsertSuffix(col *ColumnMap) string {
+ return ""
+}
+
+func (d SqlServerDialect) CreateTableSuffix() string { return ";" }
+
+func (d SqlServerDialect) TruncateClause() string {
+ return "truncate table"
+}
+
+// Returns "?"
+func (d SqlServerDialect) BindVar(i int) string {
+ return "?"
+}
+
+func (d SqlServerDialect) InsertAutoIncr(exec SqlExecutor, insertSql string, params ...interface{}) (int64, error) {
+ return standardInsertAutoIncr(exec, insertSql, params...)
+}
+
+func (d SqlServerDialect) QuoteField(f string) string {
+ return "[" + strings.Replace(f, "]", "]]", -1) + "]"
+}
+
+func (d SqlServerDialect) QuotedTableForQuery(schema string, table string) string {
+ if strings.TrimSpace(schema) == "" {
+ return d.QuoteField(table)
+ }
+ return d.QuoteField(schema) + "." + d.QuoteField(table)
+}
+
+func (d SqlServerDialect) QuerySuffix() string { return ";" }
+
+func (d SqlServerDialect) IfSchemaNotExists(command, schema string) string {
+ s := fmt.Sprintf("if schema_id(N'%s') is null %s", schema, command)
+ return s
+}
+
+func (d SqlServerDialect) IfTableExists(command, schema, table string) string {
+ var schema_clause string
+ if strings.TrimSpace(schema) != "" {
+ schema_clause = fmt.Sprintf("%s.", d.QuoteField(schema))
+ }
+ s := fmt.Sprintf("if object_id('%s%s') is not null %s", schema_clause, d.QuoteField(table), command)
+ return s
+}
+
+func (d SqlServerDialect) IfTableNotExists(command, schema, table string) string {
+ var schema_clause string
+ if strings.TrimSpace(schema) != "" {
+ schema_clause = fmt.Sprintf("%s.", schema)
+ }
+ s := fmt.Sprintf("if object_id('%s%s') is null %s", schema_clause, table, command)
+ return s
+}
+
+func (d SqlServerDialect) CreateIndexSuffix() string { return "" }
+func (d SqlServerDialect) DropIndexSuffix() string { return "" }
diff --git a/vendor/github.com/go-gorp/gorp/v3/doc.go b/vendor/github.com/go-gorp/gorp/v3/doc.go
new file mode 100644
index 0000000000..593f1c3c12
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/doc.go
@@ -0,0 +1,11 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+// Package gorp provides a simple way to marshal Go structs to and from
+// SQL databases. It uses the database/sql package, and should work with any
+// compliant database/sql driver.
+//
+// Source code and project home:
+// https://github.com/go-gorp/gorp
+package gorp
diff --git a/vendor/github.com/go-gorp/gorp/v3/errors.go b/vendor/github.com/go-gorp/gorp/v3/errors.go
new file mode 100644
index 0000000000..752ad1bca4
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/errors.go
@@ -0,0 +1,31 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package gorp
+
+import (
+ "fmt"
+)
+
+// A non-fatal error, when a select query returns columns that do not exist
+// as fields in the struct it is being mapped to
+// TODO: discuss wether this needs an error. encoding/json silently ignores missing fields
+type NoFieldInTypeError struct {
+ TypeName string
+ MissingColNames []string
+}
+
+func (err *NoFieldInTypeError) Error() string {
+ return fmt.Sprintf("gorp: no fields %+v in type %s", err.MissingColNames, err.TypeName)
+}
+
+// returns true if the error is non-fatal (ie, we shouldn't immediately return)
+func NonFatalError(err error) bool {
+ switch err.(type) {
+ case *NoFieldInTypeError:
+ return true
+ default:
+ return false
+ }
+}
diff --git a/vendor/github.com/go-gorp/gorp/v3/gorp.go b/vendor/github.com/go-gorp/gorp/v3/gorp.go
new file mode 100644
index 0000000000..fc6545676d
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/gorp.go
@@ -0,0 +1,672 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package gorp
+
+import (
+ "context"
+ "database/sql"
+ "database/sql/driver"
+ "fmt"
+ "reflect"
+ "regexp"
+ "strings"
+ "time"
+)
+
+// OracleString (empty string is null)
+// TODO: move to dialect/oracle?, rename to String?
+type OracleString struct {
+ sql.NullString
+}
+
+// Scan implements the Scanner interface.
+func (os *OracleString) Scan(value interface{}) error {
+ if value == nil {
+ os.String, os.Valid = "", false
+ return nil
+ }
+ os.Valid = true
+ return os.NullString.Scan(value)
+}
+
+// Value implements the driver Valuer interface.
+func (os OracleString) Value() (driver.Value, error) {
+ if !os.Valid || os.String == "" {
+ return nil, nil
+ }
+ return os.String, nil
+}
+
+// SqlTyper is a type that returns its database type. Most of the
+// time, the type can just use "database/sql/driver".Valuer; but when
+// it returns nil for its empty value, it needs to implement SqlTyper
+// to have its column type detected properly during table creation.
+type SqlTyper interface {
+ SqlType() driver.Value
+}
+
+// legacySqlTyper prevents breaking clients who depended on the previous
+// SqlTyper interface
+type legacySqlTyper interface {
+ SqlType() driver.Valuer
+}
+
+// for fields that exists in DB table, but not exists in struct
+type dummyField struct{}
+
+// Scan implements the Scanner interface.
+func (nt *dummyField) Scan(value interface{}) error {
+ return nil
+}
+
+var zeroVal reflect.Value
+var versFieldConst = "[gorp_ver_field]"
+
+// The TypeConverter interface provides a way to map a value of one
+// type to another type when persisting to, or loading from, a database.
+//
+// Example use cases: Implement type converter to convert bool types to "y"/"n" strings,
+// or serialize a struct member as a JSON blob.
+type TypeConverter interface {
+ // ToDb converts val to another type. Called before INSERT/UPDATE operations
+ ToDb(val interface{}) (interface{}, error)
+
+ // FromDb returns a CustomScanner appropriate for this type. This will be used
+ // to hold values returned from SELECT queries.
+ //
+ // In particular the CustomScanner returned should implement a Binder
+ // function appropriate for the Go type you wish to convert the db value to
+ //
+ // If bool==false, then no custom scanner will be used for this field.
+ FromDb(target interface{}) (CustomScanner, bool)
+}
+
+// SqlExecutor exposes gorp operations that can be run from Pre/Post
+// hooks. This hides whether the current operation that triggered the
+// hook is in a transaction.
+//
+// See the DbMap function docs for each of the functions below for more
+// information.
+type SqlExecutor interface {
+ WithContext(ctx context.Context) SqlExecutor
+ Get(i interface{}, keys ...interface{}) (interface{}, error)
+ Insert(list ...interface{}) error
+ Update(list ...interface{}) (int64, error)
+ Delete(list ...interface{}) (int64, error)
+ Exec(query string, args ...interface{}) (sql.Result, error)
+ Select(i interface{}, query string, args ...interface{}) ([]interface{}, error)
+ SelectInt(query string, args ...interface{}) (int64, error)
+ SelectNullInt(query string, args ...interface{}) (sql.NullInt64, error)
+ SelectFloat(query string, args ...interface{}) (float64, error)
+ SelectNullFloat(query string, args ...interface{}) (sql.NullFloat64, error)
+ SelectStr(query string, args ...interface{}) (string, error)
+ SelectNullStr(query string, args ...interface{}) (sql.NullString, error)
+ SelectOne(holder interface{}, query string, args ...interface{}) error
+ Query(query string, args ...interface{}) (*sql.Rows, error)
+ QueryRow(query string, args ...interface{}) *sql.Row
+}
+
+// DynamicTable allows the users of gorp to dynamically
+// use different database table names during runtime
+// while sharing the same golang struct for in-memory data
+type DynamicTable interface {
+ TableName() string
+ SetTableName(string)
+}
+
+// Compile-time check that DbMap and Transaction implement the SqlExecutor
+// interface.
+var _, _ SqlExecutor = &DbMap{}, &Transaction{}
+
+func argValue(a interface{}) interface{} {
+ v, ok := a.(driver.Valuer)
+ if !ok {
+ return a
+ }
+ vV := reflect.ValueOf(v)
+ if vV.Kind() == reflect.Ptr && vV.IsNil() {
+ return nil
+ }
+ ret, err := v.Value()
+ if err != nil {
+ return a
+ }
+ return ret
+}
+
+func argsString(args ...interface{}) string {
+ var margs string
+ for i, a := range args {
+ v := argValue(a)
+ switch v.(type) {
+ case string:
+ v = fmt.Sprintf("%q", v)
+ default:
+ v = fmt.Sprintf("%v", v)
+ }
+ margs += fmt.Sprintf("%d:%s", i+1, v)
+ if i+1 < len(args) {
+ margs += " "
+ }
+ }
+ return margs
+}
+
+// Calls the Exec function on the executor, but attempts to expand any eligible named
+// query arguments first.
+func maybeExpandNamedQueryAndExec(e SqlExecutor, query string, args ...interface{}) (sql.Result, error) {
+ dbMap := extractDbMap(e)
+
+ if len(args) == 1 {
+ query, args = maybeExpandNamedQuery(dbMap, query, args)
+ }
+
+ return exec(e, query, args...)
+}
+
+func extractDbMap(e SqlExecutor) *DbMap {
+ switch m := e.(type) {
+ case *DbMap:
+ return m
+ case *Transaction:
+ return m.dbmap
+ }
+ return nil
+}
+
+// executor exposes the sql.DB and sql.Tx functions so that it can be used
+// on internal functions that need to be agnostic to the underlying object.
+type executor interface {
+ Exec(query string, args ...interface{}) (sql.Result, error)
+ Prepare(query string) (*sql.Stmt, error)
+ QueryRow(query string, args ...interface{}) *sql.Row
+ Query(query string, args ...interface{}) (*sql.Rows, error)
+ ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
+ PrepareContext(ctx context.Context, query string) (*sql.Stmt, error)
+ QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row
+ QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
+}
+
+func extractExecutorAndContext(e SqlExecutor) (executor, context.Context) {
+ switch m := e.(type) {
+ case *DbMap:
+ return m.Db, m.ctx
+ case *Transaction:
+ return m.tx, m.ctx
+ }
+ return nil, nil
+}
+
+// maybeExpandNamedQuery checks the given arg to see if it's eligible to be used
+// as input to a named query. If so, it rewrites the query to use
+// dialect-dependent bindvars and instantiates the corresponding slice of
+// parameters by extracting data from the map / struct.
+// If not, returns the input values unchanged.
+func maybeExpandNamedQuery(m *DbMap, query string, args []interface{}) (string, []interface{}) {
+ var (
+ arg = args[0]
+ argval = reflect.ValueOf(arg)
+ )
+ if argval.Kind() == reflect.Ptr {
+ argval = argval.Elem()
+ }
+
+ if argval.Kind() == reflect.Map && argval.Type().Key().Kind() == reflect.String {
+ return expandNamedQuery(m, query, func(key string) reflect.Value {
+ return argval.MapIndex(reflect.ValueOf(key))
+ })
+ }
+ if argval.Kind() != reflect.Struct {
+ return query, args
+ }
+ if _, ok := arg.(time.Time); ok {
+ // time.Time is driver.Value
+ return query, args
+ }
+ if _, ok := arg.(driver.Valuer); ok {
+ // driver.Valuer will be converted to driver.Value.
+ return query, args
+ }
+
+ return expandNamedQuery(m, query, argval.FieldByName)
+}
+
+var keyRegexp = regexp.MustCompile(`:[[:word:]]+`)
+
+// expandNamedQuery accepts a query with placeholders of the form ":key", and a
+// single arg of Kind Struct or Map[string]. It returns the query with the
+// dialect's placeholders, and a slice of args ready for positional insertion
+// into the query.
+func expandNamedQuery(m *DbMap, query string, keyGetter func(key string) reflect.Value) (string, []interface{}) {
+ var (
+ n int
+ args []interface{}
+ )
+ return keyRegexp.ReplaceAllStringFunc(query, func(key string) string {
+ val := keyGetter(key[1:])
+ if !val.IsValid() {
+ return key
+ }
+ args = append(args, val.Interface())
+ newVar := m.Dialect.BindVar(n)
+ n++
+ return newVar
+ }), args
+}
+
+func columnToFieldIndex(m *DbMap, t reflect.Type, name string, cols []string) ([][]int, error) {
+ colToFieldIndex := make([][]int, len(cols))
+
+ // check if type t is a mapped table - if so we'll
+ // check the table for column aliasing below
+ tableMapped := false
+ table := tableOrNil(m, t, name)
+ if table != nil {
+ tableMapped = true
+ }
+
+ // Loop over column names and find field in i to bind to
+ // based on column name. all returned columns must match
+ // a field in the i struct
+ missingColNames := []string{}
+ for x := range cols {
+ colName := strings.ToLower(cols[x])
+ field, found := t.FieldByNameFunc(func(fieldName string) bool {
+ field, _ := t.FieldByName(fieldName)
+ cArguments := strings.Split(field.Tag.Get("db"), ",")
+ fieldName = cArguments[0]
+
+ if fieldName == "-" {
+ return false
+ } else if fieldName == "" {
+ fieldName = field.Name
+ }
+ if tableMapped {
+ colMap := colMapOrNil(table, fieldName)
+ if colMap != nil {
+ fieldName = colMap.ColumnName
+ }
+ }
+ return colName == strings.ToLower(fieldName)
+ })
+ if found {
+ colToFieldIndex[x] = field.Index
+ }
+ if colToFieldIndex[x] == nil {
+ missingColNames = append(missingColNames, colName)
+ }
+ }
+ if len(missingColNames) > 0 {
+ return colToFieldIndex, &NoFieldInTypeError{
+ TypeName: t.Name(),
+ MissingColNames: missingColNames,
+ }
+ }
+ return colToFieldIndex, nil
+}
+
+func fieldByName(val reflect.Value, fieldName string) *reflect.Value {
+ // try to find field by exact match
+ f := val.FieldByName(fieldName)
+
+ if f != zeroVal {
+ return &f
+ }
+
+ // try to find by case insensitive match - only the Postgres driver
+ // seems to require this - in the case where columns are aliased in the sql
+ fieldNameL := strings.ToLower(fieldName)
+ fieldCount := val.NumField()
+ t := val.Type()
+ for i := 0; i < fieldCount; i++ {
+ sf := t.Field(i)
+ if strings.ToLower(sf.Name) == fieldNameL {
+ f := val.Field(i)
+ return &f
+ }
+ }
+
+ return nil
+}
+
+// toSliceType returns the element type of the given object, if the object is a
+// "*[]*Element" or "*[]Element". If not, returns nil.
+// err is returned if the user was trying to pass a pointer-to-slice but failed.
+func toSliceType(i interface{}) (reflect.Type, error) {
+ t := reflect.TypeOf(i)
+ if t.Kind() != reflect.Ptr {
+ // If it's a slice, return a more helpful error message
+ if t.Kind() == reflect.Slice {
+ return nil, fmt.Errorf("gorp: cannot SELECT into a non-pointer slice: %v", t)
+ }
+ return nil, nil
+ }
+ if t = t.Elem(); t.Kind() != reflect.Slice {
+ return nil, nil
+ }
+ return t.Elem(), nil
+}
+
+func toType(i interface{}) (reflect.Type, error) {
+ t := reflect.TypeOf(i)
+
+ // If a Pointer to a type, follow
+ for t.Kind() == reflect.Ptr {
+ t = t.Elem()
+ }
+
+ if t.Kind() != reflect.Struct {
+ return nil, fmt.Errorf("gorp: cannot SELECT into this type: %v", reflect.TypeOf(i))
+ }
+ return t, nil
+}
+
+type foundTable struct {
+ table *TableMap
+ dynName *string
+}
+
+func tableFor(m *DbMap, t reflect.Type, i interface{}) (*foundTable, error) {
+ if dyn, isDynamic := i.(DynamicTable); isDynamic {
+ tableName := dyn.TableName()
+ table, err := m.DynamicTableFor(tableName, true)
+ if err != nil {
+ return nil, err
+ }
+ return &foundTable{
+ table: table,
+ dynName: &tableName,
+ }, nil
+ }
+ table, err := m.TableFor(t, true)
+ if err != nil {
+ return nil, err
+ }
+ return &foundTable{table: table}, nil
+}
+
+func get(m *DbMap, exec SqlExecutor, i interface{},
+ keys ...interface{}) (interface{}, error) {
+
+ t, err := toType(i)
+ if err != nil {
+ return nil, err
+ }
+
+ foundTable, err := tableFor(m, t, i)
+ if err != nil {
+ return nil, err
+ }
+ table := foundTable.table
+
+ plan := table.bindGet()
+
+ v := reflect.New(t)
+ if foundTable.dynName != nil {
+ retDyn := v.Interface().(DynamicTable)
+ retDyn.SetTableName(*foundTable.dynName)
+ }
+
+ dest := make([]interface{}, len(plan.argFields))
+
+ conv := m.TypeConverter
+ custScan := make([]CustomScanner, 0)
+
+ for x, fieldName := range plan.argFields {
+ f := v.Elem().FieldByName(fieldName)
+ target := f.Addr().Interface()
+ if conv != nil {
+ scanner, ok := conv.FromDb(target)
+ if ok {
+ target = scanner.Holder
+ custScan = append(custScan, scanner)
+ }
+ }
+ dest[x] = target
+ }
+
+ row := exec.QueryRow(plan.query, keys...)
+ err = row.Scan(dest...)
+ if err != nil {
+ if err == sql.ErrNoRows {
+ err = nil
+ }
+ return nil, err
+ }
+
+ for _, c := range custScan {
+ err = c.Bind()
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if v, ok := v.Interface().(HasPostGet); ok {
+ err := v.PostGet(exec)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return v.Interface(), nil
+}
+
+func delete(m *DbMap, exec SqlExecutor, list ...interface{}) (int64, error) {
+ count := int64(0)
+ for _, ptr := range list {
+ table, elem, err := m.tableForPointer(ptr, true)
+ if err != nil {
+ return -1, err
+ }
+
+ eval := elem.Addr().Interface()
+ if v, ok := eval.(HasPreDelete); ok {
+ err = v.PreDelete(exec)
+ if err != nil {
+ return -1, err
+ }
+ }
+
+ bi, err := table.bindDelete(elem)
+ if err != nil {
+ return -1, err
+ }
+
+ res, err := exec.Exec(bi.query, bi.args...)
+ if err != nil {
+ return -1, err
+ }
+ rows, err := res.RowsAffected()
+ if err != nil {
+ return -1, err
+ }
+
+ if rows == 0 && bi.existingVersion > 0 {
+ return lockError(m, exec, table.TableName,
+ bi.existingVersion, elem, bi.keys...)
+ }
+
+ count += rows
+
+ if v, ok := eval.(HasPostDelete); ok {
+ err := v.PostDelete(exec)
+ if err != nil {
+ return -1, err
+ }
+ }
+ }
+
+ return count, nil
+}
+
+func update(m *DbMap, exec SqlExecutor, colFilter ColumnFilter, list ...interface{}) (int64, error) {
+ count := int64(0)
+ for _, ptr := range list {
+ table, elem, err := m.tableForPointer(ptr, true)
+ if err != nil {
+ return -1, err
+ }
+
+ eval := elem.Addr().Interface()
+ if v, ok := eval.(HasPreUpdate); ok {
+ err = v.PreUpdate(exec)
+ if err != nil {
+ return -1, err
+ }
+ }
+
+ bi, err := table.bindUpdate(elem, colFilter)
+ if err != nil {
+ return -1, err
+ }
+
+ res, err := exec.Exec(bi.query, bi.args...)
+ if err != nil {
+ return -1, err
+ }
+
+ rows, err := res.RowsAffected()
+ if err != nil {
+ return -1, err
+ }
+
+ if rows == 0 && bi.existingVersion > 0 {
+ return lockError(m, exec, table.TableName,
+ bi.existingVersion, elem, bi.keys...)
+ }
+
+ if bi.versField != "" {
+ elem.FieldByName(bi.versField).SetInt(bi.existingVersion + 1)
+ }
+
+ count += rows
+
+ if v, ok := eval.(HasPostUpdate); ok {
+ err = v.PostUpdate(exec)
+ if err != nil {
+ return -1, err
+ }
+ }
+ }
+ return count, nil
+}
+
+func insert(m *DbMap, exec SqlExecutor, list ...interface{}) error {
+ for _, ptr := range list {
+ table, elem, err := m.tableForPointer(ptr, false)
+ if err != nil {
+ return err
+ }
+
+ eval := elem.Addr().Interface()
+ if v, ok := eval.(HasPreInsert); ok {
+ err := v.PreInsert(exec)
+ if err != nil {
+ return err
+ }
+ }
+
+ bi, err := table.bindInsert(elem)
+ if err != nil {
+ return err
+ }
+
+ if bi.autoIncrIdx > -1 {
+ f := elem.FieldByName(bi.autoIncrFieldName)
+ switch inserter := m.Dialect.(type) {
+ case IntegerAutoIncrInserter:
+ id, err := inserter.InsertAutoIncr(exec, bi.query, bi.args...)
+ if err != nil {
+ return err
+ }
+ k := f.Kind()
+ if (k == reflect.Int) || (k == reflect.Int16) || (k == reflect.Int32) || (k == reflect.Int64) {
+ f.SetInt(id)
+ } else if (k == reflect.Uint) || (k == reflect.Uint16) || (k == reflect.Uint32) || (k == reflect.Uint64) {
+ f.SetUint(uint64(id))
+ } else {
+ return fmt.Errorf("gorp: cannot set autoincrement value on non-Int field. SQL=%s autoIncrIdx=%d autoIncrFieldName=%s", bi.query, bi.autoIncrIdx, bi.autoIncrFieldName)
+ }
+ case TargetedAutoIncrInserter:
+ err := inserter.InsertAutoIncrToTarget(exec, bi.query, f.Addr().Interface(), bi.args...)
+ if err != nil {
+ return err
+ }
+ case TargetQueryInserter:
+ var idQuery = table.ColMap(bi.autoIncrFieldName).GeneratedIdQuery
+ if idQuery == "" {
+ return fmt.Errorf("gorp: cannot set %s value if its ColumnMap.GeneratedIdQuery is empty", bi.autoIncrFieldName)
+ }
+ err := inserter.InsertQueryToTarget(exec, bi.query, idQuery, f.Addr().Interface(), bi.args...)
+ if err != nil {
+ return err
+ }
+ default:
+ return fmt.Errorf("gorp: cannot use autoincrement fields on dialects that do not implement an autoincrementing interface")
+ }
+ } else {
+ _, err := exec.Exec(bi.query, bi.args...)
+ if err != nil {
+ return err
+ }
+ }
+
+ if v, ok := eval.(HasPostInsert); ok {
+ err := v.PostInsert(exec)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func exec(e SqlExecutor, query string, args ...interface{}) (sql.Result, error) {
+ executor, ctx := extractExecutorAndContext(e)
+
+ if ctx != nil {
+ return executor.ExecContext(ctx, query, args...)
+ }
+
+ return executor.Exec(query, args...)
+}
+
+func prepare(e SqlExecutor, query string) (*sql.Stmt, error) {
+ executor, ctx := extractExecutorAndContext(e)
+
+ if ctx != nil {
+ return executor.PrepareContext(ctx, query)
+ }
+
+ return executor.Prepare(query)
+}
+
+func queryRow(e SqlExecutor, query string, args ...interface{}) *sql.Row {
+ executor, ctx := extractExecutorAndContext(e)
+
+ if ctx != nil {
+ return executor.QueryRowContext(ctx, query, args...)
+ }
+
+ return executor.QueryRow(query, args...)
+}
+
+func query(e SqlExecutor, query string, args ...interface{}) (*sql.Rows, error) {
+ executor, ctx := extractExecutorAndContext(e)
+
+ if ctx != nil {
+ return executor.QueryContext(ctx, query, args...)
+ }
+
+ return executor.Query(query, args...)
+}
+
+func begin(m *DbMap) (*sql.Tx, error) {
+ if m.ctx != nil {
+ return m.Db.BeginTx(m.ctx, nil)
+ }
+
+ return m.Db.Begin()
+}
diff --git a/vendor/github.com/go-gorp/gorp/v3/hooks.go b/vendor/github.com/go-gorp/gorp/v3/hooks.go
new file mode 100644
index 0000000000..1e80bca7ee
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/hooks.go
@@ -0,0 +1,42 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package gorp
+
+//++ TODO v2-phase3: HasPostGet => PostGetter, HasPostDelete => PostDeleter, etc.
+
+// HasPostGet provides PostGet() which will be executed after the GET statement.
+type HasPostGet interface {
+ PostGet(SqlExecutor) error
+}
+
+// HasPostDelete provides PostDelete() which will be executed after the DELETE statement
+type HasPostDelete interface {
+ PostDelete(SqlExecutor) error
+}
+
+// HasPostUpdate provides PostUpdate() which will be executed after the UPDATE statement
+type HasPostUpdate interface {
+ PostUpdate(SqlExecutor) error
+}
+
+// HasPostInsert provides PostInsert() which will be executed after the INSERT statement
+type HasPostInsert interface {
+ PostInsert(SqlExecutor) error
+}
+
+// HasPreDelete provides PreDelete() which will be executed before the DELETE statement.
+type HasPreDelete interface {
+ PreDelete(SqlExecutor) error
+}
+
+// HasPreUpdate provides PreUpdate() which will be executed before UPDATE statement.
+type HasPreUpdate interface {
+ PreUpdate(SqlExecutor) error
+}
+
+// HasPreInsert provides PreInsert() which will be executed before INSERT statement.
+type HasPreInsert interface {
+ PreInsert(SqlExecutor) error
+}
diff --git a/vendor/github.com/go-gorp/gorp/v3/index.go b/vendor/github.com/go-gorp/gorp/v3/index.go
new file mode 100644
index 0000000000..df1cf55205
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/index.go
@@ -0,0 +1,49 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package gorp
+
+// IndexMap represents a mapping between a Go struct field and a single
+// index in a table.
+// Unique and MaxSize only inform the
+// CreateTables() function and are not used by Insert/Update/Delete/Get.
+type IndexMap struct {
+ // Index name in db table
+ IndexName string
+
+ // If true, " unique" is added to create index statements.
+ // Not used elsewhere
+ Unique bool
+
+ // Index type supported by Dialect
+ // Postgres: B-tree, Hash, GiST and GIN.
+ // Mysql: Btree, Hash.
+ // Sqlite: nil.
+ IndexType string
+
+ // Columns name for single and multiple indexes
+ columns []string
+}
+
+// Rename allows you to specify the index name in the table
+//
+// Example: table.IndMap("customer_test_idx").Rename("customer_idx")
+//
+func (idx *IndexMap) Rename(indname string) *IndexMap {
+ idx.IndexName = indname
+ return idx
+}
+
+// SetUnique adds "unique" to the create index statements for this
+// index, if b is true.
+func (idx *IndexMap) SetUnique(b bool) *IndexMap {
+ idx.Unique = b
+ return idx
+}
+
+// SetIndexType specifies the index type supported by chousen SQL Dialect
+func (idx *IndexMap) SetIndexType(indtype string) *IndexMap {
+ idx.IndexType = indtype
+ return idx
+}
diff --git a/vendor/github.com/go-gorp/gorp/v3/lockerror.go b/vendor/github.com/go-gorp/gorp/v3/lockerror.go
new file mode 100644
index 0000000000..7e81891e2b
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/lockerror.go
@@ -0,0 +1,56 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package gorp
+
+import (
+ "fmt"
+ "reflect"
+)
+
+// OptimisticLockError is returned by Update() or Delete() if the
+// struct being modified has a Version field and the value is not equal to
+// the current value in the database
+type OptimisticLockError struct {
+ // Table name where the lock error occurred
+ TableName string
+
+ // Primary key values of the row being updated/deleted
+ Keys []interface{}
+
+ // true if a row was found with those keys, indicating the
+ // LocalVersion is stale. false if no value was found with those
+ // keys, suggesting the row has been deleted since loaded, or
+ // was never inserted to begin with
+ RowExists bool
+
+ // Version value on the struct passed to Update/Delete. This value is
+ // out of sync with the database.
+ LocalVersion int64
+}
+
+// Error returns a description of the cause of the lock error
+func (e OptimisticLockError) Error() string {
+ if e.RowExists {
+ return fmt.Sprintf("gorp: OptimisticLockError table=%s keys=%v out of date version=%d", e.TableName, e.Keys, e.LocalVersion)
+ }
+
+ return fmt.Sprintf("gorp: OptimisticLockError no row found for table=%s keys=%v", e.TableName, e.Keys)
+}
+
+func lockError(m *DbMap, exec SqlExecutor, tableName string,
+ existingVer int64, elem reflect.Value,
+ keys ...interface{}) (int64, error) {
+
+ existing, err := get(m, exec, elem.Interface(), keys...)
+ if err != nil {
+ return -1, err
+ }
+
+ ole := OptimisticLockError{tableName, keys, true, existingVer}
+ if existing == nil {
+ ole.RowExists = false
+ }
+ return -1, ole
+}
diff --git a/vendor/github.com/go-gorp/gorp/v3/logging.go b/vendor/github.com/go-gorp/gorp/v3/logging.go
new file mode 100644
index 0000000000..e8cba3db2c
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/logging.go
@@ -0,0 +1,42 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package gorp
+
+import "fmt"
+
+// GorpLogger is a deprecated alias of Logger.
+type GorpLogger = Logger
+
+// Logger is the type that gorp uses to log SQL statements.
+// See DbMap.TraceOn.
+type Logger interface {
+ Printf(format string, v ...interface{})
+}
+
+// TraceOn turns on SQL statement logging for this DbMap. After this is
+// called, all SQL statements will be sent to the logger. If prefix is
+// a non-empty string, it will be written to the front of all logged
+// strings, which can aid in filtering log lines.
+//
+// Use TraceOn if you want to spy on the SQL statements that gorp
+// generates.
+//
+// Note that the base log.Logger type satisfies Logger, but adapters can
+// easily be written for other logging packages (e.g., the golang-sanctioned
+// glog framework).
+func (m *DbMap) TraceOn(prefix string, logger Logger) {
+ m.logger = logger
+ if prefix == "" {
+ m.logPrefix = prefix
+ } else {
+ m.logPrefix = fmt.Sprintf("%s ", prefix)
+ }
+}
+
+// TraceOff turns off tracing. It is idempotent.
+func (m *DbMap) TraceOff() {
+ m.logger = nil
+ m.logPrefix = ""
+}
diff --git a/vendor/github.com/go-gorp/gorp/v3/nulltypes.go b/vendor/github.com/go-gorp/gorp/v3/nulltypes.go
new file mode 100644
index 0000000000..87b21f83fa
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/nulltypes.go
@@ -0,0 +1,65 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package gorp
+
+import (
+ "database/sql/driver"
+ "log"
+ "time"
+)
+
+// A nullable Time value
+type NullTime struct {
+ Time time.Time
+ Valid bool // Valid is true if Time is not NULL
+}
+
+// Scan implements the Scanner interface.
+func (nt *NullTime) Scan(value interface{}) error {
+ log.Printf("Time scan value is: %#v", value)
+ switch t := value.(type) {
+ case time.Time:
+ nt.Time, nt.Valid = t, true
+ case []byte:
+ v := strToTime(string(t))
+ if v != nil {
+ nt.Valid = true
+ nt.Time = *v
+ }
+ case string:
+ v := strToTime(t)
+ if v != nil {
+ nt.Valid = true
+ nt.Time = *v
+ }
+ }
+ return nil
+}
+
+func strToTime(v string) *time.Time {
+ for _, dtfmt := range []string{
+ "2006-01-02 15:04:05.999999999",
+ "2006-01-02T15:04:05.999999999",
+ "2006-01-02 15:04:05",
+ "2006-01-02T15:04:05",
+ "2006-01-02 15:04",
+ "2006-01-02T15:04",
+ "2006-01-02",
+ "2006-01-02 15:04:05-07:00",
+ } {
+ if t, err := time.Parse(dtfmt, v); err == nil {
+ return &t
+ }
+ }
+ return nil
+}
+
+// Value implements the driver Valuer interface.
+func (nt NullTime) Value() (driver.Value, error) {
+ if !nt.Valid {
+ return nil, nil
+ }
+ return nt.Time, nil
+}
diff --git a/vendor/github.com/go-gorp/gorp/v3/select.go b/vendor/github.com/go-gorp/gorp/v3/select.go
new file mode 100644
index 0000000000..2d2d596186
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/select.go
@@ -0,0 +1,359 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package gorp
+
+import (
+ "database/sql"
+ "fmt"
+ "reflect"
+)
+
+// SelectInt executes the given query, which should be a SELECT statement for a single
+// integer column, and returns the value of the first row returned. If no rows are
+// found, zero is returned.
+func SelectInt(e SqlExecutor, query string, args ...interface{}) (int64, error) {
+ var h int64
+ err := selectVal(e, &h, query, args...)
+ if err != nil && err != sql.ErrNoRows {
+ return 0, err
+ }
+ return h, nil
+}
+
+// SelectNullInt executes the given query, which should be a SELECT statement for a single
+// integer column, and returns the value of the first row returned. If no rows are
+// found, the empty sql.NullInt64 value is returned.
+func SelectNullInt(e SqlExecutor, query string, args ...interface{}) (sql.NullInt64, error) {
+ var h sql.NullInt64
+ err := selectVal(e, &h, query, args...)
+ if err != nil && err != sql.ErrNoRows {
+ return h, err
+ }
+ return h, nil
+}
+
+// SelectFloat executes the given query, which should be a SELECT statement for a single
+// float column, and returns the value of the first row returned. If no rows are
+// found, zero is returned.
+func SelectFloat(e SqlExecutor, query string, args ...interface{}) (float64, error) {
+ var h float64
+ err := selectVal(e, &h, query, args...)
+ if err != nil && err != sql.ErrNoRows {
+ return 0, err
+ }
+ return h, nil
+}
+
+// SelectNullFloat executes the given query, which should be a SELECT statement for a single
+// float column, and returns the value of the first row returned. If no rows are
+// found, the empty sql.NullInt64 value is returned.
+func SelectNullFloat(e SqlExecutor, query string, args ...interface{}) (sql.NullFloat64, error) {
+ var h sql.NullFloat64
+ err := selectVal(e, &h, query, args...)
+ if err != nil && err != sql.ErrNoRows {
+ return h, err
+ }
+ return h, nil
+}
+
+// SelectStr executes the given query, which should be a SELECT statement for a single
+// char/varchar column, and returns the value of the first row returned. If no rows are
+// found, an empty string is returned.
+func SelectStr(e SqlExecutor, query string, args ...interface{}) (string, error) {
+ var h string
+ err := selectVal(e, &h, query, args...)
+ if err != nil && err != sql.ErrNoRows {
+ return "", err
+ }
+ return h, nil
+}
+
+// SelectNullStr executes the given query, which should be a SELECT
+// statement for a single char/varchar column, and returns the value
+// of the first row returned. If no rows are found, the empty
+// sql.NullString is returned.
+func SelectNullStr(e SqlExecutor, query string, args ...interface{}) (sql.NullString, error) {
+ var h sql.NullString
+ err := selectVal(e, &h, query, args...)
+ if err != nil && err != sql.ErrNoRows {
+ return h, err
+ }
+ return h, nil
+}
+
+// SelectOne executes the given query (which should be a SELECT statement)
+// and binds the result to holder, which must be a pointer.
+//
+// If no row is found, an error (sql.ErrNoRows specifically) will be returned
+//
+// If more than one row is found, an error will be returned.
+//
+func SelectOne(m *DbMap, e SqlExecutor, holder interface{}, query string, args ...interface{}) error {
+ t := reflect.TypeOf(holder)
+ if t.Kind() == reflect.Ptr {
+ t = t.Elem()
+ } else {
+ return fmt.Errorf("gorp: SelectOne holder must be a pointer, but got: %t", holder)
+ }
+
+ // Handle pointer to pointer
+ isptr := false
+ if t.Kind() == reflect.Ptr {
+ isptr = true
+ t = t.Elem()
+ }
+
+ if t.Kind() == reflect.Struct {
+ var nonFatalErr error
+
+ list, err := hookedselect(m, e, holder, query, args...)
+ if err != nil {
+ if !NonFatalError(err) { // FIXME: double negative, rename NonFatalError to FatalError
+ return err
+ }
+ nonFatalErr = err
+ }
+
+ dest := reflect.ValueOf(holder)
+ if isptr {
+ dest = dest.Elem()
+ }
+
+ if list != nil && len(list) > 0 { // FIXME: invert if/else
+ // check for multiple rows
+ if len(list) > 1 {
+ return fmt.Errorf("gorp: multiple rows returned for: %s - %v", query, args)
+ }
+
+ // Initialize if nil
+ if dest.IsNil() {
+ dest.Set(reflect.New(t))
+ }
+
+ // only one row found
+ src := reflect.ValueOf(list[0])
+ dest.Elem().Set(src.Elem())
+ } else {
+ // No rows found, return a proper error.
+ return sql.ErrNoRows
+ }
+
+ return nonFatalErr
+ }
+
+ return selectVal(e, holder, query, args...)
+}
+
+func selectVal(e SqlExecutor, holder interface{}, query string, args ...interface{}) error {
+ if len(args) == 1 {
+ switch m := e.(type) {
+ case *DbMap:
+ query, args = maybeExpandNamedQuery(m, query, args)
+ case *Transaction:
+ query, args = maybeExpandNamedQuery(m.dbmap, query, args)
+ }
+ }
+ rows, err := e.Query(query, args...)
+ if err != nil {
+ return err
+ }
+ defer rows.Close()
+
+ if !rows.Next() {
+ if err := rows.Err(); err != nil {
+ return err
+ }
+ return sql.ErrNoRows
+ }
+
+ return rows.Scan(holder)
+}
+
+func hookedselect(m *DbMap, exec SqlExecutor, i interface{}, query string,
+ args ...interface{}) ([]interface{}, error) {
+
+ var nonFatalErr error
+
+ list, err := rawselect(m, exec, i, query, args...)
+ if err != nil {
+ if !NonFatalError(err) {
+ return nil, err
+ }
+ nonFatalErr = err
+ }
+
+ // Determine where the results are: written to i, or returned in list
+ if t, _ := toSliceType(i); t == nil {
+ for _, v := range list {
+ if v, ok := v.(HasPostGet); ok {
+ err := v.PostGet(exec)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+ } else {
+ resultsValue := reflect.Indirect(reflect.ValueOf(i))
+ for i := 0; i < resultsValue.Len(); i++ {
+ if v, ok := resultsValue.Index(i).Interface().(HasPostGet); ok {
+ err := v.PostGet(exec)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+ }
+ return list, nonFatalErr
+}
+
+func rawselect(m *DbMap, exec SqlExecutor, i interface{}, query string,
+ args ...interface{}) ([]interface{}, error) {
+ var (
+ appendToSlice = false // Write results to i directly?
+ intoStruct = true // Selecting into a struct?
+ pointerElements = true // Are the slice elements pointers (vs values)?
+ )
+
+ var nonFatalErr error
+
+ tableName := ""
+ var dynObj DynamicTable
+ isDynamic := false
+ if dynObj, isDynamic = i.(DynamicTable); isDynamic {
+ tableName = dynObj.TableName()
+ }
+
+ // get type for i, verifying it's a supported destination
+ t, err := toType(i)
+ if err != nil {
+ var err2 error
+ if t, err2 = toSliceType(i); t == nil {
+ if err2 != nil {
+ return nil, err2
+ }
+ return nil, err
+ }
+ pointerElements = t.Kind() == reflect.Ptr
+ if pointerElements {
+ t = t.Elem()
+ }
+ appendToSlice = true
+ intoStruct = t.Kind() == reflect.Struct
+ }
+
+ // If the caller supplied a single struct/map argument, assume a "named
+ // parameter" query. Extract the named arguments from the struct/map, create
+ // the flat arg slice, and rewrite the query to use the dialect's placeholder.
+ if len(args) == 1 {
+ query, args = maybeExpandNamedQuery(m, query, args)
+ }
+
+ // Run the query
+ rows, err := exec.Query(query, args...)
+ if err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+
+ // Fetch the column names as returned from db
+ cols, err := rows.Columns()
+ if err != nil {
+ return nil, err
+ }
+
+ if !intoStruct && len(cols) > 1 {
+ return nil, fmt.Errorf("gorp: select into non-struct slice requires 1 column, got %d", len(cols))
+ }
+
+ var colToFieldIndex [][]int
+ if intoStruct {
+ colToFieldIndex, err = columnToFieldIndex(m, t, tableName, cols)
+ if err != nil {
+ if !NonFatalError(err) {
+ return nil, err
+ }
+ nonFatalErr = err
+ }
+ }
+
+ conv := m.TypeConverter
+
+ // Add results to one of these two slices.
+ var (
+ list = make([]interface{}, 0)
+ sliceValue = reflect.Indirect(reflect.ValueOf(i))
+ )
+
+ for {
+ if !rows.Next() {
+ // if error occured return rawselect
+ if rows.Err() != nil {
+ return nil, rows.Err()
+ }
+ // time to exit from outer "for" loop
+ break
+ }
+ v := reflect.New(t)
+
+ if isDynamic {
+ v.Interface().(DynamicTable).SetTableName(tableName)
+ }
+
+ dest := make([]interface{}, len(cols))
+
+ custScan := make([]CustomScanner, 0)
+
+ for x := range cols {
+ f := v.Elem()
+ if intoStruct {
+ index := colToFieldIndex[x]
+ if index == nil {
+ // this field is not present in the struct, so create a dummy
+ // value for rows.Scan to scan into
+ var dummy dummyField
+ dest[x] = &dummy
+ continue
+ }
+ f = f.FieldByIndex(index)
+ }
+ target := f.Addr().Interface()
+ if conv != nil {
+ scanner, ok := conv.FromDb(target)
+ if ok {
+ target = scanner.Holder
+ custScan = append(custScan, scanner)
+ }
+ }
+ dest[x] = target
+ }
+
+ err = rows.Scan(dest...)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, c := range custScan {
+ err = c.Bind()
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if appendToSlice {
+ if !pointerElements {
+ v = v.Elem()
+ }
+ sliceValue.Set(reflect.Append(sliceValue, v))
+ } else {
+ list = append(list, v.Interface())
+ }
+ }
+
+ if appendToSlice && sliceValue.IsNil() {
+ sliceValue.Set(reflect.MakeSlice(sliceValue.Type(), 0, 0))
+ }
+
+ return list, nonFatalErr
+}
diff --git a/vendor/github.com/go-gorp/gorp/v3/table.go b/vendor/github.com/go-gorp/gorp/v3/table.go
new file mode 100644
index 0000000000..5931b2d9eb
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/table.go
@@ -0,0 +1,258 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package gorp
+
+import (
+ "bytes"
+ "fmt"
+ "reflect"
+ "strings"
+)
+
+// TableMap represents a mapping between a Go struct and a database table
+// Use dbmap.AddTable() or dbmap.AddTableWithName() to create these
+type TableMap struct {
+ // Name of database table.
+ TableName string
+ SchemaName string
+ gotype reflect.Type
+ Columns []*ColumnMap
+ keys []*ColumnMap
+ indexes []*IndexMap
+ uniqueTogether [][]string
+ version *ColumnMap
+ insertPlan bindPlan
+ updatePlan bindPlan
+ deletePlan bindPlan
+ getPlan bindPlan
+ dbmap *DbMap
+}
+
+// ResetSql removes cached insert/update/select/delete SQL strings
+// associated with this TableMap. Call this if you've modified
+// any column names or the table name itself.
+func (t *TableMap) ResetSql() {
+ t.insertPlan = bindPlan{}
+ t.updatePlan = bindPlan{}
+ t.deletePlan = bindPlan{}
+ t.getPlan = bindPlan{}
+}
+
+// SetKeys lets you specify the fields on a struct that map to primary
+// key columns on the table. If isAutoIncr is set, result.LastInsertId()
+// will be used after INSERT to bind the generated id to the Go struct.
+//
+// Automatically calls ResetSql() to ensure SQL statements are regenerated.
+//
+// Panics if isAutoIncr is true, and fieldNames length != 1
+//
+func (t *TableMap) SetKeys(isAutoIncr bool, fieldNames ...string) *TableMap {
+ if isAutoIncr && len(fieldNames) != 1 {
+ panic(fmt.Sprintf(
+ "gorp: SetKeys: fieldNames length must be 1 if key is auto-increment. (Saw %v fieldNames)",
+ len(fieldNames)))
+ }
+ t.keys = make([]*ColumnMap, 0)
+ for _, name := range fieldNames {
+ colmap := t.ColMap(name)
+ colmap.isPK = true
+ colmap.isAutoIncr = isAutoIncr
+ t.keys = append(t.keys, colmap)
+ }
+ t.ResetSql()
+
+ return t
+}
+
+// SetUniqueTogether lets you specify uniqueness constraints across multiple
+// columns on the table. Each call adds an additional constraint for the
+// specified columns.
+//
+// Automatically calls ResetSql() to ensure SQL statements are regenerated.
+//
+// Panics if fieldNames length < 2.
+//
+func (t *TableMap) SetUniqueTogether(fieldNames ...string) *TableMap {
+ if len(fieldNames) < 2 {
+ panic(fmt.Sprintf(
+ "gorp: SetUniqueTogether: must provide at least two fieldNames to set uniqueness constraint."))
+ }
+
+ columns := make([]string, 0, len(fieldNames))
+ for _, name := range fieldNames {
+ columns = append(columns, name)
+ }
+
+ for _, existingColumns := range t.uniqueTogether {
+ if equal(existingColumns, columns) {
+ return t
+ }
+ }
+ t.uniqueTogether = append(t.uniqueTogether, columns)
+ t.ResetSql()
+
+ return t
+}
+
+// ColMap returns the ColumnMap pointer matching the given struct field
+// name. It panics if the struct does not contain a field matching this
+// name.
+func (t *TableMap) ColMap(field string) *ColumnMap {
+ col := colMapOrNil(t, field)
+ if col == nil {
+ e := fmt.Sprintf("No ColumnMap in table %s type %s with field %s",
+ t.TableName, t.gotype.Name(), field)
+
+ panic(e)
+ }
+ return col
+}
+
+func colMapOrNil(t *TableMap, field string) *ColumnMap {
+ for _, col := range t.Columns {
+ if col.fieldName == field || col.ColumnName == field {
+ return col
+ }
+ }
+ return nil
+}
+
+// IdxMap returns the IndexMap pointer matching the given index name.
+func (t *TableMap) IdxMap(field string) *IndexMap {
+ for _, idx := range t.indexes {
+ if idx.IndexName == field {
+ return idx
+ }
+ }
+ return nil
+}
+
+// AddIndex registers the index with gorp for specified table with given parameters.
+// This operation is idempotent. If index is already mapped, the
+// existing *IndexMap is returned
+// Function will panic if one of the given for index columns does not exists
+//
+// Automatically calls ResetSql() to ensure SQL statements are regenerated.
+//
+func (t *TableMap) AddIndex(name string, idxtype string, columns []string) *IndexMap {
+ // check if we have a index with this name already
+ for _, idx := range t.indexes {
+ if idx.IndexName == name {
+ return idx
+ }
+ }
+ for _, icol := range columns {
+ if res := t.ColMap(icol); res == nil {
+ e := fmt.Sprintf("No ColumnName in table %s to create index on", t.TableName)
+ panic(e)
+ }
+ }
+
+ idx := &IndexMap{IndexName: name, Unique: false, IndexType: idxtype, columns: columns}
+ t.indexes = append(t.indexes, idx)
+ t.ResetSql()
+ return idx
+}
+
+// SetVersionCol sets the column to use as the Version field. By default
+// the "Version" field is used. Returns the column found, or panics
+// if the struct does not contain a field matching this name.
+//
+// Automatically calls ResetSql() to ensure SQL statements are regenerated.
+func (t *TableMap) SetVersionCol(field string) *ColumnMap {
+ c := t.ColMap(field)
+ t.version = c
+ t.ResetSql()
+ return c
+}
+
+// SqlForCreateTable gets a sequence of SQL commands that will create
+// the specified table and any associated schema
+func (t *TableMap) SqlForCreate(ifNotExists bool) string {
+ s := bytes.Buffer{}
+ dialect := t.dbmap.Dialect
+
+ if strings.TrimSpace(t.SchemaName) != "" {
+ schemaCreate := "create schema"
+ if ifNotExists {
+ s.WriteString(dialect.IfSchemaNotExists(schemaCreate, t.SchemaName))
+ } else {
+ s.WriteString(schemaCreate)
+ }
+ s.WriteString(fmt.Sprintf(" %s;", t.SchemaName))
+ }
+
+ tableCreate := "create table"
+ if ifNotExists {
+ s.WriteString(dialect.IfTableNotExists(tableCreate, t.SchemaName, t.TableName))
+ } else {
+ s.WriteString(tableCreate)
+ }
+ s.WriteString(fmt.Sprintf(" %s (", dialect.QuotedTableForQuery(t.SchemaName, t.TableName)))
+
+ x := 0
+ for _, col := range t.Columns {
+ if !col.Transient {
+ if x > 0 {
+ s.WriteString(", ")
+ }
+ stype := dialect.ToSqlType(col.gotype, col.MaxSize, col.isAutoIncr)
+ s.WriteString(fmt.Sprintf("%s %s", dialect.QuoteField(col.ColumnName), stype))
+
+ if col.isPK || col.isNotNull {
+ s.WriteString(" not null")
+ }
+ if col.isPK && len(t.keys) == 1 {
+ s.WriteString(" primary key")
+ }
+ if col.Unique {
+ s.WriteString(" unique")
+ }
+ if col.isAutoIncr {
+ s.WriteString(fmt.Sprintf(" %s", dialect.AutoIncrStr()))
+ }
+
+ x++
+ }
+ }
+ if len(t.keys) > 1 {
+ s.WriteString(", primary key (")
+ for x := range t.keys {
+ if x > 0 {
+ s.WriteString(", ")
+ }
+ s.WriteString(dialect.QuoteField(t.keys[x].ColumnName))
+ }
+ s.WriteString(")")
+ }
+ if len(t.uniqueTogether) > 0 {
+ for _, columns := range t.uniqueTogether {
+ s.WriteString(", unique (")
+ for i, column := range columns {
+ if i > 0 {
+ s.WriteString(", ")
+ }
+ s.WriteString(dialect.QuoteField(column))
+ }
+ s.WriteString(")")
+ }
+ }
+ s.WriteString(") ")
+ s.WriteString(dialect.CreateTableSuffix())
+ s.WriteString(dialect.QuerySuffix())
+ return s.String()
+}
+
+func equal(a, b []string) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i := range a {
+ if a[i] != b[i] {
+ return false
+ }
+ }
+ return true
+}
diff --git a/vendor/github.com/go-gorp/gorp/v3/table_bindings.go b/vendor/github.com/go-gorp/gorp/v3/table_bindings.go
new file mode 100644
index 0000000000..43c0b3dd48
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/table_bindings.go
@@ -0,0 +1,305 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package gorp
+
+import (
+ "bytes"
+ "fmt"
+ "reflect"
+ "sync"
+)
+
+// CustomScanner binds a database column value to a Go type
+type CustomScanner struct {
+ // After a row is scanned, Holder will contain the value from the database column.
+ // Initialize the CustomScanner with the concrete Go type you wish the database
+ // driver to scan the raw column into.
+ Holder interface{}
+ // Target typically holds a pointer to the target struct field to bind the Holder
+ // value to.
+ Target interface{}
+ // Binder is a custom function that converts the holder value to the target type
+ // and sets target accordingly. This function should return error if a problem
+ // occurs converting the holder to the target.
+ Binder func(holder interface{}, target interface{}) error
+}
+
+// Used to filter columns when selectively updating
+type ColumnFilter func(*ColumnMap) bool
+
+func acceptAllFilter(col *ColumnMap) bool {
+ return true
+}
+
+// Bind is called automatically by gorp after Scan()
+func (me CustomScanner) Bind() error {
+ return me.Binder(me.Holder, me.Target)
+}
+
+type bindPlan struct {
+ query string
+ argFields []string
+ keyFields []string
+ versField string
+ autoIncrIdx int
+ autoIncrFieldName string
+ once sync.Once
+}
+
+func (plan *bindPlan) createBindInstance(elem reflect.Value, conv TypeConverter) (bindInstance, error) {
+ bi := bindInstance{query: plan.query, autoIncrIdx: plan.autoIncrIdx, autoIncrFieldName: plan.autoIncrFieldName, versField: plan.versField}
+ if plan.versField != "" {
+ bi.existingVersion = elem.FieldByName(plan.versField).Int()
+ }
+
+ var err error
+
+ for i := 0; i < len(plan.argFields); i++ {
+ k := plan.argFields[i]
+ if k == versFieldConst {
+ newVer := bi.existingVersion + 1
+ bi.args = append(bi.args, newVer)
+ if bi.existingVersion == 0 {
+ elem.FieldByName(plan.versField).SetInt(int64(newVer))
+ }
+ } else {
+ val := elem.FieldByName(k).Interface()
+ if conv != nil {
+ val, err = conv.ToDb(val)
+ if err != nil {
+ return bindInstance{}, err
+ }
+ }
+ bi.args = append(bi.args, val)
+ }
+ }
+
+ for i := 0; i < len(plan.keyFields); i++ {
+ k := plan.keyFields[i]
+ val := elem.FieldByName(k).Interface()
+ if conv != nil {
+ val, err = conv.ToDb(val)
+ if err != nil {
+ return bindInstance{}, err
+ }
+ }
+ bi.keys = append(bi.keys, val)
+ }
+
+ return bi, nil
+}
+
+type bindInstance struct {
+ query string
+ args []interface{}
+ keys []interface{}
+ existingVersion int64
+ versField string
+ autoIncrIdx int
+ autoIncrFieldName string
+}
+
+func (t *TableMap) bindInsert(elem reflect.Value) (bindInstance, error) {
+ plan := &t.insertPlan
+ plan.once.Do(func() {
+ plan.autoIncrIdx = -1
+
+ s := bytes.Buffer{}
+ s2 := bytes.Buffer{}
+ s.WriteString(fmt.Sprintf("insert into %s (", t.dbmap.Dialect.QuotedTableForQuery(t.SchemaName, t.TableName)))
+
+ x := 0
+ first := true
+ for y := range t.Columns {
+ col := t.Columns[y]
+ if !(col.isAutoIncr && t.dbmap.Dialect.AutoIncrBindValue() == "") {
+ if !col.Transient {
+ if !first {
+ s.WriteString(",")
+ s2.WriteString(",")
+ }
+ s.WriteString(t.dbmap.Dialect.QuoteField(col.ColumnName))
+
+ if col.isAutoIncr {
+ s2.WriteString(t.dbmap.Dialect.AutoIncrBindValue())
+ plan.autoIncrIdx = y
+ plan.autoIncrFieldName = col.fieldName
+ } else {
+ if col.DefaultValue == "" {
+ s2.WriteString(t.dbmap.Dialect.BindVar(x))
+ if col == t.version {
+ plan.versField = col.fieldName
+ plan.argFields = append(plan.argFields, versFieldConst)
+ } else {
+ plan.argFields = append(plan.argFields, col.fieldName)
+ }
+ x++
+ } else {
+ s2.WriteString(col.DefaultValue)
+ }
+ }
+ first = false
+ }
+ } else {
+ plan.autoIncrIdx = y
+ plan.autoIncrFieldName = col.fieldName
+ }
+ }
+ s.WriteString(") values (")
+ s.WriteString(s2.String())
+ s.WriteString(")")
+ if plan.autoIncrIdx > -1 {
+ s.WriteString(t.dbmap.Dialect.AutoIncrInsertSuffix(t.Columns[plan.autoIncrIdx]))
+ }
+ s.WriteString(t.dbmap.Dialect.QuerySuffix())
+
+ plan.query = s.String()
+ })
+
+ return plan.createBindInstance(elem, t.dbmap.TypeConverter)
+}
+
+func (t *TableMap) bindUpdate(elem reflect.Value, colFilter ColumnFilter) (bindInstance, error) {
+ if colFilter == nil {
+ colFilter = acceptAllFilter
+ }
+
+ plan := &t.updatePlan
+ plan.once.Do(func() {
+ s := bytes.Buffer{}
+ s.WriteString(fmt.Sprintf("update %s set ", t.dbmap.Dialect.QuotedTableForQuery(t.SchemaName, t.TableName)))
+ x := 0
+
+ for y := range t.Columns {
+ col := t.Columns[y]
+ if !col.isAutoIncr && !col.Transient && colFilter(col) {
+ if x > 0 {
+ s.WriteString(", ")
+ }
+ s.WriteString(t.dbmap.Dialect.QuoteField(col.ColumnName))
+ s.WriteString("=")
+ s.WriteString(t.dbmap.Dialect.BindVar(x))
+
+ if col == t.version {
+ plan.versField = col.fieldName
+ plan.argFields = append(plan.argFields, versFieldConst)
+ } else {
+ plan.argFields = append(plan.argFields, col.fieldName)
+ }
+ x++
+ }
+ }
+
+ s.WriteString(" where ")
+ for y := range t.keys {
+ col := t.keys[y]
+ if y > 0 {
+ s.WriteString(" and ")
+ }
+ s.WriteString(t.dbmap.Dialect.QuoteField(col.ColumnName))
+ s.WriteString("=")
+ s.WriteString(t.dbmap.Dialect.BindVar(x))
+
+ plan.argFields = append(plan.argFields, col.fieldName)
+ plan.keyFields = append(plan.keyFields, col.fieldName)
+ x++
+ }
+ if plan.versField != "" {
+ s.WriteString(" and ")
+ s.WriteString(t.dbmap.Dialect.QuoteField(t.version.ColumnName))
+ s.WriteString("=")
+ s.WriteString(t.dbmap.Dialect.BindVar(x))
+ plan.argFields = append(plan.argFields, plan.versField)
+ }
+ s.WriteString(t.dbmap.Dialect.QuerySuffix())
+
+ plan.query = s.String()
+ })
+
+ return plan.createBindInstance(elem, t.dbmap.TypeConverter)
+}
+
+func (t *TableMap) bindDelete(elem reflect.Value) (bindInstance, error) {
+ plan := &t.deletePlan
+ plan.once.Do(func() {
+ s := bytes.Buffer{}
+ s.WriteString(fmt.Sprintf("delete from %s", t.dbmap.Dialect.QuotedTableForQuery(t.SchemaName, t.TableName)))
+
+ for y := range t.Columns {
+ col := t.Columns[y]
+ if !col.Transient {
+ if col == t.version {
+ plan.versField = col.fieldName
+ }
+ }
+ }
+
+ s.WriteString(" where ")
+ for x := range t.keys {
+ k := t.keys[x]
+ if x > 0 {
+ s.WriteString(" and ")
+ }
+ s.WriteString(t.dbmap.Dialect.QuoteField(k.ColumnName))
+ s.WriteString("=")
+ s.WriteString(t.dbmap.Dialect.BindVar(x))
+
+ plan.keyFields = append(plan.keyFields, k.fieldName)
+ plan.argFields = append(plan.argFields, k.fieldName)
+ }
+ if plan.versField != "" {
+ s.WriteString(" and ")
+ s.WriteString(t.dbmap.Dialect.QuoteField(t.version.ColumnName))
+ s.WriteString("=")
+ s.WriteString(t.dbmap.Dialect.BindVar(len(plan.argFields)))
+
+ plan.argFields = append(plan.argFields, plan.versField)
+ }
+ s.WriteString(t.dbmap.Dialect.QuerySuffix())
+
+ plan.query = s.String()
+ })
+
+ return plan.createBindInstance(elem, t.dbmap.TypeConverter)
+}
+
+func (t *TableMap) bindGet() *bindPlan {
+ plan := &t.getPlan
+ plan.once.Do(func() {
+ s := bytes.Buffer{}
+ s.WriteString("select ")
+
+ x := 0
+ for _, col := range t.Columns {
+ if !col.Transient {
+ if x > 0 {
+ s.WriteString(",")
+ }
+ s.WriteString(t.dbmap.Dialect.QuoteField(col.ColumnName))
+ plan.argFields = append(plan.argFields, col.fieldName)
+ x++
+ }
+ }
+ s.WriteString(" from ")
+ s.WriteString(t.dbmap.Dialect.QuotedTableForQuery(t.SchemaName, t.TableName))
+ s.WriteString(" where ")
+ for x := range t.keys {
+ col := t.keys[x]
+ if x > 0 {
+ s.WriteString(" and ")
+ }
+ s.WriteString(t.dbmap.Dialect.QuoteField(col.ColumnName))
+ s.WriteString("=")
+ s.WriteString(t.dbmap.Dialect.BindVar(x))
+
+ plan.keyFields = append(plan.keyFields, col.fieldName)
+ }
+ s.WriteString(t.dbmap.Dialect.QuerySuffix())
+
+ plan.query = s.String()
+ })
+
+ return plan
+}
diff --git a/vendor/github.com/go-gorp/gorp/v3/test_all.sh b/vendor/github.com/go-gorp/gorp/v3/test_all.sh
new file mode 100644
index 0000000000..91007d6454
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/test_all.sh
@@ -0,0 +1,23 @@
+#!/bin/bash -ex
+
+# on macs, you may need to:
+# export GOBUILDFLAG=-ldflags -linkmode=external
+
+echo "Running unit tests"
+go test -race
+
+echo "Testing against postgres"
+export GORP_TEST_DSN="host=postgres user=gorptest password=gorptest dbname=gorptest sslmode=disable"
+export GORP_TEST_DIALECT=postgres
+go test -tags integration $GOBUILDFLAG $@ .
+
+echo "Testing against sqlite"
+export GORP_TEST_DSN=/tmp/gorptest.bin
+export GORP_TEST_DIALECT=sqlite
+go test -tags integration $GOBUILDFLAG $@ .
+rm -f /tmp/gorptest.bin
+
+echo "Testing against mysql"
+export GORP_TEST_DSN="gorptest:gorptest@tcp(mysql)/gorptest"
+export GORP_TEST_DIALECT=mysql
+go test -tags integration $GOBUILDFLAG $@ .
diff --git a/vendor/github.com/go-gorp/gorp/v3/transaction.go b/vendor/github.com/go-gorp/gorp/v3/transaction.go
new file mode 100644
index 0000000000..d505d94c91
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/v3/transaction.go
@@ -0,0 +1,239 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package gorp
+
+import (
+ "context"
+ "database/sql"
+ "time"
+)
+
+// Transaction represents a database transaction.
+// Insert/Update/Delete/Get/Exec operations will be run in the context
+// of that transaction. Transactions should be terminated with
+// a call to Commit() or Rollback()
+type Transaction struct {
+ ctx context.Context
+ dbmap *DbMap
+ tx *sql.Tx
+ closed bool
+}
+
+func (t *Transaction) WithContext(ctx context.Context) SqlExecutor {
+ copy := &Transaction{}
+ *copy = *t
+ copy.ctx = ctx
+ return copy
+}
+
+// Insert has the same behavior as DbMap.Insert(), but runs in a transaction.
+func (t *Transaction) Insert(list ...interface{}) error {
+ return insert(t.dbmap, t, list...)
+}
+
+// Update had the same behavior as DbMap.Update(), but runs in a transaction.
+func (t *Transaction) Update(list ...interface{}) (int64, error) {
+ return update(t.dbmap, t, nil, list...)
+}
+
+// UpdateColumns had the same behavior as DbMap.UpdateColumns(), but runs in a transaction.
+func (t *Transaction) UpdateColumns(filter ColumnFilter, list ...interface{}) (int64, error) {
+ return update(t.dbmap, t, filter, list...)
+}
+
+// Delete has the same behavior as DbMap.Delete(), but runs in a transaction.
+func (t *Transaction) Delete(list ...interface{}) (int64, error) {
+ return delete(t.dbmap, t, list...)
+}
+
+// Get has the same behavior as DbMap.Get(), but runs in a transaction.
+func (t *Transaction) Get(i interface{}, keys ...interface{}) (interface{}, error) {
+ return get(t.dbmap, t, i, keys...)
+}
+
+// Select has the same behavior as DbMap.Select(), but runs in a transaction.
+func (t *Transaction) Select(i interface{}, query string, args ...interface{}) ([]interface{}, error) {
+ if t.dbmap.ExpandSliceArgs {
+ expandSliceArgs(&query, args...)
+ }
+
+ return hookedselect(t.dbmap, t, i, query, args...)
+}
+
+// Exec has the same behavior as DbMap.Exec(), but runs in a transaction.
+func (t *Transaction) Exec(query string, args ...interface{}) (sql.Result, error) {
+ if t.dbmap.ExpandSliceArgs {
+ expandSliceArgs(&query, args...)
+ }
+
+ if t.dbmap.logger != nil {
+ now := time.Now()
+ defer t.dbmap.trace(now, query, args...)
+ }
+ return maybeExpandNamedQueryAndExec(t, query, args...)
+}
+
+// SelectInt is a convenience wrapper around the gorp.SelectInt function.
+func (t *Transaction) SelectInt(query string, args ...interface{}) (int64, error) {
+ if t.dbmap.ExpandSliceArgs {
+ expandSliceArgs(&query, args...)
+ }
+
+ return SelectInt(t, query, args...)
+}
+
+// SelectNullInt is a convenience wrapper around the gorp.SelectNullInt function.
+func (t *Transaction) SelectNullInt(query string, args ...interface{}) (sql.NullInt64, error) {
+ if t.dbmap.ExpandSliceArgs {
+ expandSliceArgs(&query, args...)
+ }
+
+ return SelectNullInt(t, query, args...)
+}
+
+// SelectFloat is a convenience wrapper around the gorp.SelectFloat function.
+func (t *Transaction) SelectFloat(query string, args ...interface{}) (float64, error) {
+ if t.dbmap.ExpandSliceArgs {
+ expandSliceArgs(&query, args...)
+ }
+
+ return SelectFloat(t, query, args...)
+}
+
+// SelectNullFloat is a convenience wrapper around the gorp.SelectNullFloat function.
+func (t *Transaction) SelectNullFloat(query string, args ...interface{}) (sql.NullFloat64, error) {
+ if t.dbmap.ExpandSliceArgs {
+ expandSliceArgs(&query, args...)
+ }
+
+ return SelectNullFloat(t, query, args...)
+}
+
+// SelectStr is a convenience wrapper around the gorp.SelectStr function.
+func (t *Transaction) SelectStr(query string, args ...interface{}) (string, error) {
+ if t.dbmap.ExpandSliceArgs {
+ expandSliceArgs(&query, args...)
+ }
+
+ return SelectStr(t, query, args...)
+}
+
+// SelectNullStr is a convenience wrapper around the gorp.SelectNullStr function.
+func (t *Transaction) SelectNullStr(query string, args ...interface{}) (sql.NullString, error) {
+ if t.dbmap.ExpandSliceArgs {
+ expandSliceArgs(&query, args...)
+ }
+
+ return SelectNullStr(t, query, args...)
+}
+
+// SelectOne is a convenience wrapper around the gorp.SelectOne function.
+func (t *Transaction) SelectOne(holder interface{}, query string, args ...interface{}) error {
+ if t.dbmap.ExpandSliceArgs {
+ expandSliceArgs(&query, args...)
+ }
+
+ return SelectOne(t.dbmap, t, holder, query, args...)
+}
+
+// Commit commits the underlying database transaction.
+func (t *Transaction) Commit() error {
+ if !t.closed {
+ t.closed = true
+ if t.dbmap.logger != nil {
+ now := time.Now()
+ defer t.dbmap.trace(now, "commit;")
+ }
+ return t.tx.Commit()
+ }
+
+ return sql.ErrTxDone
+}
+
+// Rollback rolls back the underlying database transaction.
+func (t *Transaction) Rollback() error {
+ if !t.closed {
+ t.closed = true
+ if t.dbmap.logger != nil {
+ now := time.Now()
+ defer t.dbmap.trace(now, "rollback;")
+ }
+ return t.tx.Rollback()
+ }
+
+ return sql.ErrTxDone
+}
+
+// Savepoint creates a savepoint with the given name. The name is interpolated
+// directly into the SQL SAVEPOINT statement, so you must sanitize it if it is
+// derived from user input.
+func (t *Transaction) Savepoint(name string) error {
+ query := "savepoint " + t.dbmap.Dialect.QuoteField(name)
+ if t.dbmap.logger != nil {
+ now := time.Now()
+ defer t.dbmap.trace(now, query, nil)
+ }
+ _, err := exec(t, query)
+ return err
+}
+
+// RollbackToSavepoint rolls back to the savepoint with the given name. The
+// name is interpolated directly into the SQL SAVEPOINT statement, so you must
+// sanitize it if it is derived from user input.
+func (t *Transaction) RollbackToSavepoint(savepoint string) error {
+ query := "rollback to savepoint " + t.dbmap.Dialect.QuoteField(savepoint)
+ if t.dbmap.logger != nil {
+ now := time.Now()
+ defer t.dbmap.trace(now, query, nil)
+ }
+ _, err := exec(t, query)
+ return err
+}
+
+// ReleaseSavepint releases the savepoint with the given name. The name is
+// interpolated directly into the SQL SAVEPOINT statement, so you must sanitize
+// it if it is derived from user input.
+func (t *Transaction) ReleaseSavepoint(savepoint string) error {
+ query := "release savepoint " + t.dbmap.Dialect.QuoteField(savepoint)
+ if t.dbmap.logger != nil {
+ now := time.Now()
+ defer t.dbmap.trace(now, query, nil)
+ }
+ _, err := exec(t, query)
+ return err
+}
+
+// Prepare has the same behavior as DbMap.Prepare(), but runs in a transaction.
+func (t *Transaction) Prepare(query string) (*sql.Stmt, error) {
+ if t.dbmap.logger != nil {
+ now := time.Now()
+ defer t.dbmap.trace(now, query, nil)
+ }
+ return prepare(t, query)
+}
+
+func (t *Transaction) QueryRow(query string, args ...interface{}) *sql.Row {
+ if t.dbmap.ExpandSliceArgs {
+ expandSliceArgs(&query, args...)
+ }
+
+ if t.dbmap.logger != nil {
+ now := time.Now()
+ defer t.dbmap.trace(now, query, args...)
+ }
+ return queryRow(t, query, args...)
+}
+
+func (t *Transaction) Query(q string, args ...interface{}) (*sql.Rows, error) {
+ if t.dbmap.ExpandSliceArgs {
+ expandSliceArgs(&q, args...)
+ }
+
+ if t.dbmap.logger != nil {
+ now := time.Now()
+ defer t.dbmap.trace(now, q, args...)
+ }
+ return query(t, q, args...)
+}
diff --git a/vendor/github.com/go-openapi/jsonpointer/.cliff.toml b/vendor/github.com/go-openapi/jsonpointer/.cliff.toml
new file mode 100644
index 0000000000..702629f5dc
--- /dev/null
+++ b/vendor/github.com/go-openapi/jsonpointer/.cliff.toml
@@ -0,0 +1,181 @@
+# git-cliff ~ configuration file
+# https://git-cliff.org/docs/configuration
+
+[changelog]
+header = """
+"""
+
+footer = """
+
+-----
+
+**[{{ remote.github.repo }}]({{ self::remote_url() }}) license terms**
+
+[![License][license-badge]][license-url]
+
+[license-badge]: http://img.shields.io/badge/license-Apache%20v2-orange.svg
+[license-url]: {{ self::remote_url() }}/?tab=Apache-2.0-1-ov-file#readme
+
+{%- macro remote_url() -%}
+ https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}
+{%- endmacro -%}
+"""
+
+body = """
+{%- if version %}
+## [{{ version | trim_start_matches(pat="v") }}]({{ self::remote_url() }}/tree/{{ version }}) - {{ timestamp | date(format="%Y-%m-%d") }}
+{%- else %}
+## [unreleased]
+{%- endif %}
+{%- if message %}
+ {%- raw %}\n{% endraw %}
+{{ message }}
+ {%- raw %}\n{% endraw %}
+{%- endif %}
+{%- if version %}
+ {%- if previous.version %}
+
+**Full Changelog**: <{{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }}>
+ {%- endif %}
+{%- else %}
+ {%- raw %}\n{% endraw %}
+{%- endif %}
+
+{%- if statistics %}{% if statistics.commit_count %}
+ {%- raw %}\n{% endraw %}
+{{ statistics.commit_count }} commits in this release.
+ {%- raw %}\n{% endraw %}
+{%- endif %}{% endif %}
+-----
+
+{%- for group, commits in commits | group_by(attribute="group") %}
+ {%- raw %}\n{% endraw %}
+### {{ group | upper_first }}
+ {%- raw %}\n{% endraw %}
+ {%- for commit in commits %}
+ {%- if commit.remote.pr_title %}
+ {%- set commit_message = commit.remote.pr_title %}
+ {%- else %}
+ {%- set commit_message = commit.message %}
+ {%- endif %}
+* {{ commit_message | split(pat="\n") | first | trim }}
+ {%- if commit.remote.username %}
+{%- raw %} {% endraw %}by [@{{ commit.remote.username }}](https://github.com/{{ commit.remote.username }})
+ {%- endif %}
+ {%- if commit.remote.pr_number %}
+{%- raw %} {% endraw %}in [#{{ commit.remote.pr_number }}]({{ self::remote_url() }}/pull/{{ commit.remote.pr_number }})
+ {%- endif %}
+{%- raw %} {% endraw %}[...]({{ self::remote_url() }}/commit/{{ commit.id }})
+ {%- endfor %}
+{%- endfor %}
+
+{%- if github %}
+{%- raw %}\n{% endraw -%}
+ {%- set all_contributors = github.contributors | length %}
+ {%- if github.contributors | filter(attribute="username", value="dependabot[bot]") | length < all_contributors %}
+-----
+
+### People who contributed to this release
+ {% endif %}
+ {%- for contributor in github.contributors | filter(attribute="username") | sort(attribute="username") %}
+ {%- if contributor.username != "dependabot[bot]" and contributor.username != "github-actions[bot]" %}
+* [@{{ contributor.username }}](https://github.com/{{ contributor.username }})
+ {%- endif %}
+ {%- endfor %}
+
+ {% if github.contributors | filter(attribute="is_first_time", value=true) | length != 0 %}
+-----
+ {%- raw %}\n{% endraw %}
+
+### New Contributors
+ {%- endif %}
+
+ {%- for contributor in github.contributors | filter(attribute="is_first_time", value=true) %}
+ {%- if contributor.username != "dependabot[bot]" and contributor.username != "github-actions[bot]" %}
+* @{{ contributor.username }} made their first contribution
+ {%- if contributor.pr_number %}
+ in [#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \
+ {%- endif %}
+ {%- endif %}
+ {%- endfor %}
+{%- endif %}
+
+{%- raw %}\n{% endraw %}
+
+{%- macro remote_url() -%}
+ https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}
+{%- endmacro -%}
+"""
+# Remove leading and trailing whitespaces from the changelog's body.
+trim = true
+# Render body even when there are no releases to process.
+render_always = true
+# An array of regex based postprocessors to modify the changelog.
+postprocessors = [
+ # Replace the placeholder with a URL.
+ #{ pattern = '', replace = "https://github.com/orhun/git-cliff" },
+]
+# output file path
+# output = "test.md"
+
+[git]
+# Parse commits according to the conventional commits specification.
+# See https://www.conventionalcommits.org
+conventional_commits = false
+# Exclude commits that do not match the conventional commits specification.
+filter_unconventional = false
+# Require all commits to be conventional.
+# Takes precedence over filter_unconventional.
+require_conventional = false
+# Split commits on newlines, treating each line as an individual commit.
+split_commits = false
+# An array of regex based parsers to modify commit messages prior to further processing.
+commit_preprocessors = [
+ # Replace issue numbers with link templates to be updated in `changelog.postprocessors`.
+ #{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](/issues/${2}))"},
+ # Check spelling of the commit message using https://github.com/crate-ci/typos.
+ # If the spelling is incorrect, it will be fixed automatically.
+ #{ pattern = '.*', replace_command = 'typos --write-changes -' }
+]
+# Prevent commits that are breaking from being excluded by commit parsers.
+protect_breaking_commits = false
+# An array of regex based parsers for extracting data from the commit message.
+# Assigns commits to groups.
+# Optionally sets the commit's scope and can decide to exclude commits from further processing.
+commit_parsers = [
+ { message = "^[Cc]hore\\([Rr]elease\\): prepare for", skip = true },
+ { message = "(^[Mm]erge)|([Mm]erge conflict)", skip = true },
+ { field = "author.name", pattern = "dependabot*", group = "Updates" },
+ { message = "([Ss]ecurity)|([Vv]uln)", group = "Security" },
+ { body = "(.*[Ss]ecurity)|([Vv]uln)", group = "Security" },
+ { message = "([Cc]hore\\(lint\\))|(style)|(lint)|(codeql)|(golangci)", group = "Code quality" },
+ { message = "(^[Dd]oc)|((?i)readme)|(badge)|(typo)|(documentation)", group = "Documentation" },
+ { message = "(^[Ff]eat)|(^[Ee]nhancement)", group = "Implemented enhancements" },
+ { message = "(^ci)|(\\(ci\\))|(fixup\\s+ci)|(fix\\s+ci)|(license)|(example)", group = "Miscellaneous tasks" },
+ { message = "^test", group = "Testing" },
+ { message = "(^fix)|(panic)", group = "Fixed bugs" },
+ { message = "(^refact)|(rework)", group = "Refactor" },
+ { message = "(^[Pp]erf)|(performance)", group = "Performance" },
+ { message = "(^[Cc]hore)", group = "Miscellaneous tasks" },
+ { message = "^[Rr]evert", group = "Reverted changes" },
+ { message = "(upgrade.*?go)|(go\\s+version)", group = "Updates" },
+ { message = ".*", group = "Other" },
+]
+# Exclude commits that are not matched by any commit parser.
+filter_commits = false
+# An array of link parsers for extracting external references, and turning them into URLs, using regex.
+link_parsers = []
+# Include only the tags that belong to the current branch.
+use_branch_tags = false
+# Order releases topologically instead of chronologically.
+topo_order = false
+# Order releases topologically instead of chronologically.
+topo_order_commits = true
+# Order of commits in each group/release within the changelog.
+# Allowed values: newest, oldest
+sort_commits = "newest"
+# Process submodules commits
+recurse_submodules = false
+
+#[remote.github]
+#owner = "go-openapi"
diff --git a/vendor/github.com/go-openapi/jsonpointer/.gitignore b/vendor/github.com/go-openapi/jsonpointer/.gitignore
index 769c244007..59cd294891 100644
--- a/vendor/github.com/go-openapi/jsonpointer/.gitignore
+++ b/vendor/github.com/go-openapi/jsonpointer/.gitignore
@@ -1 +1,4 @@
-secrets.yml
+*.out
+*.cov
+.idea
+.env
diff --git a/vendor/github.com/go-openapi/jsonpointer/.golangci.yml b/vendor/github.com/go-openapi/jsonpointer/.golangci.yml
index 500630621f..fdae591bce 100644
--- a/vendor/github.com/go-openapi/jsonpointer/.golangci.yml
+++ b/vendor/github.com/go-openapi/jsonpointer/.golangci.yml
@@ -2,43 +2,37 @@ version: "2"
linters:
default: all
disable:
- - cyclop
- depguard
- - errchkjson
- - errorlint
- - exhaustruct
- - forcetypeassert
- funlen
- - gochecknoglobals
- - gochecknoinits
- - gocognit
- - godot
- godox
- - gosmopolitan
- - inamedparam
- - ireturn
- - lll
- - musttag
- - nestif
+ - exhaustruct
- nlreturn
- nonamedreturns
+ - noinlineerr
- paralleltest
+ - recvcheck
- testpackage
- - thelper
- tparallel
- - unparam
- varnamelen
- whitespace
- wrapcheck
- wsl
+ - wsl_v5
settings:
dupl:
threshold: 200
goconst:
min-len: 2
min-occurrences: 3
+ cyclop:
+ max-complexity: 20
gocyclo:
- min-complexity: 45
+ min-complexity: 20
+ exhaustive:
+ default-signifies-exhaustive: true
+ default-case-required: true
+ lll:
+ line-length: 180
exclusions:
generated: lax
presets:
@@ -54,9 +48,19 @@ formatters:
enable:
- gofmt
- goimports
+ - gofumpt
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
+issues:
+ # Maximum issues count per one linter.
+ # Set to 0 to disable.
+ # Default: 50
+ max-issues-per-linter: 0
+ # Maximum count of issues with the same text.
+ # Set to 0 to disable.
+ # Default: 3
+ max-same-issues: 0
diff --git a/vendor/github.com/go-openapi/jsonpointer/CONTRIBUTORS.md b/vendor/github.com/go-openapi/jsonpointer/CONTRIBUTORS.md
new file mode 100644
index 0000000000..03c098316d
--- /dev/null
+++ b/vendor/github.com/go-openapi/jsonpointer/CONTRIBUTORS.md
@@ -0,0 +1,24 @@
+# Contributors
+
+- Repository: ['go-openapi/jsonpointer']
+
+| Total Contributors | Total Contributions |
+| --- | --- |
+| 12 | 95 |
+
+| Username | All Time Contribution Count | All Commits |
+| --- | --- | --- |
+| @fredbi | 48 | https://github.com/go-openapi/jsonpointer/commits?author=fredbi |
+| @casualjim | 33 | https://github.com/go-openapi/jsonpointer/commits?author=casualjim |
+| @magodo | 3 | https://github.com/go-openapi/jsonpointer/commits?author=magodo |
+| @youyuanwu | 3 | https://github.com/go-openapi/jsonpointer/commits?author=youyuanwu |
+| @gaiaz-iusipov | 1 | https://github.com/go-openapi/jsonpointer/commits?author=gaiaz-iusipov |
+| @gbjk | 1 | https://github.com/go-openapi/jsonpointer/commits?author=gbjk |
+| @gordallott | 1 | https://github.com/go-openapi/jsonpointer/commits?author=gordallott |
+| @ianlancetaylor | 1 | https://github.com/go-openapi/jsonpointer/commits?author=ianlancetaylor |
+| @mfleader | 1 | https://github.com/go-openapi/jsonpointer/commits?author=mfleader |
+| @Neo2308 | 1 | https://github.com/go-openapi/jsonpointer/commits?author=Neo2308 |
+| @olivierlemasle | 1 | https://github.com/go-openapi/jsonpointer/commits?author=olivierlemasle |
+| @testwill | 1 | https://github.com/go-openapi/jsonpointer/commits?author=testwill |
+
+ _this file was generated by the [Contributors GitHub Action](https://github.com/github/contributors)_
diff --git a/vendor/github.com/go-openapi/jsonpointer/LICENSE b/vendor/github.com/go-openapi/jsonpointer/LICENSE
index d645695673..261eeb9e9f 100644
--- a/vendor/github.com/go-openapi/jsonpointer/LICENSE
+++ b/vendor/github.com/go-openapi/jsonpointer/LICENSE
@@ -1,4 +1,3 @@
-
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
diff --git a/vendor/github.com/go-openapi/jsonpointer/NOTICE b/vendor/github.com/go-openapi/jsonpointer/NOTICE
new file mode 100644
index 0000000000..f3b51939a9
--- /dev/null
+++ b/vendor/github.com/go-openapi/jsonpointer/NOTICE
@@ -0,0 +1,39 @@
+Copyright 2015-2025 go-swagger maintainers
+
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+This software library, github.com/go-openapi/jsonpointer, includes software developed
+by the go-swagger and go-openapi maintainers ("go-swagger maintainers").
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this software except in compliance with the License.
+
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0.
+
+This software is copied from, derived from, and inspired by other original software products.
+It ships with copies of other software which license terms are recalled below.
+
+The original software was authored on 25-02-2013 by sigu-399 (https://github.com/sigu-399, sigu.399@gmail.com).
+
+github.com/sigh-399/jsonpointer
+===========================
+
+// SPDX-FileCopyrightText: Copyright 2013 sigu-399 ( https://github.com/sigu-399 )
+// SPDX-License-Identifier: Apache-2.0
+
+Copyright 2013 sigu-399 ( https://github.com/sigu-399 )
+
+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.
diff --git a/vendor/github.com/go-openapi/jsonpointer/README.md b/vendor/github.com/go-openapi/jsonpointer/README.md
index 0108f1d572..b61b63fd9a 100644
--- a/vendor/github.com/go-openapi/jsonpointer/README.md
+++ b/vendor/github.com/go-openapi/jsonpointer/README.md
@@ -1,19 +1,149 @@
-# gojsonpointer [](https://github.com/go-openapi/jsonpointer/actions?query=workflow%3A"go+test") [](https://codecov.io/gh/go-openapi/jsonpointer)
+# jsonpointer
-[](https://slackin.goswagger.io)
-[](https://raw.githubusercontent.com/go-openapi/jsonpointer/master/LICENSE)
-[](https://pkg.go.dev/github.com/go-openapi/jsonpointer)
-[](https://goreportcard.com/report/github.com/go-openapi/jsonpointer)
+
+[![Tests][test-badge]][test-url] [![Coverage][cov-badge]][cov-url] [![CI vuln scan][vuln-scan-badge]][vuln-scan-url] [![CodeQL][codeql-badge]][codeql-url]
+
+
+
+[![Release][release-badge]][release-url] [![Go Report Card][gocard-badge]][gocard-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url]
+
+
+[![GoDoc][godoc-badge]][godoc-url] [![Slack Channel][slack-logo]![slack-badge]][slack-url] [![go version][goversion-badge]][goversion-url] ![Top language][top-badge] ![Commits since latest release][commits-badge]
-An implementation of JSON Pointer - Go language
+---
+
+An implementation of JSON Pointer for golang, which supports go `struct`.
## Status
-Completed YES
-Tested YES
+API is stable.
+
+## Import this library in your project
+
+```cmd
+go get github.com/go-openapi/jsonpointer
+```
+
+## Basic usage
+
+See also some [examples](./examples_test.go)
+
+### Retrieving a value
+
+```go
+ import (
+ "github.com/go-openapi/jsonpointer"
+ )
+
+
+ var doc any
+
+ ...
+
+ pointer, err := jsonpointer.New("/foo/1")
+ if err != nil {
+ ... // error: e.g. invalid JSON pointer specification
+ }
+
+ value, kind, err := pointer.Get(doc)
+ if err != nil {
+ ... // error: e.g. key not found, index out of bounds, etc.
+ }
+
+ ...
+```
+
+### Setting a value
+
+```go
+ ...
+ var doc any
+ ...
+ pointer, err := jsonpointer.New("/foo/1")
+ if err != nil {
+ ... // error: e.g. invalid JSON pointer specification
+ }
+
+ doc, err = p.Set(doc, "value")
+ if err != nil {
+ ... // error: e.g. key not found, index out of bounds, etc.
+ }
+```
+
+## Change log
+
+See
## References
-http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07
-### Note
-The 4.Evaluation part of the previous reference, starting with 'If the currently referenced value is a JSON array, the reference token MUST contain either...' is not implemented.
+
+
+also known as [RFC6901](https://www.rfc-editor.org/rfc/rfc6901)
+
+## Licensing
+
+This library ships under the [SPDX-License-Identifier: Apache-2.0](./LICENSE).
+
+See the license [NOTICE](./NOTICE), which recalls the licensing terms of all the pieces of software
+on top of which it has been built.
+
+## Limitations
+
+The 4.Evaluation part of the previous reference, starting with 'If the currently referenced value is a JSON array,
+the reference token MUST contain either...' is not implemented.
+
+That is because our implementation of the JSON pointer only supports explicit references to array elements:
+the provision in the spec to resolve non-existent members as "the last element in the array",
+using the special trailing character "-" is not implemented.
+
+## Other documentation
+
+* [All-time contributors](./CONTRIBUTORS.md)
+* [Contributing guidelines](.github/CONTRIBUTING.md)
+* [Maintainers documentation](docs/MAINTAINERS.md)
+* [Code style](docs/STYLE.md)
+
+## Cutting a new release
+
+Maintainers can cut a new release by either:
+
+* running [this workflow](https://github.com/go-openapi/jsonpointer/actions/workflows/bump-release.yml)
+* or pushing a semver tag
+ * signed tags are preferred
+ * The tag message is prepended to release notes
+
+
+[test-badge]: https://github.com/go-openapi/jsonpointer/actions/workflows/go-test.yml/badge.svg
+[test-url]: https://github.com/go-openapi/jsonpointer/actions/workflows/go-test.yml
+[cov-badge]: https://codecov.io/gh/go-openapi/jsonpointer/branch/master/graph/badge.svg
+[cov-url]: https://codecov.io/gh/go-openapi/jsonpointer
+[vuln-scan-badge]: https://github.com/go-openapi/jsonpointer/actions/workflows/scanner.yml/badge.svg
+[vuln-scan-url]: https://github.com/go-openapi/jsonpointer/actions/workflows/scanner.yml
+[codeql-badge]: https://github.com/go-openapi/jsonpointer/actions/workflows/codeql.yml/badge.svg
+[codeql-url]: https://github.com/go-openapi/jsonpointer/actions/workflows/codeql.yml
+
+[release-badge]: https://badge.fury.io/gh/go-openapi%2Fjsonpointer.svg
+[release-url]: https://badge.fury.io/gh/go-openapi%2Fjsonpointer
+[gomod-badge]: https://badge.fury.io/go/github.com%2Fgo-openapi%2Fjsonpointer.svg
+[gomod-url]: https://badge.fury.io/go/github.com%2Fgo-openapi%2Fjsonpointer
+
+[gocard-badge]: https://goreportcard.com/badge/github.com/go-openapi/jsonpointer
+[gocard-url]: https://goreportcard.com/report/github.com/go-openapi/jsonpointer
+[codefactor-badge]: https://img.shields.io/codefactor/grade/github/go-openapi/jsonpointer
+[codefactor-url]: https://www.codefactor.io/repository/github/go-openapi/jsonpointer
+
+[doc-badge]: https://img.shields.io/badge/doc-site-blue?link=https%3A%2F%2Fgoswagger.io%2Fgo-openapi%2F
+[doc-url]: https://goswagger.io/go-openapi
+[godoc-badge]: https://pkg.go.dev/badge/github.com/go-openapi/jsonpointer
+[godoc-url]: http://pkg.go.dev/github.com/go-openapi/jsonpointer
+[slack-logo]: https://a.slack-edge.com/e6a93c1/img/icons/favicon-32.png
+[slack-badge]: https://img.shields.io/badge/slack-blue?link=https%3A%2F%2Fgoswagger.slack.com%2Farchives%2FC04R30YM
+[slack-url]: https://goswagger.slack.com/archives/C04R30YMU
+
+[license-badge]: http://img.shields.io/badge/license-Apache%20v2-orange.svg
+[license-url]: https://github.com/go-openapi/jsonpointer/?tab=Apache-2.0-1-ov-file#readme
+
+[goversion-badge]: https://img.shields.io/github/go-mod/go-version/go-openapi/jsonpointer
+[goversion-url]: https://github.com/go-openapi/jsonpointer/blob/master/go.mod
+[top-badge]: https://img.shields.io/github/languages/top/go-openapi/jsonpointer
+[commits-badge]: https://img.shields.io/github/commits-since/go-openapi/jsonpointer/latest
diff --git a/vendor/github.com/go-openapi/jsonpointer/SECURITY.md b/vendor/github.com/go-openapi/jsonpointer/SECURITY.md
new file mode 100644
index 0000000000..2a7b6f0910
--- /dev/null
+++ b/vendor/github.com/go-openapi/jsonpointer/SECURITY.md
@@ -0,0 +1,19 @@
+# Security Policy
+
+This policy outlines the commitment and practices of the go-openapi maintainers regarding security.
+
+## Supported Versions
+
+| Version | Supported |
+| ------- | ------------------ |
+| 0.22.x | :white_check_mark: |
+
+## Reporting a vulnerability
+
+If you become aware of a security vulnerability that affects the current repository,
+please report it privately to the maintainers.
+
+Please follow the instructions provided by github to
+[Privately report a security vulnerability](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability).
+
+TL;DR: on Github, navigate to the project's "Security" tab then click on "Report a vulnerability".
diff --git a/vendor/github.com/go-openapi/jsonpointer/errors.go b/vendor/github.com/go-openapi/jsonpointer/errors.go
index b84343d9d7..8c50dde8bc 100644
--- a/vendor/github.com/go-openapi/jsonpointer/errors.go
+++ b/vendor/github.com/go-openapi/jsonpointer/errors.go
@@ -1,5 +1,10 @@
+// SPDX-FileCopyrightText: Copyright (c) 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
package jsonpointer
+import "fmt"
+
type pointerError string
func (e pointerError) Error() string {
@@ -7,12 +12,24 @@ func (e pointerError) Error() string {
}
const (
- // ErrPointer is an error raised by the jsonpointer package
+ // ErrPointer is a sentinel error raised by all errors from this package.
ErrPointer pointerError = "JSON pointer error"
- // ErrInvalidStart states that a JSON pointer must start with a separator ("/")
+ // ErrInvalidStart states that a JSON pointer must start with a separator ("/").
ErrInvalidStart pointerError = `JSON pointer must be empty or start with a "` + pointerSeparator
- // ErrUnsupportedValueType indicates that a value of the wrong type is being set
+ // ErrUnsupportedValueType indicates that a value of the wrong type is being set.
ErrUnsupportedValueType pointerError = "only structs, pointers, maps and slices are supported for setting values"
)
+
+func errNoKey(key string) error {
+ return fmt.Errorf("object has no key %q: %w", key, ErrPointer)
+}
+
+func errOutOfBounds(length, idx int) error {
+ return fmt.Errorf("index out of bounds array[0,%d] index '%d': %w", length-1, idx, ErrPointer)
+}
+
+func errInvalidReference(token string) error {
+ return fmt.Errorf("invalid token reference %q: %w", token, ErrPointer)
+}
diff --git a/vendor/github.com/go-openapi/jsonpointer/pointer.go b/vendor/github.com/go-openapi/jsonpointer/pointer.go
index 6136210572..7df49af3b9 100644
--- a/vendor/github.com/go-openapi/jsonpointer/pointer.go
+++ b/vendor/github.com/go-openapi/jsonpointer/pointer.go
@@ -1,28 +1,7 @@
-// Copyright 2013 sigu-399 ( https://github.com/sigu-399 )
-//
-// 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.
-
-// author sigu-399
-// author-github https://github.com/sigu-399
-// author-mail sigu.399@gmail.com
-//
-// repository-name jsonpointer
-// repository-desc An implementation of JSON Pointer - Go language
-//
-// description Main and unique file.
-//
-// created 25-02-2013
+// SPDX-FileCopyrightText: Copyright (c) 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+// Package jsonpointer provides a golang implementation for json pointers.
package jsonpointer
import (
@@ -33,7 +12,7 @@ import (
"strconv"
"strings"
- "github.com/go-openapi/swag"
+ "github.com/go-openapi/swag/jsonname"
)
const (
@@ -41,70 +20,273 @@ const (
pointerSeparator = `/`
)
-var jsonPointableType = reflect.TypeOf(new(JSONPointable)).Elem()
-var jsonSetableType = reflect.TypeOf(new(JSONSetable)).Elem()
-
-// JSONPointable is an interface for structs to implement when they need to customize the
-// json pointer process
+// JSONPointable is an interface for structs to implement,
+// when they need to customize the json pointer process or want to avoid the use of reflection.
type JSONPointable interface {
- JSONLookup(string) (any, error)
+ // JSONLookup returns a value pointed at this (unescaped) key.
+ JSONLookup(key string) (any, error)
}
-// JSONSetable is an interface for structs to implement when they need to customize the
-// json pointer process
+// JSONSetable is an interface for structs to implement,
+// when they need to customize the json pointer process or want to avoid the use of reflection.
type JSONSetable interface {
- JSONSet(string, any) error
+ // JSONSet sets the value pointed at the (unescaped) key.
+ JSONSet(key string, value any) error
}
-// New creates a new json pointer for the given string
-func New(jsonPointerString string) (Pointer, error) {
+// Pointer is a representation of a json pointer.
+//
+// Use [Pointer.Get] to retrieve a value or [Pointer.Set] to set a value.
+//
+// It works with any go type interpreted as a JSON document, which means:
+//
+// - if a type implements [JSONPointable], its [JSONPointable.JSONLookup] method is used to resolve [Pointer.Get]
+// - if a type implements [JSONSetable], its [JSONPointable.JSONSet] method is used to resolve [Pointer.Set]
+// - a go map[K]V is interpreted as an object, with type K assignable to a string
+// - a go slice []T is interpreted as an array
+// - a go struct is interpreted as an object, with exported fields interpreted as keys
+// - promoted fields from an embedded struct are traversed
+// - scalars (e.g. int, float64 ...), channels, functions and go arrays cannot be traversed
+//
+// For struct s resolved by reflection, key mappings honor the conventional struct tag `json`.
+//
+// Fields that do not specify a `json` tag, or specify an empty one, or are tagged as `json:"-"` are ignored.
+//
+// # Limitations
+//
+// - Unlike go standard marshaling, untagged fields do not default to the go field name and are ignored.
+// - anonymous fields are not traversed if untagged
+type Pointer struct {
+ referenceTokens []string
+}
+// New creates a new json pointer from its string representation.
+func New(jsonPointerString string) (Pointer, error) {
var p Pointer
err := p.parse(jsonPointerString)
+
return p, err
+}
+// Get uses the pointer to retrieve a value from a JSON document.
+//
+// It returns the value with its type as a [reflect.Kind] or an error.
+func (p *Pointer) Get(document any) (any, reflect.Kind, error) {
+ return p.get(document, jsonname.DefaultJSONNameProvider)
}
-// Pointer the json pointer reprsentation
-type Pointer struct {
- referenceTokens []string
+// Set uses the pointer to set a value from a data type
+// that represent a JSON document.
+//
+// It returns the updated document.
+func (p *Pointer) Set(document any, value any) (any, error) {
+ return document, p.set(document, value, jsonname.DefaultJSONNameProvider)
}
-// "Constructor", parses the given string JSON pointer
-func (p *Pointer) parse(jsonPointerString string) error {
+// DecodedTokens returns the decoded (unescaped) tokens of this JSON pointer.
+func (p *Pointer) DecodedTokens() []string {
+ result := make([]string, 0, len(p.referenceTokens))
+ for _, token := range p.referenceTokens {
+ result = append(result, Unescape(token))
+ }
- var err error
+ return result
+}
- if jsonPointerString != emptyPointer {
- if !strings.HasPrefix(jsonPointerString, pointerSeparator) {
- err = errors.Join(ErrInvalidStart, ErrPointer)
- } else {
- referenceTokens := strings.Split(jsonPointerString, pointerSeparator)
- p.referenceTokens = append(p.referenceTokens, referenceTokens[1:]...)
- }
+// IsEmpty returns true if this is an empty json pointer.
+//
+// This indicates that it points to the root document.
+func (p *Pointer) IsEmpty() bool {
+ return len(p.referenceTokens) == 0
+}
+
+// String representation of a pointer.
+func (p *Pointer) String() string {
+ if len(p.referenceTokens) == 0 {
+ return emptyPointer
}
- return err
+ return pointerSeparator + strings.Join(p.referenceTokens, pointerSeparator)
}
-// Get uses the pointer to retrieve a value from a JSON document
-func (p *Pointer) Get(document any) (any, reflect.Kind, error) {
- return p.get(document, swag.DefaultJSONNameProvider)
+func (p *Pointer) Offset(document string) (int64, error) {
+ dec := json.NewDecoder(strings.NewReader(document))
+ var offset int64
+ for _, ttk := range p.DecodedTokens() {
+ tk, err := dec.Token()
+ if err != nil {
+ return 0, err
+ }
+ switch tk := tk.(type) {
+ case json.Delim:
+ switch tk {
+ case '{':
+ offset, err = offsetSingleObject(dec, ttk)
+ if err != nil {
+ return 0, err
+ }
+ case '[':
+ offset, err = offsetSingleArray(dec, ttk)
+ if err != nil {
+ return 0, err
+ }
+ default:
+ return 0, fmt.Errorf("invalid token %#v: %w", tk, ErrPointer)
+ }
+ default:
+ return 0, fmt.Errorf("invalid token %#v: %w", tk, ErrPointer)
+ }
+ }
+ return offset, nil
}
-// Set uses the pointer to set a value from a JSON document
-func (p *Pointer) Set(document any, value any) (any, error) {
- return document, p.set(document, value, swag.DefaultJSONNameProvider)
+// "Constructor", parses the given string JSON pointer.
+func (p *Pointer) parse(jsonPointerString string) error {
+ if jsonPointerString == emptyPointer {
+ return nil
+ }
+
+ if !strings.HasPrefix(jsonPointerString, pointerSeparator) {
+ // non empty pointer must start with "/"
+ return errors.Join(ErrInvalidStart, ErrPointer)
+ }
+
+ referenceTokens := strings.Split(jsonPointerString, pointerSeparator)
+ p.referenceTokens = append(p.referenceTokens, referenceTokens[1:]...)
+
+ return nil
}
-// GetForToken gets a value for a json pointer token 1 level deep
-func GetForToken(document any, decodedToken string) (any, reflect.Kind, error) {
- return getSingleImpl(document, decodedToken, swag.DefaultJSONNameProvider)
+func (p *Pointer) get(node any, nameProvider *jsonname.NameProvider) (any, reflect.Kind, error) {
+ if nameProvider == nil {
+ nameProvider = jsonname.DefaultJSONNameProvider
+ }
+
+ kind := reflect.Invalid
+
+ // full document when empty
+ if len(p.referenceTokens) == 0 {
+ return node, kind, nil
+ }
+
+ for _, token := range p.referenceTokens {
+ decodedToken := Unescape(token)
+
+ r, knd, err := getSingleImpl(node, decodedToken, nameProvider)
+ if err != nil {
+ return nil, knd, err
+ }
+ node = r
+ }
+
+ rValue := reflect.ValueOf(node)
+ kind = rValue.Kind()
+
+ return node, kind, nil
}
-// SetForToken gets a value for a json pointer token 1 level deep
-func SetForToken(document any, decodedToken string, value any) (any, error) {
- return document, setSingleImpl(document, value, decodedToken, swag.DefaultJSONNameProvider)
+func (p *Pointer) set(node, data any, nameProvider *jsonname.NameProvider) error {
+ knd := reflect.ValueOf(node).Kind()
+
+ if knd != reflect.Pointer && knd != reflect.Struct && knd != reflect.Map && knd != reflect.Slice && knd != reflect.Array {
+ return errors.Join(
+ fmt.Errorf("unexpected type: %T", node), //nolint:err113 // err wrapping is carried out by errors.Join, not fmt.Errorf.
+ ErrUnsupportedValueType,
+ ErrPointer,
+ )
+ }
+
+ l := len(p.referenceTokens)
+
+ // full document when empty
+ if l == 0 {
+ return nil
+ }
+
+ if nameProvider == nil {
+ nameProvider = jsonname.DefaultJSONNameProvider
+ }
+
+ var decodedToken string
+ lastIndex := l - 1
+
+ if lastIndex > 0 { // skip if we only have one token in pointer
+ for _, token := range p.referenceTokens[:lastIndex] {
+ decodedToken = Unescape(token)
+ next, err := p.resolveNodeForToken(node, decodedToken, nameProvider)
+ if err != nil {
+ return err
+ }
+
+ node = next
+ }
+ }
+
+ // last token
+ decodedToken = Unescape(p.referenceTokens[lastIndex])
+
+ return setSingleImpl(node, data, decodedToken, nameProvider)
+}
+
+func (p *Pointer) resolveNodeForToken(node any, decodedToken string, nameProvider *jsonname.NameProvider) (next any, err error) {
+ // check for nil during traversal
+ if isNil(node) {
+ return nil, fmt.Errorf("cannot traverse through nil value at %q: %w", decodedToken, ErrPointer)
+ }
+
+ pointable, ok := node.(JSONPointable)
+ if ok {
+ r, err := pointable.JSONLookup(decodedToken)
+ if err != nil {
+ return nil, err
+ }
+
+ fld := reflect.ValueOf(r)
+ if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Pointer {
+ return fld.Addr().Interface(), nil
+ }
+
+ return r, nil
+ }
+
+ rValue := reflect.Indirect(reflect.ValueOf(node))
+ kind := rValue.Kind()
+
+ switch kind {
+ case reflect.Struct:
+ nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
+ if !ok {
+ return nil, fmt.Errorf("object has no field %q: %w", decodedToken, ErrPointer)
+ }
+
+ return typeFromValue(rValue.FieldByName(nm)), nil
+
+ case reflect.Map:
+ kv := reflect.ValueOf(decodedToken)
+ mv := rValue.MapIndex(kv)
+
+ if !mv.IsValid() {
+ return nil, errNoKey(decodedToken)
+ }
+
+ return typeFromValue(mv), nil
+
+ case reflect.Slice:
+ tokenIndex, err := strconv.Atoi(decodedToken)
+ if err != nil {
+ return nil, errors.Join(err, ErrPointer)
+ }
+
+ sLength := rValue.Len()
+ if tokenIndex < 0 || tokenIndex >= sLength {
+ return nil, errOutOfBounds(sLength, tokenIndex)
+ }
+
+ return typeFromValue(rValue.Index(tokenIndex)), nil
+
+ default:
+ return nil, errInvalidReference(decodedToken)
+ }
}
func isNil(input any) bool {
@@ -113,15 +295,33 @@ func isNil(input any) bool {
}
kind := reflect.TypeOf(input).Kind()
- switch kind { //nolint:exhaustive
- case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Chan:
+ switch kind {
+ case reflect.Pointer, reflect.Map, reflect.Slice, reflect.Chan:
return reflect.ValueOf(input).IsNil()
default:
return false
}
}
-func getSingleImpl(node any, decodedToken string, nameProvider *swag.NameProvider) (any, reflect.Kind, error) {
+func typeFromValue(v reflect.Value) any {
+ if v.CanAddr() && v.Kind() != reflect.Interface && v.Kind() != reflect.Map && v.Kind() != reflect.Slice && v.Kind() != reflect.Pointer {
+ return v.Addr().Interface()
+ }
+
+ return v.Interface()
+}
+
+// GetForToken gets a value for a json pointer token 1 level deep.
+func GetForToken(document any, decodedToken string) (any, reflect.Kind, error) {
+ return getSingleImpl(document, decodedToken, jsonname.DefaultJSONNameProvider)
+}
+
+// SetForToken sets a value for a json pointer token 1 level deep.
+func SetForToken(document any, decodedToken string, value any) (any, error) {
+ return document, setSingleImpl(document, value, decodedToken, jsonname.DefaultJSONNameProvider)
+}
+
+func getSingleImpl(node any, decodedToken string, nameProvider *jsonname.NameProvider) (any, reflect.Kind, error) {
rValue := reflect.Indirect(reflect.ValueOf(node))
kind := rValue.Kind()
if isNil(node) {
@@ -139,13 +339,15 @@ func getSingleImpl(node any, decodedToken string, nameProvider *swag.NameProvide
return getSingleImpl(*typed, decodedToken, nameProvider)
}
- switch kind { //nolint:exhaustive
+ switch kind {
case reflect.Struct:
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok {
return nil, kind, fmt.Errorf("object has no field %q: %w", decodedToken, ErrPointer)
}
+
fld := rValue.FieldByName(nm)
+
return fld.Interface(), kind, nil
case reflect.Map:
@@ -155,271 +357,100 @@ func getSingleImpl(node any, decodedToken string, nameProvider *swag.NameProvide
if mv.IsValid() {
return mv.Interface(), kind, nil
}
- return nil, kind, fmt.Errorf("object has no key %q: %w", decodedToken, ErrPointer)
+
+ return nil, kind, errNoKey(decodedToken)
case reflect.Slice:
tokenIndex, err := strconv.Atoi(decodedToken)
if err != nil {
- return nil, kind, err
+ return nil, kind, errors.Join(err, ErrPointer)
}
sLength := rValue.Len()
if tokenIndex < 0 || tokenIndex >= sLength {
- return nil, kind, fmt.Errorf("index out of bounds array[0,%d] index '%d': %w", sLength-1, tokenIndex, ErrPointer)
+ return nil, kind, errOutOfBounds(sLength, tokenIndex)
}
elem := rValue.Index(tokenIndex)
return elem.Interface(), kind, nil
default:
- return nil, kind, fmt.Errorf("invalid token reference %q: %w", decodedToken, ErrPointer)
+ return nil, kind, errInvalidReference(decodedToken)
}
-
}
-func setSingleImpl(node, data any, decodedToken string, nameProvider *swag.NameProvider) error {
- rValue := reflect.Indirect(reflect.ValueOf(node))
-
- // Check for nil to prevent panic when calling rValue.Type()
+func setSingleImpl(node, data any, decodedToken string, nameProvider *jsonname.NameProvider) error {
+ // check for nil to prevent panic when calling rValue.Type()
if isNil(node) {
return fmt.Errorf("cannot set field %q on nil value: %w", decodedToken, ErrPointer)
}
- if ns, ok := node.(JSONSetable); ok { // pointer impl
+ if ns, ok := node.(JSONSetable); ok {
return ns.JSONSet(decodedToken, data)
}
- if rValue.Type().Implements(jsonSetableType) {
- return node.(JSONSetable).JSONSet(decodedToken, data)
- }
+ rValue := reflect.Indirect(reflect.ValueOf(node))
- switch rValue.Kind() { //nolint:exhaustive
+ switch rValue.Kind() {
case reflect.Struct:
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok {
return fmt.Errorf("object has no field %q: %w", decodedToken, ErrPointer)
}
+
fld := rValue.FieldByName(nm)
- if fld.IsValid() {
- fld.Set(reflect.ValueOf(data))
+ if !fld.CanSet() {
+ return fmt.Errorf("can't set struct field %s to %v: %w", nm, data, ErrPointer)
+ }
+
+ value := reflect.ValueOf(data)
+ valueType := value.Type()
+ assignedType := fld.Type()
+
+ if !valueType.AssignableTo(assignedType) {
+ return fmt.Errorf("can't set value with type %T to field %s with type %v: %w", data, nm, assignedType, ErrPointer)
}
+
+ fld.Set(value)
+
return nil
case reflect.Map:
kv := reflect.ValueOf(decodedToken)
rValue.SetMapIndex(kv, reflect.ValueOf(data))
+
return nil
case reflect.Slice:
tokenIndex, err := strconv.Atoi(decodedToken)
if err != nil {
- return err
+ return errors.Join(err, ErrPointer)
}
+
sLength := rValue.Len()
if tokenIndex < 0 || tokenIndex >= sLength {
- return fmt.Errorf("index out of bounds array[0,%d] index '%d': %w", sLength, tokenIndex, ErrPointer)
+ return errOutOfBounds(sLength, tokenIndex)
}
elem := rValue.Index(tokenIndex)
if !elem.CanSet() {
return fmt.Errorf("can't set slice index %s to %v: %w", decodedToken, data, ErrPointer)
}
- elem.Set(reflect.ValueOf(data))
- return nil
-
- default:
- return fmt.Errorf("invalid token reference %q: %w", decodedToken, ErrPointer)
- }
-
-}
-func (p *Pointer) get(node any, nameProvider *swag.NameProvider) (any, reflect.Kind, error) {
+ value := reflect.ValueOf(data)
+ valueType := value.Type()
+ assignedType := elem.Type()
- if nameProvider == nil {
- nameProvider = swag.DefaultJSONNameProvider
- }
-
- kind := reflect.Invalid
-
- // Full document when empty
- if len(p.referenceTokens) == 0 {
- return node, kind, nil
- }
-
- for _, token := range p.referenceTokens {
- decodedToken := Unescape(token)
-
- r, knd, err := getSingleImpl(node, decodedToken, nameProvider)
- if err != nil {
- return nil, knd, err
+ if !valueType.AssignableTo(assignedType) {
+ return fmt.Errorf("can't set value with type %T to slice element %d with type %v: %w", data, tokenIndex, assignedType, ErrPointer)
}
- node = r
- }
-
- rValue := reflect.ValueOf(node)
- kind = rValue.Kind()
- return node, kind, nil
-}
+ elem.Set(value)
-func (p *Pointer) set(node, data any, nameProvider *swag.NameProvider) error {
- knd := reflect.ValueOf(node).Kind()
-
- if knd != reflect.Ptr && knd != reflect.Struct && knd != reflect.Map && knd != reflect.Slice && knd != reflect.Array {
- return errors.Join(
- ErrUnsupportedValueType,
- ErrPointer,
- )
- }
-
- if nameProvider == nil {
- nameProvider = swag.DefaultJSONNameProvider
- }
-
- // Full document when empty
- if len(p.referenceTokens) == 0 {
return nil
- }
-
- lastI := len(p.referenceTokens) - 1
- for i, token := range p.referenceTokens {
- isLastToken := i == lastI
- decodedToken := Unescape(token)
-
- if isLastToken {
-
- return setSingleImpl(node, data, decodedToken, nameProvider)
- }
-
- // Check for nil during traversal
- if isNil(node) {
- return fmt.Errorf("cannot traverse through nil value at %q: %w", decodedToken, ErrPointer)
- }
-
- rValue := reflect.Indirect(reflect.ValueOf(node))
- kind := rValue.Kind()
-
- if rValue.Type().Implements(jsonPointableType) {
- r, err := node.(JSONPointable).JSONLookup(decodedToken)
- if err != nil {
- return err
- }
- fld := reflect.ValueOf(r)
- if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Ptr {
- node = fld.Addr().Interface()
- continue
- }
- node = r
- continue
- }
-
- switch kind { //nolint:exhaustive
- case reflect.Struct:
- nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
- if !ok {
- return fmt.Errorf("object has no field %q: %w", decodedToken, ErrPointer)
- }
- fld := rValue.FieldByName(nm)
- if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Ptr {
- node = fld.Addr().Interface()
- continue
- }
- node = fld.Interface()
-
- case reflect.Map:
- kv := reflect.ValueOf(decodedToken)
- mv := rValue.MapIndex(kv)
-
- if !mv.IsValid() {
- return fmt.Errorf("object has no key %q: %w", decodedToken, ErrPointer)
- }
- if mv.CanAddr() && mv.Kind() != reflect.Interface && mv.Kind() != reflect.Map && mv.Kind() != reflect.Slice && mv.Kind() != reflect.Ptr {
- node = mv.Addr().Interface()
- continue
- }
- node = mv.Interface()
-
- case reflect.Slice:
- tokenIndex, err := strconv.Atoi(decodedToken)
- if err != nil {
- return err
- }
- sLength := rValue.Len()
- if tokenIndex < 0 || tokenIndex >= sLength {
- return fmt.Errorf("index out of bounds array[0,%d] index '%d': %w", sLength, tokenIndex, ErrPointer)
- }
-
- elem := rValue.Index(tokenIndex)
- if elem.CanAddr() && elem.Kind() != reflect.Interface && elem.Kind() != reflect.Map && elem.Kind() != reflect.Slice && elem.Kind() != reflect.Ptr {
- node = elem.Addr().Interface()
- continue
- }
- node = elem.Interface()
-
- default:
- return fmt.Errorf("invalid token reference %q: %w", decodedToken, ErrPointer)
- }
-
- }
-
- return nil
-}
-
-// DecodedTokens returns the decoded tokens
-func (p *Pointer) DecodedTokens() []string {
- result := make([]string, 0, len(p.referenceTokens))
- for _, t := range p.referenceTokens {
- result = append(result, Unescape(t))
- }
- return result
-}
-
-// IsEmpty returns true if this is an empty json pointer
-// this indicates that it points to the root document
-func (p *Pointer) IsEmpty() bool {
- return len(p.referenceTokens) == 0
-}
-
-// Pointer to string representation function
-func (p *Pointer) String() string {
-
- if len(p.referenceTokens) == 0 {
- return emptyPointer
- }
- pointerString := pointerSeparator + strings.Join(p.referenceTokens, pointerSeparator)
-
- return pointerString
-}
-
-func (p *Pointer) Offset(document string) (int64, error) {
- dec := json.NewDecoder(strings.NewReader(document))
- var offset int64
- for _, ttk := range p.DecodedTokens() {
- tk, err := dec.Token()
- if err != nil {
- return 0, err
- }
- switch tk := tk.(type) {
- case json.Delim:
- switch tk {
- case '{':
- offset, err = offsetSingleObject(dec, ttk)
- if err != nil {
- return 0, err
- }
- case '[':
- offset, err = offsetSingleArray(dec, ttk)
- if err != nil {
- return 0, err
- }
- default:
- return 0, fmt.Errorf("invalid token %#v: %w", tk, ErrPointer)
- }
- default:
- return 0, fmt.Errorf("invalid token %#v: %w", tk, ErrPointer)
- }
+ default:
+ return errInvalidReference(decodedToken)
}
- return offset, nil
}
func offsetSingleObject(dec *json.Decoder, decodedToken string) (int64, error) {
@@ -449,13 +480,14 @@ func offsetSingleObject(dec *json.Decoder, decodedToken string) (int64, error) {
return 0, fmt.Errorf("invalid token %#v: %w", tk, ErrPointer)
}
}
+
return 0, fmt.Errorf("token reference %q not found: %w", decodedToken, ErrPointer)
}
func offsetSingleArray(dec *json.Decoder, decodedToken string) (int64, error) {
idx, err := strconv.Atoi(decodedToken)
if err != nil {
- return 0, fmt.Errorf("token reference %q is not a number: %v: %w", decodedToken, err, ErrPointer)
+ return 0, fmt.Errorf("token reference %q is not a number: %w: %w", decodedToken, err, ErrPointer)
}
var i int
for i = 0; i < idx && dec.More(); i++ {
@@ -481,10 +513,12 @@ func offsetSingleArray(dec *json.Decoder, decodedToken string) (int64, error) {
if !dec.More() {
return 0, fmt.Errorf("token reference %q not found: %w", decodedToken, ErrPointer)
}
+
return dec.InputOffset(), nil
}
// drainSingle drains a single level of object or array.
+//
// The decoder has to guarantee the beginning delim (i.e. '{' or '[') has been consumed.
func drainSingle(dec *json.Decoder) error {
for dec.More() {
@@ -506,14 +540,15 @@ func drainSingle(dec *json.Decoder) error {
}
}
- // Consumes the ending delim
+ // consumes the ending delim
if _, err := dec.Token(); err != nil {
return err
}
+
return nil
}
-// Specific JSON pointer encoding here
+// JSON pointer encoding:
// ~0 => ~
// ~1 => /
// ... and vice versa
@@ -525,16 +560,24 @@ const (
decRefTok1 = `/`
)
-// Unescape unescapes a json pointer reference token string to the original representation
+var (
+ encRefTokReplacer = strings.NewReplacer(encRefTok1, decRefTok1, encRefTok0, decRefTok0) //nolint:gochecknoglobals // it's okay to declare a replacer as a private global
+ decRefTokReplacer = strings.NewReplacer(decRefTok1, encRefTok1, decRefTok0, encRefTok0) //nolint:gochecknoglobals // it's okay to declare a replacer as a private global
+)
+
+// Unescape unescapes a json pointer reference token string to the original representation.
func Unescape(token string) string {
- step1 := strings.ReplaceAll(token, encRefTok1, decRefTok1)
- step2 := strings.ReplaceAll(step1, encRefTok0, decRefTok0)
- return step2
+ return encRefTokReplacer.Replace(token)
}
-// Escape escapes a pointer reference token string
+// Escape escapes a pointer reference token string.
+//
+// The JSONPointer specification defines "/" as a separator and "~" as an escape prefix.
+//
+// Keys containing such characters are escaped with the following rules:
+//
+// - "~" is escaped as "~0"
+// - "/" is escaped as "~1"
func Escape(token string) string {
- step1 := strings.ReplaceAll(token, decRefTok0, encRefTok0)
- step2 := strings.ReplaceAll(step1, decRefTok1, encRefTok1)
- return step2
+ return decRefTokReplacer.Replace(token)
}
diff --git a/vendor/github.com/go-openapi/jsonreference/.cliff.toml b/vendor/github.com/go-openapi/jsonreference/.cliff.toml
new file mode 100644
index 0000000000..702629f5dc
--- /dev/null
+++ b/vendor/github.com/go-openapi/jsonreference/.cliff.toml
@@ -0,0 +1,181 @@
+# git-cliff ~ configuration file
+# https://git-cliff.org/docs/configuration
+
+[changelog]
+header = """
+"""
+
+footer = """
+
+-----
+
+**[{{ remote.github.repo }}]({{ self::remote_url() }}) license terms**
+
+[![License][license-badge]][license-url]
+
+[license-badge]: http://img.shields.io/badge/license-Apache%20v2-orange.svg
+[license-url]: {{ self::remote_url() }}/?tab=Apache-2.0-1-ov-file#readme
+
+{%- macro remote_url() -%}
+ https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}
+{%- endmacro -%}
+"""
+
+body = """
+{%- if version %}
+## [{{ version | trim_start_matches(pat="v") }}]({{ self::remote_url() }}/tree/{{ version }}) - {{ timestamp | date(format="%Y-%m-%d") }}
+{%- else %}
+## [unreleased]
+{%- endif %}
+{%- if message %}
+ {%- raw %}\n{% endraw %}
+{{ message }}
+ {%- raw %}\n{% endraw %}
+{%- endif %}
+{%- if version %}
+ {%- if previous.version %}
+
+**Full Changelog**: <{{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }}>
+ {%- endif %}
+{%- else %}
+ {%- raw %}\n{% endraw %}
+{%- endif %}
+
+{%- if statistics %}{% if statistics.commit_count %}
+ {%- raw %}\n{% endraw %}
+{{ statistics.commit_count }} commits in this release.
+ {%- raw %}\n{% endraw %}
+{%- endif %}{% endif %}
+-----
+
+{%- for group, commits in commits | group_by(attribute="group") %}
+ {%- raw %}\n{% endraw %}
+### {{ group | upper_first }}
+ {%- raw %}\n{% endraw %}
+ {%- for commit in commits %}
+ {%- if commit.remote.pr_title %}
+ {%- set commit_message = commit.remote.pr_title %}
+ {%- else %}
+ {%- set commit_message = commit.message %}
+ {%- endif %}
+* {{ commit_message | split(pat="\n") | first | trim }}
+ {%- if commit.remote.username %}
+{%- raw %} {% endraw %}by [@{{ commit.remote.username }}](https://github.com/{{ commit.remote.username }})
+ {%- endif %}
+ {%- if commit.remote.pr_number %}
+{%- raw %} {% endraw %}in [#{{ commit.remote.pr_number }}]({{ self::remote_url() }}/pull/{{ commit.remote.pr_number }})
+ {%- endif %}
+{%- raw %} {% endraw %}[...]({{ self::remote_url() }}/commit/{{ commit.id }})
+ {%- endfor %}
+{%- endfor %}
+
+{%- if github %}
+{%- raw %}\n{% endraw -%}
+ {%- set all_contributors = github.contributors | length %}
+ {%- if github.contributors | filter(attribute="username", value="dependabot[bot]") | length < all_contributors %}
+-----
+
+### People who contributed to this release
+ {% endif %}
+ {%- for contributor in github.contributors | filter(attribute="username") | sort(attribute="username") %}
+ {%- if contributor.username != "dependabot[bot]" and contributor.username != "github-actions[bot]" %}
+* [@{{ contributor.username }}](https://github.com/{{ contributor.username }})
+ {%- endif %}
+ {%- endfor %}
+
+ {% if github.contributors | filter(attribute="is_first_time", value=true) | length != 0 %}
+-----
+ {%- raw %}\n{% endraw %}
+
+### New Contributors
+ {%- endif %}
+
+ {%- for contributor in github.contributors | filter(attribute="is_first_time", value=true) %}
+ {%- if contributor.username != "dependabot[bot]" and contributor.username != "github-actions[bot]" %}
+* @{{ contributor.username }} made their first contribution
+ {%- if contributor.pr_number %}
+ in [#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \
+ {%- endif %}
+ {%- endif %}
+ {%- endfor %}
+{%- endif %}
+
+{%- raw %}\n{% endraw %}
+
+{%- macro remote_url() -%}
+ https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}
+{%- endmacro -%}
+"""
+# Remove leading and trailing whitespaces from the changelog's body.
+trim = true
+# Render body even when there are no releases to process.
+render_always = true
+# An array of regex based postprocessors to modify the changelog.
+postprocessors = [
+ # Replace the placeholder with a URL.
+ #{ pattern = '', replace = "https://github.com/orhun/git-cliff" },
+]
+# output file path
+# output = "test.md"
+
+[git]
+# Parse commits according to the conventional commits specification.
+# See https://www.conventionalcommits.org
+conventional_commits = false
+# Exclude commits that do not match the conventional commits specification.
+filter_unconventional = false
+# Require all commits to be conventional.
+# Takes precedence over filter_unconventional.
+require_conventional = false
+# Split commits on newlines, treating each line as an individual commit.
+split_commits = false
+# An array of regex based parsers to modify commit messages prior to further processing.
+commit_preprocessors = [
+ # Replace issue numbers with link templates to be updated in `changelog.postprocessors`.
+ #{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](/issues/${2}))"},
+ # Check spelling of the commit message using https://github.com/crate-ci/typos.
+ # If the spelling is incorrect, it will be fixed automatically.
+ #{ pattern = '.*', replace_command = 'typos --write-changes -' }
+]
+# Prevent commits that are breaking from being excluded by commit parsers.
+protect_breaking_commits = false
+# An array of regex based parsers for extracting data from the commit message.
+# Assigns commits to groups.
+# Optionally sets the commit's scope and can decide to exclude commits from further processing.
+commit_parsers = [
+ { message = "^[Cc]hore\\([Rr]elease\\): prepare for", skip = true },
+ { message = "(^[Mm]erge)|([Mm]erge conflict)", skip = true },
+ { field = "author.name", pattern = "dependabot*", group = "Updates" },
+ { message = "([Ss]ecurity)|([Vv]uln)", group = "Security" },
+ { body = "(.*[Ss]ecurity)|([Vv]uln)", group = "Security" },
+ { message = "([Cc]hore\\(lint\\))|(style)|(lint)|(codeql)|(golangci)", group = "Code quality" },
+ { message = "(^[Dd]oc)|((?i)readme)|(badge)|(typo)|(documentation)", group = "Documentation" },
+ { message = "(^[Ff]eat)|(^[Ee]nhancement)", group = "Implemented enhancements" },
+ { message = "(^ci)|(\\(ci\\))|(fixup\\s+ci)|(fix\\s+ci)|(license)|(example)", group = "Miscellaneous tasks" },
+ { message = "^test", group = "Testing" },
+ { message = "(^fix)|(panic)", group = "Fixed bugs" },
+ { message = "(^refact)|(rework)", group = "Refactor" },
+ { message = "(^[Pp]erf)|(performance)", group = "Performance" },
+ { message = "(^[Cc]hore)", group = "Miscellaneous tasks" },
+ { message = "^[Rr]evert", group = "Reverted changes" },
+ { message = "(upgrade.*?go)|(go\\s+version)", group = "Updates" },
+ { message = ".*", group = "Other" },
+]
+# Exclude commits that are not matched by any commit parser.
+filter_commits = false
+# An array of link parsers for extracting external references, and turning them into URLs, using regex.
+link_parsers = []
+# Include only the tags that belong to the current branch.
+use_branch_tags = false
+# Order releases topologically instead of chronologically.
+topo_order = false
+# Order releases topologically instead of chronologically.
+topo_order_commits = true
+# Order of commits in each group/release within the changelog.
+# Allowed values: newest, oldest
+sort_commits = "newest"
+# Process submodules commits
+recurse_submodules = false
+
+#[remote.github]
+#owner = "go-openapi"
diff --git a/vendor/github.com/go-openapi/jsonreference/.editorconfig b/vendor/github.com/go-openapi/jsonreference/.editorconfig
new file mode 100644
index 0000000000..3152da69a5
--- /dev/null
+++ b/vendor/github.com/go-openapi/jsonreference/.editorconfig
@@ -0,0 +1,26 @@
+# top-most EditorConfig file
+root = true
+
+# Unix-style newlines with a newline ending every file
+[*]
+end_of_line = lf
+insert_final_newline = true
+indent_style = space
+indent_size = 2
+trim_trailing_whitespace = true
+
+# Set default charset
+[*.{js,py,go,scala,rb,java,html,css,less,sass,md}]
+charset = utf-8
+
+# Tab indentation (no size specified)
+[*.go]
+indent_style = tab
+
+[*.md]
+trim_trailing_whitespace = false
+
+# Matches the exact files either package.json or .travis.yml
+[{package.json,.travis.yml}]
+indent_style = space
+indent_size = 2
diff --git a/vendor/github.com/go-openapi/jsonreference/.golangci.yml b/vendor/github.com/go-openapi/jsonreference/.golangci.yml
index 22f8d21cca..fdae591bce 100644
--- a/vendor/github.com/go-openapi/jsonreference/.golangci.yml
+++ b/vendor/github.com/go-openapi/jsonreference/.golangci.yml
@@ -1,61 +1,66 @@
-linters-settings:
- govet:
- check-shadowing: true
- golint:
- min-confidence: 0
- gocyclo:
- min-complexity: 45
- maligned:
- suggest-new: true
- dupl:
- threshold: 200
- goconst:
- min-len: 2
- min-occurrences: 3
-
+version: "2"
linters:
- enable-all: true
+ default: all
disable:
- - maligned
- - unparam
- - lll
- - gochecknoinits
- - gochecknoglobals
+ - depguard
- funlen
- godox
- - gocognit
- - whitespace
- - wsl
- - wrapcheck
- - testpackage
+ - exhaustruct
- nlreturn
- - gomnd
- - exhaustivestruct
- - goerr113
- - errorlint
- - nestif
- - godot
- - gofumpt
+ - nonamedreturns
+ - noinlineerr
- paralleltest
+ - recvcheck
+ - testpackage
- tparallel
- - thelper
- - ifshort
- - exhaustruct
- varnamelen
- - gci
- - depguard
- - errchkjson
- - inamedparam
- - nonamedreturns
- - musttag
- - ireturn
- - forcetypeassert
- - cyclop
- # deprecated linters
- - deadcode
- - interfacer
- - scopelint
- - varcheck
- - structcheck
- - golint
- - nosnakecase
+ - whitespace
+ - wrapcheck
+ - wsl
+ - wsl_v5
+ settings:
+ dupl:
+ threshold: 200
+ goconst:
+ min-len: 2
+ min-occurrences: 3
+ cyclop:
+ max-complexity: 20
+ gocyclo:
+ min-complexity: 20
+ exhaustive:
+ default-signifies-exhaustive: true
+ default-case-required: true
+ lll:
+ line-length: 180
+ exclusions:
+ generated: lax
+ presets:
+ - comments
+ - common-false-positives
+ - legacy
+ - std-error-handling
+ paths:
+ - third_party$
+ - builtin$
+ - examples$
+formatters:
+ enable:
+ - gofmt
+ - goimports
+ - gofumpt
+ exclusions:
+ generated: lax
+ paths:
+ - third_party$
+ - builtin$
+ - examples$
+issues:
+ # Maximum issues count per one linter.
+ # Set to 0 to disable.
+ # Default: 50
+ max-issues-per-linter: 0
+ # Maximum count of issues with the same text.
+ # Set to 0 to disable.
+ # Default: 3
+ max-same-issues: 0
diff --git a/vendor/github.com/go-openapi/jsonreference/CONTRIBUTORS.md b/vendor/github.com/go-openapi/jsonreference/CONTRIBUTORS.md
new file mode 100644
index 0000000000..9907d5d212
--- /dev/null
+++ b/vendor/github.com/go-openapi/jsonreference/CONTRIBUTORS.md
@@ -0,0 +1,21 @@
+# Contributors
+
+- Repository: ['go-openapi/jsonreference']
+
+| Total Contributors | Total Contributions |
+| --- | --- |
+| 9 | 68 |
+
+| Username | All Time Contribution Count | All Commits |
+| --- | --- | --- |
+| @fredbi | 31 | https://github.com/go-openapi/jsonreference/commits?author=fredbi |
+| @casualjim | 25 | https://github.com/go-openapi/jsonreference/commits?author=casualjim |
+| @youyuanwu | 5 | https://github.com/go-openapi/jsonreference/commits?author=youyuanwu |
+| @olivierlemasle | 2 | https://github.com/go-openapi/jsonreference/commits?author=olivierlemasle |
+| @apelisse | 1 | https://github.com/go-openapi/jsonreference/commits?author=apelisse |
+| @gbjk | 1 | https://github.com/go-openapi/jsonreference/commits?author=gbjk |
+| @honza | 1 | https://github.com/go-openapi/jsonreference/commits?author=honza |
+| @Neo2308 | 1 | https://github.com/go-openapi/jsonreference/commits?author=Neo2308 |
+| @erraggy | 1 | https://github.com/go-openapi/jsonreference/commits?author=erraggy |
+
+ _this file was generated by the [Contributors GitHub Action](https://github.com/github/contributors)_
diff --git a/vendor/github.com/go-openapi/jsonreference/NOTICE b/vendor/github.com/go-openapi/jsonreference/NOTICE
new file mode 100644
index 0000000000..f3b51939a9
--- /dev/null
+++ b/vendor/github.com/go-openapi/jsonreference/NOTICE
@@ -0,0 +1,39 @@
+Copyright 2015-2025 go-swagger maintainers
+
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+This software library, github.com/go-openapi/jsonpointer, includes software developed
+by the go-swagger and go-openapi maintainers ("go-swagger maintainers").
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this software except in compliance with the License.
+
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0.
+
+This software is copied from, derived from, and inspired by other original software products.
+It ships with copies of other software which license terms are recalled below.
+
+The original software was authored on 25-02-2013 by sigu-399 (https://github.com/sigu-399, sigu.399@gmail.com).
+
+github.com/sigh-399/jsonpointer
+===========================
+
+// SPDX-FileCopyrightText: Copyright 2013 sigu-399 ( https://github.com/sigu-399 )
+// SPDX-License-Identifier: Apache-2.0
+
+Copyright 2013 sigu-399 ( https://github.com/sigu-399 )
+
+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.
diff --git a/vendor/github.com/go-openapi/jsonreference/README.md b/vendor/github.com/go-openapi/jsonreference/README.md
index c7fc2049c1..d479dbdc73 100644
--- a/vendor/github.com/go-openapi/jsonreference/README.md
+++ b/vendor/github.com/go-openapi/jsonreference/README.md
@@ -1,19 +1,99 @@
-# gojsonreference [](https://github.com/go-openapi/jsonreference/actions?query=workflow%3A"go+test") [](https://codecov.io/gh/go-openapi/jsonreference)
+# jsonreference
-[](https://slackin.goswagger.io)
-[](https://raw.githubusercontent.com/go-openapi/jsonreference/master/LICENSE)
-[](https://pkg.go.dev/github.com/go-openapi/jsonreference)
-[](https://goreportcard.com/report/github.com/go-openapi/jsonreference)
+
+[![Tests][test-badge]][test-url] [![Coverage][cov-badge]][cov-url] [![CI vuln scan][vuln-scan-badge]][vuln-scan-url] [![CodeQL][codeql-badge]][codeql-url]
+
+
+
+[![Release][release-badge]][release-url] [![Go Report Card][gocard-badge]][gocard-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url]
+
+
+[![GoDoc][godoc-badge]][godoc-url] [![Slack Channel][slack-logo]![slack-badge]][slack-url] [![go version][goversion-badge]][goversion-url] ![Top language][top-badge] ![Commits since latest release][commits-badge]
-An implementation of JSON Reference - Go language
+---
+
+An implementation of JSON Reference for golang.
## Status
-Feature complete. Stable API
+
+API is stable.
+
+## Import this library in your project
+
+```cmd
+go get github.com/go-openapi/jsonreference
+```
## Dependencies
+
* https://github.com/go-openapi/jsonpointer
+## Basic usage
+
+## Change log
+
+See
+
## References
* http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07
* http://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03
+
+## Licensing
+
+This library ships under the [SPDX-License-Identifier: Apache-2.0](./LICENSE).
+
+See the license [NOTICE](./NOTICE), which recalls the licensing terms of all the pieces of software
+on top of which it has been built.
+
+## Other documentation
+
+* [All-time contributors](./CONTRIBUTORS.md)
+* [Contributing guidelines](.github/CONTRIBUTING.md)
+* [Maintainers documentation](docs/MAINTAINERS.md)
+* [Code style](docs/STYLE.md)
+
+## Cutting a new release
+
+Maintainers can cut a new release by either:
+
+* running [this workflow](https://github.com/go-openapi/jsonreference/actions/workflows/bump-release.yml)
+* or pushing a semver tag
+ * signed tags are preferred
+ * The tag message is prepended to release notes
+
+
+[test-badge]: https://github.com/go-openapi/jsonreference/actions/workflows/go-test.yml/badge.svg
+[test-url]: https://github.com/go-openapi/jsonreference/actions/workflows/go-test.yml
+[cov-badge]: https://codecov.io/gh/go-openapi/jsonreference/branch/master/graph/badge.svg
+[cov-url]: https://codecov.io/gh/go-openapi/jsonreference
+[vuln-scan-badge]: https://github.com/go-openapi/jsonreference/actions/workflows/scanner.yml/badge.svg
+[vuln-scan-url]: https://github.com/go-openapi/jsonreference/actions/workflows/scanner.yml
+[codeql-badge]: https://github.com/go-openapi/jsonreference/actions/workflows/codeql.yml/badge.svg
+[codeql-url]: https://github.com/go-openapi/jsonreference/actions/workflows/codeql.yml
+
+[release-badge]: https://badge.fury.io/gh/go-openapi%2Fjsonreference.svg
+[release-url]: https://badge.fury.io/gh/go-openapi%2Fjsonreference
+[gomod-badge]: https://badge.fury.io/go/github.com%2Fgo-openapi%2Fjsonreference.svg
+[gomod-url]: https://badge.fury.io/go/github.com%2Fgo-openapi%2Fjsonreference
+
+[gocard-badge]: https://goreportcard.com/badge/github.com/go-openapi/jsonreference
+[gocard-url]: https://goreportcard.com/report/github.com/go-openapi/jsonreference
+[codefactor-badge]: https://img.shields.io/codefactor/grade/github/go-openapi/jsonreference
+[codefactor-url]: https://www.codefactor.io/repository/github/go-openapi/jsonreference
+
+[doc-badge]: https://img.shields.io/badge/doc-site-blue?link=https%3A%2F%2Fgoswagger.io%2Fgo-openapi%2F
+[doc-url]: https://goswagger.io/go-openapi
+[godoc-badge]: https://pkg.go.dev/badge/github.com/go-openapi/jsonreference
+[godoc-url]: http://pkg.go.dev/github.com/go-openapi/jsonreference
+[slack-logo]: https://a.slack-edge.com/e6a93c1/img/icons/favicon-32.png
+[slack-badge]: https://img.shields.io/badge/slack-blue?link=https%3A%2F%2Fgoswagger.slack.com%2Farchives%2FC04R30YM
+[slack-url]: https://goswagger.slack.com/archives/C04R30YMU
+
+[license-badge]: http://img.shields.io/badge/license-Apache%20v2-orange.svg
+[license-url]: https://github.com/go-openapi/jsonreference/?tab=Apache-2.0-1-ov-file#readme
+
+[goversion-badge]: https://img.shields.io/github/go-mod/go-version/go-openapi/jsonreference
+[goversion-url]: https://github.com/go-openapi/jsonreference/blob/master/go.mod
+[top-badge]: https://img.shields.io/github/languages/top/go-openapi/jsonreference
+[commits-badge]: https://img.shields.io/github/commits-since/go-openapi/jsonreference/latest
diff --git a/vendor/github.com/go-openapi/jsonreference/SECURITY.md b/vendor/github.com/go-openapi/jsonreference/SECURITY.md
new file mode 100644
index 0000000000..2a7b6f0910
--- /dev/null
+++ b/vendor/github.com/go-openapi/jsonreference/SECURITY.md
@@ -0,0 +1,19 @@
+# Security Policy
+
+This policy outlines the commitment and practices of the go-openapi maintainers regarding security.
+
+## Supported Versions
+
+| Version | Supported |
+| ------- | ------------------ |
+| 0.22.x | :white_check_mark: |
+
+## Reporting a vulnerability
+
+If you become aware of a security vulnerability that affects the current repository,
+please report it privately to the maintainers.
+
+Please follow the instructions provided by github to
+[Privately report a security vulnerability](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability).
+
+TL;DR: on Github, navigate to the project's "Security" tab then click on "Report a vulnerability".
diff --git a/vendor/github.com/go-openapi/jsonreference/internal/normalize_url.go b/vendor/github.com/go-openapi/jsonreference/internal/normalize_url.go
index f0610cf1e5..a08b47320e 100644
--- a/vendor/github.com/go-openapi/jsonreference/internal/normalize_url.go
+++ b/vendor/github.com/go-openapi/jsonreference/internal/normalize_url.go
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright (c) 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
package internal
import (
@@ -11,9 +14,11 @@ const (
defaultHTTPSPort = ":443"
)
-// Regular expressions used by the normalizations
-var rxPort = regexp.MustCompile(`(:\d+)/?$`)
-var rxDupSlashes = regexp.MustCompile(`/{2,}`)
+// Regular expressions used by the normalizations.
+var (
+ rxPort = regexp.MustCompile(`(:\d+)/?$`)
+ rxDupSlashes = regexp.MustCompile(`/{2,}`)
+)
// NormalizeURL will normalize the specified URL
// This was added to replace a previous call to the no longer maintained purell library:
diff --git a/vendor/github.com/go-openapi/jsonreference/reference.go b/vendor/github.com/go-openapi/jsonreference/reference.go
index cfdef03e5d..6e3ae49951 100644
--- a/vendor/github.com/go-openapi/jsonreference/reference.go
+++ b/vendor/github.com/go-openapi/jsonreference/reference.go
@@ -1,27 +1,5 @@
-// Copyright 2013 sigu-399 ( https://github.com/sigu-399 )
-//
-// 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.
-
-// author sigu-399
-// author-github https://github.com/sigu-399
-// author-mail sigu.399@gmail.com
-//
-// repository-name jsonreference
-// repository-desc An implementation of JSON Reference - Go language
-//
-// description Main and unique file.
-//
-// created 26-02-2013
+// SPDX-FileCopyrightText: Copyright (c) 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
package jsonreference
@@ -38,50 +16,50 @@ const (
fragmentRune = `#`
)
-// New creates a new reference for the given string
-func New(jsonReferenceString string) (Ref, error) {
+var ErrChildURL = errors.New("child url is nil")
+
+// Ref represents a json reference object.
+type Ref struct {
+ referenceURL *url.URL
+ referencePointer jsonpointer.Pointer
+
+ HasFullURL bool
+ HasURLPathOnly bool
+ HasFragmentOnly bool
+ HasFileScheme bool
+ HasFullFilePath bool
+}
+// New creates a new reference for the given string.
+func New(jsonReferenceString string) (Ref, error) {
var r Ref
err := r.parse(jsonReferenceString)
return r, err
-
}
// MustCreateRef parses the ref string and panics when it's invalid.
-// Use the New method for a version that returns an error
+// Use the New method for a version that returns an error.
func MustCreateRef(ref string) Ref {
r, err := New(ref)
if err != nil {
panic(err)
}
- return r
-}
-// Ref represents a json reference object
-type Ref struct {
- referenceURL *url.URL
- referencePointer jsonpointer.Pointer
-
- HasFullURL bool
- HasURLPathOnly bool
- HasFragmentOnly bool
- HasFileScheme bool
- HasFullFilePath bool
+ return r
}
-// GetURL gets the URL for this reference
+// GetURL gets the URL for this reference.
func (r *Ref) GetURL() *url.URL {
return r.referenceURL
}
-// GetPointer gets the json pointer for this reference
+// GetPointer gets the json pointer for this reference.
func (r *Ref) GetPointer() *jsonpointer.Pointer {
return &r.referencePointer
}
-// String returns the best version of the url for this reference
+// String returns the best version of the url for this reference.
func (r *Ref) String() string {
-
if r.referenceURL != nil {
return r.referenceURL.String()
}
@@ -93,7 +71,7 @@ func (r *Ref) String() string {
return r.referencePointer.String()
}
-// IsRoot returns true if this reference is a root document
+// IsRoot returns true if this reference is a root document.
func (r *Ref) IsRoot() bool {
return r.referenceURL != nil &&
!r.IsCanonical() &&
@@ -101,14 +79,32 @@ func (r *Ref) IsRoot() bool {
r.referenceURL.Fragment == ""
}
-// IsCanonical returns true when this pointer starts with http(s):// or file://
+// IsCanonical returns true when this pointer starts with http(s):// or file://.
func (r *Ref) IsCanonical() bool {
return (r.HasFileScheme && r.HasFullFilePath) || (!r.HasFileScheme && r.HasFullURL)
}
-// "Constructor", parses the given string JSON reference
-func (r *Ref) parse(jsonReferenceString string) error {
+// Inherits creates a new reference from a parent and a child
+// If the child cannot inherit from the parent, an error is returned.
+func (r *Ref) Inherits(child Ref) (*Ref, error) {
+ childURL := child.GetURL()
+ parentURL := r.GetURL()
+ if childURL == nil {
+ return nil, ErrChildURL
+ }
+ if parentURL == nil {
+ return &child, nil
+ }
+
+ ref, err := New(parentURL.ResolveReference(childURL).String())
+ if err != nil {
+ return nil, err
+ }
+ return &ref, nil
+}
+// "Constructor", parses the given string JSON reference.
+func (r *Ref) parse(jsonReferenceString string) error {
parsed, err := url.Parse(jsonReferenceString)
if err != nil {
return err
@@ -137,22 +133,3 @@ func (r *Ref) parse(jsonReferenceString string) error {
return nil
}
-
-// Inherits creates a new reference from a parent and a child
-// If the child cannot inherit from the parent, an error is returned
-func (r *Ref) Inherits(child Ref) (*Ref, error) {
- childURL := child.GetURL()
- parentURL := r.GetURL()
- if childURL == nil {
- return nil, errors.New("child url is nil")
- }
- if parentURL == nil {
- return &child, nil
- }
-
- ref, err := New(parentURL.ResolveReference(childURL).String())
- if err != nil {
- return nil, err
- }
- return &ref, nil
-}
diff --git a/vendor/github.com/go-openapi/swag/.codecov.yml b/vendor/github.com/go-openapi/swag/.codecov.yml
new file mode 100644
index 0000000000..3354f44b28
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/.codecov.yml
@@ -0,0 +1,4 @@
+ignore:
+ - jsonutils/fixtures_test
+ - jsonutils/adapters/ifaces/mocks
+ - jsonutils/adapters/testintegration/benchmarks
diff --git a/vendor/github.com/go-openapi/swag/.golangci.yml b/vendor/github.com/go-openapi/swag/.golangci.yml
index d2fafb8a2b..126264a6b8 100644
--- a/vendor/github.com/go-openapi/swag/.golangci.yml
+++ b/vendor/github.com/go-openapi/swag/.golangci.yml
@@ -1,56 +1,78 @@
-linters-settings:
- gocyclo:
- min-complexity: 45
- dupl:
- threshold: 200
- goconst:
- min-len: 2
- min-occurrences: 3
-
+version: "2"
linters:
- enable-all: true
+ default: all
disable:
- - recvcheck
- - unparam
- - lll
- - gochecknoinits
- - gochecknoglobals
+ - cyclop
+ - depguard
+ - errchkjson
+ - errorlint
+ - exhaustruct
+ - forcetypeassert
- funlen
- - godox
+ - gochecknoglobals
+ - gochecknoinits
- gocognit
- - whitespace
- - wsl
- - wrapcheck
- - testpackage
- - nlreturn
- - errorlint
- - nestif
- godot
- - gofumpt
+ - godox
+ - gomoddirectives
+ - gosmopolitan
+ - inamedparam
+ - intrange
+ - ireturn
+ - lll
+ - musttag
+ - modernize
+ - nestif
+ - nlreturn
+ - nonamedreturns
+ - noinlineerr
- paralleltest
- - tparallel
+ - recvcheck
+ - testpackage
- thelper
- - exhaustruct
+ - tagliatelle
+ - tparallel
+ - unparam
- varnamelen
- - gci
- - depguard
- - errchkjson
- - inamedparam
- - nonamedreturns
- - musttag
- - ireturn
- - forcetypeassert
- - cyclop
- # deprecated linters
- #- deadcode
- #- interfacer
- #- scopelint
- #- varcheck
- #- structcheck
- #- golint
- #- nosnakecase
- #- maligned
- #- goerr113
- #- ifshort
- #- gomnd
- #- exhaustivestruct
+ - whitespace
+ - wrapcheck
+ - wsl
+ - wsl_v5
+ settings:
+ dupl:
+ threshold: 200
+ goconst:
+ min-len: 2
+ min-occurrences: 3
+ gocyclo:
+ min-complexity: 45
+ exclusions:
+ generated: lax
+ presets:
+ - comments
+ - common-false-positives
+ - legacy
+ - std-error-handling
+ paths:
+ - third_party$
+ - builtin$
+ - examples$
+formatters:
+ enable:
+ - gofmt
+ - goimports
+ exclusions:
+ generated: lax
+ paths:
+ - third_party$
+ - builtin$
+ - examples$
+issues:
+ # Maximum issues count per one linter.
+ # Set to 0 to disable.
+ # Default: 50
+ max-issues-per-linter: 0
+ # Maximum count of issues with the same text.
+ # Set to 0 to disable.
+ # Default: 3
+ max-same-issues: 0
diff --git a/vendor/github.com/go-openapi/swag/.mockery.yml b/vendor/github.com/go-openapi/swag/.mockery.yml
new file mode 100644
index 0000000000..8557cb58d3
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/.mockery.yml
@@ -0,0 +1,30 @@
+all: false
+dir: '{{.InterfaceDir}}'
+filename: mocks_test.go
+force-file-write: true
+formatter: goimports
+include-auto-generated: false
+log-level: info
+structname: '{{.Mock}}{{.InterfaceName}}'
+pkgname: '{{.SrcPackageName}}'
+recursive: false
+require-template-schema-exists: true
+template: matryer
+template-schema: '{{.Template}}.schema.json'
+packages:
+ github.com/go-openapi/swag/jsonutils/adapters/ifaces:
+ config:
+ dir: jsonutils/adapters/ifaces/mocks
+ filename: mocks.go
+ pkgname: 'mocks'
+ force-file-write: true
+ all: true
+ github.com/go-openapi/swag/jsonutils/adapters/testintegration:
+ config:
+ inpackage: true
+ dir: jsonutils/adapters/testintegration
+ force-file-write: true
+ all: true
+ interfaces:
+ EJMarshaler:
+ EJUnmarshaler:
diff --git a/vendor/github.com/go-openapi/swag/README.md b/vendor/github.com/go-openapi/swag/README.md
index a729222998..371fd55fdc 100644
--- a/vendor/github.com/go-openapi/swag/README.md
+++ b/vendor/github.com/go-openapi/swag/README.md
@@ -1,23 +1,239 @@
# Swag [](https://github.com/go-openapi/swag/actions?query=workflow%3A"go+test") [](https://codecov.io/gh/go-openapi/swag)
[](https://slackin.goswagger.io)
-[](https://raw.githubusercontent.com/go-openapi/swag/master/LICENSE)
+[](https://raw.githubusercontent.com/go-openapi/swag/master/LICENSE)
[](https://pkg.go.dev/github.com/go-openapi/swag)
[](https://goreportcard.com/report/github.com/go-openapi/swag)
-Contains a bunch of helper functions for go-openapi and go-swagger projects.
+Package `swag` contains a bunch of helper functions for go-openapi and go-swagger projects.
You may also use it standalone for your projects.
-* convert between value and pointers for builtin types
-* convert from string to builtin types (wraps strconv)
-* fast json concatenation
-* search in path
-* load from file or http
-* name mangling
+> **NOTE**
+> `swag` is one of the foundational building blocks of the go-openapi initiative.
+> Most repositories in `github.com/go-openapi/...` depend on it in some way.
+> And so does our CLI tool `github.com/go-swagger/go-swagger`,
+> as well as the code generated by this tool.
+* [Contents](#contents)
+* [Dependencies](#dependencies)
+* [Release Notes](#release-notes)
+* [Licensing](#licensing)
+* [Note to contributors](#note-to-contributors)
+* [TODOs, suggestions and plans](#todos-suggestions-and-plans)
-This repo has only few dependencies outside of the standard library:
+## Contents
-* YAML utilities depend on `gopkg.in/yaml.v3`
-* `github.com/mailru/easyjson v0.7.7`
+`go-openapi/swag` exposes a collection of relatively independent modules.
+
+Moving forward, no additional feature will be added to the `swag` API directly at the root package level,
+which remains there for backward-compatibility purposes. All exported top-level features are now deprecated.
+
+Child modules will continue to evolve and some new ones may be added in the future.
+
+| Module | Content | Main features |
+|---------------|---------|---------------|
+| `cmdutils` | utilities to work with CLIs ||
+| `conv` | type conversion utilities | convert between values and pointers for any types
convert from string to builtin types (wraps `strconv`)
require `./typeutils` (test dependency)
|
+| `fileutils` | file utilities | |
+| `jsonname` | JSON utilities | infer JSON names from `go` properties
|
+| `jsonutils` | JSON utilities | fast json concatenation
read and write JSON from and to dynamic `go` data structures
~require `github.com/mailru/easyjson`~
|
+| `loading` | file loading | load from file or http
require `./yamlutils`
|
+| `mangling` | safe name generation | name mangling for `go`
|
+| `netutils` | networking utilities | host, port from address
|
+| `stringutils` | `string` utilities | search in slice (with case-insensitive)
split/join query parameters as arrays
|
+| `typeutils` | `go` types utilities | check the zero value for any type
safe check for a nil value
|
+| `yamlutils` | YAML utilities | converting YAML to JSON
loading YAML into a dynamic YAML document
maintaining the original order of keys in YAML objects
require `./jsonutils`
~require `github.com/mailru/easyjson`~
require `go.yaml.in/yaml/v3`
|
+
+---
+
+## Dependencies
+
+The root module `github.com/go-openapi/swag` at the repo level maintains a few
+dependencies outside of the standard library.
+
+* YAML utilities depend on `go.yaml.in/yaml/v3`
+* JSON utilities depend on their registered adapter module:
+ * by default, only the standard library is used
+ * `github.com/mailru/easyjson` is now only a dependency for module
+ `github.com/go-openapi/swag/jsonutils/adapters/easyjson/json`,
+ for users willing to import that module.
+ * integration tests and benchmarks use all the dependencies are published as their own module
+* other dependencies are test dependencies drawn from `github.com/stretchr/testify`
+
+## Release notes
+
+### v0.25.4
+
+** mangling**
+
+Bug fix
+
+* [x] mangler may panic with pluralized overlapping initialisms
+
+Tests
+
+* [x] introduced fuzz tests
+
+### v0.25.3
+
+** mangling**
+
+Bug fix
+
+* [x] mangler may panic with pluralized initialisms
+
+### v0.25.2
+
+Minor changes due to internal maintenance that don't affect the behavior of the library.
+
+* [x] removed indirect test dependencies by switching all tests to `go-openapi/testify`,
+ a fork of `stretch/testify` with zero-dependencies.
+* [x] improvements to CI to catch test reports.
+* [x] modernized licensing annotations in source code, using the more compact SPDX annotations
+ rather than the full license terms.
+* [x] simplified a bit JSON & YAML testing by using newly available assertions
+* started the journey to an OpenSSF score card badge:
+ * [x] explicited permissions in CI workflows
+ * [x] published security policy
+ * pinned dependencies to github actions
+ * introduced fuzzing in tests
+
+### v0.25.1
+
+* fixes a data race that could occur when using the standard library implementation of a JSON ordered map
+
+### v0.25.0
+
+**New with this release**:
+
+* requires `go1.24`, as iterators are being introduced
+* removes the dependency to `mailru/easyjson` by default (#68)
+ * functionality remains the same, but performance may somewhat degrade for applications
+ that relied on `easyjson`
+ * users of the JSON or YAML utilities who want to use `easyjson` as their preferred JSON serializer library
+ will be able to do so by registering this the corresponding JSON adapter at runtime. See below.
+ * ordered keys in JSON and YAML objects: this feature used to rely solely on `easyjson`.
+ With this release, an implementation relying on the standard `encoding/json` is provided.
+ * an independent [benchmark](./jsonutils/adapters/testintegration/benchmarks/README.md) to compare the different adapters
+* improves the "float is integer" check (`conv.IsFloat64AJSONInteger`) (#59)
+* removes the _direct_ dependency to `gopkg.in/yaml.v3` (indirect dependency is still incurred through `stretchr/testify`) (#127)
+* exposed `conv.IsNil()` (previously kept private): a safe nil check (accounting for the "non-nil interface with nil value" nonsensical go trick)
+
+**What coming next?**
+
+Moving forward, we want to :
+* provide an implementation of the JSON adapter based on `encoding/json/v2`, for `go1.25` builds.
+* provide similar implementations for `goccy/go-json` and `jsoniterator/go`, and perhaps some other
+ similar libraries may be interesting too.
+
+
+**How to explicitly register a dependency at runtime**?
+
+The following would maintain how JSON utilities proposed by `swag` used work, up to `v0.24.1`.
+
+ ```go
+ import (
+ "github.com/go-openapi/swag/jsonutils/adapters"
+ easyjson "github.com/go-openapi/swag/jsonutils/adapters/easyjson/json"
+ )
+
+ func init() {
+ easyjson.Register(adapters.Registry)
+ }
+ ```
+
+Subsequent calls to `jsonutils.ReadJSON()` or `jsonutils.WriteJSON()` will switch to `easyjson`
+whenever the passed data structures implement the `easyjson.Unmarshaler` or `easyjson.Marshaler` respectively,
+or fallback to the standard library.
+
+For more details, you may also look at our
+[integration tests](jsonutils/adapters/testintegration/integration_suite_test.go#29).
+
+### v0.24.0
+
+With this release, we have largely modernized the API of `swag`:
+
+* The traditional `swag` API is still supported: code that imports `swag` will still
+ compile and work the same.
+* A deprecation notice is published to encourage consumers of this library to adopt
+ the newer API
+* **Deprecation notice**
+ * configuration through global variables is now deprecated, in favor of options passed as parameters
+ * all helper functions are moved to more specialized packages, which are exposed as
+ go modules. Importing such a module would reduce the footprint of dependencies.
+ * _all_ functions, variables, constants exposed by the deprecated API have now moved, so
+ that consumers of the new API no longer need to import github.com/go-openapi/swag, but
+ should import the desired sub-module(s).
+
+**New with this release**:
+
+* [x] type converters and pointer to value helpers now support generic types
+* [x] name mangling now support pluralized initialisms (issue #46)
+ Strings like "contact IDs" are now recognized as such a plural form and mangled as a linter would expect.
+* [x] performance: small improvements to reduce the overhead of convert/format wrappers (see issues #110, or PR #108)
+* [x] performance: name mangling utilities run ~ 10% faster (PR #115)
+
+---
+
+## Licensing
+
+This library ships under the [SPDX-License-Identifier: Apache-2.0](./LICENSE).
+
+## Note to contributors
+
+A mono-repo structure comes with some unavoidable extra pains...
+
+* Testing
+
+> The usual `go test ./...` command, run from the root of this repo won't work any longer to test all submodules.
+>
+> Each module constitutes an independant unit of test. So you have to run `go test` inside each module.
+> Or you may take a look at how this is achieved by CI
+> [here] https://github.com/go-openapi/swag/blob/master/.github/workflows/go-test.yml).
+>
+> There are also some alternative tricks using `go work`, for local development, if you feel comfortable with
+> go workspaces. Perhaps some day, we'll have a `go work test` to run all tests without any hack.
+
+* Releasing
+
+> Each module follows its own independant module versioning.
+>
+> So you have tags like `mangling/v0.24.0`, `fileutils/v0.24.0` etc that are used by `go mod` and `go get`
+> to refer to the tagged version of each module specifically.
+>
+> This means we may release patches etc to each module independently.
+>
+> We'd like to adopt the rule that modules in this repo would only differ by a patch version
+> (e.g. `v0.24.5` vs `v0.24.3`), and we'll level all modules whenever a minor version is introduced.
+>
+> A script in `./hack` is provided to tag all modules with the same version in one go.
+
+* Continuous integration
+
+> At this moment, all tests in all modules are systematically run over the full test matrix (3 platform x 2 go releases).
+> This generates quite a lot of jobs.
+>
+> We ought to reduce the number of jobs required to test a PR focused on only a few modules.
+
+## Todos, suggestions and plans
+
+All kinds of contributions are welcome.
+
+A few ideas:
+
+* [x] Complete the split of dependencies to isolate easyjson from the rest
+* [x] Improve CI to reduce needed tests
+* [x] Replace dependency to `gopkg.in/yaml.v3` (`yamlutil`)
+* [ ] Improve mangling utilities (improve readability, support for capitalized words,
+ better word substitution for non-letter symbols...)
+* [ ] Move back to this common shared pot a few of the technical features introduced by go-swagger independently
+ (e.g. mangle go package names, search package with go modules support, ...)
+* [ ] Apply a similar mono-repo approach to go-openapi/strfmt which suffer from similar woes: bloated API,
+ imposed dependency to some database driver.
+* [ ] Adapt `go-swagger` (incl. generated code) to the new `swag` API.
+* [ ] Factorize some tests, as there is a lot of redundant testing code in `jsonutils`
+* [ ] Benchmark & profiling: publish independently the tool built to analyze and chart benchmarks (e.g. similar to `benchvisual`)
+* [ ] more thorough testing for nil / null case
+* [ ] ci pipeline to manage releases
+* [ ] cleaner mockery generation (doesn't work out of the box for all sub-modules)
diff --git a/vendor/github.com/go-openapi/swag/SECURITY.md b/vendor/github.com/go-openapi/swag/SECURITY.md
new file mode 100644
index 0000000000..72296a8313
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/SECURITY.md
@@ -0,0 +1,19 @@
+# Security Policy
+
+This policy outlines the commitment and practices of the go-openapi maintainers regarding security.
+
+## Supported Versions
+
+| Version | Supported |
+| ------- | ------------------ |
+| 0.25.x | :white_check_mark: |
+
+## Reporting a vulnerability
+
+If you become aware of a security vulnerability that affects the current repository,
+please report it privately to the maintainers.
+
+Please follow the instructions provided by github to
+[Privately report a security vulnerability](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability).
+
+TL;DR: on Github, navigate to the project's "Security" tab then click on "Report a vulnerability".
diff --git a/vendor/github.com/go-openapi/swag/cmdutils/LICENSE b/vendor/github.com/go-openapi/swag/cmdutils/LICENSE
new file mode 100644
index 0000000000..d645695673
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/cmdutils/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/vendor/github.com/go-openapi/swag/cmdutils/cmd_utils.go b/vendor/github.com/go-openapi/swag/cmdutils/cmd_utils.go
new file mode 100644
index 0000000000..6c7bbb26f0
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/cmdutils/cmd_utils.go
@@ -0,0 +1,13 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package cmdutils
+
+// CommandLineOptionsGroup represents a group of user-defined command line options.
+//
+// This is for instance used to configure command line arguments in API servers generated by go-swagger.
+type CommandLineOptionsGroup struct {
+ ShortDescription string
+ LongDescription string
+ Options any
+}
diff --git a/vendor/github.com/go-openapi/swag/cmdutils/doc.go b/vendor/github.com/go-openapi/swag/cmdutils/doc.go
new file mode 100644
index 0000000000..31f2c37538
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/cmdutils/doc.go
@@ -0,0 +1,5 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+// Package cmdutils brings helpers for CLIs produced by go-openapi
+package cmdutils
diff --git a/vendor/github.com/go-openapi/swag/cmdutils_iface.go b/vendor/github.com/go-openapi/swag/cmdutils_iface.go
new file mode 100644
index 0000000000..bd0c1fc128
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/cmdutils_iface.go
@@ -0,0 +1,11 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package swag
+
+import "github.com/go-openapi/swag/cmdutils"
+
+// CommandLineOptionsGroup represents a group of user-defined command line options.
+//
+// Deprecated: use [cmdutils.CommandLineOptionsGroup] instead.
+type CommandLineOptionsGroup = cmdutils.CommandLineOptionsGroup
diff --git a/vendor/github.com/go-openapi/swag/conv/LICENSE b/vendor/github.com/go-openapi/swag/conv/LICENSE
new file mode 100644
index 0000000000..d645695673
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/conv/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/vendor/github.com/go-openapi/swag/conv/convert.go b/vendor/github.com/go-openapi/swag/conv/convert.go
new file mode 100644
index 0000000000..f205c39134
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/conv/convert.go
@@ -0,0 +1,161 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package conv
+
+import (
+ "math"
+ "strconv"
+ "strings"
+)
+
+// same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER
+const (
+ maxJSONFloat = float64(1<<53 - 1) // 9007199254740991.0 2^53 - 1
+ minJSONFloat = -float64(1<<53 - 1) //-9007199254740991.0 -2^53 - 1
+ epsilon float64 = 1e-9
+)
+
+// IsFloat64AJSONInteger allows for integers [-2^53, 2^53-1] inclusive.
+func IsFloat64AJSONInteger(f float64) bool {
+ if math.IsNaN(f) || math.IsInf(f, 0) || f < minJSONFloat || f > maxJSONFloat {
+ return false
+ }
+ rounded := math.Round(f)
+ if f == rounded {
+ return true
+ }
+ if rounded == 0 { // f = 0.0 exited above
+ return false
+ }
+
+ diff := math.Abs(f - rounded)
+ if diff == 0 {
+ return true
+ }
+
+ // relative error Abs{f - Round(f)) / Round(f)} < ε ; Round(f)
+ return diff < epsilon*math.Abs(rounded)
+}
+
+// ConvertFloat turns a string into a float numerical value.
+func ConvertFloat[T Float](str string) (T, error) {
+ var v T
+ f, err := strconv.ParseFloat(str, bitsize(v))
+ if err != nil {
+ return 0, err
+ }
+
+ return T(f), nil
+}
+
+// ConvertInteger turns a string into a signed integer.
+func ConvertInteger[T Signed](str string) (T, error) {
+ var v T
+ f, err := strconv.ParseInt(str, 10, bitsize(v))
+ if err != nil {
+ return 0, err
+ }
+
+ return T(f), nil
+}
+
+// ConvertUinteger turns a string into an unsigned integer.
+func ConvertUinteger[T Unsigned](str string) (T, error) {
+ var v T
+ f, err := strconv.ParseUint(str, 10, bitsize(v))
+ if err != nil {
+ return 0, err
+ }
+
+ return T(f), nil
+}
+
+// ConvertBool turns a string into a boolean.
+//
+// It supports a few more "true" strings than [strconv.ParseBool]:
+//
+// - it is not case sensitive ("trUe" or "FalsE" work)
+// - "ok", "yes", "y", "on", "selected", "checked", "enabled" are all true
+// - everything that is not true is false: there is never an actual error returned
+func ConvertBool(str string) (bool, error) {
+ switch strings.ToLower(str) {
+ case "true",
+ "1",
+ "yes",
+ "ok",
+ "y",
+ "on",
+ "selected",
+ "checked",
+ "t",
+ "enabled":
+ return true, nil
+ default:
+ return false, nil
+ }
+}
+
+// ConvertFloat32 turns a string into a float32.
+func ConvertFloat32(str string) (float32, error) { return ConvertFloat[float32](str) }
+
+// ConvertFloat64 turns a string into a float64
+func ConvertFloat64(str string) (float64, error) { return ConvertFloat[float64](str) }
+
+// ConvertInt8 turns a string into an int8
+func ConvertInt8(str string) (int8, error) { return ConvertInteger[int8](str) }
+
+// ConvertInt16 turns a string into an int16
+func ConvertInt16(str string) (int16, error) {
+ i, err := strconv.ParseInt(str, 10, 16)
+ if err != nil {
+ return 0, err
+ }
+ return int16(i), nil
+}
+
+// ConvertInt32 turns a string into an int32
+func ConvertInt32(str string) (int32, error) {
+ i, err := strconv.ParseInt(str, 10, 32)
+ if err != nil {
+ return 0, err
+ }
+ return int32(i), nil
+}
+
+// ConvertInt64 turns a string into an int64
+func ConvertInt64(str string) (int64, error) {
+ return strconv.ParseInt(str, 10, 64)
+}
+
+// ConvertUint8 turns a string into an uint8
+func ConvertUint8(str string) (uint8, error) {
+ i, err := strconv.ParseUint(str, 10, 8)
+ if err != nil {
+ return 0, err
+ }
+ return uint8(i), nil
+}
+
+// ConvertUint16 turns a string into an uint16
+func ConvertUint16(str string) (uint16, error) {
+ i, err := strconv.ParseUint(str, 10, 16)
+ if err != nil {
+ return 0, err
+ }
+ return uint16(i), nil
+}
+
+// ConvertUint32 turns a string into an uint32
+func ConvertUint32(str string) (uint32, error) {
+ i, err := strconv.ParseUint(str, 10, 32)
+ if err != nil {
+ return 0, err
+ }
+ return uint32(i), nil
+}
+
+// ConvertUint64 turns a string into an uint64
+func ConvertUint64(str string) (uint64, error) {
+ return strconv.ParseUint(str, 10, 64)
+}
diff --git a/vendor/github.com/go-openapi/swag/conv/convert_types.go b/vendor/github.com/go-openapi/swag/conv/convert_types.go
new file mode 100644
index 0000000000..cf4c6495eb
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/conv/convert_types.go
@@ -0,0 +1,72 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package conv
+
+// Unlicensed credits (idea, concept)
+//
+// The idea to convert values to pointers and the other way around, was inspired, eons ago, by the aws go sdk.
+//
+// Nowadays, all sensible API sdk's expose a similar functionality.
+
+// Pointer returns a pointer to the value passed in.
+func Pointer[T any](v T) *T {
+ return &v
+}
+
+// Value returns a shallow copy of the value of the pointer passed in.
+//
+// If the pointer is nil, the returned value is the zero value.
+func Value[T any](v *T) T {
+ if v != nil {
+ return *v
+ }
+
+ var zero T
+ return zero
+}
+
+// PointerSlice converts a slice of values into a slice of pointers.
+func PointerSlice[T any](src []T) []*T {
+ dst := make([]*T, len(src))
+ for i := 0; i < len(src); i++ {
+ dst[i] = &(src[i])
+ }
+ return dst
+}
+
+// ValueSlice converts a slice of pointers into a slice of values.
+//
+// nil elements are zero values.
+func ValueSlice[T any](src []*T) []T {
+ dst := make([]T, len(src))
+ for i := 0; i < len(src); i++ {
+ if src[i] != nil {
+ dst[i] = *(src[i])
+ }
+ }
+ return dst
+}
+
+// PointerMap converts a map of values into a map of pointers.
+func PointerMap[K comparable, T any](src map[K]T) map[K]*T {
+ dst := make(map[K]*T)
+ for k, val := range src {
+ v := val
+ dst[k] = &v
+ }
+ return dst
+}
+
+// ValueMap converts a map of pointers into a map of values.
+//
+// nil elements are skipped.
+func ValueMap[K comparable, T any](src map[K]*T) map[K]T {
+ dst := make(map[K]T)
+ for k, val := range src {
+ if val != nil {
+ dst[k] = *val
+ }
+ }
+ return dst
+}
diff --git a/vendor/github.com/go-openapi/swag/conv/doc.go b/vendor/github.com/go-openapi/swag/conv/doc.go
new file mode 100644
index 0000000000..1bd6ead6e2
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/conv/doc.go
@@ -0,0 +1,15 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+// Package conv exposes utilities to convert types.
+//
+// The Convert and Format families of functions are essentially a shorthand to [strconv] functions,
+// using the decimal representation of numbers.
+//
+// Features:
+//
+// - from string representation to value ("Convert*") and reciprocally ("Format*")
+// - from pointer to value ([Value]) and reciprocally ([Pointer])
+// - from slice of values to slice of pointers ([PointerSlice]) and reciprocally ([ValueSlice])
+// - from map of values to map of pointers ([PointerMap]) and reciprocally ([ValueMap])
+package conv
diff --git a/vendor/github.com/go-openapi/swag/conv/format.go b/vendor/github.com/go-openapi/swag/conv/format.go
new file mode 100644
index 0000000000..5b87b8e146
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/conv/format.go
@@ -0,0 +1,28 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package conv
+
+import (
+ "strconv"
+)
+
+// FormatInteger turns an integer type into a string.
+func FormatInteger[T Signed](value T) string {
+ return strconv.FormatInt(int64(value), 10)
+}
+
+// FormatUinteger turns an unsigned integer type into a string.
+func FormatUinteger[T Unsigned](value T) string {
+ return strconv.FormatUint(uint64(value), 10)
+}
+
+// FormatFloat turns a floating point numerical value into a string.
+func FormatFloat[T Float](value T) string {
+ return strconv.FormatFloat(float64(value), 'f', -1, bitsize(value))
+}
+
+// FormatBool turns a boolean into a string.
+func FormatBool(value bool) string {
+ return strconv.FormatBool(value)
+}
diff --git a/vendor/github.com/go-openapi/swag/conv/sizeof.go b/vendor/github.com/go-openapi/swag/conv/sizeof.go
new file mode 100644
index 0000000000..4943465573
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/conv/sizeof.go
@@ -0,0 +1,20 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package conv
+
+import "unsafe"
+
+// bitsize returns the size in bits of a type.
+//
+// NOTE: [unsafe.SizeOf] simply returns the size in bytes of the value.
+// For primitive types T, the generic stencil is precompiled and this value
+// is resolved at compile time, resulting in an immediate call to [strconv.ParseFloat].
+//
+// We may leave up to the go compiler to simplify this function into a
+// constant value, which happens in practice at least for primitive types
+// (e.g. numerical types).
+func bitsize[T Numerical](value T) int {
+ const bitsPerByte = 8
+ return int(unsafe.Sizeof(value)) * bitsPerByte
+}
diff --git a/vendor/github.com/go-openapi/swag/conv/type_constraints.go b/vendor/github.com/go-openapi/swag/conv/type_constraints.go
new file mode 100644
index 0000000000..81135e827e
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/conv/type_constraints.go
@@ -0,0 +1,29 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package conv
+
+type (
+ // these type constraints are redefined after golang.org/x/exp/constraints,
+ // because importing that package causes an undesired go upgrade.
+
+ // Signed integer types, cf. [golang.org/x/exp/constraints.Signed]
+ Signed interface {
+ ~int | ~int8 | ~int16 | ~int32 | ~int64
+ }
+
+ // Unsigned integer types, cf. [golang.org/x/exp/constraints.Unsigned]
+ Unsigned interface {
+ ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
+ }
+
+ // Float numerical types, cf. [golang.org/x/exp/constraints.Float]
+ Float interface {
+ ~float32 | ~float64
+ }
+
+ // Numerical types
+ Numerical interface {
+ Signed | Unsigned | Float
+ }
+)
diff --git a/vendor/github.com/go-openapi/swag/conv_iface.go b/vendor/github.com/go-openapi/swag/conv_iface.go
new file mode 100644
index 0000000000..eea7b2e56e
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/conv_iface.go
@@ -0,0 +1,486 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package swag
+
+import (
+ "time"
+
+ "github.com/go-openapi/swag/conv"
+)
+
+// IsFloat64AJSONInteger allows for integers [-2^53, 2^53-1] inclusive.
+//
+// Deprecated: use [conv.IsFloat64AJSONInteger] instead.
+func IsFloat64AJSONInteger(f float64) bool { return conv.IsFloat64AJSONInteger(f) }
+
+// ConvertBool turns a string into a boolean.
+//
+// Deprecated: use [conv.ConvertBool] instead.
+func ConvertBool(str string) (bool, error) { return conv.ConvertBool(str) }
+
+// ConvertFloat32 turns a string into a float32.
+//
+// Deprecated: use [conv.ConvertFloat32] instead. Alternatively, you may use the generic version [conv.ConvertFloat].
+func ConvertFloat32(str string) (float32, error) { return conv.ConvertFloat[float32](str) }
+
+// ConvertFloat64 turns a string into a float64.
+//
+// Deprecated: use [conv.ConvertFloat64] instead. Alternatively, you may use the generic version [conv.ConvertFloat].
+func ConvertFloat64(str string) (float64, error) { return conv.ConvertFloat[float64](str) }
+
+// ConvertInt8 turns a string into an int8.
+//
+// Deprecated: use [conv.ConvertInt8] instead. Alternatively, you may use the generic version [conv.ConvertInteger].
+func ConvertInt8(str string) (int8, error) { return conv.ConvertInteger[int8](str) }
+
+// ConvertInt16 turns a string into an int16.
+//
+// Deprecated: use [conv.ConvertInt16] instead. Alternatively, you may use the generic version [conv.ConvertInteger].
+func ConvertInt16(str string) (int16, error) { return conv.ConvertInteger[int16](str) }
+
+// ConvertInt32 turns a string into an int32.
+//
+// Deprecated: use [conv.ConvertInt32] instead. Alternatively, you may use the generic version [conv.ConvertInteger].
+func ConvertInt32(str string) (int32, error) { return conv.ConvertInteger[int32](str) }
+
+// ConvertInt64 turns a string into an int64.
+//
+// Deprecated: use [conv.ConvertInt64] instead. Alternatively, you may use the generic version [conv.ConvertInteger].
+func ConvertInt64(str string) (int64, error) { return conv.ConvertInteger[int64](str) }
+
+// ConvertUint8 turns a string into an uint8.
+//
+// Deprecated: use [conv.ConvertUint8] instead. Alternatively, you may use the generic version [conv.ConvertUinteger].
+func ConvertUint8(str string) (uint8, error) { return conv.ConvertUinteger[uint8](str) }
+
+// ConvertUint16 turns a string into an uint16.
+//
+// Deprecated: use [conv.ConvertUint16] instead. Alternatively, you may use the generic version [conv.ConvertUinteger].
+func ConvertUint16(str string) (uint16, error) { return conv.ConvertUinteger[uint16](str) }
+
+// ConvertUint32 turns a string into an uint32.
+//
+// Deprecated: use [conv.ConvertUint32] instead. Alternatively, you may use the generic version [conv.ConvertUinteger].
+func ConvertUint32(str string) (uint32, error) { return conv.ConvertUinteger[uint32](str) }
+
+// ConvertUint64 turns a string into an uint64.
+//
+// Deprecated: use [conv.ConvertUint64] instead. Alternatively, you may use the generic version [conv.ConvertUinteger].
+func ConvertUint64(str string) (uint64, error) { return conv.ConvertUinteger[uint64](str) }
+
+// FormatBool turns a boolean into a string.
+//
+// Deprecated: use [conv.FormatBool] instead.
+func FormatBool(value bool) string { return conv.FormatBool(value) }
+
+// FormatFloat32 turns a float32 into a string.
+//
+// Deprecated: use [conv.FormatFloat] instead.
+func FormatFloat32(value float32) string { return conv.FormatFloat(value) }
+
+// FormatFloat64 turns a float64 into a string.
+//
+// Deprecated: use [conv.FormatFloat] instead.
+func FormatFloat64(value float64) string { return conv.FormatFloat(value) }
+
+// FormatInt8 turns an int8 into a string.
+//
+// Deprecated: use [conv.FormatInteger] instead.
+func FormatInt8(value int8) string { return conv.FormatInteger(value) }
+
+// FormatInt16 turns an int16 into a string.
+//
+// Deprecated: use [conv.FormatInteger] instead.
+func FormatInt16(value int16) string { return conv.FormatInteger(value) }
+
+// FormatInt32 turns an int32 into a string
+//
+// Deprecated: use [conv.FormatInteger] instead.
+func FormatInt32(value int32) string { return conv.FormatInteger(value) }
+
+// FormatInt64 turns an int64 into a string.
+//
+// Deprecated: use [conv.FormatInteger] instead.
+func FormatInt64(value int64) string { return conv.FormatInteger(value) }
+
+// FormatUint8 turns an uint8 into a string.
+//
+// Deprecated: use [conv.FormatUinteger] instead.
+func FormatUint8(value uint8) string { return conv.FormatUinteger(value) }
+
+// FormatUint16 turns an uint16 into a string.
+//
+// Deprecated: use [conv.FormatUinteger] instead.
+func FormatUint16(value uint16) string { return conv.FormatUinteger(value) }
+
+// FormatUint32 turns an uint32 into a string.
+//
+// Deprecated: use [conv.FormatUinteger] instead.
+func FormatUint32(value uint32) string { return conv.FormatUinteger(value) }
+
+// FormatUint64 turns an uint64 into a string.
+//
+// Deprecated: use [conv.FormatUinteger] instead.
+func FormatUint64(value uint64) string { return conv.FormatUinteger(value) }
+
+// String turn a pointer to of the string value passed in.
+//
+// Deprecated: use [conv.Pointer] instead.
+func String(v string) *string { return conv.Pointer(v) }
+
+// StringValue turn the value of the string pointer passed in or
+// "" if the pointer is nil.
+//
+// Deprecated: use [conv.Value] instead.
+func StringValue(v *string) string { return conv.Value(v) }
+
+// StringSlice converts a slice of string values into a slice of string pointers.
+//
+// Deprecated: use [conv.PointerSlice] instead.
+func StringSlice(src []string) []*string { return conv.PointerSlice(src) }
+
+// StringValueSlice converts a slice of string pointers into a slice of string values.
+//
+// Deprecated: use [conv.ValueSlice] instead.
+func StringValueSlice(src []*string) []string { return conv.ValueSlice(src) }
+
+// StringMap converts a string map of string values into a string map of string pointers.
+//
+// Deprecated: use [conv.PointerMap] instead.
+func StringMap(src map[string]string) map[string]*string { return conv.PointerMap(src) }
+
+// StringValueMap converts a string map of string pointers into a string map of string values.
+//
+// Deprecated: use [conv.ValueMap] instead.
+func StringValueMap(src map[string]*string) map[string]string { return conv.ValueMap(src) }
+
+// Bool turn a pointer to of the bool value passed in.
+//
+// Deprecated: use [conv.Pointer] instead.
+func Bool(v bool) *bool { return conv.Pointer(v) }
+
+// BoolValue turn the value of the bool pointer passed in or false if the pointer is nil.
+//
+// Deprecated: use [conv.Value] instead.
+func BoolValue(v *bool) bool { return conv.Value(v) }
+
+// BoolSlice converts a slice of bool values into a slice of bool pointers.
+//
+// Deprecated: use [conv.PointerSlice] instead.
+func BoolSlice(src []bool) []*bool { return conv.PointerSlice(src) }
+
+// BoolValueSlice converts a slice of bool pointers into a slice of bool values.
+//
+// Deprecated: use [conv.ValueSlice] instead.
+func BoolValueSlice(src []*bool) []bool { return conv.ValueSlice(src) }
+
+// BoolMap converts a string map of bool values into a string map of bool pointers.
+//
+// Deprecated: use [conv.PointerMap] instead.
+func BoolMap(src map[string]bool) map[string]*bool { return conv.PointerMap(src) }
+
+// BoolValueMap converts a string map of bool pointers into a string map of bool values.
+//
+// Deprecated: use [conv.ValueMap] instead.
+func BoolValueMap(src map[string]*bool) map[string]bool { return conv.ValueMap(src) }
+
+// Int turn a pointer to of the int value passed in.
+//
+// Deprecated: use [conv.Pointer] instead.
+func Int(v int) *int { return conv.Pointer(v) }
+
+// IntValue turn the value of the int pointer passed in or 0 if the pointer is nil.
+//
+// Deprecated: use [conv.Value] instead.
+func IntValue(v *int) int { return conv.Value(v) }
+
+// IntSlice converts a slice of int values into a slice of int pointers.
+//
+// Deprecated: use [conv.PointerSlice] instead.
+func IntSlice(src []int) []*int { return conv.PointerSlice(src) }
+
+// IntValueSlice converts a slice of int pointers into a slice of int values.
+//
+// Deprecated: use [conv.ValueSlice] instead.
+func IntValueSlice(src []*int) []int { return conv.ValueSlice(src) }
+
+// IntMap converts a string map of int values into a string map of int pointers.
+//
+// Deprecated: use [conv.PointerMap] instead.
+func IntMap(src map[string]int) map[string]*int { return conv.PointerMap(src) }
+
+// IntValueMap converts a string map of int pointers into a string map of int values.
+//
+// Deprecated: use [conv.ValueMap] instead.
+func IntValueMap(src map[string]*int) map[string]int { return conv.ValueMap(src) }
+
+// Int32 turn a pointer to of the int32 value passed in.
+//
+// Deprecated: use [conv.Pointer] instead.
+func Int32(v int32) *int32 { return conv.Pointer(v) }
+
+// Int32Value turn the value of the int32 pointer passed in or 0 if the pointer is nil.
+//
+// Deprecated: use [conv.Value] instead.
+func Int32Value(v *int32) int32 { return conv.Value(v) }
+
+// Int32Slice converts a slice of int32 values into a slice of int32 pointers.
+//
+// Deprecated: use [conv.PointerSlice] instead.
+func Int32Slice(src []int32) []*int32 { return conv.PointerSlice(src) }
+
+// Int32ValueSlice converts a slice of int32 pointers into a slice of int32 values.
+//
+// Deprecated: use [conv.ValueSlice] instead.
+func Int32ValueSlice(src []*int32) []int32 { return conv.ValueSlice(src) }
+
+// Int32Map converts a string map of int32 values into a string map of int32 pointers.
+//
+// Deprecated: use [conv.PointerMap] instead.
+func Int32Map(src map[string]int32) map[string]*int32 { return conv.PointerMap(src) }
+
+// Int32ValueMap converts a string map of int32 pointers into a string map of int32 values.
+//
+// Deprecated: use [conv.ValueMap] instead.
+func Int32ValueMap(src map[string]*int32) map[string]int32 { return conv.ValueMap(src) }
+
+// Int64 turn a pointer to of the int64 value passed in.
+//
+// Deprecated: use [conv.Pointer] instead.
+func Int64(v int64) *int64 { return conv.Pointer(v) }
+
+// Int64Value turn the value of the int64 pointer passed in or 0 if the pointer is nil.
+//
+// Deprecated: use [conv.Value] instead.
+func Int64Value(v *int64) int64 { return conv.Value(v) }
+
+// Int64Slice converts a slice of int64 values into a slice of int64 pointers.
+//
+// Deprecated: use [conv.PointerSlice] instead.
+func Int64Slice(src []int64) []*int64 { return conv.PointerSlice(src) }
+
+// Int64ValueSlice converts a slice of int64 pointers into a slice of int64 values.
+//
+// Deprecated: use [conv.ValueSlice] instead.
+func Int64ValueSlice(src []*int64) []int64 { return conv.ValueSlice(src) }
+
+// Int64Map converts a string map of int64 values into a string map of int64 pointers.
+//
+// Deprecated: use [conv.PointerMap] instead.
+func Int64Map(src map[string]int64) map[string]*int64 { return conv.PointerMap(src) }
+
+// Int64ValueMap converts a string map of int64 pointers into a string map of int64 values.
+//
+// Deprecated: use [conv.ValueMap] instead.
+func Int64ValueMap(src map[string]*int64) map[string]int64 { return conv.ValueMap(src) }
+
+// Uint16 turn a pointer to of the uint16 value passed in.
+//
+// Deprecated: use [conv.Pointer] instead.
+func Uint16(v uint16) *uint16 { return conv.Pointer(v) }
+
+// Uint16Value turn the value of the uint16 pointer passed in or 0 if the pointer is nil.
+//
+// Deprecated: use [conv.Value] instead.
+func Uint16Value(v *uint16) uint16 { return conv.Value(v) }
+
+// Uint16Slice converts a slice of uint16 values into a slice of uint16 pointers.
+//
+// Deprecated: use [conv.PointerSlice] instead.
+func Uint16Slice(src []uint16) []*uint16 { return conv.PointerSlice(src) }
+
+// Uint16ValueSlice converts a slice of uint16 pointers into a slice of uint16 values.
+//
+// Deprecated: use [conv.ValueSlice] instead.
+func Uint16ValueSlice(src []*uint16) []uint16 { return conv.ValueSlice(src) }
+
+// Uint16Map converts a string map of uint16 values into a string map of uint16 pointers.
+//
+// Deprecated: use [conv.PointerMap] instead.
+func Uint16Map(src map[string]uint16) map[string]*uint16 { return conv.PointerMap(src) }
+
+// Uint16ValueMap converts a string map of uint16 pointers into a string map of uint16 values.
+//
+// Deprecated: use [conv.ValueMap] instead.
+func Uint16ValueMap(src map[string]*uint16) map[string]uint16 { return conv.ValueMap(src) }
+
+// Uint turn a pointer to of the uint value passed in.
+//
+// Deprecated: use [conv.Pointer] instead.
+func Uint(v uint) *uint { return conv.Pointer(v) }
+
+// UintValue turn the value of the uint pointer passed in or 0 if the pointer is nil.
+//
+// Deprecated: use [conv.Value] instead.
+func UintValue(v *uint) uint { return conv.Value(v) }
+
+// UintSlice converts a slice of uint values into a slice of uint pointers.
+//
+// Deprecated: use [conv.PointerSlice] instead.
+func UintSlice(src []uint) []*uint { return conv.PointerSlice(src) }
+
+// UintValueSlice converts a slice of uint pointers into a slice of uint values.
+//
+// Deprecated: use [conv.ValueSlice] instead.
+func UintValueSlice(src []*uint) []uint { return conv.ValueSlice(src) }
+
+// UintMap converts a string map of uint values into a string map of uint pointers.
+//
+// Deprecated: use [conv.PointerMap] instead.
+func UintMap(src map[string]uint) map[string]*uint { return conv.PointerMap(src) }
+
+// UintValueMap converts a string map of uint pointers into a string map of uint values.
+//
+// Deprecated: use [conv.ValueMap] instead.
+func UintValueMap(src map[string]*uint) map[string]uint { return conv.ValueMap(src) }
+
+// Uint32 turn a pointer to of the uint32 value passed in.
+//
+// Deprecated: use [conv.Pointer] instead.
+func Uint32(v uint32) *uint32 { return conv.Pointer(v) }
+
+// Uint32Value turn the value of the uint32 pointer passed in or 0 if the pointer is nil.
+//
+// Deprecated: use [conv.Value] instead.
+func Uint32Value(v *uint32) uint32 { return conv.Value(v) }
+
+// Uint32Slice converts a slice of uint32 values into a slice of uint32 pointers.
+//
+// Deprecated: use [conv.PointerSlice] instead.
+func Uint32Slice(src []uint32) []*uint32 { return conv.PointerSlice(src) }
+
+// Uint32ValueSlice converts a slice of uint32 pointers into a slice of uint32 values.
+//
+// Deprecated: use [conv.ValueSlice] instead.
+func Uint32ValueSlice(src []*uint32) []uint32 { return conv.ValueSlice(src) }
+
+// Uint32Map converts a string map of uint32 values into a string map of uint32 pointers.
+//
+// Deprecated: use [conv.PointerMap] instead.
+func Uint32Map(src map[string]uint32) map[string]*uint32 { return conv.PointerMap(src) }
+
+// Uint32ValueMap converts a string map of uint32 pointers into a string map of uint32 values.
+//
+// Deprecated: use [conv.ValueMap] instead.
+func Uint32ValueMap(src map[string]*uint32) map[string]uint32 { return conv.ValueMap(src) }
+
+// Uint64 turn a pointer to of the uint64 value passed in.
+//
+// Deprecated: use [conv.Pointer] instead.
+func Uint64(v uint64) *uint64 { return conv.Pointer(v) }
+
+// Uint64Value turn the value of the uint64 pointer passed in or 0 if the pointer is nil.
+//
+// Deprecated: use [conv.Value] instead.
+func Uint64Value(v *uint64) uint64 { return conv.Value(v) }
+
+// Uint64Slice converts a slice of uint64 values into a slice of uint64 pointers.
+//
+// Deprecated: use [conv.PointerSlice] instead.
+func Uint64Slice(src []uint64) []*uint64 { return conv.PointerSlice(src) }
+
+// Uint64ValueSlice converts a slice of uint64 pointers into a slice of uint64 values.
+//
+// Deprecated: use [conv.ValueSlice] instead.
+func Uint64ValueSlice(src []*uint64) []uint64 { return conv.ValueSlice(src) }
+
+// Uint64Map converts a string map of uint64 values into a string map of uint64 pointers.
+//
+// Deprecated: use [conv.PointerMap] instead.
+func Uint64Map(src map[string]uint64) map[string]*uint64 { return conv.PointerMap(src) }
+
+// Uint64ValueMap converts a string map of uint64 pointers into a string map of uint64 values.
+//
+// Deprecated: use [conv.ValueMap] instead.
+func Uint64ValueMap(src map[string]*uint64) map[string]uint64 { return conv.ValueMap(src) }
+
+// Float32 turn a pointer to of the float32 value passed in.
+//
+// Deprecated: use [conv.Pointer] instead.
+func Float32(v float32) *float32 { return conv.Pointer(v) }
+
+// Float32Value turn the value of the float32 pointer passed in or 0 if the pointer is nil.
+//
+// Deprecated: use [conv.Value] instead.
+func Float32Value(v *float32) float32 { return conv.Value(v) }
+
+// Float32Slice converts a slice of float32 values into a slice of float32 pointers.
+//
+// Deprecated: use [conv.PointerSlice] instead.
+func Float32Slice(src []float32) []*float32 { return conv.PointerSlice(src) }
+
+// Float32ValueSlice converts a slice of float32 pointers into a slice of float32 values.
+//
+// Deprecated: use [conv.ValueSlice] instead.
+func Float32ValueSlice(src []*float32) []float32 { return conv.ValueSlice(src) }
+
+// Float32Map converts a string map of float32 values into a string map of float32 pointers.
+//
+// Deprecated: use [conv.PointerMap] instead.
+func Float32Map(src map[string]float32) map[string]*float32 { return conv.PointerMap(src) }
+
+// Float32ValueMap converts a string map of float32 pointers into a string map of float32 values.
+//
+// Deprecated: use [conv.ValueMap] instead.
+func Float32ValueMap(src map[string]*float32) map[string]float32 { return conv.ValueMap(src) }
+
+// Float64 turn a pointer to of the float64 value passed in.
+//
+// Deprecated: use [conv.Pointer] instead.
+func Float64(v float64) *float64 { return conv.Pointer(v) }
+
+// Float64Value turn the value of the float64 pointer passed in or 0 if the pointer is nil.
+//
+// Deprecated: use [conv.Value] instead.
+func Float64Value(v *float64) float64 { return conv.Value(v) }
+
+// Float64Slice converts a slice of float64 values into a slice of float64 pointers.
+//
+// Deprecated: use [conv.PointerSlice] instead.
+func Float64Slice(src []float64) []*float64 { return conv.PointerSlice(src) }
+
+// Float64ValueSlice converts a slice of float64 pointers into a slice of float64 values.
+//
+// Deprecated: use [conv.ValueSlice] instead.
+func Float64ValueSlice(src []*float64) []float64 { return conv.ValueSlice(src) }
+
+// Float64Map converts a string map of float64 values into a string map of float64 pointers.
+//
+// Deprecated: use [conv.PointerMap] instead.
+func Float64Map(src map[string]float64) map[string]*float64 { return conv.PointerMap(src) }
+
+// Float64ValueMap converts a string map of float64 pointers into a string map of float64 values.
+//
+// Deprecated: use [conv.ValueMap] instead.
+func Float64ValueMap(src map[string]*float64) map[string]float64 { return conv.ValueMap(src) }
+
+// Time turn a pointer to of the time.Time value passed in.
+//
+// Deprecated: use [conv.Pointer] instead.
+func Time(v time.Time) *time.Time { return conv.Pointer(v) }
+
+// TimeValue turn the value of the time.Time pointer passed in or time.Time{} if the pointer is nil.
+//
+// Deprecated: use [conv.Value] instead.
+func TimeValue(v *time.Time) time.Time { return conv.Value(v) }
+
+// TimeSlice converts a slice of time.Time values into a slice of time.Time pointers.
+//
+// Deprecated: use [conv.PointerSlice] instead.
+func TimeSlice(src []time.Time) []*time.Time { return conv.PointerSlice(src) }
+
+// TimeValueSlice converts a slice of time.Time pointers into a slice of time.Time values
+//
+// Deprecated: use [conv.ValueSlice] instead.
+func TimeValueSlice(src []*time.Time) []time.Time { return conv.ValueSlice(src) }
+
+// TimeMap converts a string map of time.Time values into a string map of time.Time pointers.
+//
+// Deprecated: use [conv.PointerMap] instead.
+func TimeMap(src map[string]time.Time) map[string]*time.Time { return conv.PointerMap(src) }
+
+// TimeValueMap converts a string map of time.Time pointers into a string map of time.Time values.
+//
+// Deprecated: use [conv.ValueMap] instead.
+func TimeValueMap(src map[string]*time.Time) map[string]time.Time { return conv.ValueMap(src) }
diff --git a/vendor/github.com/go-openapi/swag/convert.go b/vendor/github.com/go-openapi/swag/convert.go
deleted file mode 100644
index fc085aeb8e..0000000000
--- a/vendor/github.com/go-openapi/swag/convert.go
+++ /dev/null
@@ -1,208 +0,0 @@
-// Copyright 2015 go-swagger maintainers
-//
-// 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 swag
-
-import (
- "math"
- "strconv"
- "strings"
-)
-
-// same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER
-const (
- maxJSONFloat = float64(1<<53 - 1) // 9007199254740991.0 2^53 - 1
- minJSONFloat = -float64(1<<53 - 1) //-9007199254740991.0 -2^53 - 1
- epsilon float64 = 1e-9
-)
-
-// IsFloat64AJSONInteger allow for integers [-2^53, 2^53-1] inclusive
-func IsFloat64AJSONInteger(f float64) bool {
- if math.IsNaN(f) || math.IsInf(f, 0) || f < minJSONFloat || f > maxJSONFloat {
- return false
- }
- fa := math.Abs(f)
- g := float64(uint64(f))
- ga := math.Abs(g)
-
- diff := math.Abs(f - g)
-
- // more info: https://floating-point-gui.de/errors/comparison/#look-out-for-edge-cases
- switch {
- case f == g: // best case
- return true
- case f == float64(int64(f)) || f == float64(uint64(f)): // optimistic case
- return true
- case f == 0 || g == 0 || diff < math.SmallestNonzeroFloat64: // very close to 0 values
- return diff < (epsilon * math.SmallestNonzeroFloat64)
- }
- // check the relative error
- return diff/math.Min(fa+ga, math.MaxFloat64) < epsilon
-}
-
-var evaluatesAsTrue map[string]struct{}
-
-func init() {
- evaluatesAsTrue = map[string]struct{}{
- "true": {},
- "1": {},
- "yes": {},
- "ok": {},
- "y": {},
- "on": {},
- "selected": {},
- "checked": {},
- "t": {},
- "enabled": {},
- }
-}
-
-// ConvertBool turn a string into a boolean
-func ConvertBool(str string) (bool, error) {
- _, ok := evaluatesAsTrue[strings.ToLower(str)]
- return ok, nil
-}
-
-// ConvertFloat32 turn a string into a float32
-func ConvertFloat32(str string) (float32, error) {
- f, err := strconv.ParseFloat(str, 32)
- if err != nil {
- return 0, err
- }
- return float32(f), nil
-}
-
-// ConvertFloat64 turn a string into a float64
-func ConvertFloat64(str string) (float64, error) {
- return strconv.ParseFloat(str, 64)
-}
-
-// ConvertInt8 turn a string into an int8
-func ConvertInt8(str string) (int8, error) {
- i, err := strconv.ParseInt(str, 10, 8)
- if err != nil {
- return 0, err
- }
- return int8(i), nil
-}
-
-// ConvertInt16 turn a string into an int16
-func ConvertInt16(str string) (int16, error) {
- i, err := strconv.ParseInt(str, 10, 16)
- if err != nil {
- return 0, err
- }
- return int16(i), nil
-}
-
-// ConvertInt32 turn a string into an int32
-func ConvertInt32(str string) (int32, error) {
- i, err := strconv.ParseInt(str, 10, 32)
- if err != nil {
- return 0, err
- }
- return int32(i), nil
-}
-
-// ConvertInt64 turn a string into an int64
-func ConvertInt64(str string) (int64, error) {
- return strconv.ParseInt(str, 10, 64)
-}
-
-// ConvertUint8 turn a string into an uint8
-func ConvertUint8(str string) (uint8, error) {
- i, err := strconv.ParseUint(str, 10, 8)
- if err != nil {
- return 0, err
- }
- return uint8(i), nil
-}
-
-// ConvertUint16 turn a string into an uint16
-func ConvertUint16(str string) (uint16, error) {
- i, err := strconv.ParseUint(str, 10, 16)
- if err != nil {
- return 0, err
- }
- return uint16(i), nil
-}
-
-// ConvertUint32 turn a string into an uint32
-func ConvertUint32(str string) (uint32, error) {
- i, err := strconv.ParseUint(str, 10, 32)
- if err != nil {
- return 0, err
- }
- return uint32(i), nil
-}
-
-// ConvertUint64 turn a string into an uint64
-func ConvertUint64(str string) (uint64, error) {
- return strconv.ParseUint(str, 10, 64)
-}
-
-// FormatBool turns a boolean into a string
-func FormatBool(value bool) string {
- return strconv.FormatBool(value)
-}
-
-// FormatFloat32 turns a float32 into a string
-func FormatFloat32(value float32) string {
- return strconv.FormatFloat(float64(value), 'f', -1, 32)
-}
-
-// FormatFloat64 turns a float64 into a string
-func FormatFloat64(value float64) string {
- return strconv.FormatFloat(value, 'f', -1, 64)
-}
-
-// FormatInt8 turns an int8 into a string
-func FormatInt8(value int8) string {
- return strconv.FormatInt(int64(value), 10)
-}
-
-// FormatInt16 turns an int16 into a string
-func FormatInt16(value int16) string {
- return strconv.FormatInt(int64(value), 10)
-}
-
-// FormatInt32 turns an int32 into a string
-func FormatInt32(value int32) string {
- return strconv.Itoa(int(value))
-}
-
-// FormatInt64 turns an int64 into a string
-func FormatInt64(value int64) string {
- return strconv.FormatInt(value, 10)
-}
-
-// FormatUint8 turns an uint8 into a string
-func FormatUint8(value uint8) string {
- return strconv.FormatUint(uint64(value), 10)
-}
-
-// FormatUint16 turns an uint16 into a string
-func FormatUint16(value uint16) string {
- return strconv.FormatUint(uint64(value), 10)
-}
-
-// FormatUint32 turns an uint32 into a string
-func FormatUint32(value uint32) string {
- return strconv.FormatUint(uint64(value), 10)
-}
-
-// FormatUint64 turns an uint64 into a string
-func FormatUint64(value uint64) string {
- return strconv.FormatUint(value, 10)
-}
diff --git a/vendor/github.com/go-openapi/swag/convert_types.go b/vendor/github.com/go-openapi/swag/convert_types.go
deleted file mode 100644
index c49cc473a8..0000000000
--- a/vendor/github.com/go-openapi/swag/convert_types.go
+++ /dev/null
@@ -1,730 +0,0 @@
-package swag
-
-import "time"
-
-// This file was taken from the aws go sdk
-
-// String returns a pointer to of the string value passed in.
-func String(v string) *string {
- return &v
-}
-
-// StringValue returns the value of the string pointer passed in or
-// "" if the pointer is nil.
-func StringValue(v *string) string {
- if v != nil {
- return *v
- }
- return ""
-}
-
-// StringSlice converts a slice of string values into a slice of
-// string pointers
-func StringSlice(src []string) []*string {
- dst := make([]*string, len(src))
- for i := 0; i < len(src); i++ {
- dst[i] = &(src[i])
- }
- return dst
-}
-
-// StringValueSlice converts a slice of string pointers into a slice of
-// string values
-func StringValueSlice(src []*string) []string {
- dst := make([]string, len(src))
- for i := 0; i < len(src); i++ {
- if src[i] != nil {
- dst[i] = *(src[i])
- }
- }
- return dst
-}
-
-// StringMap converts a string map of string values into a string
-// map of string pointers
-func StringMap(src map[string]string) map[string]*string {
- dst := make(map[string]*string)
- for k, val := range src {
- v := val
- dst[k] = &v
- }
- return dst
-}
-
-// StringValueMap converts a string map of string pointers into a string
-// map of string values
-func StringValueMap(src map[string]*string) map[string]string {
- dst := make(map[string]string)
- for k, val := range src {
- if val != nil {
- dst[k] = *val
- }
- }
- return dst
-}
-
-// Bool returns a pointer to of the bool value passed in.
-func Bool(v bool) *bool {
- return &v
-}
-
-// BoolValue returns the value of the bool pointer passed in or
-// false if the pointer is nil.
-func BoolValue(v *bool) bool {
- if v != nil {
- return *v
- }
- return false
-}
-
-// BoolSlice converts a slice of bool values into a slice of
-// bool pointers
-func BoolSlice(src []bool) []*bool {
- dst := make([]*bool, len(src))
- for i := 0; i < len(src); i++ {
- dst[i] = &(src[i])
- }
- return dst
-}
-
-// BoolValueSlice converts a slice of bool pointers into a slice of
-// bool values
-func BoolValueSlice(src []*bool) []bool {
- dst := make([]bool, len(src))
- for i := 0; i < len(src); i++ {
- if src[i] != nil {
- dst[i] = *(src[i])
- }
- }
- return dst
-}
-
-// BoolMap converts a string map of bool values into a string
-// map of bool pointers
-func BoolMap(src map[string]bool) map[string]*bool {
- dst := make(map[string]*bool)
- for k, val := range src {
- v := val
- dst[k] = &v
- }
- return dst
-}
-
-// BoolValueMap converts a string map of bool pointers into a string
-// map of bool values
-func BoolValueMap(src map[string]*bool) map[string]bool {
- dst := make(map[string]bool)
- for k, val := range src {
- if val != nil {
- dst[k] = *val
- }
- }
- return dst
-}
-
-// Int returns a pointer to of the int value passed in.
-func Int(v int) *int {
- return &v
-}
-
-// IntValue returns the value of the int pointer passed in or
-// 0 if the pointer is nil.
-func IntValue(v *int) int {
- if v != nil {
- return *v
- }
- return 0
-}
-
-// IntSlice converts a slice of int values into a slice of
-// int pointers
-func IntSlice(src []int) []*int {
- dst := make([]*int, len(src))
- for i := 0; i < len(src); i++ {
- dst[i] = &(src[i])
- }
- return dst
-}
-
-// IntValueSlice converts a slice of int pointers into a slice of
-// int values
-func IntValueSlice(src []*int) []int {
- dst := make([]int, len(src))
- for i := 0; i < len(src); i++ {
- if src[i] != nil {
- dst[i] = *(src[i])
- }
- }
- return dst
-}
-
-// IntMap converts a string map of int values into a string
-// map of int pointers
-func IntMap(src map[string]int) map[string]*int {
- dst := make(map[string]*int)
- for k, val := range src {
- v := val
- dst[k] = &v
- }
- return dst
-}
-
-// IntValueMap converts a string map of int pointers into a string
-// map of int values
-func IntValueMap(src map[string]*int) map[string]int {
- dst := make(map[string]int)
- for k, val := range src {
- if val != nil {
- dst[k] = *val
- }
- }
- return dst
-}
-
-// Int32 returns a pointer to of the int32 value passed in.
-func Int32(v int32) *int32 {
- return &v
-}
-
-// Int32Value returns the value of the int32 pointer passed in or
-// 0 if the pointer is nil.
-func Int32Value(v *int32) int32 {
- if v != nil {
- return *v
- }
- return 0
-}
-
-// Int32Slice converts a slice of int32 values into a slice of
-// int32 pointers
-func Int32Slice(src []int32) []*int32 {
- dst := make([]*int32, len(src))
- for i := 0; i < len(src); i++ {
- dst[i] = &(src[i])
- }
- return dst
-}
-
-// Int32ValueSlice converts a slice of int32 pointers into a slice of
-// int32 values
-func Int32ValueSlice(src []*int32) []int32 {
- dst := make([]int32, len(src))
- for i := 0; i < len(src); i++ {
- if src[i] != nil {
- dst[i] = *(src[i])
- }
- }
- return dst
-}
-
-// Int32Map converts a string map of int32 values into a string
-// map of int32 pointers
-func Int32Map(src map[string]int32) map[string]*int32 {
- dst := make(map[string]*int32)
- for k, val := range src {
- v := val
- dst[k] = &v
- }
- return dst
-}
-
-// Int32ValueMap converts a string map of int32 pointers into a string
-// map of int32 values
-func Int32ValueMap(src map[string]*int32) map[string]int32 {
- dst := make(map[string]int32)
- for k, val := range src {
- if val != nil {
- dst[k] = *val
- }
- }
- return dst
-}
-
-// Int64 returns a pointer to of the int64 value passed in.
-func Int64(v int64) *int64 {
- return &v
-}
-
-// Int64Value returns the value of the int64 pointer passed in or
-// 0 if the pointer is nil.
-func Int64Value(v *int64) int64 {
- if v != nil {
- return *v
- }
- return 0
-}
-
-// Int64Slice converts a slice of int64 values into a slice of
-// int64 pointers
-func Int64Slice(src []int64) []*int64 {
- dst := make([]*int64, len(src))
- for i := 0; i < len(src); i++ {
- dst[i] = &(src[i])
- }
- return dst
-}
-
-// Int64ValueSlice converts a slice of int64 pointers into a slice of
-// int64 values
-func Int64ValueSlice(src []*int64) []int64 {
- dst := make([]int64, len(src))
- for i := 0; i < len(src); i++ {
- if src[i] != nil {
- dst[i] = *(src[i])
- }
- }
- return dst
-}
-
-// Int64Map converts a string map of int64 values into a string
-// map of int64 pointers
-func Int64Map(src map[string]int64) map[string]*int64 {
- dst := make(map[string]*int64)
- for k, val := range src {
- v := val
- dst[k] = &v
- }
- return dst
-}
-
-// Int64ValueMap converts a string map of int64 pointers into a string
-// map of int64 values
-func Int64ValueMap(src map[string]*int64) map[string]int64 {
- dst := make(map[string]int64)
- for k, val := range src {
- if val != nil {
- dst[k] = *val
- }
- }
- return dst
-}
-
-// Uint16 returns a pointer to of the uint16 value passed in.
-func Uint16(v uint16) *uint16 {
- return &v
-}
-
-// Uint16Value returns the value of the uint16 pointer passed in or
-// 0 if the pointer is nil.
-func Uint16Value(v *uint16) uint16 {
- if v != nil {
- return *v
- }
-
- return 0
-}
-
-// Uint16Slice converts a slice of uint16 values into a slice of
-// uint16 pointers
-func Uint16Slice(src []uint16) []*uint16 {
- dst := make([]*uint16, len(src))
- for i := 0; i < len(src); i++ {
- dst[i] = &(src[i])
- }
-
- return dst
-}
-
-// Uint16ValueSlice converts a slice of uint16 pointers into a slice of
-// uint16 values
-func Uint16ValueSlice(src []*uint16) []uint16 {
- dst := make([]uint16, len(src))
-
- for i := 0; i < len(src); i++ {
- if src[i] != nil {
- dst[i] = *(src[i])
- }
- }
-
- return dst
-}
-
-// Uint16Map converts a string map of uint16 values into a string
-// map of uint16 pointers
-func Uint16Map(src map[string]uint16) map[string]*uint16 {
- dst := make(map[string]*uint16)
-
- for k, val := range src {
- v := val
- dst[k] = &v
- }
-
- return dst
-}
-
-// Uint16ValueMap converts a string map of uint16 pointers into a string
-// map of uint16 values
-func Uint16ValueMap(src map[string]*uint16) map[string]uint16 {
- dst := make(map[string]uint16)
-
- for k, val := range src {
- if val != nil {
- dst[k] = *val
- }
- }
-
- return dst
-}
-
-// Uint returns a pointer to of the uint value passed in.
-func Uint(v uint) *uint {
- return &v
-}
-
-// UintValue returns the value of the uint pointer passed in or
-// 0 if the pointer is nil.
-func UintValue(v *uint) uint {
- if v != nil {
- return *v
- }
- return 0
-}
-
-// UintSlice converts a slice of uint values into a slice of
-// uint pointers
-func UintSlice(src []uint) []*uint {
- dst := make([]*uint, len(src))
- for i := 0; i < len(src); i++ {
- dst[i] = &(src[i])
- }
- return dst
-}
-
-// UintValueSlice converts a slice of uint pointers into a slice of
-// uint values
-func UintValueSlice(src []*uint) []uint {
- dst := make([]uint, len(src))
- for i := 0; i < len(src); i++ {
- if src[i] != nil {
- dst[i] = *(src[i])
- }
- }
- return dst
-}
-
-// UintMap converts a string map of uint values into a string
-// map of uint pointers
-func UintMap(src map[string]uint) map[string]*uint {
- dst := make(map[string]*uint)
- for k, val := range src {
- v := val
- dst[k] = &v
- }
- return dst
-}
-
-// UintValueMap converts a string map of uint pointers into a string
-// map of uint values
-func UintValueMap(src map[string]*uint) map[string]uint {
- dst := make(map[string]uint)
- for k, val := range src {
- if val != nil {
- dst[k] = *val
- }
- }
- return dst
-}
-
-// Uint32 returns a pointer to of the uint32 value passed in.
-func Uint32(v uint32) *uint32 {
- return &v
-}
-
-// Uint32Value returns the value of the uint32 pointer passed in or
-// 0 if the pointer is nil.
-func Uint32Value(v *uint32) uint32 {
- if v != nil {
- return *v
- }
- return 0
-}
-
-// Uint32Slice converts a slice of uint32 values into a slice of
-// uint32 pointers
-func Uint32Slice(src []uint32) []*uint32 {
- dst := make([]*uint32, len(src))
- for i := 0; i < len(src); i++ {
- dst[i] = &(src[i])
- }
- return dst
-}
-
-// Uint32ValueSlice converts a slice of uint32 pointers into a slice of
-// uint32 values
-func Uint32ValueSlice(src []*uint32) []uint32 {
- dst := make([]uint32, len(src))
- for i := 0; i < len(src); i++ {
- if src[i] != nil {
- dst[i] = *(src[i])
- }
- }
- return dst
-}
-
-// Uint32Map converts a string map of uint32 values into a string
-// map of uint32 pointers
-func Uint32Map(src map[string]uint32) map[string]*uint32 {
- dst := make(map[string]*uint32)
- for k, val := range src {
- v := val
- dst[k] = &v
- }
- return dst
-}
-
-// Uint32ValueMap converts a string map of uint32 pointers into a string
-// map of uint32 values
-func Uint32ValueMap(src map[string]*uint32) map[string]uint32 {
- dst := make(map[string]uint32)
- for k, val := range src {
- if val != nil {
- dst[k] = *val
- }
- }
- return dst
-}
-
-// Uint64 returns a pointer to of the uint64 value passed in.
-func Uint64(v uint64) *uint64 {
- return &v
-}
-
-// Uint64Value returns the value of the uint64 pointer passed in or
-// 0 if the pointer is nil.
-func Uint64Value(v *uint64) uint64 {
- if v != nil {
- return *v
- }
- return 0
-}
-
-// Uint64Slice converts a slice of uint64 values into a slice of
-// uint64 pointers
-func Uint64Slice(src []uint64) []*uint64 {
- dst := make([]*uint64, len(src))
- for i := 0; i < len(src); i++ {
- dst[i] = &(src[i])
- }
- return dst
-}
-
-// Uint64ValueSlice converts a slice of uint64 pointers into a slice of
-// uint64 values
-func Uint64ValueSlice(src []*uint64) []uint64 {
- dst := make([]uint64, len(src))
- for i := 0; i < len(src); i++ {
- if src[i] != nil {
- dst[i] = *(src[i])
- }
- }
- return dst
-}
-
-// Uint64Map converts a string map of uint64 values into a string
-// map of uint64 pointers
-func Uint64Map(src map[string]uint64) map[string]*uint64 {
- dst := make(map[string]*uint64)
- for k, val := range src {
- v := val
- dst[k] = &v
- }
- return dst
-}
-
-// Uint64ValueMap converts a string map of uint64 pointers into a string
-// map of uint64 values
-func Uint64ValueMap(src map[string]*uint64) map[string]uint64 {
- dst := make(map[string]uint64)
- for k, val := range src {
- if val != nil {
- dst[k] = *val
- }
- }
- return dst
-}
-
-// Float32 returns a pointer to of the float32 value passed in.
-func Float32(v float32) *float32 {
- return &v
-}
-
-// Float32Value returns the value of the float32 pointer passed in or
-// 0 if the pointer is nil.
-func Float32Value(v *float32) float32 {
- if v != nil {
- return *v
- }
-
- return 0
-}
-
-// Float32Slice converts a slice of float32 values into a slice of
-// float32 pointers
-func Float32Slice(src []float32) []*float32 {
- dst := make([]*float32, len(src))
-
- for i := 0; i < len(src); i++ {
- dst[i] = &(src[i])
- }
-
- return dst
-}
-
-// Float32ValueSlice converts a slice of float32 pointers into a slice of
-// float32 values
-func Float32ValueSlice(src []*float32) []float32 {
- dst := make([]float32, len(src))
-
- for i := 0; i < len(src); i++ {
- if src[i] != nil {
- dst[i] = *(src[i])
- }
- }
-
- return dst
-}
-
-// Float32Map converts a string map of float32 values into a string
-// map of float32 pointers
-func Float32Map(src map[string]float32) map[string]*float32 {
- dst := make(map[string]*float32)
-
- for k, val := range src {
- v := val
- dst[k] = &v
- }
-
- return dst
-}
-
-// Float32ValueMap converts a string map of float32 pointers into a string
-// map of float32 values
-func Float32ValueMap(src map[string]*float32) map[string]float32 {
- dst := make(map[string]float32)
-
- for k, val := range src {
- if val != nil {
- dst[k] = *val
- }
- }
-
- return dst
-}
-
-// Float64 returns a pointer to of the float64 value passed in.
-func Float64(v float64) *float64 {
- return &v
-}
-
-// Float64Value returns the value of the float64 pointer passed in or
-// 0 if the pointer is nil.
-func Float64Value(v *float64) float64 {
- if v != nil {
- return *v
- }
- return 0
-}
-
-// Float64Slice converts a slice of float64 values into a slice of
-// float64 pointers
-func Float64Slice(src []float64) []*float64 {
- dst := make([]*float64, len(src))
- for i := 0; i < len(src); i++ {
- dst[i] = &(src[i])
- }
- return dst
-}
-
-// Float64ValueSlice converts a slice of float64 pointers into a slice of
-// float64 values
-func Float64ValueSlice(src []*float64) []float64 {
- dst := make([]float64, len(src))
- for i := 0; i < len(src); i++ {
- if src[i] != nil {
- dst[i] = *(src[i])
- }
- }
- return dst
-}
-
-// Float64Map converts a string map of float64 values into a string
-// map of float64 pointers
-func Float64Map(src map[string]float64) map[string]*float64 {
- dst := make(map[string]*float64)
- for k, val := range src {
- v := val
- dst[k] = &v
- }
- return dst
-}
-
-// Float64ValueMap converts a string map of float64 pointers into a string
-// map of float64 values
-func Float64ValueMap(src map[string]*float64) map[string]float64 {
- dst := make(map[string]float64)
- for k, val := range src {
- if val != nil {
- dst[k] = *val
- }
- }
- return dst
-}
-
-// Time returns a pointer to of the time.Time value passed in.
-func Time(v time.Time) *time.Time {
- return &v
-}
-
-// TimeValue returns the value of the time.Time pointer passed in or
-// time.Time{} if the pointer is nil.
-func TimeValue(v *time.Time) time.Time {
- if v != nil {
- return *v
- }
- return time.Time{}
-}
-
-// TimeSlice converts a slice of time.Time values into a slice of
-// time.Time pointers
-func TimeSlice(src []time.Time) []*time.Time {
- dst := make([]*time.Time, len(src))
- for i := 0; i < len(src); i++ {
- dst[i] = &(src[i])
- }
- return dst
-}
-
-// TimeValueSlice converts a slice of time.Time pointers into a slice of
-// time.Time values
-func TimeValueSlice(src []*time.Time) []time.Time {
- dst := make([]time.Time, len(src))
- for i := 0; i < len(src); i++ {
- if src[i] != nil {
- dst[i] = *(src[i])
- }
- }
- return dst
-}
-
-// TimeMap converts a string map of time.Time values into a string
-// map of time.Time pointers
-func TimeMap(src map[string]time.Time) map[string]*time.Time {
- dst := make(map[string]*time.Time)
- for k, val := range src {
- v := val
- dst[k] = &v
- }
- return dst
-}
-
-// TimeValueMap converts a string map of time.Time pointers into a string
-// map of time.Time values
-func TimeValueMap(src map[string]*time.Time) map[string]time.Time {
- dst := make(map[string]time.Time)
- for k, val := range src {
- if val != nil {
- dst[k] = *val
- }
- }
- return dst
-}
diff --git a/vendor/github.com/go-openapi/swag/doc.go b/vendor/github.com/go-openapi/swag/doc.go
index 55094cb74c..b54b57478a 100644
--- a/vendor/github.com/go-openapi/swag/doc.go
+++ b/vendor/github.com/go-openapi/swag/doc.go
@@ -1,31 +1,47 @@
-// Copyright 2015 go-swagger maintainers
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+// Package swag contains a bunch of helper functions for go-openapi and go-swagger projects.
//
-// 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
+// You may also use it standalone for your projects.
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// NOTE: all features that used to be exposed as package-level members (constants, variables,
+// functions and types) are now deprecated and are superseded by equivalent features in
+// more specialized sub-packages.
+// Moving forward, no additional feature will be added to the [swag] API directly at the root package level,
+// which remains there for backward-compatibility purposes.
//
-// 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 swag contains a bunch of helper functions for go-openapi and go-swagger projects.
-
-You may also use it standalone for your projects.
-
- - convert between value and pointers for builtin types
- - convert from string to builtin types (wraps strconv)
- - fast json concatenation
- - search in path
- - load from file or http
- - name mangling
-
-This repo has only few dependencies outside of the standard library:
-
- - YAML utilities depend on gopkg.in/yaml.v2
-*/
+// Child modules will continue to evolve or some new ones may be added in the future.
+//
+// # Modules
+//
+// - [cmdutils] utilities to work with CLIs
+//
+// - [conv] type conversion utilities
+//
+// - [fileutils] file utilities
+//
+// - [jsonname] JSON utilities
+//
+// - [jsonutils] JSON utilities
+//
+// - [loading] file loading
+//
+// - [mangling] safe name generation
+//
+// - [netutils] networking utilities
+//
+// - [stringutils] `string` utilities
+//
+// - [typeutils] `go` types utilities
+//
+// - [yamlutils] YAML utilities
+//
+// # Dependencies
+//
+// This repo has a few dependencies outside of the standard library:
+//
+// - YAML utilities depend on [go.yaml.in/yaml/v3]
package swag
+
+//go:generate mockery
diff --git a/vendor/github.com/go-openapi/swag/errors.go b/vendor/github.com/go-openapi/swag/errors.go
deleted file mode 100644
index 6c67fbf92e..0000000000
--- a/vendor/github.com/go-openapi/swag/errors.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package swag
-
-type swagError string
-
-const (
- // ErrYAML is an error raised by YAML utilities
- ErrYAML swagError = "yaml error"
-
- // ErrLoader is an error raised by the file loader utility
- ErrLoader swagError = "loader error"
-)
-
-func (e swagError) Error() string {
- return string(e)
-}
diff --git a/vendor/github.com/go-openapi/swag/fileutils/LICENSE b/vendor/github.com/go-openapi/swag/fileutils/LICENSE
new file mode 100644
index 0000000000..d645695673
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/fileutils/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/vendor/github.com/go-openapi/swag/fileutils/doc.go b/vendor/github.com/go-openapi/swag/fileutils/doc.go
new file mode 100644
index 0000000000..859a200d84
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/fileutils/doc.go
@@ -0,0 +1,10 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+// Package fileutils exposes utilities to deal with files and paths.
+//
+// Currently, there is:
+// - [File] to represent an abstraction of an uploaded file.
+// For instance, this is used by [github.com/go-openapi/runtime.File].
+// - path search utilities (e.g. finding packages in the GO search path)
+package fileutils
diff --git a/vendor/github.com/go-openapi/swag/fileutils/file.go b/vendor/github.com/go-openapi/swag/fileutils/file.go
new file mode 100644
index 0000000000..5ad4cfaeaf
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/fileutils/file.go
@@ -0,0 +1,22 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package fileutils
+
+import "mime/multipart"
+
+// File represents an uploaded file.
+type File struct {
+ Data multipart.File
+ Header *multipart.FileHeader
+}
+
+// Read bytes from the file
+func (f *File) Read(p []byte) (n int, err error) {
+ return f.Data.Read(p)
+}
+
+// Close the file
+func (f *File) Close() error {
+ return f.Data.Close()
+}
diff --git a/vendor/github.com/go-openapi/swag/path.go b/vendor/github.com/go-openapi/swag/fileutils/path.go
similarity index 58%
rename from vendor/github.com/go-openapi/swag/path.go
rename to vendor/github.com/go-openapi/swag/fileutils/path.go
index 941bd0176b..dd09f690bf 100644
--- a/vendor/github.com/go-openapi/swag/path.go
+++ b/vendor/github.com/go-openapi/swag/fileutils/path.go
@@ -1,18 +1,7 @@
-// Copyright 2015 go-swagger maintainers
-//
-// 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.
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
-package swag
+package fileutils
import (
"os"
@@ -21,10 +10,8 @@ import (
"strings"
)
-const (
- // GOPATHKey represents the env key for gopath
- GOPATHKey = "GOPATH"
-)
+// GOPATHKey represents the env key for gopath
+const GOPATHKey = "GOPATH"
// FindInSearchPath finds a package in a provided lists of paths
func FindInSearchPath(searchPath, pkg string) string {
@@ -40,11 +27,17 @@ func FindInSearchPath(searchPath, pkg string) string {
}
// FindInGoSearchPath finds a package in the $GOPATH:$GOROOT
+//
+// Deprecated: this function is no longer relevant with modern go.
+// It uses [runtime.GOROOT] under the hood, which is deprecated as of go1.24.
func FindInGoSearchPath(pkg string) string {
return FindInSearchPath(FullGoSearchPath(), pkg)
}
// FullGoSearchPath gets the search paths for finding packages
+//
+// Deprecated: this function is no longer relevant with modern go.
+// It uses [runtime.GOROOT] under the hood, which is deprecated as of go1.24.
func FullGoSearchPath() string {
allPaths := os.Getenv(GOPATHKey)
if allPaths == "" {
diff --git a/vendor/github.com/go-openapi/swag/fileutils_iface.go b/vendor/github.com/go-openapi/swag/fileutils_iface.go
new file mode 100644
index 0000000000..f3e79a0e4b
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/fileutils_iface.go
@@ -0,0 +1,33 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package swag
+
+import "github.com/go-openapi/swag/fileutils"
+
+// GOPATHKey represents the env key for gopath
+//
+// Deprecated: use [fileutils.GOPATHKey] instead.
+const GOPATHKey = fileutils.GOPATHKey
+
+// File represents an uploaded file.
+//
+// Deprecated: use [fileutils.File] instead.
+type File = fileutils.File
+
+// FindInSearchPath finds a package in a provided lists of paths.
+//
+// Deprecated: use [fileutils.FindInSearchPath] instead.
+func FindInSearchPath(searchPath, pkg string) string {
+ return fileutils.FindInSearchPath(searchPath, pkg)
+}
+
+// FindInGoSearchPath finds a package in the $GOPATH:$GOROOT
+//
+// Deprecated: use [fileutils.FindInGoSearchPath] instead.
+func FindInGoSearchPath(pkg string) string { return fileutils.FindInGoSearchPath(pkg) }
+
+// FullGoSearchPath gets the search paths for finding packages
+//
+// Deprecated: use [fileutils.FullGoSearchPath] instead.
+func FullGoSearchPath() string { return fileutils.FullGoSearchPath() }
diff --git a/vendor/github.com/go-openapi/swag/go.work b/vendor/github.com/go-openapi/swag/go.work
new file mode 100644
index 0000000000..1e537f0749
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/go.work
@@ -0,0 +1,20 @@
+use (
+ .
+ ./cmdutils
+ ./conv
+ ./fileutils
+ ./jsonname
+ ./jsonutils
+ ./jsonutils/adapters/easyjson
+ ./jsonutils/adapters/testintegration
+ ./jsonutils/adapters/testintegration/benchmarks
+ ./jsonutils/fixtures_test
+ ./loading
+ ./mangling
+ ./netutils
+ ./stringutils
+ ./typeutils
+ ./yamlutils
+)
+
+go 1.24.0
diff --git a/vendor/github.com/go-openapi/swag/go.work.sum b/vendor/github.com/go-openapi/swag/go.work.sum
new file mode 100644
index 0000000000..c1308cafa6
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/go.work.sum
@@ -0,0 +1,7 @@
+github.com/go-openapi/testify/v2 v2.0.1/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
+golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
+golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
+golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
+golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
+golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
diff --git a/vendor/github.com/go-openapi/swag/initialism_index.go b/vendor/github.com/go-openapi/swag/initialism_index.go
deleted file mode 100644
index 20a359bb60..0000000000
--- a/vendor/github.com/go-openapi/swag/initialism_index.go
+++ /dev/null
@@ -1,202 +0,0 @@
-// Copyright 2015 go-swagger maintainers
-//
-// 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 swag
-
-import (
- "sort"
- "strings"
- "sync"
-)
-
-var (
- // commonInitialisms are common acronyms that are kept as whole uppercased words.
- commonInitialisms *indexOfInitialisms
-
- // initialisms is a slice of sorted initialisms
- initialisms []string
-
- // a copy of initialisms pre-baked as []rune
- initialismsRunes [][]rune
- initialismsUpperCased [][]rune
-
- isInitialism func(string) bool
-
- maxAllocMatches int
-)
-
-func init() {
- // Taken from https://github.com/golang/lint/blob/3390df4df2787994aea98de825b964ac7944b817/lint.go#L732-L769
- configuredInitialisms := map[string]bool{
- "ACL": true,
- "API": true,
- "ASCII": true,
- "CPU": true,
- "CSS": true,
- "DNS": true,
- "EOF": true,
- "GUID": true,
- "HTML": true,
- "HTTPS": true,
- "HTTP": true,
- "ID": true,
- "IP": true,
- "IPv4": true,
- "IPv6": true,
- "JSON": true,
- "LHS": true,
- "OAI": true,
- "QPS": true,
- "RAM": true,
- "RHS": true,
- "RPC": true,
- "SLA": true,
- "SMTP": true,
- "SQL": true,
- "SSH": true,
- "TCP": true,
- "TLS": true,
- "TTL": true,
- "UDP": true,
- "UI": true,
- "UID": true,
- "UUID": true,
- "URI": true,
- "URL": true,
- "UTF8": true,
- "VM": true,
- "XML": true,
- "XMPP": true,
- "XSRF": true,
- "XSS": true,
- }
-
- // a thread-safe index of initialisms
- commonInitialisms = newIndexOfInitialisms().load(configuredInitialisms)
- initialisms = commonInitialisms.sorted()
- initialismsRunes = asRunes(initialisms)
- initialismsUpperCased = asUpperCased(initialisms)
- maxAllocMatches = maxAllocHeuristic(initialismsRunes)
-
- // a test function
- isInitialism = commonInitialisms.isInitialism
-}
-
-func asRunes(in []string) [][]rune {
- out := make([][]rune, len(in))
- for i, initialism := range in {
- out[i] = []rune(initialism)
- }
-
- return out
-}
-
-func asUpperCased(in []string) [][]rune {
- out := make([][]rune, len(in))
-
- for i, initialism := range in {
- out[i] = []rune(upper(trim(initialism)))
- }
-
- return out
-}
-
-func maxAllocHeuristic(in [][]rune) int {
- heuristic := make(map[rune]int)
- for _, initialism := range in {
- heuristic[initialism[0]]++
- }
-
- var maxAlloc int
- for _, val := range heuristic {
- if val > maxAlloc {
- maxAlloc = val
- }
- }
-
- return maxAlloc
-}
-
-// AddInitialisms add additional initialisms
-func AddInitialisms(words ...string) {
- for _, word := range words {
- // commonInitialisms[upper(word)] = true
- commonInitialisms.add(upper(word))
- }
- // sort again
- initialisms = commonInitialisms.sorted()
- initialismsRunes = asRunes(initialisms)
- initialismsUpperCased = asUpperCased(initialisms)
-}
-
-// indexOfInitialisms is a thread-safe implementation of the sorted index of initialisms.
-// Since go1.9, this may be implemented with sync.Map.
-type indexOfInitialisms struct {
- sortMutex *sync.Mutex
- index *sync.Map
-}
-
-func newIndexOfInitialisms() *indexOfInitialisms {
- return &indexOfInitialisms{
- sortMutex: new(sync.Mutex),
- index: new(sync.Map),
- }
-}
-
-func (m *indexOfInitialisms) load(initial map[string]bool) *indexOfInitialisms {
- m.sortMutex.Lock()
- defer m.sortMutex.Unlock()
- for k, v := range initial {
- m.index.Store(k, v)
- }
- return m
-}
-
-func (m *indexOfInitialisms) isInitialism(key string) bool {
- _, ok := m.index.Load(key)
- return ok
-}
-
-func (m *indexOfInitialisms) add(key string) *indexOfInitialisms {
- m.index.Store(key, true)
- return m
-}
-
-func (m *indexOfInitialisms) sorted() (result []string) {
- m.sortMutex.Lock()
- defer m.sortMutex.Unlock()
- m.index.Range(func(key, _ interface{}) bool {
- k := key.(string)
- result = append(result, k)
- return true
- })
- sort.Sort(sort.Reverse(byInitialism(result)))
- return
-}
-
-type byInitialism []string
-
-func (s byInitialism) Len() int {
- return len(s)
-}
-func (s byInitialism) Swap(i, j int) {
- s[i], s[j] = s[j], s[i]
-}
-func (s byInitialism) Less(i, j int) bool {
- if len(s[i]) != len(s[j]) {
- return len(s[i]) < len(s[j])
- }
-
- return strings.Compare(s[i], s[j]) > 0
-}
diff --git a/vendor/github.com/go-openapi/swag/json.go b/vendor/github.com/go-openapi/swag/json.go
deleted file mode 100644
index c7caa9908f..0000000000
--- a/vendor/github.com/go-openapi/swag/json.go
+++ /dev/null
@@ -1,313 +0,0 @@
-// Copyright 2015 go-swagger maintainers
-//
-// 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 swag
-
-import (
- "bytes"
- "encoding/json"
- "log"
- "reflect"
- "strings"
- "sync"
-
- "github.com/mailru/easyjson/jlexer"
- "github.com/mailru/easyjson/jwriter"
-)
-
-// nullJSON represents a JSON object with null type
-var nullJSON = []byte("null")
-
-// DefaultJSONNameProvider the default cache for types
-var DefaultJSONNameProvider = NewNameProvider()
-
-const comma = byte(',')
-
-var closers map[byte]byte
-
-func init() {
- closers = map[byte]byte{
- '{': '}',
- '[': ']',
- }
-}
-
-type ejMarshaler interface {
- MarshalEasyJSON(w *jwriter.Writer)
-}
-
-type ejUnmarshaler interface {
- UnmarshalEasyJSON(w *jlexer.Lexer)
-}
-
-// WriteJSON writes json data, prefers finding an appropriate interface to short-circuit the marshaler
-// so it takes the fastest option available.
-func WriteJSON(data interface{}) ([]byte, error) {
- if d, ok := data.(ejMarshaler); ok {
- jw := new(jwriter.Writer)
- d.MarshalEasyJSON(jw)
- return jw.BuildBytes()
- }
- if d, ok := data.(json.Marshaler); ok {
- return d.MarshalJSON()
- }
- return json.Marshal(data)
-}
-
-// ReadJSON reads json data, prefers finding an appropriate interface to short-circuit the unmarshaler
-// so it takes the fastest option available
-func ReadJSON(data []byte, value interface{}) error {
- trimmedData := bytes.Trim(data, "\x00")
- if d, ok := value.(ejUnmarshaler); ok {
- jl := &jlexer.Lexer{Data: trimmedData}
- d.UnmarshalEasyJSON(jl)
- return jl.Error()
- }
- if d, ok := value.(json.Unmarshaler); ok {
- return d.UnmarshalJSON(trimmedData)
- }
- return json.Unmarshal(trimmedData, value)
-}
-
-// DynamicJSONToStruct converts an untyped json structure into a struct
-func DynamicJSONToStruct(data interface{}, target interface{}) error {
- // TODO: convert straight to a json typed map (mergo + iterate?)
- b, err := WriteJSON(data)
- if err != nil {
- return err
- }
- return ReadJSON(b, target)
-}
-
-// ConcatJSON concatenates multiple json objects efficiently
-func ConcatJSON(blobs ...[]byte) []byte {
- if len(blobs) == 0 {
- return nil
- }
-
- last := len(blobs) - 1
- for blobs[last] == nil || bytes.Equal(blobs[last], nullJSON) {
- // strips trailing null objects
- last--
- if last < 0 {
- // there was nothing but "null"s or nil...
- return nil
- }
- }
- if last == 0 {
- return blobs[0]
- }
-
- var opening, closing byte
- var idx, a int
- buf := bytes.NewBuffer(nil)
-
- for i, b := range blobs[:last+1] {
- if b == nil || bytes.Equal(b, nullJSON) {
- // a null object is in the list: skip it
- continue
- }
- if len(b) > 0 && opening == 0 { // is this an array or an object?
- opening, closing = b[0], closers[b[0]]
- }
-
- if opening != '{' && opening != '[' {
- continue // don't know how to concatenate non container objects
- }
-
- const minLengthIfNotEmpty = 3
- if len(b) < minLengthIfNotEmpty { // yep empty but also the last one, so closing this thing
- if i == last && a > 0 {
- if err := buf.WriteByte(closing); err != nil {
- log.Println(err)
- }
- }
- continue
- }
-
- idx = 0
- if a > 0 { // we need to join with a comma for everything beyond the first non-empty item
- if err := buf.WriteByte(comma); err != nil {
- log.Println(err)
- }
- idx = 1 // this is not the first or the last so we want to drop the leading bracket
- }
-
- if i != last { // not the last one, strip brackets
- if _, err := buf.Write(b[idx : len(b)-1]); err != nil {
- log.Println(err)
- }
- } else { // last one, strip only the leading bracket
- if _, err := buf.Write(b[idx:]); err != nil {
- log.Println(err)
- }
- }
- a++
- }
- // somehow it ended up being empty, so provide a default value
- if buf.Len() == 0 {
- if err := buf.WriteByte(opening); err != nil {
- log.Println(err)
- }
- if err := buf.WriteByte(closing); err != nil {
- log.Println(err)
- }
- }
- return buf.Bytes()
-}
-
-// ToDynamicJSON turns an object into a properly JSON typed structure
-func ToDynamicJSON(data interface{}) interface{} {
- // TODO: convert straight to a json typed map (mergo + iterate?)
- b, err := json.Marshal(data)
- if err != nil {
- log.Println(err)
- }
- var res interface{}
- if err := json.Unmarshal(b, &res); err != nil {
- log.Println(err)
- }
- return res
-}
-
-// FromDynamicJSON turns an object into a properly JSON typed structure
-func FromDynamicJSON(data, target interface{}) error {
- b, err := json.Marshal(data)
- if err != nil {
- log.Println(err)
- }
- return json.Unmarshal(b, target)
-}
-
-// NameProvider represents an object capable of translating from go property names
-// to json property names
-// This type is thread-safe.
-type NameProvider struct {
- lock *sync.Mutex
- index map[reflect.Type]nameIndex
-}
-
-type nameIndex struct {
- jsonNames map[string]string
- goNames map[string]string
-}
-
-// NewNameProvider creates a new name provider
-func NewNameProvider() *NameProvider {
- return &NameProvider{
- lock: &sync.Mutex{},
- index: make(map[reflect.Type]nameIndex),
- }
-}
-
-func buildnameIndex(tpe reflect.Type, idx, reverseIdx map[string]string) {
- for i := 0; i < tpe.NumField(); i++ {
- targetDes := tpe.Field(i)
-
- if targetDes.PkgPath != "" { // unexported
- continue
- }
-
- if targetDes.Anonymous { // walk embedded structures tree down first
- buildnameIndex(targetDes.Type, idx, reverseIdx)
- continue
- }
-
- if tag := targetDes.Tag.Get("json"); tag != "" {
-
- parts := strings.Split(tag, ",")
- if len(parts) == 0 {
- continue
- }
-
- nm := parts[0]
- if nm == "-" {
- continue
- }
- if nm == "" { // empty string means we want to use the Go name
- nm = targetDes.Name
- }
-
- idx[nm] = targetDes.Name
- reverseIdx[targetDes.Name] = nm
- }
- }
-}
-
-func newNameIndex(tpe reflect.Type) nameIndex {
- var idx = make(map[string]string, tpe.NumField())
- var reverseIdx = make(map[string]string, tpe.NumField())
-
- buildnameIndex(tpe, idx, reverseIdx)
- return nameIndex{jsonNames: idx, goNames: reverseIdx}
-}
-
-// GetJSONNames gets all the json property names for a type
-func (n *NameProvider) GetJSONNames(subject interface{}) []string {
- n.lock.Lock()
- defer n.lock.Unlock()
- tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
- names, ok := n.index[tpe]
- if !ok {
- names = n.makeNameIndex(tpe)
- }
-
- res := make([]string, 0, len(names.jsonNames))
- for k := range names.jsonNames {
- res = append(res, k)
- }
- return res
-}
-
-// GetJSONName gets the json name for a go property name
-func (n *NameProvider) GetJSONName(subject interface{}, name string) (string, bool) {
- tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
- return n.GetJSONNameForType(tpe, name)
-}
-
-// GetJSONNameForType gets the json name for a go property name on a given type
-func (n *NameProvider) GetJSONNameForType(tpe reflect.Type, name string) (string, bool) {
- n.lock.Lock()
- defer n.lock.Unlock()
- names, ok := n.index[tpe]
- if !ok {
- names = n.makeNameIndex(tpe)
- }
- nme, ok := names.goNames[name]
- return nme, ok
-}
-
-func (n *NameProvider) makeNameIndex(tpe reflect.Type) nameIndex {
- names := newNameIndex(tpe)
- n.index[tpe] = names
- return names
-}
-
-// GetGoName gets the go name for a json property name
-func (n *NameProvider) GetGoName(subject interface{}, name string) (string, bool) {
- tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
- return n.GetGoNameForType(tpe, name)
-}
-
-// GetGoNameForType gets the go name for a given type for a json property name
-func (n *NameProvider) GetGoNameForType(tpe reflect.Type, name string) (string, bool) {
- n.lock.Lock()
- defer n.lock.Unlock()
- names, ok := n.index[tpe]
- if !ok {
- names = n.makeNameIndex(tpe)
- }
- nme, ok := names.jsonNames[name]
- return nme, ok
-}
diff --git a/vendor/github.com/go-openapi/swag/jsonname/LICENSE b/vendor/github.com/go-openapi/swag/jsonname/LICENSE
new file mode 100644
index 0000000000..d645695673
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonname/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/vendor/github.com/go-openapi/swag/jsonname/doc.go b/vendor/github.com/go-openapi/swag/jsonname/doc.go
new file mode 100644
index 0000000000..79232eaca4
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonname/doc.go
@@ -0,0 +1,5 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+// Package jsonname is a provider of json property names from go properties.
+package jsonname
diff --git a/vendor/github.com/go-openapi/swag/jsonname/name_provider.go b/vendor/github.com/go-openapi/swag/jsonname/name_provider.go
new file mode 100644
index 0000000000..8eaf1bece8
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonname/name_provider.go
@@ -0,0 +1,138 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package jsonname
+
+import (
+ "reflect"
+ "strings"
+ "sync"
+)
+
+// DefaultJSONNameProvider is the default cache for types.
+var DefaultJSONNameProvider = NewNameProvider()
+
+// NameProvider represents an object capable of translating from go property names
+// to json property names.
+//
+// This type is thread-safe.
+//
+// See [github.com/go-openapi/jsonpointer.Pointer] for an example.
+type NameProvider struct {
+ lock *sync.Mutex
+ index map[reflect.Type]nameIndex
+}
+
+type nameIndex struct {
+ jsonNames map[string]string
+ goNames map[string]string
+}
+
+// NewNameProvider creates a new name provider
+func NewNameProvider() *NameProvider {
+ return &NameProvider{
+ lock: &sync.Mutex{},
+ index: make(map[reflect.Type]nameIndex),
+ }
+}
+
+func buildnameIndex(tpe reflect.Type, idx, reverseIdx map[string]string) {
+ for i := 0; i < tpe.NumField(); i++ {
+ targetDes := tpe.Field(i)
+
+ if targetDes.PkgPath != "" { // unexported
+ continue
+ }
+
+ if targetDes.Anonymous { // walk embedded structures tree down first
+ buildnameIndex(targetDes.Type, idx, reverseIdx)
+ continue
+ }
+
+ if tag := targetDes.Tag.Get("json"); tag != "" {
+
+ parts := strings.Split(tag, ",")
+ if len(parts) == 0 {
+ continue
+ }
+
+ nm := parts[0]
+ if nm == "-" {
+ continue
+ }
+ if nm == "" { // empty string means we want to use the Go name
+ nm = targetDes.Name
+ }
+
+ idx[nm] = targetDes.Name
+ reverseIdx[targetDes.Name] = nm
+ }
+ }
+}
+
+func newNameIndex(tpe reflect.Type) nameIndex {
+ var idx = make(map[string]string, tpe.NumField())
+ var reverseIdx = make(map[string]string, tpe.NumField())
+
+ buildnameIndex(tpe, idx, reverseIdx)
+ return nameIndex{jsonNames: idx, goNames: reverseIdx}
+}
+
+// GetJSONNames gets all the json property names for a type
+func (n *NameProvider) GetJSONNames(subject any) []string {
+ n.lock.Lock()
+ defer n.lock.Unlock()
+ tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
+ names, ok := n.index[tpe]
+ if !ok {
+ names = n.makeNameIndex(tpe)
+ }
+
+ res := make([]string, 0, len(names.jsonNames))
+ for k := range names.jsonNames {
+ res = append(res, k)
+ }
+ return res
+}
+
+// GetJSONName gets the json name for a go property name
+func (n *NameProvider) GetJSONName(subject any, name string) (string, bool) {
+ tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
+ return n.GetJSONNameForType(tpe, name)
+}
+
+// GetJSONNameForType gets the json name for a go property name on a given type
+func (n *NameProvider) GetJSONNameForType(tpe reflect.Type, name string) (string, bool) {
+ n.lock.Lock()
+ defer n.lock.Unlock()
+ names, ok := n.index[tpe]
+ if !ok {
+ names = n.makeNameIndex(tpe)
+ }
+ nme, ok := names.goNames[name]
+ return nme, ok
+}
+
+// GetGoName gets the go name for a json property name
+func (n *NameProvider) GetGoName(subject any, name string) (string, bool) {
+ tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
+ return n.GetGoNameForType(tpe, name)
+}
+
+// GetGoNameForType gets the go name for a given type for a json property name
+func (n *NameProvider) GetGoNameForType(tpe reflect.Type, name string) (string, bool) {
+ n.lock.Lock()
+ defer n.lock.Unlock()
+ names, ok := n.index[tpe]
+ if !ok {
+ names = n.makeNameIndex(tpe)
+ }
+ nme, ok := names.jsonNames[name]
+ return nme, ok
+}
+
+func (n *NameProvider) makeNameIndex(tpe reflect.Type) nameIndex {
+ names := newNameIndex(tpe)
+ n.index[tpe] = names
+ return names
+}
diff --git a/vendor/github.com/go-openapi/swag/jsonname_iface.go b/vendor/github.com/go-openapi/swag/jsonname_iface.go
new file mode 100644
index 0000000000..303a007f6f
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonname_iface.go
@@ -0,0 +1,24 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package swag
+
+import (
+ "github.com/go-openapi/swag/jsonname"
+)
+
+// DefaultJSONNameProvider is the default cache for types
+//
+// Deprecated: use [jsonname.DefaultJSONNameProvider] instead.
+var DefaultJSONNameProvider = jsonname.DefaultJSONNameProvider
+
+// NameProvider represents an object capable of translating from go property names
+// to json property names.
+//
+// Deprecated: use [jsonname.NameProvider] instead.
+type NameProvider = jsonname.NameProvider
+
+// NewNameProvider creates a new name provider
+//
+// Deprecated: use [jsonname.NewNameProvider] instead.
+func NewNameProvider() *NameProvider { return jsonname.NewNameProvider() }
diff --git a/vendor/github.com/go-openapi/swag/jsonutils/LICENSE b/vendor/github.com/go-openapi/swag/jsonutils/LICENSE
new file mode 100644
index 0000000000..d645695673
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonutils/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/vendor/github.com/go-openapi/swag/jsonutils/README.md b/vendor/github.com/go-openapi/swag/jsonutils/README.md
new file mode 100644
index 0000000000..d745cdb466
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonutils/README.md
@@ -0,0 +1,108 @@
+ # jsonutils
+
+`jsonutils` exposes a few tools to work with JSON:
+
+- a fast, simple `Concat` to concatenate (not merge) JSON objects and arrays
+- `FromDynamicJSON` to convert a data structure into a "dynamic JSON" data structure
+- `ReadJSON` and `WriteJSON` behave like `json.Unmarshal` and `json.Marshal`,
+ with the ability to use another underlying serialization library through an `Adapter`
+ configured at runtime
+- a `JSONMapSlice` structure that may be used to store JSON objects with the order of keys maintained
+
+## Dynamic JSON
+
+We call "dynamic JSON" the go data structure that results from unmarshaling JSON like this:
+
+```go
+ var value any
+ jsonBytes := `{"a": 1, ... }`
+ _ = json.Unmarshal(jsonBytes, &value)
+```
+
+In this configuration, the standard library mappings are as follows:
+
+| JSON | go |
+|-----------|------------------|
+| `number` | `float64` |
+| `string` | `string` |
+| `boolean` | `bool` |
+| `null` | `nil` |
+| `object` | `map[string]any` |
+| `array` | `[]any` |
+
+## Map slices
+
+When using `JSONMapSlice`, the ordering of keys is ensured by replacing
+mappings to `map[string]any` by a `JSONMapSlice` which is an (ordered)
+slice of `JSONMapItem`s.
+
+Notice that a similar feature is available for YAML (see [`yamlutils`](../yamlutils)),
+with a `YAMLMapSlice` type based on the `JSONMapSlice`.
+
+`JSONMapSlice` is similar to an ordered map, but the keys are not retrieved
+in constant time.
+
+Another difference with the the above standard mappings is that numbers don't always map
+to a `float64`: if the value is a JSON integer, it unmarshals to `int64`.
+
+See also [some examples](https://pkg.go.dev/github.com/go-openapi/swag/jsonutils#pkg-examples)
+
+## Adapters
+
+`ReadJSON`, `WriteJSON` and `FromDynamicJSON` (which is a combination of the latter two)
+are wrappers on top of `json.Unmarshal` and `json.Marshal`.
+
+By default, the adapter merely wraps the standard library.
+
+The adapter may be used to register other JSON serialization libraries,
+possibly several ones at the same time.
+
+If the value passed is identified as an "ordered map" (i.e. implements `ifaces.Ordered`
+or `ifaces.SetOrdered`, the adapter favors the "ordered" JSON behavior and tries to
+find a registered implementation that support ordered keys in objects.
+
+Our standard library implementation supports this.
+
+As of `v0.25.0`, we support through such an adapter the popular `mailru/easyjson`
+library, which kicks in when the passed values support the `easyjson.Unmarshaler`
+or `easyjson.Marshaler` interfaces.
+
+In the future, we plan to add more similar libraries that compete on the go JSON
+serializers scene.
+
+## Registering an adapter
+
+In package `github.com/go-openapi/swag/easyjson/adapters`, several adapters are available.
+
+Each adapter is an independent go module. Hence you'll pick its dependencies only if you import it.
+
+At this moment we provide:
+* `stdlib`: JSON adapter based on the standard library
+* `easyjson`: JSON adapter based on the `github.com/mailru/easyjson`
+
+The adapters provide the basic `Marshal` and `Unmarshal` capabilities, plus an implementation
+of the `MapSlice` pattern.
+
+You may also build your own adapter based on your specific use-case. An adapter is not required to implement
+all capabilities.
+
+Every adapter comes with a `Register` function, possibly with some options, to register the adapter
+to a global registry.
+
+For example, to enable `easyjson` to be used in `ReadJSON` and `WriteJSON`, you would write something like:
+
+```go
+ import (
+ "github.com/go-openapi/swag/jsonutils/adapters"
+ easyjson "github.com/go-openapi/swag/jsonutils/adapters/easyjson/json"
+ )
+
+ func init() {
+ easyjson.Register(adapters.Registry)
+ }
+```
+
+You may register several adapters. In this case, capability matching is evaluated from the last registered
+adapters (LIFO).
+
+## [Benchmarks](./adapters/testintegration/benchmarks/README.md)
diff --git a/vendor/github.com/go-openapi/swag/jsonutils/adapters/doc.go b/vendor/github.com/go-openapi/swag/jsonutils/adapters/doc.go
new file mode 100644
index 0000000000..76d3898fca
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonutils/adapters/doc.go
@@ -0,0 +1,8 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+// Package adapters exposes a registry of adapters to multiple
+// JSON serialization libraries.
+//
+// All interfaces are defined in package [ifaces.Adapter].
+package adapters
diff --git a/vendor/github.com/go-openapi/swag/jsonutils/adapters/ifaces/doc.go b/vendor/github.com/go-openapi/swag/jsonutils/adapters/ifaces/doc.go
new file mode 100644
index 0000000000..1fd43a1fad
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonutils/adapters/ifaces/doc.go
@@ -0,0 +1,5 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+// Package ifaces exposes all interfaces to work with adapters.
+package ifaces
diff --git a/vendor/github.com/go-openapi/swag/jsonutils/adapters/ifaces/ifaces.go b/vendor/github.com/go-openapi/swag/jsonutils/adapters/ifaces/ifaces.go
new file mode 100644
index 0000000000..7805e5e5e3
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonutils/adapters/ifaces/ifaces.go
@@ -0,0 +1,84 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package ifaces
+
+import (
+ _ "encoding/json" // for documentation purpose
+ "iter"
+)
+
+// Ordered knows how to iterate over the (key,value) pairs of a JSON object.
+type Ordered interface {
+ OrderedItems() iter.Seq2[string, any]
+}
+
+// SetOrdered knows how to append or update the keys of a JSON object,
+// given an iterator over (key,value) pairs.
+//
+// If the provided iterator is nil then the receiver should be set to nil.
+type SetOrdered interface {
+ SetOrderedItems(iter.Seq2[string, any])
+}
+
+// OrderedMap represent a JSON object (i.e. like a map[string,any]),
+// and knows how to serialize and deserialize JSON with the order of keys maintained.
+type OrderedMap interface {
+ Ordered
+ SetOrdered
+
+ OrderedMarshalJSON() ([]byte, error)
+ OrderedUnmarshalJSON([]byte) error
+}
+
+// MarshalAdapter behaves likes the standard library [json.Marshal].
+type MarshalAdapter interface {
+ Poolable
+
+ Marshal(any) ([]byte, error)
+}
+
+// OrderedMarshalAdapter behaves likes the standard library [json.Marshal], preserving the order of keys in objects.
+type OrderedMarshalAdapter interface {
+ Poolable
+
+ OrderedMarshal(Ordered) ([]byte, error)
+}
+
+// UnmarshalAdapter behaves likes the standard library [json.Unmarshal].
+type UnmarshalAdapter interface {
+ Poolable
+
+ Unmarshal([]byte, any) error
+}
+
+// OrderedUnmarshalAdapter behaves likes the standard library [json.Unmarshal], preserving the order of keys in objects.
+type OrderedUnmarshalAdapter interface {
+ Poolable
+
+ OrderedUnmarshal([]byte, SetOrdered) error
+}
+
+// Adapter exposes an interface like the standard [json] library.
+type Adapter interface {
+ MarshalAdapter
+ UnmarshalAdapter
+
+ OrderedAdapter
+}
+
+// OrderedAdapter exposes interfaces to process JSON and keep the order of object keys.
+type OrderedAdapter interface {
+ OrderedMarshalAdapter
+ OrderedUnmarshalAdapter
+ NewOrderedMap(capacity int) OrderedMap
+}
+
+type Poolable interface {
+ // Self-redeem: for [Adapter] s that are allocated from a pool.
+ // The [Adapter] must not be used after calling [Redeem].
+ Redeem()
+
+ // Reset the state of the [Adapter], if any.
+ Reset()
+}
diff --git a/vendor/github.com/go-openapi/swag/jsonutils/adapters/ifaces/registry_iface.go b/vendor/github.com/go-openapi/swag/jsonutils/adapters/ifaces/registry_iface.go
new file mode 100644
index 0000000000..2d6c69f4e6
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonutils/adapters/ifaces/registry_iface.go
@@ -0,0 +1,91 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package ifaces
+
+import (
+ "strings"
+)
+
+// Capability indicates what a JSON adapter is capable of.
+type Capability uint8
+
+const (
+ CapabilityMarshalJSON Capability = 1 << iota
+ CapabilityUnmarshalJSON
+ CapabilityOrderedMarshalJSON
+ CapabilityOrderedUnmarshalJSON
+ CapabilityOrderedMap
+)
+
+func (c Capability) String() string {
+ switch c {
+ case CapabilityMarshalJSON:
+ return "MarshalJSON"
+ case CapabilityUnmarshalJSON:
+ return "UnmarshalJSON"
+ case CapabilityOrderedMarshalJSON:
+ return "OrderedMarshalJSON"
+ case CapabilityOrderedUnmarshalJSON:
+ return "OrderedUnmarshalJSON"
+ case CapabilityOrderedMap:
+ return "OrderedMap"
+ default:
+ return ""
+ }
+}
+
+// Capabilities holds several unitary capability flags
+type Capabilities uint8
+
+// Has some capability flag enabled.
+func (c Capabilities) Has(capability Capability) bool {
+ return Capability(c)&capability > 0
+}
+
+func (c Capabilities) String() string {
+ var w strings.Builder
+
+ first := true
+ for _, capability := range []Capability{
+ CapabilityMarshalJSON,
+ CapabilityUnmarshalJSON,
+ CapabilityOrderedMarshalJSON,
+ CapabilityOrderedUnmarshalJSON,
+ CapabilityOrderedMap,
+ } {
+ if c.Has(capability) {
+ if !first {
+ w.WriteByte('|')
+ } else {
+ first = false
+ }
+ w.WriteString(capability.String())
+ }
+ }
+
+ return w.String()
+}
+
+const (
+ AllCapabilities Capabilities = Capabilities(uint8(CapabilityMarshalJSON) |
+ uint8(CapabilityUnmarshalJSON) |
+ uint8(CapabilityOrderedMarshalJSON) |
+ uint8(CapabilityOrderedUnmarshalJSON) |
+ uint8(CapabilityOrderedMap))
+
+ AllUnorderedCapabilities Capabilities = Capabilities(uint8(CapabilityMarshalJSON) | uint8(CapabilityUnmarshalJSON))
+)
+
+// RegistryEntry describes how any given adapter registers its capabilities to the [Registrar].
+type RegistryEntry struct {
+ Who string
+ What Capabilities
+ Constructor func() Adapter
+ Support func(what Capability, value any) bool
+}
+
+// Registrar is a type that knows how to keep registration calls from adapters.
+type Registrar interface {
+ RegisterFor(RegistryEntry)
+}
diff --git a/vendor/github.com/go-openapi/swag/jsonutils/adapters/registry.go b/vendor/github.com/go-openapi/swag/jsonutils/adapters/registry.go
new file mode 100644
index 0000000000..3062acaff2
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonutils/adapters/registry.go
@@ -0,0 +1,229 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package adapters
+
+import (
+ "fmt"
+ "reflect"
+ "slices"
+ "sync"
+
+ "github.com/go-openapi/swag/jsonutils/adapters/ifaces"
+ stdlib "github.com/go-openapi/swag/jsonutils/adapters/stdlib/json"
+)
+
+// Registry holds the global registry for registered adapters.
+var Registry = NewRegistrar()
+
+var (
+ defaultRegistered = stdlib.Register
+
+ _ ifaces.Registrar = &Registrar{}
+)
+
+type registryError string
+
+func (e registryError) Error() string {
+ return string(e)
+}
+
+// ErrRegistry indicates an error returned by the [Registrar].
+var ErrRegistry registryError = "JSON adapters registry error"
+
+type registry []*ifaces.RegistryEntry
+
+// Registrar holds registered [ifaces.Adapters] for different serialization capabilities.
+//
+// Internally, it maintains a cache for data types that favor a given adapter.
+type Registrar struct {
+ marshalerRegistry registry
+ unmarshalerRegistry registry
+ orderedMarshalerRegistry registry
+ orderedUnmarshalerRegistry registry
+ orderedMapRegistry registry
+
+ gmx sync.RWMutex
+
+ // cache indexed by value type, so we don't have to lookup
+ marshalerCache map[reflect.Type]*ifaces.RegistryEntry
+ unmarshalerCache map[reflect.Type]*ifaces.RegistryEntry
+ orderedMarshalerCache map[reflect.Type]*ifaces.RegistryEntry
+ orderedUnmarshalerCache map[reflect.Type]*ifaces.RegistryEntry
+ orderedMapCache map[reflect.Type]*ifaces.RegistryEntry
+}
+
+func NewRegistrar() *Registrar {
+ r := &Registrar{}
+
+ r.marshalerRegistry = make(registry, 0, 1)
+ r.unmarshalerRegistry = make(registry, 0, 1)
+ r.orderedMarshalerRegistry = make(registry, 0, 1)
+ r.orderedUnmarshalerRegistry = make(registry, 0, 1)
+ r.orderedMapRegistry = make(registry, 0, 1)
+
+ r.marshalerCache = make(map[reflect.Type]*ifaces.RegistryEntry)
+ r.unmarshalerCache = make(map[reflect.Type]*ifaces.RegistryEntry)
+ r.orderedMarshalerCache = make(map[reflect.Type]*ifaces.RegistryEntry)
+ r.orderedUnmarshalerCache = make(map[reflect.Type]*ifaces.RegistryEntry)
+ r.orderedMapCache = make(map[reflect.Type]*ifaces.RegistryEntry)
+
+ defaultRegistered(r)
+
+ return r
+}
+
+// ClearCache resets the internal type cache.
+func (r *Registrar) ClearCache() {
+ r.gmx.Lock()
+ r.clearCache()
+ r.gmx.Unlock()
+}
+
+// Reset the [Registrar] to its defaults.
+func (r *Registrar) Reset() {
+ r.gmx.Lock()
+ r.clearCache()
+ r.marshalerRegistry = r.marshalerRegistry[:0]
+ r.unmarshalerRegistry = r.unmarshalerRegistry[:0]
+ r.orderedMarshalerRegistry = r.orderedMarshalerRegistry[:0]
+ r.orderedUnmarshalerRegistry = r.orderedUnmarshalerRegistry[:0]
+ r.orderedMapRegistry = r.orderedMapRegistry[:0]
+ r.gmx.Unlock()
+
+ defaultRegistered(r)
+}
+
+// RegisterFor registers an adapter for some JSON capabilities.
+func (r *Registrar) RegisterFor(entry ifaces.RegistryEntry) {
+ r.gmx.Lock()
+ if entry.What.Has(ifaces.CapabilityMarshalJSON) {
+ e := entry
+ e.What &= ifaces.Capabilities(ifaces.CapabilityMarshalJSON)
+ r.marshalerRegistry = slices.Insert(r.marshalerRegistry, 0, &e)
+ }
+ if entry.What.Has(ifaces.CapabilityUnmarshalJSON) {
+ e := entry
+ e.What &= ifaces.Capabilities(ifaces.CapabilityUnmarshalJSON)
+ r.unmarshalerRegistry = slices.Insert(r.unmarshalerRegistry, 0, &e)
+ }
+ if entry.What.Has(ifaces.CapabilityOrderedMarshalJSON) {
+ e := entry
+ e.What &= ifaces.Capabilities(ifaces.CapabilityOrderedMarshalJSON)
+ r.orderedMarshalerRegistry = slices.Insert(r.orderedMarshalerRegistry, 0, &e)
+ }
+ if entry.What.Has(ifaces.CapabilityOrderedUnmarshalJSON) {
+ e := entry
+ e.What &= ifaces.Capabilities(ifaces.CapabilityOrderedUnmarshalJSON)
+ r.orderedUnmarshalerRegistry = slices.Insert(r.orderedUnmarshalerRegistry, 0, &e)
+ }
+ if entry.What.Has(ifaces.CapabilityOrderedMap) {
+ e := entry
+ e.What &= ifaces.Capabilities(ifaces.CapabilityOrderedMap)
+ r.orderedMapRegistry = slices.Insert(r.orderedMapRegistry, 0, &e)
+ }
+ r.gmx.Unlock()
+}
+
+// AdapterFor returns an [ifaces.Adapter] that supports this capability for this type of value.
+//
+// The [ifaces.Adapter] may be redeemed to its pool using its Redeem() method, for adapters that support global
+// pooling. When this is not the case, the redeem function is just a no-operation.
+func (r *Registrar) AdapterFor(capability ifaces.Capability, value any) ifaces.Adapter {
+ entry := r.findFirstFor(capability, value)
+ if entry == nil {
+ return nil
+ }
+
+ return entry.Constructor()
+}
+
+func (r *Registrar) clearCache() {
+ clear(r.marshalerCache)
+ clear(r.unmarshalerCache)
+ clear(r.orderedMarshalerCache)
+ clear(r.orderedUnmarshalerCache)
+ clear(r.orderedMapCache)
+}
+
+func (r *Registrar) findFirstFor(capability ifaces.Capability, value any) *ifaces.RegistryEntry {
+ switch capability {
+ case ifaces.CapabilityMarshalJSON:
+ return r.findFirstInRegistryFor(r.marshalerRegistry, r.marshalerCache, capability, value)
+ case ifaces.CapabilityUnmarshalJSON:
+ return r.findFirstInRegistryFor(r.unmarshalerRegistry, r.unmarshalerCache, capability, value)
+ case ifaces.CapabilityOrderedMarshalJSON:
+ return r.findFirstInRegistryFor(r.orderedMarshalerRegistry, r.orderedMarshalerCache, capability, value)
+ case ifaces.CapabilityOrderedUnmarshalJSON:
+ return r.findFirstInRegistryFor(r.orderedUnmarshalerRegistry, r.orderedUnmarshalerCache, capability, value)
+ case ifaces.CapabilityOrderedMap:
+ return r.findFirstInRegistryFor(r.orderedMapRegistry, r.orderedMapCache, capability, value)
+ default:
+ panic(fmt.Errorf("unsupported capability %d: %w", capability, ErrRegistry))
+ }
+}
+
+func (r *Registrar) findFirstInRegistryFor(reg registry, cache map[reflect.Type]*ifaces.RegistryEntry, capability ifaces.Capability, value any) *ifaces.RegistryEntry {
+ r.gmx.RLock()
+ if len(reg) > 1 {
+ if entry, ok := cache[reflect.TypeOf(value)]; ok {
+ // cache hit
+ r.gmx.RUnlock()
+ return entry
+ }
+ }
+
+ for _, entry := range reg {
+ if !entry.Support(capability, value) {
+ continue
+ }
+
+ r.gmx.RUnlock()
+
+ // update the internal cache
+ r.gmx.Lock()
+ cache[reflect.TypeOf(value)] = entry
+ r.gmx.Unlock()
+
+ return entry
+ }
+
+ // no adapter found
+ r.gmx.RUnlock()
+
+ return nil
+}
+
+// MarshalAdapterFor returns the first adapter that knows how to Marshal this type of value.
+func MarshalAdapterFor(value any) ifaces.MarshalAdapter {
+ return Registry.AdapterFor(ifaces.CapabilityMarshalJSON, value)
+}
+
+// OrderedMarshalAdapterFor returns the first adapter that knows how to OrderedMarshal this type of value.
+func OrderedMarshalAdapterFor(value ifaces.Ordered) ifaces.OrderedMarshalAdapter {
+ return Registry.AdapterFor(ifaces.CapabilityOrderedMarshalJSON, value)
+}
+
+// UnmarshalAdapterFor returns the first adapter that knows how to Unmarshal this type of value.
+func UnmarshalAdapterFor(value any) ifaces.UnmarshalAdapter {
+ return Registry.AdapterFor(ifaces.CapabilityUnmarshalJSON, value)
+}
+
+// OrderedUnmarshalAdapterFor provides the first adapter that knows how to OrderedUnmarshal this type of value.
+func OrderedUnmarshalAdapterFor(value ifaces.SetOrdered) ifaces.OrderedUnmarshalAdapter {
+ return Registry.AdapterFor(ifaces.CapabilityOrderedUnmarshalJSON, value)
+}
+
+// NewOrderedMap provides the "ordered map" implementation provided by the registry.
+func NewOrderedMap(capacity int) ifaces.OrderedMap {
+ var v any
+ adapter := Registry.AdapterFor(ifaces.CapabilityOrderedUnmarshalJSON, v)
+ if adapter == nil {
+ return nil
+ }
+
+ defer adapter.Redeem()
+ return adapter.NewOrderedMap(capacity)
+}
+
+func noopRedeemer() {}
diff --git a/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/adapter.go b/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/adapter.go
new file mode 100644
index 0000000000..0213ff5c29
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/adapter.go
@@ -0,0 +1,115 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package json
+
+import (
+ stdjson "encoding/json"
+
+ "github.com/go-openapi/swag/jsonutils/adapters/ifaces"
+ "github.com/go-openapi/swag/typeutils"
+)
+
+const sensibleBufferSize = 8192
+
+type jsonError string
+
+func (e jsonError) Error() string {
+ return string(e)
+}
+
+// ErrStdlib indicates that an error comes from the stdlib JSON adapter
+var ErrStdlib jsonError = "error from the JSON adapter stdlib"
+
+var _ ifaces.Adapter = &Adapter{}
+
+type Adapter struct {
+}
+
+// NewAdapter yields an [ifaces.Adapter] using the standard library.
+func NewAdapter() *Adapter {
+ return &Adapter{}
+}
+
+func (a *Adapter) Marshal(value any) ([]byte, error) {
+ return stdjson.Marshal(value)
+}
+
+func (a *Adapter) Unmarshal(data []byte, value any) error {
+ return stdjson.Unmarshal(data, value)
+}
+
+func (a *Adapter) OrderedMarshal(value ifaces.Ordered) ([]byte, error) {
+ w := poolOfWriters.Borrow()
+ defer func() {
+ poolOfWriters.Redeem(w)
+ }()
+
+ if typeutils.IsNil(value) {
+ w.RawString("null")
+
+ return w.BuildBytes()
+ }
+
+ w.RawByte('{')
+ first := true
+ for k, v := range value.OrderedItems() {
+ if first {
+ first = false
+ } else {
+ w.RawByte(',')
+ }
+
+ w.String(k)
+ w.RawByte(':')
+
+ switch val := v.(type) {
+ case ifaces.Ordered:
+ w.Raw(a.OrderedMarshal(val))
+ default:
+ w.Raw(stdjson.Marshal(v))
+ }
+ }
+
+ w.RawByte('}')
+
+ return w.BuildBytes()
+}
+
+func (a *Adapter) OrderedUnmarshal(data []byte, value ifaces.SetOrdered) error {
+ var m MapSlice
+ if err := m.OrderedUnmarshalJSON(data); err != nil {
+ return err
+ }
+
+ if typeutils.IsNil(m) {
+ // force input value to nil
+ value.SetOrderedItems(nil)
+
+ return nil
+ }
+
+ value.SetOrderedItems(m.OrderedItems())
+
+ return nil
+}
+
+func (a *Adapter) NewOrderedMap(capacity int) ifaces.OrderedMap {
+ m := make(MapSlice, 0, capacity)
+
+ return &m
+}
+
+// Redeem the [Adapter] when it comes from a pool.
+//
+// The adapter becomes immediately unusable once redeemed.
+func (a *Adapter) Redeem() {
+ if a == nil {
+ return
+ }
+
+ RedeemAdapter(a)
+}
+
+func (a *Adapter) Reset() {
+}
diff --git a/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/doc.go b/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/doc.go
new file mode 100644
index 0000000000..5ea1b44042
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/doc.go
@@ -0,0 +1,5 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+// Package json implements an [ifaces.Adapter] using the standard library.
+package json
diff --git a/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/lexer.go b/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/lexer.go
new file mode 100644
index 0000000000..b5aa1c7972
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/lexer.go
@@ -0,0 +1,320 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package json
+
+import (
+ stdjson "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "math"
+ "strconv"
+
+ "github.com/go-openapi/swag/conv"
+)
+
+type token struct {
+ stdjson.Token
+}
+
+func (t token) String() string {
+ if t == invalidToken {
+ return "invalid token"
+ }
+ if t == eofToken {
+ return "EOF"
+ }
+
+ return fmt.Sprintf("%v", t.Token)
+}
+
+func (t token) Kind() tokenKind {
+ switch t.Token.(type) {
+ case nil:
+ return tokenNull
+ case stdjson.Delim:
+ return tokenDelim
+ case bool:
+ return tokenBool
+ case float64:
+ return tokenFloat
+ case stdjson.Number:
+ return tokenNumber
+ case string:
+ return tokenString
+ default:
+ return tokenUndef
+ }
+}
+
+func (t token) Delim() byte {
+ r, ok := t.Token.(stdjson.Delim)
+ if !ok {
+ return 0
+ }
+
+ return byte(r)
+}
+
+type tokenKind uint8
+
+const (
+ tokenUndef tokenKind = iota
+ tokenString
+ tokenNumber
+ tokenFloat
+ tokenBool
+ tokenNull
+ tokenDelim
+)
+
+var (
+ invalidToken = token{
+ Token: stdjson.Token(struct{}{}),
+ }
+
+ eofToken = token{
+ Token: stdjson.Token(&struct{}{}),
+ }
+
+ undefToken = token{
+ Token: stdjson.Token(uint8(0)),
+ }
+)
+
+// jlexer apes easyjson's jlexer, but uses the standard library decoder under the hood.
+type jlexer struct {
+ buf *bytesReader
+ dec *stdjson.Decoder
+ err error
+ // current token
+ next token
+ // started bool
+}
+
+type bytesReader struct {
+ buf []byte
+ offset int
+}
+
+func (b *bytesReader) Reset() {
+ b.buf = nil
+ b.offset = 0
+}
+
+func (b *bytesReader) Read(p []byte) (int, error) {
+ if b.offset >= len(b.buf) {
+ return 0, io.EOF
+ }
+
+ n := len(p)
+ buf := b.buf[b.offset:]
+ m := len(buf)
+
+ if n >= m {
+ copy(p, buf)
+ b.offset += m
+
+ return m, nil
+ }
+
+ copy(p, buf[:n])
+ b.offset += n
+
+ return n, nil
+}
+
+var _ io.Reader = &bytesReader{}
+
+func newLexer(data []byte) *jlexer {
+ l := &jlexer{
+ // current: undefToken,
+ next: undefToken,
+ }
+ l.buf = &bytesReader{
+ buf: data,
+ }
+ l.dec = stdjson.NewDecoder(l.buf) // unfortunately, cannot pool this
+
+ return l
+}
+
+func (l *jlexer) Reset() {
+ l.err = nil
+ l.next = undefToken
+ // leave l.dec and l.buf alone, since they are replaced at every Borrow
+}
+
+func (l *jlexer) Error() error {
+ return l.err
+}
+
+func (l *jlexer) SetErr(err error) {
+ l.err = err
+}
+
+func (l *jlexer) Ok() bool {
+ return l.err == nil
+}
+
+// NextToken consumes a token
+func (l *jlexer) NextToken() token {
+ if !l.Ok() {
+ return invalidToken
+ }
+
+ if l.next != undefToken {
+ next := l.next
+ l.next = undefToken
+
+ return next
+ }
+
+ return l.fetchToken()
+}
+
+// PeekToken returns the next token without consuming it
+func (l *jlexer) PeekToken() token {
+ if l.next == undefToken {
+ l.next = l.fetchToken()
+ }
+
+ return l.next
+}
+
+func (l *jlexer) Skip() {
+ _ = l.NextToken()
+}
+
+func (l *jlexer) IsDelim(c byte) bool {
+ if !l.Ok() {
+ return false
+ }
+
+ next := l.PeekToken()
+ if next.Kind() != tokenDelim {
+ return false
+ }
+
+ if next.Delim() != c {
+ return false
+ }
+
+ return true
+}
+
+func (l *jlexer) IsNull() bool {
+ if !l.Ok() {
+ return false
+ }
+
+ next := l.PeekToken()
+
+ return next.Kind() == tokenNull
+}
+
+func (l *jlexer) Delim(c byte) {
+ if !l.Ok() {
+ return
+ }
+
+ tok := l.NextToken()
+ if tok.Kind() != tokenDelim {
+ l.err = fmt.Errorf("expected a delimiter token but got '%v': %w", tok, ErrStdlib)
+
+ return
+ }
+
+ if tok.Delim() != c {
+ l.err = fmt.Errorf("expected delimiter '%q' but got '%q': %w", c, tok.Delim(), ErrStdlib)
+ }
+}
+
+func (l *jlexer) Null() {
+ if !l.Ok() {
+ return
+ }
+
+ tok := l.NextToken()
+ if tok.Kind() != tokenNull {
+ l.err = fmt.Errorf("expected a null token but got '%v': %w", tok, ErrStdlib)
+ }
+}
+
+func (l *jlexer) Number() any {
+ if !l.Ok() {
+ return 0
+ }
+
+ tok := l.NextToken()
+
+ switch tok.Kind() { //nolint:exhaustive
+ case tokenNumber:
+ n := tok.Token.(stdjson.Number).String()
+ f, _ := strconv.ParseFloat(n, 64)
+ if conv.IsFloat64AJSONInteger(f) {
+ return int64(math.Trunc(f))
+ }
+
+ return f
+
+ case tokenFloat:
+ f := tok.Token.(float64)
+ if conv.IsFloat64AJSONInteger(f) {
+ return int64(math.Trunc(f))
+ }
+
+ return f
+
+ default:
+ l.err = fmt.Errorf("expected a number token but got '%v': %w", tok, ErrStdlib)
+
+ return 0
+ }
+}
+
+func (l *jlexer) Bool() bool {
+ if !l.Ok() {
+ return false
+ }
+
+ tok := l.NextToken()
+ if tok.Kind() != tokenBool {
+ l.err = fmt.Errorf("expected a bool token but got '%v': %w", tok, ErrStdlib)
+
+ return false
+ }
+
+ return tok.Token.(bool)
+}
+
+func (l *jlexer) String() string {
+ if !l.Ok() {
+ return ""
+ }
+
+ tok := l.NextToken()
+ if tok.Kind() != tokenString {
+ l.err = fmt.Errorf("expected a string token but got '%v': %w", tok, ErrStdlib)
+
+ return ""
+ }
+
+ return tok.Token.(string)
+}
+
+// Commas and colons are elided.
+func (l *jlexer) fetchToken() token {
+ jtok, err := l.dec.Token()
+ if err != nil {
+ if errors.Is(err, io.EOF) {
+ return eofToken
+ }
+
+ l.err = errors.Join(err, ErrStdlib)
+ return invalidToken
+ }
+
+ return token{Token: jtok}
+}
diff --git a/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/ordered_map.go b/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/ordered_map.go
new file mode 100644
index 0000000000..54deef406f
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/ordered_map.go
@@ -0,0 +1,266 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package json
+
+import (
+ stdjson "encoding/json"
+ "fmt"
+ "iter"
+
+ "github.com/go-openapi/swag/jsonutils/adapters/ifaces"
+)
+
+var _ ifaces.OrderedMap = &MapSlice{}
+
+// MapSlice represents a JSON object, with the order of keys maintained.
+type MapSlice []MapItem
+
+func (s MapSlice) OrderedItems() iter.Seq2[string, any] {
+ return func(yield func(string, any) bool) {
+ for _, item := range s {
+ if !yield(item.Key, item.Value) {
+ return
+ }
+ }
+ }
+}
+
+func (s *MapSlice) SetOrderedItems(items iter.Seq2[string, any]) {
+ if items == nil {
+ *s = nil
+
+ return
+ }
+
+ m := *s
+ if len(m) > 0 {
+ // update mode
+ idx := make(map[string]int, len(m))
+
+ for i, item := range m {
+ idx[item.Key] = i
+ }
+
+ for k, v := range items {
+ idx, ok := idx[k]
+ if ok {
+ m[idx].Value = v
+
+ continue
+ }
+ m = append(m, MapItem{Key: k, Value: v})
+ }
+
+ *s = m
+
+ return
+ }
+
+ for k, v := range items {
+ m = append(m, MapItem{Key: k, Value: v})
+ }
+
+ *s = m
+}
+
+// MarshalJSON renders a [MapSlice] as JSON bytes, preserving the order of keys.
+func (s MapSlice) MarshalJSON() ([]byte, error) {
+ return s.OrderedMarshalJSON()
+}
+
+func (s MapSlice) OrderedMarshalJSON() ([]byte, error) {
+ w := poolOfWriters.Borrow()
+ defer func() {
+ poolOfWriters.Redeem(w)
+ }()
+
+ s.marshalObject(w)
+
+ return w.BuildBytes() // this clones data, so it's okay to redeem the writer and its buffer
+}
+
+// UnmarshalJSON builds a [MapSlice] from JSON bytes, preserving the order of keys.
+//
+// Inner objects are unmarshaled as [MapSlice] slices and not map[string]any.
+func (s *MapSlice) UnmarshalJSON(data []byte) error {
+ return s.OrderedUnmarshalJSON(data)
+}
+
+func (s *MapSlice) OrderedUnmarshalJSON(data []byte) error {
+ l := poolOfLexers.Borrow(data)
+ defer func() {
+ poolOfLexers.Redeem(l)
+ }()
+
+ s.unmarshalObject(l)
+
+ return l.Error()
+}
+
+func (s MapSlice) marshalObject(w *jwriter) {
+ if s == nil {
+ w.RawString("null")
+
+ return
+ }
+
+ w.RawByte('{')
+
+ if len(s) == 0 {
+ w.RawByte('}')
+
+ return
+ }
+
+ s[0].marshalJSON(w)
+
+ for i := 1; i < len(s); i++ {
+ w.RawByte(',')
+ s[i].marshalJSON(w)
+ }
+
+ w.RawByte('}')
+}
+
+func (s *MapSlice) unmarshalObject(in *jlexer) {
+ if in.IsNull() {
+ in.Skip()
+
+ return
+ }
+
+ in.Delim('{') // consume token
+ if !in.Ok() {
+ return
+ }
+
+ result := make(MapSlice, 0)
+
+ for in.Ok() && !in.IsDelim('}') {
+ var mi MapItem
+
+ mi.unmarshalKeyValue(in)
+ result = append(result, mi)
+ }
+
+ in.Delim('}')
+
+ if !in.Ok() {
+ return
+ }
+
+ *s = result
+}
+
+// MapItem represents the value of a key in a JSON object held by [MapSlice].
+//
+// Notice that [MapItem] should not be marshaled to or unmarshaled from JSON directly,
+// use this type as part of a [MapSlice] when dealing with JSON bytes.
+type MapItem struct {
+ Key string
+ Value any
+}
+
+func (s MapItem) marshalJSON(w *jwriter) {
+ w.String(s.Key)
+ w.RawByte(':')
+ w.Raw(stdjson.Marshal(s.Value))
+}
+
+func (s *MapItem) unmarshalKeyValue(in *jlexer) {
+ key := in.String() // consume string
+ value := s.asInterface(in) // consume any value, including termination tokens '}' or ']'
+
+ if !in.Ok() {
+ return
+ }
+
+ s.Key = key
+ s.Value = value
+}
+
+func (s *MapItem) unmarshalArray(in *jlexer) []any {
+ if in.IsNull() {
+ in.Skip()
+
+ return nil
+ }
+
+ in.Delim('[') // consume token
+ if !in.Ok() {
+ return nil
+ }
+
+ ret := make([]any, 0)
+
+ for in.Ok() && !in.IsDelim(']') {
+ ret = append(ret, s.asInterface(in))
+ }
+
+ in.Delim(']')
+ if !in.Ok() {
+ return nil
+ }
+
+ return ret
+}
+
+// asInterface is very much like [jlexer.Lexer.Interface], but unmarshals an object
+// into a [MapSlice], not a map[string]any.
+//
+// We have to force parsing errors somehow, since [jlexer.Lexer] doesn't let us
+// set a parsing error directly.
+func (s *MapItem) asInterface(in *jlexer) any {
+ if !in.Ok() {
+ return nil
+ }
+
+ tok := in.PeekToken() // look-ahead what the next token looks like
+ kind := tok.Kind()
+
+ switch kind {
+ case tokenString:
+ return in.String() // consume string
+
+ case tokenNumber, tokenFloat:
+ return in.Number()
+
+ case tokenBool:
+ return in.Bool()
+
+ case tokenNull:
+ in.Null()
+
+ return nil
+
+ case tokenDelim:
+ switch tok.Delim() {
+ case '{': // not consumed yet
+ ret := make(MapSlice, 0)
+ ret.unmarshalObject(in) // consumes the terminating '}'
+
+ if in.Ok() {
+ return ret
+ }
+
+ // lexer is in an error state: will exhaust
+ return nil
+
+ case '[': // not consumed yet
+ return s.unmarshalArray(in) // consumes the terminating ']'
+ default:
+ in.SetErr(fmt.Errorf("unexpected delimiter: %v: %w", tok, ErrStdlib)) // force error
+ return nil
+ }
+
+ case tokenUndef:
+ fallthrough
+ default:
+ if in.Ok() {
+ in.SetErr(fmt.Errorf("unexpected token: %v: %w", tok, ErrStdlib)) // force error
+ }
+
+ return nil
+ }
+}
diff --git a/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/pool.go b/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/pool.go
new file mode 100644
index 0000000000..709b97c304
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/pool.go
@@ -0,0 +1,143 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package json
+
+import (
+ "encoding/json"
+ "sync"
+
+ "github.com/go-openapi/swag/jsonutils/adapters/ifaces"
+)
+
+type adaptersPool struct {
+ sync.Pool
+}
+
+func (p *adaptersPool) Borrow() *Adapter {
+ return p.Get().(*Adapter)
+}
+
+func (p *adaptersPool) BorrowIface() ifaces.Adapter {
+ return p.Get().(*Adapter)
+}
+
+func (p *adaptersPool) Redeem(a *Adapter) {
+ p.Put(a)
+}
+
+type writersPool struct {
+ sync.Pool
+}
+
+func (p *writersPool) Borrow() *jwriter {
+ ptr := p.Get()
+
+ jw := ptr.(*jwriter)
+ jw.Reset()
+
+ return jw
+}
+
+func (p *writersPool) Redeem(w *jwriter) {
+ p.Put(w)
+}
+
+type lexersPool struct {
+ sync.Pool
+}
+
+func (p *lexersPool) Borrow(data []byte) *jlexer {
+ ptr := p.Get()
+
+ l := ptr.(*jlexer)
+ l.buf = poolOfReaders.Borrow(data)
+ l.dec = json.NewDecoder(l.buf) // cannot pool, not exposed by the encoding/json API
+ l.Reset()
+
+ return l
+}
+
+func (p *lexersPool) Redeem(l *jlexer) {
+ l.dec = nil
+ discard := l.buf
+ l.buf = nil
+ poolOfReaders.Redeem(discard)
+ p.Put(l)
+}
+
+type readersPool struct {
+ sync.Pool
+}
+
+func (p *readersPool) Borrow(data []byte) *bytesReader {
+ ptr := p.Get()
+
+ b := ptr.(*bytesReader)
+ b.Reset()
+ b.buf = data
+
+ return b
+}
+
+func (p *readersPool) Redeem(b *bytesReader) {
+ p.Put(b)
+}
+
+var (
+ poolOfAdapters = &adaptersPool{
+ Pool: sync.Pool{
+ New: func() any {
+ return NewAdapter()
+ },
+ },
+ }
+
+ poolOfWriters = &writersPool{
+ Pool: sync.Pool{
+ New: func() any {
+ return newJWriter()
+ },
+ },
+ }
+
+ poolOfLexers = &lexersPool{
+ Pool: sync.Pool{
+ New: func() any {
+ return newLexer(nil)
+ },
+ },
+ }
+
+ poolOfReaders = &readersPool{
+ Pool: sync.Pool{
+ New: func() any {
+ return &bytesReader{}
+ },
+ },
+ }
+)
+
+// BorrowAdapter borrows an [Adapter] from the pool, recycling already allocated instances.
+func BorrowAdapter() *Adapter {
+ return poolOfAdapters.Borrow()
+}
+
+// BorrowAdapterIface borrows a stdlib [Adapter] and converts it directly
+// to [ifaces.Adapter]. This is useful to avoid further allocations when
+// translating the concrete type into an interface.
+func BorrowAdapterIface() ifaces.Adapter {
+ return poolOfAdapters.BorrowIface()
+}
+
+// RedeemAdapter redeems an [Adapter] to the pool, so it may be recycled.
+func RedeemAdapter(a *Adapter) {
+ poolOfAdapters.Redeem(a)
+}
+
+func RedeemAdapterIface(a ifaces.Adapter) {
+ concrete, ok := a.(*Adapter)
+ if ok {
+ poolOfAdapters.Redeem(concrete)
+ }
+}
diff --git a/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/register.go b/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/register.go
new file mode 100644
index 0000000000..fc8818694e
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/register.go
@@ -0,0 +1,26 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package json
+
+import (
+ "fmt"
+ "reflect"
+
+ "github.com/go-openapi/swag/jsonutils/adapters/ifaces"
+)
+
+func Register(dispatcher ifaces.Registrar) {
+ t := reflect.TypeOf(Adapter{})
+ dispatcher.RegisterFor(
+ ifaces.RegistryEntry{
+ Who: fmt.Sprintf("%s.%s", t.PkgPath(), t.Name()),
+ What: ifaces.AllCapabilities,
+ Constructor: BorrowAdapterIface,
+ Support: support,
+ })
+}
+
+func support(_ ifaces.Capability, _ any) bool {
+ return true
+}
diff --git a/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/writer.go b/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/writer.go
new file mode 100644
index 0000000000..dc2325c1a3
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonutils/adapters/stdlib/json/writer.go
@@ -0,0 +1,75 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package json
+
+import (
+ "bytes"
+ "encoding/json"
+ "strings"
+)
+
+type jwriter struct {
+ buf *bytes.Buffer
+ err error
+}
+
+func newJWriter() *jwriter {
+ buf := make([]byte, 0, sensibleBufferSize)
+
+ return &jwriter{buf: bytes.NewBuffer(buf)}
+}
+
+func (w *jwriter) Reset() {
+ w.buf.Reset()
+ w.err = nil
+}
+
+func (w *jwriter) RawString(s string) {
+ if w.err != nil {
+ return
+ }
+ w.buf.WriteString(s)
+}
+
+func (w *jwriter) Raw(b []byte, err error) {
+ if w.err != nil {
+ return
+ }
+ if err != nil {
+ w.err = err
+ return
+ }
+
+ _, _ = w.buf.Write(b)
+}
+
+func (w *jwriter) RawByte(c byte) {
+ if w.err != nil {
+ return
+ }
+ w.buf.WriteByte(c)
+}
+
+var quoteReplacer = strings.NewReplacer(`"`, `\"`, `\`, `\\`)
+
+func (w *jwriter) String(s string) {
+ if w.err != nil {
+ return
+ }
+ // escape quotes and \
+ s = quoteReplacer.Replace(s)
+
+ _ = w.buf.WriteByte('"')
+ json.HTMLEscape(w.buf, []byte(s))
+ _ = w.buf.WriteByte('"')
+}
+
+// BuildBytes returns a clone of the internal buffer.
+func (w *jwriter) BuildBytes() ([]byte, error) {
+ if w.err != nil {
+ return nil, w.err
+ }
+
+ return bytes.Clone(w.buf.Bytes()), nil
+}
diff --git a/vendor/github.com/go-openapi/swag/jsonutils/concat.go b/vendor/github.com/go-openapi/swag/jsonutils/concat.go
new file mode 100644
index 0000000000..2068503af0
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonutils/concat.go
@@ -0,0 +1,92 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package jsonutils
+
+import (
+ "bytes"
+)
+
+// nullJSON represents a JSON object with null type
+var nullJSON = []byte("null")
+
+const comma = byte(',')
+
+var closers map[byte]byte
+
+func init() {
+ closers = map[byte]byte{
+ '{': '}',
+ '[': ']',
+ }
+}
+
+// ConcatJSON concatenates multiple json objects or arrays efficiently.
+//
+// Note that [ConcatJSON] performs a very simple (and fast) concatenation
+// operation: it does not attempt to merge objects.
+func ConcatJSON(blobs ...[]byte) []byte {
+ if len(blobs) == 0 {
+ return nil
+ }
+
+ last := len(blobs) - 1
+ for blobs[last] == nil || bytes.Equal(blobs[last], nullJSON) {
+ // strips trailing null objects
+ last--
+ if last < 0 {
+ // there was nothing but "null"s or nil...
+ return nil
+ }
+ }
+ if last == 0 {
+ return blobs[0]
+ }
+
+ var opening, closing byte
+ var idx, a int
+ buf := bytes.NewBuffer(nil)
+
+ for i, b := range blobs[:last+1] {
+ if b == nil || bytes.Equal(b, nullJSON) {
+ // a null object is in the list: skip it
+ continue
+ }
+ if len(b) > 0 && opening == 0 { // is this an array or an object?
+ opening, closing = b[0], closers[b[0]]
+ }
+
+ if opening != '{' && opening != '[' {
+ continue // don't know how to concatenate non container objects
+ }
+
+ const minLengthIfNotEmpty = 3
+ if len(b) < minLengthIfNotEmpty { // yep empty but also the last one, so closing this thing
+ if i == last && a > 0 {
+ _ = buf.WriteByte(closing) // never returns err != nil
+ }
+ continue
+ }
+
+ idx = 0
+ if a > 0 { // we need to join with a comma for everything beyond the first non-empty item
+ _ = buf.WriteByte(comma) // never returns err != nil
+ idx = 1 // this is not the first or the last so we want to drop the leading bracket
+ }
+
+ if i != last { // not the last one, strip brackets
+ _, _ = buf.Write(b[idx : len(b)-1]) // never returns err != nil
+ } else { // last one, strip only the leading bracket
+ _, _ = buf.Write(b[idx:])
+ }
+ a++
+ }
+
+ // somehow it ended up being empty, so provide a default value
+ if buf.Len() == 0 && (opening == '{' || opening == '[') {
+ _ = buf.WriteByte(opening) // never returns err != nil
+ _ = buf.WriteByte(closing)
+ }
+
+ return buf.Bytes()
+}
diff --git a/vendor/github.com/go-openapi/swag/jsonutils/doc.go b/vendor/github.com/go-openapi/swag/jsonutils/doc.go
new file mode 100644
index 0000000000..3926cc58d1
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonutils/doc.go
@@ -0,0 +1,7 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+// Package jsonutils provides helpers to work with JSON.
+//
+// These utilities work with dynamic go structures to and from JSON.
+package jsonutils
diff --git a/vendor/github.com/go-openapi/swag/jsonutils/json.go b/vendor/github.com/go-openapi/swag/jsonutils/json.go
new file mode 100644
index 0000000000..40753ce03f
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonutils/json.go
@@ -0,0 +1,116 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package jsonutils
+
+import (
+ "bytes"
+ "encoding/json"
+
+ "github.com/go-openapi/swag/jsonutils/adapters"
+ "github.com/go-openapi/swag/jsonutils/adapters/ifaces"
+)
+
+// WriteJSON marshals a data structure as JSON.
+//
+// The difference with [json.Marshal] is that it may check among several alternatives
+// to do so.
+//
+// See [adapters.Registrar] for more details about how to configure
+// multiple serialization alternatives.
+//
+// NOTE: to allow types that are [easyjson.Marshaler] s to use that route to process JSON,
+// you now need to register the adapter for easyjson at runtime.
+func WriteJSON(value any) ([]byte, error) {
+ if orderedMap, isOrdered := value.(ifaces.Ordered); isOrdered {
+ orderedMarshaler := adapters.OrderedMarshalAdapterFor(orderedMap)
+
+ if orderedMarshaler != nil {
+ defer orderedMarshaler.Redeem()
+
+ return orderedMarshaler.OrderedMarshal(orderedMap)
+ }
+
+ // no support found in registered adapters, fallback to the default (unordered) case
+ }
+
+ marshaler := adapters.MarshalAdapterFor(value)
+ if marshaler != nil {
+ defer marshaler.Redeem()
+
+ return marshaler.Marshal(value)
+ }
+
+ // no support found in registered adapters, fallback to the default standard library.
+ //
+ // This only happens when tinkering with the global registry of adapters, since the default handles all the above cases.
+ return json.Marshal(value) // Codecov ignore // this is a safeguard not easily simulated in tests
+}
+
+// ReadJSON unmarshals JSON data into a data structure.
+//
+// The difference with [json.Unmarshal] is that it may check among several alternatives
+// to do so.
+//
+// See [adapters.Registrar] for more details about how to configure
+// multiple serialization alternatives.
+//
+// NOTE: value must be a pointer.
+//
+// If the provided value implements [ifaces.SetOrdered], it is a considered an "ordered map" and [ReadJSON]
+// will favor an adapter that supports the [ifaces.OrderedUnmarshal] feature, or fallback to
+// an unordered behavior if none is found.
+//
+// NOTE: to allow types that are [easyjson.Unmarshaler] s to use that route to process JSON,
+// you now need to register the adapter for easyjson at runtime.
+func ReadJSON(data []byte, value any) error {
+ trimmedData := bytes.Trim(data, "\x00")
+
+ if orderedMap, isOrdered := value.(ifaces.SetOrdered); isOrdered {
+ // if the value is an ordered map, favors support for OrderedUnmarshal.
+
+ orderedUnmarshaler := adapters.OrderedUnmarshalAdapterFor(orderedMap)
+
+ if orderedUnmarshaler != nil {
+ defer orderedUnmarshaler.Redeem()
+
+ return orderedUnmarshaler.OrderedUnmarshal(trimmedData, orderedMap)
+ }
+
+ // no support found in registered adapters, fallback to the default (unordered) case
+ }
+
+ unmarshaler := adapters.UnmarshalAdapterFor(value)
+ if unmarshaler != nil {
+ defer unmarshaler.Redeem()
+
+ return unmarshaler.Unmarshal(trimmedData, value)
+ }
+
+ // no support found in registered adapters, fallback to the default standard library.
+ //
+ // This only happens when tinkering with the global registry of adapters, since the default handles all the above cases.
+ return json.Unmarshal(trimmedData, value) // Codecov ignore // this is a safeguard not easily simulated in tests
+}
+
+// FromDynamicJSON turns a go value into a properly JSON typed structure.
+//
+// "Dynamic JSON" refers to what you get when unmarshaling JSON into an untyped any,
+// i.e. objects are represented by map[string]any, arrays by []any, and
+// all numbers are represented as float64.
+//
+// NOTE: target must be a pointer.
+//
+// # Maintaining the order of keys in objects
+//
+// If source and target implement [ifaces.Ordered] and [ifaces.SetOrdered] respectively,
+// they are considered "ordered maps" and the order of keys is maintained in the
+// "jsonification" process. In that case, map[string]any values are replaced by (ordered) [JSONMapSlice] ones.
+func FromDynamicJSON(source, target any) error {
+ b, err := WriteJSON(source)
+ if err != nil {
+ return err
+ }
+
+ return ReadJSON(b, target)
+}
diff --git a/vendor/github.com/go-openapi/swag/jsonutils/ordered_map.go b/vendor/github.com/go-openapi/swag/jsonutils/ordered_map.go
new file mode 100644
index 0000000000..38dd3e2444
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonutils/ordered_map.go
@@ -0,0 +1,114 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package jsonutils
+
+import (
+ "iter"
+
+ "github.com/go-openapi/swag/jsonutils/adapters"
+ "github.com/go-openapi/swag/typeutils"
+)
+
+// JSONMapSlice represents a JSON object, with the order of keys maintained.
+//
+// It behaves like an ordered map, but keys can't be accessed in constant time.
+type JSONMapSlice []JSONMapItem
+
+// OrderedItems iterates over all (key,value) pairs with the order of keys maintained.
+//
+// This implements the [ifaces.Ordered] interface, so that [ifaces.Adapter] s know how to marshal
+// keys in the desired order.
+func (s JSONMapSlice) OrderedItems() iter.Seq2[string, any] {
+ return func(yield func(string, any) bool) {
+ for _, item := range s {
+ if !yield(item.Key, item.Value) {
+ return
+ }
+ }
+ }
+}
+
+// SetOrderedItems sets keys in the [JSONMapSlice] objects, as presented by
+// the provided iterator.
+//
+// As a special case, if items is nil, this sets to receiver to a nil slice.
+//
+// This implements the [ifaces.SetOrdered] interface, so that [ifaces.Adapter] s know how to unmarshal
+// keys in the desired order.
+func (s *JSONMapSlice) SetOrderedItems(items iter.Seq2[string, any]) {
+ if items == nil {
+ // force receiver to be a nil slice
+ *s = nil
+
+ return
+ }
+
+ m := *s
+ if len(m) > 0 {
+ // update mode: short-circuited when unmarshaling fresh data structures
+ idx := make(map[string]int, len(m))
+
+ for i, item := range m {
+ idx[item.Key] = i
+ }
+
+ for k, v := range items {
+ idx, ok := idx[k]
+ if ok {
+ m[idx].Value = v
+
+ continue
+ }
+
+ m = append(m, JSONMapItem{Key: k, Value: v})
+ }
+
+ *s = m
+
+ return
+ }
+
+ for k, v := range items {
+ m = append(m, JSONMapItem{Key: k, Value: v})
+ }
+
+ *s = m
+}
+
+// MarshalJSON renders a [JSONMapSlice] as JSON bytes, preserving the order of keys.
+//
+// It will pick the JSON library currently configured by the [adapters.Registry] (defaults to the standard library).
+func (s JSONMapSlice) MarshalJSON() ([]byte, error) {
+ orderedMarshaler := adapters.OrderedMarshalAdapterFor(s)
+ defer orderedMarshaler.Redeem()
+
+ return orderedMarshaler.OrderedMarshal(s)
+}
+
+// UnmarshalJSON builds a [JSONMapSlice] from JSON bytes, preserving the order of keys.
+//
+// Inner objects are unmarshaled as ordered [JSONMapSlice] slices and not map[string]any.
+//
+// It will pick the JSON library currently configured by the [adapters.Registry] (defaults to the standard library).
+func (s *JSONMapSlice) UnmarshalJSON(data []byte) error {
+ if typeutils.IsNil(*s) {
+ // allow to unmarshal with a simple var declaration (nil slice)
+ *s = JSONMapSlice{}
+ }
+
+ orderedUnmarshaler := adapters.OrderedUnmarshalAdapterFor(s)
+ defer orderedUnmarshaler.Redeem()
+
+ return orderedUnmarshaler.OrderedUnmarshal(data, s)
+}
+
+// JSONMapItem represents the value of a key in a JSON object held by [JSONMapSlice].
+//
+// Notice that JSONMapItem should not be marshaled to or unmarshaled from JSON directly.
+//
+// Use this type as part of a [JSONMapSlice] when dealing with JSON bytes.
+type JSONMapItem struct {
+ Key string
+ Value any
+}
diff --git a/vendor/github.com/go-openapi/swag/jsonutils_iface.go b/vendor/github.com/go-openapi/swag/jsonutils_iface.go
new file mode 100644
index 0000000000..7bd4105fa5
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/jsonutils_iface.go
@@ -0,0 +1,65 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package swag
+
+import (
+ "log"
+
+ "github.com/go-openapi/swag/jsonutils"
+)
+
+// JSONMapSlice represents a JSON object, with the order of keys maintained
+//
+// Deprecated: use [jsonutils.JSONMapSlice] instead, or [yamlutils.YAMLMapSlice] if you marshal YAML.
+type JSONMapSlice = jsonutils.JSONMapSlice
+
+// JSONMapItem represents a JSON object, with the order of keys maintained
+//
+// Deprecated: use [jsonutils.JSONMapItem] instead.
+type JSONMapItem = jsonutils.JSONMapItem
+
+// WriteJSON writes json data.
+//
+// Deprecated: use [jsonutils.WriteJSON] instead.
+func WriteJSON(data any) ([]byte, error) { return jsonutils.WriteJSON(data) }
+
+// ReadJSON reads json data.
+//
+// Deprecated: use [jsonutils.ReadJSON] instead.
+func ReadJSON(data []byte, value any) error { return jsonutils.ReadJSON(data, value) }
+
+// DynamicJSONToStruct converts an untyped JSON structure into a target data type.
+//
+// Deprecated: use [jsonutils.FromDynamicJSON] instead.
+func DynamicJSONToStruct(data any, target any) error {
+ return jsonutils.FromDynamicJSON(data, target)
+}
+
+// ConcatJSON concatenates multiple JSON objects efficiently.
+//
+// Deprecated: use [jsonutils.ConcatJSON] instead.
+func ConcatJSON(blobs ...[]byte) []byte { return jsonutils.ConcatJSON(blobs...) }
+
+// ToDynamicJSON turns a go value into a properly JSON untyped structure.
+//
+// It is the same as [FromDynamicJSON], but doesn't check for errors.
+//
+// Deprecated: this function is a misnomer and is unsafe. Use [jsonutils.FromDynamicJSON] instead.
+func ToDynamicJSON(value any) any {
+ var res any
+ if err := FromDynamicJSON(value, &res); err != nil {
+ log.Println(err)
+ }
+
+ return res
+}
+
+// FromDynamicJSON turns a go value into a properly JSON typed structure.
+//
+// "Dynamic JSON" refers to what you get when unmarshaling JSON into an untyped any,
+// i.e. objects are represented by map[string]any, arrays by []any, and all
+// scalar values are any.
+//
+// Deprecated: use [jsonutils.FromDynamicJSON] instead.
+func FromDynamicJSON(data, target any) error { return jsonutils.FromDynamicJSON(data, target) }
diff --git a/vendor/github.com/go-openapi/swag/loading/LICENSE b/vendor/github.com/go-openapi/swag/loading/LICENSE
new file mode 100644
index 0000000000..d645695673
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/loading/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/vendor/github.com/go-openapi/swag/loading/doc.go b/vendor/github.com/go-openapi/swag/loading/doc.go
new file mode 100644
index 0000000000..8cf7bcb8b9
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/loading/doc.go
@@ -0,0 +1,5 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+// Package loading provides tools to load a file from http or from a local file system.
+package loading
diff --git a/vendor/github.com/go-openapi/swag/loading/errors.go b/vendor/github.com/go-openapi/swag/loading/errors.go
new file mode 100644
index 0000000000..b3964289c7
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/loading/errors.go
@@ -0,0 +1,15 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package loading
+
+type loadingError string
+
+const (
+ // ErrLoader is an error raised by the file loader utility
+ ErrLoader loadingError = "loader error"
+)
+
+func (e loadingError) Error() string {
+ return string(e)
+}
diff --git a/vendor/github.com/go-openapi/swag/loading/json.go b/vendor/github.com/go-openapi/swag/loading/json.go
new file mode 100644
index 0000000000..59db12f5cf
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/loading/json.go
@@ -0,0 +1,25 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package loading
+
+import (
+ "encoding/json"
+ "errors"
+ "path/filepath"
+)
+
+// JSONMatcher matches json for a file loader.
+func JSONMatcher(path string) bool {
+ ext := filepath.Ext(path)
+ return ext == ".json" || ext == ".jsn" || ext == ".jso"
+}
+
+// JSONDoc loads a json document from either a file or a remote url.
+func JSONDoc(path string, opts ...Option) (json.RawMessage, error) {
+ data, err := LoadFromFileOrHTTP(path, opts...)
+ if err != nil {
+ return nil, errors.Join(err, ErrLoader)
+ }
+ return json.RawMessage(data), nil
+}
diff --git a/vendor/github.com/go-openapi/swag/loading.go b/vendor/github.com/go-openapi/swag/loading/loading.go
similarity index 61%
rename from vendor/github.com/go-openapi/swag/loading.go
rename to vendor/github.com/go-openapi/swag/loading/loading.go
index 658a24b789..269fb74d16 100644
--- a/vendor/github.com/go-openapi/swag/loading.go
+++ b/vendor/github.com/go-openapi/swag/loading/loading.go
@@ -1,54 +1,26 @@
-// Copyright 2015 go-swagger maintainers
-//
-// 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.
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
-package swag
+package loading
import (
+ "context"
+ "embed"
"fmt"
"io"
"log"
"net/http"
"net/url"
- "os"
"path"
"path/filepath"
"runtime"
"strings"
- "time"
)
-// LoadHTTPTimeout the default timeout for load requests
-var LoadHTTPTimeout = 30 * time.Second
-
-// LoadHTTPBasicAuthUsername the username to use when load requests require basic auth
-var LoadHTTPBasicAuthUsername = ""
-
-// LoadHTTPBasicAuthPassword the password to use when load requests require basic auth
-var LoadHTTPBasicAuthPassword = ""
-
-// LoadHTTPCustomHeaders an optional collection of custom HTTP headers for load requests
-var LoadHTTPCustomHeaders = map[string]string{}
-
// LoadFromFileOrHTTP loads the bytes from a file or a remote http server based on the path passed in
-func LoadFromFileOrHTTP(pth string) ([]byte, error) {
- return LoadStrategy(pth, os.ReadFile, loadHTTPBytes(LoadHTTPTimeout))(pth)
-}
-
-// LoadFromFileOrHTTPWithTimeout loads the bytes from a file or a remote http server based on the path passed in
-// timeout arg allows for per request overriding of the request timeout
-func LoadFromFileOrHTTPWithTimeout(pth string, timeout time.Duration) ([]byte, error) {
- return LoadStrategy(pth, os.ReadFile, loadHTTPBytes(timeout))(pth)
+func LoadFromFileOrHTTP(pth string, opts ...Option) ([]byte, error) {
+ o := optionsWithDefaults(opts)
+ return LoadStrategy(pth, o.ReadFileFunc(), loadHTTPBytes(opts...), opts...)(pth)
}
// LoadStrategy returns a loader function for a given path or URI.
@@ -81,10 +53,12 @@ func LoadFromFileOrHTTPWithTimeout(pth string, timeout time.Duration) ([]byte, e
// - `file://host/folder/file` becomes an UNC path like `\\host\folder\file` (no port specification is supported)
// - `file:///c:/folder/file` becomes `C:\folder\file`
// - `file://c:/folder/file` is tolerated (without leading `/`) and becomes `c:\folder\file`
-func LoadStrategy(pth string, local, remote func(string) ([]byte, error)) func(string) ([]byte, error) {
+func LoadStrategy(pth string, local, remote func(string) ([]byte, error), opts ...Option) func(string) ([]byte, error) {
if strings.HasPrefix(pth, "http") {
return remote
}
+ o := optionsWithDefaults(opts)
+ _, isEmbedFS := o.fs.(embed.FS)
return func(p string) ([]byte, error) {
upth, err := url.PathUnescape(p)
@@ -92,19 +66,19 @@ func LoadStrategy(pth string, local, remote func(string) ([]byte, error)) func(s
return nil, err
}
- if !strings.HasPrefix(p, `file://`) {
+ cpth, hasPrefix := strings.CutPrefix(upth, "file://")
+ if !hasPrefix || isEmbedFS || runtime.GOOS != "windows" {
+ // crude processing: trim the file:// prefix. This leaves full URIs with a host with a (mostly) unexpected result
// regular file path provided: just normalize slashes
- return local(filepath.FromSlash(upth))
- }
-
- if runtime.GOOS != "windows" {
- // crude processing: this leaves full URIs with a host with a (mostly) unexpected result
- upth = strings.TrimPrefix(upth, `file://`)
+ if isEmbedFS {
+ // on windows, we need to slash the path if FS is an embed FS.
+ return local(strings.TrimLeft(filepath.ToSlash(cpth), "./")) // remove invalid leading characters for embed FS
+ }
- return local(filepath.FromSlash(upth))
+ return local(filepath.FromSlash(cpth))
}
- // windows-only pre-processing of file://... URIs
+ // windows-only pre-processing of file://... URIs, excluding embed.FS
// support for canonical file URIs on windows.
u, err := url.Parse(filepath.ToSlash(upth))
@@ -139,19 +113,29 @@ func LoadStrategy(pth string, local, remote func(string) ([]byte, error)) func(s
}
}
-func loadHTTPBytes(timeout time.Duration) func(path string) ([]byte, error) {
+func loadHTTPBytes(opts ...Option) func(path string) ([]byte, error) {
+ o := optionsWithDefaults(opts)
+
return func(path string) ([]byte, error) {
- client := &http.Client{Timeout: timeout}
- req, err := http.NewRequest(http.MethodGet, path, nil) //nolint:noctx
+ client := o.client
+ timeoutCtx := context.Background()
+ var cancel func()
+
+ if o.httpTimeout > 0 {
+ timeoutCtx, cancel = context.WithTimeout(timeoutCtx, o.httpTimeout)
+ defer cancel()
+ }
+
+ req, err := http.NewRequestWithContext(timeoutCtx, http.MethodGet, path, nil)
if err != nil {
return nil, err
}
- if LoadHTTPBasicAuthUsername != "" && LoadHTTPBasicAuthPassword != "" {
- req.SetBasicAuth(LoadHTTPBasicAuthUsername, LoadHTTPBasicAuthPassword)
+ if o.basicAuthUsername != "" && o.basicAuthPassword != "" {
+ req.SetBasicAuth(o.basicAuthUsername, o.basicAuthPassword)
}
- for key, val := range LoadHTTPCustomHeaders {
+ for key, val := range o.customHeaders {
req.Header.Set(key, val)
}
diff --git a/vendor/github.com/go-openapi/swag/loading/options.go b/vendor/github.com/go-openapi/swag/loading/options.go
new file mode 100644
index 0000000000..6674ac69e6
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/loading/options.go
@@ -0,0 +1,125 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package loading
+
+import (
+ "io/fs"
+ "net/http"
+ "os"
+ "time"
+)
+
+type (
+ // Option provides options for loading a file over HTTP or from a file.
+ Option func(*options)
+
+ httpOptions struct {
+ httpTimeout time.Duration
+ basicAuthUsername string
+ basicAuthPassword string
+ customHeaders map[string]string
+ client *http.Client
+ }
+
+ fileOptions struct {
+ fs fs.ReadFileFS
+ }
+
+ options struct {
+ httpOptions
+ fileOptions
+ }
+)
+
+func (fo fileOptions) ReadFileFunc() func(string) ([]byte, error) {
+ if fo.fs == nil {
+ return os.ReadFile
+ }
+
+ return fo.fs.ReadFile
+}
+
+// WithTimeout sets a timeout for the remote file loader.
+//
+// The default timeout is 30s.
+func WithTimeout(timeout time.Duration) Option {
+ return func(o *options) {
+ o.httpTimeout = timeout
+ }
+}
+
+// WithBasicAuth sets a basic authentication scheme for the remote file loader.
+func WithBasicAuth(username, password string) Option {
+ return func(o *options) {
+ o.basicAuthUsername = username
+ o.basicAuthPassword = password
+ }
+}
+
+// WithCustomHeaders sets custom headers for the remote file loader.
+func WithCustomHeaders(headers map[string]string) Option {
+ return func(o *options) {
+ if o.customHeaders == nil {
+ o.customHeaders = make(map[string]string, len(headers))
+ }
+
+ for header, value := range headers {
+ o.customHeaders[header] = value
+ }
+ }
+}
+
+// WithHTTPClient overrides the default HTTP client used to fetch a remote file.
+//
+// By default, [http.DefaultClient] is used.
+func WithHTTPClient(client *http.Client) Option {
+ return func(o *options) {
+ o.client = client
+ }
+}
+
+// WithFS sets a file system for the local file loader.
+//
+// If the provided file system is a [fs.ReadFileFS], the ReadFile function is used.
+// Otherwise, ReadFile is wrapped using [fs.ReadFile].
+//
+// By default, the file system is the one provided by the os package.
+//
+// For example, this may be set to consume from an embedded file system, or a rooted FS.
+func WithFS(filesystem fs.FS) Option {
+ return func(o *options) {
+ if rfs, ok := filesystem.(fs.ReadFileFS); ok {
+ o.fs = rfs
+
+ return
+ }
+ o.fs = readFileFS{FS: filesystem}
+ }
+}
+
+type readFileFS struct {
+ fs.FS
+}
+
+func (r readFileFS) ReadFile(name string) ([]byte, error) {
+ return fs.ReadFile(r.FS, name)
+}
+
+func optionsWithDefaults(opts []Option) options {
+ const defaultTimeout = 30 * time.Second
+
+ o := options{
+ // package level defaults
+ httpOptions: httpOptions{
+ httpTimeout: defaultTimeout,
+ client: http.DefaultClient,
+ },
+ }
+
+ for _, apply := range opts {
+ apply(&o)
+ }
+
+ return o
+}
diff --git a/vendor/github.com/go-openapi/swag/loading/yaml.go b/vendor/github.com/go-openapi/swag/loading/yaml.go
new file mode 100644
index 0000000000..3ebb53668c
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/loading/yaml.go
@@ -0,0 +1,37 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package loading
+
+import (
+ "encoding/json"
+ "path/filepath"
+
+ "github.com/go-openapi/swag/yamlutils"
+)
+
+// YAMLMatcher matches yaml for a file loader.
+func YAMLMatcher(path string) bool {
+ ext := filepath.Ext(path)
+ return ext == ".yaml" || ext == ".yml"
+}
+
+// YAMLDoc loads a yaml document from either http or a file and converts it to json.
+func YAMLDoc(path string, opts ...Option) (json.RawMessage, error) {
+ yamlDoc, err := YAMLData(path, opts...)
+ if err != nil {
+ return nil, err
+ }
+
+ return yamlutils.YAMLToJSON(yamlDoc)
+}
+
+// YAMLData loads a yaml document from either http or a file.
+func YAMLData(path string, opts ...Option) (any, error) {
+ data, err := LoadFromFileOrHTTP(path, opts...)
+ if err != nil {
+ return nil, err
+ }
+
+ return yamlutils.BytesToYAMLDoc(data)
+}
diff --git a/vendor/github.com/go-openapi/swag/loading_iface.go b/vendor/github.com/go-openapi/swag/loading_iface.go
new file mode 100644
index 0000000000..27ec3fb8c3
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/loading_iface.go
@@ -0,0 +1,91 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package swag
+
+import (
+ "encoding/json"
+ "time"
+
+ "github.com/go-openapi/swag/loading"
+)
+
+var (
+ // Package-level defaults for the file loading utilities (deprecated).
+
+ // LoadHTTPTimeout the default timeout for load requests.
+ //
+ // Deprecated: use [loading.WithTimeout] instead.
+ LoadHTTPTimeout = 30 * time.Second
+
+ // LoadHTTPBasicAuthUsername the username to use when load requests require basic auth.
+ //
+ // Deprecated: use [loading.WithBasicAuth] instead.
+ LoadHTTPBasicAuthUsername = ""
+
+ // LoadHTTPBasicAuthPassword the password to use when load requests require basic auth.
+ //
+ // Deprecated: use [loading.WithBasicAuth] instead.
+ LoadHTTPBasicAuthPassword = ""
+
+ // LoadHTTPCustomHeaders an optional collection of custom HTTP headers for load requests.
+ //
+ // Deprecated: use [loading.WithCustomHeaders] instead.
+ LoadHTTPCustomHeaders = map[string]string{}
+)
+
+// LoadFromFileOrHTTP loads the bytes from a file or a remote http server based on the provided path.
+//
+// Deprecated: use [loading.LoadFromFileOrHTTP] instead.
+func LoadFromFileOrHTTP(pth string, opts ...loading.Option) ([]byte, error) {
+ return loading.LoadFromFileOrHTTP(pth, loadingOptionsWithDefaults(opts)...)
+}
+
+// LoadFromFileOrHTTPWithTimeout loads the bytes from a file or a remote http server based on the path passed in
+// timeout arg allows for per request overriding of the request timeout.
+//
+// Deprecated: use [loading.LoadFileOrHTTP] with the [loading.WithTimeout] option instead.
+func LoadFromFileOrHTTPWithTimeout(pth string, timeout time.Duration, opts ...loading.Option) ([]byte, error) {
+ opts = append(opts, loading.WithTimeout(timeout))
+
+ return LoadFromFileOrHTTP(pth, opts...)
+}
+
+// LoadStrategy returns a loader function for a given path or URL.
+//
+// Deprecated: use [loading.LoadStrategy] instead.
+func LoadStrategy(pth string, local, remote func(string) ([]byte, error), opts ...loading.Option) func(string) ([]byte, error) {
+ return loading.LoadStrategy(pth, local, remote, loadingOptionsWithDefaults(opts)...)
+}
+
+// YAMLMatcher matches yaml for a file loader.
+//
+// Deprecated: use [loading.YAMLMatcher] instead.
+func YAMLMatcher(path string) bool { return loading.YAMLMatcher(path) }
+
+// YAMLDoc loads a yaml document from either http or a file and converts it to json.
+//
+// Deprecated: use [loading.YAMLDoc] instead.
+func YAMLDoc(path string) (json.RawMessage, error) {
+ return loading.YAMLDoc(path)
+}
+
+// YAMLData loads a yaml document from either http or a file.
+//
+// Deprecated: use [loading.YAMLData] instead.
+func YAMLData(path string) (any, error) {
+ return loading.YAMLData(path)
+}
+
+// loadingOptionsWithDefaults bridges deprecated default settings that use package-level variables,
+// with the recommended use of loading.Option.
+func loadingOptionsWithDefaults(opts []loading.Option) []loading.Option {
+ o := []loading.Option{
+ loading.WithTimeout(LoadHTTPTimeout),
+ loading.WithBasicAuth(LoadHTTPBasicAuthUsername, LoadHTTPBasicAuthPassword),
+ loading.WithCustomHeaders(LoadHTTPCustomHeaders),
+ }
+ o = append(o, opts...)
+
+ return o
+}
diff --git a/vendor/github.com/go-openapi/swag/BENCHMARK.md b/vendor/github.com/go-openapi/swag/mangling/BENCHMARK.md
similarity index 53%
rename from vendor/github.com/go-openapi/swag/BENCHMARK.md
rename to vendor/github.com/go-openapi/swag/mangling/BENCHMARK.md
index e7f28ed6b7..6674c63b72 100644
--- a/vendor/github.com/go-openapi/swag/BENCHMARK.md
+++ b/vendor/github.com/go-openapi/swag/mangling/BENCHMARK.md
@@ -1,12 +1,10 @@
-# Benchmarks
-
-## Name mangling utilities
+# Benchmarking name mangling utilities
```bash
go test -bench XXX -run XXX -benchtime 30s
```
-### Benchmarks at b3e7a5386f996177e4808f11acb2aa93a0f660df
+## Benchmarks at b3e7a5386f996177e4808f11acb2aa93a0f660df
```
goos: linux
@@ -21,7 +19,7 @@ BenchmarkToXXXName/ToHumanNameLower-4 895334 40354 ns/op 10472 B/op
BenchmarkToXXXName/ToHumanNameTitle-4 882441 40678 ns/op 10566 B/op 749 allocs/op
```
-### Benchmarks after PR #79
+## Benchmarks after PR #79
~ x10 performance improvement and ~ /100 memory allocations.
@@ -50,3 +48,43 @@ BenchmarkToXXXName/ToCommandName-16 32256634 1137 ns/op 147 B/op
BenchmarkToXXXName/ToHumanNameLower-16 18599661 1946 ns/op 92 B/op 6 allocs/op
BenchmarkToXXXName/ToHumanNameTitle-16 17581353 2054 ns/op 105 B/op 6 allocs/op
```
+
+## Benchmarks at d7d2d1b895f5b6747afaff312dd2a402e69e818b
+
+go1.24
+
+```
+goos: linux
+goarch: amd64
+pkg: github.com/go-openapi/swag
+cpu: AMD Ryzen 7 5800X 8-Core Processor
+BenchmarkToXXXName/ToGoName-16 19757858 1881 ns/op 42 B/op 5 allocs/op
+BenchmarkToXXXName/ToVarName-16 17494111 2094 ns/op 74 B/op 7 allocs/op
+BenchmarkToXXXName/ToFileName-16 28161226 1492 ns/op 158 B/op 7 allocs/op
+BenchmarkToXXXName/ToCommandName-16 23787333 1489 ns/op 158 B/op 7 allocs/op
+BenchmarkToXXXName/ToHumanNameLower-16 17537257 2030 ns/op 103 B/op 6 allocs/op
+BenchmarkToXXXName/ToHumanNameTitle-16 16977453 2156 ns/op 105 B/op 6 allocs/op
+```
+
+## Benchmarks after PR #106
+
+Moving the scope of everything down to a struct allowed to reduce a bit garbage and pooling.
+
+On top of that, ToGoName (and thus ToVarName) have been subject to a minor optimization, removing a few allocations.
+
+Overall timings improve by ~ -10%.
+
+go1.24
+
+```
+goos: linux
+goarch: amd64
+pkg: github.com/go-openapi/swag/mangling
+cpu: AMD Ryzen 7 5800X 8-Core Processor
+BenchmarkToXXXName/ToGoName-16 22496130 1618 ns/op 31 B/op 3 allocs/op
+BenchmarkToXXXName/ToVarName-16 22538068 1618 ns/op 33 B/op 3 allocs/op
+BenchmarkToXXXName/ToFileName-16 27722977 1236 ns/op 105 B/op 6 allocs/op
+BenchmarkToXXXName/ToCommandName-16 27967395 1258 ns/op 105 B/op 6 allocs/op
+BenchmarkToXXXName/ToHumanNameLower-16 18587901 1917 ns/op 103 B/op 6 allocs/op
+BenchmarkToXXXName/ToHumanNameTitle-16 17193208 2019 ns/op 108 B/op 7 allocs/op
+```
diff --git a/vendor/github.com/go-openapi/swag/mangling/LICENSE b/vendor/github.com/go-openapi/swag/mangling/LICENSE
new file mode 100644
index 0000000000..d645695673
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/mangling/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/vendor/github.com/go-openapi/swag/mangling/doc.go b/vendor/github.com/go-openapi/swag/mangling/doc.go
new file mode 100644
index 0000000000..ce0d890485
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/mangling/doc.go
@@ -0,0 +1,25 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+// Package mangling provides name mangling capabilities.
+//
+// Name mangling is an important stage when generating code:
+// it helps construct safe program identifiers that abide by the language rules
+// and play along with linters.
+//
+// Examples:
+//
+// Suppose we get an object name taken from an API spec: "json_object",
+//
+// We may generate a legit go type name using [NameMangler.ToGoName]: "JsonObject".
+//
+// We may then locate this type in a source file named using [NameMangler.ToFileName]: "json_object.go".
+//
+// The methods exposed by the NameMangler are used to generate code in many different contexts, such as:
+//
+// - generating exported or unexported go identifiers from a JSON schema or an API spec
+// - generating file names
+// - generating human-readable comments for types and variables
+// - generating JSON-like API identifiers from go code
+// - ...
+package mangling
diff --git a/vendor/github.com/go-openapi/swag/mangling/initialism_index.go b/vendor/github.com/go-openapi/swag/mangling/initialism_index.go
new file mode 100644
index 0000000000..e5b70c1493
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/mangling/initialism_index.go
@@ -0,0 +1,270 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package mangling
+
+import (
+ "sort"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+// DefaultInitialisms returns all the initialisms configured by default for this package.
+//
+// # Motivation
+//
+// Common initialisms are acronyms for which the ordinary camel-casing rules are altered and
+// for which we retain the original case.
+//
+// This is largely specific to the go naming conventions enforced by golint (now revive).
+//
+// # Example
+//
+// In go, "id" is a good-looking identifier, but "Id" is not and "ID" is preferred
+// (notice that this stems only from conventions: the go compiler accepts all of these).
+//
+// Similarly, we may use "http", but not "Http". In this case, "HTTP" is preferred.
+//
+// # Reference and customization
+//
+// The default list of these casing-style exceptions is taken from the [github.com/mgechev/revive] linter for go:
+// https://github.com/mgechev/revive/blob/master/lint/name.go#L93
+//
+// There are a few additions to the original list, such as IPv4, IPv6 and OAI ("OpenAPI").
+//
+// For these additions, "IPv4" would be preferred to "Ipv4" or "IPV4", and "OAI" to "Oai"
+//
+// You may redefine this list entirely using the mangler option [WithInitialisms], or simply add extra definitions
+// using [WithAdditionalInitialisms].
+//
+// # Mixed-case and plurals
+//
+// Notice that initialisms are not necessarily fully upper-cased: a mixed-case initialism indicates the preferred casing.
+//
+// Obviously, lower-case only initialisms do not make a lot of sense: if lower-case only initialisms are added,
+// they will be considered fully capitalized.
+//
+// Plural forms use mixed case like "IDs". And so do values like "IPv4" or "IPv6".
+//
+// The [NameMangler] automatically detects simple plurals for words such as "IDs" or "APIs",
+// so you don't need to configure these variants.
+//
+// At this moment, it doesn't support pluralization of terms that ends with an 's' (or 'S'), since there is
+// no clear consensus on whether a word like DNS should be pluralized as DNSes or remain invariant.
+// The [NameMangler] consider those invariant. Therefore DNSs or DNSes are not recognized as plurals for DNS.
+//
+// Besids, we don't want to support pluralization of terms which would otherwise conflict with another one,
+// like "HTTPs" vs "HTTPS". All these should be considered invariant. Hence: "Https" matches "HTTPS" and
+// "HTTPSS" is "HTTPS" followed by "S".
+func DefaultInitialisms() []string {
+ return []string{
+ "ACL",
+ "API",
+ "ASCII",
+ "CPU",
+ "CSS",
+ "DNS",
+ "EOF",
+ "GUID",
+ "HTML",
+ "HTTPS",
+ "HTTP",
+ "ID",
+ "IP",
+ "IPv4", // prefer the mixed case outcome IPv4 over the capitalized IPV4
+ "IPv6", // prefer the mixed case outcome IPv6 over the capitalized IPV6
+ "JSON",
+ "LHS",
+ "OAI",
+ "QPS",
+ "RAM",
+ "RHS",
+ "RPC",
+ "SLA",
+ "SMTP",
+ "SQL",
+ "SSH",
+ "TCP",
+ "TLS",
+ "TTL",
+ "UDP",
+ "UI",
+ "UID",
+ "UUID",
+ "URI",
+ "URL",
+ "UTF8",
+ "VM",
+ "XML",
+ "XMPP",
+ "XSRF",
+ "XSS",
+ }
+}
+
+type indexOfInitialisms struct {
+ initialismsCache
+
+ index map[string]struct{}
+}
+
+func newIndexOfInitialisms() *indexOfInitialisms {
+ return &indexOfInitialisms{
+ index: make(map[string]struct{}),
+ }
+}
+
+func (m *indexOfInitialisms) add(words ...string) *indexOfInitialisms {
+ for _, word := range words {
+ // sanitization of injected words: trimmed from blanks, and must start with a letter
+ trimmed := strings.TrimSpace(word)
+
+ firstRune, _ := utf8.DecodeRuneInString(trimmed)
+ if !unicode.IsLetter(firstRune) {
+ continue
+ }
+
+ // Initialisms are case-sensitive. This means that we support mixed-case words.
+ // However, if specified as a lower-case string, the initialism should be fully capitalized.
+ if trimmed == strings.ToLower(trimmed) {
+ m.index[strings.ToUpper(trimmed)] = struct{}{}
+
+ continue
+ }
+
+ m.index[trimmed] = struct{}{}
+ }
+ return m
+}
+
+func (m *indexOfInitialisms) sorted() []string {
+ result := make([]string, 0, len(m.index))
+ for k := range m.index {
+ result = append(result, k)
+ }
+ sort.Sort(sort.Reverse(byInitialism(result)))
+ return result
+}
+
+func (m *indexOfInitialisms) buildCache() {
+ m.build(m.sorted(), m.pluralForm)
+}
+
+// initialismsCache caches all needed pre-computed and converted initialism entries,
+// in the desired resolution order.
+type initialismsCache struct {
+ initialisms []string
+ initialismsRunes [][]rune
+ initialismsUpperCased [][]rune // initialisms cached in their trimmed, upper-cased version
+ initialismsPluralForm []pluralForm
+}
+
+func (c *initialismsCache) build(in []string, pluralfunc func(string) pluralForm) {
+ c.initialisms = in
+ c.initialismsRunes = asRunes(c.initialisms)
+ c.initialismsUpperCased = asUpperCased(c.initialisms)
+ c.initialismsPluralForm = asPluralForms(c.initialisms, pluralfunc)
+}
+
+// pluralForm denotes the kind of pluralization to be used for initialisms.
+//
+// At this moment, initialisms are either invariant or follow a simple plural form with an
+// extra (lower case) "s".
+type pluralForm uint8
+
+const (
+ notPlural pluralForm = iota
+ invariantPlural
+ simplePlural
+)
+
+func (f pluralForm) String() string {
+ switch f {
+ case notPlural:
+ return "notPlural"
+ case invariantPlural:
+ return "invariantPlural"
+ case simplePlural:
+ return "simplePlural"
+ default:
+ return ""
+ }
+}
+
+// pluralForm indicates how we want to pluralize a given initialism.
+//
+// Besides configured invariant forms (like HTTP and HTTPS),
+// an initialism is normally pluralized by adding a single 's', like in IDs.
+//
+// Initialisms ending with an 'S' or an 's' are configured as invariant (we don't
+// support plural forms like CSSes or DNSes, however the mechanism could be extended to
+// do just that).
+func (m *indexOfInitialisms) pluralForm(key string) pluralForm {
+ if _, ok := m.index[key]; !ok {
+ return notPlural
+ }
+
+ if strings.HasSuffix(strings.ToUpper(key), "S") {
+ return invariantPlural
+ }
+
+ if _, ok := m.index[key+"s"]; ok {
+ return invariantPlural
+ }
+
+ if _, ok := m.index[key+"S"]; ok {
+ return invariantPlural
+ }
+
+ return simplePlural
+}
+
+type byInitialism []string
+
+func (s byInitialism) Len() int {
+ return len(s)
+}
+func (s byInitialism) Swap(i, j int) {
+ s[i], s[j] = s[j], s[i]
+}
+
+// Less specifies the order in which initialisms are prioritized:
+// 1. match longest first
+// 2. when equal length, match in reverse lexicographical order, lower case match comes first
+func (s byInitialism) Less(i, j int) bool {
+ if len(s[i]) != len(s[j]) {
+ return len(s[i]) < len(s[j])
+ }
+
+ return s[i] < s[j]
+}
+
+func asRunes(in []string) [][]rune {
+ out := make([][]rune, len(in))
+ for i, initialism := range in {
+ out[i] = []rune(initialism)
+ }
+
+ return out
+}
+
+func asUpperCased(in []string) [][]rune {
+ out := make([][]rune, len(in))
+
+ for i, initialism := range in {
+ out[i] = []rune(upper(trim(initialism)))
+ }
+
+ return out
+}
+
+// asPluralForms bakes an index of pluralization support.
+func asPluralForms(in []string, pluralFunc func(string) pluralForm) []pluralForm {
+ out := make([]pluralForm, len(in))
+ for i, initialism := range in {
+ out[i] = pluralFunc(initialism)
+ }
+
+ return out
+}
diff --git a/vendor/github.com/go-openapi/swag/mangling/name_lexem.go b/vendor/github.com/go-openapi/swag/mangling/name_lexem.go
new file mode 100644
index 0000000000..bc837e3b9f
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/mangling/name_lexem.go
@@ -0,0 +1,186 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package mangling
+
+import (
+ "bytes"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+type (
+ lexemKind uint8
+
+ nameLexem struct {
+ original string
+ matchedInitialism string
+ kind lexemKind
+ }
+)
+
+const (
+ lexemKindCasualName lexemKind = iota
+ lexemKindInitialismName
+)
+
+func newInitialismNameLexem(original, matchedInitialism string) nameLexem {
+ return nameLexem{
+ kind: lexemKindInitialismName,
+ original: original,
+ matchedInitialism: matchedInitialism,
+ }
+}
+
+func newCasualNameLexem(original string) nameLexem {
+ return nameLexem{
+ kind: lexemKindCasualName,
+ original: trim(original), // TODO: save on calls to trim
+ }
+}
+
+// WriteTitleized writes the titleized lexeme to a bytes.Buffer.
+//
+// If the first letter cannot be capitalized, it doesn't write anything and return false,
+// so the caller may attempt some workaround strategy.
+func (l nameLexem) WriteTitleized(w *bytes.Buffer, alwaysUpper bool) bool {
+ if l.kind == lexemKindInitialismName {
+ w.WriteString(l.matchedInitialism)
+
+ return true
+ }
+
+ if len(l.original) == 0 {
+ return true
+ }
+
+ if len(l.original) == 1 {
+ // identifier is too short: casing will depend on the context
+ firstByte := l.original[0]
+ switch {
+ case 'A' <= firstByte && firstByte <= 'Z':
+ // safe
+ w.WriteByte(firstByte)
+
+ return true
+ case alwaysUpper && 'a' <= firstByte && firstByte <= 'z':
+ w.WriteByte(firstByte - 'a' + 'A')
+
+ return true
+ default:
+
+ // not a letter: skip and let the caller decide
+ return false
+ }
+ }
+
+ if firstByte := l.original[0]; firstByte < utf8.RuneSelf {
+ // ASCII
+ switch {
+ case 'A' <= firstByte && firstByte <= 'Z':
+ // already an upper case letter
+ w.WriteString(l.original)
+
+ return true
+ case 'a' <= firstByte && firstByte <= 'z':
+ w.WriteByte(firstByte - 'a' + 'A')
+ w.WriteString(l.original[1:])
+
+ return true
+ default:
+ // not a good candidate: doesn't start with a letter
+ return false
+ }
+ }
+
+ // unicode
+ firstRune, idx := utf8.DecodeRuneInString(l.original)
+ if !unicode.IsLetter(firstRune) || !unicode.IsUpper(unicode.ToUpper(firstRune)) {
+ // not a good candidate: doesn't start with a letter
+ // or a rune for which case doesn't make sense (e.g. East-Asian runes etc)
+ return false
+ }
+
+ rest := l.original[idx:]
+ w.WriteRune(unicode.ToUpper(firstRune))
+ w.WriteString(strings.ToLower(rest))
+
+ return true
+}
+
+// WriteLower is like write titleized but it writes a lower-case version of the lexeme.
+//
+// Similarly, there is no writing if the casing of the first rune doesn't make sense.
+func (l nameLexem) WriteLower(w *bytes.Buffer, alwaysLower bool) bool {
+ if l.kind == lexemKindInitialismName {
+ w.WriteString(lower(l.matchedInitialism))
+
+ return true
+ }
+
+ if len(l.original) == 0 {
+ return true
+ }
+
+ if len(l.original) == 1 {
+ // identifier is too short: casing will depend on the context
+ firstByte := l.original[0]
+ switch {
+ case 'a' <= firstByte && firstByte <= 'z':
+ // safe
+ w.WriteByte(firstByte)
+
+ return true
+ case alwaysLower && 'A' <= firstByte && firstByte <= 'Z':
+ w.WriteByte(firstByte - 'A' + 'a')
+
+ return true
+ default:
+
+ // not a letter: skip and let the caller decide
+ return false
+ }
+ }
+
+ if firstByte := l.original[0]; firstByte < utf8.RuneSelf {
+ // ASCII
+ switch {
+ case 'a' <= firstByte && firstByte <= 'z':
+ // already a lower case letter
+ w.WriteString(l.original)
+
+ return true
+ case 'A' <= firstByte && firstByte <= 'Z':
+ w.WriteByte(firstByte - 'A' + 'a')
+ w.WriteString(l.original[1:])
+
+ return true
+ default:
+ // not a good candidate: doesn't start with a letter
+ return false
+ }
+ }
+
+ // unicode
+ firstRune, idx := utf8.DecodeRuneInString(l.original)
+ if !unicode.IsLetter(firstRune) || !unicode.IsLower(unicode.ToLower(firstRune)) {
+ // not a good candidate: doesn't start with a letter
+ // or a rune for which case doesn't make sense (e.g. East-Asian runes etc)
+ return false
+ }
+
+ rest := l.original[idx:]
+ w.WriteRune(unicode.ToLower(firstRune))
+ w.WriteString(rest)
+
+ return true
+}
+
+func (l nameLexem) GetOriginal() string {
+ return l.original
+}
+
+func (l nameLexem) IsInitialism() bool {
+ return l.kind == lexemKindInitialismName
+}
diff --git a/vendor/github.com/go-openapi/swag/mangling/name_mangler.go b/vendor/github.com/go-openapi/swag/mangling/name_mangler.go
new file mode 100644
index 0000000000..da685681d0
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/mangling/name_mangler.go
@@ -0,0 +1,370 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package mangling
+
+import (
+ "strings"
+ "unicode"
+)
+
+// NameMangler knows how to transform sentences or words into
+// identifiers that are a better fit in contexts such as:
+//
+// - unexported or exported go variable identifiers
+// - file names
+// - camel cased identifiers
+// - ...
+//
+// The [NameMangler] is safe for concurrent use, save for its [NameMangler.AddInitialisms] method,
+// which is not.
+//
+// # Known limitations
+//
+// At this moment, the [NameMangler] doesn't play well with "all caps" text:
+//
+// unless every single upper-cased word is declared as an initialism, capitalized words would generally
+// not be transformed with the expected result, e.g.
+//
+// ToFileName("THIS_IS_ALL_CAPS")
+//
+// yields the weird outcome
+//
+// "t_h_i_s_i_s_a_l_l_c_a_p_s"
+type NameMangler struct {
+ options
+
+ index *indexOfInitialisms
+
+ splitter splitter
+ splitterWithPostSplit splitter
+
+ _ struct{}
+}
+
+// NewNameMangler builds a name mangler ready to convert strings.
+//
+// The default name mangler is configured with default common initialisms and all default options.
+func NewNameMangler(opts ...Option) NameMangler {
+ m := NameMangler{
+ options: optionsWithDefaults(opts),
+ index: newIndexOfInitialisms(),
+ }
+ m.addInitialisms(m.commonInitialisms...)
+
+ // a splitter that returns matches lexemes as ready-to-assemble strings:
+ // details of the lexemes are redeemed.
+ m.splitter = newSplitter(
+ withInitialismsCache(&m.index.initialismsCache),
+ withReplaceFunc(m.replaceFunc),
+ )
+
+ // a splitter that returns matches lexemes ready for post-processing
+ m.splitterWithPostSplit = newSplitter(
+ withInitialismsCache(&m.index.initialismsCache),
+ withReplaceFunc(m.replaceFunc),
+ withPostSplitInitialismCheck,
+ )
+
+ return m
+}
+
+// AddInitialisms declares extra initialisms to the mangler.
+//
+// It declares extra words as "initialisms" (i.e. words that won't be camel cased or titled cased),
+// on top of the existing list of common initialisms (such as ID, HTTP...).
+//
+// Added words must start with a (unicode) letter. If some don't, they are ignored.
+// Added words are either fully capitalized or mixed-cased. Lower-case only words are considered capitalized.
+//
+// It is typically used just after initializing the [NameMangler].
+//
+// When all initialisms are known at the time the mangler is initialized, it is preferable to
+// use [NewNameMangler] with the option [WithAdditionalInitialisms].
+//
+// Adding initialisms mutates the mangler and should not be carried out concurrently with other calls to the mangler.
+func (m *NameMangler) AddInitialisms(words ...string) {
+ m.addInitialisms(words...)
+}
+
+// Initialisms renders the list of initialisms supported by this mangler.
+func (m *NameMangler) Initialisms() []string {
+ return m.index.initialisms
+}
+
+// Camelize a single word.
+//
+// Example:
+//
+// - "HELLO" and "hello" become "Hello".
+func (m NameMangler) Camelize(word string) string {
+ ru := []rune(word)
+
+ switch len(ru) {
+ case 0:
+ return ""
+ case 1:
+ return string(unicode.ToUpper(ru[0]))
+ default:
+ camelized := poolOfBuffers.BorrowBuffer(len(word))
+ camelized.Grow(len(word))
+ defer func() {
+ poolOfBuffers.RedeemBuffer(camelized)
+ }()
+
+ camelized.WriteRune(unicode.ToUpper(ru[0]))
+ for _, ru := range ru[1:] {
+ camelized.WriteRune(unicode.ToLower(ru))
+ }
+
+ return camelized.String()
+ }
+}
+
+// ToFileName generates a suitable snake-case file name from a sentence.
+//
+// It lower-cases everything with underscore (_) as a word separator.
+//
+// Examples:
+//
+// - "Hello, Swagger" becomes "hello_swagger"
+// - "HelloSwagger" becomes "hello_swagger"
+func (m NameMangler) ToFileName(name string) string {
+ inptr := m.split(name)
+ in := *inptr
+ out := make([]string, 0, len(in))
+
+ for _, w := range in {
+ out = append(out, lower(w))
+ }
+ poolOfStrings.RedeemStrings(inptr)
+
+ return strings.Join(out, "_")
+}
+
+// ToCommandName generates a suitable CLI command name from a sentence.
+//
+// It lower-cases everything with dash (-) as a word separator.
+//
+// Examples:
+//
+// - "Hello, Swagger" becomes "hello-swagger"
+// - "HelloSwagger" becomes "hello-swagger"
+func (m NameMangler) ToCommandName(name string) string {
+ inptr := m.split(name)
+ in := *inptr
+ out := make([]string, 0, len(in))
+
+ for _, w := range in {
+ out = append(out, lower(w))
+ }
+ poolOfStrings.RedeemStrings(inptr)
+
+ return strings.Join(out, "-")
+}
+
+// ToHumanNameLower represents a code name as a human-readable series of words.
+//
+// It lower-cases everything with blank space as a word separator.
+//
+// NOTE: parts recognized as initialisms just keep their original casing.
+//
+// Examples:
+//
+// - "Hello, Swagger" becomes "hello swagger"
+// - "HelloSwagger" or "Hello-Swagger" become "hello swagger"
+func (m NameMangler) ToHumanNameLower(name string) string {
+ s := m.splitterWithPostSplit
+ in := s.split(name)
+ out := make([]string, 0, len(*in))
+
+ for _, w := range *in {
+ if !w.IsInitialism() {
+ out = append(out, lower(w.GetOriginal()))
+ } else {
+ out = append(out, trim(w.GetOriginal()))
+ }
+ }
+
+ poolOfLexems.RedeemLexems(in)
+
+ return strings.Join(out, " ")
+}
+
+// ToHumanNameTitle represents a code name as a human-readable series of titleized words.
+//
+// It titleizes every word with blank space as a word separator.
+//
+// Examples:
+//
+// - "hello, Swagger" becomes "Hello Swagger"
+// - "helloSwagger" becomes "Hello Swagger"
+func (m NameMangler) ToHumanNameTitle(name string) string {
+ s := m.splitterWithPostSplit
+ in := s.split(name)
+
+ out := make([]string, 0, len(*in))
+ for _, w := range *in {
+ original := trim(w.GetOriginal())
+ if !w.IsInitialism() {
+ out = append(out, m.Camelize(original))
+ } else {
+ out = append(out, original)
+ }
+ }
+ poolOfLexems.RedeemLexems(in)
+
+ return strings.Join(out, " ")
+}
+
+// ToJSONName generates a camelized single-word version of a sentence.
+//
+// The output assembles every camelized word, but for the first word, which
+// is lower-cased.
+//
+// Example:
+//
+// - "Hello_swagger" becomes "helloSwagger"
+func (m NameMangler) ToJSONName(name string) string {
+ inptr := m.split(name)
+ in := *inptr
+ out := make([]string, 0, len(in))
+
+ for i, w := range in {
+ if i == 0 {
+ out = append(out, lower(w))
+ continue
+ }
+ out = append(out, m.Camelize(trim(w)))
+ }
+
+ poolOfStrings.RedeemStrings(inptr)
+
+ return strings.Join(out, "")
+}
+
+// ToVarName generates a legit unexported go variable name from a sentence.
+//
+// The generated name plays well with linters (see also [NameMangler.ToGoName]).
+//
+// Examples:
+//
+// - "Hello_swagger" becomes "helloSwagger"
+// - "Http_server" becomes "httpServer"
+//
+// This name applies the same rules as [NameMangler.ToGoName] (legit exported variable), save the
+// capitalization of the initial rune.
+//
+// Special case: when the initial part is a recognized as an initialism (like in the example above),
+// the full part is lower-cased.
+func (m NameMangler) ToVarName(name string) string {
+ return m.goIdentifier(name, false)
+}
+
+// ToGoName generates a legit exported go variable name from a sentence.
+//
+// The generated name plays well with most linters.
+//
+// ToGoName abides by the go "exported" symbol rule starting with an upper-case letter.
+//
+// Examples:
+//
+// - "hello_swagger" becomes "HelloSwagger"
+// - "Http_server" becomes "HTTPServer"
+//
+// # Edge cases
+//
+// Whenever the first rune is not eligible to upper case, a special prefix is prepended to the resulting name.
+// By default this is simply "X" and you may customize this behavior using the [WithGoNamePrefixFunc] option.
+//
+// This happens when the first rune is not a letter, e.g. a digit, or a symbol that has no word transliteration
+// (see also [WithReplaceFunc] about symbol transliterations),
+// as well as for most East Asian or Devanagari runes, for which there is no such concept as upper-case.
+//
+// # Linting
+//
+// [revive], the successor of golint is the reference linter.
+//
+// This means that [NameMangler.ToGoName] supports the initialisms that revive checks (see also [DefaultInitialisms]).
+//
+// At this moment, there is no attempt to transliterate unicode into ascii, meaning that some linters
+// (e.g. asciicheck, gosmopolitan) may croak on go identifiers generated from unicode input.
+//
+// [revive]: https://github.com/mgechev/revive
+func (m NameMangler) ToGoName(name string) string {
+ return m.goIdentifier(name, true)
+}
+
+func (m NameMangler) goIdentifier(name string, exported bool) string {
+ s := m.splitterWithPostSplit
+ lexems := s.split(name)
+ defer func() {
+ poolOfLexems.RedeemLexems(lexems)
+ }()
+ lexemes := *lexems
+
+ if len(lexemes) == 0 {
+ return ""
+ }
+
+ result := poolOfBuffers.BorrowBuffer(len(name))
+ defer func() {
+ poolOfBuffers.RedeemBuffer(result)
+ }()
+
+ firstPart := lexemes[0]
+ if !exported {
+ if ok := firstPart.WriteLower(result, true); !ok {
+ // NOTE: an initialism as the first part is lower-cased: no longer generates stuff like hTTPxyz.
+ //
+ // same prefixing rule applied to unexported variable as to an exported one, so that we have consistent
+ // names, whether the generated identifier is exported or not.
+ result.WriteString(strings.ToLower(m.prefixFunc()(name)))
+ result.WriteString(lexemes[0].GetOriginal())
+ }
+ } else {
+ if ok := firstPart.WriteTitleized(result, true); !ok {
+ // "repairs" a lexeme that doesn't start with a letter to become
+ // the start a legit go name. The current strategy is very crude and simply adds a fixed prefix,
+ // e.g. "X".
+ // For instance "1_sesame_street" would be split into lexemes ["1", "sesame", "street"] and
+ // the first one ("1") would result in something like "X1" (with the default prefix function).
+ //
+ // NOTE: no longer forcing the first part to be fully upper-cased
+ result.WriteString(m.prefixFunc()(name))
+ result.WriteString(lexemes[0].GetOriginal())
+ }
+ }
+
+ for _, lexem := range lexemes[1:] {
+ // NOTE: no longer forcing initialism parts to be fully upper-cased:
+ // * pluralized initialism preserve their trailing "s"
+ // * mixed-cased initialisms, such as IPv4, are preserved
+ if ok := lexem.WriteTitleized(result, false); !ok {
+ // it's not titleized: perhaps it's too short, perhaps the first rune is not a letter.
+ // write anyway
+ result.WriteString(lexem.GetOriginal())
+ }
+ }
+
+ return result.String()
+}
+
+func (m *NameMangler) addInitialisms(words ...string) {
+ m.index.add(words...)
+ m.index.buildCache()
+}
+
+// split calls the inner splitter.
+func (m NameMangler) split(str string) *[]string {
+ s := m.splitter
+ lexems := s.split(str)
+ result := poolOfStrings.BorrowStrings()
+
+ for _, lexem := range *lexems {
+ *result = append(*result, lexem.GetOriginal())
+ }
+ poolOfLexems.RedeemLexems(lexems)
+
+ return result
+}
diff --git a/vendor/github.com/go-openapi/swag/mangling/options.go b/vendor/github.com/go-openapi/swag/mangling/options.go
new file mode 100644
index 0000000000..3c92b2f18b
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/mangling/options.go
@@ -0,0 +1,150 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package mangling
+
+type (
+ // PrefixFunc defines a safeguard rule (that may depend on the input string), to prefix
+ // a generated go name (in [NameMangler.ToGoName] and [NameMangler.ToVarName]).
+ //
+ // See [NameMangler.ToGoName] for more about which edge cases the prefix function covers.
+ PrefixFunc func(string) string
+
+ // ReplaceFunc is a transliteration function to replace special runes by a word.
+ ReplaceFunc func(r rune) (string, bool)
+
+ // Option to configure a [NameMangler].
+ Option func(*options)
+
+ options struct {
+ commonInitialisms []string
+
+ goNamePrefixFunc PrefixFunc
+ goNamePrefixFuncPtr *PrefixFunc
+ replaceFunc func(r rune) (string, bool)
+ }
+)
+
+func (o *options) prefixFunc() PrefixFunc {
+ if o.goNamePrefixFuncPtr != nil && *o.goNamePrefixFuncPtr != nil {
+ return *o.goNamePrefixFuncPtr
+ }
+
+ return o.goNamePrefixFunc
+}
+
+// WithGoNamePrefixFunc overrides the default prefix rule to safeguard generated go names.
+//
+// Example:
+//
+// This helps convert "123" into "{prefix}123" (a very crude strategy indeed, but it works).
+//
+// See [github.com/go-swagger/go-swagger/generator.DefaultFuncMap] for an example.
+//
+// The prefix function is assumed to return a string that starts with an upper case letter.
+//
+// The default is to prefix with "X".
+//
+// See [NameMangler.ToGoName] for more about which edge cases the prefix function covers.
+func WithGoNamePrefixFunc(fn PrefixFunc) Option {
+ return func(o *options) {
+ o.goNamePrefixFunc = fn
+ }
+}
+
+// WithGoNamePrefixFuncPtr is like [WithGoNamePrefixFunc] but it specifies a pointer to a function.
+//
+// [WithGoNamePrefixFunc] should be preferred in most situations. This option should only serve the
+// purpose of handling special situations where the prefix function is not an internal variable
+// (e.g. an exported package global).
+//
+// [WithGoNamePrefixFuncPtr] supersedes [WithGoNamePrefixFunc] if it also specified.
+//
+// If the provided pointer is nil or points to a nil value, this option has no effect.
+//
+// The caller should ensure that no undesirable concurrent changes are applied to the function pointed to.
+func WithGoNamePrefixFuncPtr(ptr *PrefixFunc) Option {
+ return func(o *options) {
+ o.goNamePrefixFuncPtr = ptr
+ }
+}
+
+// WithInitialisms declares the initialisms this mangler supports.
+//
+// This supersedes any pre-loaded defaults (see [DefaultInitialisms] for more about what initialisms are).
+//
+// It declares words to be recognized as "initialisms" (i.e. words that won't be camel cased or titled cased).
+//
+// Words must start with a (unicode) letter. If some don't, they are ignored.
+// Words are either fully capitalized or mixed-cased. Lower-case only words are considered capitalized.
+func WithInitialisms(words ...string) Option {
+ return func(o *options) {
+ o.commonInitialisms = words
+ }
+}
+
+// WithAdditionalInitialisms adds new initialisms to the currently supported list (see [DefaultInitialisms]).
+//
+// The same sanitization rules apply as those described for [WithInitialisms].
+func WithAdditionalInitialisms(words ...string) Option {
+ return func(o *options) {
+ o.commonInitialisms = append(o.commonInitialisms, words...)
+ }
+}
+
+// WithReplaceFunc specifies a custom transliteration function instead of the default.
+//
+// The default translates the following characters into words as follows:
+//
+// - '@' -> 'At'
+// - '&' -> 'And'
+// - '|' -> 'Pipe'
+// - '$' -> 'Dollar'
+// - '!' -> 'Bang'
+//
+// Notice that the outcome of a transliteration should always be titleized.
+func WithReplaceFunc(fn ReplaceFunc) Option {
+ return func(o *options) {
+ o.replaceFunc = fn
+ }
+}
+
+func defaultPrefixFunc(_ string) string {
+ return "X"
+}
+
+// defaultReplaceTable finds a word representation for special characters.
+func defaultReplaceTable(r rune) (string, bool) {
+ switch r {
+ case '@':
+ return "At ", true
+ case '&':
+ return "And ", true
+ case '|':
+ return "Pipe ", true
+ case '$':
+ return "Dollar ", true
+ case '!':
+ return "Bang ", true
+ case '-':
+ return "", true
+ case '_':
+ return "", true
+ default:
+ return "", false
+ }
+}
+
+func optionsWithDefaults(opts []Option) options {
+ o := options{
+ commonInitialisms: DefaultInitialisms(),
+ goNamePrefixFunc: defaultPrefixFunc,
+ replaceFunc: defaultReplaceTable,
+ }
+
+ for _, apply := range opts {
+ apply(&o)
+ }
+
+ return o
+}
diff --git a/vendor/github.com/go-openapi/swag/mangling/pools.go b/vendor/github.com/go-openapi/swag/mangling/pools.go
new file mode 100644
index 0000000000..f810435144
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/mangling/pools.go
@@ -0,0 +1,123 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package mangling
+
+import (
+ "bytes"
+ "sync"
+)
+
+const maxAllocMatches = 8
+
+type (
+ // memory pools of temporary objects.
+ //
+ // These are used to recycle temporarily allocated objects
+ // and relieve the GC from undue pressure.
+
+ matchesPool struct {
+ *sync.Pool
+ }
+
+ buffersPool struct {
+ *sync.Pool
+ }
+
+ lexemsPool struct {
+ *sync.Pool
+ }
+
+ stringsPool struct {
+ *sync.Pool
+ }
+)
+
+var (
+ // poolOfMatches holds temporary slices for recycling during the initialism match process
+ poolOfMatches = matchesPool{
+ Pool: &sync.Pool{
+ New: func() any {
+ s := make(initialismMatches, 0, maxAllocMatches)
+
+ return &s
+ },
+ },
+ }
+
+ poolOfBuffers = buffersPool{
+ Pool: &sync.Pool{
+ New: func() any {
+ return new(bytes.Buffer)
+ },
+ },
+ }
+
+ poolOfLexems = lexemsPool{
+ Pool: &sync.Pool{
+ New: func() any {
+ s := make([]nameLexem, 0, maxAllocMatches)
+
+ return &s
+ },
+ },
+ }
+
+ poolOfStrings = stringsPool{
+ Pool: &sync.Pool{
+ New: func() any {
+ s := make([]string, 0, maxAllocMatches)
+
+ return &s
+ },
+ },
+ }
+)
+
+func (p matchesPool) BorrowMatches() *initialismMatches {
+ s := p.Get().(*initialismMatches)
+ *s = (*s)[:0] // reset slice, keep allocated capacity
+
+ return s
+}
+
+func (p buffersPool) BorrowBuffer(size int) *bytes.Buffer {
+ s := p.Get().(*bytes.Buffer)
+ s.Reset()
+
+ if s.Cap() < size {
+ s.Grow(size)
+ }
+
+ return s
+}
+
+func (p lexemsPool) BorrowLexems() *[]nameLexem {
+ s := p.Get().(*[]nameLexem)
+ *s = (*s)[:0] // reset slice, keep allocated capacity
+
+ return s
+}
+
+func (p stringsPool) BorrowStrings() *[]string {
+ s := p.Get().(*[]string)
+ *s = (*s)[:0] // reset slice, keep allocated capacity
+
+ return s
+}
+
+func (p matchesPool) RedeemMatches(s *initialismMatches) {
+ p.Put(s)
+}
+
+func (p buffersPool) RedeemBuffer(s *bytes.Buffer) {
+ p.Put(s)
+}
+
+func (p lexemsPool) RedeemLexems(s *[]nameLexem) {
+ p.Put(s)
+}
+
+func (p stringsPool) RedeemStrings(s *[]string) {
+ p.Put(s)
+}
diff --git a/vendor/github.com/go-openapi/swag/mangling/split.go b/vendor/github.com/go-openapi/swag/mangling/split.go
new file mode 100644
index 0000000000..ed12ea2567
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/mangling/split.go
@@ -0,0 +1,341 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package mangling
+
+import (
+ "fmt"
+ "unicode"
+)
+
+type splitterOption func(*splitter)
+
+// withPostSplitInitialismCheck allows to catch initialisms after main split process
+func withPostSplitInitialismCheck(s *splitter) {
+ s.postSplitInitialismCheck = true
+}
+
+func withReplaceFunc(fn ReplaceFunc) func(*splitter) {
+ return func(s *splitter) {
+ s.replaceFunc = fn
+ }
+}
+
+func withInitialismsCache(c *initialismsCache) splitterOption {
+ return func(s *splitter) {
+ s.initialismsCache = c
+ }
+}
+
+type (
+ initialismMatch struct {
+ body []rune
+ start, end int
+ complete bool
+ hasPlural pluralForm
+ }
+ initialismMatches []initialismMatch
+)
+
+// String representation of a match, e.g. for debugging.
+func (m initialismMatch) String() string {
+ return fmt.Sprintf("{body: %s (%d), start: %d, end; %d, complete: %t, hasPlural: %v}",
+ string(m.body), len(m.body), m.start, m.end, m.complete, m.hasPlural,
+ )
+}
+
+func (m initialismMatch) isZero() bool {
+ return m.start == 0 && m.end == 0
+}
+
+type splitter struct {
+ *initialismsCache
+
+ postSplitInitialismCheck bool
+ replaceFunc ReplaceFunc
+}
+
+func newSplitter(options ...splitterOption) splitter {
+ var s splitter
+
+ for _, option := range options {
+ option(&s)
+ }
+
+ if s.replaceFunc == nil {
+ s.replaceFunc = defaultReplaceTable
+ }
+
+ return s
+}
+
+func (s splitter) split(name string) *[]nameLexem {
+ nameRunes := []rune(name)
+ matches := s.gatherInitialismMatches(nameRunes)
+ if matches == nil {
+ return poolOfLexems.BorrowLexems()
+ }
+
+ return s.mapMatchesToNameLexems(nameRunes, matches)
+}
+
+func (s splitter) gatherInitialismMatches(nameRunes []rune) *initialismMatches {
+ matches := poolOfMatches.BorrowMatches()
+ const minLenInitialism = 1
+ if len(nameRunes) < minLenInitialism+1 {
+ // can't match initialism with 0 or 1 rune
+ return matches
+ }
+
+ // first iteration
+ s.findMatches(matches, nameRunes, nameRunes[0], 0)
+
+ for i, currentRune := range nameRunes[1:] {
+ currentRunePosition := i + 1
+ // recycle allocations as we loop over runes
+ // with such recycling, only 2 slices should be allocated per call
+ // instead of o(n).
+ //
+ // BorrowMatches always yields slices with zero length (with some capacity)
+ newMatches := poolOfMatches.BorrowMatches()
+
+ // check current initialism matches
+ for _, match := range *matches {
+ if keepCompleteMatch := match.complete; keepCompleteMatch {
+ // the match is already complete: keep it then move on to the next match
+ *newMatches = append(*newMatches, match)
+ continue
+ }
+
+ if currentRunePosition-match.start == len(match.body) {
+ // unmatched: skip
+ continue
+ }
+
+ // 1. by construction of the matches, we can't have currentRunePosition - match.start < 0
+ // because matches have been computed with their start <= currentRunePosition in the previous
+ // iterations.
+ // 2. by construction of the matches, we can't have currentRunePosition - match.start >= len(match.body)
+
+ currentMatchRune := match.body[currentRunePosition-match.start]
+ if currentMatchRune != currentRune {
+ // failed match, discard it then move on to the next match
+ continue
+ }
+
+ // try to complete the current match
+ if currentRunePosition-match.start == len(match.body)-1 {
+ // we are close: the next step is to check the symbol ahead
+ // if it is a lowercase letter, then it is not the end of match
+ // but the beginning of the next word.
+ //
+ // NOTE(fredbi): this heuristic sometimes leads to counterintuitive splits and
+ // perhaps (not sure yet) we should check against case _alternance_.
+ //
+ // Example:
+ //
+ // In the current version, in the sentence "IDS initialism", "ID" is recognized as an initialism,
+ // leading to a split like "id_s_initialism" (or IDSInitialism),
+ // whereas in the sentence "IDx initialism", it is not and produces something like
+ // "i_d_x_initialism" (or IDxInitialism). The generated file name is not great.
+ //
+ // Both go identifiers are tolerated by linters.
+ //
+ // Notice that the slightly different input "IDs initialism" is correctly detected
+ // as a pluralized initialism and produces something like "ids_initialism" (or IDsInitialism).
+
+ if currentRunePosition < len(nameRunes)-1 { // when before the last rune
+ nextRune := nameRunes[currentRunePosition+1]
+
+ // recognize a plural form for this initialism (only simple english pluralization is supported).
+ if nextRune == 's' && match.hasPlural == simplePlural {
+ // detected a pluralized initialism
+ match.body = append(match.body, nextRune)
+ lookAhead := currentRunePosition + 1
+ if lookAhead < len(nameRunes)-1 {
+ nextRune = nameRunes[lookAhead+1]
+ if newWord := unicode.IsLower(nextRune); newWord {
+ // it is the start of a new word.
+ // Match is only partial and the initialism is not recognized:
+ // move on to the next match, but do not advance the rune position
+ continue
+ }
+ }
+
+ // this is a pluralized match: keep it
+ currentRunePosition++
+ match.complete = true
+ match.hasPlural = simplePlural
+ match.end = currentRunePosition
+ *newMatches = append(*newMatches, match)
+
+ // match is complete: keep it then move on to the next match
+ continue
+ }
+
+ // other cases
+ // example: invariant plural such as "TLS"
+ if newWord := unicode.IsLower(nextRune); newWord {
+ // it is the start of a new word
+ // Match is only partial and the initialism is not recognized : move on
+ continue
+ }
+ }
+
+ match.complete = true
+ match.end = currentRunePosition
+ }
+
+ // append the ongoing matching attempt: it is not necessarily complete, but was successful so far.
+ // Let's see if it still matches on the next rune.
+ *newMatches = append(*newMatches, match)
+ }
+
+ s.findMatches(newMatches, nameRunes, currentRune, currentRunePosition)
+
+ poolOfMatches.RedeemMatches(matches)
+ matches = newMatches
+ }
+
+ // it is up to the caller to redeem this last slice
+ return matches
+}
+
+func (s splitter) findMatches(newMatches *initialismMatches, nameRunes []rune, currentRune rune, currentRunePosition int) {
+ // check for new initialism matches, based on the first character
+ for i, r := range s.initialismsRunes {
+ if r[0] != currentRune {
+ continue
+ }
+
+ if currentRunePosition+len(r) > len(nameRunes) {
+ continue // not eligible: would spilll over the initial string
+ }
+
+ // possible matches: all initialisms starting with the current rune and that can fit the given string (nameRunes)
+ *newMatches = append(*newMatches, initialismMatch{
+ start: currentRunePosition,
+ body: r,
+ complete: false,
+ hasPlural: s.initialismsPluralForm[i],
+ })
+ }
+}
+
+func (s splitter) mapMatchesToNameLexems(nameRunes []rune, matches *initialismMatches) *[]nameLexem {
+ nameLexems := poolOfLexems.BorrowLexems()
+
+ var lastAcceptedMatch initialismMatch
+ for _, match := range *matches {
+ if !match.complete {
+ continue
+ }
+
+ if firstMatch := lastAcceptedMatch.isZero(); firstMatch {
+ s.appendBrokenDownCasualString(nameLexems, nameRunes[:match.start])
+ *nameLexems = append(*nameLexems, s.breakInitialism(string(match.body)))
+
+ lastAcceptedMatch = match
+
+ continue
+ }
+
+ if overlappedMatch := match.start <= lastAcceptedMatch.end; overlappedMatch {
+ continue
+ }
+
+ middle := nameRunes[lastAcceptedMatch.end+1 : match.start]
+ s.appendBrokenDownCasualString(nameLexems, middle)
+ *nameLexems = append(*nameLexems, s.breakInitialism(string(match.body)))
+
+ lastAcceptedMatch = match
+ }
+
+ // we have not found any accepted matches
+ if lastAcceptedMatch.isZero() {
+ *nameLexems = (*nameLexems)[:0]
+ s.appendBrokenDownCasualString(nameLexems, nameRunes)
+ } else if lastAcceptedMatch.end+1 != len(nameRunes) {
+ rest := nameRunes[lastAcceptedMatch.end+1:]
+ s.appendBrokenDownCasualString(nameLexems, rest)
+ }
+
+ poolOfMatches.RedeemMatches(matches)
+
+ return nameLexems
+}
+
+func (s splitter) breakInitialism(original string) nameLexem {
+ return newInitialismNameLexem(original, original)
+}
+
+func (s splitter) appendBrokenDownCasualString(segments *[]nameLexem, str []rune) {
+ currentSegment := poolOfBuffers.BorrowBuffer(len(str)) // unlike strings.Builder, bytes.Buffer initial storage can reused
+ defer func() {
+ poolOfBuffers.RedeemBuffer(currentSegment)
+ }()
+
+ addCasualNameLexem := func(original string) {
+ *segments = append(*segments, newCasualNameLexem(original))
+ }
+
+ addInitialismNameLexem := func(original, match string) {
+ *segments = append(*segments, newInitialismNameLexem(original, match))
+ }
+
+ var addNameLexem func(string)
+ if s.postSplitInitialismCheck {
+ addNameLexem = func(original string) {
+ for i := range s.initialisms {
+ if isEqualFoldIgnoreSpace(s.initialismsUpperCased[i], original) {
+ addInitialismNameLexem(original, s.initialisms[i])
+
+ return
+ }
+ }
+
+ addCasualNameLexem(original)
+ }
+ } else {
+ addNameLexem = addCasualNameLexem
+ }
+
+ // NOTE: (performance). The few remaining non-amortized allocations
+ // lay in the code below: using String() forces
+ for _, rn := range str {
+ if replace, found := s.replaceFunc(rn); found {
+ if currentSegment.Len() > 0 {
+ addNameLexem(currentSegment.String())
+ currentSegment.Reset()
+ }
+
+ if replace != "" {
+ addNameLexem(replace)
+ }
+
+ continue
+ }
+
+ if !unicode.In(rn, unicode.L, unicode.M, unicode.N, unicode.Pc) {
+ if currentSegment.Len() > 0 {
+ addNameLexem(currentSegment.String())
+ currentSegment.Reset()
+ }
+
+ continue
+ }
+
+ if unicode.IsUpper(rn) {
+ if currentSegment.Len() > 0 {
+ addNameLexem(currentSegment.String())
+ }
+ currentSegment.Reset()
+ }
+
+ currentSegment.WriteRune(rn)
+ }
+
+ if currentSegment.Len() > 0 {
+ addNameLexem(currentSegment.String())
+ }
+}
diff --git a/vendor/github.com/go-openapi/swag/string_bytes.go b/vendor/github.com/go-openapi/swag/mangling/string_bytes.go
similarity index 60%
rename from vendor/github.com/go-openapi/swag/string_bytes.go
rename to vendor/github.com/go-openapi/swag/mangling/string_bytes.go
index 90745d5ca9..28daaf72b1 100644
--- a/vendor/github.com/go-openapi/swag/string_bytes.go
+++ b/vendor/github.com/go-openapi/swag/mangling/string_bytes.go
@@ -1,4 +1,7 @@
-package swag
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package mangling
import "unsafe"
diff --git a/vendor/github.com/go-openapi/swag/mangling/util.go b/vendor/github.com/go-openapi/swag/mangling/util.go
new file mode 100644
index 0000000000..0636417e36
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/mangling/util.go
@@ -0,0 +1,118 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package mangling
+
+import (
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+// Removes leading whitespaces
+func trim(str string) string { return strings.TrimSpace(str) }
+
+// upper is strings.ToUpper() combined with trim
+func upper(str string) string {
+ return strings.ToUpper(trim(str))
+}
+
+// lower is strings.ToLower() combined with trim
+func lower(str string) string {
+ return strings.ToLower(trim(str))
+}
+
+// isEqualFoldIgnoreSpace is the same as strings.EqualFold, but
+// it ignores leading and trailing blank spaces in the compared
+// string.
+//
+// base is assumed to be composed of upper-cased runes, and be already
+// trimmed.
+//
+// This code is heavily inspired from strings.EqualFold.
+func isEqualFoldIgnoreSpace(base []rune, str string) bool {
+ var i, baseIndex int
+ // equivalent to b := []byte(str), but without data copy
+ b := hackStringBytes(str)
+
+ for i < len(b) {
+ if c := b[i]; c < utf8.RuneSelf {
+ // fast path for ASCII
+ if c != ' ' && c != '\t' {
+ break
+ }
+ i++
+
+ continue
+ }
+
+ // unicode case
+ r, size := utf8.DecodeRune(b[i:])
+ if !unicode.IsSpace(r) {
+ break
+ }
+ i += size
+ }
+
+ if i >= len(b) {
+ return len(base) == 0
+ }
+
+ for _, baseRune := range base {
+ if i >= len(b) {
+ break
+ }
+
+ if c := b[i]; c < utf8.RuneSelf {
+ // single byte rune case (ASCII)
+ if baseRune >= utf8.RuneSelf {
+ return false
+ }
+
+ baseChar := byte(baseRune)
+ if c != baseChar && ((c < 'a') || (c > 'z') || (c-'a'+'A' != baseChar)) {
+ return false
+ }
+
+ baseIndex++
+ i++
+
+ continue
+ }
+
+ // unicode case
+ r, size := utf8.DecodeRune(b[i:])
+ if unicode.ToUpper(r) != baseRune {
+ return false
+ }
+ baseIndex++
+ i += size
+ }
+
+ if baseIndex != len(base) {
+ return false
+ }
+
+ // all passed: now we should only have blanks
+ for i < len(b) {
+ if c := b[i]; c < utf8.RuneSelf {
+ // fast path for ASCII
+ if c != ' ' && c != '\t' {
+ return false
+ }
+ i++
+
+ continue
+ }
+
+ // unicode case
+ r, size := utf8.DecodeRune(b[i:])
+ if !unicode.IsSpace(r) {
+ return false
+ }
+
+ i += size
+ }
+
+ return true
+}
diff --git a/vendor/github.com/go-openapi/swag/mangling_iface.go b/vendor/github.com/go-openapi/swag/mangling_iface.go
new file mode 100644
index 0000000000..98b9a99929
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/mangling_iface.go
@@ -0,0 +1,69 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package swag
+
+import "github.com/go-openapi/swag/mangling"
+
+// GoNamePrefixFunc sets an optional rule to prefix go names
+// which do not start with a letter.
+//
+// GoNamePrefixFunc should not be written to while concurrently using the other mangling functions of this package.
+//
+// Deprecated: use [mangling.WithGoNamePrefixFunc] instead.
+var GoNamePrefixFunc mangling.PrefixFunc
+
+// swagNameMangler is a global instance of the name mangler specifically alloted
+// to support deprecated functions.
+var swagNameMangler = mangling.NewNameMangler(
+ mangling.WithGoNamePrefixFuncPtr(&GoNamePrefixFunc),
+)
+
+// AddInitialisms adds additional initialisms to the default list (see [mangling.DefaultInitialisms]).
+//
+// AddInitialisms is not safe to be called concurrently.
+//
+// Deprecated: use [mangling.WithAdditionalInitialisms] instead.
+func AddInitialisms(words ...string) {
+ swagNameMangler.AddInitialisms(words...)
+}
+
+// Camelize a single word.
+//
+// Deprecated: use [mangling.NameMangler.Camelize] instead.
+func Camelize(word string) string { return swagNameMangler.Camelize(word) }
+
+// ToFileName lowercases and underscores a go type name.
+//
+// Deprecated: use [mangling.NameMangler.ToFileName] instead.
+func ToFileName(name string) string { return swagNameMangler.ToFileName(name) }
+
+// ToCommandName lowercases and underscores a go type name.
+//
+// Deprecated: use [mangling.NameMangler.ToCommandName] instead.
+func ToCommandName(name string) string { return swagNameMangler.ToCommandName(name) }
+
+// ToHumanNameLower represents a code name as a human series of words.
+//
+// Deprecated: use [mangling.NameMangler.ToHumanNameLower] instead.
+func ToHumanNameLower(name string) string { return swagNameMangler.ToHumanNameLower(name) }
+
+// ToHumanNameTitle represents a code name as a human series of words with the first letters titleized.
+//
+// Deprecated: use [mangling.NameMangler.ToHumanNameTitle] instead.
+func ToHumanNameTitle(name string) string { return swagNameMangler.ToHumanNameTitle(name) }
+
+// ToJSONName camel-cases a name which can be underscored or pascal-cased.
+//
+// Deprecated: use [mangling.NameMangler.ToJSONName] instead.
+func ToJSONName(name string) string { return swagNameMangler.ToJSONName(name) }
+
+// ToVarName camel-cases a name which can be underscored or pascal-cased.
+//
+// Deprecated: use [mangling.NameMangler.ToVarName] instead.
+func ToVarName(name string) string { return swagNameMangler.ToVarName(name) }
+
+// ToGoName translates a swagger name which can be underscored or camel cased to a name that golint likes.
+//
+// Deprecated: use [mangling.NameMangler.ToGoName] instead.
+func ToGoName(name string) string { return swagNameMangler.ToGoName(name) }
diff --git a/vendor/github.com/go-openapi/swag/name_lexem.go b/vendor/github.com/go-openapi/swag/name_lexem.go
deleted file mode 100644
index 8bb64ac32f..0000000000
--- a/vendor/github.com/go-openapi/swag/name_lexem.go
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2015 go-swagger maintainers
-//
-// 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 swag
-
-import (
- "unicode"
- "unicode/utf8"
-)
-
-type (
- lexemKind uint8
-
- nameLexem struct {
- original string
- matchedInitialism string
- kind lexemKind
- }
-)
-
-const (
- lexemKindCasualName lexemKind = iota
- lexemKindInitialismName
-)
-
-func newInitialismNameLexem(original, matchedInitialism string) nameLexem {
- return nameLexem{
- kind: lexemKindInitialismName,
- original: original,
- matchedInitialism: matchedInitialism,
- }
-}
-
-func newCasualNameLexem(original string) nameLexem {
- return nameLexem{
- kind: lexemKindCasualName,
- original: original,
- }
-}
-
-func (l nameLexem) GetUnsafeGoName() string {
- if l.kind == lexemKindInitialismName {
- return l.matchedInitialism
- }
-
- var (
- first rune
- rest string
- )
-
- for i, orig := range l.original {
- if i == 0 {
- first = orig
- continue
- }
-
- if i > 0 {
- rest = l.original[i:]
- break
- }
- }
-
- if len(l.original) > 1 {
- b := poolOfBuffers.BorrowBuffer(utf8.UTFMax + len(rest))
- defer func() {
- poolOfBuffers.RedeemBuffer(b)
- }()
- b.WriteRune(unicode.ToUpper(first))
- b.WriteString(lower(rest))
- return b.String()
- }
-
- return l.original
-}
-
-func (l nameLexem) GetOriginal() string {
- return l.original
-}
-
-func (l nameLexem) IsInitialism() bool {
- return l.kind == lexemKindInitialismName
-}
diff --git a/vendor/github.com/go-openapi/swag/netutils/LICENSE b/vendor/github.com/go-openapi/swag/netutils/LICENSE
new file mode 100644
index 0000000000..d645695673
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/netutils/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/vendor/github.com/go-openapi/swag/netutils/doc.go b/vendor/github.com/go-openapi/swag/netutils/doc.go
new file mode 100644
index 0000000000..74282f8e51
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/netutils/doc.go
@@ -0,0 +1,5 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+// Package netutils provides helpers for network-related tasks.
+package netutils
diff --git a/vendor/github.com/go-openapi/swag/netutils/net.go b/vendor/github.com/go-openapi/swag/netutils/net.go
new file mode 100644
index 0000000000..82a1544af7
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/netutils/net.go
@@ -0,0 +1,31 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package netutils
+
+import (
+ "net"
+ "strconv"
+)
+
+// SplitHostPort splits a network address into a host and a port.
+//
+// The difference with the standard net.SplitHostPort is that the port is converted to an int.
+//
+// The port is -1 when there is no port to be found.
+func SplitHostPort(addr string) (host string, port int, err error) {
+ h, p, err := net.SplitHostPort(addr)
+ if err != nil {
+ return "", -1, err
+ }
+ if p == "" {
+ return "", -1, &net.AddrError{Err: "missing port in address", Addr: addr}
+ }
+
+ pi, err := strconv.Atoi(p)
+ if err != nil {
+ return "", -1, err
+ }
+
+ return h, pi, nil
+}
diff --git a/vendor/github.com/go-openapi/swag/netutils_iface.go b/vendor/github.com/go-openapi/swag/netutils_iface.go
new file mode 100644
index 0000000000..d658de25b3
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/netutils_iface.go
@@ -0,0 +1,13 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package swag
+
+import "github.com/go-openapi/swag/netutils"
+
+// SplitHostPort splits a network address into a host and a port.
+//
+// Deprecated: use [netutils.SplitHostPort] instead.
+func SplitHostPort(addr string) (host string, port int, err error) {
+ return netutils.SplitHostPort(addr)
+}
diff --git a/vendor/github.com/go-openapi/swag/split.go b/vendor/github.com/go-openapi/swag/split.go
deleted file mode 100644
index 274727a866..0000000000
--- a/vendor/github.com/go-openapi/swag/split.go
+++ /dev/null
@@ -1,508 +0,0 @@
-// Copyright 2015 go-swagger maintainers
-//
-// 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 swag
-
-import (
- "bytes"
- "sync"
- "unicode"
- "unicode/utf8"
-)
-
-type (
- splitter struct {
- initialisms []string
- initialismsRunes [][]rune
- initialismsUpperCased [][]rune // initialisms cached in their trimmed, upper-cased version
- postSplitInitialismCheck bool
- }
-
- splitterOption func(*splitter)
-
- initialismMatch struct {
- body []rune
- start, end int
- complete bool
- }
- initialismMatches []initialismMatch
-)
-
-type (
- // memory pools of temporary objects.
- //
- // These are used to recycle temporarily allocated objects
- // and relieve the GC from undue pressure.
-
- matchesPool struct {
- *sync.Pool
- }
-
- buffersPool struct {
- *sync.Pool
- }
-
- lexemsPool struct {
- *sync.Pool
- }
-
- splittersPool struct {
- *sync.Pool
- }
-)
-
-var (
- // poolOfMatches holds temporary slices for recycling during the initialism match process
- poolOfMatches = matchesPool{
- Pool: &sync.Pool{
- New: func() any {
- s := make(initialismMatches, 0, maxAllocMatches)
-
- return &s
- },
- },
- }
-
- poolOfBuffers = buffersPool{
- Pool: &sync.Pool{
- New: func() any {
- return new(bytes.Buffer)
- },
- },
- }
-
- poolOfLexems = lexemsPool{
- Pool: &sync.Pool{
- New: func() any {
- s := make([]nameLexem, 0, maxAllocMatches)
-
- return &s
- },
- },
- }
-
- poolOfSplitters = splittersPool{
- Pool: &sync.Pool{
- New: func() any {
- s := newSplitter()
-
- return &s
- },
- },
- }
-)
-
-// nameReplaceTable finds a word representation for special characters.
-func nameReplaceTable(r rune) (string, bool) {
- switch r {
- case '@':
- return "At ", true
- case '&':
- return "And ", true
- case '|':
- return "Pipe ", true
- case '$':
- return "Dollar ", true
- case '!':
- return "Bang ", true
- case '-':
- return "", true
- case '_':
- return "", true
- default:
- return "", false
- }
-}
-
-// split calls the splitter.
-//
-// Use newSplitter for more control and options
-func split(str string) []string {
- s := poolOfSplitters.BorrowSplitter()
- lexems := s.split(str)
- result := make([]string, 0, len(*lexems))
-
- for _, lexem := range *lexems {
- result = append(result, lexem.GetOriginal())
- }
- poolOfLexems.RedeemLexems(lexems)
- poolOfSplitters.RedeemSplitter(s)
-
- return result
-
-}
-
-func newSplitter(options ...splitterOption) splitter {
- s := splitter{
- postSplitInitialismCheck: false,
- initialisms: initialisms,
- initialismsRunes: initialismsRunes,
- initialismsUpperCased: initialismsUpperCased,
- }
-
- for _, option := range options {
- option(&s)
- }
-
- return s
-}
-
-// withPostSplitInitialismCheck allows to catch initialisms after main split process
-func withPostSplitInitialismCheck(s *splitter) {
- s.postSplitInitialismCheck = true
-}
-
-func (p matchesPool) BorrowMatches() *initialismMatches {
- s := p.Get().(*initialismMatches)
- *s = (*s)[:0] // reset slice, keep allocated capacity
-
- return s
-}
-
-func (p buffersPool) BorrowBuffer(size int) *bytes.Buffer {
- s := p.Get().(*bytes.Buffer)
- s.Reset()
-
- if s.Cap() < size {
- s.Grow(size)
- }
-
- return s
-}
-
-func (p lexemsPool) BorrowLexems() *[]nameLexem {
- s := p.Get().(*[]nameLexem)
- *s = (*s)[:0] // reset slice, keep allocated capacity
-
- return s
-}
-
-func (p splittersPool) BorrowSplitter(options ...splitterOption) *splitter {
- s := p.Get().(*splitter)
- s.postSplitInitialismCheck = false // reset options
- for _, apply := range options {
- apply(s)
- }
-
- return s
-}
-
-func (p matchesPool) RedeemMatches(s *initialismMatches) {
- p.Put(s)
-}
-
-func (p buffersPool) RedeemBuffer(s *bytes.Buffer) {
- p.Put(s)
-}
-
-func (p lexemsPool) RedeemLexems(s *[]nameLexem) {
- p.Put(s)
-}
-
-func (p splittersPool) RedeemSplitter(s *splitter) {
- p.Put(s)
-}
-
-func (m initialismMatch) isZero() bool {
- return m.start == 0 && m.end == 0
-}
-
-func (s splitter) split(name string) *[]nameLexem {
- nameRunes := []rune(name)
- matches := s.gatherInitialismMatches(nameRunes)
- if matches == nil {
- return poolOfLexems.BorrowLexems()
- }
-
- return s.mapMatchesToNameLexems(nameRunes, matches)
-}
-
-func (s splitter) gatherInitialismMatches(nameRunes []rune) *initialismMatches {
- var matches *initialismMatches
-
- for currentRunePosition, currentRune := range nameRunes {
- // recycle these allocations as we loop over runes
- // with such recycling, only 2 slices should be allocated per call
- // instead of o(n).
- newMatches := poolOfMatches.BorrowMatches()
-
- // check current initialism matches
- if matches != nil { // skip first iteration
- for _, match := range *matches {
- if keepCompleteMatch := match.complete; keepCompleteMatch {
- *newMatches = append(*newMatches, match)
- continue
- }
-
- // drop failed match
- currentMatchRune := match.body[currentRunePosition-match.start]
- if currentMatchRune != currentRune {
- continue
- }
-
- // try to complete ongoing match
- if currentRunePosition-match.start == len(match.body)-1 {
- // we are close; the next step is to check the symbol ahead
- // if it is a small letter, then it is not the end of match
- // but beginning of the next word
-
- if currentRunePosition < len(nameRunes)-1 {
- nextRune := nameRunes[currentRunePosition+1]
- if newWord := unicode.IsLower(nextRune); newWord {
- // oh ok, it was the start of a new word
- continue
- }
- }
-
- match.complete = true
- match.end = currentRunePosition
- }
-
- *newMatches = append(*newMatches, match)
- }
- }
-
- // check for new initialism matches
- for i := range s.initialisms {
- initialismRunes := s.initialismsRunes[i]
- if initialismRunes[0] == currentRune {
- *newMatches = append(*newMatches, initialismMatch{
- start: currentRunePosition,
- body: initialismRunes,
- complete: false,
- })
- }
- }
-
- if matches != nil {
- poolOfMatches.RedeemMatches(matches)
- }
- matches = newMatches
- }
-
- // up to the caller to redeem this last slice
- return matches
-}
-
-func (s splitter) mapMatchesToNameLexems(nameRunes []rune, matches *initialismMatches) *[]nameLexem {
- nameLexems := poolOfLexems.BorrowLexems()
-
- var lastAcceptedMatch initialismMatch
- for _, match := range *matches {
- if !match.complete {
- continue
- }
-
- if firstMatch := lastAcceptedMatch.isZero(); firstMatch {
- s.appendBrokenDownCasualString(nameLexems, nameRunes[:match.start])
- *nameLexems = append(*nameLexems, s.breakInitialism(string(match.body)))
-
- lastAcceptedMatch = match
-
- continue
- }
-
- if overlappedMatch := match.start <= lastAcceptedMatch.end; overlappedMatch {
- continue
- }
-
- middle := nameRunes[lastAcceptedMatch.end+1 : match.start]
- s.appendBrokenDownCasualString(nameLexems, middle)
- *nameLexems = append(*nameLexems, s.breakInitialism(string(match.body)))
-
- lastAcceptedMatch = match
- }
-
- // we have not found any accepted matches
- if lastAcceptedMatch.isZero() {
- *nameLexems = (*nameLexems)[:0]
- s.appendBrokenDownCasualString(nameLexems, nameRunes)
- } else if lastAcceptedMatch.end+1 != len(nameRunes) {
- rest := nameRunes[lastAcceptedMatch.end+1:]
- s.appendBrokenDownCasualString(nameLexems, rest)
- }
-
- poolOfMatches.RedeemMatches(matches)
-
- return nameLexems
-}
-
-func (s splitter) breakInitialism(original string) nameLexem {
- return newInitialismNameLexem(original, original)
-}
-
-func (s splitter) appendBrokenDownCasualString(segments *[]nameLexem, str []rune) {
- currentSegment := poolOfBuffers.BorrowBuffer(len(str)) // unlike strings.Builder, bytes.Buffer initial storage can reused
- defer func() {
- poolOfBuffers.RedeemBuffer(currentSegment)
- }()
-
- addCasualNameLexem := func(original string) {
- *segments = append(*segments, newCasualNameLexem(original))
- }
-
- addInitialismNameLexem := func(original, match string) {
- *segments = append(*segments, newInitialismNameLexem(original, match))
- }
-
- var addNameLexem func(string)
- if s.postSplitInitialismCheck {
- addNameLexem = func(original string) {
- for i := range s.initialisms {
- if isEqualFoldIgnoreSpace(s.initialismsUpperCased[i], original) {
- addInitialismNameLexem(original, s.initialisms[i])
-
- return
- }
- }
-
- addCasualNameLexem(original)
- }
- } else {
- addNameLexem = addCasualNameLexem
- }
-
- for _, rn := range str {
- if replace, found := nameReplaceTable(rn); found {
- if currentSegment.Len() > 0 {
- addNameLexem(currentSegment.String())
- currentSegment.Reset()
- }
-
- if replace != "" {
- addNameLexem(replace)
- }
-
- continue
- }
-
- if !unicode.In(rn, unicode.L, unicode.M, unicode.N, unicode.Pc) {
- if currentSegment.Len() > 0 {
- addNameLexem(currentSegment.String())
- currentSegment.Reset()
- }
-
- continue
- }
-
- if unicode.IsUpper(rn) {
- if currentSegment.Len() > 0 {
- addNameLexem(currentSegment.String())
- }
- currentSegment.Reset()
- }
-
- currentSegment.WriteRune(rn)
- }
-
- if currentSegment.Len() > 0 {
- addNameLexem(currentSegment.String())
- }
-}
-
-// isEqualFoldIgnoreSpace is the same as strings.EqualFold, but
-// it ignores leading and trailing blank spaces in the compared
-// string.
-//
-// base is assumed to be composed of upper-cased runes, and be already
-// trimmed.
-//
-// This code is heavily inspired from strings.EqualFold.
-func isEqualFoldIgnoreSpace(base []rune, str string) bool {
- var i, baseIndex int
- // equivalent to b := []byte(str), but without data copy
- b := hackStringBytes(str)
-
- for i < len(b) {
- if c := b[i]; c < utf8.RuneSelf {
- // fast path for ASCII
- if c != ' ' && c != '\t' {
- break
- }
- i++
-
- continue
- }
-
- // unicode case
- r, size := utf8.DecodeRune(b[i:])
- if !unicode.IsSpace(r) {
- break
- }
- i += size
- }
-
- if i >= len(b) {
- return len(base) == 0
- }
-
- for _, baseRune := range base {
- if i >= len(b) {
- break
- }
-
- if c := b[i]; c < utf8.RuneSelf {
- // single byte rune case (ASCII)
- if baseRune >= utf8.RuneSelf {
- return false
- }
-
- baseChar := byte(baseRune)
- if c != baseChar &&
- !('a' <= c && c <= 'z' && c-'a'+'A' == baseChar) {
- return false
- }
-
- baseIndex++
- i++
-
- continue
- }
-
- // unicode case
- r, size := utf8.DecodeRune(b[i:])
- if unicode.ToUpper(r) != baseRune {
- return false
- }
- baseIndex++
- i += size
- }
-
- if baseIndex != len(base) {
- return false
- }
-
- // all passed: now we should only have blanks
- for i < len(b) {
- if c := b[i]; c < utf8.RuneSelf {
- // fast path for ASCII
- if c != ' ' && c != '\t' {
- return false
- }
- i++
-
- continue
- }
-
- // unicode case
- r, size := utf8.DecodeRune(b[i:])
- if !unicode.IsSpace(r) {
- return false
- }
-
- i += size
- }
-
- return true
-}
diff --git a/vendor/github.com/go-openapi/swag/stringutils/LICENSE b/vendor/github.com/go-openapi/swag/stringutils/LICENSE
new file mode 100644
index 0000000000..d645695673
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/stringutils/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/vendor/github.com/go-openapi/swag/stringutils/collection_formats.go b/vendor/github.com/go-openapi/swag/stringutils/collection_formats.go
new file mode 100644
index 0000000000..28056ad25c
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/stringutils/collection_formats.go
@@ -0,0 +1,74 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package stringutils
+
+import "strings"
+
+const (
+ // collectionFormatComma = "csv"
+ collectionFormatSpace = "ssv"
+ collectionFormatTab = "tsv"
+ collectionFormatPipe = "pipes"
+ collectionFormatMulti = "multi"
+
+ collectionFormatDefaultSep = ","
+)
+
+// JoinByFormat joins a string array by a known format (e.g. swagger's collectionFormat attribute):
+//
+// ssv: space separated value
+// tsv: tab separated value
+// pipes: pipe (|) separated value
+// csv: comma separated value (default)
+func JoinByFormat(data []string, format string) []string {
+ if len(data) == 0 {
+ return data
+ }
+ var sep string
+ switch format {
+ case collectionFormatSpace:
+ sep = " "
+ case collectionFormatTab:
+ sep = "\t"
+ case collectionFormatPipe:
+ sep = "|"
+ case collectionFormatMulti:
+ return data
+ default:
+ sep = collectionFormatDefaultSep
+ }
+ return []string{strings.Join(data, sep)}
+}
+
+// SplitByFormat splits a string by a known format:
+//
+// ssv: space separated value
+// tsv: tab separated value
+// pipes: pipe (|) separated value
+// csv: comma separated value (default)
+func SplitByFormat(data, format string) []string {
+ if data == "" {
+ return nil
+ }
+ var sep string
+ switch format {
+ case collectionFormatSpace:
+ sep = " "
+ case collectionFormatTab:
+ sep = "\t"
+ case collectionFormatPipe:
+ sep = "|"
+ case collectionFormatMulti:
+ return nil
+ default:
+ sep = collectionFormatDefaultSep
+ }
+ var result []string
+ for _, s := range strings.Split(data, sep) {
+ if ts := strings.TrimSpace(s); ts != "" {
+ result = append(result, ts)
+ }
+ }
+ return result
+}
diff --git a/vendor/github.com/go-openapi/swag/stringutils/doc.go b/vendor/github.com/go-openapi/swag/stringutils/doc.go
new file mode 100644
index 0000000000..c6d17a1160
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/stringutils/doc.go
@@ -0,0 +1,5 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+// Package stringutils exposes helpers to search and process strings.
+package stringutils
diff --git a/vendor/github.com/go-openapi/swag/stringutils/strings.go b/vendor/github.com/go-openapi/swag/stringutils/strings.go
new file mode 100644
index 0000000000..cd792b7d08
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/stringutils/strings.go
@@ -0,0 +1,23 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package stringutils
+
+import (
+ "slices"
+ "strings"
+)
+
+// ContainsStrings searches a slice of strings for a case-sensitive match
+//
+// Now equivalent to the standard library [slice.Contains].
+func ContainsStrings(coll []string, item string) bool {
+ return slices.Contains(coll, item)
+}
+
+// ContainsStringsCI searches a slice of strings for a case-insensitive match
+func ContainsStringsCI(coll []string, item string) bool {
+ return slices.ContainsFunc(coll, func(e string) bool {
+ return strings.EqualFold(e, item)
+ })
+}
diff --git a/vendor/github.com/go-openapi/swag/stringutils_iface.go b/vendor/github.com/go-openapi/swag/stringutils_iface.go
new file mode 100644
index 0000000000..dbfa484843
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/stringutils_iface.go
@@ -0,0 +1,34 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package swag
+
+import "github.com/go-openapi/swag/stringutils"
+
+// ContainsStrings searches a slice of strings for a case-sensitive match.
+//
+// Deprecated: use [slices.Contains] or [stringutils.ContainsStrings] instead.
+func ContainsStrings(coll []string, item string) bool {
+ return stringutils.ContainsStrings(coll, item)
+}
+
+// ContainsStringsCI searches a slice of strings for a case-insensitive match.
+//
+// Deprecated: use [stringutils.ContainsStringsCI] instead.
+func ContainsStringsCI(coll []string, item string) bool {
+ return stringutils.ContainsStringsCI(coll, item)
+}
+
+// JoinByFormat joins a string array by a known format (e.g. swagger's collectionFormat attribute).
+//
+// Deprecated: use [stringutils.JoinByFormat] instead.
+func JoinByFormat(data []string, format string) []string {
+ return stringutils.JoinByFormat(data, format)
+}
+
+// SplitByFormat splits a string by a known format.
+//
+// Deprecated: use [stringutils.SplitByFormat] instead.
+func SplitByFormat(data, format string) []string {
+ return stringutils.SplitByFormat(data, format)
+}
diff --git a/vendor/github.com/go-openapi/swag/typeutils/LICENSE b/vendor/github.com/go-openapi/swag/typeutils/LICENSE
new file mode 100644
index 0000000000..d645695673
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/typeutils/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/vendor/github.com/go-openapi/swag/typeutils/doc.go b/vendor/github.com/go-openapi/swag/typeutils/doc.go
new file mode 100644
index 0000000000..66bed20dff
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/typeutils/doc.go
@@ -0,0 +1,5 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+// Package typeutils exposes utilities to inspect generic types.
+package typeutils
diff --git a/vendor/github.com/go-openapi/swag/typeutils/types.go b/vendor/github.com/go-openapi/swag/typeutils/types.go
new file mode 100644
index 0000000000..55487a673c
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/typeutils/types.go
@@ -0,0 +1,80 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package typeutils
+
+import "reflect"
+
+type zeroable interface {
+ IsZero() bool
+}
+
+// IsZero returns true when the value passed into the function is a zero value.
+// This allows for safer checking of interface values.
+func IsZero(data any) bool {
+ v := reflect.ValueOf(data)
+ // check for nil data
+ switch v.Kind() { //nolint:exhaustive
+ case
+ reflect.Interface,
+ reflect.Func,
+ reflect.Chan,
+ reflect.Pointer,
+ reflect.UnsafePointer,
+ reflect.Map,
+ reflect.Slice:
+ if v.IsNil() {
+ return true
+ }
+ }
+
+ // check for things that have an IsZero method instead
+ if vv, ok := data.(zeroable); ok {
+ return vv.IsZero()
+ }
+
+ // continue with slightly more complex reflection
+ switch v.Kind() { //nolint:exhaustive
+ case 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.Struct, reflect.Array:
+ return reflect.DeepEqual(data, reflect.Zero(v.Type()).Interface())
+ case reflect.Invalid:
+ return true
+ default:
+ return false
+ }
+}
+
+// IsNil checks if input is nil.
+//
+// For types chan, func, interface, map, pointer, or slice it returns true if its argument is nil.
+//
+// See [reflect.Value.IsNil].
+func IsNil(input any) bool {
+ if input == nil {
+ return true
+ }
+
+ kind := reflect.TypeOf(input).Kind()
+ switch kind { //nolint:exhaustive
+ case reflect.Pointer,
+ reflect.UnsafePointer,
+ reflect.Map,
+ reflect.Slice,
+ reflect.Chan,
+ reflect.Interface,
+ reflect.Func:
+ return reflect.ValueOf(input).IsNil()
+ default:
+ return false
+ }
+}
diff --git a/vendor/github.com/go-openapi/swag/typeutils_iface.go b/vendor/github.com/go-openapi/swag/typeutils_iface.go
new file mode 100644
index 0000000000..b63813ea40
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/typeutils_iface.go
@@ -0,0 +1,12 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package swag
+
+import "github.com/go-openapi/swag/typeutils"
+
+// IsZero returns true when the value passed into the function is a zero value.
+// This allows for safer checking of interface values.
+//
+// Deprecated: use [typeutils.IsZero] instead.
+func IsZero(data any) bool { return typeutils.IsZero(data) }
diff --git a/vendor/github.com/go-openapi/swag/util.go b/vendor/github.com/go-openapi/swag/util.go
deleted file mode 100644
index 5051401c49..0000000000
--- a/vendor/github.com/go-openapi/swag/util.go
+++ /dev/null
@@ -1,364 +0,0 @@
-// Copyright 2015 go-swagger maintainers
-//
-// 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 swag
-
-import (
- "reflect"
- "strings"
- "unicode"
- "unicode/utf8"
-)
-
-// GoNamePrefixFunc sets an optional rule to prefix go names
-// which do not start with a letter.
-//
-// The prefix function is assumed to return a string that starts with an upper case letter.
-//
-// e.g. to help convert "123" into "{prefix}123"
-//
-// The default is to prefix with "X"
-var GoNamePrefixFunc func(string) string
-
-func prefixFunc(name, in string) string {
- if GoNamePrefixFunc == nil {
- return "X" + in
- }
-
- return GoNamePrefixFunc(name) + in
-}
-
-const (
- // collectionFormatComma = "csv"
- collectionFormatSpace = "ssv"
- collectionFormatTab = "tsv"
- collectionFormatPipe = "pipes"
- collectionFormatMulti = "multi"
-)
-
-// JoinByFormat joins a string array by a known format (e.g. swagger's collectionFormat attribute):
-//
-// ssv: space separated value
-// tsv: tab separated value
-// pipes: pipe (|) separated value
-// csv: comma separated value (default)
-func JoinByFormat(data []string, format string) []string {
- if len(data) == 0 {
- return data
- }
- var sep string
- switch format {
- case collectionFormatSpace:
- sep = " "
- case collectionFormatTab:
- sep = "\t"
- case collectionFormatPipe:
- sep = "|"
- case collectionFormatMulti:
- return data
- default:
- sep = ","
- }
- return []string{strings.Join(data, sep)}
-}
-
-// SplitByFormat splits a string by a known format:
-//
-// ssv: space separated value
-// tsv: tab separated value
-// pipes: pipe (|) separated value
-// csv: comma separated value (default)
-func SplitByFormat(data, format string) []string {
- if data == "" {
- return nil
- }
- var sep string
- switch format {
- case collectionFormatSpace:
- sep = " "
- case collectionFormatTab:
- sep = "\t"
- case collectionFormatPipe:
- sep = "|"
- case collectionFormatMulti:
- return nil
- default:
- sep = ","
- }
- var result []string
- for _, s := range strings.Split(data, sep) {
- if ts := strings.TrimSpace(s); ts != "" {
- result = append(result, ts)
- }
- }
- return result
-}
-
-// Removes leading whitespaces
-func trim(str string) string {
- return strings.TrimSpace(str)
-}
-
-// Shortcut to strings.ToUpper()
-func upper(str string) string {
- return strings.ToUpper(trim(str))
-}
-
-// Shortcut to strings.ToLower()
-func lower(str string) string {
- return strings.ToLower(trim(str))
-}
-
-// Camelize an uppercased word
-func Camelize(word string) string {
- camelized := poolOfBuffers.BorrowBuffer(len(word))
- defer func() {
- poolOfBuffers.RedeemBuffer(camelized)
- }()
-
- for pos, ru := range []rune(word) {
- if pos > 0 {
- camelized.WriteRune(unicode.ToLower(ru))
- } else {
- camelized.WriteRune(unicode.ToUpper(ru))
- }
- }
- return camelized.String()
-}
-
-// ToFileName lowercases and underscores a go type name
-func ToFileName(name string) string {
- in := split(name)
- out := make([]string, 0, len(in))
-
- for _, w := range in {
- out = append(out, lower(w))
- }
-
- return strings.Join(out, "_")
-}
-
-// ToCommandName lowercases and underscores a go type name
-func ToCommandName(name string) string {
- in := split(name)
- out := make([]string, 0, len(in))
-
- for _, w := range in {
- out = append(out, lower(w))
- }
- return strings.Join(out, "-")
-}
-
-// ToHumanNameLower represents a code name as a human series of words
-func ToHumanNameLower(name string) string {
- s := poolOfSplitters.BorrowSplitter(withPostSplitInitialismCheck)
- in := s.split(name)
- poolOfSplitters.RedeemSplitter(s)
- out := make([]string, 0, len(*in))
-
- for _, w := range *in {
- if !w.IsInitialism() {
- out = append(out, lower(w.GetOriginal()))
- } else {
- out = append(out, trim(w.GetOriginal()))
- }
- }
- poolOfLexems.RedeemLexems(in)
-
- return strings.Join(out, " ")
-}
-
-// ToHumanNameTitle represents a code name as a human series of words with the first letters titleized
-func ToHumanNameTitle(name string) string {
- s := poolOfSplitters.BorrowSplitter(withPostSplitInitialismCheck)
- in := s.split(name)
- poolOfSplitters.RedeemSplitter(s)
-
- out := make([]string, 0, len(*in))
- for _, w := range *in {
- original := trim(w.GetOriginal())
- if !w.IsInitialism() {
- out = append(out, Camelize(original))
- } else {
- out = append(out, original)
- }
- }
- poolOfLexems.RedeemLexems(in)
-
- return strings.Join(out, " ")
-}
-
-// ToJSONName camelcases a name which can be underscored or pascal cased
-func ToJSONName(name string) string {
- in := split(name)
- out := make([]string, 0, len(in))
-
- for i, w := range in {
- if i == 0 {
- out = append(out, lower(w))
- continue
- }
- out = append(out, Camelize(trim(w)))
- }
- return strings.Join(out, "")
-}
-
-// ToVarName camelcases a name which can be underscored or pascal cased
-func ToVarName(name string) string {
- res := ToGoName(name)
- if isInitialism(res) {
- return lower(res)
- }
- if len(res) <= 1 {
- return lower(res)
- }
- return lower(res[:1]) + res[1:]
-}
-
-// ToGoName translates a swagger name which can be underscored or camel cased to a name that golint likes
-func ToGoName(name string) string {
- s := poolOfSplitters.BorrowSplitter(withPostSplitInitialismCheck)
- lexems := s.split(name)
- poolOfSplitters.RedeemSplitter(s)
- defer func() {
- poolOfLexems.RedeemLexems(lexems)
- }()
- lexemes := *lexems
-
- if len(lexemes) == 0 {
- return ""
- }
-
- result := poolOfBuffers.BorrowBuffer(len(name))
- defer func() {
- poolOfBuffers.RedeemBuffer(result)
- }()
-
- // check if not starting with a letter, upper case
- firstPart := lexemes[0].GetUnsafeGoName()
- if lexemes[0].IsInitialism() {
- firstPart = upper(firstPart)
- }
-
- if c := firstPart[0]; c < utf8.RuneSelf {
- // ASCII
- switch {
- case 'A' <= c && c <= 'Z':
- result.WriteString(firstPart)
- case 'a' <= c && c <= 'z':
- result.WriteByte(c - 'a' + 'A')
- result.WriteString(firstPart[1:])
- default:
- result.WriteString(prefixFunc(name, firstPart))
- // NOTE: no longer check if prefixFunc returns a string that starts with uppercase:
- // assume this is always the case
- }
- } else {
- // unicode
- firstRune, _ := utf8.DecodeRuneInString(firstPart)
- switch {
- case !unicode.IsLetter(firstRune):
- result.WriteString(prefixFunc(name, firstPart))
- case !unicode.IsUpper(firstRune):
- result.WriteString(prefixFunc(name, firstPart))
- /*
- result.WriteRune(unicode.ToUpper(firstRune))
- result.WriteString(firstPart[offset:])
- */
- default:
- result.WriteString(firstPart)
- }
- }
-
- for _, lexem := range lexemes[1:] {
- goName := lexem.GetUnsafeGoName()
-
- // to support old behavior
- if lexem.IsInitialism() {
- goName = upper(goName)
- }
- result.WriteString(goName)
- }
-
- return result.String()
-}
-
-// ContainsStrings searches a slice of strings for a case-sensitive match
-func ContainsStrings(coll []string, item string) bool {
- for _, a := range coll {
- if a == item {
- return true
- }
- }
- return false
-}
-
-// ContainsStringsCI searches a slice of strings for a case-insensitive match
-func ContainsStringsCI(coll []string, item string) bool {
- for _, a := range coll {
- if strings.EqualFold(a, item) {
- return true
- }
- }
- return false
-}
-
-type zeroable interface {
- IsZero() bool
-}
-
-// IsZero returns true when the value passed into the function is a zero value.
-// This allows for safer checking of interface values.
-func IsZero(data interface{}) bool {
- v := reflect.ValueOf(data)
- // check for nil data
- switch v.Kind() { //nolint:exhaustive
- case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
- if v.IsNil() {
- return true
- }
- }
-
- // check for things that have an IsZero method instead
- if vv, ok := data.(zeroable); ok {
- return vv.IsZero()
- }
-
- // continue with slightly more complex reflection
- switch v.Kind() { //nolint:exhaustive
- case 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.Struct, reflect.Array:
- return reflect.DeepEqual(data, reflect.Zero(v.Type()).Interface())
- case reflect.Invalid:
- return true
- default:
- return false
- }
-}
-
-// CommandLineOptionsGroup represents a group of user-defined command line options
-type CommandLineOptionsGroup struct {
- ShortDescription string
- LongDescription string
- Options interface{}
-}
diff --git a/vendor/github.com/go-openapi/swag/yaml.go b/vendor/github.com/go-openapi/swag/yaml.go
deleted file mode 100644
index 575346539a..0000000000
--- a/vendor/github.com/go-openapi/swag/yaml.go
+++ /dev/null
@@ -1,481 +0,0 @@
-// Copyright 2015 go-swagger maintainers
-//
-// 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 swag
-
-import (
- "encoding/json"
- "fmt"
- "path/filepath"
- "reflect"
- "sort"
- "strconv"
-
- "github.com/mailru/easyjson/jlexer"
- "github.com/mailru/easyjson/jwriter"
- yaml "gopkg.in/yaml.v3"
-)
-
-// YAMLMatcher matches yaml
-func YAMLMatcher(path string) bool {
- ext := filepath.Ext(path)
- return ext == ".yaml" || ext == ".yml"
-}
-
-// YAMLToJSON converts YAML unmarshaled data into json compatible data
-func YAMLToJSON(data interface{}) (json.RawMessage, error) {
- jm, err := transformData(data)
- if err != nil {
- return nil, err
- }
- b, err := WriteJSON(jm)
- return json.RawMessage(b), err
-}
-
-// BytesToYAMLDoc converts a byte slice into a YAML document
-func BytesToYAMLDoc(data []byte) (interface{}, error) {
- var document yaml.Node // preserve order that is present in the document
- if err := yaml.Unmarshal(data, &document); err != nil {
- return nil, err
- }
- if document.Kind != yaml.DocumentNode || len(document.Content) != 1 || document.Content[0].Kind != yaml.MappingNode {
- return nil, fmt.Errorf("only YAML documents that are objects are supported: %w", ErrYAML)
- }
- return &document, nil
-}
-
-func yamlNode(root *yaml.Node) (interface{}, error) {
- switch root.Kind {
- case yaml.DocumentNode:
- return yamlDocument(root)
- case yaml.SequenceNode:
- return yamlSequence(root)
- case yaml.MappingNode:
- return yamlMapping(root)
- case yaml.ScalarNode:
- return yamlScalar(root)
- case yaml.AliasNode:
- return yamlNode(root.Alias)
- default:
- return nil, fmt.Errorf("unsupported YAML node type: %v: %w", root.Kind, ErrYAML)
- }
-}
-
-func yamlDocument(node *yaml.Node) (interface{}, error) {
- if len(node.Content) != 1 {
- return nil, fmt.Errorf("unexpected YAML Document node content length: %d: %w", len(node.Content), ErrYAML)
- }
- return yamlNode(node.Content[0])
-}
-
-func yamlMapping(node *yaml.Node) (interface{}, error) {
- const sensibleAllocDivider = 2
- m := make(JSONMapSlice, len(node.Content)/sensibleAllocDivider)
-
- var j int
- for i := 0; i < len(node.Content); i += 2 {
- var nmi JSONMapItem
- k, err := yamlStringScalarC(node.Content[i])
- if err != nil {
- return nil, fmt.Errorf("unable to decode YAML map key: %w: %w", err, ErrYAML)
- }
- nmi.Key = k
- v, err := yamlNode(node.Content[i+1])
- if err != nil {
- return nil, fmt.Errorf("unable to process YAML map value for key %q: %w: %w", k, err, ErrYAML)
- }
- nmi.Value = v
- m[j] = nmi
- j++
- }
- return m, nil
-}
-
-func yamlSequence(node *yaml.Node) (interface{}, error) {
- s := make([]interface{}, 0)
-
- for i := 0; i < len(node.Content); i++ {
-
- v, err := yamlNode(node.Content[i])
- if err != nil {
- return nil, fmt.Errorf("unable to decode YAML sequence value: %w: %w", err, ErrYAML)
- }
- s = append(s, v)
- }
- return s, nil
-}
-
-const ( // See https://yaml.org/type/
- yamlStringScalar = "tag:yaml.org,2002:str"
- yamlIntScalar = "tag:yaml.org,2002:int"
- yamlBoolScalar = "tag:yaml.org,2002:bool"
- yamlFloatScalar = "tag:yaml.org,2002:float"
- yamlTimestamp = "tag:yaml.org,2002:timestamp"
- yamlNull = "tag:yaml.org,2002:null"
-)
-
-func yamlScalar(node *yaml.Node) (interface{}, error) {
- switch node.LongTag() {
- case yamlStringScalar:
- return node.Value, nil
- case yamlBoolScalar:
- b, err := strconv.ParseBool(node.Value)
- if err != nil {
- return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting bool content: %w: %w", node.Value, err, ErrYAML)
- }
- return b, nil
- case yamlIntScalar:
- i, err := strconv.ParseInt(node.Value, 10, 64)
- if err != nil {
- return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting integer content: %w: %w", node.Value, err, ErrYAML)
- }
- return i, nil
- case yamlFloatScalar:
- f, err := strconv.ParseFloat(node.Value, 64)
- if err != nil {
- return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting float content: %w: %w", node.Value, err, ErrYAML)
- }
- return f, nil
- case yamlTimestamp:
- return node.Value, nil
- case yamlNull:
- return nil, nil //nolint:nilnil
- default:
- return nil, fmt.Errorf("YAML tag %q is not supported: %w", node.LongTag(), ErrYAML)
- }
-}
-
-func yamlStringScalarC(node *yaml.Node) (string, error) {
- if node.Kind != yaml.ScalarNode {
- return "", fmt.Errorf("expecting a string scalar but got %q: %w", node.Kind, ErrYAML)
- }
- switch node.LongTag() {
- case yamlStringScalar, yamlIntScalar, yamlFloatScalar:
- return node.Value, nil
- default:
- return "", fmt.Errorf("YAML tag %q is not supported as map key: %w", node.LongTag(), ErrYAML)
- }
-}
-
-// JSONMapSlice represent a JSON object, with the order of keys maintained
-type JSONMapSlice []JSONMapItem
-
-// MarshalJSON renders a JSONMapSlice as JSON
-func (s JSONMapSlice) MarshalJSON() ([]byte, error) {
- w := &jwriter.Writer{Flags: jwriter.NilMapAsEmpty | jwriter.NilSliceAsEmpty}
- s.MarshalEasyJSON(w)
- return w.BuildBytes()
-}
-
-// MarshalEasyJSON renders a JSONMapSlice as JSON, using easyJSON
-func (s JSONMapSlice) MarshalEasyJSON(w *jwriter.Writer) {
- w.RawByte('{')
-
- ln := len(s)
- last := ln - 1
- for i := 0; i < ln; i++ {
- s[i].MarshalEasyJSON(w)
- if i != last { // last item
- w.RawByte(',')
- }
- }
-
- w.RawByte('}')
-}
-
-// UnmarshalJSON makes a JSONMapSlice from JSON
-func (s *JSONMapSlice) UnmarshalJSON(data []byte) error {
- l := jlexer.Lexer{Data: data}
- s.UnmarshalEasyJSON(&l)
- return l.Error()
-}
-
-// UnmarshalEasyJSON makes a JSONMapSlice from JSON, using easyJSON
-func (s *JSONMapSlice) UnmarshalEasyJSON(in *jlexer.Lexer) {
- if in.IsNull() {
- in.Skip()
- return
- }
-
- var result JSONMapSlice
- in.Delim('{')
- for !in.IsDelim('}') {
- var mi JSONMapItem
- mi.UnmarshalEasyJSON(in)
- result = append(result, mi)
- }
- *s = result
-}
-
-func (s JSONMapSlice) MarshalYAML() (interface{}, error) {
- var n yaml.Node
- n.Kind = yaml.DocumentNode
- var nodes []*yaml.Node
- for _, item := range s {
- nn, err := json2yaml(item.Value)
- if err != nil {
- return nil, err
- }
- ns := []*yaml.Node{
- {
- Kind: yaml.ScalarNode,
- Tag: yamlStringScalar,
- Value: item.Key,
- },
- nn,
- }
- nodes = append(nodes, ns...)
- }
-
- n.Content = []*yaml.Node{
- {
- Kind: yaml.MappingNode,
- Content: nodes,
- },
- }
-
- return yaml.Marshal(&n)
-}
-
-func isNil(input interface{}) bool {
- if input == nil {
- return true
- }
- kind := reflect.TypeOf(input).Kind()
- switch kind { //nolint:exhaustive
- case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Chan:
- return reflect.ValueOf(input).IsNil()
- default:
- return false
- }
-}
-
-func json2yaml(item interface{}) (*yaml.Node, error) {
- if isNil(item) {
- return &yaml.Node{
- Kind: yaml.ScalarNode,
- Value: "null",
- }, nil
- }
-
- switch val := item.(type) {
- case JSONMapSlice:
- var n yaml.Node
- n.Kind = yaml.MappingNode
- for i := range val {
- childNode, err := json2yaml(&val[i].Value)
- if err != nil {
- return nil, err
- }
- n.Content = append(n.Content, &yaml.Node{
- Kind: yaml.ScalarNode,
- Tag: yamlStringScalar,
- Value: val[i].Key,
- }, childNode)
- }
- return &n, nil
- case map[string]interface{}:
- var n yaml.Node
- n.Kind = yaml.MappingNode
- keys := make([]string, 0, len(val))
- for k := range val {
- keys = append(keys, k)
- }
- sort.Strings(keys)
-
- for _, k := range keys {
- v := val[k]
- childNode, err := json2yaml(v)
- if err != nil {
- return nil, err
- }
- n.Content = append(n.Content, &yaml.Node{
- Kind: yaml.ScalarNode,
- Tag: yamlStringScalar,
- Value: k,
- }, childNode)
- }
- return &n, nil
- case []interface{}:
- var n yaml.Node
- n.Kind = yaml.SequenceNode
- for i := range val {
- childNode, err := json2yaml(val[i])
- if err != nil {
- return nil, err
- }
- n.Content = append(n.Content, childNode)
- }
- return &n, nil
- case string:
- return &yaml.Node{
- Kind: yaml.ScalarNode,
- Tag: yamlStringScalar,
- Value: val,
- }, nil
- case float64:
- return &yaml.Node{
- Kind: yaml.ScalarNode,
- Tag: yamlFloatScalar,
- Value: strconv.FormatFloat(val, 'f', -1, 64),
- }, nil
- case int64:
- return &yaml.Node{
- Kind: yaml.ScalarNode,
- Tag: yamlIntScalar,
- Value: strconv.FormatInt(val, 10),
- }, nil
- case uint64:
- return &yaml.Node{
- Kind: yaml.ScalarNode,
- Tag: yamlIntScalar,
- Value: strconv.FormatUint(val, 10),
- }, nil
- case bool:
- return &yaml.Node{
- Kind: yaml.ScalarNode,
- Tag: yamlBoolScalar,
- Value: strconv.FormatBool(val),
- }, nil
- default:
- return nil, fmt.Errorf("unhandled type: %T: %w", val, ErrYAML)
- }
-}
-
-// JSONMapItem represents the value of a key in a JSON object held by JSONMapSlice
-type JSONMapItem struct {
- Key string
- Value interface{}
-}
-
-// MarshalJSON renders a JSONMapItem as JSON
-func (s JSONMapItem) MarshalJSON() ([]byte, error) {
- w := &jwriter.Writer{Flags: jwriter.NilMapAsEmpty | jwriter.NilSliceAsEmpty}
- s.MarshalEasyJSON(w)
- return w.BuildBytes()
-}
-
-// MarshalEasyJSON renders a JSONMapItem as JSON, using easyJSON
-func (s JSONMapItem) MarshalEasyJSON(w *jwriter.Writer) {
- w.String(s.Key)
- w.RawByte(':')
- w.Raw(WriteJSON(s.Value))
-}
-
-// UnmarshalJSON makes a JSONMapItem from JSON
-func (s *JSONMapItem) UnmarshalJSON(data []byte) error {
- l := jlexer.Lexer{Data: data}
- s.UnmarshalEasyJSON(&l)
- return l.Error()
-}
-
-// UnmarshalEasyJSON makes a JSONMapItem from JSON, using easyJSON
-func (s *JSONMapItem) UnmarshalEasyJSON(in *jlexer.Lexer) {
- key := in.UnsafeString()
- in.WantColon()
- value := in.Interface()
- in.WantComma()
- s.Key = key
- s.Value = value
-}
-
-func transformData(input interface{}) (out interface{}, err error) {
- format := func(t interface{}) (string, error) {
- switch k := t.(type) {
- case string:
- return k, nil
- case uint:
- return strconv.FormatUint(uint64(k), 10), nil
- case uint8:
- return strconv.FormatUint(uint64(k), 10), nil
- case uint16:
- return strconv.FormatUint(uint64(k), 10), nil
- case uint32:
- return strconv.FormatUint(uint64(k), 10), nil
- case uint64:
- return strconv.FormatUint(k, 10), nil
- case int:
- return strconv.Itoa(k), nil
- case int8:
- return strconv.FormatInt(int64(k), 10), nil
- case int16:
- return strconv.FormatInt(int64(k), 10), nil
- case int32:
- return strconv.FormatInt(int64(k), 10), nil
- case int64:
- return strconv.FormatInt(k, 10), nil
- default:
- return "", fmt.Errorf("unexpected map key type, got: %T: %w", k, ErrYAML)
- }
- }
-
- switch in := input.(type) {
- case yaml.Node:
- return yamlNode(&in)
- case *yaml.Node:
- return yamlNode(in)
- case map[interface{}]interface{}:
- o := make(JSONMapSlice, 0, len(in))
- for ke, va := range in {
- var nmi JSONMapItem
- if nmi.Key, err = format(ke); err != nil {
- return nil, err
- }
-
- v, ert := transformData(va)
- if ert != nil {
- return nil, ert
- }
- nmi.Value = v
- o = append(o, nmi)
- }
- return o, nil
- case []interface{}:
- len1 := len(in)
- o := make([]interface{}, len1)
- for i := 0; i < len1; i++ {
- o[i], err = transformData(in[i])
- if err != nil {
- return nil, err
- }
- }
- return o, nil
- }
- return input, nil
-}
-
-// YAMLDoc loads a yaml document from either http or a file and converts it to json
-func YAMLDoc(path string) (json.RawMessage, error) {
- yamlDoc, err := YAMLData(path)
- if err != nil {
- return nil, err
- }
-
- data, err := YAMLToJSON(yamlDoc)
- if err != nil {
- return nil, err
- }
-
- return data, nil
-}
-
-// YAMLData loads a yaml document from either http or a file
-func YAMLData(path string) (interface{}, error) {
- data, err := LoadFromFileOrHTTP(path)
- if err != nil {
- return nil, err
- }
-
- return BytesToYAMLDoc(data)
-}
diff --git a/vendor/github.com/go-openapi/swag/yamlutils/LICENSE b/vendor/github.com/go-openapi/swag/yamlutils/LICENSE
new file mode 100644
index 0000000000..d645695673
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/yamlutils/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/vendor/github.com/go-openapi/swag/yamlutils/doc.go b/vendor/github.com/go-openapi/swag/yamlutils/doc.go
new file mode 100644
index 0000000000..7bb92a82f1
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/yamlutils/doc.go
@@ -0,0 +1,13 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+// Package yamlutils provides utilities to work with YAML documents.
+//
+// - [BytesToYAMLDoc] to construct a [yaml.Node] document
+// - [YAMLToJSON] to convert a [yaml.Node] document to JSON bytes
+// - [YAMLMapSlice] to serialize and deserialize YAML with the order of keys maintained
+package yamlutils
+
+import (
+ _ "go.yaml.in/yaml/v3" // for documentation purpose only
+)
diff --git a/vendor/github.com/go-openapi/swag/yamlutils/errors.go b/vendor/github.com/go-openapi/swag/yamlutils/errors.go
new file mode 100644
index 0000000000..e87bc5e8be
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/yamlutils/errors.go
@@ -0,0 +1,15 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package yamlutils
+
+type yamlError string
+
+const (
+ // ErrYAML is an error raised by YAML utilities
+ ErrYAML yamlError = "yaml error"
+)
+
+func (e yamlError) Error() string {
+ return string(e)
+}
diff --git a/vendor/github.com/go-openapi/swag/yamlutils/ordered_map.go b/vendor/github.com/go-openapi/swag/yamlutils/ordered_map.go
new file mode 100644
index 0000000000..3daf68dbba
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/yamlutils/ordered_map.go
@@ -0,0 +1,316 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package yamlutils
+
+import (
+ "fmt"
+ "iter"
+ "slices"
+ "sort"
+ "strconv"
+
+ "github.com/go-openapi/swag/conv"
+ "github.com/go-openapi/swag/jsonutils"
+ "github.com/go-openapi/swag/jsonutils/adapters/ifaces"
+ "github.com/go-openapi/swag/typeutils"
+ yaml "go.yaml.in/yaml/v3"
+)
+
+var (
+ _ yaml.Marshaler = YAMLMapSlice{}
+ _ yaml.Unmarshaler = &YAMLMapSlice{}
+)
+
+// YAMLMapSlice represents a YAML object, with the order of keys maintained.
+//
+// It is similar to [jsonutils.JSONMapSlice] and also knows how to marshal and unmarshal YAML.
+//
+// It behaves like an ordered map, but keys can't be accessed in constant time.
+type YAMLMapSlice []YAMLMapItem
+
+// YAMLMapItem represents the value of a key in a YAML object held by [YAMLMapSlice].
+//
+// It is entirely equivalent to [jsonutils.JSONMapItem], with the same limitation that
+// you should not Marshal or Unmarshal directly this type, outside of a [YAMLMapSlice].
+type YAMLMapItem = jsonutils.JSONMapItem
+
+func (s YAMLMapSlice) OrderedItems() iter.Seq2[string, any] {
+ return func(yield func(string, any) bool) {
+ for _, item := range s {
+ if !yield(item.Key, item.Value) {
+ return
+ }
+ }
+ }
+}
+
+// SetOrderedItems implements [ifaces.SetOrdered]: it merges keys passed by the iterator argument
+// into the [YAMLMapSlice].
+func (s *YAMLMapSlice) SetOrderedItems(items iter.Seq2[string, any]) {
+ if items == nil {
+ // force receiver to be a nil slice
+ *s = nil
+
+ return
+ }
+
+ m := *s
+ if len(m) > 0 {
+ // update mode: short-circuited when unmarshaling fresh data structures
+ idx := make(map[string]int, len(m))
+
+ for i, item := range m {
+ idx[item.Key] = i
+ }
+
+ for k, v := range items {
+ idx, ok := idx[k]
+ if ok {
+ m[idx].Value = v
+
+ continue
+ }
+
+ m = append(m, YAMLMapItem{Key: k, Value: v})
+ }
+
+ *s = m
+
+ return
+ }
+
+ for k, v := range items {
+ m = append(m, YAMLMapItem{Key: k, Value: v})
+ }
+
+ *s = m
+}
+
+// MarshalJSON renders this YAML object as JSON bytes.
+//
+// The difference with standard JSON marshaling is that the order of keys is maintained.
+func (s YAMLMapSlice) MarshalJSON() ([]byte, error) {
+ return jsonutils.JSONMapSlice(s).MarshalJSON()
+}
+
+// UnmarshalJSON builds this YAML object from JSON bytes.
+//
+// The difference with standard JSON marshaling is that the order of keys is maintained.
+func (s *YAMLMapSlice) UnmarshalJSON(data []byte) error {
+ js := jsonutils.JSONMapSlice(*s)
+
+ if err := js.UnmarshalJSON(data); err != nil {
+ return err
+ }
+
+ *s = YAMLMapSlice(js)
+
+ return nil
+}
+
+// MarshalYAML produces a YAML document as bytes
+//
+// The difference with standard YAML marshaling is that the order of keys is maintained.
+//
+// It implements [yaml.Marshaler].
+func (s YAMLMapSlice) MarshalYAML() (any, error) {
+ if typeutils.IsNil(s) {
+ return []byte("null\n"), nil
+ }
+ var n yaml.Node
+ n.Kind = yaml.DocumentNode
+ var nodes []*yaml.Node
+
+ for _, item := range s {
+ nn, err := json2yaml(item.Value)
+ if err != nil {
+ return nil, err
+ }
+
+ ns := []*yaml.Node{
+ {
+ Kind: yaml.ScalarNode,
+ Tag: yamlStringScalar,
+ Value: item.Key,
+ },
+ nn,
+ }
+ nodes = append(nodes, ns...)
+ }
+
+ n.Content = []*yaml.Node{
+ {
+ Kind: yaml.MappingNode,
+ Content: nodes,
+ },
+ }
+
+ return yaml.Marshal(&n)
+}
+
+// UnmarshalYAML builds a YAMLMapSlice object from a YAML document [yaml.Node].
+//
+// It implements [yaml.Unmarshaler].
+func (s *YAMLMapSlice) UnmarshalYAML(node *yaml.Node) error {
+ if typeutils.IsNil(*s) {
+ // allow to unmarshal with a simple var declaration (nil slice)
+ *s = YAMLMapSlice{}
+ }
+ if node == nil {
+ *s = nil
+ return nil
+ }
+
+ const sensibleAllocDivider = 2
+ m := slices.Grow(*s, len(node.Content)/sensibleAllocDivider)
+ m = m[:0]
+
+ for i := 0; i < len(node.Content); i += 2 {
+ var nmi YAMLMapItem
+ k, err := yamlStringScalarC(node.Content[i])
+ if err != nil {
+ return fmt.Errorf("unable to decode YAML map key: %w: %w", err, ErrYAML)
+ }
+ nmi.Key = k
+ v, err := yamlNode(node.Content[i+1])
+ if err != nil {
+ return fmt.Errorf("unable to process YAML map value for key %q: %w: %w", k, err, ErrYAML)
+ }
+ nmi.Value = v
+ m = append(m, nmi)
+ }
+
+ *s = m
+
+ return nil
+}
+
+func json2yaml(item any) (*yaml.Node, error) {
+ if typeutils.IsNil(item) {
+ return &yaml.Node{
+ Kind: yaml.ScalarNode,
+ Value: "null",
+ }, nil
+ }
+
+ switch val := item.(type) {
+ case ifaces.Ordered:
+ return orderedYAML(val)
+
+ case map[string]any:
+ var n yaml.Node
+ n.Kind = yaml.MappingNode
+ keys := make([]string, 0, len(val))
+ for k := range val {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+
+ for _, k := range keys {
+ v := val[k]
+ childNode, err := json2yaml(v)
+ if err != nil {
+ return nil, err
+ }
+ n.Content = append(n.Content, &yaml.Node{
+ Kind: yaml.ScalarNode,
+ Tag: yamlStringScalar,
+ Value: k,
+ }, childNode)
+ }
+ return &n, nil
+
+ case []any:
+ var n yaml.Node
+ n.Kind = yaml.SequenceNode
+ for i := range val {
+ childNode, err := json2yaml(val[i])
+ if err != nil {
+ return nil, err
+ }
+ n.Content = append(n.Content, childNode)
+ }
+ return &n, nil
+ case string:
+ return &yaml.Node{
+ Kind: yaml.ScalarNode,
+ Tag: yamlStringScalar,
+ Value: val,
+ }, nil
+ case float32:
+ return floatNode(val)
+ case float64:
+ return floatNode(val)
+ case int:
+ return integerNode(val)
+ case int8:
+ return integerNode(val)
+ case int16:
+ return integerNode(val)
+ case int32:
+ return integerNode(val)
+ case int64:
+ return integerNode(val)
+ case uint:
+ return uintegerNode(val)
+ case uint8:
+ return uintegerNode(val)
+ case uint16:
+ return uintegerNode(val)
+ case uint32:
+ return uintegerNode(val)
+ case uint64:
+ return uintegerNode(val)
+ case bool:
+ return &yaml.Node{
+ Kind: yaml.ScalarNode,
+ Tag: yamlBoolScalar,
+ Value: strconv.FormatBool(val),
+ }, nil
+ default:
+ return nil, fmt.Errorf("unhandled type: %T: %w", val, ErrYAML)
+ }
+}
+
+func floatNode[T conv.Float](val T) (*yaml.Node, error) {
+ return &yaml.Node{
+ Kind: yaml.ScalarNode,
+ Tag: yamlFloatScalar,
+ Value: conv.FormatFloat(val),
+ }, nil
+}
+
+func integerNode[T conv.Signed](val T) (*yaml.Node, error) {
+ return &yaml.Node{
+ Kind: yaml.ScalarNode,
+ Tag: yamlIntScalar,
+ Value: conv.FormatInteger(val),
+ }, nil
+}
+
+func uintegerNode[T conv.Unsigned](val T) (*yaml.Node, error) {
+ return &yaml.Node{
+ Kind: yaml.ScalarNode,
+ Tag: yamlIntScalar,
+ Value: conv.FormatUinteger(val),
+ }, nil
+}
+
+func orderedYAML[T ifaces.Ordered](val T) (*yaml.Node, error) {
+ var n yaml.Node
+ n.Kind = yaml.MappingNode
+ for key, value := range val.OrderedItems() {
+ childNode, err := json2yaml(value)
+ if err != nil {
+ return nil, err
+ }
+
+ n.Content = append(n.Content, &yaml.Node{
+ Kind: yaml.ScalarNode,
+ Tag: yamlStringScalar,
+ Value: key,
+ }, childNode)
+ }
+ return &n, nil
+}
diff --git a/vendor/github.com/go-openapi/swag/yamlutils/yaml.go b/vendor/github.com/go-openapi/swag/yamlutils/yaml.go
new file mode 100644
index 0000000000..e3aff3c2fd
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/yamlutils/yaml.go
@@ -0,0 +1,211 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package yamlutils
+
+import (
+ json "encoding/json"
+ "fmt"
+ "strconv"
+
+ "github.com/go-openapi/swag/jsonutils"
+ yaml "go.yaml.in/yaml/v3"
+)
+
+// YAMLToJSON converts a YAML document into JSON bytes.
+//
+// Note: a YAML document is the output from a [yaml.Marshaler], e.g a pointer to a [yaml.Node].
+//
+// [YAMLToJSON] is typically called after [BytesToYAMLDoc].
+func YAMLToJSON(value any) (json.RawMessage, error) {
+ jm, err := transformData(value)
+ if err != nil {
+ return nil, err
+ }
+
+ b, err := jsonutils.WriteJSON(jm)
+
+ return json.RawMessage(b), err
+}
+
+// BytesToYAMLDoc converts a byte slice into a YAML document.
+//
+// This function only supports root documents that are objects.
+//
+// A YAML document is a pointer to a [yaml.Node].
+func BytesToYAMLDoc(data []byte) (any, error) {
+ var document yaml.Node // preserve order that is present in the document
+ if err := yaml.Unmarshal(data, &document); err != nil {
+ return nil, err
+ }
+ if document.Kind != yaml.DocumentNode || len(document.Content) != 1 || document.Content[0].Kind != yaml.MappingNode {
+ return nil, fmt.Errorf("only YAML documents that are objects are supported: %w", ErrYAML)
+ }
+ return &document, nil
+}
+
+func yamlNode(root *yaml.Node) (any, error) {
+ switch root.Kind {
+ case yaml.DocumentNode:
+ return yamlDocument(root)
+ case yaml.SequenceNode:
+ return yamlSequence(root)
+ case yaml.MappingNode:
+ return yamlMapping(root)
+ case yaml.ScalarNode:
+ return yamlScalar(root)
+ case yaml.AliasNode:
+ return yamlNode(root.Alias)
+ default:
+ return nil, fmt.Errorf("unsupported YAML node type: %v: %w", root.Kind, ErrYAML)
+ }
+}
+
+func yamlDocument(node *yaml.Node) (any, error) {
+ if len(node.Content) != 1 {
+ return nil, fmt.Errorf("unexpected YAML Document node content length: %d: %w", len(node.Content), ErrYAML)
+ }
+ return yamlNode(node.Content[0])
+}
+
+func yamlMapping(node *yaml.Node) (any, error) {
+ const sensibleAllocDivider = 2 // nodes concatenate (key,value) sequences
+ m := make(YAMLMapSlice, len(node.Content)/sensibleAllocDivider)
+
+ if err := m.UnmarshalYAML(node); err != nil {
+ return nil, err
+ }
+
+ return m, nil
+}
+
+func yamlSequence(node *yaml.Node) (any, error) {
+ s := make([]any, 0)
+
+ for i := range len(node.Content) {
+ v, err := yamlNode(node.Content[i])
+ if err != nil {
+ return nil, fmt.Errorf("unable to decode YAML sequence value: %w: %w", err, ErrYAML)
+ }
+ s = append(s, v)
+ }
+ return s, nil
+}
+
+const ( // See https://yaml.org/type/
+ yamlStringScalar = "tag:yaml.org,2002:str"
+ yamlIntScalar = "tag:yaml.org,2002:int"
+ yamlBoolScalar = "tag:yaml.org,2002:bool"
+ yamlFloatScalar = "tag:yaml.org,2002:float"
+ yamlTimestamp = "tag:yaml.org,2002:timestamp"
+ yamlNull = "tag:yaml.org,2002:null"
+)
+
+func yamlScalar(node *yaml.Node) (any, error) {
+ switch node.LongTag() {
+ case yamlStringScalar:
+ return node.Value, nil
+ case yamlBoolScalar:
+ b, err := strconv.ParseBool(node.Value)
+ if err != nil {
+ return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting bool content: %w: %w", node.Value, err, ErrYAML)
+ }
+ return b, nil
+ case yamlIntScalar:
+ i, err := strconv.ParseInt(node.Value, 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting integer content: %w: %w", node.Value, err, ErrYAML)
+ }
+ return i, nil
+ case yamlFloatScalar:
+ f, err := strconv.ParseFloat(node.Value, 64)
+ if err != nil {
+ return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting float content: %w: %w", node.Value, err, ErrYAML)
+ }
+ return f, nil
+ case yamlTimestamp:
+ // YAML timestamp is marshaled as string, not time
+ return node.Value, nil
+ case yamlNull:
+ return nil, nil //nolint:nilnil
+ default:
+ return nil, fmt.Errorf("YAML tag %q is not supported: %w", node.LongTag(), ErrYAML)
+ }
+}
+
+func yamlStringScalarC(node *yaml.Node) (string, error) {
+ if node.Kind != yaml.ScalarNode {
+ return "", fmt.Errorf("expecting a string scalar but got %q: %w", node.Kind, ErrYAML)
+ }
+ switch node.LongTag() {
+ case yamlStringScalar, yamlIntScalar, yamlFloatScalar:
+ return node.Value, nil
+ default:
+ return "", fmt.Errorf("YAML tag %q is not supported as map key: %w", node.LongTag(), ErrYAML)
+ }
+}
+
+func format(t any) (string, error) {
+ switch k := t.(type) {
+ case string:
+ return k, nil
+ case uint:
+ return strconv.FormatUint(uint64(k), 10), nil
+ case uint8:
+ return strconv.FormatUint(uint64(k), 10), nil
+ case uint16:
+ return strconv.FormatUint(uint64(k), 10), nil
+ case uint32:
+ return strconv.FormatUint(uint64(k), 10), nil
+ case uint64:
+ return strconv.FormatUint(k, 10), nil
+ case int:
+ return strconv.Itoa(k), nil
+ case int8:
+ return strconv.FormatInt(int64(k), 10), nil
+ case int16:
+ return strconv.FormatInt(int64(k), 10), nil
+ case int32:
+ return strconv.FormatInt(int64(k), 10), nil
+ case int64:
+ return strconv.FormatInt(k, 10), nil
+ default:
+ return "", fmt.Errorf("unexpected map key type, got: %T: %w", k, ErrYAML)
+ }
+}
+
+func transformData(input any) (out any, err error) {
+ switch in := input.(type) {
+ case yaml.Node:
+ return yamlNode(&in)
+ case *yaml.Node:
+ return yamlNode(in)
+ case map[any]any:
+ o := make(YAMLMapSlice, 0, len(in))
+ for ke, va := range in {
+ var nmi YAMLMapItem
+ if nmi.Key, err = format(ke); err != nil {
+ return nil, err
+ }
+
+ v, ert := transformData(va)
+ if ert != nil {
+ return nil, ert
+ }
+ nmi.Value = v
+ o = append(o, nmi)
+ }
+ return o, nil
+ case []any:
+ len1 := len(in)
+ o := make([]any, len1)
+ for i := range len1 {
+ o[i], err = transformData(in[i])
+ if err != nil {
+ return nil, err
+ }
+ }
+ return o, nil
+ }
+ return input, nil
+}
diff --git a/vendor/github.com/go-openapi/swag/yamlutils_iface.go b/vendor/github.com/go-openapi/swag/yamlutils_iface.go
new file mode 100644
index 0000000000..57767efc56
--- /dev/null
+++ b/vendor/github.com/go-openapi/swag/yamlutils_iface.go
@@ -0,0 +1,20 @@
+// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
+// SPDX-License-Identifier: Apache-2.0
+
+package swag
+
+import (
+ "encoding/json"
+
+ "github.com/go-openapi/swag/yamlutils"
+)
+
+// YAMLToJSON converts YAML unmarshaled data into json compatible data
+//
+// Deprecated: use [yamlutils.YAMLToJSON] instead.
+func YAMLToJSON(data any) (json.RawMessage, error) { return yamlutils.YAMLToJSON(data) }
+
+// BytesToYAMLDoc converts a byte slice into a YAML document
+//
+// Deprecated: use [yamlutils.BytesToYAMLDoc] instead.
+func BytesToYAMLDoc(data []byte) (any, error) { return yamlutils.BytesToYAMLDoc(data) }
diff --git a/vendor/github.com/gobwas/glob/.gitignore b/vendor/github.com/gobwas/glob/.gitignore
new file mode 100644
index 0000000000..b4ae623be5
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/.gitignore
@@ -0,0 +1,8 @@
+glob.iml
+.idea
+*.cpu
+*.mem
+*.test
+*.dot
+*.png
+*.svg
diff --git a/vendor/github.com/gobwas/glob/.travis.yml b/vendor/github.com/gobwas/glob/.travis.yml
new file mode 100644
index 0000000000..e8a276826c
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/.travis.yml
@@ -0,0 +1,9 @@
+sudo: false
+
+language: go
+
+go:
+ - 1.5.3
+
+script:
+ - go test -v ./...
diff --git a/vendor/github.com/gobwas/glob/LICENSE b/vendor/github.com/gobwas/glob/LICENSE
new file mode 100644
index 0000000000..9d4735cad9
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Sergey Kamardin
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/vendor/github.com/gobwas/glob/bench.sh b/vendor/github.com/gobwas/glob/bench.sh
new file mode 100644
index 0000000000..804cf22e64
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/bench.sh
@@ -0,0 +1,26 @@
+#! /bin/bash
+
+bench() {
+ filename="/tmp/$1-$2.bench"
+ if test -e "${filename}";
+ then
+ echo "Already exists ${filename}"
+ else
+ backup=`git rev-parse --abbrev-ref HEAD`
+ git checkout $1
+ echo -n "Creating ${filename}... "
+ go test ./... -run=NONE -bench=$2 > "${filename}" -benchmem
+ echo "OK"
+ git checkout ${backup}
+ sleep 5
+ fi
+}
+
+
+to=$1
+current=`git rev-parse --abbrev-ref HEAD`
+
+bench ${to} $2
+bench ${current} $2
+
+benchcmp $3 "/tmp/${to}-$2.bench" "/tmp/${current}-$2.bench"
diff --git a/vendor/github.com/gobwas/glob/compiler/compiler.go b/vendor/github.com/gobwas/glob/compiler/compiler.go
new file mode 100644
index 0000000000..02e7de80a0
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/compiler/compiler.go
@@ -0,0 +1,525 @@
+package compiler
+
+// TODO use constructor with all matchers, and to their structs private
+// TODO glue multiple Text nodes (like after QuoteMeta)
+
+import (
+ "fmt"
+ "reflect"
+
+ "github.com/gobwas/glob/match"
+ "github.com/gobwas/glob/syntax/ast"
+ "github.com/gobwas/glob/util/runes"
+)
+
+func optimizeMatcher(matcher match.Matcher) match.Matcher {
+ switch m := matcher.(type) {
+
+ case match.Any:
+ if len(m.Separators) == 0 {
+ return match.NewSuper()
+ }
+
+ case match.AnyOf:
+ if len(m.Matchers) == 1 {
+ return m.Matchers[0]
+ }
+
+ return m
+
+ case match.List:
+ if m.Not == false && len(m.List) == 1 {
+ return match.NewText(string(m.List))
+ }
+
+ return m
+
+ case match.BTree:
+ m.Left = optimizeMatcher(m.Left)
+ m.Right = optimizeMatcher(m.Right)
+
+ r, ok := m.Value.(match.Text)
+ if !ok {
+ return m
+ }
+
+ var (
+ leftNil = m.Left == nil
+ rightNil = m.Right == nil
+ )
+ if leftNil && rightNil {
+ return match.NewText(r.Str)
+ }
+
+ _, leftSuper := m.Left.(match.Super)
+ lp, leftPrefix := m.Left.(match.Prefix)
+ la, leftAny := m.Left.(match.Any)
+
+ _, rightSuper := m.Right.(match.Super)
+ rs, rightSuffix := m.Right.(match.Suffix)
+ ra, rightAny := m.Right.(match.Any)
+
+ switch {
+ case leftSuper && rightSuper:
+ return match.NewContains(r.Str, false)
+
+ case leftSuper && rightNil:
+ return match.NewSuffix(r.Str)
+
+ case rightSuper && leftNil:
+ return match.NewPrefix(r.Str)
+
+ case leftNil && rightSuffix:
+ return match.NewPrefixSuffix(r.Str, rs.Suffix)
+
+ case rightNil && leftPrefix:
+ return match.NewPrefixSuffix(lp.Prefix, r.Str)
+
+ case rightNil && leftAny:
+ return match.NewSuffixAny(r.Str, la.Separators)
+
+ case leftNil && rightAny:
+ return match.NewPrefixAny(r.Str, ra.Separators)
+ }
+
+ return m
+ }
+
+ return matcher
+}
+
+func compileMatchers(matchers []match.Matcher) (match.Matcher, error) {
+ if len(matchers) == 0 {
+ return nil, fmt.Errorf("compile error: need at least one matcher")
+ }
+ if len(matchers) == 1 {
+ return matchers[0], nil
+ }
+ if m := glueMatchers(matchers); m != nil {
+ return m, nil
+ }
+
+ idx := -1
+ maxLen := -1
+ var val match.Matcher
+ for i, matcher := range matchers {
+ if l := matcher.Len(); l != -1 && l >= maxLen {
+ maxLen = l
+ idx = i
+ val = matcher
+ }
+ }
+
+ if val == nil { // not found matcher with static length
+ r, err := compileMatchers(matchers[1:])
+ if err != nil {
+ return nil, err
+ }
+ return match.NewBTree(matchers[0], nil, r), nil
+ }
+
+ left := matchers[:idx]
+ var right []match.Matcher
+ if len(matchers) > idx+1 {
+ right = matchers[idx+1:]
+ }
+
+ var l, r match.Matcher
+ var err error
+ if len(left) > 0 {
+ l, err = compileMatchers(left)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if len(right) > 0 {
+ r, err = compileMatchers(right)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return match.NewBTree(val, l, r), nil
+}
+
+func glueMatchers(matchers []match.Matcher) match.Matcher {
+ if m := glueMatchersAsEvery(matchers); m != nil {
+ return m
+ }
+ if m := glueMatchersAsRow(matchers); m != nil {
+ return m
+ }
+ return nil
+}
+
+func glueMatchersAsRow(matchers []match.Matcher) match.Matcher {
+ if len(matchers) <= 1 {
+ return nil
+ }
+
+ var (
+ c []match.Matcher
+ l int
+ )
+ for _, matcher := range matchers {
+ if ml := matcher.Len(); ml == -1 {
+ return nil
+ } else {
+ c = append(c, matcher)
+ l += ml
+ }
+ }
+ return match.NewRow(l, c...)
+}
+
+func glueMatchersAsEvery(matchers []match.Matcher) match.Matcher {
+ if len(matchers) <= 1 {
+ return nil
+ }
+
+ var (
+ hasAny bool
+ hasSuper bool
+ hasSingle bool
+ min int
+ separator []rune
+ )
+
+ for i, matcher := range matchers {
+ var sep []rune
+
+ switch m := matcher.(type) {
+ case match.Super:
+ sep = []rune{}
+ hasSuper = true
+
+ case match.Any:
+ sep = m.Separators
+ hasAny = true
+
+ case match.Single:
+ sep = m.Separators
+ hasSingle = true
+ min++
+
+ case match.List:
+ if !m.Not {
+ return nil
+ }
+ sep = m.List
+ hasSingle = true
+ min++
+
+ default:
+ return nil
+ }
+
+ // initialize
+ if i == 0 {
+ separator = sep
+ }
+
+ if runes.Equal(sep, separator) {
+ continue
+ }
+
+ return nil
+ }
+
+ if hasSuper && !hasAny && !hasSingle {
+ return match.NewSuper()
+ }
+
+ if hasAny && !hasSuper && !hasSingle {
+ return match.NewAny(separator)
+ }
+
+ if (hasAny || hasSuper) && min > 0 && len(separator) == 0 {
+ return match.NewMin(min)
+ }
+
+ every := match.NewEveryOf()
+
+ if min > 0 {
+ every.Add(match.NewMin(min))
+
+ if !hasAny && !hasSuper {
+ every.Add(match.NewMax(min))
+ }
+ }
+
+ if len(separator) > 0 {
+ every.Add(match.NewContains(string(separator), true))
+ }
+
+ return every
+}
+
+func minimizeMatchers(matchers []match.Matcher) []match.Matcher {
+ var done match.Matcher
+ var left, right, count int
+
+ for l := 0; l < len(matchers); l++ {
+ for r := len(matchers); r > l; r-- {
+ if glued := glueMatchers(matchers[l:r]); glued != nil {
+ var swap bool
+
+ if done == nil {
+ swap = true
+ } else {
+ cl, gl := done.Len(), glued.Len()
+ swap = cl > -1 && gl > -1 && gl > cl
+ swap = swap || count < r-l
+ }
+
+ if swap {
+ done = glued
+ left = l
+ right = r
+ count = r - l
+ }
+ }
+ }
+ }
+
+ if done == nil {
+ return matchers
+ }
+
+ next := append(append([]match.Matcher{}, matchers[:left]...), done)
+ if right < len(matchers) {
+ next = append(next, matchers[right:]...)
+ }
+
+ if len(next) == len(matchers) {
+ return next
+ }
+
+ return minimizeMatchers(next)
+}
+
+// minimizeAnyOf tries to apply some heuristics to minimize number of nodes in given tree
+func minimizeTree(tree *ast.Node) *ast.Node {
+ switch tree.Kind {
+ case ast.KindAnyOf:
+ return minimizeTreeAnyOf(tree)
+ default:
+ return nil
+ }
+}
+
+// minimizeAnyOf tries to find common children of given node of AnyOf pattern
+// it searches for common children from left and from right
+// if any common children are found – then it returns new optimized ast tree
+// else it returns nil
+func minimizeTreeAnyOf(tree *ast.Node) *ast.Node {
+ if !areOfSameKind(tree.Children, ast.KindPattern) {
+ return nil
+ }
+
+ commonLeft, commonRight := commonChildren(tree.Children)
+ commonLeftCount, commonRightCount := len(commonLeft), len(commonRight)
+ if commonLeftCount == 0 && commonRightCount == 0 { // there are no common parts
+ return nil
+ }
+
+ var result []*ast.Node
+ if commonLeftCount > 0 {
+ result = append(result, ast.NewNode(ast.KindPattern, nil, commonLeft...))
+ }
+
+ var anyOf []*ast.Node
+ for _, child := range tree.Children {
+ reuse := child.Children[commonLeftCount : len(child.Children)-commonRightCount]
+ var node *ast.Node
+ if len(reuse) == 0 {
+ // this pattern is completely reduced by commonLeft and commonRight patterns
+ // so it become nothing
+ node = ast.NewNode(ast.KindNothing, nil)
+ } else {
+ node = ast.NewNode(ast.KindPattern, nil, reuse...)
+ }
+ anyOf = appendIfUnique(anyOf, node)
+ }
+ switch {
+ case len(anyOf) == 1 && anyOf[0].Kind != ast.KindNothing:
+ result = append(result, anyOf[0])
+ case len(anyOf) > 1:
+ result = append(result, ast.NewNode(ast.KindAnyOf, nil, anyOf...))
+ }
+
+ if commonRightCount > 0 {
+ result = append(result, ast.NewNode(ast.KindPattern, nil, commonRight...))
+ }
+
+ return ast.NewNode(ast.KindPattern, nil, result...)
+}
+
+func commonChildren(nodes []*ast.Node) (commonLeft, commonRight []*ast.Node) {
+ if len(nodes) <= 1 {
+ return
+ }
+
+ // find node that has least number of children
+ idx := leastChildren(nodes)
+ if idx == -1 {
+ return
+ }
+ tree := nodes[idx]
+ treeLength := len(tree.Children)
+
+ // allocate max able size for rightCommon slice
+ // to get ability insert elements in reverse order (from end to start)
+ // without sorting
+ commonRight = make([]*ast.Node, treeLength)
+ lastRight := treeLength // will use this to get results as commonRight[lastRight:]
+
+ var (
+ breakLeft bool
+ breakRight bool
+ commonTotal int
+ )
+ for i, j := 0, treeLength-1; commonTotal < treeLength && j >= 0 && !(breakLeft && breakRight); i, j = i+1, j-1 {
+ treeLeft := tree.Children[i]
+ treeRight := tree.Children[j]
+
+ for k := 0; k < len(nodes) && !(breakLeft && breakRight); k++ {
+ // skip least children node
+ if k == idx {
+ continue
+ }
+
+ restLeft := nodes[k].Children[i]
+ restRight := nodes[k].Children[j+len(nodes[k].Children)-treeLength]
+
+ breakLeft = breakLeft || !treeLeft.Equal(restLeft)
+
+ // disable searching for right common parts, if left part is already overlapping
+ breakRight = breakRight || (!breakLeft && j <= i)
+ breakRight = breakRight || !treeRight.Equal(restRight)
+ }
+
+ if !breakLeft {
+ commonTotal++
+ commonLeft = append(commonLeft, treeLeft)
+ }
+ if !breakRight {
+ commonTotal++
+ lastRight = j
+ commonRight[j] = treeRight
+ }
+ }
+
+ commonRight = commonRight[lastRight:]
+
+ return
+}
+
+func appendIfUnique(target []*ast.Node, val *ast.Node) []*ast.Node {
+ for _, n := range target {
+ if reflect.DeepEqual(n, val) {
+ return target
+ }
+ }
+ return append(target, val)
+}
+
+func areOfSameKind(nodes []*ast.Node, kind ast.Kind) bool {
+ for _, n := range nodes {
+ if n.Kind != kind {
+ return false
+ }
+ }
+ return true
+}
+
+func leastChildren(nodes []*ast.Node) int {
+ min := -1
+ idx := -1
+ for i, n := range nodes {
+ if idx == -1 || (len(n.Children) < min) {
+ min = len(n.Children)
+ idx = i
+ }
+ }
+ return idx
+}
+
+func compileTreeChildren(tree *ast.Node, sep []rune) ([]match.Matcher, error) {
+ var matchers []match.Matcher
+ for _, desc := range tree.Children {
+ m, err := compile(desc, sep)
+ if err != nil {
+ return nil, err
+ }
+ matchers = append(matchers, optimizeMatcher(m))
+ }
+ return matchers, nil
+}
+
+func compile(tree *ast.Node, sep []rune) (m match.Matcher, err error) {
+ switch tree.Kind {
+ case ast.KindAnyOf:
+ // todo this could be faster on pattern_alternatives_combine_lite (see glob_test.go)
+ if n := minimizeTree(tree); n != nil {
+ return compile(n, sep)
+ }
+ matchers, err := compileTreeChildren(tree, sep)
+ if err != nil {
+ return nil, err
+ }
+ return match.NewAnyOf(matchers...), nil
+
+ case ast.KindPattern:
+ if len(tree.Children) == 0 {
+ return match.NewNothing(), nil
+ }
+ matchers, err := compileTreeChildren(tree, sep)
+ if err != nil {
+ return nil, err
+ }
+ m, err = compileMatchers(minimizeMatchers(matchers))
+ if err != nil {
+ return nil, err
+ }
+
+ case ast.KindAny:
+ m = match.NewAny(sep)
+
+ case ast.KindSuper:
+ m = match.NewSuper()
+
+ case ast.KindSingle:
+ m = match.NewSingle(sep)
+
+ case ast.KindNothing:
+ m = match.NewNothing()
+
+ case ast.KindList:
+ l := tree.Value.(ast.List)
+ m = match.NewList([]rune(l.Chars), l.Not)
+
+ case ast.KindRange:
+ r := tree.Value.(ast.Range)
+ m = match.NewRange(r.Lo, r.Hi, r.Not)
+
+ case ast.KindText:
+ t := tree.Value.(ast.Text)
+ m = match.NewText(t.Text)
+
+ default:
+ return nil, fmt.Errorf("could not compile tree: unknown node type")
+ }
+
+ return optimizeMatcher(m), nil
+}
+
+func Compile(tree *ast.Node, sep []rune) (match.Matcher, error) {
+ m, err := compile(tree, sep)
+ if err != nil {
+ return nil, err
+ }
+
+ return m, nil
+}
diff --git a/vendor/github.com/gobwas/glob/glob.go b/vendor/github.com/gobwas/glob/glob.go
new file mode 100644
index 0000000000..2afde343af
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/glob.go
@@ -0,0 +1,80 @@
+package glob
+
+import (
+ "github.com/gobwas/glob/compiler"
+ "github.com/gobwas/glob/syntax"
+)
+
+// Glob represents compiled glob pattern.
+type Glob interface {
+ Match(string) bool
+}
+
+// Compile creates Glob for given pattern and strings (if any present after pattern) as separators.
+// The pattern syntax is:
+//
+// pattern:
+// { term }
+//
+// term:
+// `*` matches any sequence of non-separator characters
+// `**` matches any sequence of characters
+// `?` matches any single non-separator character
+// `[` [ `!` ] { character-range } `]`
+// character class (must be non-empty)
+// `{` pattern-list `}`
+// pattern alternatives
+// c matches character c (c != `*`, `**`, `?`, `\`, `[`, `{`, `}`)
+// `\` c matches character c
+//
+// character-range:
+// c matches character c (c != `\\`, `-`, `]`)
+// `\` c matches character c
+// lo `-` hi matches character c for lo <= c <= hi
+//
+// pattern-list:
+// pattern { `,` pattern }
+// comma-separated (without spaces) patterns
+//
+func Compile(pattern string, separators ...rune) (Glob, error) {
+ ast, err := syntax.Parse(pattern)
+ if err != nil {
+ return nil, err
+ }
+
+ matcher, err := compiler.Compile(ast, separators)
+ if err != nil {
+ return nil, err
+ }
+
+ return matcher, nil
+}
+
+// MustCompile is the same as Compile, except that if Compile returns error, this will panic
+func MustCompile(pattern string, separators ...rune) Glob {
+ g, err := Compile(pattern, separators...)
+ if err != nil {
+ panic(err)
+ }
+
+ return g
+}
+
+// QuoteMeta returns a string that quotes all glob pattern meta characters
+// inside the argument text; For example, QuoteMeta(`{foo*}`) returns `\[foo\*\]`.
+func QuoteMeta(s string) string {
+ b := make([]byte, 2*len(s))
+
+ // a byte loop is correct because all meta characters are ASCII
+ j := 0
+ for i := 0; i < len(s); i++ {
+ if syntax.Special(s[i]) {
+ b[j] = '\\'
+ j++
+ }
+ b[j] = s[i]
+ j++
+ }
+
+ return string(b[0:j])
+}
diff --git a/vendor/github.com/gobwas/glob/match/any.go b/vendor/github.com/gobwas/glob/match/any.go
new file mode 100644
index 0000000000..514a9a5c45
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/match/any.go
@@ -0,0 +1,45 @@
+package match
+
+import (
+ "fmt"
+ "github.com/gobwas/glob/util/strings"
+)
+
+type Any struct {
+ Separators []rune
+}
+
+func NewAny(s []rune) Any {
+ return Any{s}
+}
+
+func (self Any) Match(s string) bool {
+ return strings.IndexAnyRunes(s, self.Separators) == -1
+}
+
+func (self Any) Index(s string) (int, []int) {
+ found := strings.IndexAnyRunes(s, self.Separators)
+ switch found {
+ case -1:
+ case 0:
+ return 0, segments0
+ default:
+ s = s[:found]
+ }
+
+ segments := acquireSegments(len(s))
+ for i := range s {
+ segments = append(segments, i)
+ }
+ segments = append(segments, len(s))
+
+ return 0, segments
+}
+
+func (self Any) Len() int {
+ return lenNo
+}
+
+func (self Any) String() string {
+ return fmt.Sprintf("", string(self.Separators))
+}
diff --git a/vendor/github.com/gobwas/glob/match/any_of.go b/vendor/github.com/gobwas/glob/match/any_of.go
new file mode 100644
index 0000000000..8e65356cdc
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/match/any_of.go
@@ -0,0 +1,82 @@
+package match
+
+import "fmt"
+
+type AnyOf struct {
+ Matchers Matchers
+}
+
+func NewAnyOf(m ...Matcher) AnyOf {
+ return AnyOf{Matchers(m)}
+}
+
+func (self *AnyOf) Add(m Matcher) error {
+ self.Matchers = append(self.Matchers, m)
+ return nil
+}
+
+func (self AnyOf) Match(s string) bool {
+ for _, m := range self.Matchers {
+ if m.Match(s) {
+ return true
+ }
+ }
+
+ return false
+}
+
+func (self AnyOf) Index(s string) (int, []int) {
+ index := -1
+
+ segments := acquireSegments(len(s))
+ for _, m := range self.Matchers {
+ idx, seg := m.Index(s)
+ if idx == -1 {
+ continue
+ }
+
+ if index == -1 || idx < index {
+ index = idx
+ segments = append(segments[:0], seg...)
+ continue
+ }
+
+ if idx > index {
+ continue
+ }
+
+ // here idx == index
+ segments = appendMerge(segments, seg)
+ }
+
+ if index == -1 {
+ releaseSegments(segments)
+ return -1, nil
+ }
+
+ return index, segments
+}
+
+func (self AnyOf) Len() (l int) {
+ l = -1
+ for _, m := range self.Matchers {
+ ml := m.Len()
+ switch {
+ case l == -1:
+ l = ml
+ continue
+
+ case ml == -1:
+ return -1
+
+ case l != ml:
+ return -1
+ }
+ }
+
+ return
+}
+
+func (self AnyOf) String() string {
+ return fmt.Sprintf("", self.Matchers)
+}
diff --git a/vendor/github.com/gobwas/glob/match/btree.go b/vendor/github.com/gobwas/glob/match/btree.go
new file mode 100644
index 0000000000..a8130e93ea
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/match/btree.go
@@ -0,0 +1,146 @@
+package match
+
+import (
+ "fmt"
+ "unicode/utf8"
+)
+
+type BTree struct {
+ Value Matcher
+ Left Matcher
+ Right Matcher
+ ValueLengthRunes int
+ LeftLengthRunes int
+ RightLengthRunes int
+ LengthRunes int
+}
+
+func NewBTree(Value, Left, Right Matcher) (tree BTree) {
+ tree.Value = Value
+ tree.Left = Left
+ tree.Right = Right
+
+ lenOk := true
+ if tree.ValueLengthRunes = Value.Len(); tree.ValueLengthRunes == -1 {
+ lenOk = false
+ }
+
+ if Left != nil {
+ if tree.LeftLengthRunes = Left.Len(); tree.LeftLengthRunes == -1 {
+ lenOk = false
+ }
+ }
+
+ if Right != nil {
+ if tree.RightLengthRunes = Right.Len(); tree.RightLengthRunes == -1 {
+ lenOk = false
+ }
+ }
+
+ if lenOk {
+ tree.LengthRunes = tree.LeftLengthRunes + tree.ValueLengthRunes + tree.RightLengthRunes
+ } else {
+ tree.LengthRunes = -1
+ }
+
+ return tree
+}
+
+func (self BTree) Len() int {
+ return self.LengthRunes
+}
+
+// todo?
+func (self BTree) Index(s string) (int, []int) {
+ return -1, nil
+}
+
+func (self BTree) Match(s string) bool {
+ inputLen := len(s)
+
+ // self.Length, self.RLen and self.LLen are values meaning the length of runes for each part
+ // here we manipulating byte length for better optimizations
+ // but these checks still works, cause minLen of 1-rune string is 1 byte.
+ if self.LengthRunes != -1 && self.LengthRunes > inputLen {
+ return false
+ }
+
+ // try to cut unnecessary parts
+ // by knowledge of length of right and left part
+ var offset, limit int
+ if self.LeftLengthRunes >= 0 {
+ offset = self.LeftLengthRunes
+ }
+ if self.RightLengthRunes >= 0 {
+ limit = inputLen - self.RightLengthRunes
+ } else {
+ limit = inputLen
+ }
+
+ for offset < limit {
+ // search for matching part in substring
+ index, segments := self.Value.Index(s[offset:limit])
+ if index == -1 {
+ releaseSegments(segments)
+ return false
+ }
+
+ l := s[:offset+index]
+ var left bool
+ if self.Left != nil {
+ left = self.Left.Match(l)
+ } else {
+ left = l == ""
+ }
+
+ if left {
+ for i := len(segments) - 1; i >= 0; i-- {
+ length := segments[i]
+
+ var right bool
+ var r string
+ // if there is no string for the right branch
+ if inputLen <= offset+index+length {
+ r = ""
+ } else {
+ r = s[offset+index+length:]
+ }
+
+ if self.Right != nil {
+ right = self.Right.Match(r)
+ } else {
+ right = r == ""
+ }
+
+ if right {
+ releaseSegments(segments)
+ return true
+ }
+ }
+ }
+
+ _, step := utf8.DecodeRuneInString(s[offset+index:])
+ offset += index + step
+
+ releaseSegments(segments)
+ }
+
+ return false
+}
+
+func (self BTree) String() string {
+ const n string = ""
+ var l, r string
+ if self.Left == nil {
+ l = n
+ } else {
+ l = self.Left.String()
+ }
+ if self.Right == nil {
+ r = n
+ } else {
+ r = self.Right.String()
+ }
+
+ return fmt.Sprintf("%s]>", l, self.Value, r)
+}
diff --git a/vendor/github.com/gobwas/glob/match/contains.go b/vendor/github.com/gobwas/glob/match/contains.go
new file mode 100644
index 0000000000..0998e95b0e
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/match/contains.go
@@ -0,0 +1,58 @@
+package match
+
+import (
+ "fmt"
+ "strings"
+)
+
+type Contains struct {
+ Needle string
+ Not bool
+}
+
+func NewContains(needle string, not bool) Contains {
+ return Contains{needle, not}
+}
+
+func (self Contains) Match(s string) bool {
+ return strings.Contains(s, self.Needle) != self.Not
+}
+
+func (self Contains) Index(s string) (int, []int) {
+ var offset int
+
+ idx := strings.Index(s, self.Needle)
+
+ if !self.Not {
+ if idx == -1 {
+ return -1, nil
+ }
+
+ offset = idx + len(self.Needle)
+ if len(s) <= offset {
+ return 0, []int{offset}
+ }
+ s = s[offset:]
+ } else if idx != -1 {
+ s = s[:idx]
+ }
+
+ segments := acquireSegments(len(s) + 1)
+ for i := range s {
+ segments = append(segments, offset+i)
+ }
+
+ return 0, append(segments, offset+len(s))
+}
+
+func (self Contains) Len() int {
+ return lenNo
+}
+
+func (self Contains) String() string {
+ var not string
+ if self.Not {
+ not = "!"
+ }
+ return fmt.Sprintf("", not, self.Needle)
+}
diff --git a/vendor/github.com/gobwas/glob/match/every_of.go b/vendor/github.com/gobwas/glob/match/every_of.go
new file mode 100644
index 0000000000..7c968ee368
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/match/every_of.go
@@ -0,0 +1,99 @@
+package match
+
+import (
+ "fmt"
+)
+
+type EveryOf struct {
+ Matchers Matchers
+}
+
+func NewEveryOf(m ...Matcher) EveryOf {
+ return EveryOf{Matchers(m)}
+}
+
+func (self *EveryOf) Add(m Matcher) error {
+ self.Matchers = append(self.Matchers, m)
+ return nil
+}
+
+func (self EveryOf) Len() (l int) {
+ for _, m := range self.Matchers {
+ if ml := m.Len(); l > 0 {
+ l += ml
+ } else {
+ return -1
+ }
+ }
+
+ return
+}
+
+func (self EveryOf) Index(s string) (int, []int) {
+ var index int
+ var offset int
+
+ // make `in` with cap as len(s),
+ // cause it is the maximum size of output segments values
+ next := acquireSegments(len(s))
+ current := acquireSegments(len(s))
+
+ sub := s
+ for i, m := range self.Matchers {
+ idx, seg := m.Index(sub)
+ if idx == -1 {
+ releaseSegments(next)
+ releaseSegments(current)
+ return -1, nil
+ }
+
+ if i == 0 {
+ // we use copy here instead of `current = seg`
+ // cause seg is a slice from reusable buffer `in`
+ // and it could be overwritten in next iteration
+ current = append(current, seg...)
+ } else {
+ // clear the next
+ next = next[:0]
+
+ delta := index - (idx + offset)
+ for _, ex := range current {
+ for _, n := range seg {
+ if ex+delta == n {
+ next = append(next, n)
+ }
+ }
+ }
+
+ if len(next) == 0 {
+ releaseSegments(next)
+ releaseSegments(current)
+ return -1, nil
+ }
+
+ current = append(current[:0], next...)
+ }
+
+ index = idx + offset
+ sub = s[index:]
+ offset += idx
+ }
+
+ releaseSegments(next)
+
+ return index, current
+}
+
+func (self EveryOf) Match(s string) bool {
+ for _, m := range self.Matchers {
+ if !m.Match(s) {
+ return false
+ }
+ }
+
+ return true
+}
+
+func (self EveryOf) String() string {
+ return fmt.Sprintf("", self.Matchers)
+}
diff --git a/vendor/github.com/gobwas/glob/match/list.go b/vendor/github.com/gobwas/glob/match/list.go
new file mode 100644
index 0000000000..7fd763ecd8
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/match/list.go
@@ -0,0 +1,49 @@
+package match
+
+import (
+ "fmt"
+ "github.com/gobwas/glob/util/runes"
+ "unicode/utf8"
+)
+
+type List struct {
+ List []rune
+ Not bool
+}
+
+func NewList(list []rune, not bool) List {
+ return List{list, not}
+}
+
+func (self List) Match(s string) bool {
+ r, w := utf8.DecodeRuneInString(s)
+ if len(s) > w {
+ return false
+ }
+
+ inList := runes.IndexRune(self.List, r) != -1
+ return inList == !self.Not
+}
+
+func (self List) Len() int {
+ return lenOne
+}
+
+func (self List) Index(s string) (int, []int) {
+ for i, r := range s {
+ if self.Not == (runes.IndexRune(self.List, r) == -1) {
+ return i, segmentsByRuneLength[utf8.RuneLen(r)]
+ }
+ }
+
+ return -1, nil
+}
+
+func (self List) String() string {
+ var not string
+ if self.Not {
+ not = "!"
+ }
+
+ return fmt.Sprintf("", not, string(self.List))
+}
diff --git a/vendor/github.com/gobwas/glob/match/match.go b/vendor/github.com/gobwas/glob/match/match.go
new file mode 100644
index 0000000000..f80e007fb8
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/match/match.go
@@ -0,0 +1,81 @@
+package match
+
+// todo common table of rune's length
+
+import (
+ "fmt"
+ "strings"
+)
+
+const lenOne = 1
+const lenZero = 0
+const lenNo = -1
+
+type Matcher interface {
+ Match(string) bool
+ Index(string) (int, []int)
+ Len() int
+ String() string
+}
+
+type Matchers []Matcher
+
+func (m Matchers) String() string {
+ var s []string
+ for _, matcher := range m {
+ s = append(s, fmt.Sprint(matcher))
+ }
+
+ return fmt.Sprintf("%s", strings.Join(s, ","))
+}
+
+// appendMerge merges and sorts given already SORTED and UNIQUE segments.
+func appendMerge(target, sub []int) []int {
+ lt, ls := len(target), len(sub)
+ out := make([]int, 0, lt+ls)
+
+ for x, y := 0, 0; x < lt || y < ls; {
+ if x >= lt {
+ out = append(out, sub[y:]...)
+ break
+ }
+
+ if y >= ls {
+ out = append(out, target[x:]...)
+ break
+ }
+
+ xValue := target[x]
+ yValue := sub[y]
+
+ switch {
+
+ case xValue == yValue:
+ out = append(out, xValue)
+ x++
+ y++
+
+ case xValue < yValue:
+ out = append(out, xValue)
+ x++
+
+ case yValue < xValue:
+ out = append(out, yValue)
+ y++
+
+ }
+ }
+
+ target = append(target[:0], out...)
+
+ return target
+}
+
+func reverseSegments(input []int) {
+ l := len(input)
+ m := l / 2
+
+ for i := 0; i < m; i++ {
+ input[i], input[l-i-1] = input[l-i-1], input[i]
+ }
+}
diff --git a/vendor/github.com/gobwas/glob/match/max.go b/vendor/github.com/gobwas/glob/match/max.go
new file mode 100644
index 0000000000..d72f69efff
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/match/max.go
@@ -0,0 +1,49 @@
+package match
+
+import (
+ "fmt"
+ "unicode/utf8"
+)
+
+type Max struct {
+ Limit int
+}
+
+func NewMax(l int) Max {
+ return Max{l}
+}
+
+func (self Max) Match(s string) bool {
+ var l int
+ for range s {
+ l += 1
+ if l > self.Limit {
+ return false
+ }
+ }
+
+ return true
+}
+
+func (self Max) Index(s string) (int, []int) {
+ segments := acquireSegments(self.Limit + 1)
+ segments = append(segments, 0)
+ var count int
+ for i, r := range s {
+ count++
+ if count > self.Limit {
+ break
+ }
+ segments = append(segments, i+utf8.RuneLen(r))
+ }
+
+ return 0, segments
+}
+
+func (self Max) Len() int {
+ return lenNo
+}
+
+func (self Max) String() string {
+ return fmt.Sprintf("", self.Limit)
+}
diff --git a/vendor/github.com/gobwas/glob/match/min.go b/vendor/github.com/gobwas/glob/match/min.go
new file mode 100644
index 0000000000..db57ac8eb4
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/match/min.go
@@ -0,0 +1,57 @@
+package match
+
+import (
+ "fmt"
+ "unicode/utf8"
+)
+
+type Min struct {
+ Limit int
+}
+
+func NewMin(l int) Min {
+ return Min{l}
+}
+
+func (self Min) Match(s string) bool {
+ var l int
+ for range s {
+ l += 1
+ if l >= self.Limit {
+ return true
+ }
+ }
+
+ return false
+}
+
+func (self Min) Index(s string) (int, []int) {
+ var count int
+
+ c := len(s) - self.Limit + 1
+ if c <= 0 {
+ return -1, nil
+ }
+
+ segments := acquireSegments(c)
+ for i, r := range s {
+ count++
+ if count >= self.Limit {
+ segments = append(segments, i+utf8.RuneLen(r))
+ }
+ }
+
+ if len(segments) == 0 {
+ return -1, nil
+ }
+
+ return 0, segments
+}
+
+func (self Min) Len() int {
+ return lenNo
+}
+
+func (self Min) String() string {
+ return fmt.Sprintf("", self.Limit)
+}
diff --git a/vendor/github.com/gobwas/glob/match/nothing.go b/vendor/github.com/gobwas/glob/match/nothing.go
new file mode 100644
index 0000000000..0d4ecd36b8
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/match/nothing.go
@@ -0,0 +1,27 @@
+package match
+
+import (
+ "fmt"
+)
+
+type Nothing struct{}
+
+func NewNothing() Nothing {
+ return Nothing{}
+}
+
+func (self Nothing) Match(s string) bool {
+ return len(s) == 0
+}
+
+func (self Nothing) Index(s string) (int, []int) {
+ return 0, segments0
+}
+
+func (self Nothing) Len() int {
+ return lenZero
+}
+
+func (self Nothing) String() string {
+ return fmt.Sprintf("")
+}
diff --git a/vendor/github.com/gobwas/glob/match/prefix.go b/vendor/github.com/gobwas/glob/match/prefix.go
new file mode 100644
index 0000000000..a7347250e8
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/match/prefix.go
@@ -0,0 +1,50 @@
+package match
+
+import (
+ "fmt"
+ "strings"
+ "unicode/utf8"
+)
+
+type Prefix struct {
+ Prefix string
+}
+
+func NewPrefix(p string) Prefix {
+ return Prefix{p}
+}
+
+func (self Prefix) Index(s string) (int, []int) {
+ idx := strings.Index(s, self.Prefix)
+ if idx == -1 {
+ return -1, nil
+ }
+
+ length := len(self.Prefix)
+ var sub string
+ if len(s) > idx+length {
+ sub = s[idx+length:]
+ } else {
+ sub = ""
+ }
+
+ segments := acquireSegments(len(sub) + 1)
+ segments = append(segments, length)
+ for i, r := range sub {
+ segments = append(segments, length+i+utf8.RuneLen(r))
+ }
+
+ return idx, segments
+}
+
+func (self Prefix) Len() int {
+ return lenNo
+}
+
+func (self Prefix) Match(s string) bool {
+ return strings.HasPrefix(s, self.Prefix)
+}
+
+func (self Prefix) String() string {
+ return fmt.Sprintf("", self.Prefix)
+}
diff --git a/vendor/github.com/gobwas/glob/match/prefix_any.go b/vendor/github.com/gobwas/glob/match/prefix_any.go
new file mode 100644
index 0000000000..8ee58fe1b3
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/match/prefix_any.go
@@ -0,0 +1,55 @@
+package match
+
+import (
+ "fmt"
+ "strings"
+ "unicode/utf8"
+
+ sutil "github.com/gobwas/glob/util/strings"
+)
+
+type PrefixAny struct {
+ Prefix string
+ Separators []rune
+}
+
+func NewPrefixAny(s string, sep []rune) PrefixAny {
+ return PrefixAny{s, sep}
+}
+
+func (self PrefixAny) Index(s string) (int, []int) {
+ idx := strings.Index(s, self.Prefix)
+ if idx == -1 {
+ return -1, nil
+ }
+
+ n := len(self.Prefix)
+ sub := s[idx+n:]
+ i := sutil.IndexAnyRunes(sub, self.Separators)
+ if i > -1 {
+ sub = sub[:i]
+ }
+
+ seg := acquireSegments(len(sub) + 1)
+ seg = append(seg, n)
+ for i, r := range sub {
+ seg = append(seg, n+i+utf8.RuneLen(r))
+ }
+
+ return idx, seg
+}
+
+func (self PrefixAny) Len() int {
+ return lenNo
+}
+
+func (self PrefixAny) Match(s string) bool {
+ if !strings.HasPrefix(s, self.Prefix) {
+ return false
+ }
+ return sutil.IndexAnyRunes(s[len(self.Prefix):], self.Separators) == -1
+}
+
+func (self PrefixAny) String() string {
+ return fmt.Sprintf("", self.Prefix, string(self.Separators))
+}
diff --git a/vendor/github.com/gobwas/glob/match/prefix_suffix.go b/vendor/github.com/gobwas/glob/match/prefix_suffix.go
new file mode 100644
index 0000000000..8208085a19
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/match/prefix_suffix.go
@@ -0,0 +1,62 @@
+package match
+
+import (
+ "fmt"
+ "strings"
+)
+
+type PrefixSuffix struct {
+ Prefix, Suffix string
+}
+
+func NewPrefixSuffix(p, s string) PrefixSuffix {
+ return PrefixSuffix{p, s}
+}
+
+func (self PrefixSuffix) Index(s string) (int, []int) {
+ prefixIdx := strings.Index(s, self.Prefix)
+ if prefixIdx == -1 {
+ return -1, nil
+ }
+
+ suffixLen := len(self.Suffix)
+ if suffixLen <= 0 {
+ return prefixIdx, []int{len(s) - prefixIdx}
+ }
+
+ if (len(s) - prefixIdx) <= 0 {
+ return -1, nil
+ }
+
+ segments := acquireSegments(len(s) - prefixIdx)
+ for sub := s[prefixIdx:]; ; {
+ suffixIdx := strings.LastIndex(sub, self.Suffix)
+ if suffixIdx == -1 {
+ break
+ }
+
+ segments = append(segments, suffixIdx+suffixLen)
+ sub = sub[:suffixIdx]
+ }
+
+ if len(segments) == 0 {
+ releaseSegments(segments)
+ return -1, nil
+ }
+
+ reverseSegments(segments)
+
+ return prefixIdx, segments
+}
+
+func (self PrefixSuffix) Len() int {
+ return lenNo
+}
+
+func (self PrefixSuffix) Match(s string) bool {
+ return strings.HasPrefix(s, self.Prefix) && strings.HasSuffix(s, self.Suffix)
+}
+
+func (self PrefixSuffix) String() string {
+ return fmt.Sprintf("", self.Prefix, self.Suffix)
+}
diff --git a/vendor/github.com/gobwas/glob/match/range.go b/vendor/github.com/gobwas/glob/match/range.go
new file mode 100644
index 0000000000..ce30245a40
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/match/range.go
@@ -0,0 +1,48 @@
+package match
+
+import (
+ "fmt"
+ "unicode/utf8"
+)
+
+type Range struct {
+ Lo, Hi rune
+ Not bool
+}
+
+func NewRange(lo, hi rune, not bool) Range {
+ return Range{lo, hi, not}
+}
+
+func (self Range) Len() int {
+ return lenOne
+}
+
+func (self Range) Match(s string) bool {
+ r, w := utf8.DecodeRuneInString(s)
+ if len(s) > w {
+ return false
+ }
+
+ inRange := r >= self.Lo && r <= self.Hi
+
+ return inRange == !self.Not
+}
+
+func (self Range) Index(s string) (int, []int) {
+ for i, r := range s {
+ if self.Not != (r >= self.Lo && r <= self.Hi) {
+ return i, segmentsByRuneLength[utf8.RuneLen(r)]
+ }
+ }
+
+ return -1, nil
+}
+
+func (self Range) String() string {
+ var not string
+ if self.Not {
+ not = "!"
+ }
+ return fmt.Sprintf("", not, string(self.Lo), string(self.Hi))
+}
diff --git a/vendor/github.com/gobwas/glob/match/row.go b/vendor/github.com/gobwas/glob/match/row.go
new file mode 100644
index 0000000000..4379042e42
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/match/row.go
@@ -0,0 +1,77 @@
+package match
+
+import (
+ "fmt"
+)
+
+type Row struct {
+ Matchers Matchers
+ RunesLength int
+ Segments []int
+}
+
+func NewRow(len int, m ...Matcher) Row {
+ return Row{
+ Matchers: Matchers(m),
+ RunesLength: len,
+ Segments: []int{len},
+ }
+}
+
+func (self Row) matchAll(s string) bool {
+ var idx int
+ for _, m := range self.Matchers {
+ length := m.Len()
+
+ var next, i int
+ for next = range s[idx:] {
+ i++
+ if i == length {
+ break
+ }
+ }
+
+ if i < length || !m.Match(s[idx:idx+next+1]) {
+ return false
+ }
+
+ idx += next + 1
+ }
+
+ return true
+}
+
+func (self Row) lenOk(s string) bool {
+ var i int
+ for range s {
+ i++
+ if i > self.RunesLength {
+ return false
+ }
+ }
+ return self.RunesLength == i
+}
+
+func (self Row) Match(s string) bool {
+ return self.lenOk(s) && self.matchAll(s)
+}
+
+func (self Row) Len() (l int) {
+ return self.RunesLength
+}
+
+func (self Row) Index(s string) (int, []int) {
+ for i := range s {
+ if len(s[i:]) < self.RunesLength {
+ break
+ }
+ if self.matchAll(s[i:]) {
+ return i, self.Segments
+ }
+ }
+ return -1, nil
+}
+
+func (self Row) String() string {
+ return fmt.Sprintf("", self.RunesLength, self.Matchers)
+}
diff --git a/vendor/github.com/gobwas/glob/match/segments.go b/vendor/github.com/gobwas/glob/match/segments.go
new file mode 100644
index 0000000000..9ea6f30943
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/match/segments.go
@@ -0,0 +1,91 @@
+package match
+
+import (
+ "sync"
+)
+
+type SomePool interface {
+ Get() []int
+ Put([]int)
+}
+
+var segmentsPools [1024]sync.Pool
+
+func toPowerOfTwo(v int) int {
+ v--
+ v |= v >> 1
+ v |= v >> 2
+ v |= v >> 4
+ v |= v >> 8
+ v |= v >> 16
+ v++
+
+ return v
+}
+
+const (
+ cacheFrom = 16
+ cacheToAndHigher = 1024
+ cacheFromIndex = 15
+ cacheToAndHigherIndex = 1023
+)
+
+var (
+ segments0 = []int{0}
+ segments1 = []int{1}
+ segments2 = []int{2}
+ segments3 = []int{3}
+ segments4 = []int{4}
+)
+
+var segmentsByRuneLength [5][]int = [5][]int{
+ 0: segments0,
+ 1: segments1,
+ 2: segments2,
+ 3: segments3,
+ 4: segments4,
+}
+
+func init() {
+ for i := cacheToAndHigher; i >= cacheFrom; i >>= 1 {
+ func(i int) {
+ segmentsPools[i-1] = sync.Pool{New: func() interface{} {
+ return make([]int, 0, i)
+ }}
+ }(i)
+ }
+}
+
+func getTableIndex(c int) int {
+ p := toPowerOfTwo(c)
+ switch {
+ case p >= cacheToAndHigher:
+ return cacheToAndHigherIndex
+ case p <= cacheFrom:
+ return cacheFromIndex
+ default:
+ return p - 1
+ }
+}
+
+func acquireSegments(c int) []int {
+ // make []int with less capacity than cacheFrom
+ // is faster than acquiring it from pool
+ if c < cacheFrom {
+ return make([]int, 0, c)
+ }
+
+ return segmentsPools[getTableIndex(c)].Get().([]int)[:0]
+}
+
+func releaseSegments(s []int) {
+ c := cap(s)
+
+ // make []int with less capacity than cacheFrom
+ // is faster than acquiring it from pool
+ if c < cacheFrom {
+ return
+ }
+
+ segmentsPools[getTableIndex(c)].Put(s)
+}
diff --git a/vendor/github.com/gobwas/glob/match/single.go b/vendor/github.com/gobwas/glob/match/single.go
new file mode 100644
index 0000000000..ee6e3954c1
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/match/single.go
@@ -0,0 +1,43 @@
+package match
+
+import (
+ "fmt"
+ "github.com/gobwas/glob/util/runes"
+ "unicode/utf8"
+)
+
+// single represents ?
+type Single struct {
+ Separators []rune
+}
+
+func NewSingle(s []rune) Single {
+ return Single{s}
+}
+
+func (self Single) Match(s string) bool {
+ r, w := utf8.DecodeRuneInString(s)
+ if len(s) > w {
+ return false
+ }
+
+ return runes.IndexRune(self.Separators, r) == -1
+}
+
+func (self Single) Len() int {
+ return lenOne
+}
+
+func (self Single) Index(s string) (int, []int) {
+ for i, r := range s {
+ if runes.IndexRune(self.Separators, r) == -1 {
+ return i, segmentsByRuneLength[utf8.RuneLen(r)]
+ }
+ }
+
+ return -1, nil
+}
+
+func (self Single) String() string {
+ return fmt.Sprintf("", string(self.Separators))
+}
diff --git a/vendor/github.com/gobwas/glob/match/suffix.go b/vendor/github.com/gobwas/glob/match/suffix.go
new file mode 100644
index 0000000000..85bea8c68e
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/match/suffix.go
@@ -0,0 +1,35 @@
+package match
+
+import (
+ "fmt"
+ "strings"
+)
+
+type Suffix struct {
+ Suffix string
+}
+
+func NewSuffix(s string) Suffix {
+ return Suffix{s}
+}
+
+func (self Suffix) Len() int {
+ return lenNo
+}
+
+func (self Suffix) Match(s string) bool {
+ return strings.HasSuffix(s, self.Suffix)
+}
+
+func (self Suffix) Index(s string) (int, []int) {
+ idx := strings.Index(s, self.Suffix)
+ if idx == -1 {
+ return -1, nil
+ }
+
+ return 0, []int{idx + len(self.Suffix)}
+}
+
+func (self Suffix) String() string {
+ return fmt.Sprintf("", self.Suffix)
+}
diff --git a/vendor/github.com/gobwas/glob/match/suffix_any.go b/vendor/github.com/gobwas/glob/match/suffix_any.go
new file mode 100644
index 0000000000..c5106f8196
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/match/suffix_any.go
@@ -0,0 +1,43 @@
+package match
+
+import (
+ "fmt"
+ "strings"
+
+ sutil "github.com/gobwas/glob/util/strings"
+)
+
+type SuffixAny struct {
+ Suffix string
+ Separators []rune
+}
+
+func NewSuffixAny(s string, sep []rune) SuffixAny {
+ return SuffixAny{s, sep}
+}
+
+func (self SuffixAny) Index(s string) (int, []int) {
+ idx := strings.Index(s, self.Suffix)
+ if idx == -1 {
+ return -1, nil
+ }
+
+ i := sutil.LastIndexAnyRunes(s[:idx], self.Separators) + 1
+
+ return i, []int{idx + len(self.Suffix) - i}
+}
+
+func (self SuffixAny) Len() int {
+ return lenNo
+}
+
+func (self SuffixAny) Match(s string) bool {
+ if !strings.HasSuffix(s, self.Suffix) {
+ return false
+ }
+ return sutil.IndexAnyRunes(s[:len(s)-len(self.Suffix)], self.Separators) == -1
+}
+
+func (self SuffixAny) String() string {
+ return fmt.Sprintf("", string(self.Separators), self.Suffix)
+}
diff --git a/vendor/github.com/gobwas/glob/match/super.go b/vendor/github.com/gobwas/glob/match/super.go
new file mode 100644
index 0000000000..3875950bb8
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/match/super.go
@@ -0,0 +1,33 @@
+package match
+
+import (
+ "fmt"
+)
+
+type Super struct{}
+
+func NewSuper() Super {
+ return Super{}
+}
+
+func (self Super) Match(s string) bool {
+ return true
+}
+
+func (self Super) Len() int {
+ return lenNo
+}
+
+func (self Super) Index(s string) (int, []int) {
+ segments := acquireSegments(len(s) + 1)
+ for i := range s {
+ segments = append(segments, i)
+ }
+ segments = append(segments, len(s))
+
+ return 0, segments
+}
+
+func (self Super) String() string {
+ return fmt.Sprintf("")
+}
diff --git a/vendor/github.com/gobwas/glob/match/text.go b/vendor/github.com/gobwas/glob/match/text.go
new file mode 100644
index 0000000000..0a17616d3c
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/match/text.go
@@ -0,0 +1,45 @@
+package match
+
+import (
+ "fmt"
+ "strings"
+ "unicode/utf8"
+)
+
+// raw represents raw string to match
+type Text struct {
+ Str string
+ RunesLength int
+ BytesLength int
+ Segments []int
+}
+
+func NewText(s string) Text {
+ return Text{
+ Str: s,
+ RunesLength: utf8.RuneCountInString(s),
+ BytesLength: len(s),
+ Segments: []int{len(s)},
+ }
+}
+
+func (self Text) Match(s string) bool {
+ return self.Str == s
+}
+
+func (self Text) Len() int {
+ return self.RunesLength
+}
+
+func (self Text) Index(s string) (int, []int) {
+ index := strings.Index(s, self.Str)
+ if index == -1 {
+ return -1, nil
+ }
+
+ return index, self.Segments
+}
+
+func (self Text) String() string {
+ return fmt.Sprintf("", self.Str)
+}
diff --git a/vendor/github.com/gobwas/glob/readme.md b/vendor/github.com/gobwas/glob/readme.md
new file mode 100644
index 0000000000..f58144e733
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/readme.md
@@ -0,0 +1,148 @@
+# glob.[go](https://golang.org)
+
+[![GoDoc][godoc-image]][godoc-url] [![Build Status][travis-image]][travis-url]
+
+> Go Globbing Library.
+
+## Install
+
+```shell
+ go get github.com/gobwas/glob
+```
+
+## Example
+
+```go
+
+package main
+
+import "github.com/gobwas/glob"
+
+func main() {
+ var g glob.Glob
+
+ // create simple glob
+ g = glob.MustCompile("*.github.com")
+ g.Match("api.github.com") // true
+
+ // quote meta characters and then create simple glob
+ g = glob.MustCompile(glob.QuoteMeta("*.github.com"))
+ g.Match("*.github.com") // true
+
+ // create new glob with set of delimiters as ["."]
+ g = glob.MustCompile("api.*.com", '.')
+ g.Match("api.github.com") // true
+ g.Match("api.gi.hub.com") // false
+
+ // create new glob with set of delimiters as ["."]
+ // but now with super wildcard
+ g = glob.MustCompile("api.**.com", '.')
+ g.Match("api.github.com") // true
+ g.Match("api.gi.hub.com") // true
+
+ // create glob with single symbol wildcard
+ g = glob.MustCompile("?at")
+ g.Match("cat") // true
+ g.Match("fat") // true
+ g.Match("at") // false
+
+ // create glob with single symbol wildcard and delimiters ['f']
+ g = glob.MustCompile("?at", 'f')
+ g.Match("cat") // true
+ g.Match("fat") // false
+ g.Match("at") // false
+
+ // create glob with character-list matchers
+ g = glob.MustCompile("[abc]at")
+ g.Match("cat") // true
+ g.Match("bat") // true
+ g.Match("fat") // false
+ g.Match("at") // false
+
+ // create glob with character-list matchers
+ g = glob.MustCompile("[!abc]at")
+ g.Match("cat") // false
+ g.Match("bat") // false
+ g.Match("fat") // true
+ g.Match("at") // false
+
+ // create glob with character-range matchers
+ g = glob.MustCompile("[a-c]at")
+ g.Match("cat") // true
+ g.Match("bat") // true
+ g.Match("fat") // false
+ g.Match("at") // false
+
+ // create glob with character-range matchers
+ g = glob.MustCompile("[!a-c]at")
+ g.Match("cat") // false
+ g.Match("bat") // false
+ g.Match("fat") // true
+ g.Match("at") // false
+
+ // create glob with pattern-alternatives list
+ g = glob.MustCompile("{cat,bat,[fr]at}")
+ g.Match("cat") // true
+ g.Match("bat") // true
+ g.Match("fat") // true
+ g.Match("rat") // true
+ g.Match("at") // false
+ g.Match("zat") // false
+}
+
+```
+
+## Performance
+
+This library is created for compile-once patterns. This means, that compilation could take time, but
+strings matching is done faster, than in case when always parsing template.
+
+If you will not use compiled `glob.Glob` object, and do `g := glob.MustCompile(pattern); g.Match(...)` every time, then your code will be much more slower.
+
+Run `go test -bench=.` from source root to see the benchmarks:
+
+Pattern | Fixture | Match | Speed (ns/op)
+--------|---------|-------|--------------
+`[a-z][!a-x]*cat*[h][!b]*eyes*` | `my cat has very bright eyes` | `true` | 432
+`[a-z][!a-x]*cat*[h][!b]*eyes*` | `my dog has very bright eyes` | `false` | 199
+`https://*.google.*` | `https://account.google.com` | `true` | 96
+`https://*.google.*` | `https://google.com` | `false` | 66
+`{https://*.google.*,*yandex.*,*yahoo.*,*mail.ru}` | `http://yahoo.com` | `true` | 163
+`{https://*.google.*,*yandex.*,*yahoo.*,*mail.ru}` | `http://google.com` | `false` | 197
+`{https://*gobwas.com,http://exclude.gobwas.com}` | `https://safe.gobwas.com` | `true` | 22
+`{https://*gobwas.com,http://exclude.gobwas.com}` | `http://safe.gobwas.com` | `false` | 24
+`abc*` | `abcdef` | `true` | 8.15
+`abc*` | `af` | `false` | 5.68
+`*def` | `abcdef` | `true` | 8.84
+`*def` | `af` | `false` | 5.74
+`ab*ef` | `abcdef` | `true` | 15.2
+`ab*ef` | `af` | `false` | 10.4
+
+The same things with `regexp` package:
+
+Pattern | Fixture | Match | Speed (ns/op)
+--------|---------|-------|--------------
+`^[a-z][^a-x].*cat.*[h][^b].*eyes.*$` | `my cat has very bright eyes` | `true` | 2553
+`^[a-z][^a-x].*cat.*[h][^b].*eyes.*$` | `my dog has very bright eyes` | `false` | 1383
+`^https:\/\/.*\.google\..*$` | `https://account.google.com` | `true` | 1205
+`^https:\/\/.*\.google\..*$` | `https://google.com` | `false` | 767
+`^(https:\/\/.*\.google\..*|.*yandex\..*|.*yahoo\..*|.*mail\.ru)$` | `http://yahoo.com` | `true` | 1435
+`^(https:\/\/.*\.google\..*|.*yandex\..*|.*yahoo\..*|.*mail\.ru)$` | `http://google.com` | `false` | 1674
+`^(https:\/\/.*gobwas\.com|http://exclude.gobwas.com)$` | `https://safe.gobwas.com` | `true` | 1039
+`^(https:\/\/.*gobwas\.com|http://exclude.gobwas.com)$` | `http://safe.gobwas.com` | `false` | 272
+`^abc.*$` | `abcdef` | `true` | 237
+`^abc.*$` | `af` | `false` | 100
+`^.*def$` | `abcdef` | `true` | 464
+`^.*def$` | `af` | `false` | 265
+`^ab.*ef$` | `abcdef` | `true` | 375
+`^ab.*ef$` | `af` | `false` | 145
+
+[godoc-image]: https://godoc.org/github.com/gobwas/glob?status.svg
+[godoc-url]: https://godoc.org/github.com/gobwas/glob
+[travis-image]: https://travis-ci.org/gobwas/glob.svg?branch=master
+[travis-url]: https://travis-ci.org/gobwas/glob
+
+## Syntax
+
+Syntax is inspired by [standard wildcards](http://tldp.org/LDP/GNU-Linux-Tools-Summary/html/x11655.htm),
+except that `**` is aka super-asterisk, that do not sensitive for separators.
\ No newline at end of file
diff --git a/vendor/github.com/gobwas/glob/syntax/ast/ast.go b/vendor/github.com/gobwas/glob/syntax/ast/ast.go
new file mode 100644
index 0000000000..3220a694a9
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/syntax/ast/ast.go
@@ -0,0 +1,122 @@
+package ast
+
+import (
+ "bytes"
+ "fmt"
+)
+
+type Node struct {
+ Parent *Node
+ Children []*Node
+ Value interface{}
+ Kind Kind
+}
+
+func NewNode(k Kind, v interface{}, ch ...*Node) *Node {
+ n := &Node{
+ Kind: k,
+ Value: v,
+ }
+ for _, c := range ch {
+ Insert(n, c)
+ }
+ return n
+}
+
+func (a *Node) Equal(b *Node) bool {
+ if a.Kind != b.Kind {
+ return false
+ }
+ if a.Value != b.Value {
+ return false
+ }
+ if len(a.Children) != len(b.Children) {
+ return false
+ }
+ for i, c := range a.Children {
+ if !c.Equal(b.Children[i]) {
+ return false
+ }
+ }
+ return true
+}
+
+func (a *Node) String() string {
+ var buf bytes.Buffer
+ buf.WriteString(a.Kind.String())
+ if a.Value != nil {
+ buf.WriteString(" =")
+ buf.WriteString(fmt.Sprintf("%v", a.Value))
+ }
+ if len(a.Children) > 0 {
+ buf.WriteString(" [")
+ for i, c := range a.Children {
+ if i > 0 {
+ buf.WriteString(", ")
+ }
+ buf.WriteString(c.String())
+ }
+ buf.WriteString("]")
+ }
+ return buf.String()
+}
+
+func Insert(parent *Node, children ...*Node) {
+ parent.Children = append(parent.Children, children...)
+ for _, ch := range children {
+ ch.Parent = parent
+ }
+}
+
+type List struct {
+ Not bool
+ Chars string
+}
+
+type Range struct {
+ Not bool
+ Lo, Hi rune
+}
+
+type Text struct {
+ Text string
+}
+
+type Kind int
+
+const (
+ KindNothing Kind = iota
+ KindPattern
+ KindList
+ KindRange
+ KindText
+ KindAny
+ KindSuper
+ KindSingle
+ KindAnyOf
+)
+
+func (k Kind) String() string {
+ switch k {
+ case KindNothing:
+ return "Nothing"
+ case KindPattern:
+ return "Pattern"
+ case KindList:
+ return "List"
+ case KindRange:
+ return "Range"
+ case KindText:
+ return "Text"
+ case KindAny:
+ return "Any"
+ case KindSuper:
+ return "Super"
+ case KindSingle:
+ return "Single"
+ case KindAnyOf:
+ return "AnyOf"
+ default:
+ return ""
+ }
+}
diff --git a/vendor/github.com/gobwas/glob/syntax/ast/parser.go b/vendor/github.com/gobwas/glob/syntax/ast/parser.go
new file mode 100644
index 0000000000..429b409430
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/syntax/ast/parser.go
@@ -0,0 +1,157 @@
+package ast
+
+import (
+ "errors"
+ "fmt"
+ "github.com/gobwas/glob/syntax/lexer"
+ "unicode/utf8"
+)
+
+type Lexer interface {
+ Next() lexer.Token
+}
+
+type parseFn func(*Node, Lexer) (parseFn, *Node, error)
+
+func Parse(lexer Lexer) (*Node, error) {
+ var parser parseFn
+
+ root := NewNode(KindPattern, nil)
+
+ var (
+ tree *Node
+ err error
+ )
+ for parser, tree = parserMain, root; parser != nil; {
+ parser, tree, err = parser(tree, lexer)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return root, nil
+}
+
+func parserMain(tree *Node, lex Lexer) (parseFn, *Node, error) {
+ for {
+ token := lex.Next()
+ switch token.Type {
+ case lexer.EOF:
+ return nil, tree, nil
+
+ case lexer.Error:
+ return nil, tree, errors.New(token.Raw)
+
+ case lexer.Text:
+ Insert(tree, NewNode(KindText, Text{token.Raw}))
+ return parserMain, tree, nil
+
+ case lexer.Any:
+ Insert(tree, NewNode(KindAny, nil))
+ return parserMain, tree, nil
+
+ case lexer.Super:
+ Insert(tree, NewNode(KindSuper, nil))
+ return parserMain, tree, nil
+
+ case lexer.Single:
+ Insert(tree, NewNode(KindSingle, nil))
+ return parserMain, tree, nil
+
+ case lexer.RangeOpen:
+ return parserRange, tree, nil
+
+ case lexer.TermsOpen:
+ a := NewNode(KindAnyOf, nil)
+ Insert(tree, a)
+
+ p := NewNode(KindPattern, nil)
+ Insert(a, p)
+
+ return parserMain, p, nil
+
+ case lexer.Separator:
+ p := NewNode(KindPattern, nil)
+ Insert(tree.Parent, p)
+
+ return parserMain, p, nil
+
+ case lexer.TermsClose:
+ return parserMain, tree.Parent.Parent, nil
+
+ default:
+ return nil, tree, fmt.Errorf("unexpected token: %s", token)
+ }
+ }
+ return nil, tree, fmt.Errorf("unknown error")
+}
+
+func parserRange(tree *Node, lex Lexer) (parseFn, *Node, error) {
+ var (
+ not bool
+ lo rune
+ hi rune
+ chars string
+ )
+ for {
+ token := lex.Next()
+ switch token.Type {
+ case lexer.EOF:
+ return nil, tree, errors.New("unexpected end")
+
+ case lexer.Error:
+ return nil, tree, errors.New(token.Raw)
+
+ case lexer.Not:
+ not = true
+
+ case lexer.RangeLo:
+ r, w := utf8.DecodeRuneInString(token.Raw)
+ if len(token.Raw) > w {
+ return nil, tree, fmt.Errorf("unexpected length of lo character")
+ }
+ lo = r
+
+ case lexer.RangeBetween:
+ //
+
+ case lexer.RangeHi:
+ r, w := utf8.DecodeRuneInString(token.Raw)
+ if len(token.Raw) > w {
+ return nil, tree, fmt.Errorf("unexpected length of lo character")
+ }
+
+ hi = r
+
+ if hi < lo {
+ return nil, tree, fmt.Errorf("hi character '%s' should be greater than lo '%s'", string(hi), string(lo))
+ }
+
+ case lexer.Text:
+ chars = token.Raw
+
+ case lexer.RangeClose:
+ isRange := lo != 0 && hi != 0
+ isChars := chars != ""
+
+ if isChars == isRange {
+ return nil, tree, fmt.Errorf("could not parse range")
+ }
+
+ if isRange {
+ Insert(tree, NewNode(KindRange, Range{
+ Lo: lo,
+ Hi: hi,
+ Not: not,
+ }))
+ } else {
+ Insert(tree, NewNode(KindList, List{
+ Chars: chars,
+ Not: not,
+ }))
+ }
+
+ return parserMain, tree, nil
+ }
+ }
+}
diff --git a/vendor/github.com/gobwas/glob/syntax/lexer/lexer.go b/vendor/github.com/gobwas/glob/syntax/lexer/lexer.go
new file mode 100644
index 0000000000..a1c8d1962a
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/syntax/lexer/lexer.go
@@ -0,0 +1,273 @@
+package lexer
+
+import (
+ "bytes"
+ "fmt"
+ "github.com/gobwas/glob/util/runes"
+ "unicode/utf8"
+)
+
+const (
+ char_any = '*'
+ char_comma = ','
+ char_single = '?'
+ char_escape = '\\'
+ char_range_open = '['
+ char_range_close = ']'
+ char_terms_open = '{'
+ char_terms_close = '}'
+ char_range_not = '!'
+ char_range_between = '-'
+)
+
+var specials = []byte{
+ char_any,
+ char_single,
+ char_escape,
+ char_range_open,
+ char_range_close,
+ char_terms_open,
+ char_terms_close,
+}
+
+func Special(c byte) bool {
+ return bytes.IndexByte(specials, c) != -1
+}
+
+type tokens []Token
+
+func (i *tokens) shift() (ret Token) {
+ ret = (*i)[0]
+ copy(*i, (*i)[1:])
+ *i = (*i)[:len(*i)-1]
+ return
+}
+
+func (i *tokens) push(v Token) {
+ *i = append(*i, v)
+}
+
+func (i *tokens) empty() bool {
+ return len(*i) == 0
+}
+
+var eof rune = 0
+
+type lexer struct {
+ data string
+ pos int
+ err error
+
+ tokens tokens
+ termsLevel int
+
+ lastRune rune
+ lastRuneSize int
+ hasRune bool
+}
+
+func NewLexer(source string) *lexer {
+ l := &lexer{
+ data: source,
+ tokens: tokens(make([]Token, 0, 4)),
+ }
+ return l
+}
+
+func (l *lexer) Next() Token {
+ if l.err != nil {
+ return Token{Error, l.err.Error()}
+ }
+ if !l.tokens.empty() {
+ return l.tokens.shift()
+ }
+
+ l.fetchItem()
+ return l.Next()
+}
+
+func (l *lexer) peek() (r rune, w int) {
+ if l.pos == len(l.data) {
+ return eof, 0
+ }
+
+ r, w = utf8.DecodeRuneInString(l.data[l.pos:])
+ if r == utf8.RuneError {
+ l.errorf("could not read rune")
+ r = eof
+ w = 0
+ }
+
+ return
+}
+
+func (l *lexer) read() rune {
+ if l.hasRune {
+ l.hasRune = false
+ l.seek(l.lastRuneSize)
+ return l.lastRune
+ }
+
+ r, s := l.peek()
+ l.seek(s)
+
+ l.lastRune = r
+ l.lastRuneSize = s
+
+ return r
+}
+
+func (l *lexer) seek(w int) {
+ l.pos += w
+}
+
+func (l *lexer) unread() {
+ if l.hasRune {
+ l.errorf("could not unread rune")
+ return
+ }
+ l.seek(-l.lastRuneSize)
+ l.hasRune = true
+}
+
+func (l *lexer) errorf(f string, v ...interface{}) {
+ l.err = fmt.Errorf(f, v...)
+}
+
+func (l *lexer) inTerms() bool {
+ return l.termsLevel > 0
+}
+
+func (l *lexer) termsEnter() {
+ l.termsLevel++
+}
+
+func (l *lexer) termsLeave() {
+ l.termsLevel--
+}
+
+var inTextBreakers = []rune{char_single, char_any, char_range_open, char_terms_open}
+var inTermsBreakers = append(inTextBreakers, char_terms_close, char_comma)
+
+func (l *lexer) fetchItem() {
+ r := l.read()
+ switch {
+ case r == eof:
+ l.tokens.push(Token{EOF, ""})
+
+ case r == char_terms_open:
+ l.termsEnter()
+ l.tokens.push(Token{TermsOpen, string(r)})
+
+ case r == char_comma && l.inTerms():
+ l.tokens.push(Token{Separator, string(r)})
+
+ case r == char_terms_close && l.inTerms():
+ l.tokens.push(Token{TermsClose, string(r)})
+ l.termsLeave()
+
+ case r == char_range_open:
+ l.tokens.push(Token{RangeOpen, string(r)})
+ l.fetchRange()
+
+ case r == char_single:
+ l.tokens.push(Token{Single, string(r)})
+
+ case r == char_any:
+ if l.read() == char_any {
+ l.tokens.push(Token{Super, string(r) + string(r)})
+ } else {
+ l.unread()
+ l.tokens.push(Token{Any, string(r)})
+ }
+
+ default:
+ l.unread()
+
+ var breakers []rune
+ if l.inTerms() {
+ breakers = inTermsBreakers
+ } else {
+ breakers = inTextBreakers
+ }
+ l.fetchText(breakers)
+ }
+}
+
+func (l *lexer) fetchRange() {
+ var wantHi bool
+ var wantClose bool
+ var seenNot bool
+ for {
+ r := l.read()
+ if r == eof {
+ l.errorf("unexpected end of input")
+ return
+ }
+
+ if wantClose {
+ if r != char_range_close {
+ l.errorf("expected close range character")
+ } else {
+ l.tokens.push(Token{RangeClose, string(r)})
+ }
+ return
+ }
+
+ if wantHi {
+ l.tokens.push(Token{RangeHi, string(r)})
+ wantClose = true
+ continue
+ }
+
+ if !seenNot && r == char_range_not {
+ l.tokens.push(Token{Not, string(r)})
+ seenNot = true
+ continue
+ }
+
+ if n, w := l.peek(); n == char_range_between {
+ l.seek(w)
+ l.tokens.push(Token{RangeLo, string(r)})
+ l.tokens.push(Token{RangeBetween, string(n)})
+ wantHi = true
+ continue
+ }
+
+ l.unread() // unread first peek and fetch as text
+ l.fetchText([]rune{char_range_close})
+ wantClose = true
+ }
+}
+
+func (l *lexer) fetchText(breakers []rune) {
+ var data []rune
+ var escaped bool
+
+reading:
+ for {
+ r := l.read()
+ if r == eof {
+ break
+ }
+
+ if !escaped {
+ if r == char_escape {
+ escaped = true
+ continue
+ }
+
+ if runes.IndexRune(breakers, r) != -1 {
+ l.unread()
+ break reading
+ }
+ }
+
+ escaped = false
+ data = append(data, r)
+ }
+
+ if len(data) > 0 {
+ l.tokens.push(Token{Text, string(data)})
+ }
+}
diff --git a/vendor/github.com/gobwas/glob/syntax/lexer/token.go b/vendor/github.com/gobwas/glob/syntax/lexer/token.go
new file mode 100644
index 0000000000..2797c4e83a
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/syntax/lexer/token.go
@@ -0,0 +1,88 @@
+package lexer
+
+import "fmt"
+
+type TokenType int
+
+const (
+ EOF TokenType = iota
+ Error
+ Text
+ Char
+ Any
+ Super
+ Single
+ Not
+ Separator
+ RangeOpen
+ RangeClose
+ RangeLo
+ RangeHi
+ RangeBetween
+ TermsOpen
+ TermsClose
+)
+
+func (tt TokenType) String() string {
+ switch tt {
+ case EOF:
+ return "eof"
+
+ case Error:
+ return "error"
+
+ case Text:
+ return "text"
+
+ case Char:
+ return "char"
+
+ case Any:
+ return "any"
+
+ case Super:
+ return "super"
+
+ case Single:
+ return "single"
+
+ case Not:
+ return "not"
+
+ case Separator:
+ return "separator"
+
+ case RangeOpen:
+ return "range_open"
+
+ case RangeClose:
+ return "range_close"
+
+ case RangeLo:
+ return "range_lo"
+
+ case RangeHi:
+ return "range_hi"
+
+ case RangeBetween:
+ return "range_between"
+
+ case TermsOpen:
+ return "terms_open"
+
+ case TermsClose:
+ return "terms_close"
+
+ default:
+ return "undef"
+ }
+}
+
+type Token struct {
+ Type TokenType
+ Raw string
+}
+
+func (t Token) String() string {
+ return fmt.Sprintf("%v<%q>", t.Type, t.Raw)
+}
diff --git a/vendor/github.com/gobwas/glob/syntax/syntax.go b/vendor/github.com/gobwas/glob/syntax/syntax.go
new file mode 100644
index 0000000000..1d168b1482
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/syntax/syntax.go
@@ -0,0 +1,14 @@
+package syntax
+
+import (
+ "github.com/gobwas/glob/syntax/ast"
+ "github.com/gobwas/glob/syntax/lexer"
+)
+
+func Parse(s string) (*ast.Node, error) {
+ return ast.Parse(lexer.NewLexer(s))
+}
+
+func Special(b byte) bool {
+ return lexer.Special(b)
+}
diff --git a/vendor/github.com/gobwas/glob/util/runes/runes.go b/vendor/github.com/gobwas/glob/util/runes/runes.go
new file mode 100644
index 0000000000..a723556410
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/util/runes/runes.go
@@ -0,0 +1,154 @@
+package runes
+
+func Index(s, needle []rune) int {
+ ls, ln := len(s), len(needle)
+
+ switch {
+ case ln == 0:
+ return 0
+ case ln == 1:
+ return IndexRune(s, needle[0])
+ case ln == ls:
+ if Equal(s, needle) {
+ return 0
+ }
+ return -1
+ case ln > ls:
+ return -1
+ }
+
+head:
+ for i := 0; i < ls && ls-i >= ln; i++ {
+ for y := 0; y < ln; y++ {
+ if s[i+y] != needle[y] {
+ continue head
+ }
+ }
+
+ return i
+ }
+
+ return -1
+}
+
+func LastIndex(s, needle []rune) int {
+ ls, ln := len(s), len(needle)
+
+ switch {
+ case ln == 0:
+ if ls == 0 {
+ return 0
+ }
+ return ls
+ case ln == 1:
+ return IndexLastRune(s, needle[0])
+ case ln == ls:
+ if Equal(s, needle) {
+ return 0
+ }
+ return -1
+ case ln > ls:
+ return -1
+ }
+
+head:
+ for i := ls - 1; i >= 0 && i >= ln; i-- {
+ for y := ln - 1; y >= 0; y-- {
+ if s[i-(ln-y-1)] != needle[y] {
+ continue head
+ }
+ }
+
+ return i - ln + 1
+ }
+
+ return -1
+}
+
+// IndexAny returns the index of the first instance of any Unicode code point
+// from chars in s, or -1 if no Unicode code point from chars is present in s.
+func IndexAny(s, chars []rune) int {
+ if len(chars) > 0 {
+ for i, c := range s {
+ for _, m := range chars {
+ if c == m {
+ return i
+ }
+ }
+ }
+ }
+ return -1
+}
+
+func Contains(s, needle []rune) bool {
+ return Index(s, needle) >= 0
+}
+
+func Max(s []rune) (max rune) {
+ for _, r := range s {
+ if r > max {
+ max = r
+ }
+ }
+
+ return
+}
+
+func Min(s []rune) rune {
+ min := rune(-1)
+ for _, r := range s {
+ if min == -1 {
+ min = r
+ continue
+ }
+
+ if r < min {
+ min = r
+ }
+ }
+
+ return min
+}
+
+func IndexRune(s []rune, r rune) int {
+ for i, c := range s {
+ if c == r {
+ return i
+ }
+ }
+ return -1
+}
+
+func IndexLastRune(s []rune, r rune) int {
+ for i := len(s) - 1; i >= 0; i-- {
+ if s[i] == r {
+ return i
+ }
+ }
+
+ return -1
+}
+
+func Equal(a, b []rune) bool {
+ if len(a) == len(b) {
+ for i := 0; i < len(a); i++ {
+ if a[i] != b[i] {
+ return false
+ }
+ }
+
+ return true
+ }
+
+ return false
+}
+
+// HasPrefix tests whether the string s begins with prefix.
+func HasPrefix(s, prefix []rune) bool {
+ return len(s) >= len(prefix) && Equal(s[0:len(prefix)], prefix)
+}
+
+// HasSuffix tests whether the string s ends with suffix.
+func HasSuffix(s, suffix []rune) bool {
+ return len(s) >= len(suffix) && Equal(s[len(s)-len(suffix):], suffix)
+}
diff --git a/vendor/github.com/gobwas/glob/util/strings/strings.go b/vendor/github.com/gobwas/glob/util/strings/strings.go
new file mode 100644
index 0000000000..e8ee1920b1
--- /dev/null
+++ b/vendor/github.com/gobwas/glob/util/strings/strings.go
@@ -0,0 +1,39 @@
+package strings
+
+import (
+ "strings"
+ "unicode/utf8"
+)
+
+func IndexAnyRunes(s string, rs []rune) int {
+ for _, r := range rs {
+ if i := strings.IndexRune(s, r); i != -1 {
+ return i
+ }
+ }
+
+ return -1
+}
+
+func LastIndexAnyRunes(s string, rs []rune) int {
+ for _, r := range rs {
+ i := -1
+ if 0 <= r && r < utf8.RuneSelf {
+ i = strings.LastIndexByte(s, byte(r))
+ } else {
+ sub := s
+ for len(sub) > 0 {
+ j := strings.IndexRune(s, r)
+ if j == -1 {
+ break
+ }
+ i = j
+ sub = sub[i+1:]
+ }
+ }
+ if i != -1 {
+ return i
+ }
+ }
+ return -1
+}
diff --git a/vendor/github.com/google/gnostic-models/extensions/extension.proto b/vendor/github.com/google/gnostic-models/extensions/extension.proto
index 875137c1a8..a600429890 100644
--- a/vendor/github.com/google/gnostic-models/extensions/extension.proto
+++ b/vendor/github.com/google/gnostic-models/extensions/extension.proto
@@ -42,7 +42,7 @@ option java_package = "org.gnostic.v1";
option objc_class_prefix = "GNX";
// The Go package name.
-option go_package = "./extensions;gnostic_extension_v1";
+option go_package = "github.com/google/gnostic-models/extensions;gnostic_extension_v1";
// The version number of Gnostic.
message Version {
diff --git a/vendor/github.com/google/gnostic-models/openapiv2/OpenAPIv2.proto b/vendor/github.com/google/gnostic-models/openapiv2/OpenAPIv2.proto
index 1c59b2f4ae..49adafcc8e 100644
--- a/vendor/github.com/google/gnostic-models/openapiv2/OpenAPIv2.proto
+++ b/vendor/github.com/google/gnostic-models/openapiv2/OpenAPIv2.proto
@@ -42,7 +42,7 @@ option java_package = "org.openapi_v2";
option objc_class_prefix = "OAS";
// The Go package name.
-option go_package = "./openapiv2;openapi_v2";
+option go_package = "github.com/google/gnostic-models/openapiv2;openapi_v2";
message AdditionalPropertiesItem {
oneof oneof {
diff --git a/vendor/github.com/google/gnostic-models/openapiv3/OpenAPIv3.proto b/vendor/github.com/google/gnostic-models/openapiv3/OpenAPIv3.proto
index 1be335b89b..af4b6254bc 100644
--- a/vendor/github.com/google/gnostic-models/openapiv3/OpenAPIv3.proto
+++ b/vendor/github.com/google/gnostic-models/openapiv3/OpenAPIv3.proto
@@ -42,7 +42,7 @@ option java_package = "org.openapi_v3";
option objc_class_prefix = "OAS";
// The Go package name.
-option go_package = "./openapiv3;openapi_v3";
+option go_package = "github.com/google/gnostic-models/openapiv3;openapi_v3";
message AdditionalPropertiesItem {
oneof oneof {
diff --git a/vendor/github.com/google/gnostic-models/openapiv3/annotations.proto b/vendor/github.com/google/gnostic-models/openapiv3/annotations.proto
index 09ee0aac51..895b4567cd 100644
--- a/vendor/github.com/google/gnostic-models/openapiv3/annotations.proto
+++ b/vendor/github.com/google/gnostic-models/openapiv3/annotations.proto
@@ -20,7 +20,7 @@ import "google/protobuf/descriptor.proto";
import "openapiv3/OpenAPIv3.proto";
// The Go package name.
-option go_package = "./openapiv3;openapi_v3";
+option go_package = "github.com/google/gnostic-models/openapiv3;openapi_v3";
// This option lets the proto compiler generate Java code inside the package
// name (see below) instead of inside an outer class. It creates a simpler
// developer experience by reducing one-level of name nesting and be
diff --git a/vendor/github.com/gosuri/uitable/.travis.yml b/vendor/github.com/gosuri/uitable/.travis.yml
new file mode 100644
index 0000000000..26fc3b438b
--- /dev/null
+++ b/vendor/github.com/gosuri/uitable/.travis.yml
@@ -0,0 +1,6 @@
+language: go
+sudo: false
+install:
+ - go get ./...
+go:
+ - tip
diff --git a/vendor/github.com/gosuri/uitable/LICENSE b/vendor/github.com/gosuri/uitable/LICENSE
new file mode 100644
index 0000000000..e436d90439
--- /dev/null
+++ b/vendor/github.com/gosuri/uitable/LICENSE
@@ -0,0 +1,10 @@
+MIT License
+===========
+
+Copyright (c) 2015, Greg Osuri
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/gosuri/uitable/Makefile b/vendor/github.com/gosuri/uitable/Makefile
new file mode 100644
index 0000000000..60246a8a93
--- /dev/null
+++ b/vendor/github.com/gosuri/uitable/Makefile
@@ -0,0 +1,4 @@
+test:
+ @go test ./...
+
+.PHONY: test
diff --git a/vendor/github.com/gosuri/uitable/README.md b/vendor/github.com/gosuri/uitable/README.md
new file mode 100644
index 0000000000..683b538d13
--- /dev/null
+++ b/vendor/github.com/gosuri/uitable/README.md
@@ -0,0 +1,67 @@
+# uitable [](https://godoc.org/github.com/gosuri/uitable) [](https://travis-ci.org/gosuri/uitable)
+
+uitable is a go library for representing data as tables for terminal applications. It provides primitives for sizing and wrapping columns to improve readability.
+
+## Example Usage
+
+Full source code for the example is available at [example/main.go](example/main.go)
+
+```go
+table := uitable.New()
+table.MaxColWidth = 50
+
+table.AddRow("NAME", "BIRTHDAY", "BIO")
+for _, hacker := range hackers {
+ table.AddRow(hacker.Name, hacker.Birthday, hacker.Bio)
+}
+fmt.Println(table)
+```
+
+Will render the data as:
+
+```sh
+NAME BIRTHDAY BIO
+Ada Lovelace December 10, 1815 Ada was a British mathematician and writer, chi...
+Alan Turing June 23, 1912 Alan was a British pioneering computer scientis...
+```
+
+For wrapping in two columns:
+
+```go
+table = uitable.New()
+table.MaxColWidth = 80
+table.Wrap = true // wrap columns
+
+for _, hacker := range hackers {
+ table.AddRow("Name:", hacker.Name)
+ table.AddRow("Birthday:", hacker.Birthday)
+ table.AddRow("Bio:", hacker.Bio)
+ table.AddRow("") // blank
+}
+fmt.Println(table)
+```
+
+Will render the data as:
+
+```
+Name: Ada Lovelace
+Birthday: December 10, 1815
+Bio: Ada was a British mathematician and writer, chiefly known for her work on
+ Charles Babbage's early mechanical general-purpose computer, the Analytical
+ Engine
+
+Name: Alan Turing
+Birthday: June 23, 1912
+Bio: Alan was a British pioneering computer scientist, mathematician, logician,
+ cryptanalyst and theoretical biologist
+```
+
+## Installation
+
+```
+$ go get -v github.com/gosuri/uitable
+```
+
+
+[](https://bitdeli.com/free "Bitdeli Badge")
+
diff --git a/vendor/github.com/gosuri/uitable/table.go b/vendor/github.com/gosuri/uitable/table.go
new file mode 100644
index 0000000000..b764e51502
--- /dev/null
+++ b/vendor/github.com/gosuri/uitable/table.go
@@ -0,0 +1,205 @@
+// Package uitable provides a decorator for formating data as a table
+package uitable
+
+import (
+ "fmt"
+ "strings"
+ "sync"
+
+ "github.com/fatih/color"
+ "github.com/gosuri/uitable/util/strutil"
+ "github.com/gosuri/uitable/util/wordwrap"
+)
+
+// Separator is the default column seperator
+var Separator = "\t"
+
+// Table represents a decorator that renders the data in formatted in a table
+type Table struct {
+ // Rows is the collection of rows in the table
+ Rows []*Row
+
+ // MaxColWidth is the maximum allowed width for cells in the table
+ MaxColWidth uint
+
+ // Wrap when set to true wraps the contents of the columns when the length exceeds the MaxColWidth
+ Wrap bool
+
+ // Separator is the seperator for columns in the table. Default is "\t"
+ Separator string
+
+ mtx *sync.RWMutex
+ rightAlign map[int]bool
+}
+
+// New returns a new Table with default values
+func New() *Table {
+ return &Table{
+ Separator: Separator,
+ mtx: new(sync.RWMutex),
+ rightAlign: map[int]bool{},
+ }
+}
+
+// AddRow adds a new row to the table
+func (t *Table) AddRow(data ...interface{}) *Table {
+ t.mtx.Lock()
+ defer t.mtx.Unlock()
+ r := NewRow(data...)
+ t.Rows = append(t.Rows, r)
+ return t
+}
+
+// Bytes returns the []byte value of table
+func (t *Table) Bytes() []byte {
+ return []byte(t.String())
+}
+
+func (t *Table) RightAlign(col int) {
+ t.mtx.Lock()
+ t.rightAlign[col] = true
+ t.mtx.Unlock()
+}
+
+// String returns the string value of table
+func (t *Table) String() string {
+ t.mtx.RLock()
+ defer t.mtx.RUnlock()
+
+ if len(t.Rows) == 0 {
+ return ""
+ }
+
+ // determine the width for each column (cell in a row)
+ var colwidths []uint
+ for _, row := range t.Rows {
+ for i, cell := range row.Cells {
+ // resize colwidth array
+ if i+1 > len(colwidths) {
+ colwidths = append(colwidths, 0)
+ }
+ cellwidth := cell.LineWidth()
+ if t.MaxColWidth != 0 && cellwidth > t.MaxColWidth {
+ cellwidth = t.MaxColWidth
+ }
+
+ if cellwidth > colwidths[i] {
+ colwidths[i] = cellwidth
+ }
+ }
+ }
+
+ var lines []string
+ for _, row := range t.Rows {
+ row.Separator = t.Separator
+ for i, cell := range row.Cells {
+ cell.Width = colwidths[i]
+ cell.Wrap = t.Wrap
+ cell.RightAlign = t.rightAlign[i]
+ }
+ lines = append(lines, row.String())
+ }
+ return strutil.Join(lines, "\n")
+}
+
+// Row represents a row in a table
+type Row struct {
+ // Cells is the group of cell for the row
+ Cells []*Cell
+
+ // Separator for tabular columns
+ Separator string
+}
+
+// NewRow returns a new Row and adds the data to the row
+func NewRow(data ...interface{}) *Row {
+ r := &Row{Cells: make([]*Cell, len(data))}
+ for i, d := range data {
+ r.Cells[i] = &Cell{Data: d}
+ }
+ return r
+}
+
+// String returns the string representation of the row
+func (r *Row) String() string {
+ // get the max number of lines for each cell
+ var lc int // line count
+ for _, cell := range r.Cells {
+ if clc := len(strings.Split(cell.String(), "\n")); clc > lc {
+ lc = clc
+ }
+ }
+
+ // allocate a two-dimentional array of cells for each line and add size them
+ cells := make([][]*Cell, lc)
+ for x := 0; x < lc; x++ {
+ cells[x] = make([]*Cell, len(r.Cells))
+ for y := 0; y < len(r.Cells); y++ {
+ cells[x][y] = &Cell{Width: r.Cells[y].Width}
+ }
+ }
+
+ // insert each line in a cell as new cell in the cells array
+ for y, cell := range r.Cells {
+ lines := strings.Split(cell.String(), "\n")
+ for x, line := range lines {
+ cells[x][y].Data = line
+ }
+ }
+
+ // format each line
+ lines := make([]string, lc)
+ for x := range lines {
+ line := make([]string, len(cells[x]))
+ for y := range cells[x] {
+ line[y] = cells[x][y].String()
+ }
+ lines[x] = strutil.Join(line, r.Separator)
+ }
+ return strings.Join(lines, "\n")
+}
+
+// Cell represents a column in a row
+type Cell struct {
+ // Width is the width of the cell
+ Width uint
+
+ // Wrap when true wraps the contents of the cell when the lenght exceeds the width
+ Wrap bool
+
+ // RightAlign when true aligns contents to the right
+ RightAlign bool
+
+ // Data is the cell data
+ Data interface{}
+}
+
+// LineWidth returns the max width of all the lines in a cell
+func (c *Cell) LineWidth() uint {
+ width := 0
+ for _, s := range strings.Split(c.String(), "\n") {
+ w := strutil.StringWidth(s)
+ if w > width {
+ width = w
+ }
+ }
+ return uint(width)
+}
+
+// String returns the string formated representation of the cell
+func (c *Cell) String() string {
+ if c.Data == nil {
+ return strutil.PadLeft(" ", int(c.Width), ' ')
+ }
+ col := color.New(color.FgBlack)
+ col.DisableColor()
+ s := fmt.Sprintf("%v", col.Sprint(c.Data))
+ if c.Width > 0 {
+ if c.Wrap && uint(len(s)) > c.Width {
+ return wordwrap.WrapString(s, c.Width)
+ } else {
+ return strutil.Resize(s, c.Width, c.RightAlign)
+ }
+ }
+ return s
+}
diff --git a/vendor/github.com/gosuri/uitable/util/strutil/strutil.go b/vendor/github.com/gosuri/uitable/util/strutil/strutil.go
new file mode 100644
index 0000000000..53f30a8fd3
--- /dev/null
+++ b/vendor/github.com/gosuri/uitable/util/strutil/strutil.go
@@ -0,0 +1,101 @@
+// Package strutil provides various utilities for manipulating strings
+package strutil
+
+import (
+ "bytes"
+ "regexp"
+
+ "github.com/mattn/go-runewidth"
+)
+
+const ansi = "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))"
+
+var re = regexp.MustCompile(ansi)
+
+// PadRight returns a new string of a specified length in which the end of the current string is padded with spaces or with a specified Unicode character.
+func PadRight(str string, length int, pad byte) string {
+ slen := StringWidth(str)
+ if slen >= length {
+ return str
+ }
+ buf := bytes.NewBufferString(str)
+ for i := 0; i < length-slen; i++ {
+ buf.WriteByte(pad)
+ }
+ return buf.String()
+}
+
+// PadLeft returns a new string of a specified length in which the beginning of the current string is padded with spaces or with a specified Unicode character.
+func PadLeft(str string, length int, pad byte) string {
+ slen := StringWidth(str)
+ if slen >= length {
+ return str
+ }
+ var buf bytes.Buffer
+ for i := 0; i < length-slen; i++ {
+ buf.WriteByte(pad)
+ }
+ buf.WriteString(str)
+ return buf.String()
+}
+
+// Resize resizes the string with the given length. It ellipses with '...' when the string's length exceeds
+// the desired length or pads spaces to the right of the string when length is smaller than desired
+func Resize(s string, length uint, rightAlign bool) string {
+ slen := StringWidth(s)
+ n := int(length)
+ if slen == n {
+ return s
+ }
+ // Pads only when length of the string smaller than len needed
+ if rightAlign {
+ s = PadLeft(s, n, ' ')
+ } else {
+ s = PadRight(s, n, ' ')
+ }
+ if slen > n {
+ rs := []rune(s)
+ var buf bytes.Buffer
+ w := 0
+ for _, r := range rs {
+ buf.WriteRune(r)
+ rw := RuneWidth(r)
+ if w+rw >= n-3 {
+ break
+ }
+ w += rw
+ }
+ buf.WriteString("...")
+ s = buf.String()
+ }
+ return s
+}
+
+// Join joins the list of the string with the delim provided.
+// Returns an empty string for empty list
+func Join(list []string, delim string) string {
+ if len(list) == 0 {
+ return ""
+ }
+ var buf bytes.Buffer
+ for i := 0; i < len(list)-1; i++ {
+ buf.WriteString(list[i] + delim)
+ }
+ buf.WriteString(list[len(list)-1])
+ return buf.String()
+}
+
+// Strip strips the string of all colors
+func Strip(s string) string {
+ return re.ReplaceAllString(s, "")
+}
+
+// StringWidth returns the actual width of the string without colors
+func StringWidth(s string) int {
+ return runewidth.StringWidth(Strip(s))
+}
+
+// RuneWidth returns the actual width of the rune
+func RuneWidth(s rune) int {
+ return runewidth.RuneWidth(s)
+}
diff --git a/vendor/github.com/gosuri/uitable/util/wordwrap/LICENSE.md b/vendor/github.com/gosuri/uitable/util/wordwrap/LICENSE.md
new file mode 100644
index 0000000000..2298515904
--- /dev/null
+++ b/vendor/github.com/gosuri/uitable/util/wordwrap/LICENSE.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Mitchell Hashimoto
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/github.com/gosuri/uitable/util/wordwrap/README.md b/vendor/github.com/gosuri/uitable/util/wordwrap/README.md
new file mode 100644
index 0000000000..60ae311700
--- /dev/null
+++ b/vendor/github.com/gosuri/uitable/util/wordwrap/README.md
@@ -0,0 +1,39 @@
+# go-wordwrap
+
+`go-wordwrap` (Golang package: `wordwrap`) is a package for Go that
+automatically wraps words into multiple lines. The primary use case for this
+is in formatting CLI output, but of course word wrapping is a generally useful
+thing to do.
+
+## Installation and Usage
+
+Install using `go get github.com/mitchellh/go-wordwrap`.
+
+Full documentation is available at
+http://godoc.org/github.com/mitchellh/go-wordwrap
+
+Below is an example of its usage ignoring errors:
+
+```go
+wrapped := wordwrap.WrapString("foo bar baz", 3)
+fmt.Println(wrapped)
+```
+
+Would output:
+
+```
+foo
+bar
+baz
+```
+
+## Word Wrap Algorithm
+
+This library doesn't use any clever algorithm for word wrapping. The wrapping
+is actually very naive: whenever there is whitespace or an explicit linebreak.
+The goal of this library is for word wrapping CLI output, so the input is
+typically pretty well controlled human language. Because of this, the naive
+approach typically works just fine.
+
+In the future, we'd like to make the algorithm more advanced. We would do
+so without breaking the API.
diff --git a/vendor/github.com/gosuri/uitable/util/wordwrap/wordwrap.go b/vendor/github.com/gosuri/uitable/util/wordwrap/wordwrap.go
new file mode 100644
index 0000000000..b2c63b8795
--- /dev/null
+++ b/vendor/github.com/gosuri/uitable/util/wordwrap/wordwrap.go
@@ -0,0 +1,85 @@
+// Package wordwrap provides methods for wrapping the contents of a string
+package wordwrap
+
+import (
+ "bytes"
+ "unicode"
+
+ "github.com/gosuri/uitable/util/strutil"
+)
+
+// WrapString wraps the given string within lim width in characters.
+//
+// Wrapping is currently naive and only happens at white-space. A future
+// version of the library will implement smarter wrapping. This means that
+// pathological cases can dramatically reach past the limit, such as a very
+// long word.
+func WrapString(s string, lim uint) string {
+ // Initialize a buffer with a slightly larger size to account for breaks
+ init := make([]byte, 0, len(s))
+ buf := bytes.NewBuffer(init)
+
+ var current uint
+ var wordBuf, spaceBuf bytes.Buffer
+ var wordWidth, spaceWidth int
+
+ for _, char := range s {
+ if char == '\n' {
+ if wordBuf.Len() == 0 {
+ if current+uint(spaceWidth) > lim {
+ current = 0
+ } else {
+ current += uint(spaceWidth)
+ spaceBuf.WriteTo(buf)
+ spaceWidth += strutil.StringWidth(buf.String())
+ }
+ spaceBuf.Reset()
+ spaceWidth = 0
+ } else {
+ current += uint(spaceWidth + wordWidth)
+ spaceBuf.WriteTo(buf)
+ spaceBuf.Reset()
+ wordBuf.WriteTo(buf)
+ wordBuf.Reset()
+ spaceWidth = 0
+ wordWidth = 0
+ }
+ buf.WriteRune(char)
+ current = 0
+ } else if unicode.IsSpace(char) {
+ if spaceBuf.Len() == 0 || wordBuf.Len() > 0 {
+ current += uint(spaceWidth + wordWidth)
+ spaceBuf.WriteTo(buf)
+ spaceBuf.Reset()
+ wordBuf.WriteTo(buf)
+ wordBuf.Reset()
+ spaceWidth = 0
+ wordWidth = 0
+ }
+
+ spaceBuf.WriteRune(char)
+ spaceWidth += strutil.RuneWidth(char)
+ } else {
+ wordBuf.WriteRune(char)
+ wordWidth += strutil.RuneWidth(char)
+
+ if current+uint(spaceWidth+wordWidth) > lim && uint(wordWidth) < lim {
+ buf.WriteRune('\n')
+ current = 0
+ spaceBuf.Reset()
+ spaceWidth = 0
+ }
+ }
+ }
+
+ if wordBuf.Len() == 0 {
+ if current+uint(spaceWidth) <= lim {
+ spaceBuf.WriteTo(buf)
+ }
+ } else {
+ spaceBuf.WriteTo(buf)
+ wordBuf.WriteTo(buf)
+ }
+
+ return buf.String()
+}
diff --git a/vendor/github.com/gregjones/httpcache/.travis.yml b/vendor/github.com/gregjones/httpcache/.travis.yml
new file mode 100644
index 0000000000..597bc9996f
--- /dev/null
+++ b/vendor/github.com/gregjones/httpcache/.travis.yml
@@ -0,0 +1,18 @@
+sudo: false
+language: go
+matrix:
+ allow_failures:
+ - go: master
+ fast_finish: true
+ include:
+ - go: 1.10.x
+ - go: 1.11.x
+ env: GOFMT=1
+ - go: master
+install:
+ - # Do nothing. This is needed to prevent default install action "go get -t -v ./..." from happening here (we want it to happen inside script step).
+script:
+ - go get -t -v ./...
+ - if test -n "${GOFMT}"; then gofmt -w -s . && git diff --exit-code; fi
+ - go tool vet .
+ - go test -v -race ./...
diff --git a/vendor/github.com/gregjones/httpcache/LICENSE.txt b/vendor/github.com/gregjones/httpcache/LICENSE.txt
new file mode 100644
index 0000000000..81316beb0c
--- /dev/null
+++ b/vendor/github.com/gregjones/httpcache/LICENSE.txt
@@ -0,0 +1,7 @@
+Copyright © 2012 Greg Jones (greg.jones@gmail.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Softwareâ€), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED “AS ISâ€, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/vendor/github.com/gregjones/httpcache/README.md b/vendor/github.com/gregjones/httpcache/README.md
new file mode 100644
index 0000000000..51e7d23d09
--- /dev/null
+++ b/vendor/github.com/gregjones/httpcache/README.md
@@ -0,0 +1,29 @@
+httpcache
+=========
+
+[](https://travis-ci.org/gregjones/httpcache) [](https://godoc.org/github.com/gregjones/httpcache)
+
+Package httpcache provides a http.RoundTripper implementation that works as a mostly [RFC 7234](https://tools.ietf.org/html/rfc7234) compliant cache for http responses.
+
+It is only suitable for use as a 'private' cache (i.e. for a web-browser or an API-client and not for a shared proxy).
+
+This project isn't actively maintained; it works for what I, and seemingly others, want to do with it, and I consider it "done". That said, if you find any issues, please open a Pull Request and I will try to review it. Any changes now that change the public API won't be considered.
+
+Cache Backends
+--------------
+
+- The built-in 'memory' cache stores responses in an in-memory map.
+- [`github.com/gregjones/httpcache/diskcache`](https://github.com/gregjones/httpcache/tree/master/diskcache) provides a filesystem-backed cache using the [diskv](https://github.com/peterbourgon/diskv) library.
+- [`github.com/gregjones/httpcache/memcache`](https://github.com/gregjones/httpcache/tree/master/memcache) provides memcache implementations, for both App Engine and 'normal' memcache servers.
+- [`sourcegraph.com/sourcegraph/s3cache`](https://sourcegraph.com/github.com/sourcegraph/s3cache) uses Amazon S3 for storage.
+- [`github.com/gregjones/httpcache/leveldbcache`](https://github.com/gregjones/httpcache/tree/master/leveldbcache) provides a filesystem-backed cache using [leveldb](https://github.com/syndtr/goleveldb/leveldb).
+- [`github.com/die-net/lrucache`](https://github.com/die-net/lrucache) provides an in-memory cache that will evict least-recently used entries.
+- [`github.com/die-net/lrucache/twotier`](https://github.com/die-net/lrucache/tree/master/twotier) allows caches to be combined, for example to use lrucache above with a persistent disk-cache.
+- [`github.com/birkelund/boltdbcache`](https://github.com/birkelund/boltdbcache) provides a BoltDB implementation (based on the [bbolt](https://github.com/coreos/bbolt) fork).
+
+If you implement any other backend and wish it to be linked here, please send a PR editing this file.
+
+License
+-------
+
+- [MIT License](LICENSE.txt)
diff --git a/vendor/github.com/gregjones/httpcache/httpcache.go b/vendor/github.com/gregjones/httpcache/httpcache.go
new file mode 100644
index 0000000000..b41a63d1ff
--- /dev/null
+++ b/vendor/github.com/gregjones/httpcache/httpcache.go
@@ -0,0 +1,551 @@
+// Package httpcache provides a http.RoundTripper implementation that works as a
+// mostly RFC-compliant cache for http responses.
+//
+// It is only suitable for use as a 'private' cache (i.e. for a web-browser or an API-client
+// and not for a shared proxy).
+//
+package httpcache
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/http/httputil"
+ "strings"
+ "sync"
+ "time"
+)
+
+const (
+ stale = iota
+ fresh
+ transparent
+ // XFromCache is the header added to responses that are returned from the cache
+ XFromCache = "X-From-Cache"
+)
+
+// A Cache interface is used by the Transport to store and retrieve responses.
+type Cache interface {
+ // Get returns the []byte representation of a cached response and a bool
+ // set to true if the value isn't empty
+ Get(key string) (responseBytes []byte, ok bool)
+ // Set stores the []byte representation of a response against a key
+ Set(key string, responseBytes []byte)
+ // Delete removes the value associated with the key
+ Delete(key string)
+}
+
+// cacheKey returns the cache key for req.
+func cacheKey(req *http.Request) string {
+ if req.Method == http.MethodGet {
+ return req.URL.String()
+ } else {
+ return req.Method + " " + req.URL.String()
+ }
+}
+
+// CachedResponse returns the cached http.Response for req if present, and nil
+// otherwise.
+func CachedResponse(c Cache, req *http.Request) (resp *http.Response, err error) {
+ cachedVal, ok := c.Get(cacheKey(req))
+ if !ok {
+ return
+ }
+
+ b := bytes.NewBuffer(cachedVal)
+ return http.ReadResponse(bufio.NewReader(b), req)
+}
+
+// MemoryCache is an implemtation of Cache that stores responses in an in-memory map.
+type MemoryCache struct {
+ mu sync.RWMutex
+ items map[string][]byte
+}
+
+// Get returns the []byte representation of the response and true if present, false if not
+func (c *MemoryCache) Get(key string) (resp []byte, ok bool) {
+ c.mu.RLock()
+ resp, ok = c.items[key]
+ c.mu.RUnlock()
+ return resp, ok
+}
+
+// Set saves response resp to the cache with key
+func (c *MemoryCache) Set(key string, resp []byte) {
+ c.mu.Lock()
+ c.items[key] = resp
+ c.mu.Unlock()
+}
+
+// Delete removes key from the cache
+func (c *MemoryCache) Delete(key string) {
+ c.mu.Lock()
+ delete(c.items, key)
+ c.mu.Unlock()
+}
+
+// NewMemoryCache returns a new Cache that will store items in an in-memory map
+func NewMemoryCache() *MemoryCache {
+ c := &MemoryCache{items: map[string][]byte{}}
+ return c
+}
+
+// Transport is an implementation of http.RoundTripper that will return values from a cache
+// where possible (avoiding a network request) and will additionally add validators (etag/if-modified-since)
+// to repeated requests allowing servers to return 304 / Not Modified
+type Transport struct {
+ // The RoundTripper interface actually used to make requests
+ // If nil, http.DefaultTransport is used
+ Transport http.RoundTripper
+ Cache Cache
+ // If true, responses returned from the cache will be given an extra header, X-From-Cache
+ MarkCachedResponses bool
+}
+
+// NewTransport returns a new Transport with the
+// provided Cache implementation and MarkCachedResponses set to true
+func NewTransport(c Cache) *Transport {
+ return &Transport{Cache: c, MarkCachedResponses: true}
+}
+
+// Client returns an *http.Client that caches responses.
+func (t *Transport) Client() *http.Client {
+ return &http.Client{Transport: t}
+}
+
+// varyMatches will return false unless all of the cached values for the headers listed in Vary
+// match the new request
+func varyMatches(cachedResp *http.Response, req *http.Request) bool {
+ for _, header := range headerAllCommaSepValues(cachedResp.Header, "vary") {
+ header = http.CanonicalHeaderKey(header)
+ if header != "" && req.Header.Get(header) != cachedResp.Header.Get("X-Varied-"+header) {
+ return false
+ }
+ }
+ return true
+}
+
+// RoundTrip takes a Request and returns a Response
+//
+// If there is a fresh Response already in cache, then it will be returned without connecting to
+// the server.
+//
+// If there is a stale Response, then any validators it contains will be set on the new request
+// to give the server a chance to respond with NotModified. If this happens, then the cached Response
+// will be returned.
+func (t *Transport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
+ cacheKey := cacheKey(req)
+ cacheable := (req.Method == "GET" || req.Method == "HEAD") && req.Header.Get("range") == ""
+ var cachedResp *http.Response
+ if cacheable {
+ cachedResp, err = CachedResponse(t.Cache, req)
+ } else {
+ // Need to invalidate an existing value
+ t.Cache.Delete(cacheKey)
+ }
+
+ transport := t.Transport
+ if transport == nil {
+ transport = http.DefaultTransport
+ }
+
+ if cacheable && cachedResp != nil && err == nil {
+ if t.MarkCachedResponses {
+ cachedResp.Header.Set(XFromCache, "1")
+ }
+
+ if varyMatches(cachedResp, req) {
+ // Can only use cached value if the new request doesn't Vary significantly
+ freshness := getFreshness(cachedResp.Header, req.Header)
+ if freshness == fresh {
+ return cachedResp, nil
+ }
+
+ if freshness == stale {
+ var req2 *http.Request
+ // Add validators if caller hasn't already done so
+ etag := cachedResp.Header.Get("etag")
+ if etag != "" && req.Header.Get("etag") == "" {
+ req2 = cloneRequest(req)
+ req2.Header.Set("if-none-match", etag)
+ }
+ lastModified := cachedResp.Header.Get("last-modified")
+ if lastModified != "" && req.Header.Get("last-modified") == "" {
+ if req2 == nil {
+ req2 = cloneRequest(req)
+ }
+ req2.Header.Set("if-modified-since", lastModified)
+ }
+ if req2 != nil {
+ req = req2
+ }
+ }
+ }
+
+ resp, err = transport.RoundTrip(req)
+ if err == nil && req.Method == "GET" && resp.StatusCode == http.StatusNotModified {
+ // Replace the 304 response with the one from cache, but update with some new headers
+ endToEndHeaders := getEndToEndHeaders(resp.Header)
+ for _, header := range endToEndHeaders {
+ cachedResp.Header[header] = resp.Header[header]
+ }
+ resp = cachedResp
+ } else if (err != nil || (cachedResp != nil && resp.StatusCode >= 500)) &&
+ req.Method == "GET" && canStaleOnError(cachedResp.Header, req.Header) {
+ // In case of transport failure and stale-if-error activated, returns cached content
+ // when available
+ return cachedResp, nil
+ } else {
+ if err != nil || resp.StatusCode != http.StatusOK {
+ t.Cache.Delete(cacheKey)
+ }
+ if err != nil {
+ return nil, err
+ }
+ }
+ } else {
+ reqCacheControl := parseCacheControl(req.Header)
+ if _, ok := reqCacheControl["only-if-cached"]; ok {
+ resp = newGatewayTimeoutResponse(req)
+ } else {
+ resp, err = transport.RoundTrip(req)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ if cacheable && canStore(parseCacheControl(req.Header), parseCacheControl(resp.Header)) {
+ for _, varyKey := range headerAllCommaSepValues(resp.Header, "vary") {
+ varyKey = http.CanonicalHeaderKey(varyKey)
+ fakeHeader := "X-Varied-" + varyKey
+ reqValue := req.Header.Get(varyKey)
+ if reqValue != "" {
+ resp.Header.Set(fakeHeader, reqValue)
+ }
+ }
+ switch req.Method {
+ case "GET":
+ // Delay caching until EOF is reached.
+ resp.Body = &cachingReadCloser{
+ R: resp.Body,
+ OnEOF: func(r io.Reader) {
+ resp := *resp
+ resp.Body = ioutil.NopCloser(r)
+ respBytes, err := httputil.DumpResponse(&resp, true)
+ if err == nil {
+ t.Cache.Set(cacheKey, respBytes)
+ }
+ },
+ }
+ default:
+ respBytes, err := httputil.DumpResponse(resp, true)
+ if err == nil {
+ t.Cache.Set(cacheKey, respBytes)
+ }
+ }
+ } else {
+ t.Cache.Delete(cacheKey)
+ }
+ return resp, nil
+}
+
+// ErrNoDateHeader indicates that the HTTP headers contained no Date header.
+var ErrNoDateHeader = errors.New("no Date header")
+
+// Date parses and returns the value of the Date header.
+func Date(respHeaders http.Header) (date time.Time, err error) {
+ dateHeader := respHeaders.Get("date")
+ if dateHeader == "" {
+ err = ErrNoDateHeader
+ return
+ }
+
+ return time.Parse(time.RFC1123, dateHeader)
+}
+
+type realClock struct{}
+
+func (c *realClock) since(d time.Time) time.Duration {
+ return time.Since(d)
+}
+
+type timer interface {
+ since(d time.Time) time.Duration
+}
+
+var clock timer = &realClock{}
+
+// getFreshness will return one of fresh/stale/transparent based on the cache-control
+// values of the request and the response
+//
+// fresh indicates the response can be returned
+// stale indicates that the response needs validating before it is returned
+// transparent indicates the response should not be used to fulfil the request
+//
+// Because this is only a private cache, 'public' and 'private' in cache-control aren't
+// signficant. Similarly, smax-age isn't used.
+func getFreshness(respHeaders, reqHeaders http.Header) (freshness int) {
+ respCacheControl := parseCacheControl(respHeaders)
+ reqCacheControl := parseCacheControl(reqHeaders)
+ if _, ok := reqCacheControl["no-cache"]; ok {
+ return transparent
+ }
+ if _, ok := respCacheControl["no-cache"]; ok {
+ return stale
+ }
+ if _, ok := reqCacheControl["only-if-cached"]; ok {
+ return fresh
+ }
+
+ date, err := Date(respHeaders)
+ if err != nil {
+ return stale
+ }
+ currentAge := clock.since(date)
+
+ var lifetime time.Duration
+ var zeroDuration time.Duration
+
+ // If a response includes both an Expires header and a max-age directive,
+ // the max-age directive overrides the Expires header, even if the Expires header is more restrictive.
+ if maxAge, ok := respCacheControl["max-age"]; ok {
+ lifetime, err = time.ParseDuration(maxAge + "s")
+ if err != nil {
+ lifetime = zeroDuration
+ }
+ } else {
+ expiresHeader := respHeaders.Get("Expires")
+ if expiresHeader != "" {
+ expires, err := time.Parse(time.RFC1123, expiresHeader)
+ if err != nil {
+ lifetime = zeroDuration
+ } else {
+ lifetime = expires.Sub(date)
+ }
+ }
+ }
+
+ if maxAge, ok := reqCacheControl["max-age"]; ok {
+ // the client is willing to accept a response whose age is no greater than the specified time in seconds
+ lifetime, err = time.ParseDuration(maxAge + "s")
+ if err != nil {
+ lifetime = zeroDuration
+ }
+ }
+ if minfresh, ok := reqCacheControl["min-fresh"]; ok {
+ // the client wants a response that will still be fresh for at least the specified number of seconds.
+ minfreshDuration, err := time.ParseDuration(minfresh + "s")
+ if err == nil {
+ currentAge = time.Duration(currentAge + minfreshDuration)
+ }
+ }
+
+ if maxstale, ok := reqCacheControl["max-stale"]; ok {
+ // Indicates that the client is willing to accept a response that has exceeded its expiration time.
+ // If max-stale is assigned a value, then the client is willing to accept a response that has exceeded
+ // its expiration time by no more than the specified number of seconds.
+ // If no value is assigned to max-stale, then the client is willing to accept a stale response of any age.
+ //
+ // Responses served only because of a max-stale value are supposed to have a Warning header added to them,
+ // but that seems like a hassle, and is it actually useful? If so, then there needs to be a different
+ // return-value available here.
+ if maxstale == "" {
+ return fresh
+ }
+ maxstaleDuration, err := time.ParseDuration(maxstale + "s")
+ if err == nil {
+ currentAge = time.Duration(currentAge - maxstaleDuration)
+ }
+ }
+
+ if lifetime > currentAge {
+ return fresh
+ }
+
+ return stale
+}
+
+// Returns true if either the request or the response includes the stale-if-error
+// cache control extension: https://tools.ietf.org/html/rfc5861
+func canStaleOnError(respHeaders, reqHeaders http.Header) bool {
+ respCacheControl := parseCacheControl(respHeaders)
+ reqCacheControl := parseCacheControl(reqHeaders)
+
+ var err error
+ lifetime := time.Duration(-1)
+
+ if staleMaxAge, ok := respCacheControl["stale-if-error"]; ok {
+ if staleMaxAge != "" {
+ lifetime, err = time.ParseDuration(staleMaxAge + "s")
+ if err != nil {
+ return false
+ }
+ } else {
+ return true
+ }
+ }
+ if staleMaxAge, ok := reqCacheControl["stale-if-error"]; ok {
+ if staleMaxAge != "" {
+ lifetime, err = time.ParseDuration(staleMaxAge + "s")
+ if err != nil {
+ return false
+ }
+ } else {
+ return true
+ }
+ }
+
+ if lifetime >= 0 {
+ date, err := Date(respHeaders)
+ if err != nil {
+ return false
+ }
+ currentAge := clock.since(date)
+ if lifetime > currentAge {
+ return true
+ }
+ }
+
+ return false
+}
+
+func getEndToEndHeaders(respHeaders http.Header) []string {
+ // These headers are always hop-by-hop
+ hopByHopHeaders := map[string]struct{}{
+ "Connection": {},
+ "Keep-Alive": {},
+ "Proxy-Authenticate": {},
+ "Proxy-Authorization": {},
+ "Te": {},
+ "Trailers": {},
+ "Transfer-Encoding": {},
+ "Upgrade": {},
+ }
+
+ for _, extra := range strings.Split(respHeaders.Get("connection"), ",") {
+ // any header listed in connection, if present, is also considered hop-by-hop
+ if strings.Trim(extra, " ") != "" {
+ hopByHopHeaders[http.CanonicalHeaderKey(extra)] = struct{}{}
+ }
+ }
+ endToEndHeaders := []string{}
+ for respHeader := range respHeaders {
+ if _, ok := hopByHopHeaders[respHeader]; !ok {
+ endToEndHeaders = append(endToEndHeaders, respHeader)
+ }
+ }
+ return endToEndHeaders
+}
+
+func canStore(reqCacheControl, respCacheControl cacheControl) (canStore bool) {
+ if _, ok := respCacheControl["no-store"]; ok {
+ return false
+ }
+ if _, ok := reqCacheControl["no-store"]; ok {
+ return false
+ }
+ return true
+}
+
+func newGatewayTimeoutResponse(req *http.Request) *http.Response {
+ var braw bytes.Buffer
+ braw.WriteString("HTTP/1.1 504 Gateway Timeout\r\n\r\n")
+ resp, err := http.ReadResponse(bufio.NewReader(&braw), req)
+ if err != nil {
+ panic(err)
+ }
+ return resp
+}
+
+// cloneRequest returns a clone of the provided *http.Request.
+// The clone is a shallow copy of the struct and its Header map.
+// (This function copyright goauth2 authors: https://code.google.com/p/goauth2)
+func cloneRequest(r *http.Request) *http.Request {
+ // shallow copy of the struct
+ r2 := new(http.Request)
+ *r2 = *r
+ // deep copy of the Header
+ r2.Header = make(http.Header)
+ for k, s := range r.Header {
+ r2.Header[k] = s
+ }
+ return r2
+}
+
+type cacheControl map[string]string
+
+func parseCacheControl(headers http.Header) cacheControl {
+ cc := cacheControl{}
+ ccHeader := headers.Get("Cache-Control")
+ for _, part := range strings.Split(ccHeader, ",") {
+ part = strings.Trim(part, " ")
+ if part == "" {
+ continue
+ }
+ if strings.ContainsRune(part, '=') {
+ keyval := strings.Split(part, "=")
+ cc[strings.Trim(keyval[0], " ")] = strings.Trim(keyval[1], ",")
+ } else {
+ cc[part] = ""
+ }
+ }
+ return cc
+}
+
+// headerAllCommaSepValues returns all comma-separated values (each
+// with whitespace trimmed) for header name in headers. According to
+// Section 4.2 of the HTTP/1.1 spec
+// (http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2),
+// values from multiple occurrences of a header should be concatenated, if
+// the header's value is a comma-separated list.
+func headerAllCommaSepValues(headers http.Header, name string) []string {
+ var vals []string
+ for _, val := range headers[http.CanonicalHeaderKey(name)] {
+ fields := strings.Split(val, ",")
+ for i, f := range fields {
+ fields[i] = strings.TrimSpace(f)
+ }
+ vals = append(vals, fields...)
+ }
+ return vals
+}
+
+// cachingReadCloser is a wrapper around ReadCloser R that calls OnEOF
+// handler with a full copy of the content read from R when EOF is
+// reached.
+type cachingReadCloser struct {
+ // Underlying ReadCloser.
+ R io.ReadCloser
+ // OnEOF is called with a copy of the content of R when EOF is reached.
+ OnEOF func(io.Reader)
+
+ buf bytes.Buffer // buf stores a copy of the content of R.
+}
+
+// Read reads the next len(p) bytes from R or until R is drained. The
+// return value n is the number of bytes read. If R has no data to
+// return, err is io.EOF and OnEOF is called with a full copy of what
+// has been read so far.
+func (r *cachingReadCloser) Read(p []byte) (n int, err error) {
+ n, err = r.R.Read(p)
+ r.buf.Write(p[:n])
+ if err == io.EOF {
+ r.OnEOF(bytes.NewReader(r.buf.Bytes()))
+ }
+ return n, err
+}
+
+func (r *cachingReadCloser) Close() error {
+ return r.R.Close()
+}
+
+// NewMemoryCacheTransport returns a new Transport using the in-memory cache implementation
+func NewMemoryCacheTransport() *Transport {
+ c := NewMemoryCache()
+ t := NewTransport(c)
+ return t
+}
diff --git a/vendor/github.com/hashicorp/errwrap/LICENSE b/vendor/github.com/hashicorp/errwrap/LICENSE
new file mode 100644
index 0000000000..c33dcc7c92
--- /dev/null
+++ b/vendor/github.com/hashicorp/errwrap/LICENSE
@@ -0,0 +1,354 @@
+Mozilla Public License, version 2.0
+
+1. Definitions
+
+1.1. “Contributorâ€
+
+ means each individual or legal entity that creates, contributes to the
+ creation of, or owns Covered Software.
+
+1.2. “Contributor Versionâ€
+
+ means the combination of the Contributions of others (if any) used by a
+ Contributor and that particular Contributor’s Contribution.
+
+1.3. “Contributionâ€
+
+ means Covered Software of a particular Contributor.
+
+1.4. “Covered Softwareâ€
+
+ means Source Code Form to which the initial Contributor has attached the
+ notice in Exhibit A, the Executable Form of such Source Code Form, and
+ Modifications of such Source Code Form, in each case including portions
+ thereof.
+
+1.5. “Incompatible With Secondary Licensesâ€
+ means
+
+ a. that the initial Contributor has attached the notice described in
+ Exhibit B to the Covered Software; or
+
+ b. that the Covered Software was made available under the terms of version
+ 1.1 or earlier of the License, but not also under the terms of a
+ Secondary License.
+
+1.6. “Executable Formâ€
+
+ means any form of the work other than Source Code Form.
+
+1.7. “Larger Workâ€
+
+ means a work that combines Covered Software with other material, in a separate
+ file or files, that is not Covered Software.
+
+1.8. “Licenseâ€
+
+ means this document.
+
+1.9. “Licensableâ€
+
+ means having the right to grant, to the maximum extent possible, whether at the
+ time of the initial grant or subsequently, any and all of the rights conveyed by
+ this License.
+
+1.10. “Modificationsâ€
+
+ means any of the following:
+
+ a. any file in Source Code Form that results from an addition to, deletion
+ from, or modification of the contents of Covered Software; or
+
+ b. any new file in Source Code Form that contains any Covered Software.
+
+1.11. “Patent Claims†of a Contributor
+
+ means any patent claim(s), including without limitation, method, process,
+ and apparatus claims, in any patent Licensable by such Contributor that
+ would be infringed, but for the grant of the License, by the making,
+ using, selling, offering for sale, having made, import, or transfer of
+ either its Contributions or its Contributor Version.
+
+1.12. “Secondary Licenseâ€
+
+ means either the GNU General Public License, Version 2.0, the GNU Lesser
+ General Public License, Version 2.1, the GNU Affero General Public
+ License, Version 3.0, or any later versions of those licenses.
+
+1.13. “Source Code Formâ€
+
+ means the form of the work preferred for making modifications.
+
+1.14. “You†(or “Yourâ€)
+
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, “You†includes any entity that controls, is
+ controlled by, or is under common control with You. For purposes of this
+ definition, “control†means (a) the power, direct or indirect, to cause
+ the direction or management of such entity, whether by contract or
+ otherwise, or (b) ownership of more than fifty percent (50%) of the
+ outstanding shares or beneficial ownership of such entity.
+
+
+2. License Grants and Conditions
+
+2.1. Grants
+
+ Each Contributor hereby grants You a world-wide, royalty-free,
+ non-exclusive license:
+
+ a. under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or as
+ part of a Larger Work; and
+
+ b. under Patent Claims of such Contributor to make, use, sell, offer for
+ sale, have made, import, and otherwise transfer either its Contributions
+ or its Contributor Version.
+
+2.2. Effective Date
+
+ The licenses granted in Section 2.1 with respect to any Contribution become
+ effective for each Contribution on the date the Contributor first distributes
+ such Contribution.
+
+2.3. Limitations on Grant Scope
+
+ The licenses granted in this Section 2 are the only rights granted under this
+ License. No additional rights or licenses will be implied from the distribution
+ or licensing of Covered Software under this License. Notwithstanding Section
+ 2.1(b) above, no patent license is granted by a Contributor:
+
+ a. for any code that a Contributor has removed from Covered Software; or
+
+ b. for infringements caused by: (i) Your and any other third party’s
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+ c. under Patent Claims infringed by Covered Software in the absence of its
+ Contributions.
+
+ This License does not grant any rights in the trademarks, service marks, or
+ logos of any Contributor (except as may be necessary to comply with the
+ notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+ No Contributor makes additional grants as a result of Your choice to
+ distribute the Covered Software under a subsequent version of this License
+ (see Section 10.2) or under the terms of a Secondary License (if permitted
+ under the terms of Section 3.3).
+
+2.5. Representation
+
+ Each Contributor represents that the Contributor believes its Contributions
+ are its original creation(s) or it has sufficient rights to grant the
+ rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+ This License is not intended to limit any rights You have under applicable
+ copyright doctrines of fair use, fair dealing, or other equivalents.
+
+2.7. Conditions
+
+ Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
+ Section 2.1.
+
+
+3. Responsibilities
+
+3.1. Distribution of Source Form
+
+ All distribution of Covered Software in Source Code Form, including any
+ Modifications that You create or to which You contribute, must be under the
+ terms of this License. You must inform recipients that the Source Code Form
+ of the Covered Software is governed by the terms of this License, and how
+ they can obtain a copy of this License. You may not attempt to alter or
+ restrict the recipients’ rights in the Source Code Form.
+
+3.2. Distribution of Executable Form
+
+ If You distribute Covered Software in Executable Form then:
+
+ a. such Covered Software must also be made available in Source Code Form,
+ as described in Section 3.1, and You must inform recipients of the
+ Executable Form how they can obtain a copy of such Source Code Form by
+ reasonable means in a timely manner, at a charge no more than the cost
+ of distribution to the recipient; and
+
+ b. You may distribute such Executable Form under the terms of this License,
+ or sublicense it under different terms, provided that the license for
+ the Executable Form does not attempt to limit or alter the recipients’
+ rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+ You may create and distribute a Larger Work under terms of Your choice,
+ provided that You also comply with the requirements of this License for the
+ Covered Software. If the Larger Work is a combination of Covered Software
+ with a work governed by one or more Secondary Licenses, and the Covered
+ Software is not Incompatible With Secondary Licenses, this License permits
+ You to additionally distribute such Covered Software under the terms of
+ such Secondary License(s), so that the recipient of the Larger Work may, at
+ their option, further distribute the Covered Software under the terms of
+ either this License or such Secondary License(s).
+
+3.4. Notices
+
+ You may not remove or alter the substance of any license notices (including
+ copyright notices, patent notices, disclaimers of warranty, or limitations
+ of liability) contained within the Source Code Form of the Covered
+ Software, except that You may alter any license notices to the extent
+ required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+ You may choose to offer, and to charge a fee for, warranty, support,
+ indemnity or liability obligations to one or more recipients of Covered
+ Software. However, You may do so only on Your own behalf, and not on behalf
+ of any Contributor. You must make it absolutely clear that any such
+ warranty, support, indemnity, or liability obligation is offered by You
+ alone, and You hereby agree to indemnify every Contributor for any
+ liability incurred by such Contributor as a result of warranty, support,
+ indemnity or liability terms You offer. You may include additional
+ disclaimers of warranty and limitations of liability specific to any
+ jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+
+ If it is impossible for You to comply with any of the terms of this License
+ with respect to some or all of the Covered Software due to statute, judicial
+ order, or regulation then You must: (a) comply with the terms of this License
+ to the maximum extent possible; and (b) describe the limitations and the code
+ they affect. Such description must be placed in a text file included with all
+ distributions of the Covered Software under this License. Except to the
+ extent prohibited by statute or regulation, such description must be
+ sufficiently detailed for a recipient of ordinary skill to be able to
+ understand it.
+
+5. Termination
+
+5.1. The rights granted under this License will terminate automatically if You
+ fail to comply with any of its terms. However, if You become compliant,
+ then the rights granted under this License from a particular Contributor
+ are reinstated (a) provisionally, unless and until such Contributor
+ explicitly and finally terminates Your grants, and (b) on an ongoing basis,
+ if such Contributor fails to notify You of the non-compliance by some
+ reasonable means prior to 60 days after You have come back into compliance.
+ Moreover, Your grants from a particular Contributor are reinstated on an
+ ongoing basis if such Contributor notifies You of the non-compliance by
+ some reasonable means, this is the first time You have received notice of
+ non-compliance with this License from such Contributor, and You become
+ compliant prior to 30 days after Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+ infringement claim (excluding declaratory judgment actions, counter-claims,
+ and cross-claims) alleging that a Contributor Version directly or
+ indirectly infringes any patent, then the rights granted to You by any and
+ all Contributors for the Covered Software under Section 2.1 of this License
+ shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
+ license agreements (excluding distributors and resellers) which have been
+ validly granted by You or Your distributors under this License prior to
+ termination shall survive termination.
+
+6. Disclaimer of Warranty
+
+ Covered Software is provided under this License on an “as is†basis, without
+ warranty of any kind, either expressed, implied, or statutory, including,
+ without limitation, warranties that the Covered Software is free of defects,
+ merchantable, fit for a particular purpose or non-infringing. The entire
+ risk as to the quality and performance of the Covered Software is with You.
+ Should any Covered Software prove defective in any respect, You (not any
+ Contributor) assume the cost of any necessary servicing, repair, or
+ correction. This disclaimer of warranty constitutes an essential part of this
+ License. No use of any Covered Software is authorized under this License
+ except under this disclaimer.
+
+7. Limitation of Liability
+
+ Under no circumstances and under no legal theory, whether tort (including
+ negligence), contract, or otherwise, shall any Contributor, or anyone who
+ distributes Covered Software as permitted above, be liable to You for any
+ direct, indirect, special, incidental, or consequential damages of any
+ character including, without limitation, damages for lost profits, loss of
+ goodwill, work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses, even if such party shall have been
+ informed of the possibility of such damages. This limitation of liability
+ shall not apply to liability for death or personal injury resulting from such
+ party’s negligence to the extent applicable law prohibits such limitation.
+ Some jurisdictions do not allow the exclusion or limitation of incidental or
+ consequential damages, so this exclusion and limitation may not apply to You.
+
+8. Litigation
+
+ Any litigation relating to this License may be brought only in the courts of
+ a jurisdiction where the defendant maintains its principal place of business
+ and such litigation shall be governed by laws of that jurisdiction, without
+ reference to its conflict-of-law provisions. Nothing in this Section shall
+ prevent a party’s ability to bring cross-claims or counter-claims.
+
+9. Miscellaneous
+
+ This License represents the complete agreement concerning the subject matter
+ hereof. If any provision of this License is held to be unenforceable, such
+ provision shall be reformed only to the extent necessary to make it
+ enforceable. Any law or regulation which provides that the language of a
+ contract shall be construed against the drafter shall not be used to construe
+ this License against a Contributor.
+
+
+10. Versions of the License
+
+10.1. New Versions
+
+ Mozilla Foundation is the license steward. Except as provided in Section
+ 10.3, no one other than the license steward has the right to modify or
+ publish new versions of this License. Each version will be given a
+ distinguishing version number.
+
+10.2. Effect of New Versions
+
+ You may distribute the Covered Software under the terms of the version of
+ the License under which You originally received the Covered Software, or
+ under the terms of any subsequent version published by the license
+ steward.
+
+10.3. Modified Versions
+
+ If you create software not governed by this License, and you want to
+ create a new license for such software, you may create and use a modified
+ version of this License if you rename the license and remove any
+ references to the name of the license steward (except to note that such
+ modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
+ If You choose to distribute Source Code Form that is Incompatible With
+ Secondary Licenses under the terms of this version of the License, the
+ notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+
+ This Source Code Form is subject to the
+ terms of the Mozilla Public License, v.
+ 2.0. If a copy of the MPL was not
+ distributed with this file, You can
+ obtain one at
+ http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular file, then
+You may include the notice in a location (such as a LICENSE file in a relevant
+directory) where a recipient would be likely to look for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - “Incompatible With Secondary Licenses†Notice
+
+ This Source Code Form is “Incompatible
+ With Secondary Licensesâ€, as defined by
+ the Mozilla Public License, v. 2.0.
+
diff --git a/vendor/github.com/hashicorp/errwrap/README.md b/vendor/github.com/hashicorp/errwrap/README.md
new file mode 100644
index 0000000000..444df08f8e
--- /dev/null
+++ b/vendor/github.com/hashicorp/errwrap/README.md
@@ -0,0 +1,89 @@
+# errwrap
+
+`errwrap` is a package for Go that formalizes the pattern of wrapping errors
+and checking if an error contains another error.
+
+There is a common pattern in Go of taking a returned `error` value and
+then wrapping it (such as with `fmt.Errorf`) before returning it. The problem
+with this pattern is that you completely lose the original `error` structure.
+
+Arguably the _correct_ approach is that you should make a custom structure
+implementing the `error` interface, and have the original error as a field
+on that structure, such [as this example](http://golang.org/pkg/os/#PathError).
+This is a good approach, but you have to know the entire chain of possible
+rewrapping that happens, when you might just care about one.
+
+`errwrap` formalizes this pattern (it doesn't matter what approach you use
+above) by giving a single interface for wrapping errors, checking if a specific
+error is wrapped, and extracting that error.
+
+## Installation and Docs
+
+Install using `go get github.com/hashicorp/errwrap`.
+
+Full documentation is available at
+http://godoc.org/github.com/hashicorp/errwrap
+
+## Usage
+
+#### Basic Usage
+
+Below is a very basic example of its usage:
+
+```go
+// A function that always returns an error, but wraps it, like a real
+// function might.
+func tryOpen() error {
+ _, err := os.Open("/i/dont/exist")
+ if err != nil {
+ return errwrap.Wrapf("Doesn't exist: {{err}}", err)
+ }
+
+ return nil
+}
+
+func main() {
+ err := tryOpen()
+
+ // We can use the Contains helpers to check if an error contains
+ // another error. It is safe to do this with a nil error, or with
+ // an error that doesn't even use the errwrap package.
+ if errwrap.Contains(err, "does not exist") {
+ // Do something
+ }
+ if errwrap.ContainsType(err, new(os.PathError)) {
+ // Do something
+ }
+
+ // Or we can use the associated `Get` functions to just extract
+ // a specific error. This would return nil if that specific error doesn't
+ // exist.
+ perr := errwrap.GetType(err, new(os.PathError))
+}
+```
+
+#### Custom Types
+
+If you're already making custom types that properly wrap errors, then
+you can get all the functionality of `errwraps.Contains` and such by
+implementing the `Wrapper` interface with just one function. Example:
+
+```go
+type AppError {
+ Code ErrorCode
+ Err error
+}
+
+func (e *AppError) WrappedErrors() []error {
+ return []error{e.Err}
+}
+```
+
+Now this works:
+
+```go
+err := &AppError{Err: fmt.Errorf("an error")}
+if errwrap.ContainsType(err, fmt.Errorf("")) {
+ // This will work!
+}
+```
diff --git a/vendor/github.com/hashicorp/errwrap/errwrap.go b/vendor/github.com/hashicorp/errwrap/errwrap.go
new file mode 100644
index 0000000000..44e368e569
--- /dev/null
+++ b/vendor/github.com/hashicorp/errwrap/errwrap.go
@@ -0,0 +1,178 @@
+// Package errwrap implements methods to formalize error wrapping in Go.
+//
+// All of the top-level functions that take an `error` are built to be able
+// to take any error, not just wrapped errors. This allows you to use errwrap
+// without having to type-check and type-cast everywhere.
+package errwrap
+
+import (
+ "errors"
+ "reflect"
+ "strings"
+)
+
+// WalkFunc is the callback called for Walk.
+type WalkFunc func(error)
+
+// Wrapper is an interface that can be implemented by custom types to
+// have all the Contains, Get, etc. functions in errwrap work.
+//
+// When Walk reaches a Wrapper, it will call the callback for every
+// wrapped error in addition to the wrapper itself. Since all the top-level
+// functions in errwrap use Walk, this means that all those functions work
+// with your custom type.
+type Wrapper interface {
+ WrappedErrors() []error
+}
+
+// Wrap defines that outer wraps inner, returning an error type that
+// can be cleanly used with the other methods in this package, such as
+// Contains, GetAll, etc.
+//
+// This function won't modify the error message at all (the outer message
+// will be used).
+func Wrap(outer, inner error) error {
+ return &wrappedError{
+ Outer: outer,
+ Inner: inner,
+ }
+}
+
+// Wrapf wraps an error with a formatting message. This is similar to using
+// `fmt.Errorf` to wrap an error. If you're using `fmt.Errorf` to wrap
+// errors, you should replace it with this.
+//
+// format is the format of the error message. The string '{{err}}' will
+// be replaced with the original error message.
+//
+// Deprecated: Use fmt.Errorf()
+func Wrapf(format string, err error) error {
+ outerMsg := ""
+ if err != nil {
+ outerMsg = err.Error()
+ }
+
+ outer := errors.New(strings.Replace(
+ format, "{{err}}", outerMsg, -1))
+
+ return Wrap(outer, err)
+}
+
+// Contains checks if the given error contains an error with the
+// message msg. If err is not a wrapped error, this will always return
+// false unless the error itself happens to match this msg.
+func Contains(err error, msg string) bool {
+ return len(GetAll(err, msg)) > 0
+}
+
+// ContainsType checks if the given error contains an error with
+// the same concrete type as v. If err is not a wrapped error, this will
+// check the err itself.
+func ContainsType(err error, v interface{}) bool {
+ return len(GetAllType(err, v)) > 0
+}
+
+// Get is the same as GetAll but returns the deepest matching error.
+func Get(err error, msg string) error {
+ es := GetAll(err, msg)
+ if len(es) > 0 {
+ return es[len(es)-1]
+ }
+
+ return nil
+}
+
+// GetType is the same as GetAllType but returns the deepest matching error.
+func GetType(err error, v interface{}) error {
+ es := GetAllType(err, v)
+ if len(es) > 0 {
+ return es[len(es)-1]
+ }
+
+ return nil
+}
+
+// GetAll gets all the errors that might be wrapped in err with the
+// given message. The order of the errors is such that the outermost
+// matching error (the most recent wrap) is index zero, and so on.
+func GetAll(err error, msg string) []error {
+ var result []error
+
+ Walk(err, func(err error) {
+ if err.Error() == msg {
+ result = append(result, err)
+ }
+ })
+
+ return result
+}
+
+// GetAllType gets all the errors that are the same type as v.
+//
+// The order of the return value is the same as described in GetAll.
+func GetAllType(err error, v interface{}) []error {
+ var result []error
+
+ var search string
+ if v != nil {
+ search = reflect.TypeOf(v).String()
+ }
+ Walk(err, func(err error) {
+ var needle string
+ if err != nil {
+ needle = reflect.TypeOf(err).String()
+ }
+
+ if needle == search {
+ result = append(result, err)
+ }
+ })
+
+ return result
+}
+
+// Walk walks all the wrapped errors in err and calls the callback. If
+// err isn't a wrapped error, this will be called once for err. If err
+// is a wrapped error, the callback will be called for both the wrapper
+// that implements error as well as the wrapped error itself.
+func Walk(err error, cb WalkFunc) {
+ if err == nil {
+ return
+ }
+
+ switch e := err.(type) {
+ case *wrappedError:
+ cb(e.Outer)
+ Walk(e.Inner, cb)
+ case Wrapper:
+ cb(err)
+
+ for _, err := range e.WrappedErrors() {
+ Walk(err, cb)
+ }
+ case interface{ Unwrap() error }:
+ cb(err)
+ Walk(e.Unwrap(), cb)
+ default:
+ cb(err)
+ }
+}
+
+// wrappedError is an implementation of error that has both the
+// outer and inner errors.
+type wrappedError struct {
+ Outer error
+ Inner error
+}
+
+func (w *wrappedError) Error() string {
+ return w.Outer.Error()
+}
+
+func (w *wrappedError) WrappedErrors() []error {
+ return []error{w.Outer, w.Inner}
+}
+
+func (w *wrappedError) Unwrap() error {
+ return w.Inner
+}
diff --git a/vendor/github.com/hashicorp/go-multierror/LICENSE b/vendor/github.com/hashicorp/go-multierror/LICENSE
new file mode 100644
index 0000000000..82b4de97c7
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-multierror/LICENSE
@@ -0,0 +1,353 @@
+Mozilla Public License, version 2.0
+
+1. Definitions
+
+1.1. “Contributorâ€
+
+ means each individual or legal entity that creates, contributes to the
+ creation of, or owns Covered Software.
+
+1.2. “Contributor Versionâ€
+
+ means the combination of the Contributions of others (if any) used by a
+ Contributor and that particular Contributor’s Contribution.
+
+1.3. “Contributionâ€
+
+ means Covered Software of a particular Contributor.
+
+1.4. “Covered Softwareâ€
+
+ means Source Code Form to which the initial Contributor has attached the
+ notice in Exhibit A, the Executable Form of such Source Code Form, and
+ Modifications of such Source Code Form, in each case including portions
+ thereof.
+
+1.5. “Incompatible With Secondary Licensesâ€
+ means
+
+ a. that the initial Contributor has attached the notice described in
+ Exhibit B to the Covered Software; or
+
+ b. that the Covered Software was made available under the terms of version
+ 1.1 or earlier of the License, but not also under the terms of a
+ Secondary License.
+
+1.6. “Executable Formâ€
+
+ means any form of the work other than Source Code Form.
+
+1.7. “Larger Workâ€
+
+ means a work that combines Covered Software with other material, in a separate
+ file or files, that is not Covered Software.
+
+1.8. “Licenseâ€
+
+ means this document.
+
+1.9. “Licensableâ€
+
+ means having the right to grant, to the maximum extent possible, whether at the
+ time of the initial grant or subsequently, any and all of the rights conveyed by
+ this License.
+
+1.10. “Modificationsâ€
+
+ means any of the following:
+
+ a. any file in Source Code Form that results from an addition to, deletion
+ from, or modification of the contents of Covered Software; or
+
+ b. any new file in Source Code Form that contains any Covered Software.
+
+1.11. “Patent Claims†of a Contributor
+
+ means any patent claim(s), including without limitation, method, process,
+ and apparatus claims, in any patent Licensable by such Contributor that
+ would be infringed, but for the grant of the License, by the making,
+ using, selling, offering for sale, having made, import, or transfer of
+ either its Contributions or its Contributor Version.
+
+1.12. “Secondary Licenseâ€
+
+ means either the GNU General Public License, Version 2.0, the GNU Lesser
+ General Public License, Version 2.1, the GNU Affero General Public
+ License, Version 3.0, or any later versions of those licenses.
+
+1.13. “Source Code Formâ€
+
+ means the form of the work preferred for making modifications.
+
+1.14. “You†(or “Yourâ€)
+
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, “You†includes any entity that controls, is
+ controlled by, or is under common control with You. For purposes of this
+ definition, “control†means (a) the power, direct or indirect, to cause
+ the direction or management of such entity, whether by contract or
+ otherwise, or (b) ownership of more than fifty percent (50%) of the
+ outstanding shares or beneficial ownership of such entity.
+
+
+2. License Grants and Conditions
+
+2.1. Grants
+
+ Each Contributor hereby grants You a world-wide, royalty-free,
+ non-exclusive license:
+
+ a. under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or as
+ part of a Larger Work; and
+
+ b. under Patent Claims of such Contributor to make, use, sell, offer for
+ sale, have made, import, and otherwise transfer either its Contributions
+ or its Contributor Version.
+
+2.2. Effective Date
+
+ The licenses granted in Section 2.1 with respect to any Contribution become
+ effective for each Contribution on the date the Contributor first distributes
+ such Contribution.
+
+2.3. Limitations on Grant Scope
+
+ The licenses granted in this Section 2 are the only rights granted under this
+ License. No additional rights or licenses will be implied from the distribution
+ or licensing of Covered Software under this License. Notwithstanding Section
+ 2.1(b) above, no patent license is granted by a Contributor:
+
+ a. for any code that a Contributor has removed from Covered Software; or
+
+ b. for infringements caused by: (i) Your and any other third party’s
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+ c. under Patent Claims infringed by Covered Software in the absence of its
+ Contributions.
+
+ This License does not grant any rights in the trademarks, service marks, or
+ logos of any Contributor (except as may be necessary to comply with the
+ notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+ No Contributor makes additional grants as a result of Your choice to
+ distribute the Covered Software under a subsequent version of this License
+ (see Section 10.2) or under the terms of a Secondary License (if permitted
+ under the terms of Section 3.3).
+
+2.5. Representation
+
+ Each Contributor represents that the Contributor believes its Contributions
+ are its original creation(s) or it has sufficient rights to grant the
+ rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+ This License is not intended to limit any rights You have under applicable
+ copyright doctrines of fair use, fair dealing, or other equivalents.
+
+2.7. Conditions
+
+ Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
+ Section 2.1.
+
+
+3. Responsibilities
+
+3.1. Distribution of Source Form
+
+ All distribution of Covered Software in Source Code Form, including any
+ Modifications that You create or to which You contribute, must be under the
+ terms of this License. You must inform recipients that the Source Code Form
+ of the Covered Software is governed by the terms of this License, and how
+ they can obtain a copy of this License. You may not attempt to alter or
+ restrict the recipients’ rights in the Source Code Form.
+
+3.2. Distribution of Executable Form
+
+ If You distribute Covered Software in Executable Form then:
+
+ a. such Covered Software must also be made available in Source Code Form,
+ as described in Section 3.1, and You must inform recipients of the
+ Executable Form how they can obtain a copy of such Source Code Form by
+ reasonable means in a timely manner, at a charge no more than the cost
+ of distribution to the recipient; and
+
+ b. You may distribute such Executable Form under the terms of this License,
+ or sublicense it under different terms, provided that the license for
+ the Executable Form does not attempt to limit or alter the recipients’
+ rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+ You may create and distribute a Larger Work under terms of Your choice,
+ provided that You also comply with the requirements of this License for the
+ Covered Software. If the Larger Work is a combination of Covered Software
+ with a work governed by one or more Secondary Licenses, and the Covered
+ Software is not Incompatible With Secondary Licenses, this License permits
+ You to additionally distribute such Covered Software under the terms of
+ such Secondary License(s), so that the recipient of the Larger Work may, at
+ their option, further distribute the Covered Software under the terms of
+ either this License or such Secondary License(s).
+
+3.4. Notices
+
+ You may not remove or alter the substance of any license notices (including
+ copyright notices, patent notices, disclaimers of warranty, or limitations
+ of liability) contained within the Source Code Form of the Covered
+ Software, except that You may alter any license notices to the extent
+ required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+ You may choose to offer, and to charge a fee for, warranty, support,
+ indemnity or liability obligations to one or more recipients of Covered
+ Software. However, You may do so only on Your own behalf, and not on behalf
+ of any Contributor. You must make it absolutely clear that any such
+ warranty, support, indemnity, or liability obligation is offered by You
+ alone, and You hereby agree to indemnify every Contributor for any
+ liability incurred by such Contributor as a result of warranty, support,
+ indemnity or liability terms You offer. You may include additional
+ disclaimers of warranty and limitations of liability specific to any
+ jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+
+ If it is impossible for You to comply with any of the terms of this License
+ with respect to some or all of the Covered Software due to statute, judicial
+ order, or regulation then You must: (a) comply with the terms of this License
+ to the maximum extent possible; and (b) describe the limitations and the code
+ they affect. Such description must be placed in a text file included with all
+ distributions of the Covered Software under this License. Except to the
+ extent prohibited by statute or regulation, such description must be
+ sufficiently detailed for a recipient of ordinary skill to be able to
+ understand it.
+
+5. Termination
+
+5.1. The rights granted under this License will terminate automatically if You
+ fail to comply with any of its terms. However, if You become compliant,
+ then the rights granted under this License from a particular Contributor
+ are reinstated (a) provisionally, unless and until such Contributor
+ explicitly and finally terminates Your grants, and (b) on an ongoing basis,
+ if such Contributor fails to notify You of the non-compliance by some
+ reasonable means prior to 60 days after You have come back into compliance.
+ Moreover, Your grants from a particular Contributor are reinstated on an
+ ongoing basis if such Contributor notifies You of the non-compliance by
+ some reasonable means, this is the first time You have received notice of
+ non-compliance with this License from such Contributor, and You become
+ compliant prior to 30 days after Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+ infringement claim (excluding declaratory judgment actions, counter-claims,
+ and cross-claims) alleging that a Contributor Version directly or
+ indirectly infringes any patent, then the rights granted to You by any and
+ all Contributors for the Covered Software under Section 2.1 of this License
+ shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
+ license agreements (excluding distributors and resellers) which have been
+ validly granted by You or Your distributors under this License prior to
+ termination shall survive termination.
+
+6. Disclaimer of Warranty
+
+ Covered Software is provided under this License on an “as is†basis, without
+ warranty of any kind, either expressed, implied, or statutory, including,
+ without limitation, warranties that the Covered Software is free of defects,
+ merchantable, fit for a particular purpose or non-infringing. The entire
+ risk as to the quality and performance of the Covered Software is with You.
+ Should any Covered Software prove defective in any respect, You (not any
+ Contributor) assume the cost of any necessary servicing, repair, or
+ correction. This disclaimer of warranty constitutes an essential part of this
+ License. No use of any Covered Software is authorized under this License
+ except under this disclaimer.
+
+7. Limitation of Liability
+
+ Under no circumstances and under no legal theory, whether tort (including
+ negligence), contract, or otherwise, shall any Contributor, or anyone who
+ distributes Covered Software as permitted above, be liable to You for any
+ direct, indirect, special, incidental, or consequential damages of any
+ character including, without limitation, damages for lost profits, loss of
+ goodwill, work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses, even if such party shall have been
+ informed of the possibility of such damages. This limitation of liability
+ shall not apply to liability for death or personal injury resulting from such
+ party’s negligence to the extent applicable law prohibits such limitation.
+ Some jurisdictions do not allow the exclusion or limitation of incidental or
+ consequential damages, so this exclusion and limitation may not apply to You.
+
+8. Litigation
+
+ Any litigation relating to this License may be brought only in the courts of
+ a jurisdiction where the defendant maintains its principal place of business
+ and such litigation shall be governed by laws of that jurisdiction, without
+ reference to its conflict-of-law provisions. Nothing in this Section shall
+ prevent a party’s ability to bring cross-claims or counter-claims.
+
+9. Miscellaneous
+
+ This License represents the complete agreement concerning the subject matter
+ hereof. If any provision of this License is held to be unenforceable, such
+ provision shall be reformed only to the extent necessary to make it
+ enforceable. Any law or regulation which provides that the language of a
+ contract shall be construed against the drafter shall not be used to construe
+ this License against a Contributor.
+
+
+10. Versions of the License
+
+10.1. New Versions
+
+ Mozilla Foundation is the license steward. Except as provided in Section
+ 10.3, no one other than the license steward has the right to modify or
+ publish new versions of this License. Each version will be given a
+ distinguishing version number.
+
+10.2. Effect of New Versions
+
+ You may distribute the Covered Software under the terms of the version of
+ the License under which You originally received the Covered Software, or
+ under the terms of any subsequent version published by the license
+ steward.
+
+10.3. Modified Versions
+
+ If you create software not governed by this License, and you want to
+ create a new license for such software, you may create and use a modified
+ version of this License if you rename the license and remove any
+ references to the name of the license steward (except to note that such
+ modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
+ If You choose to distribute Source Code Form that is Incompatible With
+ Secondary Licenses under the terms of this version of the License, the
+ notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+
+ This Source Code Form is subject to the
+ terms of the Mozilla Public License, v.
+ 2.0. If a copy of the MPL was not
+ distributed with this file, You can
+ obtain one at
+ http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular file, then
+You may include the notice in a location (such as a LICENSE file in a relevant
+directory) where a recipient would be likely to look for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - “Incompatible With Secondary Licenses†Notice
+
+ This Source Code Form is “Incompatible
+ With Secondary Licensesâ€, as defined by
+ the Mozilla Public License, v. 2.0.
diff --git a/vendor/github.com/hashicorp/go-multierror/Makefile b/vendor/github.com/hashicorp/go-multierror/Makefile
new file mode 100644
index 0000000000..b97cd6ed02
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-multierror/Makefile
@@ -0,0 +1,31 @@
+TEST?=./...
+
+default: test
+
+# test runs the test suite and vets the code.
+test: generate
+ @echo "==> Running tests..."
+ @go list $(TEST) \
+ | grep -v "/vendor/" \
+ | xargs -n1 go test -timeout=60s -parallel=10 ${TESTARGS}
+
+# testrace runs the race checker
+testrace: generate
+ @echo "==> Running tests (race)..."
+ @go list $(TEST) \
+ | grep -v "/vendor/" \
+ | xargs -n1 go test -timeout=60s -race ${TESTARGS}
+
+# updatedeps installs all the dependencies needed to run and build.
+updatedeps:
+ @sh -c "'${CURDIR}/scripts/deps.sh' '${NAME}'"
+
+# generate runs `go generate` to build the dynamically generated source files.
+generate:
+ @echo "==> Generating..."
+ @find . -type f -name '.DS_Store' -delete
+ @go list ./... \
+ | grep -v "/vendor/" \
+ | xargs -n1 go generate
+
+.PHONY: default test testrace updatedeps generate
diff --git a/vendor/github.com/hashicorp/go-multierror/README.md b/vendor/github.com/hashicorp/go-multierror/README.md
new file mode 100644
index 0000000000..71dd308ed8
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-multierror/README.md
@@ -0,0 +1,150 @@
+# go-multierror
+
+[](https://circleci.com/gh/hashicorp/go-multierror)
+[](https://pkg.go.dev/github.com/hashicorp/go-multierror)
+
+
+[circleci]: https://app.circleci.com/pipelines/github/hashicorp/go-multierror
+[godocs]: https://pkg.go.dev/github.com/hashicorp/go-multierror
+
+`go-multierror` is a package for Go that provides a mechanism for
+representing a list of `error` values as a single `error`.
+
+This allows a function in Go to return an `error` that might actually
+be a list of errors. If the caller knows this, they can unwrap the
+list and access the errors. If the caller doesn't know, the error
+formats to a nice human-readable format.
+
+`go-multierror` is fully compatible with the Go standard library
+[errors](https://golang.org/pkg/errors/) package, including the
+functions `As`, `Is`, and `Unwrap`. This provides a standardized approach
+for introspecting on error values.
+
+## Installation and Docs
+
+Install using `go get github.com/hashicorp/go-multierror`.
+
+Full documentation is available at
+https://pkg.go.dev/github.com/hashicorp/go-multierror
+
+### Requires go version 1.13 or newer
+
+`go-multierror` requires go version 1.13 or newer. Go 1.13 introduced
+[error wrapping](https://golang.org/doc/go1.13#error_wrapping), which
+this library takes advantage of.
+
+If you need to use an earlier version of go, you can use the
+[v1.0.0](https://github.com/hashicorp/go-multierror/tree/v1.0.0)
+tag, which doesn't rely on features in go 1.13.
+
+If you see compile errors that look like the below, it's likely that
+you're on an older version of go:
+
+```
+/go/src/github.com/hashicorp/go-multierror/multierror.go:112:9: undefined: errors.As
+/go/src/github.com/hashicorp/go-multierror/multierror.go:117:9: undefined: errors.Is
+```
+
+## Usage
+
+go-multierror is easy to use and purposely built to be unobtrusive in
+existing Go applications/libraries that may not be aware of it.
+
+**Building a list of errors**
+
+The `Append` function is used to create a list of errors. This function
+behaves a lot like the Go built-in `append` function: it doesn't matter
+if the first argument is nil, a `multierror.Error`, or any other `error`,
+the function behaves as you would expect.
+
+```go
+var result error
+
+if err := step1(); err != nil {
+ result = multierror.Append(result, err)
+}
+if err := step2(); err != nil {
+ result = multierror.Append(result, err)
+}
+
+return result
+```
+
+**Customizing the formatting of the errors**
+
+By specifying a custom `ErrorFormat`, you can customize the format
+of the `Error() string` function:
+
+```go
+var result *multierror.Error
+
+// ... accumulate errors here, maybe using Append
+
+if result != nil {
+ result.ErrorFormat = func([]error) string {
+ return "errors!"
+ }
+}
+```
+
+**Accessing the list of errors**
+
+`multierror.Error` implements `error` so if the caller doesn't know about
+multierror, it will work just fine. But if you're aware a multierror might
+be returned, you can use type switches to access the list of errors:
+
+```go
+if err := something(); err != nil {
+ if merr, ok := err.(*multierror.Error); ok {
+ // Use merr.Errors
+ }
+}
+```
+
+You can also use the standard [`errors.Unwrap`](https://golang.org/pkg/errors/#Unwrap)
+function. This will continue to unwrap into subsequent errors until none exist.
+
+**Extracting an error**
+
+The standard library [`errors.As`](https://golang.org/pkg/errors/#As)
+function can be used directly with a multierror to extract a specific error:
+
+```go
+// Assume err is a multierror value
+err := somefunc()
+
+// We want to know if "err" has a "RichErrorType" in it and extract it.
+var errRich RichErrorType
+if errors.As(err, &errRich) {
+ // It has it, and now errRich is populated.
+}
+```
+
+**Checking for an exact error value**
+
+Some errors are returned as exact errors such as the [`ErrNotExist`](https://golang.org/pkg/os/#pkg-variables)
+error in the `os` package. You can check if this error is present by using
+the standard [`errors.Is`](https://golang.org/pkg/errors/#Is) function.
+
+```go
+// Assume err is a multierror value
+err := somefunc()
+if errors.Is(err, os.ErrNotExist) {
+ // err contains os.ErrNotExist
+}
+```
+
+**Returning a multierror only if there are errors**
+
+If you build a `multierror.Error`, you can use the `ErrorOrNil` function
+to return an `error` implementation only if there are errors to return:
+
+```go
+var result *multierror.Error
+
+// ... accumulate errors here
+
+// Return the `error` only if errors were added to the multierror, otherwise
+// return nil since there are no errors.
+return result.ErrorOrNil()
+```
diff --git a/vendor/github.com/hashicorp/go-multierror/append.go b/vendor/github.com/hashicorp/go-multierror/append.go
new file mode 100644
index 0000000000..3e2589bfde
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-multierror/append.go
@@ -0,0 +1,43 @@
+package multierror
+
+// Append is a helper function that will append more errors
+// onto an Error in order to create a larger multi-error.
+//
+// If err is not a multierror.Error, then it will be turned into
+// one. If any of the errs are multierr.Error, they will be flattened
+// one level into err.
+// Any nil errors within errs will be ignored. If err is nil, a new
+// *Error will be returned.
+func Append(err error, errs ...error) *Error {
+ switch err := err.(type) {
+ case *Error:
+ // Typed nils can reach here, so initialize if we are nil
+ if err == nil {
+ err = new(Error)
+ }
+
+ // Go through each error and flatten
+ for _, e := range errs {
+ switch e := e.(type) {
+ case *Error:
+ if e != nil {
+ err.Errors = append(err.Errors, e.Errors...)
+ }
+ default:
+ if e != nil {
+ err.Errors = append(err.Errors, e)
+ }
+ }
+ }
+
+ return err
+ default:
+ newErrs := make([]error, 0, len(errs)+1)
+ if err != nil {
+ newErrs = append(newErrs, err)
+ }
+ newErrs = append(newErrs, errs...)
+
+ return Append(&Error{}, newErrs...)
+ }
+}
diff --git a/vendor/github.com/hashicorp/go-multierror/flatten.go b/vendor/github.com/hashicorp/go-multierror/flatten.go
new file mode 100644
index 0000000000..aab8e9abec
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-multierror/flatten.go
@@ -0,0 +1,26 @@
+package multierror
+
+// Flatten flattens the given error, merging any *Errors together into
+// a single *Error.
+func Flatten(err error) error {
+ // If it isn't an *Error, just return the error as-is
+ if _, ok := err.(*Error); !ok {
+ return err
+ }
+
+ // Otherwise, make the result and flatten away!
+ flatErr := new(Error)
+ flatten(err, flatErr)
+ return flatErr
+}
+
+func flatten(err error, flatErr *Error) {
+ switch err := err.(type) {
+ case *Error:
+ for _, e := range err.Errors {
+ flatten(e, flatErr)
+ }
+ default:
+ flatErr.Errors = append(flatErr.Errors, err)
+ }
+}
diff --git a/vendor/github.com/hashicorp/go-multierror/format.go b/vendor/github.com/hashicorp/go-multierror/format.go
new file mode 100644
index 0000000000..47f13c49a6
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-multierror/format.go
@@ -0,0 +1,27 @@
+package multierror
+
+import (
+ "fmt"
+ "strings"
+)
+
+// ErrorFormatFunc is a function callback that is called by Error to
+// turn the list of errors into a string.
+type ErrorFormatFunc func([]error) string
+
+// ListFormatFunc is a basic formatter that outputs the number of errors
+// that occurred along with a bullet point list of the errors.
+func ListFormatFunc(es []error) string {
+ if len(es) == 1 {
+ return fmt.Sprintf("1 error occurred:\n\t* %s\n\n", es[0])
+ }
+
+ points := make([]string, len(es))
+ for i, err := range es {
+ points[i] = fmt.Sprintf("* %s", err)
+ }
+
+ return fmt.Sprintf(
+ "%d errors occurred:\n\t%s\n\n",
+ len(es), strings.Join(points, "\n\t"))
+}
diff --git a/vendor/github.com/hashicorp/go-multierror/group.go b/vendor/github.com/hashicorp/go-multierror/group.go
new file mode 100644
index 0000000000..9c29efb7f8
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-multierror/group.go
@@ -0,0 +1,38 @@
+package multierror
+
+import "sync"
+
+// Group is a collection of goroutines which return errors that need to be
+// coalesced.
+type Group struct {
+ mutex sync.Mutex
+ err *Error
+ wg sync.WaitGroup
+}
+
+// Go calls the given function in a new goroutine.
+//
+// If the function returns an error it is added to the group multierror which
+// is returned by Wait.
+func (g *Group) Go(f func() error) {
+ g.wg.Add(1)
+
+ go func() {
+ defer g.wg.Done()
+
+ if err := f(); err != nil {
+ g.mutex.Lock()
+ g.err = Append(g.err, err)
+ g.mutex.Unlock()
+ }
+ }()
+}
+
+// Wait blocks until all function calls from the Go method have returned, then
+// returns the multierror.
+func (g *Group) Wait() *Error {
+ g.wg.Wait()
+ g.mutex.Lock()
+ defer g.mutex.Unlock()
+ return g.err
+}
diff --git a/vendor/github.com/hashicorp/go-multierror/multierror.go b/vendor/github.com/hashicorp/go-multierror/multierror.go
new file mode 100644
index 0000000000..f545743264
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-multierror/multierror.go
@@ -0,0 +1,121 @@
+package multierror
+
+import (
+ "errors"
+ "fmt"
+)
+
+// Error is an error type to track multiple errors. This is used to
+// accumulate errors in cases and return them as a single "error".
+type Error struct {
+ Errors []error
+ ErrorFormat ErrorFormatFunc
+}
+
+func (e *Error) Error() string {
+ fn := e.ErrorFormat
+ if fn == nil {
+ fn = ListFormatFunc
+ }
+
+ return fn(e.Errors)
+}
+
+// ErrorOrNil returns an error interface if this Error represents
+// a list of errors, or returns nil if the list of errors is empty. This
+// function is useful at the end of accumulation to make sure that the value
+// returned represents the existence of errors.
+func (e *Error) ErrorOrNil() error {
+ if e == nil {
+ return nil
+ }
+ if len(e.Errors) == 0 {
+ return nil
+ }
+
+ return e
+}
+
+func (e *Error) GoString() string {
+ return fmt.Sprintf("*%#v", *e)
+}
+
+// WrappedErrors returns the list of errors that this Error is wrapping. It is
+// an implementation of the errwrap.Wrapper interface so that multierror.Error
+// can be used with that library.
+//
+// This method is not safe to be called concurrently. Unlike accessing the
+// Errors field directly, this function also checks if the multierror is nil to
+// prevent a null-pointer panic. It satisfies the errwrap.Wrapper interface.
+func (e *Error) WrappedErrors() []error {
+ if e == nil {
+ return nil
+ }
+ return e.Errors
+}
+
+// Unwrap returns an error from Error (or nil if there are no errors).
+// This error returned will further support Unwrap to get the next error,
+// etc. The order will match the order of Errors in the multierror.Error
+// at the time of calling.
+//
+// The resulting error supports errors.As/Is/Unwrap so you can continue
+// to use the stdlib errors package to introspect further.
+//
+// This will perform a shallow copy of the errors slice. Any errors appended
+// to this error after calling Unwrap will not be available until a new
+// Unwrap is called on the multierror.Error.
+func (e *Error) Unwrap() error {
+ // If we have no errors then we do nothing
+ if e == nil || len(e.Errors) == 0 {
+ return nil
+ }
+
+ // If we have exactly one error, we can just return that directly.
+ if len(e.Errors) == 1 {
+ return e.Errors[0]
+ }
+
+ // Shallow copy the slice
+ errs := make([]error, len(e.Errors))
+ copy(errs, e.Errors)
+ return chain(errs)
+}
+
+// chain implements the interfaces necessary for errors.Is/As/Unwrap to
+// work in a deterministic way with multierror. A chain tracks a list of
+// errors while accounting for the current represented error. This lets
+// Is/As be meaningful.
+//
+// Unwrap returns the next error. In the cleanest form, Unwrap would return
+// the wrapped error here but we can't do that if we want to properly
+// get access to all the errors. Instead, users are recommended to use
+// Is/As to get the correct error type out.
+//
+// Precondition: []error is non-empty (len > 0)
+type chain []error
+
+// Error implements the error interface
+func (e chain) Error() string {
+ return e[0].Error()
+}
+
+// Unwrap implements errors.Unwrap by returning the next error in the
+// chain or nil if there are no more errors.
+func (e chain) Unwrap() error {
+ if len(e) == 1 {
+ return nil
+ }
+
+ return e[1:]
+}
+
+// As implements errors.As by attempting to map to the current value.
+func (e chain) As(target interface{}) bool {
+ return errors.As(e[0], target)
+}
+
+// Is implements errors.Is by comparing the current value directly.
+func (e chain) Is(target error) bool {
+ return errors.Is(e[0], target)
+}
diff --git a/vendor/github.com/hashicorp/go-multierror/prefix.go b/vendor/github.com/hashicorp/go-multierror/prefix.go
new file mode 100644
index 0000000000..5c477abe44
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-multierror/prefix.go
@@ -0,0 +1,37 @@
+package multierror
+
+import (
+ "fmt"
+
+ "github.com/hashicorp/errwrap"
+)
+
+// Prefix is a helper function that will prefix some text
+// to the given error. If the error is a multierror.Error, then
+// it will be prefixed to each wrapped error.
+//
+// This is useful to use when appending multiple multierrors
+// together in order to give better scoping.
+func Prefix(err error, prefix string) error {
+ if err == nil {
+ return nil
+ }
+
+ format := fmt.Sprintf("%s {{err}}", prefix)
+ switch err := err.(type) {
+ case *Error:
+ // Typed nils can reach here, so initialize if we are nil
+ if err == nil {
+ err = new(Error)
+ }
+
+ // Wrap each of the errors
+ for i, e := range err.Errors {
+ err.Errors[i] = errwrap.Wrapf(format, e)
+ }
+
+ return err
+ default:
+ return errwrap.Wrapf(format, err)
+ }
+}
diff --git a/vendor/github.com/hashicorp/go-multierror/sort.go b/vendor/github.com/hashicorp/go-multierror/sort.go
new file mode 100644
index 0000000000..fecb14e81c
--- /dev/null
+++ b/vendor/github.com/hashicorp/go-multierror/sort.go
@@ -0,0 +1,16 @@
+package multierror
+
+// Len implements sort.Interface function for length
+func (err Error) Len() int {
+ return len(err.Errors)
+}
+
+// Swap implements sort.Interface function for swapping elements
+func (err Error) Swap(i, j int) {
+ err.Errors[i], err.Errors[j] = err.Errors[j], err.Errors[i]
+}
+
+// Less implements sort.Interface function for determining order
+func (err Error) Less(i, j int) bool {
+ return err.Errors[i].Error() < err.Errors[j].Error()
+}
diff --git a/vendor/github.com/huandu/xstrings/.gitignore b/vendor/github.com/huandu/xstrings/.gitignore
new file mode 100644
index 0000000000..daf913b1b3
--- /dev/null
+++ b/vendor/github.com/huandu/xstrings/.gitignore
@@ -0,0 +1,24 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
diff --git a/vendor/github.com/huandu/xstrings/CONTRIBUTING.md b/vendor/github.com/huandu/xstrings/CONTRIBUTING.md
new file mode 100644
index 0000000000..d7b4b8d584
--- /dev/null
+++ b/vendor/github.com/huandu/xstrings/CONTRIBUTING.md
@@ -0,0 +1,23 @@
+# Contributing #
+
+Thanks for your contribution in advance. No matter what you will contribute to this project, pull request or bug report or feature discussion, it's always highly appreciated.
+
+## New API or feature ##
+
+I want to speak more about how to add new functions to this package.
+
+Package `xstring` is a collection of useful string functions which should be implemented in Go. It's a bit subject to say which function should be included and which should not. I set up following rules in order to make it clear and as objective as possible.
+
+* Rule 1: Only string algorithm, which takes string as input, can be included.
+* Rule 2: If a function has been implemented in package `string`, it must not be included.
+* Rule 3: If a function is not language neutral, it must not be included.
+* Rule 4: If a function is a part of standard library in other languages, it can be included.
+* Rule 5: If a function is quite useful in some famous framework or library, it can be included.
+
+New function must be discussed in project issues before submitting any code. If a pull request with new functions is sent without any ref issue, it will be rejected.
+
+## Pull request ##
+
+Pull request is always welcome. Just make sure you have run `go fmt` and all test cases passed before submit.
+
+If the pull request is to add a new API or feature, don't forget to update README.md and add new API in function list.
diff --git a/vendor/github.com/huandu/xstrings/LICENSE b/vendor/github.com/huandu/xstrings/LICENSE
new file mode 100644
index 0000000000..2701772593
--- /dev/null
+++ b/vendor/github.com/huandu/xstrings/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Huan Du
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/vendor/github.com/huandu/xstrings/README.md b/vendor/github.com/huandu/xstrings/README.md
new file mode 100644
index 0000000000..e809c79abc
--- /dev/null
+++ b/vendor/github.com/huandu/xstrings/README.md
@@ -0,0 +1,118 @@
+# xstrings
+
+[](https://github.com/huandu/xstrings/actions)
+[](https://pkg.go.dev/github.com/huandu/xstrings)
+[](https://goreportcard.com/report/github.com/huandu/xstrings)
+[](https://coveralls.io/github/huandu/xstrings?branch=master)
+
+Go package [xstrings](https://godoc.org/github.com/huandu/xstrings) is a collection of string functions, which are widely used in other languages but absent in Go package [strings](http://golang.org/pkg/strings).
+
+All functions are well tested and carefully tuned for performance.
+
+## Propose a new function
+
+Please review [contributing guideline](CONTRIBUTING.md) and [create new issue](https://github.com/huandu/xstrings/issues) to state why it should be included.
+
+## Install
+
+Use `go get` to install this library.
+
+ go get github.com/huandu/xstrings
+
+## API document
+
+See [GoDoc](https://godoc.org/github.com/huandu/xstrings) for full document.
+
+## Function list
+
+Go functions have a unique naming style. One, who has experience in other language but new in Go, may have difficulties to find out right string function to use.
+
+Here is a list of functions in [strings](http://golang.org/pkg/strings) and [xstrings](https://godoc.org/github.com/huandu/xstrings) with enough extra information about how to map these functions to their friends in other languages. Hope this list could be helpful for fresh gophers.
+
+### Package `xstrings` functions
+
+_Keep this table sorted by Function in ascending order._
+
+| Function | Friends | # |
+| --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | --------------------------------------------------- |
+| [Center](https://godoc.org/github.com/huandu/xstrings#Center) | `str.center` in Python; `String#center` in Ruby | [#30](https://github.com/huandu/xstrings/issues/30) |
+| [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) |
+| [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) |
+| [Len](https://godoc.org/github.com/huandu/xstrings#Len) | `mb_strlen` in PHP | [#23](https://github.com/huandu/xstrings/issues/23) |
+| [Partition](https://godoc.org/github.com/huandu/xstrings#Partition) | `str.partition` in Python; `String#partition` in Ruby | [#10](https://github.com/huandu/xstrings/issues/10) |
+| [Reverse](https://godoc.org/github.com/huandu/xstrings#Reverse) | `String#reverse` in Ruby; `strrev` in PHP; `reverse` in Perl | [#7](https://github.com/huandu/xstrings/issues/7) |
+| [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) |
+| [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) |
+| [WordCount](https://godoc.org/github.com/huandu/xstrings#WordCount) | `str_word_count` in PHP | [#14](https://github.com/huandu/xstrings/issues/14) |
+| [WordSplit](https://godoc.org/github.com/huandu/xstrings#WordSplit) | - | [#14](https://github.com/huandu/xstrings/issues/14) |
+
+### Package `strings` functions
+
+_Keep this table sorted by Function in ascending order._
+
+| Function | Friends |
+| --------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
+| [Contains](http://golang.org/pkg/strings/#Contains) | `String#include?` in Ruby |
+| [ContainsAny](http://golang.org/pkg/strings/#ContainsAny) | - |
+| [ContainsRune](http://golang.org/pkg/strings/#ContainsRune) | - |
+| [Count](http://golang.org/pkg/strings/#Count) | `str.count` in Python; `substr_count` in PHP |
+| [EqualFold](http://golang.org/pkg/strings/#EqualFold) | `stricmp` in PHP; `String#casecmp` in Ruby |
+| [Fields](http://golang.org/pkg/strings/#Fields) | `str.split` in Python; `split` in Perl; `String#split` in Ruby |
+| [FieldsFunc](http://golang.org/pkg/strings/#FieldsFunc) | - |
+| [HasPrefix](http://golang.org/pkg/strings/#HasPrefix) | `str.startswith` in Python; `String#start_with?` in Ruby |
+| [HasSuffix](http://golang.org/pkg/strings/#HasSuffix) | `str.endswith` in Python; `String#end_with?` in Ruby |
+| [Index](http://golang.org/pkg/strings/#Index) | `str.index` in Python; `String#index` in Ruby; `strpos` in PHP; `index` in Perl |
+| [IndexAny](http://golang.org/pkg/strings/#IndexAny) | - |
+| [IndexByte](http://golang.org/pkg/strings/#IndexByte) | - |
+| [IndexFunc](http://golang.org/pkg/strings/#IndexFunc) | - |
+| [IndexRune](http://golang.org/pkg/strings/#IndexRune) | - |
+| [Join](http://golang.org/pkg/strings/#Join) | `str.join` in Python; `Array#join` in Ruby; `implode` in PHP; `join` in Perl |
+| [LastIndex](http://golang.org/pkg/strings/#LastIndex) | `str.rindex` in Python; `String#rindex`; `strrpos` in PHP; `rindex` in Perl |
+| [LastIndexAny](http://golang.org/pkg/strings/#LastIndexAny) | - |
+| [LastIndexFunc](http://golang.org/pkg/strings/#LastIndexFunc) | - |
+| [Map](http://golang.org/pkg/strings/#Map) | `String#each_codepoint` in Ruby |
+| [Repeat](http://golang.org/pkg/strings/#Repeat) | operator `*` in Python and Ruby; `str_repeat` in PHP |
+| [Replace](http://golang.org/pkg/strings/#Replace) | `str.replace` in Python; `String#sub` in Ruby; `str_replace` in PHP |
+| [Split](http://golang.org/pkg/strings/#Split) | `str.split` in Python; `String#split` in Ruby; `explode` in PHP; `split` in Perl |
+| [SplitAfter](http://golang.org/pkg/strings/#SplitAfter) | - |
+| [SplitAfterN](http://golang.org/pkg/strings/#SplitAfterN) | - |
+| [SplitN](http://golang.org/pkg/strings/#SplitN) | `str.split` in Python; `String#split` in Ruby; `explode` in PHP; `split` in Perl |
+| [Title](http://golang.org/pkg/strings/#Title) | `str.title` in Python |
+| [ToLower](http://golang.org/pkg/strings/#ToLower) | `str.lower` in Python; `String#downcase` in Ruby; `strtolower` in PHP; `lc` in Perl |
+| [ToLowerSpecial](http://golang.org/pkg/strings/#ToLowerSpecial) | - |
+| [ToTitle](http://golang.org/pkg/strings/#ToTitle) | - |
+| [ToTitleSpecial](http://golang.org/pkg/strings/#ToTitleSpecial) | - |
+| [ToUpper](http://golang.org/pkg/strings/#ToUpper) | `str.upper` in Python; `String#upcase` in Ruby; `strtoupper` in PHP; `uc` in Perl |
+| [ToUpperSpecial](http://golang.org/pkg/strings/#ToUpperSpecial) | - |
+| [Trim](http://golang.org/pkg/strings/#Trim) | `str.strip` in Python; `String#strip` in Ruby; `trim` in PHP |
+| [TrimFunc](http://golang.org/pkg/strings/#TrimFunc) | - |
+| [TrimLeft](http://golang.org/pkg/strings/#TrimLeft) | `str.lstrip` in Python; `String#lstrip` in Ruby; `ltrim` in PHP |
+| [TrimLeftFunc](http://golang.org/pkg/strings/#TrimLeftFunc) | - |
+| [TrimPrefix](http://golang.org/pkg/strings/#TrimPrefix) | - |
+| [TrimRight](http://golang.org/pkg/strings/#TrimRight) | `str.rstrip` in Python; `String#rstrip` in Ruby; `rtrim` in PHP |
+| [TrimRightFunc](http://golang.org/pkg/strings/#TrimRightFunc) | - |
+| [TrimSpace](http://golang.org/pkg/strings/#TrimSpace) | `str.strip` in Python; `String#strip` in Ruby; `trim` in PHP |
+| [TrimSuffix](http://golang.org/pkg/strings/#TrimSuffix) | `String#chomp` in Ruby; `chomp` in Perl |
+
+## License
+
+This library is licensed under MIT license. See LICENSE for details.
diff --git a/vendor/github.com/huandu/xstrings/common.go b/vendor/github.com/huandu/xstrings/common.go
new file mode 100644
index 0000000000..f427cc84e2
--- /dev/null
+++ b/vendor/github.com/huandu/xstrings/common.go
@@ -0,0 +1,21 @@
+// Copyright 2015 Huan Du. All rights reserved.
+// Licensed under the MIT license that can be found in the LICENSE file.
+
+package xstrings
+
+const bufferMaxInitGrowSize = 2048
+
+// Lazy initialize a buffer.
+func allocBuffer(orig, cur string) *stringBuilder {
+ output := &stringBuilder{}
+ maxSize := len(orig) * 4
+
+ // Avoid to reserve too much memory at once.
+ if maxSize > bufferMaxInitGrowSize {
+ maxSize = bufferMaxInitGrowSize
+ }
+
+ output.Grow(maxSize)
+ output.WriteString(orig[:len(orig)-len(cur)])
+ return output
+}
diff --git a/vendor/github.com/huandu/xstrings/convert.go b/vendor/github.com/huandu/xstrings/convert.go
new file mode 100644
index 0000000000..5d8cfee470
--- /dev/null
+++ b/vendor/github.com/huandu/xstrings/convert.go
@@ -0,0 +1,633 @@
+// Copyright 2015 Huan Du. All rights reserved.
+// Licensed under the MIT license that can be found in the LICENSE file.
+
+package xstrings
+
+import (
+ "math/rand"
+ "unicode"
+ "unicode/utf8"
+)
+
+// ToCamelCase is to convert words separated by space, underscore and hyphen to camel case.
+//
+// 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"
+// "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
+
+ // leading connector will appear in output.
+ for len(str) > 0 {
+ r0, size = utf8.DecodeRuneInString(str)
+ str = str[size:]
+
+ if !isConnector(r0) {
+ isFirstRuneUpper = unicode.IsUpper(r0)
+
+ if isBig {
+ r0 = unicode.ToUpper(r0)
+ } else {
+ r0 = unicode.ToLower(r0)
+ }
+
+ break
+ }
+
+ buf.WriteRune(r0)
+ }
+
+ if len(str) == 0 {
+ // A special case for a string contains only 1 rune.
+ if size != 0 {
+ buf.WriteRune(r0)
+ }
+
+ return buf.String()
+ }
+
+ for len(str) > 0 {
+ r1 = r0
+ r0, size = utf8.DecodeRuneInString(str)
+ str = str[size:]
+
+ if isConnector(r0) && isConnector(r1) {
+ buf.WriteRune(r1)
+ continue
+ }
+
+ 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()
+}
+
+// ToSnakeCase can convert all upper case characters in a string to
+// snake case format.
+//
+// Some samples.
+//
+// "FirstName" => "first_name"
+// "HTTPServer" => "http_server"
+// "NoHTTPS" => "no_https"
+// "GO_PATH" => "go_path"
+// "GO PATH" => "go_path" // space is converted to underscore.
+// "GO-PATH" => "go_path" // hyphen is converted to underscore.
+// "http2xx" => "http_2xx" // insert an underscore before a number and after an alphabet.
+// "HTTP20xOK" => "http_20x_ok"
+// "Duration2m3s" => "duration_2m3s"
+// "Bld4Floor3rd" => "bld4_floor_3rd"
+func ToSnakeCase(str string) string {
+ return camelCaseToLowerCase(str, '_')
+}
+
+// ToKebabCase can convert all upper case characters in a string to
+// kebab case format.
+//
+// Some samples.
+//
+// "FirstName" => "first-name"
+// "HTTPServer" => "http-server"
+// "NoHTTPS" => "no-https"
+// "GO_PATH" => "go-path"
+// "GO PATH" => "go-path" // space is converted to '-'.
+// "GO-PATH" => "go-path" // hyphen is converted to '-'.
+// "http2xx" => "http-2xx" // insert an underscore before a number and after an alphabet.
+// "HTTP20xOK" => "http-20x-ok"
+// "Duration2m3s" => "duration-2m3s"
+// "Bld4Floor3rd" => "bld4-floor-3rd"
+func ToKebabCase(str string) string {
+ return camelCaseToLowerCase(str, '-')
+}
+
+func camelCaseToLowerCase(str string, connector rune) string {
+ if len(str) == 0 {
+ return ""
+ }
+
+ buf := &stringBuilder{}
+ wt, word, remaining := nextWord(str)
+
+ for len(remaining) > 0 {
+ if wt != connectorWord {
+ toLower(buf, wt, word, connector)
+ }
+
+ prev := wt
+ last := word
+ wt, word, remaining = nextWord(remaining)
+
+ switch prev {
+ case numberWord:
+ for wt == alphabetWord || wt == numberWord {
+ toLower(buf, wt, word, connector)
+ wt, word, remaining = nextWord(remaining)
+ }
+
+ if wt != invalidWord && wt != punctWord && wt != connectorWord {
+ buf.WriteRune(connector)
+ }
+
+ case connectorWord:
+ toLower(buf, prev, last, connector)
+
+ case punctWord:
+ // nothing.
+
+ default:
+ if wt != numberWord {
+ if wt != connectorWord && wt != punctWord {
+ buf.WriteRune(connector)
+ }
+
+ break
+ }
+
+ if len(remaining) == 0 {
+ break
+ }
+
+ last := word
+ wt, word, remaining = nextWord(remaining)
+
+ // consider number as a part of previous word.
+ // e.g. "Bld4Floor" => "bld4_floor"
+ if wt != alphabetWord {
+ toLower(buf, numberWord, last, connector)
+
+ if wt != connectorWord && wt != punctWord {
+ buf.WriteRune(connector)
+ }
+
+ break
+ }
+
+ // if there are some lower case letters following a number,
+ // add connector before the number.
+ // e.g. "HTTP2xx" => "http_2xx"
+ buf.WriteRune(connector)
+ toLower(buf, numberWord, last, connector)
+
+ for wt == alphabetWord || wt == numberWord {
+ toLower(buf, wt, word, connector)
+ wt, word, remaining = nextWord(remaining)
+ }
+
+ if wt != invalidWord && wt != connectorWord && wt != punctWord {
+ buf.WriteRune(connector)
+ }
+ }
+ }
+
+ toLower(buf, wt, word, connector)
+ return buf.String()
+}
+
+func isConnector(r rune) bool {
+ return r == '-' || r == '_' || unicode.IsSpace(r)
+}
+
+type wordType int
+
+const (
+ invalidWord wordType = iota
+ numberWord
+ upperCaseWord
+ alphabetWord
+ connectorWord
+ punctWord
+ otherWord
+)
+
+func nextWord(str string) (wt wordType, word, remaining string) {
+ if len(str) == 0 {
+ return
+ }
+
+ var offset int
+ remaining = str
+ r, size := nextValidRune(remaining, utf8.RuneError)
+ offset += size
+
+ if r == utf8.RuneError {
+ wt = invalidWord
+ word = str[:offset]
+ remaining = str[offset:]
+ return
+ }
+
+ switch {
+ case isConnector(r):
+ wt = connectorWord
+ remaining = remaining[size:]
+
+ for len(remaining) > 0 {
+ r, size = nextValidRune(remaining, r)
+
+ if !isConnector(r) {
+ break
+ }
+
+ offset += size
+ remaining = remaining[size:]
+ }
+
+ case unicode.IsPunct(r):
+ wt = punctWord
+ remaining = remaining[size:]
+
+ for len(remaining) > 0 {
+ r, size = nextValidRune(remaining, r)
+
+ if !unicode.IsPunct(r) {
+ break
+ }
+
+ offset += size
+ remaining = remaining[size:]
+ }
+
+ case unicode.IsUpper(r):
+ wt = upperCaseWord
+ remaining = remaining[size:]
+
+ if len(remaining) == 0 {
+ break
+ }
+
+ r, size = nextValidRune(remaining, r)
+
+ switch {
+ case unicode.IsUpper(r):
+ prevSize := size
+ offset += size
+ remaining = remaining[size:]
+
+ for len(remaining) > 0 {
+ r, size = nextValidRune(remaining, r)
+
+ if !unicode.IsUpper(r) {
+ break
+ }
+
+ prevSize = size
+ offset += size
+ remaining = remaining[size:]
+ }
+
+ // it's a bit complex when dealing with a case like "HTTPStatus".
+ // it's expected to be splitted into "HTTP" and "Status".
+ // Therefore "S" should be in remaining instead of word.
+ if len(remaining) > 0 && isAlphabet(r) {
+ offset -= prevSize
+ remaining = str[offset:]
+ }
+
+ case isAlphabet(r):
+ offset += size
+ remaining = remaining[size:]
+
+ for len(remaining) > 0 {
+ r, size = nextValidRune(remaining, r)
+
+ if !isAlphabet(r) || unicode.IsUpper(r) {
+ break
+ }
+
+ offset += size
+ remaining = remaining[size:]
+ }
+ }
+
+ case isAlphabet(r):
+ wt = alphabetWord
+ remaining = remaining[size:]
+
+ for len(remaining) > 0 {
+ r, size = nextValidRune(remaining, r)
+
+ if !isAlphabet(r) || unicode.IsUpper(r) {
+ break
+ }
+
+ offset += size
+ remaining = remaining[size:]
+ }
+
+ case unicode.IsNumber(r):
+ wt = numberWord
+ remaining = remaining[size:]
+
+ for len(remaining) > 0 {
+ r, size = nextValidRune(remaining, r)
+
+ if !unicode.IsNumber(r) {
+ break
+ }
+
+ offset += size
+ remaining = remaining[size:]
+ }
+
+ default:
+ wt = otherWord
+ remaining = remaining[size:]
+
+ for len(remaining) > 0 {
+ r, size = nextValidRune(remaining, r)
+
+ if size == 0 || isConnector(r) || isAlphabet(r) || unicode.IsNumber(r) || unicode.IsPunct(r) {
+ break
+ }
+
+ offset += size
+ remaining = remaining[size:]
+ }
+ }
+
+ word = str[:offset]
+ return
+}
+
+func nextValidRune(str string, prev rune) (r rune, size int) {
+ var sz int
+
+ for len(str) > 0 {
+ r, sz = utf8.DecodeRuneInString(str)
+ size += sz
+
+ if r != utf8.RuneError {
+ return
+ }
+
+ str = str[sz:]
+ }
+
+ r = prev
+ return
+}
+
+func toLower(buf *stringBuilder, wt wordType, str string, connector rune) {
+ buf.Grow(buf.Len() + len(str))
+
+ if wt != upperCaseWord && wt != connectorWord {
+ buf.WriteString(str)
+ return
+ }
+
+ for len(str) > 0 {
+ r, size := utf8.DecodeRuneInString(str)
+ str = str[size:]
+
+ if isConnector(r) {
+ buf.WriteRune(connector)
+ } else if unicode.IsUpper(r) {
+ buf.WriteRune(unicode.ToLower(r))
+ } else {
+ buf.WriteRune(r)
+ }
+ }
+}
+
+// SwapCase will swap characters case from upper to lower or lower to upper.
+func SwapCase(str string) string {
+ var r rune
+ var size int
+
+ buf := &stringBuilder{}
+
+ for len(str) > 0 {
+ r, size = utf8.DecodeRuneInString(str)
+
+ switch {
+ case unicode.IsUpper(r):
+ buf.WriteRune(unicode.ToLower(r))
+
+ case unicode.IsLower(r):
+ buf.WriteRune(unicode.ToUpper(r))
+
+ default:
+ buf.WriteRune(r)
+ }
+
+ str = str[size:]
+ }
+
+ return buf.String()
+}
+
+// FirstRuneToUpper converts first rune to upper case if necessary.
+func FirstRuneToUpper(str string) string {
+ if str == "" {
+ return str
+ }
+
+ r, size := utf8.DecodeRuneInString(str)
+
+ if !unicode.IsLower(r) {
+ return str
+ }
+
+ buf := &stringBuilder{}
+ buf.WriteRune(unicode.ToUpper(r))
+ buf.WriteString(str[size:])
+ return buf.String()
+}
+
+// FirstRuneToLower converts first rune to lower case if necessary.
+func FirstRuneToLower(str string) string {
+ if str == "" {
+ return str
+ }
+
+ r, size := utf8.DecodeRuneInString(str)
+
+ if !unicode.IsUpper(r) {
+ return str
+ }
+
+ buf := &stringBuilder{}
+ buf.WriteRune(unicode.ToLower(r))
+ buf.WriteString(str[size:])
+ return buf.String()
+}
+
+// Shuffle randomizes runes in a string and returns the result.
+// It uses default random source in `math/rand`.
+func Shuffle(str string) string {
+ if str == "" {
+ return str
+ }
+
+ runes := []rune(str)
+ index := 0
+
+ for i := len(runes) - 1; i > 0; i-- {
+ index = rand.Intn(i + 1)
+
+ if i != index {
+ runes[i], runes[index] = runes[index], runes[i]
+ }
+ }
+
+ return string(runes)
+}
+
+// ShuffleSource randomizes runes in a string with given random source.
+func ShuffleSource(str string, src rand.Source) string {
+ if str == "" {
+ return str
+ }
+
+ runes := []rune(str)
+ index := 0
+ r := rand.New(src)
+
+ for i := len(runes) - 1; i > 0; i-- {
+ index = r.Intn(i + 1)
+
+ if i != index {
+ runes[i], runes[index] = runes[index], runes[i]
+ }
+ }
+
+ return string(runes)
+}
+
+// Successor returns the successor to string.
+//
+// If there is one alphanumeric rune is found in string, increase the rune by 1.
+// If increment generates a "carry", the rune to the left of it is incremented.
+// This process repeats until there is no carry, adding an additional rune if necessary.
+//
+// If there is no alphanumeric rune, the rightmost rune will be increased by 1
+// regardless whether the result is a valid rune or not.
+//
+// Only following characters are alphanumeric.
+// - a - z
+// - A - Z
+// - 0 - 9
+//
+// Samples (borrowed from ruby's String#succ document):
+//
+// "abcd" => "abce"
+// "THX1138" => "THX1139"
+// "<>" => "<>"
+// "1999zzz" => "2000aaa"
+// "ZZZ9999" => "AAAA0000"
+// "***" => "**+"
+func Successor(str string) string {
+ if str == "" {
+ return str
+ }
+
+ var r rune
+ var i int
+ carry := ' '
+ runes := []rune(str)
+ l := len(runes)
+ lastAlphanumeric := l
+
+ for i = l - 1; i >= 0; i-- {
+ r = runes[i]
+
+ if ('a' <= r && r <= 'y') ||
+ ('A' <= r && r <= 'Y') ||
+ ('0' <= r && r <= '8') {
+ runes[i]++
+ carry = ' '
+ lastAlphanumeric = i
+ break
+ }
+
+ switch r {
+ case 'z':
+ runes[i] = 'a'
+ carry = 'a'
+ lastAlphanumeric = i
+
+ case 'Z':
+ runes[i] = 'A'
+ carry = 'A'
+ lastAlphanumeric = i
+
+ case '9':
+ runes[i] = '0'
+ carry = '0'
+ lastAlphanumeric = i
+ }
+ }
+
+ // Needs to add one character for carry.
+ if i < 0 && carry != ' ' {
+ buf := &stringBuilder{}
+ buf.Grow(l + 4) // Reserve enough space for write.
+
+ if lastAlphanumeric != 0 {
+ buf.WriteString(str[:lastAlphanumeric])
+ }
+
+ buf.WriteRune(carry)
+
+ for _, r = range runes[lastAlphanumeric:] {
+ buf.WriteRune(r)
+ }
+
+ return buf.String()
+ }
+
+ // No alphanumeric character. Simply increase last rune's value.
+ if lastAlphanumeric == l {
+ runes[l-1]++
+ }
+
+ return string(runes)
+}
diff --git a/vendor/github.com/huandu/xstrings/count.go b/vendor/github.com/huandu/xstrings/count.go
new file mode 100644
index 0000000000..f96e38703a
--- /dev/null
+++ b/vendor/github.com/huandu/xstrings/count.go
@@ -0,0 +1,120 @@
+// Copyright 2015 Huan Du. All rights reserved.
+// Licensed under the MIT license that can be found in the LICENSE file.
+
+package xstrings
+
+import (
+ "unicode"
+ "unicode/utf8"
+)
+
+// Len returns str's utf8 rune length.
+func Len(str string) int {
+ return utf8.RuneCountInString(str)
+}
+
+// WordCount returns number of words in a string.
+//
+// Word is defined as a locale dependent string containing alphabetic characters,
+// which may also contain but not start with `'` and `-` characters.
+func WordCount(str string) int {
+ var r rune
+ var size, n int
+
+ inWord := false
+
+ for len(str) > 0 {
+ r, size = utf8.DecodeRuneInString(str)
+
+ switch {
+ case isAlphabet(r):
+ if !inWord {
+ inWord = true
+ n++
+ }
+
+ case inWord && (r == '\'' || r == '-'):
+ // Still in word.
+
+ default:
+ inWord = false
+ }
+
+ str = str[size:]
+ }
+
+ return n
+}
+
+const minCJKCharacter = '\u3400'
+
+// Checks r is a letter but not CJK character.
+func isAlphabet(r rune) bool {
+ if !unicode.IsLetter(r) {
+ return false
+ }
+
+ switch {
+ // Quick check for non-CJK character.
+ case r < minCJKCharacter:
+ return true
+
+ // Common CJK characters.
+ case r >= '\u4E00' && r <= '\u9FCC':
+ return false
+
+ // Rare CJK characters.
+ case r >= '\u3400' && r <= '\u4D85':
+ return false
+
+ // Rare and historic CJK characters.
+ case r >= '\U00020000' && r <= '\U0002B81D':
+ return false
+ }
+
+ return true
+}
+
+// Width returns string width in monotype font.
+// Multi-byte characters are usually twice the width of single byte characters.
+//
+// Algorithm comes from `mb_strwidth` in PHP.
+// http://php.net/manual/en/function.mb-strwidth.php
+func Width(str string) int {
+ var r rune
+ var size, n int
+
+ for len(str) > 0 {
+ r, size = utf8.DecodeRuneInString(str)
+ n += RuneWidth(r)
+ str = str[size:]
+ }
+
+ return n
+}
+
+// RuneWidth returns character width in monotype font.
+// Multi-byte characters are usually twice the width of single byte characters.
+//
+// Algorithm comes from `mb_strwidth` in PHP.
+// http://php.net/manual/en/function.mb-strwidth.php
+func RuneWidth(r rune) int {
+ switch {
+ case r == utf8.RuneError || r < '\x20':
+ return 0
+
+ case '\x20' <= r && r < '\u2000':
+ return 1
+
+ case '\u2000' <= r && r < '\uFF61':
+ return 2
+
+ case '\uFF61' <= r && r < '\uFFA0':
+ return 1
+
+ case '\uFFA0' <= r:
+ return 2
+ }
+
+ return 0
+}
diff --git a/vendor/github.com/huandu/xstrings/doc.go b/vendor/github.com/huandu/xstrings/doc.go
new file mode 100644
index 0000000000..1a6ef069f6
--- /dev/null
+++ b/vendor/github.com/huandu/xstrings/doc.go
@@ -0,0 +1,8 @@
+// Copyright 2015 Huan Du. All rights reserved.
+// Licensed under the MIT license that can be found in the LICENSE file.
+
+// Package xstrings is to provide string algorithms which are useful but not included in `strings` package.
+// See project home page for details. https://github.com/huandu/xstrings
+//
+// Package xstrings assumes all strings are encoded in utf8.
+package xstrings
diff --git a/vendor/github.com/huandu/xstrings/format.go b/vendor/github.com/huandu/xstrings/format.go
new file mode 100644
index 0000000000..b32219bbd5
--- /dev/null
+++ b/vendor/github.com/huandu/xstrings/format.go
@@ -0,0 +1,173 @@
+// Copyright 2015 Huan Du. All rights reserved.
+// Licensed under the MIT license that can be found in the LICENSE file.
+
+package xstrings
+
+import (
+ "unicode/utf8"
+)
+
+// ExpandTabs can expand tabs ('\t') rune in str to one or more spaces dpending on
+// current column and tabSize.
+// The column number is reset to zero after each newline ('\n') occurring in the str.
+//
+// ExpandTabs uses RuneWidth to decide rune's width.
+// For example, CJK characters will be treated as two characters.
+//
+// If tabSize <= 0, ExpandTabs panics with error.
+//
+// Samples:
+//
+// ExpandTabs("a\tbc\tdef\tghij\tk", 4) => "a bc def ghij k"
+// ExpandTabs("abcdefg\thij\nk\tl", 4) => "abcdefg hij\nk l"
+// ExpandTabs("zä¸\tæ–‡\tw", 4) => "zä¸ æ–‡ w"
+func ExpandTabs(str string, tabSize int) string {
+ if tabSize <= 0 {
+ panic("tab size must be positive")
+ }
+
+ var r rune
+ var i, size, column, expand int
+ var output *stringBuilder
+
+ orig := str
+
+ for len(str) > 0 {
+ r, size = utf8.DecodeRuneInString(str)
+
+ if r == '\t' {
+ expand = tabSize - column%tabSize
+
+ if output == nil {
+ output = allocBuffer(orig, str)
+ }
+
+ for i = 0; i < expand; i++ {
+ output.WriteRune(' ')
+ }
+
+ column += expand
+ } else {
+ if r == '\n' {
+ column = 0
+ } else {
+ column += RuneWidth(r)
+ }
+
+ if output != nil {
+ output.WriteRune(r)
+ }
+ }
+
+ str = str[size:]
+ }
+
+ if output == nil {
+ return orig
+ }
+
+ return output.String()
+}
+
+// LeftJustify returns a string with pad string at right side if str's rune length is smaller than length.
+// If str's rune length is larger than length, str itself will be returned.
+//
+// If pad is an empty string, str will be returned.
+//
+// Samples:
+//
+// LeftJustify("hello", 4, " ") => "hello"
+// LeftJustify("hello", 10, " ") => "hello "
+// LeftJustify("hello", 10, "123") => "hello12312"
+func LeftJustify(str string, length int, pad string) string {
+ l := Len(str)
+
+ if l >= length || pad == "" {
+ return str
+ }
+
+ remains := length - l
+ padLen := Len(pad)
+
+ output := &stringBuilder{}
+ output.Grow(len(str) + (remains/padLen+1)*len(pad))
+ output.WriteString(str)
+ writePadString(output, pad, padLen, remains)
+ return output.String()
+}
+
+// RightJustify returns a string with pad string at left side if str's rune length is smaller than length.
+// If str's rune length is larger than length, str itself will be returned.
+//
+// If pad is an empty string, str will be returned.
+//
+// Samples:
+//
+// RightJustify("hello", 4, " ") => "hello"
+// RightJustify("hello", 10, " ") => " hello"
+// RightJustify("hello", 10, "123") => "12312hello"
+func RightJustify(str string, length int, pad string) string {
+ l := Len(str)
+
+ if l >= length || pad == "" {
+ return str
+ }
+
+ remains := length - l
+ padLen := Len(pad)
+
+ output := &stringBuilder{}
+ output.Grow(len(str) + (remains/padLen+1)*len(pad))
+ writePadString(output, pad, padLen, remains)
+ output.WriteString(str)
+ return output.String()
+}
+
+// Center returns a string with pad string at both side if str's rune length is smaller than length.
+// If str's rune length is larger than length, str itself will be returned.
+//
+// If pad is an empty string, str will be returned.
+//
+// Samples:
+//
+// Center("hello", 4, " ") => "hello"
+// Center("hello", 10, " ") => " hello "
+// Center("hello", 10, "123") => "12hello123"
+func Center(str string, length int, pad string) string {
+ l := Len(str)
+
+ if l >= length || pad == "" {
+ return str
+ }
+
+ remains := length - l
+ padLen := Len(pad)
+
+ output := &stringBuilder{}
+ output.Grow(len(str) + (remains/padLen+1)*len(pad))
+ writePadString(output, pad, padLen, remains/2)
+ output.WriteString(str)
+ writePadString(output, pad, padLen, (remains+1)/2)
+ return output.String()
+}
+
+func writePadString(output *stringBuilder, pad string, padLen, remains int) {
+ var r rune
+ var size int
+
+ repeats := remains / padLen
+
+ for i := 0; i < repeats; i++ {
+ output.WriteString(pad)
+ }
+
+ remains = remains % padLen
+
+ if remains != 0 {
+ for i := 0; i < remains; i++ {
+ r, size = utf8.DecodeRuneInString(pad)
+ output.WriteRune(r)
+ pad = pad[size:]
+ }
+ }
+}
diff --git a/vendor/github.com/huandu/xstrings/manipulate.go b/vendor/github.com/huandu/xstrings/manipulate.go
new file mode 100644
index 0000000000..ab42fe0fec
--- /dev/null
+++ b/vendor/github.com/huandu/xstrings/manipulate.go
@@ -0,0 +1,220 @@
+// Copyright 2015 Huan Du. All rights reserved.
+// Licensed under the MIT license that can be found in the LICENSE file.
+
+package xstrings
+
+import (
+ "strings"
+ "unicode/utf8"
+)
+
+// Reverse a utf8 encoded string.
+func Reverse(str string) string {
+ var size int
+
+ tail := len(str)
+ buf := make([]byte, tail)
+ s := buf
+
+ for len(str) > 0 {
+ _, size = utf8.DecodeRuneInString(str)
+ tail -= size
+ s = append(s[:tail], []byte(str[:size])...)
+ str = str[size:]
+ }
+
+ return string(buf)
+}
+
+// Slice a string by rune.
+//
+// Start must satisfy 0 <= start <= rune length.
+//
+// End can be positive, zero or negative.
+// If end >= 0, start and end must satisfy start <= end <= rune length.
+// If end < 0, it means slice to the end of string.
+//
+// Otherwise, Slice will panic as out of range.
+func Slice(str string, start, end int) string {
+ var size, startPos, endPos int
+
+ origin := str
+
+ if start < 0 || end > len(str) || (end >= 0 && start > end) {
+ panic("out of range")
+ }
+
+ if end >= 0 {
+ end -= start
+ }
+
+ for start > 0 && len(str) > 0 {
+ _, size = utf8.DecodeRuneInString(str)
+ start--
+ startPos += size
+ str = str[size:]
+ }
+
+ if end < 0 {
+ return origin[startPos:]
+ }
+
+ endPos = startPos
+
+ for end > 0 && len(str) > 0 {
+ _, size = utf8.DecodeRuneInString(str)
+ end--
+ endPos += size
+ str = str[size:]
+ }
+
+ if len(str) == 0 && (start > 0 || end > 0) {
+ panic("out of range")
+ }
+
+ return origin[startPos:endPos]
+}
+
+// Partition splits a string by sep into three parts.
+// The return value is a slice of strings with head, match and tail.
+//
+// If str contains sep, for example "hello" and "l", Partition returns
+//
+// "he", "l", "lo"
+//
+// If str doesn't contain sep, for example "hello" and "x", Partition returns
+//
+// "hello", "", ""
+func Partition(str, sep string) (head, match, tail string) {
+ index := strings.Index(str, sep)
+
+ if index == -1 {
+ head = str
+ return
+ }
+
+ head = str[:index]
+ match = str[index : index+len(sep)]
+ tail = str[index+len(sep):]
+ return
+}
+
+// LastPartition splits a string by last instance of sep into three parts.
+// The return value is a slice of strings with head, match and tail.
+//
+// If str contains sep, for example "hello" and "l", LastPartition returns
+//
+// "hel", "l", "o"
+//
+// If str doesn't contain sep, for example "hello" and "x", LastPartition returns
+//
+// "", "", "hello"
+func LastPartition(str, sep string) (head, match, tail string) {
+ index := strings.LastIndex(str, sep)
+
+ if index == -1 {
+ tail = str
+ return
+ }
+
+ head = str[:index]
+ match = str[index : index+len(sep)]
+ tail = str[index+len(sep):]
+ return
+}
+
+// Insert src into dst at given rune index.
+// Index is counted by runes instead of bytes.
+//
+// If index is out of range of dst, panic with out of range.
+func Insert(dst, src string, index int) string {
+ return Slice(dst, 0, index) + src + Slice(dst, index, -1)
+}
+
+// Scrub scrubs invalid utf8 bytes with repl string.
+// Adjacent invalid bytes are replaced only once.
+func Scrub(str, repl string) string {
+ var buf *stringBuilder
+ var r rune
+ var size, pos int
+ var hasError bool
+
+ origin := str
+
+ for len(str) > 0 {
+ r, size = utf8.DecodeRuneInString(str)
+
+ if r == utf8.RuneError {
+ if !hasError {
+ if buf == nil {
+ buf = &stringBuilder{}
+ }
+
+ buf.WriteString(origin[:pos])
+ hasError = true
+ }
+ } else if hasError {
+ hasError = false
+ buf.WriteString(repl)
+
+ origin = origin[pos:]
+ pos = 0
+ }
+
+ pos += size
+ str = str[size:]
+ }
+
+ if buf != nil {
+ buf.WriteString(origin)
+ return buf.String()
+ }
+
+ // No invalid byte.
+ return origin
+}
+
+// WordSplit splits a string into words. Returns a slice of words.
+// If there is no word in a string, return nil.
+//
+// Word is defined as a locale dependent string containing alphabetic characters,
+// which may also contain but not start with `'` and `-` characters.
+func WordSplit(str string) []string {
+ var word string
+ var words []string
+ var r rune
+ var size, pos int
+
+ inWord := false
+
+ for len(str) > 0 {
+ r, size = utf8.DecodeRuneInString(str)
+
+ switch {
+ case isAlphabet(r):
+ if !inWord {
+ inWord = true
+ word = str
+ pos = 0
+ }
+
+ case inWord && (r == '\'' || r == '-'):
+ // Still in word.
+
+ default:
+ if inWord {
+ inWord = false
+ words = append(words, word[:pos])
+ }
+ }
+
+ pos += size
+ str = str[size:]
+ }
+
+ if inWord {
+ words = append(words, word[:pos])
+ }
+
+ return words
+}
diff --git a/vendor/github.com/huandu/xstrings/stringbuilder.go b/vendor/github.com/huandu/xstrings/stringbuilder.go
new file mode 100644
index 0000000000..06812fea07
--- /dev/null
+++ b/vendor/github.com/huandu/xstrings/stringbuilder.go
@@ -0,0 +1,8 @@
+//go:build go1.10
+// +build go1.10
+
+package xstrings
+
+import "strings"
+
+type stringBuilder = strings.Builder
diff --git a/vendor/github.com/huandu/xstrings/stringbuilder_go110.go b/vendor/github.com/huandu/xstrings/stringbuilder_go110.go
new file mode 100644
index 0000000000..ccaa5aedd3
--- /dev/null
+++ b/vendor/github.com/huandu/xstrings/stringbuilder_go110.go
@@ -0,0 +1,10 @@
+//go:build !go1.10
+// +build !go1.10
+
+package xstrings
+
+import "bytes"
+
+type stringBuilder struct {
+ bytes.Buffer
+}
diff --git a/vendor/github.com/huandu/xstrings/translate.go b/vendor/github.com/huandu/xstrings/translate.go
new file mode 100644
index 0000000000..1fac6a00be
--- /dev/null
+++ b/vendor/github.com/huandu/xstrings/translate.go
@@ -0,0 +1,552 @@
+// Copyright 2015 Huan Du. All rights reserved.
+// Licensed under the MIT license that can be found in the LICENSE file.
+
+package xstrings
+
+import (
+ "unicode"
+ "unicode/utf8"
+)
+
+type runeRangeMap struct {
+ FromLo rune // Lower bound of range map.
+ FromHi rune // An inclusive higher bound of range map.
+ ToLo rune
+ ToHi rune
+}
+
+type runeDict struct {
+ Dict [unicode.MaxASCII + 1]rune
+}
+
+type runeMap map[rune]rune
+
+// Translator can translate string with pre-compiled from and to patterns.
+// If a from/to pattern pair needs to be used more than once, it's recommended
+// to create a Translator and reuse it.
+type Translator struct {
+ quickDict *runeDict // A quick dictionary to look up rune by index. Only available for latin runes.
+ runeMap runeMap // Rune map for translation.
+ ranges []*runeRangeMap // Ranges of runes.
+ mappedRune rune // If mappedRune >= 0, all matched runes are translated to the mappedRune.
+ reverted bool // If to pattern is empty, all matched characters will be deleted.
+ hasPattern bool
+}
+
+// NewTranslator creates new Translator through a from/to pattern pair.
+func NewTranslator(from, to string) *Translator {
+ tr := &Translator{}
+
+ if from == "" {
+ return tr
+ }
+
+ reverted := from[0] == '^'
+ deletion := len(to) == 0
+
+ if reverted {
+ from = from[1:]
+ }
+
+ var fromStart, fromEnd, fromRangeStep rune
+ var toStart, toEnd, toRangeStep rune
+ var fromRangeSize, toRangeSize rune
+ var singleRunes []rune
+
+ // Update the to rune range.
+ updateRange := func() {
+ // No more rune to read in the to rune pattern.
+ if toEnd == utf8.RuneError {
+ return
+ }
+
+ if toRangeStep == 0 {
+ to, toStart, toEnd, toRangeStep = nextRuneRange(to, toEnd)
+ return
+ }
+
+ // Current range is not empty. Consume 1 rune from start.
+ if toStart != toEnd {
+ toStart += toRangeStep
+ return
+ }
+
+ // No more rune. Repeat the last rune.
+ if to == "" {
+ toEnd = utf8.RuneError
+ return
+ }
+
+ // Both start and end are used. Read two more runes from the to pattern.
+ to, toStart, toEnd, toRangeStep = nextRuneRange(to, utf8.RuneError)
+ }
+
+ if deletion {
+ toStart = utf8.RuneError
+ toEnd = utf8.RuneError
+ } else {
+ // If from pattern is reverted, only the last rune in the to pattern will be used.
+ if reverted {
+ var size int
+
+ for len(to) > 0 {
+ toStart, size = utf8.DecodeRuneInString(to)
+ to = to[size:]
+ }
+
+ toEnd = utf8.RuneError
+ } else {
+ to, toStart, toEnd, toRangeStep = nextRuneRange(to, utf8.RuneError)
+ }
+ }
+
+ fromEnd = utf8.RuneError
+
+ for len(from) > 0 {
+ from, fromStart, fromEnd, fromRangeStep = nextRuneRange(from, fromEnd)
+
+ // fromStart is a single character. Just map it with a rune in the to pattern.
+ if fromRangeStep == 0 {
+ singleRunes = tr.addRune(fromStart, toStart, singleRunes)
+ updateRange()
+ continue
+ }
+
+ for toEnd != utf8.RuneError && fromStart != fromEnd {
+ // If mapped rune is a single character instead of a range, simply shift first
+ // rune in the range.
+ if toRangeStep == 0 {
+ singleRunes = tr.addRune(fromStart, toStart, singleRunes)
+ updateRange()
+ fromStart += fromRangeStep
+ continue
+ }
+
+ fromRangeSize = (fromEnd - fromStart) * fromRangeStep
+ toRangeSize = (toEnd - toStart) * toRangeStep
+
+ // Not enough runes in the to pattern. Need to read more.
+ if fromRangeSize > toRangeSize {
+ fromStart, toStart = tr.addRuneRange(fromStart, fromStart+toRangeSize*fromRangeStep, toStart, toEnd, singleRunes)
+ fromStart += fromRangeStep
+ updateRange()
+
+ // Edge case: If fromRangeSize == toRangeSize + 1, the last fromStart value needs be considered
+ // as a single rune.
+ if fromStart == fromEnd {
+ singleRunes = tr.addRune(fromStart, toStart, singleRunes)
+ updateRange()
+ }
+
+ continue
+ }
+
+ fromStart, toStart = tr.addRuneRange(fromStart, fromEnd, toStart, toStart+fromRangeSize*toRangeStep, singleRunes)
+ updateRange()
+ break
+ }
+
+ if fromStart == fromEnd {
+ fromEnd = utf8.RuneError
+ continue
+ }
+
+ _, toStart = tr.addRuneRange(fromStart, fromEnd, toStart, toStart, singleRunes)
+ fromEnd = utf8.RuneError
+ }
+
+ if fromEnd != utf8.RuneError {
+ tr.addRune(fromEnd, toStart, singleRunes)
+ }
+
+ tr.reverted = reverted
+ tr.mappedRune = -1
+ tr.hasPattern = true
+
+ // Translate RuneError only if in deletion or reverted mode.
+ if deletion || reverted {
+ tr.mappedRune = toStart
+ }
+
+ return tr
+}
+
+func (tr *Translator) addRune(from, to rune, singleRunes []rune) []rune {
+ if from <= unicode.MaxASCII {
+ if tr.quickDict == nil {
+ tr.quickDict = &runeDict{}
+ }
+
+ tr.quickDict.Dict[from] = to
+ } else {
+ if tr.runeMap == nil {
+ tr.runeMap = make(runeMap)
+ }
+
+ tr.runeMap[from] = to
+ }
+
+ singleRunes = append(singleRunes, from)
+ return singleRunes
+}
+
+func (tr *Translator) addRuneRange(fromLo, fromHi, toLo, toHi rune, singleRunes []rune) (rune, rune) {
+ var r rune
+ var rrm *runeRangeMap
+
+ if fromLo < fromHi {
+ rrm = &runeRangeMap{
+ FromLo: fromLo,
+ FromHi: fromHi,
+ ToLo: toLo,
+ ToHi: toHi,
+ }
+ } else {
+ rrm = &runeRangeMap{
+ FromLo: fromHi,
+ FromHi: fromLo,
+ ToLo: toHi,
+ ToHi: toLo,
+ }
+ }
+
+ // If there is any single rune conflicts with this rune range, clear single rune record.
+ for _, r = range singleRunes {
+ if rrm.FromLo <= r && r <= rrm.FromHi {
+ if r <= unicode.MaxASCII {
+ tr.quickDict.Dict[r] = 0
+ } else {
+ delete(tr.runeMap, r)
+ }
+ }
+ }
+
+ tr.ranges = append(tr.ranges, rrm)
+ return fromHi, toHi
+}
+
+func nextRuneRange(str string, last rune) (remaining string, start, end rune, rangeStep rune) {
+ var r rune
+ var size int
+
+ remaining = str
+ escaping := false
+ isRange := false
+
+ for len(remaining) > 0 {
+ r, size = utf8.DecodeRuneInString(remaining)
+ remaining = remaining[size:]
+
+ // Parse special characters.
+ if !escaping {
+ if r == '\\' {
+ escaping = true
+ continue
+ }
+
+ if r == '-' {
+ // Ignore slash at beginning of string.
+ if last == utf8.RuneError {
+ continue
+ }
+
+ start = last
+ isRange = true
+ continue
+ }
+ }
+
+ escaping = false
+
+ if last != utf8.RuneError {
+ // This is a range which start and end are the same.
+ // Considier it as a normal character.
+ if isRange && last == r {
+ isRange = false
+ continue
+ }
+
+ start = last
+ end = r
+
+ if isRange {
+ if start < end {
+ rangeStep = 1
+ } else {
+ rangeStep = -1
+ }
+ }
+
+ return
+ }
+
+ last = r
+ }
+
+ start = last
+ end = utf8.RuneError
+ return
+}
+
+// Translate str with a from/to pattern pair.
+//
+// See comment in Translate function for usage and samples.
+func (tr *Translator) Translate(str string) string {
+ if !tr.hasPattern || str == "" {
+ return str
+ }
+
+ var r rune
+ var size int
+ var needTr bool
+
+ orig := str
+
+ var output *stringBuilder
+
+ for len(str) > 0 {
+ r, size = utf8.DecodeRuneInString(str)
+ r, needTr = tr.TranslateRune(r)
+
+ if needTr && output == nil {
+ output = allocBuffer(orig, str)
+ }
+
+ if r != utf8.RuneError && output != nil {
+ output.WriteRune(r)
+ }
+
+ str = str[size:]
+ }
+
+ // No character is translated.
+ if output == nil {
+ return orig
+ }
+
+ return output.String()
+}
+
+// TranslateRune return translated rune and true if r matches the from pattern.
+// If r doesn't match the pattern, original r is returned and translated is false.
+func (tr *Translator) TranslateRune(r rune) (result rune, translated bool) {
+ switch {
+ case tr.quickDict != nil:
+ if r <= unicode.MaxASCII {
+ result = tr.quickDict.Dict[r]
+
+ if result != 0 {
+ translated = true
+
+ if tr.mappedRune >= 0 {
+ result = tr.mappedRune
+ }
+
+ break
+ }
+ }
+
+ fallthrough
+
+ case tr.runeMap != nil:
+ var ok bool
+
+ if result, ok = tr.runeMap[r]; ok {
+ translated = true
+
+ if tr.mappedRune >= 0 {
+ result = tr.mappedRune
+ }
+
+ break
+ }
+
+ fallthrough
+
+ default:
+ var rrm *runeRangeMap
+ ranges := tr.ranges
+
+ for i := len(ranges) - 1; i >= 0; i-- {
+ rrm = ranges[i]
+
+ if rrm.FromLo <= r && r <= rrm.FromHi {
+ translated = true
+
+ if tr.mappedRune >= 0 {
+ result = tr.mappedRune
+ break
+ }
+
+ if rrm.ToLo < rrm.ToHi {
+ result = rrm.ToLo + r - rrm.FromLo
+ } else if rrm.ToLo > rrm.ToHi {
+ // ToHi can be smaller than ToLo if range is from higher to lower.
+ result = rrm.ToLo - r + rrm.FromLo
+ } else {
+ result = rrm.ToLo
+ }
+
+ break
+ }
+ }
+ }
+
+ if tr.reverted {
+ if !translated {
+ result = tr.mappedRune
+ }
+
+ translated = !translated
+ }
+
+ if !translated {
+ result = r
+ }
+
+ return
+}
+
+// HasPattern returns true if Translator has one pattern at least.
+func (tr *Translator) HasPattern() bool {
+ return tr.hasPattern
+}
+
+// Translate str with the characters defined in from replaced by characters defined in to.
+//
+// From and to are patterns representing a set of characters. Pattern is defined as following.
+//
+// Special characters:
+//
+// 1. '-' means a range of runes, e.g.
+// "a-z" means all characters from 'a' to 'z' inclusive;
+// "z-a" means all characters from 'z' to 'a' inclusive.
+// 2. '^' as first character means a set of all runes excepted listed, e.g.
+// "^a-z" means all characters except 'a' to 'z' inclusive.
+// 3. '\' escapes special characters.
+//
+// Normal character represents itself, e.g. "abc" is a set including 'a', 'b' and 'c'.
+//
+// Translate will try to find a 1:1 mapping from from to to.
+// If to is smaller than from, last rune in to will be used to map "out of range" characters in from.
+//
+// Note that '^' only works in the from pattern. It will be considered as a normal character in the to pattern.
+//
+// If the to pattern is an empty string, Translate works exactly the same as Delete.
+//
+// Samples:
+//
+// Translate("hello", "aeiou", "12345") => "h2ll4"
+// Translate("hello", "a-z", "A-Z") => "HELLO"
+// Translate("hello", "z-a", "a-z") => "svool"
+// Translate("hello", "aeiou", "*") => "h*ll*"
+// Translate("hello", "^l", "*") => "**ll*"
+// Translate("hello ^ world", `\^lo`, "*") => "he*** * w*r*d"
+func Translate(str, from, to string) string {
+ tr := NewTranslator(from, to)
+ return tr.Translate(str)
+}
+
+// Delete runes in str matching the pattern.
+// Pattern is defined in Translate function.
+//
+// Samples:
+//
+// Delete("hello", "aeiou") => "hll"
+// Delete("hello", "a-k") => "llo"
+// Delete("hello", "^a-k") => "he"
+func Delete(str, pattern string) string {
+ tr := NewTranslator(pattern, "")
+ return tr.Translate(str)
+}
+
+// Count how many runes in str match the pattern.
+// Pattern is defined in Translate function.
+//
+// Samples:
+//
+// Count("hello", "aeiou") => 3
+// Count("hello", "a-k") => 3
+// Count("hello", "^a-k") => 2
+func Count(str, pattern string) int {
+ if pattern == "" || str == "" {
+ return 0
+ }
+
+ var r rune
+ var size int
+ var matched bool
+
+ tr := NewTranslator(pattern, "")
+ cnt := 0
+
+ for len(str) > 0 {
+ r, size = utf8.DecodeRuneInString(str)
+ str = str[size:]
+
+ if _, matched = tr.TranslateRune(r); matched {
+ cnt++
+ }
+ }
+
+ return cnt
+}
+
+// Squeeze deletes adjacent repeated runes in str.
+// If pattern is not empty, only runes matching the pattern will be squeezed.
+//
+// Samples:
+//
+// Squeeze("hello", "") => "helo"
+// Squeeze("hello", "m-z") => "hello"
+// Squeeze("hello world", " ") => "hello world"
+func Squeeze(str, pattern string) string {
+ var last, r rune
+ var size int
+ var skipSqueeze, matched bool
+ var tr *Translator
+ var output *stringBuilder
+
+ orig := str
+ last = -1
+
+ if len(pattern) > 0 {
+ tr = NewTranslator(pattern, "")
+ }
+
+ for len(str) > 0 {
+ r, size = utf8.DecodeRuneInString(str)
+
+ // Need to squeeze the str.
+ if last == r && !skipSqueeze {
+ if tr != nil {
+ if _, matched = tr.TranslateRune(r); !matched {
+ skipSqueeze = true
+ }
+ }
+
+ if output == nil {
+ output = allocBuffer(orig, str)
+ }
+
+ if skipSqueeze {
+ output.WriteRune(r)
+ }
+ } else {
+ if output != nil {
+ output.WriteRune(r)
+ }
+
+ last = r
+ skipSqueeze = false
+ }
+
+ str = str[size:]
+ }
+
+ if output == nil {
+ return orig
+ }
+
+ return output.String()
+}
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/api/v1/istio_types.go b/vendor/github.com/istio-ecosystem/sail-operator/api/v1/istio_types.go
index 9dca59d898..ac39731796 100644
--- a/vendor/github.com/istio-ecosystem/sail-operator/api/v1/istio_types.go
+++ b/vendor/github.com/istio-ecosystem/sail-operator/api/v1/istio_types.go
@@ -37,10 +37,10 @@ const (
type IstioSpec struct {
// +sail:version
// Defines the version of Istio to install.
- // Must be one of: v1.25-latest, v1.25.2, v1.25.1, v1.24-latest, v1.24.5, v1.24.4, v1.24.3, v1.24.2, v1.24.1, v1.24.0, v1.23-latest, v1.23.6, v1.23.5, v1.23.4, v1.23.3, v1.23.2, v1.22-latest, v1.22.8, v1.22.7, v1.22.6, v1.22.5, v1.21.6, master, v1.27-alpha.f23c2f66.
- // +operator-sdk:csv:customresourcedefinitions:type=spec,order=1,displayName="Istio Version",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:fieldGroup:General", "urn:alm:descriptor:com.tectonic.ui:select:v1.25-latest", "urn:alm:descriptor:com.tectonic.ui:select:v1.25.2", "urn:alm:descriptor:com.tectonic.ui:select:v1.25.1", "urn:alm:descriptor:com.tectonic.ui:select:v1.24-latest", "urn:alm:descriptor:com.tectonic.ui:select:v1.24.5", "urn:alm:descriptor:com.tectonic.ui:select:v1.24.4", "urn:alm:descriptor:com.tectonic.ui:select:v1.24.3", "urn:alm:descriptor:com.tectonic.ui:select:v1.24.2", "urn:alm:descriptor:com.tectonic.ui:select:v1.24.1", "urn:alm:descriptor:com.tectonic.ui:select:v1.24.0", "urn:alm:descriptor:com.tectonic.ui:select:v1.23-latest", "urn:alm:descriptor:com.tectonic.ui:select:v1.23.6", "urn:alm:descriptor:com.tectonic.ui:select:v1.23.5", "urn:alm:descriptor:com.tectonic.ui:select:v1.23.4", "urn:alm:descriptor:com.tectonic.ui:select:v1.23.3", "urn:alm:descriptor:com.tectonic.ui:select:v1.23.2", "urn:alm:descriptor:com.tectonic.ui:select:v1.22-latest", "urn:alm:descriptor:com.tectonic.ui:select:v1.22.8", "urn:alm:descriptor:com.tectonic.ui:select:v1.22.7", "urn:alm:descriptor:com.tectonic.ui:select:v1.22.6", "urn:alm:descriptor:com.tectonic.ui:select:v1.22.5", "urn:alm:descriptor:com.tectonic.ui:select:v1.21.6", "urn:alm:descriptor:com.tectonic.ui:select:master", "urn:alm:descriptor:com.tectonic.ui:select:v1.27-alpha.f23c2f66"}
- // +kubebuilder:validation:Enum=v1.25-latest;v1.25.2;v1.25.1;v1.24-latest;v1.24.5;v1.24.4;v1.24.3;v1.24.2;v1.24.1;v1.24.0;v1.23-latest;v1.23.6;v1.23.5;v1.23.4;v1.23.3;v1.23.2;v1.22-latest;v1.22.8;v1.22.7;v1.22.6;v1.22.5;v1.21.6;master;v1.27-alpha.f23c2f66
- // +kubebuilder:default=v1.25.2
+ // Must be one of: v1.28-latest, v1.28.3, v1.28.2, v1.28.1, v1.28.0, v1.27-latest, v1.27.5, v1.27.4, v1.27.3, v1.27.2, v1.27.1, v1.27.0, master, v1.30-alpha.a30ad733.
+ // +operator-sdk:csv:customresourcedefinitions:type=spec,order=1,displayName="Istio Version",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:fieldGroup:General", "urn:alm:descriptor:com.tectonic.ui:select:v1.28-latest", "urn:alm:descriptor:com.tectonic.ui:select:v1.28.3", "urn:alm:descriptor:com.tectonic.ui:select:v1.28.2", "urn:alm:descriptor:com.tectonic.ui:select:v1.28.1", "urn:alm:descriptor:com.tectonic.ui:select:v1.28.0", "urn:alm:descriptor:com.tectonic.ui:select:v1.27-latest", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.5", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.4", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.3", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.2", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.1", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.0", "urn:alm:descriptor:com.tectonic.ui:select:master", "urn:alm:descriptor:com.tectonic.ui:select:v1.30-alpha.a30ad733"}
+ // +kubebuilder:validation:Enum=v1.28-latest;v1.28.3;v1.28.2;v1.28.1;v1.28.0;v1.27-latest;v1.27.5;v1.27.4;v1.27.3;v1.27.2;v1.27.1;v1.27.0;v1.26-latest;v1.26.8;v1.26.7;v1.26.6;v1.26.5;v1.26.4;v1.26.3;v1.26.2;v1.26.1;v1.26.0;v1.25-latest;v1.25.5;v1.25.4;v1.25.3;v1.25.2;v1.25.1;v1.24-latest;v1.24.6;v1.24.5;v1.24.4;v1.24.3;v1.24.2;v1.24.1;v1.24.0;v1.23-latest;v1.23.6;v1.23.5;v1.23.4;v1.23.3;v1.23.2;v1.22-latest;v1.22.8;v1.22.7;v1.22.6;v1.22.5;v1.21.6;master;v1.30-alpha.a30ad733
+ // +kubebuilder:default=v1.28.3
Version string `json:"version"`
// Defines the update strategy to use when the version in the Istio CR is updated.
@@ -51,10 +51,9 @@ type IstioSpec struct {
// +sail:profile
// The built-in installation configuration profile to use.
// The 'default' profile is always applied. On OpenShift, the 'openshift' profile is also applied on top of 'default'.
- // Must be one of: ambient, default, demo, empty, external, openshift-ambient, openshift, preview, remote, stable.
- // +++PROFILES-DROPDOWN-HIDDEN-UNTIL-WE-FULLY-IMPLEMENT-THEM+++operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Profile",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:fieldGroup:General", "urn:alm:descriptor:com.tectonic.ui:select:ambient", "urn:alm:descriptor:com.tectonic.ui:select:default", "urn:alm:descriptor:com.tectonic.ui:select:demo", "urn:alm:descriptor:com.tectonic.ui:select:empty", "urn:alm:descriptor:com.tectonic.ui:select:external", "urn:alm:descriptor:com.tectonic.ui:select:minimal", "urn:alm:descriptor:com.tectonic.ui:select:preview", "urn:alm:descriptor:com.tectonic.ui:select:remote"}
- // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:hidden"}
- // +kubebuilder:validation:Enum=ambient;default;demo;empty;external;openshift-ambient;openshift;preview;remote;stable
+ // Must be one of: ambient, default, demo, empty, openshift, openshift-ambient, preview, remote, stable.
+ // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Profile",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:fieldGroup:General", "urn:alm:descriptor:com.tectonic.ui:select:ambient", "urn:alm:descriptor:com.tectonic.ui:select:default", "urn:alm:descriptor:com.tectonic.ui:select:demo", "urn:alm:descriptor:com.tectonic.ui:select:empty", "urn:alm:descriptor:com.tectonic.ui:select:openshift", "urn:alm:descriptor:com.tectonic.ui:select:openshift-ambient", "urn:alm:descriptor:com.tectonic.ui:select:preview", "urn:alm:descriptor:com.tectonic.ui:select:remote", "urn:alm:descriptor:com.tectonic.ui:select:stable"}
+ // +kubebuilder:validation:Enum=ambient;default;demo;empty;external;openshift;openshift-ambient;preview;remote;stable
Profile string `json:"profile,omitempty"`
// Namespace to which the Istio components should be installed. Note that this field is immutable.
@@ -262,7 +261,7 @@ const (
// +kubebuilder:resource:scope=Cluster,categories=istio-io
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Namespace",type="string",JSONPath=".spec.namespace",description="The namespace for the control plane components."
-// +kubebuilder:printcolumn:name="Profile",type="string",JSONPath=".spec.values.profile",description="The selected profile (collection of value presets)."
+// +kubebuilder:printcolumn:name="Profile",type="string",JSONPath=".spec.profile",description="The selected profile (collection of value presets)."
// +kubebuilder:printcolumn:name="Revisions",type="string",JSONPath=".status.revisions.total",description="Total number of IstioRevision objects currently associated with this object."
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.revisions.ready",description="Number of revisions that are ready."
// +kubebuilder:printcolumn:name="In use",type="string",JSONPath=".status.revisions.inUse",description="Number of revisions that are currently being used by workloads."
@@ -283,7 +282,7 @@ type Istio struct {
// +optional
metav1.ObjectMeta `json:"metadata"`
- // +kubebuilder:default={version: "v1.25.2", namespace: "istio-system", updateStrategy: {type:"InPlace"}}
+ // +kubebuilder:default={version: "v1.28.3", namespace: "istio-system", updateStrategy: {type:"InPlace"}}
// +optional
Spec IstioSpec `json:"spec"`
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/api/v1/istiocni_types.go b/vendor/github.com/istio-ecosystem/sail-operator/api/v1/istiocni_types.go
index 3f743c5974..5abb6eda95 100644
--- a/vendor/github.com/istio-ecosystem/sail-operator/api/v1/istiocni_types.go
+++ b/vendor/github.com/istio-ecosystem/sail-operator/api/v1/istiocni_types.go
@@ -28,19 +28,18 @@ const (
type IstioCNISpec struct {
// +sail:version
// Defines the version of Istio to install.
- // Must be one of: v1.25-latest, v1.25.2, v1.25.1, v1.24-latest, v1.24.5, v1.24.4, v1.24.3, v1.24.2, v1.24.1, v1.24.0, v1.23-latest, v1.23.6, v1.23.5, v1.23.4, v1.23.3, v1.23.2, v1.22-latest, v1.22.8, v1.22.7, v1.22.6, v1.22.5, v1.21.6, master, v1.27-alpha.f23c2f66.
- // +operator-sdk:csv:customresourcedefinitions:type=spec,order=1,displayName="Istio Version",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:fieldGroup:General", "urn:alm:descriptor:com.tectonic.ui:select:v1.25-latest", "urn:alm:descriptor:com.tectonic.ui:select:v1.25.2", "urn:alm:descriptor:com.tectonic.ui:select:v1.25.1", "urn:alm:descriptor:com.tectonic.ui:select:v1.24-latest", "urn:alm:descriptor:com.tectonic.ui:select:v1.24.5", "urn:alm:descriptor:com.tectonic.ui:select:v1.24.4", "urn:alm:descriptor:com.tectonic.ui:select:v1.24.3", "urn:alm:descriptor:com.tectonic.ui:select:v1.24.2", "urn:alm:descriptor:com.tectonic.ui:select:v1.24.1", "urn:alm:descriptor:com.tectonic.ui:select:v1.24.0", "urn:alm:descriptor:com.tectonic.ui:select:v1.23-latest", "urn:alm:descriptor:com.tectonic.ui:select:v1.23.6", "urn:alm:descriptor:com.tectonic.ui:select:v1.23.5", "urn:alm:descriptor:com.tectonic.ui:select:v1.23.4", "urn:alm:descriptor:com.tectonic.ui:select:v1.23.3", "urn:alm:descriptor:com.tectonic.ui:select:v1.23.2", "urn:alm:descriptor:com.tectonic.ui:select:v1.22-latest", "urn:alm:descriptor:com.tectonic.ui:select:v1.22.8", "urn:alm:descriptor:com.tectonic.ui:select:v1.22.7", "urn:alm:descriptor:com.tectonic.ui:select:v1.22.6", "urn:alm:descriptor:com.tectonic.ui:select:v1.22.5", "urn:alm:descriptor:com.tectonic.ui:select:v1.21.6", "urn:alm:descriptor:com.tectonic.ui:select:master", "urn:alm:descriptor:com.tectonic.ui:select:v1.27-alpha.f23c2f66"}
- // +kubebuilder:validation:Enum=v1.25-latest;v1.25.2;v1.25.1;v1.24-latest;v1.24.5;v1.24.4;v1.24.3;v1.24.2;v1.24.1;v1.24.0;v1.23-latest;v1.23.6;v1.23.5;v1.23.4;v1.23.3;v1.23.2;v1.22-latest;v1.22.8;v1.22.7;v1.22.6;v1.22.5;v1.21.6;master;v1.27-alpha.f23c2f66
- // +kubebuilder:default=v1.25.2
+ // Must be one of: v1.28-latest, v1.28.3, v1.28.2, v1.28.1, v1.28.0, v1.27-latest, v1.27.5, v1.27.4, v1.27.3, v1.27.2, v1.27.1, v1.27.0, master, v1.30-alpha.a30ad733.
+ // +operator-sdk:csv:customresourcedefinitions:type=spec,order=1,displayName="Istio Version",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:fieldGroup:General", "urn:alm:descriptor:com.tectonic.ui:select:v1.28-latest", "urn:alm:descriptor:com.tectonic.ui:select:v1.28.3", "urn:alm:descriptor:com.tectonic.ui:select:v1.28.2", "urn:alm:descriptor:com.tectonic.ui:select:v1.28.1", "urn:alm:descriptor:com.tectonic.ui:select:v1.28.0", "urn:alm:descriptor:com.tectonic.ui:select:v1.27-latest", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.5", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.4", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.3", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.2", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.1", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.0", "urn:alm:descriptor:com.tectonic.ui:select:master", "urn:alm:descriptor:com.tectonic.ui:select:v1.30-alpha.a30ad733"}
+ // +kubebuilder:validation:Enum=v1.28-latest;v1.28.3;v1.28.2;v1.28.1;v1.28.0;v1.27-latest;v1.27.5;v1.27.4;v1.27.3;v1.27.2;v1.27.1;v1.27.0;v1.26-latest;v1.26.8;v1.26.7;v1.26.6;v1.26.5;v1.26.4;v1.26.3;v1.26.2;v1.26.1;v1.26.0;v1.25-latest;v1.25.5;v1.25.4;v1.25.3;v1.25.2;v1.25.1;v1.24-latest;v1.24.6;v1.24.5;v1.24.4;v1.24.3;v1.24.2;v1.24.1;v1.24.0;v1.23-latest;v1.23.6;v1.23.5;v1.23.4;v1.23.3;v1.23.2;v1.22-latest;v1.22.8;v1.22.7;v1.22.6;v1.22.5;v1.21.6;master;v1.30-alpha.a30ad733
+ // +kubebuilder:default=v1.28.3
Version string `json:"version"`
// +sail:profile
// The built-in installation configuration profile to use.
// The 'default' profile is always applied. On OpenShift, the 'openshift' profile is also applied on top of 'default'.
- // Must be one of: ambient, default, demo, empty, external, openshift-ambient, openshift, preview, remote, stable.
- // +++PROFILES-DROPDOWN-HIDDEN-UNTIL-WE-FULLY-IMPLEMENT-THEM+++operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Profile",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:fieldGroup:General", "urn:alm:descriptor:com.tectonic.ui:select:ambient", "urn:alm:descriptor:com.tectonic.ui:select:default", "urn:alm:descriptor:com.tectonic.ui:select:demo", "urn:alm:descriptor:com.tectonic.ui:select:empty", "urn:alm:descriptor:com.tectonic.ui:select:external", "urn:alm:descriptor:com.tectonic.ui:select:minimal", "urn:alm:descriptor:com.tectonic.ui:select:preview", "urn:alm:descriptor:com.tectonic.ui:select:remote"}
- // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:hidden"}
- // +kubebuilder:validation:Enum=ambient;default;demo;empty;external;openshift-ambient;openshift;preview;remote;stable
+ // Must be one of: ambient, default, demo, empty, openshift, openshift-ambient, preview, remote, stable.
+ // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Profile",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:fieldGroup:General", "urn:alm:descriptor:com.tectonic.ui:select:ambient", "urn:alm:descriptor:com.tectonic.ui:select:default", "urn:alm:descriptor:com.tectonic.ui:select:demo", "urn:alm:descriptor:com.tectonic.ui:select:empty", "urn:alm:descriptor:com.tectonic.ui:select:openshift", "urn:alm:descriptor:com.tectonic.ui:select:openshift-ambient", "urn:alm:descriptor:com.tectonic.ui:select:preview", "urn:alm:descriptor:com.tectonic.ui:select:remote", "urn:alm:descriptor:com.tectonic.ui:select:stable"}
+ // +kubebuilder:validation:Enum=ambient;default;demo;empty;external;openshift;openshift-ambient;preview;remote;stable
Profile string `json:"profile,omitempty"`
// Namespace to which the Istio CNI component should be installed. Note that this field is immutable.
@@ -169,7 +168,7 @@ const (
// +kubebuilder:resource:scope=Cluster,categories=istio-io
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Namespace",type="string",JSONPath=".spec.namespace",description="The namespace of the istio-cni-node DaemonSet."
-// +kubebuilder:printcolumn:name="Profile",type="string",JSONPath=".spec.values.profile",description="The selected profile (collection of value presets)."
+// +kubebuilder:printcolumn:name="Profile",type="string",JSONPath=".spec.profile",description="The selected profile (collection of value presets)."
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description="Whether the Istio CNI installation is ready to handle requests."
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.state",description="The current state of this object."
// +kubebuilder:printcolumn:name="Version",type="string",JSONPath=".spec.version",description="The version of the Istio CNI installation."
@@ -182,7 +181,7 @@ type IstioCNI struct {
// +optional
metav1.ObjectMeta `json:"metadata"`
- // +kubebuilder:default={version: "v1.25.2", namespace: "istio-cni"}
+ // +kubebuilder:default={version: "v1.28.3", namespace: "istio-cni"}
// +optional
Spec IstioCNISpec `json:"spec"`
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/api/v1/istiorevision_types.go b/vendor/github.com/istio-ecosystem/sail-operator/api/v1/istiorevision_types.go
index 6bd39cea8b..03185e649a 100644
--- a/vendor/github.com/istio-ecosystem/sail-operator/api/v1/istiorevision_types.go
+++ b/vendor/github.com/istio-ecosystem/sail-operator/api/v1/istiorevision_types.go
@@ -30,9 +30,9 @@ const (
type IstioRevisionSpec struct {
// +sail:version
// Defines the version of Istio to install.
- // Must be one of: v1.25.2, v1.25.1, v1.24.5, v1.24.4, v1.24.3, v1.24.2, v1.24.1, v1.24.0, v1.23.6, v1.23.5, v1.23.4, v1.23.3, v1.23.2, v1.22.8, v1.22.7, v1.22.6, v1.22.5, v1.21.6, v1.27-alpha.f23c2f66.
- // +operator-sdk:csv:customresourcedefinitions:type=spec,order=1,displayName="Istio Version",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:fieldGroup:General", "urn:alm:descriptor:com.tectonic.ui:select:v1.25.2", "urn:alm:descriptor:com.tectonic.ui:select:v1.25.1", "urn:alm:descriptor:com.tectonic.ui:select:v1.24.5", "urn:alm:descriptor:com.tectonic.ui:select:v1.24.4", "urn:alm:descriptor:com.tectonic.ui:select:v1.24.3", "urn:alm:descriptor:com.tectonic.ui:select:v1.24.2", "urn:alm:descriptor:com.tectonic.ui:select:v1.24.1", "urn:alm:descriptor:com.tectonic.ui:select:v1.24.0", "urn:alm:descriptor:com.tectonic.ui:select:v1.23.6", "urn:alm:descriptor:com.tectonic.ui:select:v1.23.5", "urn:alm:descriptor:com.tectonic.ui:select:v1.23.4", "urn:alm:descriptor:com.tectonic.ui:select:v1.23.3", "urn:alm:descriptor:com.tectonic.ui:select:v1.23.2", "urn:alm:descriptor:com.tectonic.ui:select:v1.22.8", "urn:alm:descriptor:com.tectonic.ui:select:v1.22.7", "urn:alm:descriptor:com.tectonic.ui:select:v1.22.6", "urn:alm:descriptor:com.tectonic.ui:select:v1.22.5", "urn:alm:descriptor:com.tectonic.ui:select:v1.21.6", "urn:alm:descriptor:com.tectonic.ui:select:v1.27-alpha.f23c2f66"}
- // +kubebuilder:validation:Enum=v1.25.2;v1.25.1;v1.24.5;v1.24.4;v1.24.3;v1.24.2;v1.24.1;v1.24.0;v1.23.6;v1.23.5;v1.23.4;v1.23.3;v1.23.2;v1.22.8;v1.22.7;v1.22.6;v1.22.5;v1.21.6;v1.27-alpha.f23c2f66
+ // Must be one of: v1.28.3, v1.28.2, v1.28.1, v1.28.0, v1.27.5, v1.27.4, v1.27.3, v1.27.2, v1.27.1, v1.27.0, v1.30-alpha.a30ad733.
+ // +operator-sdk:csv:customresourcedefinitions:type=spec,order=1,displayName="Istio Version",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:fieldGroup:General", "urn:alm:descriptor:com.tectonic.ui:select:v1.28.3", "urn:alm:descriptor:com.tectonic.ui:select:v1.28.2", "urn:alm:descriptor:com.tectonic.ui:select:v1.28.1", "urn:alm:descriptor:com.tectonic.ui:select:v1.28.0", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.5", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.4", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.3", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.2", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.1", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.0", "urn:alm:descriptor:com.tectonic.ui:select:v1.30-alpha.a30ad733"}
+ // +kubebuilder:validation:Enum=v1.28.3;v1.28.2;v1.28.1;v1.28.0;v1.27.5;v1.27.4;v1.27.3;v1.27.2;v1.27.1;v1.27.0;v1.26.8;v1.26.7;v1.26.6;v1.26.5;v1.26.4;v1.26.3;v1.26.2;v1.26.1;v1.26.0;v1.25.5;v1.25.4;v1.25.3;v1.25.2;v1.25.1;v1.24.6;v1.24.5;v1.24.4;v1.24.3;v1.24.2;v1.24.1;v1.24.0;v1.23.6;v1.23.5;v1.23.4;v1.23.3;v1.23.2;v1.22.8;v1.22.7;v1.22.6;v1.22.5;v1.21.6;v1.30-alpha.a30ad733
Version string `json:"version"`
// Namespace to which the Istio components should be installed.
@@ -148,6 +148,9 @@ const (
// IstioRevisionReasonIstiodNotReady indicates that the control plane is fully reconciled, but istiod is not ready.
IstioRevisionReasonIstiodNotReady IstioRevisionConditionReason = "IstiodNotReady"
+ // IstioRevisionTagNameAlreadyExists indicates that a IstioRevisionTag with the same name as the IstioRevision already exists.
+ IstioRevisionReasonNameAlreadyExists IstioRevisionConditionReason = "NameAlreadyExists"
+
// IstioRevisionReasonRemoteIstiodNotReady indicates that the remote istiod is not ready.
IstioRevisionReasonRemoteIstiodNotReady IstioRevisionConditionReason = "RemoteIstiodNotReady"
@@ -182,6 +185,12 @@ const (
// IstioRevisionReasonIstioCNINotHealthy indicates that the IstioCNI resource is not healthy.
IstioRevisionReasonIstioCNINotHealthy IstioRevisionConditionReason = "IstioCNINotHealthy"
+ // IstioRevisionReasonZTunnelNotFound indicates that the ZTunnel resource is not found.
+ IstioRevisionReasonZTunnelNotFound IstioRevisionConditionReason = "ZTunnelNotFound"
+
+ // IstioRevisionReasonZTunnelNotHealthy indicates that the ZTunnel resource is not healthy.
+ IstioRevisionReasonZTunnelNotHealthy IstioRevisionConditionReason = "ZTunnelNotHealthy"
+
// IstioRevisionDependencyCheckFailed indicates that the status of the dependencies could not be ascertained.
IstioRevisionDependencyCheckFailed IstioRevisionConditionReason = "DependencyCheckFailed"
)
@@ -206,7 +215,7 @@ const (
// Users shouldn't create IstioRevision objects directly. Instead, they should
// create an Istio object and allow the operator to create the underlying
// IstioRevision object(s).
-// +kubebuilder:validation:XValidation:rule="self.metadata.name == 'default' ? (!has(self.spec.values.revision) || size(self.spec.values.revision) == 0) : self.spec.values.revision == self.metadata.name",message="spec.values.revision must match metadata.name"
+// +kubebuilder:validation:XValidation:rule="self.metadata.name == 'default' ? (!has(self.spec.values.revision) || size(self.spec.values.revision) == 0) : self.spec.values.revision == self.metadata.name",message="spec.values.revision must match metadata.name or be empty when the name is 'default'"
type IstioRevision struct {
metav1.TypeMeta `json:",inline"`
// +optional
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/api/v1/istiorevisiontags_types.go b/vendor/github.com/istio-ecosystem/sail-operator/api/v1/istiorevisiontags_types.go
index 1558fdd3fc..4ae3330475 100644
--- a/vendor/github.com/istio-ecosystem/sail-operator/api/v1/istiorevisiontags_types.go
+++ b/vendor/github.com/istio-ecosystem/sail-operator/api/v1/istiorevisiontags_types.go
@@ -145,7 +145,7 @@ const (
// successfully reconciled the resources defined through the CR.
IstioRevisionTagConditionReconciled IstioRevisionTagConditionType = "Reconciled"
- // IstioRevisionTagNameAlreadyExists indicates that the a revision with the same name as the IstioRevisionTag already exists.
+ // IstioRevisionTagNameAlreadyExists indicates that an IstioRevision with the same name as the IstioRevisionTag already exists.
IstioRevisionTagReasonNameAlreadyExists IstioRevisionTagConditionReason = "NameAlreadyExists"
// IstioRevisionTagReasonReferenceNotFound indicates that the resource referenced by the tag's TargetRef was not found
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/api/v1/values_types.gen.go b/vendor/github.com/istio-ecosystem/sail-operator/api/v1/values_types.gen.go
index aa2875a561..f1edb47441 100644
--- a/vendor/github.com/istio-ecosystem/sail-operator/api/v1/values_types.gen.go
+++ b/vendor/github.com/istio-ecosystem/sail-operator/api/v1/values_types.gen.go
@@ -24,6 +24,16 @@ import (
intstr "k8s.io/apimachinery/pkg/util/intstr"
)
+// +kubebuilder:validation:Enum=undefined;all;cluster;namespace
+type ResourceScope string
+
+const (
+ ResourceScopeUndefined ResourceScope = "undefined"
+ ResourceScopeAll ResourceScope = "all"
+ ResourceScopeCluster ResourceScope = "cluster"
+ ResourceScopeNamespace ResourceScope = "namespace"
+)
+
// Mode for the ingress controller.
// +kubebuilder:validation:Enum=UNSPECIFIED;DEFAULT;STRICT;OFF
type IngressControllerMode string
@@ -106,10 +116,22 @@ type CNIConfig struct {
ExcludeNamespaces []string `json:"excludeNamespaces,omitempty"`
// K8s affinity to set on the istio-cni Pods. Can be used to exclude istio-cni from being scheduled on specified nodes.
Affinity *k8sv1.Affinity `json:"affinity,omitempty"`
+ // Environment variables passed to the CNI container.
+ //
+ // Examples:
+ // env:
+ //
+ // ENV_VAR_1: value1
+ // ENV_VAR_2: value2
+ Env map[string]string `json:"env,omitempty"`
+ // Additional labels to apply to the istio-cni DaemonSet.
+ DaemonSetLabels map[string]string `json:"daemonSetLabels,omitempty"`
// Additional annotations to apply to the istio-cni Pods.
//
// Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
PodAnnotations map[string]string `json:"podAnnotations,omitempty"`
+ // Additional labels to apply to the istio-cni Pods.
+ PodLabels map[string]string `json:"podLabels,omitempty"`
// PodSecurityPolicy cluster role. No longer used anywhere.
PspClusterRole *string `json:"psp_cluster_role,omitempty"`
@@ -120,7 +142,7 @@ type CNIConfig struct {
// Configure the plugin as a chained CNI plugin. When true, the configuration is added to the CNI chain; when false,
// the configuration is added as a standalone file in the CNI configuration directory.
Chained *bool `json:"chained,omitempty"`
- // The resource quotas configration for the CNI DaemonSet.
+ // The resource quotas configuration for the CNI DaemonSet.
ResourceQuotas *ResourceQuotas `json:"resource_quotas,omitempty"`
// The k8s resource requests and limits for the istio-cni Pods.
Resources *k8sv1.ResourceRequirements `json:"resources,omitempty"`
@@ -145,6 +167,9 @@ type CNIConfig struct {
// of pods at the start of the update.
// +kubebuilder:validation:XIntOrString
RollingMaxUnavailable *intstr.IntOrString `json:"rollingMaxUnavailable,omitempty"`
+ // Specifies if an Istio owned CNI config should be created.
+ IstioOwnedCNIConfig *bool `json:"istioOwnedCNIConfig,omitempty"`
+ IstioOwnedCNIConfigFileName *string `json:"istioOwnedCNIConfigFileName,omitempty"`
}
type CNIUsageConfig struct {
@@ -423,10 +448,23 @@ type GlobalConfig struct {
// Specifies how waypoints are configured within Istio.
Waypoint *WaypointConfig `json:"waypoint,omitempty"`
// Select a custom name for istiod's CA Root Cert ConfigMap.
- TrustBundleName *string `json:"trustBundleName,omitempty"` // The next available key is 74
+ TrustBundleName *string `json:"trustBundleName,omitempty"`
+ // Specifies whether native nftables rules should be used instead of iptables rules for traffic redirection.
+ NativeNftables *bool `json:"nativeNftables,omitempty"`
+ // Settings related to Kubernetes NetworkPolicy.
+ NetworkPolicy *NetworkPolicyConfig `json:"networkPolicy,omitempty"`
+ // Specifies resource scope for discovery selectors.
+ // This is useful when installing Istio on a cluster where some resources need to be owned by a cluster administrator and some can be owned by the mesh administrator.
+ ResourceScope ResourceScope `json:"resourceScope,omitempty"`
+ // Specifies how proxies are configured within Istio.
+ Agentgateway *Agentgateway `json:"agentgateway,omitempty"` // The next available key is 78
}
+type Agentgateway struct {
+ Image *string `json:"image,omitempty"`
+}
+
// Configuration for Security Token Service (STS) server.
//
// See https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16
@@ -617,7 +655,9 @@ type PilotConfig struct {
// Configuration for the istio-discovery chart when istiod is running in a remote cluster (e.g. "remote control plane").
IstiodRemote *IstiodRemoteConfig `json:"istiodRemote,omitempty"`
// Configuration for the istio-discovery chart
- EnvVarFrom []k8sv1.EnvFromSource `json:"envVarFrom,omitempty"`
+ EnvVarFrom []k8sv1.EnvVar `json:"envVarFrom,omitempty"`
+ // Select a custom name for istiod's plugged-in CA CRL ConfigMap.
+ CrlConfigMapName *string `json:"crlConfigMapName,omitempty"`
}
type PilotTaintControllerConfig struct {
@@ -728,6 +768,10 @@ type ProxyConfig struct {
ReadinessPeriodSeconds *uint32 `json:"readinessPeriodSeconds,omitempty"`
// Sets the number of successive failed probes before indicating readiness failure.
ReadinessFailureThreshold *uint32 `json:"readinessFailureThreshold,omitempty"`
+ // Configures the seccomp profile for the istio-validation and istio-proxy containers.
+ //
+ // See: https://kubernetes.io/docs/tutorials/security/seccomp/
+ SeccompProfile *k8sv1.SeccompProfile `json:"seccompProfile,omitempty"`
// Configures the startup probe for the istio-proxy container.
StartupProbe *StartupProbe `json:"startupProbe,omitempty"`
// Default port used for the Pilot agent's health checks.
@@ -912,6 +956,9 @@ type IstiodRemoteConfig struct {
InjectionCABundle *string `json:"injectionCABundle,omitempty"`
// Indicates if this cluster/install should consume a "remote" istiod instance,
Enabled *bool `json:"enabled,omitempty"`
+ // If `true`, indicates that this cluster/install should consume a "local istiod" installation,
+ // local istiod inject sidecars
+ EnabledLocalInjectorIstiod *bool `json:"enabledLocalInjectorIstiod,omitempty"`
}
type Values struct {
@@ -955,6 +1002,8 @@ type Values struct {
// +kubebuilder:validation:Schemaless
Experimental json.RawMessage `json:"experimental,omitempty"`
// Configuration for Gateway Classes
+ // +kubebuilder:pruning:PreserveUnknownFields
+ // +kubebuilder:validation:Schemaless
GatewayClasses json.RawMessage `json:"gatewayClasses,omitempty"`
}
@@ -988,15 +1037,21 @@ type WaypointConfig struct {
Toleration []*k8sv1.Toleration `json:"toleration,omitempty"`
}
+// Configuration for NetworkPolicy
+type NetworkPolicyConfig struct {
+ // Controls whether default NetworkPolicy resources will be created.
+ Enabled *bool `json:"enabled,omitempty"`
+}
+
const filePkgApisValuesTypesProtoRawDesc = "" +
"\n" +
- "\x1bpkg/apis/values_types.proto\x12\x17istio.operator.v1alpha1\x1a\x19google/protobuf/any.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1egoogle/protobuf/wrappers.proto\x1a\"k8s.io/api/core/v1/generated.proto\x1a4k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto\"h\n" +
+ "\x1bpkg/apis/values_types.proto\x12\x17istio.operator.v1alpha1\x1a\x19google/protobuf/any.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1egoogle/protobuf/wrappers.proto\"h\n" +
"\n" +
"ArchConfig\x12\x14\n" +
"\x05amd64\x18\x01 \x01(\rR\x05amd64\x12\x18\n" +
"\appc64le\x18\x02 \x01(\rR\appc64le\x12\x14\n" +
"\x05s390x\x18\x03 \x01(\rR\x05s390x\x12\x14\n" +
- "\x05arm64\x18\x04 \x01(\rR\x05arm64\"\xeb\t\n" +
+ "\x05arm64\x18\x04 \x01(\rR\x05arm64\"\x90\f\n" +
"\tCNIConfig\x124\n" +
"\aenabled\x18\x01 \x01(\v2\x1a.google.protobuf.BoolValueR\aenabled\x12\x10\n" +
"\x03hub\x18\x02 \x01(\tR\x03hub\x12(\n" +
@@ -1012,10 +1067,13 @@ const filePkgApisValuesTypesProtoRawDesc = "" +
"cniConfDir\x12(\n" +
"\x0fcniConfFileName\x18\b \x01(\tR\x0fcniConfFileName\x12 \n" +
"\vcniNetnsDir\x18\x1f \x01(\tR\vcniNetnsDir\x12,\n" +
- "\x11excludeNamespaces\x18\t \x03(\tR\x11excludeNamespaces\x128\n" +
- "\baffinity\x18\x14 \x01(\v2\x1c.k8s.io.api.core.v1.AffinityR\baffinity\x12C\n" +
+ "\x11excludeNamespaces\x18\t \x03(\tR\x11excludeNamespaces\x123\n" +
+ "\baffinity\x18\x14 \x01(\v2\x17.google.protobuf.StructR\baffinity\x12)\n" +
+ "\x03env\x18 \x01(\v2\x17.google.protobuf.StructR\x03env\x12A\n" +
+ "\x0fdaemonSetLabels\x18! \x01(\v2\x17.google.protobuf.StructR\x0fdaemonSetLabels\x12C\n" +
"\x0epodAnnotations\x18\n" +
- " \x01(\v2\x17.google.protobuf.StructB\x02\x18\x01R\x0epodAnnotations\x12(\n" +
+ " \x01(\v2\x17.google.protobuf.StructB\x02\x18\x01R\x0epodAnnotations\x125\n" +
+ "\tpodLabels\x18\" \x01(\v2\x17.google.protobuf.StructR\tpodLabels\x12(\n" +
"\x10psp_cluster_role\x18\v \x01(\tR\x0epspClusterRole\x12\x1e\n" +
"\blogLevel\x18\f \x01(\tB\x02\x18\x01R\blogLevel\x12F\n" +
"\alogging\x18\x19 \x01(\v2,.istio.operator.v1alpha1.GlobalLoggingConfigR\alogging\x12@\n" +
@@ -1025,11 +1083,13 @@ const filePkgApisValuesTypesProtoRawDesc = "" +
"\tresources\x18\x11 \x01(\v2\".istio.operator.v1alpha1.ResourcesR\tresources\x12>\n" +
"\n" +
"privileged\x18\x12 \x01(\v2\x1a.google.protobuf.BoolValueB\x02\x18\x01R\n" +
- "privileged\x12J\n" +
- "\x0eseccompProfile\x18\x13 \x01(\v2\".k8s.io.api.core.v1.SeccompProfileR\x0eseccompProfile\x12C\n" +
+ "privileged\x12?\n" +
+ "\x0eseccompProfile\x18\x13 \x01(\v2\x17.google.protobuf.StructR\x0eseccompProfile\x12C\n" +
"\aambient\x18\x15 \x01(\v2).istio.operator.v1alpha1.CNIAmbientConfigR\aambient\x12\x1a\n" +
"\bprovider\x18\x16 \x01(\tR\bprovider\x12Z\n" +
- "\x15rollingMaxUnavailable\x18\x17 \x01(\v2$.istio.operator.v1alpha1.IntOrStringR\x15rollingMaxUnavailable\"\x9c\x01\n" +
+ "\x15rollingMaxUnavailable\x18\x17 \x01(\v2$.istio.operator.v1alpha1.IntOrStringR\x15rollingMaxUnavailable\x12L\n" +
+ "\x13istioOwnedCNIConfig\x18# \x01(\v2\x1a.google.protobuf.BoolValueR\x13istioOwnedCNIConfig\x12@\n" +
+ "\x1bistioOwnedCNIConfigFileName\x18$ \x01(\tR\x1bistioOwnedCNIConfigFileName\"\x9c\x01\n" +
"\x0eCNIUsageConfig\x124\n" +
"\aenabled\x18\x01 \x01(\v2\x1a.google.protobuf.BoolValueR\aenabled\x128\n" +
"\achained\x18\x02 \x01(\v2\x1a.google.protobuf.BoolValueB\x02\x18\x01R\achained\x12\x1a\n" +
@@ -1078,7 +1138,7 @@ const filePkgApisValuesTypesProtoRawDesc = "" +
" DefaultPodDisruptionBudgetConfig\x124\n" +
"\aenabled\x18\x01 \x01(\v2\x1a.google.protobuf.BoolValueR\aenabled\"f\n" +
"\x16DefaultResourcesConfig\x12L\n" +
- "\brequests\x18\x01 \x01(\v20.istio.operator.v1alpha1.ResourcesRequestsConfigR\brequests\"\xbb\x0f\n" +
+ "\brequests\x18\x01 \x01(\v20.istio.operator.v1alpha1.ResourcesRequestsConfigR\brequests\"\xfb\x0e\n" +
"\x13EgressGatewayConfig\x12F\n" +
"\x10autoscaleEnabled\x18\x01 \x01(\v2\x1a.google.protobuf.BoolValueR\x10autoscaleEnabled\x12\"\n" +
"\fautoscaleMax\x18\x02 \x01(\rR\fautoscaleMax\x12\"\n" +
@@ -1092,15 +1152,15 @@ const filePkgApisValuesTypesProtoRawDesc = "" +
"\x04name\x18\x19 \x01(\tR\x04name\x12?\n" +
"\fnodeSelector\x18\n" +
" \x01(\v2\x17.google.protobuf.StructB\x02\x18\x01R\fnodeSelector\x12C\n" +
- "\x0epodAnnotations\x18\v \x01(\v2\x17.google.protobuf.StructB\x02\x18\x01R\x0epodAnnotations\x12{\n" +
- "\x1cpodAntiAffinityLabelSelector\x18\f \x03(\v23.k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelectorB\x02\x18\x01R\x1cpodAntiAffinityLabelSelector\x12\x83\x01\n" +
- " podAntiAffinityTermLabelSelector\x18\r \x03(\v23.k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelectorB\x02\x18\x01R podAntiAffinityTermLabelSelector\x12:\n" +
+ "\x0epodAnnotations\x18\v \x01(\v2\x17.google.protobuf.StructB\x02\x18\x01R\x0epodAnnotations\x12_\n" +
+ "\x1cpodAntiAffinityLabelSelector\x18\f \x03(\v2\x17.google.protobuf.StructB\x02\x18\x01R\x1cpodAntiAffinityLabelSelector\x12g\n" +
+ " podAntiAffinityTermLabelSelector\x18\r \x03(\v2\x17.google.protobuf.StructB\x02\x18\x01R podAntiAffinityTermLabelSelector\x12:\n" +
"\x05ports\x18\x0e \x03(\v2$.istio.operator.v1alpha1.PortsConfigR\x05ports\x12D\n" +
"\tresources\x18\x0f \x01(\v2\".istio.operator.v1alpha1.ResourcesB\x02\x18\x01R\tresources\x12K\n" +
"\rsecretVolumes\x18\x10 \x03(\v2%.istio.operator.v1alpha1.SecretVolumeR\rsecretVolumes\x12G\n" +
"\x12serviceAnnotations\x18\x11 \x01(\v2\x17.google.protobuf.StructR\x12serviceAnnotations\x12\x12\n" +
- "\x04type\x18\x12 \x01(\tR\x04type\x12D\n" +
- "\vtolerations\x18\x14 \x03(\v2\x1e.k8s.io.api.core.v1.TolerationB\x02\x18\x01R\vtolerations\x12R\n" +
+ "\x04type\x18\x12 \x01(\tR\x04type\x12=\n" +
+ "\vtolerations\x18\x14 \x03(\v2\x17.google.protobuf.StructB\x02\x18\x01R\vtolerations\x12R\n" +
"\x0frollingMaxSurge\x18\x15 \x01(\v2$.istio.operator.v1alpha1.IntOrStringB\x02\x18\x01R\x0frollingMaxSurge\x12^\n" +
"\x15rollingMaxUnavailable\x18\x16 \x01(\v2$.istio.operator.v1alpha1.IntOrStringB\x02\x18\x01R\x15rollingMaxUnavailable\x12=\n" +
"\rconfigVolumes\x18\x17 \x03(\v2\x17.google.protobuf.StructR\rconfigVolumes\x12K\n" +
@@ -1121,15 +1181,15 @@ const filePkgApisValuesTypesProtoRawDesc = "" +
"\x14istio_ingressgateway\x18\x04 \x01(\v2-.istio.operator.v1alpha1.IngressGatewayConfigR\x14istio-ingressgateway\x12@\n" +
"\x0fsecurityContext\x18\n" +
" \x01(\v2\x16.google.protobuf.ValueR\x0fsecurityContext\x12>\n" +
- "\x0eseccompProfile\x18\f \x01(\v2\x16.google.protobuf.ValueR\x0eseccompProfile\"\xc7\x12\n" +
+ "\x0eseccompProfile\x18\f \x01(\v2\x16.google.protobuf.ValueR\x0eseccompProfile\"\xf1\x14\n" +
"\fGlobalConfig\x12;\n" +
"\x04arch\x18\x01 \x01(\v2#.istio.operator.v1alpha1.ArchConfigB\x02\x18\x01R\x04arch\x12 \n" +
"\vcertSigners\x18D \x03(\tR\vcertSigners\x12F\n" +
"\x10configValidation\x18\x03 \x01(\v2\x1a.google.protobuf.BoolValueR\x10configValidation\x12M\n" +
"\x13defaultNodeSelector\x18\x06 \x01(\v2\x17.google.protobuf.StructB\x02\x18\x01R\x13defaultNodeSelector\x12y\n" +
"\x1adefaultPodDisruptionBudget\x18\a \x01(\v29.istio.operator.v1alpha1.DefaultPodDisruptionBudgetConfigR\x1adefaultPodDisruptionBudget\x12_\n" +
- "\x10defaultResources\x18\t \x01(\v2/.istio.operator.v1alpha1.DefaultResourcesConfigB\x02\x18\x01R\x10defaultResources\x12R\n" +
- "\x12defaultTolerations\x187 \x03(\v2\x1e.k8s.io.api.core.v1.TolerationB\x02\x18\x01R\x12defaultTolerations\x12\x10\n" +
+ "\x10defaultResources\x18\t \x01(\v2/.istio.operator.v1alpha1.DefaultResourcesConfigB\x02\x18\x01R\x10defaultResources\x12K\n" +
+ "\x12defaultTolerations\x187 \x03(\v2\x17.google.protobuf.StructB\x02\x18\x01R\x12defaultTolerations\x12\x10\n" +
"\x03hub\x18\f \x01(\tR\x03hub\x12(\n" +
"\x0fimagePullPolicy\x18\r \x01(\tR\x0fimagePullPolicy\x12*\n" +
"\x10imagePullSecrets\x18% \x03(\tR\x10imagePullSecrets\x12&\n" +
@@ -1169,13 +1229,19 @@ const filePkgApisValuesTypesProtoRawDesc = "" +
"ipFamilies\x12&\n" +
"\x0eipFamilyPolicy\x18G \x01(\tR\x0eipFamilyPolicy\x12C\n" +
"\bwaypoint\x18H \x01(\v2'.istio.operator.v1alpha1.WaypointConfigR\bwaypoint\x12(\n" +
- "\x0ftrustBundleName\x18I \x01(\tR\x0ftrustBundleName\"-\n" +
+ "\x0ftrustBundleName\x18I \x01(\tR\x0ftrustBundleName\x12B\n" +
+ "\x0enativeNftables\x18J \x01(\v2\x1a.google.protobuf.BoolValueR\x0enativeNftables\x12R\n" +
+ "\rnetworkPolicy\x18K \x01(\v2,.istio.operator.v1alpha1.NetworkPolicyConfigR\rnetworkPolicy\x12L\n" +
+ "\rresourceScope\x18L \x01(\x0e2&.istio.operator.v1alpha1.ResourceScopeR\rresourceScope\x12I\n" +
+ "\fagentgateway\x18M \x01(\v2%.istio.operator.v1alpha1.AgentgatewayR\fagentgateway\"$\n" +
+ "\fAgentgateway\x12\x14\n" +
+ "\x05image\x18\x01 \x01(\tR\x05image\"-\n" +
"\tSTSConfig\x12 \n" +
"\vservicePort\x18\x01 \x01(\rR\vservicePort\"R\n" +
"\fIstiodConfig\x12B\n" +
"\x0eenableAnalysis\x18\x02 \x01(\v2\x1a.google.protobuf.BoolValueR\x0eenableAnalysis\"+\n" +
"\x13GlobalLoggingConfig\x12\x14\n" +
- "\x05level\x18\x01 \x01(\tR\x05level\"\xb1\x11\n" +
+ "\x05level\x18\x01 \x01(\tR\x05level\"\xf1\x10\n" +
"\x14IngressGatewayConfig\x12F\n" +
"\x10autoscaleEnabled\x18\x01 \x01(\v2\x1a.google.protobuf.BoolValueR\x10autoscaleEnabled\x12\"\n" +
"\fautoscaleMax\x18\x02 \x01(\rR\fautoscaleMax\x12\"\n" +
@@ -1191,9 +1257,9 @@ const filePkgApisValuesTypesProtoRawDesc = "" +
"\x18loadBalancerSourceRanges\x18\x11 \x03(\tR\x18loadBalancerSourceRanges\x12\x12\n" +
"\x04name\x18, \x01(\tR\x04name\x12?\n" +
"\fnodeSelector\x18\x13 \x01(\v2\x17.google.protobuf.StructB\x02\x18\x01R\fnodeSelector\x12C\n" +
- "\x0epodAnnotations\x18\x14 \x01(\v2\x17.google.protobuf.StructB\x02\x18\x01R\x0epodAnnotations\x12{\n" +
- "\x1cpodAntiAffinityLabelSelector\x18\x15 \x03(\v23.k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelectorB\x02\x18\x01R\x1cpodAntiAffinityLabelSelector\x12\x83\x01\n" +
- " podAntiAffinityTermLabelSelector\x18\x16 \x03(\v23.k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelectorB\x02\x18\x01R podAntiAffinityTermLabelSelector\x12:\n" +
+ "\x0epodAnnotations\x18\x14 \x01(\v2\x17.google.protobuf.StructB\x02\x18\x01R\x0epodAnnotations\x12_\n" +
+ "\x1cpodAntiAffinityLabelSelector\x18\x15 \x03(\v2\x17.google.protobuf.StructB\x02\x18\x01R\x1cpodAntiAffinityLabelSelector\x12g\n" +
+ " podAntiAffinityTermLabelSelector\x18\x16 \x03(\v2\x17.google.protobuf.StructB\x02\x18\x01R podAntiAffinityTermLabelSelector\x12:\n" +
"\x05ports\x18\x17 \x03(\v2$.istio.operator.v1alpha1.PortsConfigR\x05ports\x12&\n" +
"\freplicaCount\x18\x18 \x01(\rB\x02\x18\x01R\freplicaCount\x129\n" +
"\tresources\x18\x19 \x01(\v2\x17.google.protobuf.StructB\x02\x18\x01R\tresources\x12K\n" +
@@ -1202,8 +1268,8 @@ const filePkgApisValuesTypesProtoRawDesc = "" +
"\x04type\x18\x1d \x01(\tR\x04type\x12R\n" +
"\x0frollingMaxSurge\x18\x1f \x01(\v2$.istio.operator.v1alpha1.IntOrStringB\x02\x18\x01R\x0frollingMaxSurge\x12^\n" +
"\x15rollingMaxUnavailable\x18 \x01(\v2$.istio.operator.v1alpha1.IntOrStringB\x02\x18\x01R\x15rollingMaxUnavailable\x124\n" +
- "\x15externalTrafficPolicy\x18\" \x01(\tR\x15externalTrafficPolicy\x12D\n" +
- "\vtolerations\x18# \x03(\v2\x1e.k8s.io.api.core.v1.TolerationB\x02\x18\x01R\vtolerations\x12;\n" +
+ "\x15externalTrafficPolicy\x18\" \x01(\tR\x15externalTrafficPolicy\x12=\n" +
+ "\vtolerations\x18# \x03(\v2\x17.google.protobuf.StructB\x02\x18\x01R\vtolerations\x12;\n" +
"\fingressPorts\x18$ \x03(\v2\x17.google.protobuf.StructR\fingressPorts\x12K\n" +
"\x14additionalContainers\x18% \x03(\v2\x17.google.protobuf.StructR\x14additionalContainers\x12=\n" +
"\rconfigVolumes\x18& \x03(\v2\x17.google.protobuf.StructR\rconfigVolumes\x128\n" +
@@ -1226,7 +1292,7 @@ const filePkgApisValuesTypesProtoRawDesc = "" +
"\x04mode\x18\x02 \x01(\x0e29.istio.operator.v1alpha1.OutboundTrafficPolicyConfig.ModeR\x04mode\"(\n" +
"\x04Mode\x12\r\n" +
"\tALLOW_ANY\x10\x00\x12\x11\n" +
- "\rREGISTRY_ONLY\x10\x01\"\x98\x13\n" +
+ "\rREGISTRY_ONLY\x10\x01\"\x8d\x13\n" +
"\vPilotConfig\x124\n" +
"\aenabled\x18\x01 \x01(\v2\x1a.google.protobuf.BoolValueR\aenabled\x12F\n" +
"\x10autoscaleEnabled\x18\x02 \x01(\v2\x1a.google.protobuf.BoolValueR\x10autoscaleEnabled\x12\"\n" +
@@ -1243,23 +1309,23 @@ const filePkgApisValuesTypesProtoRawDesc = "" +
"\x10deploymentLabels\x18\x0e \x01(\v2\x17.google.protobuf.StructR\x10deploymentLabels\x125\n" +
"\tpodLabels\x18$ \x01(\v2\x17.google.protobuf.StructR\tpodLabels\x128\n" +
"\tconfigMap\x18\x12 \x01(\v2\x1a.google.protobuf.BoolValueR\tconfigMap\x12)\n" +
- "\x03env\x18\x15 \x01(\v2\x17.google.protobuf.StructR\x03env\x128\n" +
- "\baffinity\x18\x16 \x01(\v2\x1c.k8s.io.api.core.v1.AffinityR\baffinity\x12R\n" +
+ "\x03env\x18\x15 \x01(\v2\x17.google.protobuf.StructR\x03env\x123\n" +
+ "\baffinity\x18\x16 \x01(\v2\x17.google.protobuf.StructR\baffinity\x12R\n" +
"\x0frollingMaxSurge\x18\x18 \x01(\v2$.istio.operator.v1alpha1.IntOrStringB\x02\x18\x01R\x0frollingMaxSurge\x12^\n" +
- "\x15rollingMaxUnavailable\x18\x19 \x01(\v2$.istio.operator.v1alpha1.IntOrStringB\x02\x18\x01R\x15rollingMaxUnavailable\x12D\n" +
- "\vtolerations\x18\x1a \x03(\v2\x1e.k8s.io.api.core.v1.TolerationB\x02\x18\x01R\vtolerations\x12C\n" +
+ "\x15rollingMaxUnavailable\x18\x19 \x01(\v2$.istio.operator.v1alpha1.IntOrStringB\x02\x18\x01R\x15rollingMaxUnavailable\x12=\n" +
+ "\vtolerations\x18\x1a \x03(\v2\x17.google.protobuf.StructB\x02\x18\x01R\vtolerations\x12C\n" +
"\x0epodAnnotations\x18\x1e \x01(\v2\x17.google.protobuf.StructB\x02\x18\x01R\x0epodAnnotations\x12G\n" +
"\x12serviceAnnotations\x18% \x01(\v2\x17.google.protobuf.StructR\x12serviceAnnotations\x12U\n" +
"\x19serviceAccountAnnotations\x188 \x01(\v2\x17.google.protobuf.StructR\x19serviceAccountAnnotations\x128\n" +
"\x17jwksResolverExtraRootCA\x18 \x01(\tR\x17jwksResolverExtraRootCA\x12\x10\n" +
"\x03hub\x18\" \x01(\tR\x03hub\x12(\n" +
"\x03tag\x18# \x01(\v2\x16.google.protobuf.ValueR\x03tag\x12\x18\n" +
- "\avariant\x18' \x01(\tR\avariant\x12J\n" +
- "\x0eseccompProfile\x18& \x01(\v2\".k8s.io.api.core.v1.SeccompProfileR\x0eseccompProfile\x12j\n" +
- "\x19topologySpreadConstraints\x18) \x03(\v2,.k8s.io.api.core.v1.TopologySpreadConstraintR\x19topologySpreadConstraints\x12G\n" +
- "\x12extraContainerArgs\x18* \x03(\v2\x17.google.protobuf.StructR\x12extraContainerArgs\x12C\n" +
- "\fvolumeMounts\x181 \x03(\v2\x1f.k8s.io.api.core.v1.VolumeMountR\fvolumeMounts\x124\n" +
- "\avolumes\x183 \x03(\v2\x1a.k8s.io.api.core.v1.VolumeR\avolumes\x12\x1e\n" +
+ "\avariant\x18' \x01(\tR\avariant\x12?\n" +
+ "\x0eseccompProfile\x18& \x01(\v2\x17.google.protobuf.StructR\x0eseccompProfile\x12U\n" +
+ "\x19topologySpreadConstraints\x18) \x03(\v2\x17.google.protobuf.StructR\x19topologySpreadConstraints\x12G\n" +
+ "\x12extraContainerArgs\x18* \x03(\v2\x17.google.protobuf.StructR\x12extraContainerArgs\x12;\n" +
+ "\fvolumeMounts\x181 \x03(\v2\x17.google.protobuf.StructR\fvolumeMounts\x121\n" +
+ "\avolumes\x183 \x03(\v2\x17.google.protobuf.StructR\avolumes\x12\x1e\n" +
"\n" +
"ipFamilies\x184 \x03(\tR\n" +
"ipFamilies\x12&\n" +
@@ -1271,7 +1337,8 @@ const filePkgApisValuesTypesProtoRawDesc = "" +
"\fistiodRemote\x18= \x01(\v2+.istio.operator.v1alpha1.IstiodRemoteConfigR\fistiodRemote\x127\n" +
"\n" +
"envVarFrom\x18> \x03(\v2\x17.google.protobuf.StructR\n" +
- "envVarFrom\"T\n" +
+ "envVarFrom\x12*\n" +
+ "\x10crlConfigMapName\x18? \x01(\tR\x10crlConfigMapName\"T\n" +
"\x1aPilotTaintControllerConfig\x12\x18\n" +
"\aenabled\x18\x01 \x01(\bR\aenabled\x12\x1c\n" +
"\tnamespace\x18\x02 \x01(\tR\tnamespace\"\xc6\x01\n" +
@@ -1301,7 +1368,8 @@ const filePkgApisValuesTypesProtoRawDesc = "" +
"\n" +
"targetPort\x18\x04 \x01(\x05R\n" +
"targetPort\x12\x1a\n" +
- "\bprotocol\x18\x05 \x01(\tR\bprotocol\"\xca\t\n" +
+ "\bprotocol\x18\x05 \x01(\tR\bprotocol\"\x85\n" +
+ "\n" +
"\vProxyConfig\x12\x1e\n" +
"\n" +
"autoInject\x18\x04 \x01(\tR\n" +
@@ -1320,15 +1388,16 @@ const filePkgApisValuesTypesProtoRawDesc = "" +
"privileged\x12B\n" +
"\x1creadinessInitialDelaySeconds\x18\x14 \x01(\rR\x1creadinessInitialDelaySeconds\x126\n" +
"\x16readinessPeriodSeconds\x18\x15 \x01(\rR\x16readinessPeriodSeconds\x12<\n" +
- "\x19readinessFailureThreshold\x18\x16 \x01(\rR\x19readinessFailureThreshold\x12I\n" +
+ "\x19readinessFailureThreshold\x18\x16 \x01(\rR\x19readinessFailureThreshold\x12?\n" +
+ "\x0eseccompProfile\x18+ \x01(\v2\x17.google.protobuf.StructR\x0eseccompProfile\x12I\n" +
"\fstartupProbe\x18) \x01(\v2%.istio.operator.v1alpha1.StartupProbeR\fstartupProbe\x12\x1e\n" +
"\n" +
"statusPort\x18\x17 \x01(\rR\n" +
"statusPort\x12D\n" +
"\tresources\x18\x18 \x01(\v2\".istio.operator.v1alpha1.ResourcesB\x02\x18\x01R\tresources\x127\n" +
"\x06tracer\x18\x19 \x01(\x0e2\x1f.istio.operator.v1alpha1.tracerR\x06tracer\x122\n" +
- "\x14excludeOutboundPorts\x18\x1c \x01(\tR\x14excludeOutboundPorts\x12;\n" +
- "\tlifecycle\x18$ \x01(\v2\x1d.k8s.io.api.core.v1.LifecycleR\tlifecycle\x12h\n" +
+ "\x14excludeOutboundPorts\x18\x1c \x01(\tR\x14excludeOutboundPorts\x125\n" +
+ "\tlifecycle\x18$ \x01(\v2\x17.google.protobuf.StructR\tlifecycle\x12h\n" +
"\x1fholdApplicationUntilProxyStarts\x18% \x01(\v2\x1a.google.protobuf.BoolValueB\x02\x18\x01R\x1fholdApplicationUntilProxyStarts\x120\n" +
"\x13includeInboundPorts\x18& \x01(\tR\x13includeInboundPorts\x122\n" +
"\x14includeOutboundPorts\x18' \x01(\tR\x14includeOutboundPorts\"p\n" +
@@ -1348,12 +1417,12 @@ const filePkgApisValuesTypesProtoRawDesc = "" +
"\x04name\x18\x02 \x01(\tR\x04name\x12\x1e\n" +
"\n" +
"secretName\x18\x03 \x01(\tR\n" +
- "secretName\"\x91\x05\n" +
+ "secretName\"\xd9\x04\n" +
"\x15SidecarInjectorConfig\x12X\n" +
"\x19enableNamespacesByDefault\x18\x02 \x01(\v2\x1a.google.protobuf.BoolValueR\x19enableNamespacesByDefault\x12.\n" +
- "\x12reinvocationPolicy\x18\x03 \x01(\tR\x12reinvocationPolicy\x12e\n" +
- "\x13neverInjectSelector\x18\v \x03(\v23.k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelectorR\x13neverInjectSelector\x12g\n" +
- "\x14alwaysInjectSelector\x18\f \x03(\v23.k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelectorR\x14alwaysInjectSelector\x12L\n" +
+ "\x12reinvocationPolicy\x18\x03 \x01(\tR\x12reinvocationPolicy\x12I\n" +
+ "\x13neverInjectSelector\x18\v \x03(\v2\x17.google.protobuf.StructR\x13neverInjectSelector\x12K\n" +
+ "\x14alwaysInjectSelector\x18\f \x03(\v2\x17.google.protobuf.StructR\x14alwaysInjectSelector\x12L\n" +
"\x13rewriteAppHTTPProbe\x18\x10 \x01(\v2\x1a.google.protobuf.BoolValueR\x13rewriteAppHTTPProbe\x12I\n" +
"\x13injectedAnnotations\x18\x13 \x01(\v2\x17.google.protobuf.StructR\x13injectedAnnotations\x12\"\n" +
"\finjectionURL\x18\x16 \x01(\tR\finjectionURL\x125\n" +
@@ -1383,12 +1452,13 @@ const filePkgApisValuesTypesProtoRawDesc = "" +
"\rvalidationURL\x18\x02 \x01(\tR\rvalidationURL\x12P\n" +
"\x15enableIstioConfigCRDs\x18\x03 \x01(\v2\x1a.google.protobuf.BoolValueR\x15enableIstioConfigCRDs\x12D\n" +
"\x0fvalidateGateway\x18\x04 \x01(\v2\x1a.google.protobuf.BoolValueR\x0fvalidateGateway\x12.\n" +
- "\x12validationCABundle\x18\x05 \x01(\tR\x12validationCABundle\"\xc2\x01\n" +
+ "\x12validationCABundle\x18\x05 \x01(\tR\x12validationCABundle\"\x9e\x02\n" +
"\x12IstiodRemoteConfig\x12\"\n" +
"\finjectionURL\x18\x01 \x01(\tR\finjectionURL\x12$\n" +
"\rinjectionPath\x18\x02 \x01(\tR\rinjectionPath\x12,\n" +
"\x11injectionCABundle\x18\x03 \x01(\tR\x11injectionCABundle\x124\n" +
- "\aenabled\x18\x05 \x01(\v2\x1a.google.protobuf.BoolValueR\aenabled\"\xd7\b\n" +
+ "\aenabled\x18\x05 \x01(\v2\x1a.google.protobuf.BoolValueR\aenabled\x12Z\n" +
+ "\x1aenabledLocalInjectorIstiod\x18\x06 \x01(\v2\x1a.google.protobuf.BoolValueR\x1aenabledLocalInjectorIstiod\"\xd7\b\n" +
"\x06Values\x124\n" +
"\x03cni\x18\x02 \x01(\v2\".istio.operator.v1alpha1.CNIConfigR\x03cni\x12C\n" +
"\bgateways\x18\x05 \x01(\v2'.istio.operator.v1alpha1.GatewaysConfigR\bgateways\x12=\n" +
@@ -1417,15 +1487,22 @@ const filePkgApisValuesTypesProtoRawDesc = "" +
"\vIntOrString\x12\x12\n" +
"\x04type\x18\x01 \x01(\x03R\x04type\x123\n" +
"\x06intVal\x18\x02 \x01(\v2\x1b.google.protobuf.Int32ValueR\x06intVal\x124\n" +
- "\x06strVal\x18\x03 \x01(\v2\x1c.google.protobuf.StringValueR\x06strVal\"\xfe\x02\n" +
+ "\x06strVal\x18\x03 \x01(\v2\x1c.google.protobuf.StringValueR\x06strVal\"\xd4\x02\n" +
"\x0eWaypointConfig\x12@\n" +
- "\tresources\x18\x01 \x01(\v2\".istio.operator.v1alpha1.ResourcesR\tresources\x128\n" +
- "\baffinity\x18\x02 \x01(\v2\x1c.k8s.io.api.core.v1.AffinityR\baffinity\x12j\n" +
- "\x19topologySpreadConstraints\x18\x03 \x03(\v2,.k8s.io.api.core.v1.TopologySpreadConstraintR\x19topologySpreadConstraints\x12D\n" +
- "\fnodeSelector\x18\x04 \x01(\v2 .k8s.io.api.core.v1.NodeSelectorR\fnodeSelector\x12>\n" +
+ "\tresources\x18\x01 \x01(\v2\".istio.operator.v1alpha1.ResourcesR\tresources\x123\n" +
+ "\baffinity\x18\x02 \x01(\v2\x17.google.protobuf.StructR\baffinity\x12U\n" +
+ "\x19topologySpreadConstraints\x18\x03 \x03(\v2\x17.google.protobuf.StructR\x19topologySpreadConstraints\x12;\n" +
+ "\fnodeSelector\x18\x04 \x01(\v2\x17.google.protobuf.StructR\fnodeSelector\x127\n" +
"\n" +
- "toleration\x18\x05 \x03(\v2\x1e.k8s.io.api.core.v1.TolerationR\n" +
- "toleration*J\n" +
+ "toleration\x18\x05 \x03(\v2\x17.google.protobuf.StructR\n" +
+ "toleration\"K\n" +
+ "\x13NetworkPolicyConfig\x124\n" +
+ "\aenabled\x18\x01 \x01(\v2\x1a.google.protobuf.BoolValueR\aenabled*C\n" +
+ "\rResourceScope\x12\r\n" +
+ "\tundefined\x10\x00\x12\a\n" +
+ "\x03all\x10\x01\x12\v\n" +
+ "\acluster\x10\x02\x12\r\n" +
+ "\tnamespace\x10\x03*J\n" +
"\x15ingressControllerMode\x12\x0f\n" +
"\vUNSPECIFIED\x10\x00\x12\v\n" +
"\aDEFAULT\x10\x01\x12\n" +
@@ -1474,6 +1551,9 @@ type CNIGlobalConfig struct { // Default k8s resources settings for all Istio co
// An empty value means it is a vanilla Kubernetes distribution, therefore no special
// treatment will be considered.
Platform *string `json:"platform,omitempty"`
+
+ // Specifies whether native nftables rules should be used instead of iptables rules for traffic redirection.
+ NativeNftables *bool `json:"nativeNftables,omitempty"`
}
// Resource describes the source of configuration
@@ -1569,6 +1649,30 @@ const (
MeshConfigInboundTrafficPolicyModeLocalhost MeshConfigInboundTrafficPolicyMode = "LOCALHOST"
)
+// The scope of the matching service. Used to determine if the service is available locally
+// (cluster local) or globally (mesh-wide).
+// +kubebuilder:validation:Enum=LOCAL;GLOBAL
+type MeshConfigServiceScopeConfigsScope string
+
+const (
+ MeshConfigServiceScopeConfigsScopeLocal MeshConfigServiceScopeConfigsScope = "LOCAL"
+ MeshConfigServiceScopeConfigsScopeGlobal MeshConfigServiceScopeConfigsScope = "GLOBAL"
+)
+
+// Available trace context options for handling different trace header formats.
+// +kubebuilder:validation:Enum=USE_B3;USE_B3_WITH_W3C_PROPAGATION
+type MeshConfigExtensionProviderZipkinTracingProviderTraceContextOption string
+
+const (
+ // Use B3 headers only (default behavior).
+ MeshConfigExtensionProviderZipkinTracingProviderTraceContextOptionUseB3 MeshConfigExtensionProviderZipkinTracingProviderTraceContextOption = "USE_B3"
+ // Enable B3 and W3C dual header support:
+ // - For downstream: Extract from B3 headers first, fallback to W3C traceparent if B3 is unavailable.
+ // - For upstream: Inject both B3 and W3C traceparent headers.
+ // When this option is NOT set, only B3 headers are used for both extraction and injection.
+ MeshConfigExtensionProviderZipkinTracingProviderTraceContextOptionUseB3WithW3cPropagation MeshConfigExtensionProviderZipkinTracingProviderTraceContextOption = "USE_B3_WITH_W3C_PROPAGATION"
+)
+
// TraceContext selects the context propagation headers used for
// distributed tracing.
// +kubebuilder:validation:Enum=UNSPECIFIED;W3C_TRACE_CONTEXT;GRPC_BIN;CLOUD_TRACE_CONTEXT;B3
@@ -1642,6 +1746,14 @@ type MeshConfig struct {
// Connection timeout used by Envoy. (MUST be >=1ms)
// Default timeout is 10s.
ConnectTimeout *metav1.Duration `json:"connectTimeout,omitempty"`
+ // Idle timeout configured on Envoy proxies for their connection pools to ztunnel via HBONE.
+ // This controls how long Envoy will keep idle connections to ztunnel before closing them.
+ // Note: This setting is applied only on the Envoy proxy side; ztunnel does not use it.
+ // Default timeout is 1 hour (3600s).
+ // For environments with aggressive IP address reuse, it is recommended to set
+ // this to a value less than the CNI IP cooldown period to prevent stale connection reuse.
+ // For example, if your CNI has a 30s cooldown period, setting this to 15s is recommended.
+ HboneIdleTimeout *metav1.Duration `json:"hboneIdleTimeout,omitempty"`
// +hidefromdoc
// Automatic protocol detection uses a set of heuristics to
// determine whether the connection is using TLS or not (on the
@@ -1857,6 +1969,8 @@ type MeshConfig struct {
// +hidefromdoc
// Settings to be applied to select services.
ServiceSettings []*MeshConfigServiceSettings `json:"serviceSettings,omitempty"`
+ // Scope to be applied to select services.
+ ServiceScopeConfigs []*MeshConfigServiceScopeConfigs `json:"serviceScopeConfigs,omitempty"`
// If enabled, Istio agent will merge metrics exposed by the application with metrics from Envoy
// and Istio agent. The sidecar injection will replace `prometheus.io` annotations present on the pod
// and redirect them towards Istio agent, which will then merge metrics of from the application with Istio metrics.
@@ -1963,7 +2077,6 @@ type MeshConfig struct {
// Note: Mesh mTLS does not respect ECDH curves.
MeshMTLS *MeshConfigTLSConfig `json:"meshMTLS,omitempty"`
// Configuration of TLS for all traffic except for ISTIO_MUTUAL mode.
- // Currently, this supports configuration of ecdhCurves and cipherSuites only.
// For ISTIO_MUTUAL TLS settings, use meshMTLS configuration.
TlsDefaults *MeshConfigTLSConfig `json:"tlsDefaults,omitempty"`
}
@@ -2068,6 +2181,14 @@ type MeshConfigCertificateData struct {
// - "bar.baz.svc.cluster.local"
//
// ```
+//
+// When in ambient mode, if ServiceSettings are defined they will be considered in addition to the
+// ServiceScopeConfigs. If a service is defined by ServiceSetting to be cluster local and matches a
+// global service scope selector, the service will be considered cluster local. If a service is
+// considered global by ServiceSettings and does not match a global service scope selector
+// the serive will be considered local. Local scope takes precedence over global scope. Since
+// ServiceScopeConfigs is local by default, all services are considered local unless it is considered
+// global by ServiceSettings AND ServiceScopeConfigs.
type MeshConfigServiceSettings struct {
// The settings to apply to the selected services.
Settings *MeshConfigServiceSettingsSettings `json:"settings,omitempty"`
@@ -2078,6 +2199,43 @@ type MeshConfigServiceSettings struct {
Hosts []string `json:"hosts,omitempty"`
}
+// Configuration for ambient mode multicluster service scope. This setting allows mesh administrators
+// to define the criteria by which the cluster's control plane determines which services in other
+// clusters in the mesh are treated as global (accessible across multiple clusters) versus local
+// (restricted to a single cluster). The configuration can be applied to services based on namespace
+// and/or other matching criteria. This is particularly useful in multicluster service mesh deployments
+// to control service visibility and access across clusters. This API is not intended to enforce
+// security policies. Resources like DestinationRules should be used to enforce authorization policies.
+// If a service matches a global service scope selector, the service's endpoints will be globally
+// exposed. If a service is locally scoped, its endpoints will only be exposed to local cluster
+// services.
+//
+// For example, the following configures the scope of all services with the "istio.io/global" label
+// in matching namespaces to be available globally:
+//
+// ```yaml
+// serviceScopeConfigs:
+// - namespacesSelector:
+// matchExpressions:
+// - key: istio.io/global
+// operator: In
+// values: [true]
+// servicesSelector:
+// matchExpressions:
+// - key: istio.io/global
+// operator: Exists
+// scope: GLOBAL
+//
+// ```
+type MeshConfigServiceScopeConfigs struct {
+ // Match expression for namespaces.
+ NamespaceSelector *metav1.LabelSelector `json:"namespaceSelector,omitempty"`
+ // Match expression for serivces.
+ ServicesSelector *metav1.LabelSelector `json:"servicesSelector,omitempty"`
+ // Specifics the available scope for matching services.
+ Scope MeshConfigServiceScopeConfigsScope `json:"scope,omitempty"`
+}
+
type MeshConfigCA struct {
// REQUIRED. Address of the CA server implementing the Istio CA gRPC API.
// Can be IP address or a fully qualified DNS name with port
@@ -2100,7 +2258,7 @@ type MeshConfigCA struct {
IstiodSide *bool `json:"istiodSide,omitempty"`
}
-// +kubebuilder:validation:XValidation:message="At most one of [envoyExtAuthzHttp envoyExtAuthzGrpc zipkin lightstep datadog stackdriver opencensus skywalking opentelemetry prometheus envoyFileAccessLog envoyHttpAls envoyTcpAls envoyOtelAls] should be set",rule="(has(self.envoyExtAuthzHttp)?1:0) + (has(self.envoyExtAuthzGrpc)?1:0) + (has(self.zipkin)?1:0) + (has(self.lightstep)?1:0) + (has(self.datadog)?1:0) + (has(self.stackdriver)?1:0) + (has(self.opencensus)?1:0) + (has(self.skywalking)?1:0) + (has(self.opentelemetry)?1:0) + (has(self.prometheus)?1:0) + (has(self.envoyFileAccessLog)?1:0) + (has(self.envoyHttpAls)?1:0) + (has(self.envoyTcpAls)?1:0) + (has(self.envoyOtelAls)?1:0) <= 1"
+// +kubebuilder:validation:XValidation:message="At most one of [envoyExtAuthzHttp envoyExtAuthzGrpc zipkin lightstep datadog stackdriver opencensus skywalking opentelemetry prometheus envoyFileAccessLog envoyHttpAls envoyTcpAls envoyOtelAls sds] should be set",rule="(has(self.envoyExtAuthzHttp)?1:0) + (has(self.envoyExtAuthzGrpc)?1:0) + (has(self.zipkin)?1:0) + (has(self.lightstep)?1:0) + (has(self.datadog)?1:0) + (has(self.stackdriver)?1:0) + (has(self.opencensus)?1:0) + (has(self.skywalking)?1:0) + (has(self.opentelemetry)?1:0) + (has(self.prometheus)?1:0) + (has(self.envoyFileAccessLog)?1:0) + (has(self.envoyHttpAls)?1:0) + (has(self.envoyTcpAls)?1:0) + (has(self.envoyOtelAls)?1:0) + (has(self.sds)?1:0) <= 1"
type MeshConfigExtensionProvider struct {
// REQUIRED. A unique name identifying the extension provider.
// +kubebuilder:validation:Required
@@ -2156,6 +2314,12 @@ type MeshConfigExtensionProvider struct {
// Configures an Envoy Open Telemetry Access Logging Service provider.
EnvoyOtelAls *MeshConfigExtensionProviderEnvoyOpenTelemetryLogProvider `json:"envoyOtelAls,omitempty"`
+
+ // Configures an Extension Provider for SDS. This can be used to
+ // configure an external SDS service to supply secrets for certain Gateways for example.
+ // This is useful for scenarios where the secrets are stored in an external secret store like Vault.
+ // The secret should be configured with sds://provider-name format.
+ Sds *MeshConfigExtensionProviderSDSProvider `json:"sds,omitempty"`
}
// Holds the name references to the providers that will be used by default
@@ -2391,6 +2555,16 @@ type MeshConfigExtensionProviderZipkinTracingProvider struct {
// Optional. Specifies the endpoint of Zipkin API.
// The default value is "/api/v2/spans".
Path *string `json:"path,omitempty"`
+ // Optional. Determines which trace context format to use for trace header extraction and propagation.
+ // This controls both downstream request header extraction and upstream request header injection.
+ // The default value is USE_B3 to maintain backward compatibility.
+ TraceContextOption MeshConfigExtensionProviderZipkinTracingProviderTraceContextOption `json:"traceContextOption,omitempty"`
+ // Optional. The timeout for the HTTP request to the Zipkin collector.
+ // If not specified, the default timeout from Envoy's configuration will be used (which is 5 seconds currently).
+ Timeout *metav1.Duration `json:"timeout,omitempty"`
+ // Optional. Additional HTTP headers to include in the request to the Zipkin collector.
+ // These headers will be added to the HTTP request when sending spans to the collector.
+ Headers []*MeshConfigExtensionProviderHttpHeader `json:"headers,omitempty"`
}
// Defines configuration for a Lightstep tracer.
@@ -2767,6 +2941,24 @@ type MeshConfigExtensionProviderOpenTelemetryTracingProvider struct {
DynatraceSampler *MeshConfigExtensionProviderOpenTelemetryTracingProviderDynatraceSampler `json:"dynatraceSampler,omitempty"`
}
+// Defines configuration for an Gateway SDS provider.
+type MeshConfigExtensionProviderSDSProvider struct {
+ // REQUIRED. Specifies the name of the provider. This should be used to configure the Gateway SDS.
+ // +kubebuilder:validation:Required
+ Name *string `json:"name"`
+ // REQUIRED. Specifies the service that implements the SDS service.
+ // The format is `[/]`. The specification of `` is required only when it is insufficient
+ // to unambiguously resolve a service in the service registry. The `` is a fully qualified host name of a
+ // service defined by the Kubernetes service or ServiceEntry.
+ //
+ // Example: "gateway-sds.foo.svc.cluster.local" or "bar/gateway-sds.example.com".
+ // +kubebuilder:validation:Required
+ Service *string `json:"service"`
+ // REQUIRED. Specifies the port of the service.
+ // +kubebuilder:validation:Required
+ Port *uint32 `json:"port"`
+}
+
// Defines configuration for an HTTP service that can be used by an Extension Provider.
// that does communication via HTTP.
type MeshConfigExtensionProviderHttpService struct {
@@ -2943,13 +3135,14 @@ type MeshConfigExtensionProviderResourceDetectorsDynatraceResourceDetector struc
const fileMeshV1alpha1ConfigProtoRawDesc = "" +
"\n" +
- "\x1amesh/v1alpha1/config.proto\x12\x13istio.mesh.v1alpha1\x1a\x1egoogle/protobuf/duration.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1egoogle/protobuf/wrappers.proto\x1a\x19mesh/v1alpha1/proxy.proto\x1a*networking/v1alpha3/destination_rule.proto\x1a)networking/v1alpha3/virtual_service.proto\"\xebh\n" +
+ "\x1amesh/v1alpha1/config.proto\x12\x13istio.mesh.v1alpha1\x1a\x1egoogle/protobuf/duration.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1egoogle/protobuf/wrappers.proto\x1a\x19mesh/v1alpha1/proxy.proto\x1a*networking/v1alpha3/destination_rule.proto\x1a)networking/v1alpha3/virtual_service.proto\"\x83q\n" +
"\n" +
"MeshConfig\x12*\n" +
"\x11proxy_listen_port\x18\x04 \x01(\x05R\x0fproxyListenPort\x129\n" +
"\x19proxy_inbound_listen_port\x18A \x01(\x05R\x16proxyInboundListenPort\x12&\n" +
"\x0fproxy_http_port\x18\x05 \x01(\x05R\rproxyHttpPort\x12B\n" +
- "\x0fconnect_timeout\x18\x06 \x01(\v2\x19.google.protobuf.DurationR\x0econnectTimeout\x12W\n" +
+ "\x0fconnect_timeout\x18\x06 \x01(\v2\x19.google.protobuf.DurationR\x0econnectTimeout\x12G\n" +
+ "\x12hbone_idle_timeout\x18F \x01(\v2\x19.google.protobuf.DurationR\x10hboneIdleTimeout\x12W\n" +
"\x1aprotocol_detection_timeout\x18* \x01(\v2\x19.google.protobuf.DurationR\x18protocolDetectionTimeout\x12o\n" +
"\rtcp_keepalive\x18\x1c \x01(\v2J.istio.networking.v1alpha3.ConnectionPoolSettings.TCPSettings.TcpKeepaliveR\ftcpKeepalive\x12#\n" +
"\ringress_class\x18\a \x01(\tR\fingressClass\x12'\n" +
@@ -2980,7 +3173,8 @@ const fileMeshV1alpha1ConfigProtoRawDesc = "" +
"\x19inbound_cluster_stat_name\x18, \x01(\tR\x16inboundClusterStatName\x12;\n" +
"\x1aoutbound_cluster_stat_name\x18- \x01(\tR\x17outboundClusterStatName\x12H\n" +
"\fcertificates\x18/ \x03(\v2 .istio.mesh.v1alpha1.CertificateB\x02\x18\x01R\fcertificates\x12Z\n" +
- "\x10service_settings\x182 \x03(\v2/.istio.mesh.v1alpha1.MeshConfig.ServiceSettingsR\x0fserviceSettings\x12R\n" +
+ "\x10service_settings\x182 \x03(\v2/.istio.mesh.v1alpha1.MeshConfig.ServiceSettingsR\x0fserviceSettings\x12g\n" +
+ "\x15service_scope_configs\x18C \x03(\v23.istio.mesh.v1alpha1.MeshConfig.ServiceScopeConfigsR\x13serviceScopeConfigs\x12R\n" +
"\x17enable_prometheus_merge\x183 \x01(\v2\x1a.google.protobuf.BoolValueR\x15enablePrometheusMerge\x12_\n" +
"\x1cverify_certificate_at_client\x186 \x01(\v2\x1a.google.protobuf.BoolValueB\x02\x18\x01R\x19verifyCertificateAtClient\x122\n" +
"\x02ca\x187 \x01(\v2\".istio.mesh.v1alpha1.MeshConfig.CAR\x02ca\x12b\n" +
@@ -3011,13 +3205,21 @@ const fileMeshV1alpha1ConfigProtoRawDesc = "" +
"\bsettings\x18\x01 \x01(\v28.istio.mesh.v1alpha1.MeshConfig.ServiceSettings.SettingsR\bsettings\x12\x14\n" +
"\x05hosts\x18\x02 \x03(\tR\x05hosts\x1a/\n" +
"\bSettings\x12#\n" +
- "\rcluster_local\x18\x01 \x01(\bR\fclusterLocal\x1a\xd4\x01\n" +
+ "\rcluster_local\x18\x01 \x01(\bR\fclusterLocal\x1a\xaa\x02\n" +
+ "\x13ServiceScopeConfigs\x12Q\n" +
+ "\x12namespace_selector\x18\x01 \x01(\v2\".istio.mesh.v1alpha1.LabelSelectorR\x11namespaceSelector\x12O\n" +
+ "\x11services_selector\x18\x02 \x01(\v2\".istio.mesh.v1alpha1.LabelSelectorR\x10servicesSelector\x12O\n" +
+ "\x05scope\x18\x03 \x01(\x0e29.istio.mesh.v1alpha1.MeshConfig.ServiceScopeConfigs.ScopeR\x05scope\"\x1e\n" +
+ "\x05Scope\x12\t\n" +
+ "\x05LOCAL\x10\x00\x12\n" +
+ "\n" +
+ "\x06GLOBAL\x10\x01\x1a\xd4\x01\n" +
"\x02CA\x12\x18\n" +
"\aaddress\x18\x01 \x01(\tR\aaddress\x12O\n" +
"\ftls_settings\x18\x02 \x01(\v2,.istio.networking.v1alpha3.ClientTLSSettingsR\vtlsSettings\x12B\n" +
"\x0frequest_timeout\x18\x03 \x01(\v2\x19.google.protobuf.DurationR\x0erequestTimeout\x12\x1f\n" +
"\vistiod_side\x18\x04 \x01(\bR\n" +
- "istiodSide\x1a\xcc=\n" +
+ "istiodSide\x1a\xcfA\n" +
"\x11ExtensionProvider\x12\x12\n" +
"\x04name\x18\x01 \x01(\tR\x04name\x12\x8b\x01\n" +
"\x14envoy_ext_authz_http\x18\x02 \x01(\v2X.istio.mesh.v1alpha1.MeshConfig.ExtensionProvider.EnvoyExternalAuthorizationHttpProviderH\x00R\x11envoyExtAuthzHttp\x12\x8b\x01\n" +
@@ -3040,7 +3242,8 @@ const fileMeshV1alpha1ConfigProtoRawDesc = "" +
"\x15envoy_file_access_log\x18\v \x01(\v2L.istio.mesh.v1alpha1.MeshConfig.ExtensionProvider.EnvoyFileAccessLogProviderH\x00R\x12envoyFileAccessLog\x12t\n" +
"\x0eenvoy_http_als\x18\f \x01(\v2L.istio.mesh.v1alpha1.MeshConfig.ExtensionProvider.EnvoyHttpGrpcV3LogProviderH\x00R\fenvoyHttpAls\x12q\n" +
"\renvoy_tcp_als\x18\r \x01(\v2K.istio.mesh.v1alpha1.MeshConfig.ExtensionProvider.EnvoyTcpGrpcV3LogProviderH\x00R\venvoyTcpAls\x12w\n" +
- "\x0eenvoy_otel_als\x18\x0e \x01(\v2O.istio.mesh.v1alpha1.MeshConfig.ExtensionProvider.EnvoyOpenTelemetryLogProviderH\x00R\fenvoyOtelAls\x1a\xab\x01\n" +
+ "\x0eenvoy_otel_als\x18\x0e \x01(\v2O.istio.mesh.v1alpha1.MeshConfig.ExtensionProvider.EnvoyOpenTelemetryLogProviderH\x00R\fenvoyOtelAls\x12Q\n" +
+ "\x03sds\x18\x10 \x01(\v2=.istio.mesh.v1alpha1.MeshConfig.ExtensionProvider.SDSProviderH\x00R\x03sds\x1a\xab\x01\n" +
"%EnvoyExternalAuthorizationRequestBody\x12*\n" +
"\x11max_request_bytes\x18\x01 \x01(\rR\x0fmaxRequestBytes\x122\n" +
"\x15allow_partial_message\x18\x02 \x01(\bR\x13allowPartialMessage\x12\"\n" +
@@ -3072,13 +3275,20 @@ const fileMeshV1alpha1ConfigProtoRawDesc = "" +
"\tfail_open\x18\x03 \x01(\bR\bfailOpen\x12*\n" +
"\x11clear_route_cache\x18\a \x01(\bR\x0fclearRouteCache\x12&\n" +
"\x0fstatus_on_error\x18\x04 \x01(\tR\rstatusOnError\x12\x99\x01\n" +
- "\x1dinclude_request_body_in_check\x18\x06 \x01(\v2W.istio.mesh.v1alpha1.MeshConfig.ExtensionProvider.EnvoyExternalAuthorizationRequestBodyR\x19includeRequestBodyInCheck\x1a\xb2\x01\n" +
+ "\x1dinclude_request_body_in_check\x18\x06 \x01(\v2W.istio.mesh.v1alpha1.MeshConfig.ExtensionProvider.EnvoyExternalAuthorizationRequestBodyR\x19includeRequestBodyInCheck\x1a\x91\x04\n" +
"\x15ZipkinTracingProvider\x12\x18\n" +
"\aservice\x18\x01 \x01(\tR\aservice\x12\x12\n" +
"\x04port\x18\x02 \x01(\rR\x04port\x12$\n" +
"\x0emax_tag_length\x18\x03 \x01(\rR\fmaxTagLength\x121\n" +
"\x15enable_64bit_trace_id\x18\x04 \x01(\bR\x12enable64bitTraceId\x12\x12\n" +
- "\x04path\x18\x05 \x01(\tR\x04path\x1a\x91\x01\n" +
+ "\x04path\x18\x05 \x01(\tR\x04path\x12\x8c\x01\n" +
+ "\x14trace_context_option\x18\x06 \x01(\x0e2Z.istio.mesh.v1alpha1.MeshConfig.ExtensionProvider.ZipkinTracingProvider.TraceContextOptionR\x12traceContextOption\x123\n" +
+ "\atimeout\x18\a \x01(\v2\x19.google.protobuf.DurationR\atimeout\x12V\n" +
+ "\aheaders\x18\b \x03(\v2<.istio.mesh.v1alpha1.MeshConfig.ExtensionProvider.HttpHeaderR\aheaders\"A\n" +
+ "\x12TraceContextOption\x12\n" +
+ "\n" +
+ "\x06USE_B3\x10\x00\x12\x1f\n" +
+ "\x1bUSE_B3_WITH_W3C_PROPAGATION\x10\x01\x1a\x91\x01\n" +
"\x18LightstepTracingProvider\x12\x18\n" +
"\aservice\x18\x01 \x01(\tR\aservice\x12\x12\n" +
"\x04port\x18\x02 \x01(\rR\x04port\x12!\n" +
@@ -3167,7 +3377,11 @@ const fileMeshV1alpha1ConfigProtoRawDesc = "" +
"\x04port\x18\x02 \x01(\rR\x04port\x12Q\n" +
"\x04http\x18\x03 \x01(\v2=.istio.mesh.v1alpha1.MeshConfig.ExtensionProvider.HttpServiceR\x04httpB\n" +
"\n" +
- "\bsampling\x1a\xae\x01\n" +
+ "\bsampling\x1aO\n" +
+ "\vSDSProvider\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x12\x18\n" +
+ "\aservice\x18\x02 \x01(\tR\aservice\x12\x12\n" +
+ "\x04port\x18\x03 \x01(\rR\x04port\x1a\xae\x01\n" +
"\vHttpService\x12\x12\n" +
"\x04path\x18\x01 \x01(\tR\x04path\x123\n" +
"\atimeout\x18\x02 \x01(\v2\x19.google.protobuf.DurationR\atimeout\x12V\n" +
@@ -3226,7 +3440,7 @@ const fileMeshV1alpha1ConfigProtoRawDesc = "" +
"\x0fH2UpgradePolicy\x12\x12\n" +
"\x0eDO_NOT_UPGRADE\x10\x00\x12\v\n" +
"\aUPGRADE\x10\x01J\x04\b1\x102J\x04\b\x01\x10\x02J\x04\b\x02\x10\x03J\x04\b\x03\x10\x04J\x04\b0\x101J\x04\b\x19\x10\x1aJ\x04\b\x1e\x10\x1fJ\x04\b\n" +
- "\x10\vJ\x04\b\v\x10\fJ\x04\b\x0f\x10\x10J\x04\b\x10\x10\x11J\x04\b\x12\x10\x13J\x04\b\x13\x10\x14J\x04\b\x14\x10\x15J\x04\b\x15\x10\x16J\x04\b\x17\x10\x18J\x04\b\x1d\x10\x1eJ\x04\b5\x106J\x04\b%\x10&J\x04\b&\x10'J\x04\b'\x10(R\rthrift_configR\x12mixer_check_serverR\x13mixer_report_serverR\x15disable_policy_checksR\x1adisable_mixer_http_reportsR\x16policy_check_fail_openR%sidecar_to_telemetry_session_affinityR\vauth_policyR\x11rds_refresh_delayR\rmixer_addressR\x1fenable_client_side_policy_checkR\fsds_uds_pathR\x11sds_refresh_delayR\x16enable_sds_token_mountR\x12sds_use_k8s_sa_jwtR\x1atermination_drain_durationR\x14disable_report_batchR\x18report_batch_max_entriesR\x15report_batch_max_time\"\x81\x02\n" +
+ "\x10\vJ\x04\b\v\x10\fJ\x04\b\x0f\x10\x10J\x04\b\x10\x10\x11J\x04\b\x12\x10\x13J\x04\b\x13\x10\x14J\x04\b\x14\x10\x15J\x04\b\x15\x10\x16J\x04\b\x17\x10\x18J\x04\b\x1d\x10\x1eJ\x04\b5\x106J\x04\b%\x10&J\x04\b&\x10'J\x04\b'\x10(J\x04\bD\x10EJ\x04\bE\x10FR\rthrift_configR\x12mixer_check_serverR\x13mixer_report_serverR\x15disable_policy_checksR\x1adisable_mixer_http_reportsR\x16policy_check_fail_openR%sidecar_to_telemetry_session_affinityR\vauth_policyR\x11rds_refresh_delayR\rmixer_addressR\x1fenable_client_side_policy_checkR\fsds_uds_pathR\x11sds_refresh_delayR\x16enable_sds_token_mountR\x12sds_use_k8s_sa_jwtR\x1atermination_drain_durationR\x14disable_report_batchR\x18report_batch_max_entriesR\x15report_batch_max_timeR\x13file_flush_intervalR\x13file_flush_min_size\"\x81\x02\n" +
"\rLabelSelector\x12U\n" +
"\vmatchLabels\x18\x01 \x03(\v23.istio.mesh.v1alpha1.LabelSelector.MatchLabelsEntryR\vmatchLabels\x12Y\n" +
"\x10matchExpressions\x18\x02 \x03(\v2-.istio.mesh.v1alpha1.LabelSelectorRequirementR\x10matchExpressions\x1a>\n" +
@@ -3818,7 +4032,7 @@ type MeshConfigProxyConfig struct {
// ```yaml
// proxyHeaders:
//
- // perserveHttp1HeaderCase: true
+ // preserveHttp1HeaderCase: true
//
// ```
//
@@ -3841,6 +4055,19 @@ type MeshConfigProxyConfig struct {
//
// ```
ProxyHeaders *ProxyConfigProxyHeaders `json:"proxyHeaders,omitempty"`
+ // File flush interval for envoy flushes buffers to disk in milliseconds.
+ // The duration needs to be set to a value greater than or equal to 1 millisecond.
+ // Default is 1000ms.
+ // Optional.
+ FileFlushInterval *metav1.Duration `json:"fileFlushInterval,omitempty"`
+ // File flush buffer size for envoy flushes buffers to disk in kilobytes.
+ // Defaults to 64.
+ // Optional.
+ FileFlushMinSizeKb *uint32 `json:"fileFlushMinSizeKb,omitempty"`
+ // Offer HTTP compression for stats
+ // Defaults to true.
+ // Optional.
+ StatsCompression *bool `json:"statsCompression,omitempty"`
}
type RemoteService struct {
@@ -4051,6 +4278,15 @@ type ProxyConfigProxyHeaders struct {
// requests and automatically normalize headers to lowercase, ensuring compliance with HTTP/2
// standards.
PreserveHttp1HeaderCase *bool `json:"preserveHttp1HeaderCase,omitempty"`
+ // Controls the `X-Forwarded-Host` header. If enabled, the `X-Forwarded-Host` header is appended
+ // with the original host when it is rewritten.
+ // This header is disabled by default.
+ XForwardedHost *ProxyConfigProxyHeadersXForwardedHost `json:"xForwardedHost,omitempty"`
+ // Controls the `X-Forwarded-Port` header. If enabled, the `X-Forwarded-Port` header is header with the port value
+ // client used to connect to Envoy. It will be ignored if the “x-forwarded-port“ header has been set by any
+ // trusted proxy in front of Envoy.
+ // This header is disabled by default.
+ XForwardedPort *ProxyConfigProxyHeadersXForwardedPort `json:"xForwardedPort,omitempty"`
}
type ProxyConfigProxyHeadersServer struct {
@@ -4067,6 +4303,14 @@ type ProxyConfigProxyHeadersAttemptCount struct {
Disabled *bool `json:"disabled,omitempty"`
}
+type ProxyConfigProxyHeadersXForwardedHost struct {
+ Enabled *bool `json:"enabled,omitempty"`
+}
+
+type ProxyConfigProxyHeadersXForwardedPort struct {
+ Enabled *bool `json:"enabled,omitempty"`
+}
+
type ProxyConfigProxyHeadersEnvoyDebugHeaders struct {
Disabled *bool `json:"disabled,omitempty"`
}
@@ -4169,7 +4413,7 @@ const fileMeshV1alpha1ProxyProtoRawDesc = "" +
"poll_delay\x18\x01 \x01(\v2\x19.google.protobuf.DurationR\tpollDelay\x126\n" +
"\bfallback\x18\x02 \x01(\v2\x1a.google.protobuf.BoolValueR\bfallbackB\n" +
"\n" +
- "\bprovider\"\xc3#\n" +
+ "\bprovider\"\xeb'\n" +
"\vProxyConfig\x12\x1f\n" +
"\vconfig_path\x18\x01 \x01(\tR\n" +
"configPath\x12\x1f\n" +
@@ -4210,7 +4454,10 @@ const fileMeshV1alpha1ProxyProtoRawDesc = "" +
"\x13ca_certificates_pem\x18\" \x03(\tR\x11caCertificatesPem\x12:\n" +
"\x05image\x18# \x01(\v2$.istio.networking.v1beta1.ProxyImageR\x05image\x12Y\n" +
"\x14private_key_provider\x18& \x01(\v2'.istio.mesh.v1alpha1.PrivateKeyProviderR\x12privateKeyProvider\x12R\n" +
- "\rproxy_headers\x18' \x01(\v2-.istio.mesh.v1alpha1.ProxyConfig.ProxyHeadersR\fproxyHeaders\x1a@\n" +
+ "\rproxy_headers\x18' \x01(\v2-.istio.mesh.v1alpha1.ProxyConfig.ProxyHeadersR\fproxyHeaders\x12I\n" +
+ "\x13file_flush_interval\x18( \x01(\v2\x19.google.protobuf.DurationR\x11fileFlushInterval\x122\n" +
+ "\x16file_flush_min_size_kb\x18) \x01(\rR\x12fileFlushMinSizeKb\x12G\n" +
+ "\x11stats_compression\x18* \x01(\v2\x1a.google.protobuf.BoolValueR\x10statsCompression\x1a@\n" +
"\x12ProxyMetadataEntry\x12\x10\n" +
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\x1a@\n" +
@@ -4220,7 +4467,7 @@ const fileMeshV1alpha1ProxyProtoRawDesc = "" +
"\x11ProxyStatsMatcher\x12-\n" +
"\x12inclusion_prefixes\x18\x01 \x03(\tR\x11inclusionPrefixes\x12-\n" +
"\x12inclusion_suffixes\x18\x02 \x03(\tR\x11inclusionSuffixes\x12+\n" +
- "\x11inclusion_regexps\x18\x03 \x03(\tR\x10inclusionRegexps\x1a\xc5\f\n" +
+ "\x11inclusion_regexps\x18\x03 \x03(\tR\x10inclusionRegexps\x1a\xa5\x0f\n" +
"\fProxyHeaders\x12a\n" +
"\x15forwarded_client_cert\x18\x01 \x01(\x0e2-.istio.mesh.v1alpha1.ForwardClientCertDetailsR\x13forwardedClientCert\x12\x8f\x01\n" +
"\x1fset_current_client_cert_details\x18\a \x01(\v2I.istio.mesh.v1alpha1.ProxyConfig.ProxyHeaders.SetCurrentClientCertDetailsR\x1bsetCurrentClientCertDetails\x12V\n" +
@@ -4230,14 +4477,20 @@ const fileMeshV1alpha1ProxyProtoRawDesc = "" +
"\rattempt_count\x18\x04 \x01(\v2:.istio.mesh.v1alpha1.ProxyConfig.ProxyHeaders.AttemptCountR\fattemptCount\x12o\n" +
"\x13envoy_debug_headers\x18\x05 \x01(\v2?.istio.mesh.v1alpha1.ProxyConfig.ProxyHeaders.EnvoyDebugHeadersR\x11envoyDebugHeaders\x12\x81\x01\n" +
"\x19metadata_exchange_headers\x18\x06 \x01(\v2E.istio.mesh.v1alpha1.ProxyConfig.ProxyHeaders.MetadataExchangeHeadersR\x17metadataExchangeHeaders\x12W\n" +
- "\x1apreserve_http1_header_case\x18( \x01(\v2\x1a.google.protobuf.BoolValueR\x17preserveHttp1HeaderCase\x1aV\n" +
+ "\x1apreserve_http1_header_case\x18( \x01(\v2\x1a.google.protobuf.BoolValueR\x17preserveHttp1HeaderCase\x12f\n" +
+ "\x10x_forwarded_host\x18) \x01(\v2<.istio.mesh.v1alpha1.ProxyConfig.ProxyHeaders.XForwardedHostR\x0exForwardedHost\x12f\n" +
+ "\x10x_forwarded_port\x18* \x01(\v2<.istio.mesh.v1alpha1.ProxyConfig.ProxyHeaders.XForwardedPortR\x0exForwardedPort\x1aV\n" +
"\x06Server\x126\n" +
"\bdisabled\x18\x01 \x01(\v2\x1a.google.protobuf.BoolValueR\bdisabled\x12\x14\n" +
"\x05value\x18\x02 \x01(\tR\x05value\x1aC\n" +
"\tRequestId\x126\n" +
"\bdisabled\x18\x01 \x01(\v2\x1a.google.protobuf.BoolValueR\bdisabled\x1aF\n" +
"\fAttemptCount\x126\n" +
- "\bdisabled\x18\x01 \x01(\v2\x1a.google.protobuf.BoolValueR\bdisabled\x1aK\n" +
+ "\bdisabled\x18\x01 \x01(\v2\x1a.google.protobuf.BoolValueR\bdisabled\x1aF\n" +
+ "\x0eXForwardedHost\x124\n" +
+ "\aenabled\x18\x01 \x01(\v2\x1a.google.protobuf.BoolValueR\aenabled\x1aF\n" +
+ "\x0eXForwardedPort\x124\n" +
+ "\aenabled\x18\x01 \x01(\v2\x1a.google.protobuf.BoolValueR\aenabled\x1aK\n" +
"\x11EnvoyDebugHeaders\x126\n" +
"\bdisabled\x18\x01 \x01(\v2\x1a.google.protobuf.BoolValueR\bdisabled\x1aq\n" +
"\x17MetadataExchangeHeaders\x12V\n" +
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/api/v1/values_types_extra.go b/vendor/github.com/istio-ecosystem/sail-operator/api/v1/values_types_extra.go
index 637f8db30e..b6f2a5f059 100644
--- a/vendor/github.com/istio-ecosystem/sail-operator/api/v1/values_types_extra.go
+++ b/vendor/github.com/istio-ecosystem/sail-operator/api/v1/values_types_extra.go
@@ -15,6 +15,7 @@
package v1
import (
+ appsv1 "k8s.io/api/apps/v1"
k8sv1 "k8s.io/api/core/v1"
)
@@ -49,6 +50,10 @@ type ZTunnelConfig struct {
// Image name to pull from. Image will be `Hub/Image:Tag-Variant`.
// If Image contains a "/", it will replace the entire `image` in the pod.
Image *string `json:"image,omitempty"`
+ // defines the network this cluster belong to. This name corresponds to the networks in the map of mesh networks.
+ Network *string `json:"network,omitempty"`
+ // K8s affinity to set on the ztunnel Pods. Can be used to exclude ztunnel from being scheduled on specified nodes.
+ Affinity *k8sv1.Affinity `json:"affinity,omitempty"`
// resourceName, if set, will override the naming of resources. If not set, will default to the release name.
// It is recommended to not set this; this is primarily for backwards compatibility.
ResourceName *string `json:"resourceName,omitempty"`
@@ -60,12 +65,20 @@ type ZTunnelConfig struct {
VolumeMounts []k8sv1.VolumeMount `json:"volumeMounts,omitempty"`
// Additional volumes to add to the ztunnel Pod.
Volumes []k8sv1.Volume `json:"volumes,omitempty"`
+ // Tolerations for the ztunnel pod
+ Tolerations []k8sv1.Toleration `json:"tolerations,omitempty"`
// Annotations added to each pod. The default annotations are required for scraping prometheus (in most environments).
PodAnnotations map[string]string `json:"podAnnotations,omitempty"`
// Additional labels to apply on the pod level.
PodLabels map[string]string `json:"podLabels,omitempty"`
// The k8s resource requests and limits for the ztunnel Pods.
Resources *k8sv1.ResourceRequirements `json:"resources,omitempty"`
+ // The resource quotas configuration for ztunnel
+ ResourceQuotas *ResourceQuotas `json:"resourceQuotas,omitempty"`
+ // K8s node selector settings.
+ //
+ // See https://kubernetes.io/docs/user-guide/node-selection/
+ NodeSelector map[string]string `json:"nodeSelector,omitempty"`
// List of secret names to add to the service account as image pull secrets
// to use for pulling any images in pods that reference this ServiceAccount.
// Must be set for any cluster configured with private docker registry.
@@ -82,9 +95,6 @@ type ZTunnelConfig struct {
// The name of the cluster we are installing in. Note this is a user-defined name, which must be consistent
// with Istiod configuration.
MultiCluster *MultiClusterConfig `json:"multiCluster,omitempty"`
- // meshConfig defines runtime configuration of components.
- // For ztunnel, only defaultConfig is used, but this is nested under `meshConfig` for consistency with other components.
- MeshConfig *MeshConfig `json:"meshConfig,omitempty"`
// This value defines:
// 1. how many seconds kube waits for ztunnel pod to gracefully exit before forcibly terminating it (this value)
// 2. how many seconds ztunnel waits to drain its own connections (this value - 1 sec)
@@ -105,6 +115,10 @@ type ZTunnelConfig struct {
LogLevel *string `json:"logLevel,omitempty"`
// Specifies whether istio components should output logs in json format by adding --log_as_json argument to each container.
LogAsJSON *bool `json:"logAsJson,omitempty"`
+ // Set seLinux options for the ztunnel pod
+ SeLinuxOptions *k8sv1.SELinuxOptions `json:"seLinuxOptions,omitempty"`
+ // Defines the update strategy to use when the version in the Ztunnel CR is updated.
+ UpdateStrategy *appsv1.DaemonSetUpdateStrategy `json:"updateStrategy,omitempty"`
}
// ZTunnelGlobalConfig is a subset of the Global Configuration used in the Istio ztunnel chart.
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/api/v1/ztunnel_types.go b/vendor/github.com/istio-ecosystem/sail-operator/api/v1/ztunnel_types.go
new file mode 100644
index 0000000000..802a6dbd95
--- /dev/null
+++ b/vendor/github.com/istio-ecosystem/sail-operator/api/v1/ztunnel_types.go
@@ -0,0 +1,194 @@
+// Copyright Istio 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 v1
+
+import (
+ "time"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+const (
+ ZTunnelKind = "ZTunnel"
+)
+
+// ZTunnelSpec defines the desired state of ZTunnel
+type ZTunnelSpec struct {
+ // +sail:version
+ // Defines the version of Istio to install.
+ // Must be one of: v1.28-latest, v1.28.3, v1.28.2, v1.28.1, v1.28.0, v1.27-latest, v1.27.5, v1.27.4, v1.27.3, v1.27.2, v1.27.1, v1.27.0, master, v1.30-alpha.a30ad733.
+ // +operator-sdk:csv:customresourcedefinitions:type=spec,order=1,displayName="Istio Version",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:fieldGroup:General", "urn:alm:descriptor:com.tectonic.ui:select:v1.28-latest", "urn:alm:descriptor:com.tectonic.ui:select:v1.28.3", "urn:alm:descriptor:com.tectonic.ui:select:v1.28.2", "urn:alm:descriptor:com.tectonic.ui:select:v1.28.1", "urn:alm:descriptor:com.tectonic.ui:select:v1.28.0", "urn:alm:descriptor:com.tectonic.ui:select:v1.27-latest", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.5", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.4", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.3", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.2", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.1", "urn:alm:descriptor:com.tectonic.ui:select:v1.27.0", "urn:alm:descriptor:com.tectonic.ui:select:master", "urn:alm:descriptor:com.tectonic.ui:select:v1.30-alpha.a30ad733"}
+ // +kubebuilder:validation:Enum=v1.28-latest;v1.28.3;v1.28.2;v1.28.1;v1.28.0;v1.27-latest;v1.27.5;v1.27.4;v1.27.3;v1.27.2;v1.27.1;v1.27.0;v1.26-latest;v1.26.8;v1.26.7;v1.26.6;v1.26.5;v1.26.4;v1.26.3;v1.26.2;v1.26.1;v1.26.0;v1.25-latest;v1.25.5;v1.25.4;v1.25.3;v1.25.2;v1.25.1;v1.24-latest;v1.24.6;v1.24.5;v1.24.4;v1.24.3;v1.24.2;v1.24.1;v1.24.0;master;v1.30-alpha.a30ad733
+ // +kubebuilder:default=v1.28.3
+ Version string `json:"version"`
+
+ // Namespace to which the Istio ztunnel component should be installed.
+ // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:io.kubernetes:Namespace"}
+ // +kubebuilder:default=ztunnel
+ Namespace string `json:"namespace"`
+
+ // Defines the values to be passed to the Helm charts when installing Istio ztunnel.
+ // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Helm Values"
+ Values *ZTunnelValues `json:"values,omitempty"`
+}
+
+// ZTunnelStatus defines the observed state of ZTunnel
+type ZTunnelStatus struct {
+ // ObservedGeneration is the most recent generation observed for this
+ // ZTunnel object. It corresponds to the object's generation, which is
+ // updated on mutation by the API Server. The information in the status
+ // pertains to this particular generation of the object.
+ ObservedGeneration int64 `json:"observedGeneration,omitempty"`
+
+ // Represents the latest available observations of the object's current state.
+ Conditions []ZTunnelCondition `json:"conditions,omitempty"`
+
+ // Reports the current state of the object.
+ State ZTunnelConditionReason `json:"state,omitempty"`
+}
+
+// GetCondition returns the condition of the specified type
+func (s *ZTunnelStatus) GetCondition(conditionType ZTunnelConditionType) ZTunnelCondition {
+ if s != nil {
+ for i := range s.Conditions {
+ if s.Conditions[i].Type == conditionType {
+ return s.Conditions[i]
+ }
+ }
+ }
+ return ZTunnelCondition{Type: conditionType, Status: metav1.ConditionUnknown}
+}
+
+// SetCondition sets a specific condition in the list of conditions
+func (s *ZTunnelStatus) SetCondition(condition ZTunnelCondition) {
+ var now time.Time
+ if testTime == nil {
+ now = time.Now()
+ } else {
+ now = *testTime
+ }
+
+ // The lastTransitionTime only gets serialized out to the second. This can
+ // break update skipping, as the time in the resource returned from the client
+ // may not match the time in our cached status during a reconcile. We truncate
+ // here to save any problems down the line.
+ lastTransitionTime := metav1.NewTime(now.Truncate(time.Second))
+
+ for i, prevCondition := range s.Conditions {
+ if prevCondition.Type == condition.Type {
+ if prevCondition.Status != condition.Status {
+ condition.LastTransitionTime = lastTransitionTime
+ } else {
+ condition.LastTransitionTime = prevCondition.LastTransitionTime
+ }
+ s.Conditions[i] = condition
+ return
+ }
+ }
+
+ // If the condition does not exist, initialize the lastTransitionTime
+ condition.LastTransitionTime = lastTransitionTime
+ s.Conditions = append(s.Conditions, condition)
+}
+
+// ZTunnelCondition represents a specific observation of the ZTunnel object's state.
+type ZTunnelCondition struct {
+ // The type of this condition.
+ Type ZTunnelConditionType `json:"type,omitempty"`
+
+ // The status of this condition. Can be True, False or Unknown.
+ Status metav1.ConditionStatus `json:"status,omitempty"`
+
+ // Unique, single-word, CamelCase reason for the condition's last transition.
+ Reason ZTunnelConditionReason `json:"reason,omitempty"`
+
+ // Human-readable message indicating details about the last transition.
+ Message string `json:"message,omitempty"`
+
+ // Last time the condition transitioned from one status to another.
+ // +optional
+ LastTransitionTime metav1.Time `json:"lastTransitionTime,omitzero"`
+}
+
+// ZTunnelConditionType represents the type of the condition. Condition stages are:
+// Installed, Reconciled, Ready
+type ZTunnelConditionType string
+
+// ZTunnelConditionReason represents a short message indicating how the condition came
+// to be in its present state.
+type ZTunnelConditionReason string
+
+const (
+ // ZTunnelConditionReconciled signifies whether the controller has
+ // successfully reconciled the resources defined through the CR.
+ ZTunnelConditionReconciled ZTunnelConditionType = "Reconciled"
+
+ // ZTunnelReasonReconcileError indicates that the reconciliation of the resource has failed, but will be retried.
+ ZTunnelReasonReconcileError ZTunnelConditionReason = "ReconcileError"
+)
+
+const (
+ // ZTunnelConditionReady signifies whether the ztunnel DaemonSet is ready.
+ ZTunnelConditionReady ZTunnelConditionType = "Ready"
+
+ // ZTunnelDaemonSetNotReady indicates that the ztunnel DaemonSet is not ready.
+ ZTunnelDaemonSetNotReady ZTunnelConditionReason = "DaemonSetNotReady"
+
+ // ZTunnelReasonReadinessCheckFailed indicates that the DaemonSet readiness status could not be ascertained.
+ ZTunnelReasonReadinessCheckFailed ZTunnelConditionReason = "ReadinessCheckFailed"
+)
+
+const (
+ // ZTunnelReasonHealthy indicates that the control plane is fully reconciled and that all components are ready.
+ ZTunnelReasonHealthy ZTunnelConditionReason = "Healthy"
+)
+
+// +kubebuilder:object:root=true
+// +kubebuilder:resource:scope=Cluster,categories=istio-io
+// +kubebuilder:subresource:status
+// +kubebuilder:storageversion
+// +kubebuilder:printcolumn:name="Namespace",type="string",JSONPath=".spec.namespace",description="The namespace for the ztunnel component."
+// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description="Whether the Istio ztunnel installation is ready to handle requests."
+// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.state",description="The current state of this object."
+// +kubebuilder:printcolumn:name="Version",type="string",JSONPath=".spec.version",description="The version of the Istio ztunnel installation."
+// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="The age of the object"
+// +kubebuilder:validation:XValidation:rule="self.metadata.name == 'default'",message="metadata.name must be 'default'"
+
+// ZTunnel represents a deployment of the Istio ztunnel component.
+type ZTunnel struct {
+ metav1.TypeMeta `json:",inline"`
+ // +optional
+ metav1.ObjectMeta `json:"metadata"`
+
+ // +kubebuilder:default={version: "v1.28.3", namespace: "ztunnel"}
+ // +optional
+ Spec ZTunnelSpec `json:"spec"`
+
+ // +optional
+ Status ZTunnelStatus `json:"status"`
+}
+
+// +kubebuilder:object:root=true
+
+// ZTunnelList contains a list of ZTunnel
+type ZTunnelList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata"`
+ Items []ZTunnel `json:"items"`
+}
+
+func init() {
+ SchemeBuilder.Register(&ZTunnel{}, &ZTunnelList{})
+}
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/api/v1/zz_generated.deepcopy.go b/vendor/github.com/istio-ecosystem/sail-operator/api/v1/zz_generated.deepcopy.go
index baac7292dc..685cb83cc6 100644
--- a/vendor/github.com/istio-ecosystem/sail-operator/api/v1/zz_generated.deepcopy.go
+++ b/vendor/github.com/istio-ecosystem/sail-operator/api/v1/zz_generated.deepcopy.go
@@ -20,6 +20,7 @@ package v1
import (
"encoding/json"
+ appsv1 "k8s.io/api/apps/v1"
"k8s.io/api/autoscaling/v2"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -27,6 +28,26 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"
)
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Agentgateway) DeepCopyInto(out *Agentgateway) {
+ *out = *in
+ if in.Image != nil {
+ in, out := &in.Image, &out.Image
+ *out = new(string)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Agentgateway.
+func (in *Agentgateway) DeepCopy() *Agentgateway {
+ if in == nil {
+ return nil
+ }
+ out := new(Agentgateway)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ArchConfig) DeepCopyInto(out *ArchConfig) {
*out = *in
@@ -190,6 +211,20 @@ func (in *CNIConfig) DeepCopyInto(out *CNIConfig) {
*out = new(corev1.Affinity)
(*in).DeepCopyInto(*out)
}
+ if in.Env != nil {
+ in, out := &in.Env, &out.Env
+ *out = make(map[string]string, len(*in))
+ for key, val := range *in {
+ (*out)[key] = val
+ }
+ }
+ if in.DaemonSetLabels != nil {
+ in, out := &in.DaemonSetLabels, &out.DaemonSetLabels
+ *out = make(map[string]string, len(*in))
+ for key, val := range *in {
+ (*out)[key] = val
+ }
+ }
if in.PodAnnotations != nil {
in, out := &in.PodAnnotations, &out.PodAnnotations
*out = make(map[string]string, len(*in))
@@ -197,6 +232,13 @@ func (in *CNIConfig) DeepCopyInto(out *CNIConfig) {
(*out)[key] = val
}
}
+ if in.PodLabels != nil {
+ in, out := &in.PodLabels, &out.PodLabels
+ *out = make(map[string]string, len(*in))
+ for key, val := range *in {
+ (*out)[key] = val
+ }
+ }
if in.PspClusterRole != nil {
in, out := &in.PspClusterRole, &out.PspClusterRole
*out = new(string)
@@ -252,6 +294,16 @@ func (in *CNIConfig) DeepCopyInto(out *CNIConfig) {
*out = new(intstr.IntOrString)
**out = **in
}
+ if in.IstioOwnedCNIConfig != nil {
+ in, out := &in.IstioOwnedCNIConfig, &out.IstioOwnedCNIConfig
+ *out = new(bool)
+ **out = **in
+ }
+ if in.IstioOwnedCNIConfigFileName != nil {
+ in, out := &in.IstioOwnedCNIConfigFileName, &out.IstioOwnedCNIConfigFileName
+ *out = new(string)
+ **out = **in
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNIConfig.
@@ -312,6 +364,11 @@ func (in *CNIGlobalConfig) DeepCopyInto(out *CNIGlobalConfig) {
*out = new(string)
**out = **in
}
+ if in.NativeNftables != nil {
+ in, out := &in.NativeNftables, &out.NativeNftables
+ *out = new(bool)
+ **out = **in
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNIGlobalConfig.
@@ -848,6 +905,21 @@ func (in *GlobalConfig) DeepCopyInto(out *GlobalConfig) {
*out = new(string)
**out = **in
}
+ if in.NativeNftables != nil {
+ in, out := &in.NativeNftables, &out.NativeNftables
+ *out = new(bool)
+ **out = **in
+ }
+ if in.NetworkPolicy != nil {
+ in, out := &in.NetworkPolicy, &out.NetworkPolicy
+ *out = new(NetworkPolicyConfig)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.Agentgateway != nil {
+ in, out := &in.Agentgateway, &out.Agentgateway
+ *out = new(Agentgateway)
+ (*in).DeepCopyInto(*out)
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GlobalConfig.
@@ -1473,6 +1545,11 @@ func (in *IstiodRemoteConfig) DeepCopyInto(out *IstiodRemoteConfig) {
*out = new(bool)
**out = **in
}
+ if in.EnabledLocalInjectorIstiod != nil {
+ in, out := &in.EnabledLocalInjectorIstiod, &out.EnabledLocalInjectorIstiod
+ *out = new(bool)
+ **out = **in
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IstiodRemoteConfig.
@@ -1607,6 +1684,11 @@ func (in *MeshConfig) DeepCopyInto(out *MeshConfig) {
*out = new(metav1.Duration)
**out = **in
}
+ if in.HboneIdleTimeout != nil {
+ in, out := &in.HboneIdleTimeout, &out.HboneIdleTimeout
+ *out = new(metav1.Duration)
+ **out = **in
+ }
if in.ProtocolDetectionTimeout != nil {
in, out := &in.ProtocolDetectionTimeout, &out.ProtocolDetectionTimeout
*out = new(metav1.Duration)
@@ -1771,6 +1853,17 @@ func (in *MeshConfig) DeepCopyInto(out *MeshConfig) {
}
}
}
+ if in.ServiceScopeConfigs != nil {
+ in, out := &in.ServiceScopeConfigs, &out.ServiceScopeConfigs
+ *out = make([]*MeshConfigServiceScopeConfigs, len(*in))
+ for i := range *in {
+ if (*in)[i] != nil {
+ in, out := &(*in)[i], &(*out)[i]
+ *out = new(MeshConfigServiceScopeConfigs)
+ (*in).DeepCopyInto(*out)
+ }
+ }
+ }
if in.EnablePrometheusMerge != nil {
in, out := &in.EnablePrometheusMerge, &out.EnablePrometheusMerge
*out = new(bool)
@@ -2023,6 +2116,11 @@ func (in *MeshConfigExtensionProvider) DeepCopyInto(out *MeshConfigExtensionProv
*out = new(MeshConfigExtensionProviderEnvoyOpenTelemetryLogProvider)
(*in).DeepCopyInto(*out)
}
+ if in.Sds != nil {
+ in, out := &in.Sds, &out.Sds
+ *out = new(MeshConfigExtensionProviderSDSProvider)
+ (*in).DeepCopyInto(*out)
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MeshConfigExtensionProvider.
@@ -2788,6 +2886,36 @@ func (in *MeshConfigExtensionProviderResourceDetectorsEnvironmentResourceDetecto
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MeshConfigExtensionProviderSDSProvider) DeepCopyInto(out *MeshConfigExtensionProviderSDSProvider) {
+ *out = *in
+ if in.Name != nil {
+ in, out := &in.Name, &out.Name
+ *out = new(string)
+ **out = **in
+ }
+ if in.Service != nil {
+ in, out := &in.Service, &out.Service
+ *out = new(string)
+ **out = **in
+ }
+ if in.Port != nil {
+ in, out := &in.Port, &out.Port
+ *out = new(uint32)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MeshConfigExtensionProviderSDSProvider.
+func (in *MeshConfigExtensionProviderSDSProvider) DeepCopy() *MeshConfigExtensionProviderSDSProvider {
+ if in == nil {
+ return nil
+ }
+ out := new(MeshConfigExtensionProviderSDSProvider)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MeshConfigExtensionProviderSkyWalkingTracingProvider) DeepCopyInto(out *MeshConfigExtensionProviderSkyWalkingTracingProvider) {
*out = *in
@@ -2913,6 +3041,22 @@ func (in *MeshConfigExtensionProviderZipkinTracingProvider) DeepCopyInto(out *Me
*out = new(string)
**out = **in
}
+ if in.Timeout != nil {
+ in, out := &in.Timeout, &out.Timeout
+ *out = new(metav1.Duration)
+ **out = **in
+ }
+ if in.Headers != nil {
+ in, out := &in.Headers, &out.Headers
+ *out = make([]*MeshConfigExtensionProviderHttpHeader, len(*in))
+ for i := range *in {
+ if (*in)[i] != nil {
+ in, out := &(*in)[i], &(*out)[i]
+ *out = new(MeshConfigExtensionProviderHttpHeader)
+ (*in).DeepCopyInto(*out)
+ }
+ }
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MeshConfigExtensionProviderZipkinTracingProvider.
@@ -3127,6 +3271,21 @@ func (in *MeshConfigProxyConfig) DeepCopyInto(out *MeshConfigProxyConfig) {
*out = new(ProxyConfigProxyHeaders)
(*in).DeepCopyInto(*out)
}
+ if in.FileFlushInterval != nil {
+ in, out := &in.FileFlushInterval, &out.FileFlushInterval
+ *out = new(metav1.Duration)
+ **out = **in
+ }
+ if in.FileFlushMinSizeKb != nil {
+ in, out := &in.FileFlushMinSizeKb, &out.FileFlushMinSizeKb
+ *out = new(uint32)
+ **out = **in
+ }
+ if in.StatsCompression != nil {
+ in, out := &in.StatsCompression, &out.StatsCompression
+ *out = new(bool)
+ **out = **in
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MeshConfigProxyConfig.
@@ -3154,6 +3313,31 @@ func (in *MeshConfigProxyPathNormalization) DeepCopy() *MeshConfigProxyPathNorma
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MeshConfigServiceScopeConfigs) DeepCopyInto(out *MeshConfigServiceScopeConfigs) {
+ *out = *in
+ if in.NamespaceSelector != nil {
+ in, out := &in.NamespaceSelector, &out.NamespaceSelector
+ *out = new(metav1.LabelSelector)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.ServicesSelector != nil {
+ in, out := &in.ServicesSelector, &out.ServicesSelector
+ *out = new(metav1.LabelSelector)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MeshConfigServiceScopeConfigs.
+func (in *MeshConfigServiceScopeConfigs) DeepCopy() *MeshConfigServiceScopeConfigs {
+ if in == nil {
+ return nil
+ }
+ out := new(MeshConfigServiceScopeConfigs)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MeshConfigServiceSettings) DeepCopyInto(out *MeshConfigServiceSettings) {
*out = *in
@@ -3387,6 +3571,26 @@ func (in *NetworkNetworkEndpoints) DeepCopy() *NetworkNetworkEndpoints {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *NetworkPolicyConfig) DeepCopyInto(out *NetworkPolicyConfig) {
+ *out = *in
+ if in.Enabled != nil {
+ in, out := &in.Enabled, &out.Enabled
+ *out = new(bool)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkPolicyConfig.
+func (in *NetworkPolicyConfig) DeepCopy() *NetworkPolicyConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(NetworkPolicyConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OutboundTrafficPolicyConfig) DeepCopyInto(out *OutboundTrafficPolicyConfig) {
*out = *in
@@ -3624,11 +3828,16 @@ func (in *PilotConfig) DeepCopyInto(out *PilotConfig) {
}
if in.EnvVarFrom != nil {
in, out := &in.EnvVarFrom, &out.EnvVarFrom
- *out = make([]corev1.EnvFromSource, len(*in))
+ *out = make([]corev1.EnvVar, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
+ if in.CrlConfigMapName != nil {
+ in, out := &in.CrlConfigMapName, &out.CrlConfigMapName
+ *out = new(string)
+ **out = **in
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PilotConfig.
@@ -3929,6 +4138,11 @@ func (in *ProxyConfig) DeepCopyInto(out *ProxyConfig) {
*out = new(uint32)
**out = **in
}
+ if in.SeccompProfile != nil {
+ in, out := &in.SeccompProfile, &out.SeccompProfile
+ *out = new(corev1.SeccompProfile)
+ (*in).DeepCopyInto(*out)
+ }
if in.StartupProbe != nil {
in, out := &in.StartupProbe, &out.StartupProbe
*out = new(StartupProbe)
@@ -4019,6 +4233,16 @@ func (in *ProxyConfigProxyHeaders) DeepCopyInto(out *ProxyConfigProxyHeaders) {
*out = new(bool)
**out = **in
}
+ if in.XForwardedHost != nil {
+ in, out := &in.XForwardedHost, &out.XForwardedHost
+ *out = new(ProxyConfigProxyHeadersXForwardedHost)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.XForwardedPort != nil {
+ in, out := &in.XForwardedPort, &out.XForwardedPort
+ *out = new(ProxyConfigProxyHeadersXForwardedPort)
+ (*in).DeepCopyInto(*out)
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyConfigProxyHeaders.
@@ -4171,6 +4395,46 @@ func (in *ProxyConfigProxyHeadersSetCurrentClientCertDetails) DeepCopy() *ProxyC
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ProxyConfigProxyHeadersXForwardedHost) DeepCopyInto(out *ProxyConfigProxyHeadersXForwardedHost) {
+ *out = *in
+ if in.Enabled != nil {
+ in, out := &in.Enabled, &out.Enabled
+ *out = new(bool)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyConfigProxyHeadersXForwardedHost.
+func (in *ProxyConfigProxyHeadersXForwardedHost) DeepCopy() *ProxyConfigProxyHeadersXForwardedHost {
+ if in == nil {
+ return nil
+ }
+ out := new(ProxyConfigProxyHeadersXForwardedHost)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ProxyConfigProxyHeadersXForwardedPort) DeepCopyInto(out *ProxyConfigProxyHeadersXForwardedPort) {
+ *out = *in
+ if in.Enabled != nil {
+ in, out := &in.Enabled, &out.Enabled
+ *out = new(bool)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyConfigProxyHeadersXForwardedPort.
+func (in *ProxyConfigProxyHeadersXForwardedPort) DeepCopy() *ProxyConfigProxyHeadersXForwardedPort {
+ if in == nil {
+ return nil
+ }
+ out := new(ProxyConfigProxyHeadersXForwardedPort)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ProxyConfigProxyStatsMatcher) DeepCopyInto(out *ProxyConfigProxyStatsMatcher) {
*out = *in
@@ -5289,6 +5553,49 @@ func (in *WorkloadSelector) DeepCopy() *WorkloadSelector {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ZTunnel) DeepCopyInto(out *ZTunnel) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ in.Spec.DeepCopyInto(&out.Spec)
+ in.Status.DeepCopyInto(&out.Status)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZTunnel.
+func (in *ZTunnel) DeepCopy() *ZTunnel {
+ if in == nil {
+ return nil
+ }
+ out := new(ZTunnel)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ZTunnel) DeepCopyObject() runtime.Object {
+ if c := in.DeepCopy(); c != nil {
+ return c
+ }
+ return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ZTunnelCondition) DeepCopyInto(out *ZTunnelCondition) {
+ *out = *in
+ in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZTunnelCondition.
+func (in *ZTunnelCondition) DeepCopy() *ZTunnelCondition {
+ if in == nil {
+ return nil
+ }
+ out := new(ZTunnelCondition)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ZTunnelConfig) DeepCopyInto(out *ZTunnelConfig) {
*out = *in
@@ -5312,6 +5619,16 @@ func (in *ZTunnelConfig) DeepCopyInto(out *ZTunnelConfig) {
*out = new(string)
**out = **in
}
+ if in.Network != nil {
+ in, out := &in.Network, &out.Network
+ *out = new(string)
+ **out = **in
+ }
+ if in.Affinity != nil {
+ in, out := &in.Affinity, &out.Affinity
+ *out = new(corev1.Affinity)
+ (*in).DeepCopyInto(*out)
+ }
if in.ResourceName != nil {
in, out := &in.ResourceName, &out.ResourceName
*out = new(string)
@@ -5345,6 +5662,13 @@ func (in *ZTunnelConfig) DeepCopyInto(out *ZTunnelConfig) {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
+ if in.Tolerations != nil {
+ in, out := &in.Tolerations, &out.Tolerations
+ *out = make([]corev1.Toleration, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
if in.PodAnnotations != nil {
in, out := &in.PodAnnotations, &out.PodAnnotations
*out = make(map[string]string, len(*in))
@@ -5364,6 +5688,18 @@ func (in *ZTunnelConfig) DeepCopyInto(out *ZTunnelConfig) {
*out = new(corev1.ResourceRequirements)
(*in).DeepCopyInto(*out)
}
+ if in.ResourceQuotas != nil {
+ in, out := &in.ResourceQuotas, &out.ResourceQuotas
+ *out = new(ResourceQuotas)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.NodeSelector != nil {
+ in, out := &in.NodeSelector, &out.NodeSelector
+ *out = make(map[string]string, len(*in))
+ for key, val := range *in {
+ (*out)[key] = val
+ }
+ }
if in.ImagePullSecrets != nil {
in, out := &in.ImagePullSecrets, &out.ImagePullSecrets
*out = make([]string, len(*in))
@@ -5386,11 +5722,6 @@ func (in *ZTunnelConfig) DeepCopyInto(out *ZTunnelConfig) {
*out = new(MultiClusterConfig)
(*in).DeepCopyInto(*out)
}
- if in.MeshConfig != nil {
- in, out := &in.MeshConfig, &out.MeshConfig
- *out = new(MeshConfig)
- (*in).DeepCopyInto(*out)
- }
if in.TerminationGracePeriodSeconds != nil {
in, out := &in.TerminationGracePeriodSeconds, &out.TerminationGracePeriodSeconds
*out = new(int64)
@@ -5426,6 +5757,16 @@ func (in *ZTunnelConfig) DeepCopyInto(out *ZTunnelConfig) {
*out = new(bool)
**out = **in
}
+ if in.SeLinuxOptions != nil {
+ in, out := &in.SeLinuxOptions, &out.SeLinuxOptions
+ *out = new(corev1.SELinuxOptions)
+ **out = **in
+ }
+ if in.UpdateStrategy != nil {
+ in, out := &in.UpdateStrategy, &out.UpdateStrategy
+ *out = new(appsv1.DaemonSetUpdateStrategy)
+ (*in).DeepCopyInto(*out)
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZTunnelConfig.
@@ -5498,6 +5839,80 @@ func (in *ZTunnelGlobalConfig) DeepCopy() *ZTunnelGlobalConfig {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ZTunnelList) DeepCopyInto(out *ZTunnelList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ListMeta.DeepCopyInto(&out.ListMeta)
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]ZTunnel, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZTunnelList.
+func (in *ZTunnelList) DeepCopy() *ZTunnelList {
+ if in == nil {
+ return nil
+ }
+ out := new(ZTunnelList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ZTunnelList) DeepCopyObject() runtime.Object {
+ if c := in.DeepCopy(); c != nil {
+ return c
+ }
+ return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ZTunnelSpec) DeepCopyInto(out *ZTunnelSpec) {
+ *out = *in
+ if in.Values != nil {
+ in, out := &in.Values, &out.Values
+ *out = new(ZTunnelValues)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZTunnelSpec.
+func (in *ZTunnelSpec) DeepCopy() *ZTunnelSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(ZTunnelSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ZTunnelStatus) DeepCopyInto(out *ZTunnelStatus) {
+ *out = *in
+ if in.Conditions != nil {
+ in, out := &in.Conditions, &out.Conditions
+ *out = make([]ZTunnelCondition, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZTunnelStatus.
+func (in *ZTunnelStatus) DeepCopy() *ZTunnelStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(ZTunnelStatus)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ZTunnelValues) DeepCopyInto(out *ZTunnelValues) {
*out = *in
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/crds.go b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/crds.go
new file mode 100644
index 0000000000..4c8e382daa
--- /dev/null
+++ b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/crds.go
@@ -0,0 +1,27 @@
+// Copyright Istio 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 crds provides embedded CRD YAML files for Istio and Sail resources.
+package crds
+
+import "embed"
+
+// FS contains all CRD YAML files from the chart/crds directory.
+// This allows programmatic access to CRDs for installation.
+//
+// CRD files follow the naming convention: {group}_{plural}.yaml
+// Example: extensions.istio.io_wasmplugins.yaml
+//
+//go:embed *.yaml
+var FS embed.FS
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/extensions.istio.io_wasmplugins.yaml b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/extensions.istio.io_wasmplugins.yaml
new file mode 100644
index 0000000000..61922e95af
--- /dev/null
+++ b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/extensions.istio.io_wasmplugins.yaml
@@ -0,0 +1,361 @@
+# DO NOT EDIT - Generated by Cue OpenAPI generator based on Istio APIs.
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ "helm.sh/resource-policy": keep
+ labels:
+ app: istio-pilot
+ chart: istio
+ heritage: Tiller
+ release: istio
+ name: wasmplugins.extensions.istio.io
+spec:
+ group: extensions.istio.io
+ names:
+ categories:
+ - istio-io
+ - extensions-istio-io
+ kind: WasmPlugin
+ listKind: WasmPluginList
+ plural: wasmplugins
+ singular: wasmplugin
+ scope: Namespaced
+ versions:
+ - additionalPrinterColumns:
+ - description: 'CreationTimestamp is a timestamp representing the server time
+ when this object was created. It is not guaranteed to be set in happens-before
+ order across separate operations. Clients may not set this value. It is represented
+ in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for
+ lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata'
+ jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Extend the functionality provided by the Istio proxy through
+ WebAssembly filters. See more details at: https://istio.io/docs/reference/config/proxy_extensions/wasm-plugin.html'
+ properties:
+ failStrategy:
+ description: |-
+ Specifies the failure behavior for the plugin due to fatal errors.
+
+ Valid Options: FAIL_CLOSE, FAIL_OPEN, FAIL_RELOAD
+ enum:
+ - FAIL_CLOSE
+ - FAIL_OPEN
+ - FAIL_RELOAD
+ type: string
+ imagePullPolicy:
+ description: |-
+ The pull behaviour to be applied when fetching Wasm module by either OCI image or `http/https`.
+
+ Valid Options: IfNotPresent, Always
+ enum:
+ - UNSPECIFIED_POLICY
+ - IfNotPresent
+ - Always
+ type: string
+ imagePullSecret:
+ description: Credentials to use for OCI image pulling.
+ maxLength: 253
+ minLength: 1
+ type: string
+ match:
+ description: Specifies the criteria to determine which traffic is
+ passed to WasmPlugin.
+ items:
+ properties:
+ mode:
+ description: |-
+ Criteria for selecting traffic by their direction.
+
+ Valid Options: CLIENT, SERVER, CLIENT_AND_SERVER
+ enum:
+ - UNDEFINED
+ - CLIENT
+ - SERVER
+ - CLIENT_AND_SERVER
+ type: string
+ ports:
+ description: Criteria for selecting traffic by their destination
+ port.
+ items:
+ properties:
+ number:
+ maximum: 65535
+ minimum: 1
+ type: integer
+ required:
+ - number
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - number
+ x-kubernetes-list-type: map
+ type: object
+ type: array
+ phase:
+ description: |-
+ Determines where in the filter chain this `WasmPlugin` is to be injected.
+
+ Valid Options: AUTHN, AUTHZ, STATS
+ enum:
+ - UNSPECIFIED_PHASE
+ - AUTHN
+ - AUTHZ
+ - STATS
+ type: string
+ pluginConfig:
+ description: The configuration that will be passed on to the plugin.
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ pluginName:
+ description: The plugin name to be used in the Envoy configuration
+ (used to be called `rootID`).
+ maxLength: 256
+ minLength: 1
+ type: string
+ priority:
+ description: Determines ordering of `WasmPlugins` in the same `phase`.
+ format: int32
+ nullable: true
+ type: integer
+ selector:
+ description: Criteria used to select the specific set of pods/VMs
+ on which this plugin configuration should be applied.
+ properties:
+ matchLabels:
+ additionalProperties:
+ maxLength: 63
+ type: string
+ x-kubernetes-validations:
+ - message: wildcard not allowed in label value match
+ rule: '!self.contains("*")'
+ description: One or more labels that indicate a specific set of
+ pods/VMs on which a policy should be applied.
+ maxProperties: 4096
+ type: object
+ x-kubernetes-validations:
+ - message: wildcard not allowed in label key match
+ rule: self.all(key, !key.contains("*"))
+ - message: key must not be empty
+ rule: self.all(key, key.size() != 0)
+ type: object
+ sha256:
+ description: SHA256 checksum that will be used to verify Wasm module
+ or OCI container.
+ pattern: (^$|^[a-f0-9]{64}$)
+ type: string
+ targetRef:
+ properties:
+ group:
+ description: group is the group of the target resource.
+ maxLength: 253
+ pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+ type: string
+ kind:
+ description: kind is kind of the target resource.
+ maxLength: 63
+ minLength: 1
+ pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
+ type: string
+ name:
+ description: name is the name of the target resource.
+ maxLength: 253
+ minLength: 1
+ type: string
+ namespace:
+ description: namespace is the namespace of the referent.
+ type: string
+ x-kubernetes-validations:
+ - message: cross namespace referencing is not currently supported
+ rule: self.size() == 0
+ required:
+ - kind
+ - name
+ type: object
+ targetRefs:
+ description: Optional.
+ items:
+ properties:
+ group:
+ description: group is the group of the target resource.
+ maxLength: 253
+ pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+ type: string
+ kind:
+ description: kind is kind of the target resource.
+ maxLength: 63
+ minLength: 1
+ pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
+ type: string
+ name:
+ description: name is the name of the target resource.
+ maxLength: 253
+ minLength: 1
+ type: string
+ namespace:
+ description: namespace is the namespace of the referent.
+ type: string
+ x-kubernetes-validations:
+ - message: cross namespace referencing is not currently supported
+ rule: self.size() == 0
+ required:
+ - kind
+ - name
+ type: object
+ maxItems: 16
+ type: array
+ type:
+ description: |-
+ Specifies the type of Wasm Extension to be used.
+
+ Valid Options: HTTP, NETWORK
+ enum:
+ - UNSPECIFIED_PLUGIN_TYPE
+ - HTTP
+ - NETWORK
+ type: string
+ url:
+ description: URL of a Wasm module or OCI container.
+ minLength: 1
+ type: string
+ x-kubernetes-validations:
+ - message: url must have schema one of [http, https, file, oci]
+ rule: |-
+ isURL(self) ? (url(self).getScheme() in ["", "http", "https", "oci", "file"]) : (isURL("http://" + self) &&
+ url("http://" + self).getScheme() in ["", "http", "https", "oci", "file"])
+ verificationKey:
+ type: string
+ vmConfig:
+ description: Configuration for a Wasm VM.
+ properties:
+ env:
+ description: Specifies environment variables to be injected to
+ this VM.
+ items:
+ properties:
+ name:
+ description: Name of the environment variable.
+ maxLength: 256
+ minLength: 1
+ type: string
+ value:
+ description: Value for the environment variable.
+ maxLength: 2048
+ type: string
+ valueFrom:
+ description: |-
+ Source for the environment variable's value.
+
+ Valid Options: INLINE, HOST
+ enum:
+ - INLINE
+ - HOST
+ type: string
+ required:
+ - name
+ type: object
+ x-kubernetes-validations:
+ - message: value may only be set when valueFrom is INLINE
+ rule: '(has(self.valueFrom) ? self.valueFrom : "") != "HOST"
+ || !has(self.value)'
+ maxItems: 256
+ type: array
+ x-kubernetes-list-map-keys:
+ - name
+ x-kubernetes-list-type: map
+ type: object
+ required:
+ - url
+ type: object
+ x-kubernetes-validations:
+ - message: only one of targetRefs or selector can be set
+ rule: '(has(self.selector) ? 1 : 0) + (has(self.targetRef) ? 1 : 0)
+ + (has(self.targetRefs) ? 1 : 0) <= 1'
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - spec
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_destinationrules.yaml b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_destinationrules.yaml
new file mode 100644
index 0000000000..db1f194794
--- /dev/null
+++ b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_destinationrules.yaml
@@ -0,0 +1,6028 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ "helm.sh/resource-policy": keep
+ labels:
+ app: istio-pilot
+ chart: istio
+ heritage: Tiller
+ release: istio
+ name: destinationrules.networking.istio.io
+spec:
+ group: networking.istio.io
+ names:
+ categories:
+ - istio-io
+ - networking-istio-io
+ kind: DestinationRule
+ listKind: DestinationRuleList
+ plural: destinationrules
+ shortNames:
+ - dr
+ singular: destinationrule
+ scope: Namespaced
+ versions:
+ - additionalPrinterColumns:
+ - description: The name of a service from the service registry
+ jsonPath: .spec.host
+ name: Host
+ type: string
+ - description: CreationTimestamp is a timestamp representing the server time when
+ this object was created. It is not guaranteed to be set in happens-before
+ order across separate operations. Clients may not set this value. It is represented
+ in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for
+ lists. For more information, see [Kubernetes API Conventions](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#metadata)
+ jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Configuration affecting load balancing, outlier detection,
+ etc. See more details at: https://istio.io/docs/reference/config/networking/destination-rule.html'
+ properties:
+ exportTo:
+ description: A list of namespaces to which this destination rule is
+ exported.
+ items:
+ type: string
+ type: array
+ host:
+ description: The name of a service from the service registry.
+ type: string
+ subsets:
+ description: One or more named sets that represent individual versions
+ of a service.
+ items:
+ properties:
+ labels:
+ additionalProperties:
+ type: string
+ description: Labels apply a filter over the endpoints of a service
+ in the service registry.
+ type: object
+ name:
+ description: Name of the subset.
+ type: string
+ trafficPolicy:
+ description: Traffic policies that apply to this subset.
+ properties:
+ connectionPool:
+ properties:
+ http:
+ description: HTTP connection pool settings.
+ properties:
+ h2UpgradePolicy:
+ description: |-
+ Specify if http1.1 connection should be upgraded to http2 for the associated destination.
+
+ Valid Options: DEFAULT, DO_NOT_UPGRADE, UPGRADE
+ enum:
+ - DEFAULT
+ - DO_NOT_UPGRADE
+ - UPGRADE
+ type: string
+ http1MaxPendingRequests:
+ description: Maximum number of requests that will
+ be queued while waiting for a ready connection
+ pool connection.
+ format: int32
+ type: integer
+ http2MaxRequests:
+ description: Maximum number of active requests to
+ a destination.
+ format: int32
+ type: integer
+ idleTimeout:
+ description: The idle timeout for upstream connection
+ pool connections.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConcurrentStreams:
+ description: The maximum number of concurrent streams
+ allowed for a peer on one HTTP/2 connection.
+ format: int32
+ type: integer
+ maxRequestsPerConnection:
+ description: Maximum number of requests per connection
+ to a backend.
+ format: int32
+ type: integer
+ maxRetries:
+ description: Maximum number of retries that can
+ be outstanding to all hosts in a cluster at a
+ given time.
+ format: int32
+ type: integer
+ useClientProtocol:
+ description: If set to true, client protocol will
+ be preserved while initiating connection to backend.
+ type: boolean
+ type: object
+ tcp:
+ description: Settings common to both HTTP and TCP upstream
+ connections.
+ properties:
+ connectTimeout:
+ description: TCP connection timeout.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ idleTimeout:
+ description: The idle timeout for TCP connections.
+ type: string
+ maxConnectionDuration:
+ description: The maximum duration of a connection.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConnections:
+ description: Maximum number of HTTP1 /TCP connections
+ to a destination host.
+ format: int32
+ type: integer
+ tcpKeepalive:
+ description: If set then set SO_KEEPALIVE on the
+ socket to enable TCP Keepalives.
+ properties:
+ interval:
+ description: The time duration between keep-alive
+ probes.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ probes:
+ description: Maximum number of keepalive probes
+ to send without response before deciding the
+ connection is dead.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ time:
+ description: The time duration a connection
+ needs to be idle before keep-alive probes
+ start being sent.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ type: object
+ type: object
+ loadBalancer:
+ description: Settings controlling the load balancer algorithms.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ properties:
+ consistentHash:
+ allOf:
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ properties:
+ httpCookie:
+ description: Hash based on HTTP cookie.
+ properties:
+ attributes:
+ description: Additional attributes for the cookie.
+ items:
+ properties:
+ name:
+ description: The name of the cookie attribute.
+ type: string
+ value:
+ description: The optional value of the
+ cookie attribute.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ name:
+ description: Name of the cookie.
+ type: string
+ path:
+ description: Path to set for the cookie.
+ type: string
+ ttl:
+ description: Lifetime of the cookie.
+ type: string
+ required:
+ - name
+ type: object
+ httpHeaderName:
+ description: Hash based on a specific HTTP header.
+ type: string
+ httpQueryParameterName:
+ description: Hash based on a specific HTTP query
+ parameter.
+ type: string
+ maglev:
+ description: The Maglev load balancer implements
+ consistent hashing to backend hosts.
+ properties:
+ tableSize:
+ description: The table size for Maglev hashing.
+ minimum: 0
+ type: integer
+ type: object
+ minimumRingSize:
+ description: Deprecated.
+ minimum: 0
+ type: integer
+ ringHash:
+ description: The ring/modulo hash load balancer
+ implements consistent hashing to backend hosts.
+ properties:
+ minimumRingSize:
+ description: The minimum number of virtual nodes
+ to use for the hash ring.
+ minimum: 0
+ type: integer
+ type: object
+ useSourceIp:
+ description: Hash based on the source IP address.
+ type: boolean
+ type: object
+ localityLbSetting:
+ properties:
+ distribute:
+ description: 'Optional: only one of distribute,
+ failover or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating locality, '/' separated,
+ e.g.
+ type: string
+ to:
+ additionalProperties:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ description: Map of upstream localities to
+ traffic distribution weights.
+ type: object
+ type: object
+ type: array
+ enabled:
+ description: Enable locality load balancing.
+ nullable: true
+ type: boolean
+ failover:
+ description: 'Optional: only one of distribute,
+ failover or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating region.
+ type: string
+ to:
+ description: Destination region the traffic
+ will fail over to when endpoints in the
+ 'from' region becomes unhealthy.
+ type: string
+ type: object
+ type: array
+ failoverPriority:
+ description: failoverPriority is an ordered list
+ of labels used to sort endpoints to do priority
+ based load balancing.
+ items:
+ type: string
+ type: array
+ type: object
+ simple:
+ description: |2-
+
+
+ Valid Options: LEAST_CONN, RANDOM, PASSTHROUGH, ROUND_ROBIN, LEAST_REQUEST
+ enum:
+ - UNSPECIFIED
+ - LEAST_CONN
+ - RANDOM
+ - PASSTHROUGH
+ - ROUND_ROBIN
+ - LEAST_REQUEST
+ type: string
+ warmup:
+ description: Represents the warmup configuration of
+ Service.
+ properties:
+ aggression:
+ description: This parameter controls the speed of
+ traffic increase over the warmup duration.
+ format: double
+ minimum: 0
+ nullable: true
+ type: number
+ duration:
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ minimumPercent:
+ format: double
+ maximum: 100
+ minimum: 0
+ nullable: true
+ type: number
+ required:
+ - duration
+ type: object
+ warmupDurationSecs:
+ description: 'Deprecated: use `warmup` instead.'
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ outlierDetection:
+ properties:
+ baseEjectionTime:
+ description: Minimum ejection duration.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ consecutive5xxErrors:
+ description: Number of 5xx errors before a host is ejected
+ from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveErrors:
+ format: int32
+ type: integer
+ consecutiveGatewayErrors:
+ description: Number of gateway errors before a host
+ is ejected from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveLocalOriginFailures:
+ description: The number of consecutive locally originated
+ failures before ejection occurs.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ interval:
+ description: Time interval between ejection sweep analysis.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxEjectionPercent:
+ description: Maximum % of hosts in the load balancing
+ pool for the upstream service that can be ejected.
+ format: int32
+ type: integer
+ minHealthPercent:
+ description: Outlier detection will be enabled as long
+ as the associated load balancing pool has at least
+ `minHealthPercent` hosts in healthy mode.
+ format: int32
+ type: integer
+ splitExternalLocalOriginErrors:
+ description: Determines whether to distinguish local
+ origin failures from external errors.
+ type: boolean
+ type: object
+ portLevelSettings:
+ description: Traffic policies specific to individual ports.
+ items:
+ properties:
+ connectionPool:
+ properties:
+ http:
+ description: HTTP connection pool settings.
+ properties:
+ h2UpgradePolicy:
+ description: |-
+ Specify if http1.1 connection should be upgraded to http2 for the associated destination.
+
+ Valid Options: DEFAULT, DO_NOT_UPGRADE, UPGRADE
+ enum:
+ - DEFAULT
+ - DO_NOT_UPGRADE
+ - UPGRADE
+ type: string
+ http1MaxPendingRequests:
+ description: Maximum number of requests that
+ will be queued while waiting for a ready
+ connection pool connection.
+ format: int32
+ type: integer
+ http2MaxRequests:
+ description: Maximum number of active requests
+ to a destination.
+ format: int32
+ type: integer
+ idleTimeout:
+ description: The idle timeout for upstream
+ connection pool connections.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConcurrentStreams:
+ description: The maximum number of concurrent
+ streams allowed for a peer on one HTTP/2
+ connection.
+ format: int32
+ type: integer
+ maxRequestsPerConnection:
+ description: Maximum number of requests per
+ connection to a backend.
+ format: int32
+ type: integer
+ maxRetries:
+ description: Maximum number of retries that
+ can be outstanding to all hosts in a cluster
+ at a given time.
+ format: int32
+ type: integer
+ useClientProtocol:
+ description: If set to true, client protocol
+ will be preserved while initiating connection
+ to backend.
+ type: boolean
+ type: object
+ tcp:
+ description: Settings common to both HTTP and
+ TCP upstream connections.
+ properties:
+ connectTimeout:
+ description: TCP connection timeout.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ idleTimeout:
+ description: The idle timeout for TCP connections.
+ type: string
+ maxConnectionDuration:
+ description: The maximum duration of a connection.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConnections:
+ description: Maximum number of HTTP1 /TCP
+ connections to a destination host.
+ format: int32
+ type: integer
+ tcpKeepalive:
+ description: If set then set SO_KEEPALIVE
+ on the socket to enable TCP Keepalives.
+ properties:
+ interval:
+ description: The time duration between
+ keep-alive probes.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ probes:
+ description: Maximum number of keepalive
+ probes to send without response before
+ deciding the connection is dead.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ time:
+ description: The time duration a connection
+ needs to be idle before keep-alive probes
+ start being sent.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ type: object
+ type: object
+ loadBalancer:
+ description: Settings controlling the load balancer
+ algorithms.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ properties:
+ consistentHash:
+ allOf:
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ properties:
+ httpCookie:
+ description: Hash based on HTTP cookie.
+ properties:
+ attributes:
+ description: Additional attributes for
+ the cookie.
+ items:
+ properties:
+ name:
+ description: The name of the cookie
+ attribute.
+ type: string
+ value:
+ description: The optional value
+ of the cookie attribute.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ name:
+ description: Name of the cookie.
+ type: string
+ path:
+ description: Path to set for the cookie.
+ type: string
+ ttl:
+ description: Lifetime of the cookie.
+ type: string
+ required:
+ - name
+ type: object
+ httpHeaderName:
+ description: Hash based on a specific HTTP
+ header.
+ type: string
+ httpQueryParameterName:
+ description: Hash based on a specific HTTP
+ query parameter.
+ type: string
+ maglev:
+ description: The Maglev load balancer implements
+ consistent hashing to backend hosts.
+ properties:
+ tableSize:
+ description: The table size for Maglev
+ hashing.
+ minimum: 0
+ type: integer
+ type: object
+ minimumRingSize:
+ description: Deprecated.
+ minimum: 0
+ type: integer
+ ringHash:
+ description: The ring/modulo hash load balancer
+ implements consistent hashing to backend
+ hosts.
+ properties:
+ minimumRingSize:
+ description: The minimum number of virtual
+ nodes to use for the hash ring.
+ minimum: 0
+ type: integer
+ type: object
+ useSourceIp:
+ description: Hash based on the source IP address.
+ type: boolean
+ type: object
+ localityLbSetting:
+ properties:
+ distribute:
+ description: 'Optional: only one of distribute,
+ failover or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating locality, '/'
+ separated, e.g.
+ type: string
+ to:
+ additionalProperties:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ description: Map of upstream localities
+ to traffic distribution weights.
+ type: object
+ type: object
+ type: array
+ enabled:
+ description: Enable locality load balancing.
+ nullable: true
+ type: boolean
+ failover:
+ description: 'Optional: only one of distribute,
+ failover or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating region.
+ type: string
+ to:
+ description: Destination region the
+ traffic will fail over to when endpoints
+ in the 'from' region becomes unhealthy.
+ type: string
+ type: object
+ type: array
+ failoverPriority:
+ description: failoverPriority is an ordered
+ list of labels used to sort endpoints to
+ do priority based load balancing.
+ items:
+ type: string
+ type: array
+ type: object
+ simple:
+ description: |2-
+
+
+ Valid Options: LEAST_CONN, RANDOM, PASSTHROUGH, ROUND_ROBIN, LEAST_REQUEST
+ enum:
+ - UNSPECIFIED
+ - LEAST_CONN
+ - RANDOM
+ - PASSTHROUGH
+ - ROUND_ROBIN
+ - LEAST_REQUEST
+ type: string
+ warmup:
+ description: Represents the warmup configuration
+ of Service.
+ properties:
+ aggression:
+ description: This parameter controls the speed
+ of traffic increase over the warmup duration.
+ format: double
+ minimum: 0
+ nullable: true
+ type: number
+ duration:
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ minimumPercent:
+ format: double
+ maximum: 100
+ minimum: 0
+ nullable: true
+ type: number
+ required:
+ - duration
+ type: object
+ warmupDurationSecs:
+ description: 'Deprecated: use `warmup` instead.'
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ outlierDetection:
+ properties:
+ baseEjectionTime:
+ description: Minimum ejection duration.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ consecutive5xxErrors:
+ description: Number of 5xx errors before a host
+ is ejected from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveErrors:
+ format: int32
+ type: integer
+ consecutiveGatewayErrors:
+ description: Number of gateway errors before a
+ host is ejected from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveLocalOriginFailures:
+ description: The number of consecutive locally
+ originated failures before ejection occurs.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ interval:
+ description: Time interval between ejection sweep
+ analysis.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ maxEjectionPercent:
+ description: Maximum % of hosts in the load balancing
+ pool for the upstream service that can be ejected.
+ format: int32
+ type: integer
+ minHealthPercent:
+ description: Outlier detection will be enabled
+ as long as the associated load balancing pool
+ has at least `minHealthPercent` hosts in healthy
+ mode.
+ format: int32
+ type: integer
+ splitExternalLocalOriginErrors:
+ description: Determines whether to distinguish
+ local origin failures from external errors.
+ type: boolean
+ type: object
+ port:
+ description: Specifies the number of a port on the
+ destination service on which this policy is being
+ applied.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ tls:
+ description: TLS related settings for connections
+ to the upstream service.
+ properties:
+ caCertificates:
+ description: 'OPTIONAL: The path to the file containing
+ certificate authority certificates to use in
+ verifying a presented server certificate.'
+ type: string
+ caCrl:
+ description: 'OPTIONAL: The path to the file containing
+ the certificate revocation list (CRL) to use
+ in verifying a presented server certificate.'
+ type: string
+ clientCertificate:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ credentialName:
+ description: The name of the secret that holds
+ the TLS certs for the client including the CA
+ certificates.
+ type: string
+ insecureSkipVerify:
+ description: '`insecureSkipVerify` specifies whether
+ the proxy should skip verifying the CA signature
+ and SAN for the server certificate corresponding
+ to the host.'
+ nullable: true
+ type: boolean
+ mode:
+ description: |-
+ Indicates whether connections to this port should be secured using TLS.
+
+ Valid Options: DISABLE, SIMPLE, MUTUAL, ISTIO_MUTUAL
+ enum:
+ - DISABLE
+ - SIMPLE
+ - MUTUAL
+ - ISTIO_MUTUAL
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ sni:
+ description: SNI string to present to the server
+ during TLS handshake.
+ type: string
+ subjectAltNames:
+ description: A list of alternate names to verify
+ the subject identity in the certificate.
+ items:
+ type: string
+ type: array
+ type: object
+ type: object
+ maxItems: 4096
+ type: array
+ proxyProtocol:
+ description: The upstream PROXY protocol settings.
+ properties:
+ version:
+ description: |-
+ The PROXY protocol version to use.
+
+ Valid Options: V1, V2
+ enum:
+ - V1
+ - V2
+ type: string
+ type: object
+ retryBudget:
+ description: Specifies a limit on concurrent retries in
+ relation to the number of active requests.
+ properties:
+ minRetryConcurrency:
+ description: Specifies the minimum retry concurrency
+ allowed for the retry budget.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ percent:
+ description: Specifies the limit on concurrent retries
+ as a percentage of the sum of active requests and
+ active pending requests.
+ format: double
+ maximum: 100
+ minimum: 0
+ nullable: true
+ type: number
+ type: object
+ tls:
+ description: TLS related settings for connections to the
+ upstream service.
+ properties:
+ caCertificates:
+ description: 'OPTIONAL: The path to the file containing
+ certificate authority certificates to use in verifying
+ a presented server certificate.'
+ type: string
+ caCrl:
+ description: 'OPTIONAL: The path to the file containing
+ the certificate revocation list (CRL) to use in verifying
+ a presented server certificate.'
+ type: string
+ clientCertificate:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ credentialName:
+ description: The name of the secret that holds the TLS
+ certs for the client including the CA certificates.
+ type: string
+ insecureSkipVerify:
+ description: '`insecureSkipVerify` specifies whether
+ the proxy should skip verifying the CA signature and
+ SAN for the server certificate corresponding to the
+ host.'
+ nullable: true
+ type: boolean
+ mode:
+ description: |-
+ Indicates whether connections to this port should be secured using TLS.
+
+ Valid Options: DISABLE, SIMPLE, MUTUAL, ISTIO_MUTUAL
+ enum:
+ - DISABLE
+ - SIMPLE
+ - MUTUAL
+ - ISTIO_MUTUAL
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ sni:
+ description: SNI string to present to the server during
+ TLS handshake.
+ type: string
+ subjectAltNames:
+ description: A list of alternate names to verify the
+ subject identity in the certificate.
+ items:
+ type: string
+ type: array
+ type: object
+ tunnel:
+ description: Configuration of tunneling TCP over other transport
+ or application layers for the host configured in the DestinationRule.
+ properties:
+ protocol:
+ description: Specifies which protocol to use for tunneling
+ the downstream connection.
+ type: string
+ targetHost:
+ description: Specifies a host to which the downstream
+ connection is tunneled.
+ type: string
+ targetPort:
+ description: Specifies a port to which the downstream
+ connection is tunneled.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ required:
+ - targetHost
+ - targetPort
+ type: object
+ type: object
+ required:
+ - name
+ type: object
+ type: array
+ trafficPolicy:
+ description: Traffic policies to apply (load balancing policy, connection
+ pool sizes, outlier detection).
+ properties:
+ connectionPool:
+ properties:
+ http:
+ description: HTTP connection pool settings.
+ properties:
+ h2UpgradePolicy:
+ description: |-
+ Specify if http1.1 connection should be upgraded to http2 for the associated destination.
+
+ Valid Options: DEFAULT, DO_NOT_UPGRADE, UPGRADE
+ enum:
+ - DEFAULT
+ - DO_NOT_UPGRADE
+ - UPGRADE
+ type: string
+ http1MaxPendingRequests:
+ description: Maximum number of requests that will be queued
+ while waiting for a ready connection pool connection.
+ format: int32
+ type: integer
+ http2MaxRequests:
+ description: Maximum number of active requests to a destination.
+ format: int32
+ type: integer
+ idleTimeout:
+ description: The idle timeout for upstream connection
+ pool connections.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConcurrentStreams:
+ description: The maximum number of concurrent streams
+ allowed for a peer on one HTTP/2 connection.
+ format: int32
+ type: integer
+ maxRequestsPerConnection:
+ description: Maximum number of requests per connection
+ to a backend.
+ format: int32
+ type: integer
+ maxRetries:
+ description: Maximum number of retries that can be outstanding
+ to all hosts in a cluster at a given time.
+ format: int32
+ type: integer
+ useClientProtocol:
+ description: If set to true, client protocol will be preserved
+ while initiating connection to backend.
+ type: boolean
+ type: object
+ tcp:
+ description: Settings common to both HTTP and TCP upstream
+ connections.
+ properties:
+ connectTimeout:
+ description: TCP connection timeout.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ idleTimeout:
+ description: The idle timeout for TCP connections.
+ type: string
+ maxConnectionDuration:
+ description: The maximum duration of a connection.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConnections:
+ description: Maximum number of HTTP1 /TCP connections
+ to a destination host.
+ format: int32
+ type: integer
+ tcpKeepalive:
+ description: If set then set SO_KEEPALIVE on the socket
+ to enable TCP Keepalives.
+ properties:
+ interval:
+ description: The time duration between keep-alive
+ probes.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ probes:
+ description: Maximum number of keepalive probes to
+ send without response before deciding the connection
+ is dead.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ time:
+ description: The time duration a connection needs
+ to be idle before keep-alive probes start being
+ sent.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ type: object
+ type: object
+ loadBalancer:
+ description: Settings controlling the load balancer algorithms.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ properties:
+ consistentHash:
+ allOf:
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ properties:
+ httpCookie:
+ description: Hash based on HTTP cookie.
+ properties:
+ attributes:
+ description: Additional attributes for the cookie.
+ items:
+ properties:
+ name:
+ description: The name of the cookie attribute.
+ type: string
+ value:
+ description: The optional value of the cookie
+ attribute.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ name:
+ description: Name of the cookie.
+ type: string
+ path:
+ description: Path to set for the cookie.
+ type: string
+ ttl:
+ description: Lifetime of the cookie.
+ type: string
+ required:
+ - name
+ type: object
+ httpHeaderName:
+ description: Hash based on a specific HTTP header.
+ type: string
+ httpQueryParameterName:
+ description: Hash based on a specific HTTP query parameter.
+ type: string
+ maglev:
+ description: The Maglev load balancer implements consistent
+ hashing to backend hosts.
+ properties:
+ tableSize:
+ description: The table size for Maglev hashing.
+ minimum: 0
+ type: integer
+ type: object
+ minimumRingSize:
+ description: Deprecated.
+ minimum: 0
+ type: integer
+ ringHash:
+ description: The ring/modulo hash load balancer implements
+ consistent hashing to backend hosts.
+ properties:
+ minimumRingSize:
+ description: The minimum number of virtual nodes to
+ use for the hash ring.
+ minimum: 0
+ type: integer
+ type: object
+ useSourceIp:
+ description: Hash based on the source IP address.
+ type: boolean
+ type: object
+ localityLbSetting:
+ properties:
+ distribute:
+ description: 'Optional: only one of distribute, failover
+ or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating locality, '/' separated,
+ e.g.
+ type: string
+ to:
+ additionalProperties:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ description: Map of upstream localities to traffic
+ distribution weights.
+ type: object
+ type: object
+ type: array
+ enabled:
+ description: Enable locality load balancing.
+ nullable: true
+ type: boolean
+ failover:
+ description: 'Optional: only one of distribute, failover
+ or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating region.
+ type: string
+ to:
+ description: Destination region the traffic will
+ fail over to when endpoints in the 'from' region
+ becomes unhealthy.
+ type: string
+ type: object
+ type: array
+ failoverPriority:
+ description: failoverPriority is an ordered list of labels
+ used to sort endpoints to do priority based load balancing.
+ items:
+ type: string
+ type: array
+ type: object
+ simple:
+ description: |2-
+
+
+ Valid Options: LEAST_CONN, RANDOM, PASSTHROUGH, ROUND_ROBIN, LEAST_REQUEST
+ enum:
+ - UNSPECIFIED
+ - LEAST_CONN
+ - RANDOM
+ - PASSTHROUGH
+ - ROUND_ROBIN
+ - LEAST_REQUEST
+ type: string
+ warmup:
+ description: Represents the warmup configuration of Service.
+ properties:
+ aggression:
+ description: This parameter controls the speed of traffic
+ increase over the warmup duration.
+ format: double
+ minimum: 0
+ nullable: true
+ type: number
+ duration:
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ minimumPercent:
+ format: double
+ maximum: 100
+ minimum: 0
+ nullable: true
+ type: number
+ required:
+ - duration
+ type: object
+ warmupDurationSecs:
+ description: 'Deprecated: use `warmup` instead.'
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ outlierDetection:
+ properties:
+ baseEjectionTime:
+ description: Minimum ejection duration.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ consecutive5xxErrors:
+ description: Number of 5xx errors before a host is ejected
+ from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveErrors:
+ format: int32
+ type: integer
+ consecutiveGatewayErrors:
+ description: Number of gateway errors before a host is ejected
+ from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveLocalOriginFailures:
+ description: The number of consecutive locally originated
+ failures before ejection occurs.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ interval:
+ description: Time interval between ejection sweep analysis.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxEjectionPercent:
+ description: Maximum % of hosts in the load balancing pool
+ for the upstream service that can be ejected.
+ format: int32
+ type: integer
+ minHealthPercent:
+ description: Outlier detection will be enabled as long as
+ the associated load balancing pool has at least `minHealthPercent`
+ hosts in healthy mode.
+ format: int32
+ type: integer
+ splitExternalLocalOriginErrors:
+ description: Determines whether to distinguish local origin
+ failures from external errors.
+ type: boolean
+ type: object
+ portLevelSettings:
+ description: Traffic policies specific to individual ports.
+ items:
+ properties:
+ connectionPool:
+ properties:
+ http:
+ description: HTTP connection pool settings.
+ properties:
+ h2UpgradePolicy:
+ description: |-
+ Specify if http1.1 connection should be upgraded to http2 for the associated destination.
+
+ Valid Options: DEFAULT, DO_NOT_UPGRADE, UPGRADE
+ enum:
+ - DEFAULT
+ - DO_NOT_UPGRADE
+ - UPGRADE
+ type: string
+ http1MaxPendingRequests:
+ description: Maximum number of requests that will
+ be queued while waiting for a ready connection
+ pool connection.
+ format: int32
+ type: integer
+ http2MaxRequests:
+ description: Maximum number of active requests to
+ a destination.
+ format: int32
+ type: integer
+ idleTimeout:
+ description: The idle timeout for upstream connection
+ pool connections.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConcurrentStreams:
+ description: The maximum number of concurrent streams
+ allowed for a peer on one HTTP/2 connection.
+ format: int32
+ type: integer
+ maxRequestsPerConnection:
+ description: Maximum number of requests per connection
+ to a backend.
+ format: int32
+ type: integer
+ maxRetries:
+ description: Maximum number of retries that can
+ be outstanding to all hosts in a cluster at a
+ given time.
+ format: int32
+ type: integer
+ useClientProtocol:
+ description: If set to true, client protocol will
+ be preserved while initiating connection to backend.
+ type: boolean
+ type: object
+ tcp:
+ description: Settings common to both HTTP and TCP upstream
+ connections.
+ properties:
+ connectTimeout:
+ description: TCP connection timeout.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ idleTimeout:
+ description: The idle timeout for TCP connections.
+ type: string
+ maxConnectionDuration:
+ description: The maximum duration of a connection.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConnections:
+ description: Maximum number of HTTP1 /TCP connections
+ to a destination host.
+ format: int32
+ type: integer
+ tcpKeepalive:
+ description: If set then set SO_KEEPALIVE on the
+ socket to enable TCP Keepalives.
+ properties:
+ interval:
+ description: The time duration between keep-alive
+ probes.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ probes:
+ description: Maximum number of keepalive probes
+ to send without response before deciding the
+ connection is dead.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ time:
+ description: The time duration a connection
+ needs to be idle before keep-alive probes
+ start being sent.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ type: object
+ type: object
+ loadBalancer:
+ description: Settings controlling the load balancer algorithms.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ properties:
+ consistentHash:
+ allOf:
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ properties:
+ httpCookie:
+ description: Hash based on HTTP cookie.
+ properties:
+ attributes:
+ description: Additional attributes for the cookie.
+ items:
+ properties:
+ name:
+ description: The name of the cookie attribute.
+ type: string
+ value:
+ description: The optional value of the
+ cookie attribute.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ name:
+ description: Name of the cookie.
+ type: string
+ path:
+ description: Path to set for the cookie.
+ type: string
+ ttl:
+ description: Lifetime of the cookie.
+ type: string
+ required:
+ - name
+ type: object
+ httpHeaderName:
+ description: Hash based on a specific HTTP header.
+ type: string
+ httpQueryParameterName:
+ description: Hash based on a specific HTTP query
+ parameter.
+ type: string
+ maglev:
+ description: The Maglev load balancer implements
+ consistent hashing to backend hosts.
+ properties:
+ tableSize:
+ description: The table size for Maglev hashing.
+ minimum: 0
+ type: integer
+ type: object
+ minimumRingSize:
+ description: Deprecated.
+ minimum: 0
+ type: integer
+ ringHash:
+ description: The ring/modulo hash load balancer
+ implements consistent hashing to backend hosts.
+ properties:
+ minimumRingSize:
+ description: The minimum number of virtual nodes
+ to use for the hash ring.
+ minimum: 0
+ type: integer
+ type: object
+ useSourceIp:
+ description: Hash based on the source IP address.
+ type: boolean
+ type: object
+ localityLbSetting:
+ properties:
+ distribute:
+ description: 'Optional: only one of distribute,
+ failover or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating locality, '/' separated,
+ e.g.
+ type: string
+ to:
+ additionalProperties:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ description: Map of upstream localities to
+ traffic distribution weights.
+ type: object
+ type: object
+ type: array
+ enabled:
+ description: Enable locality load balancing.
+ nullable: true
+ type: boolean
+ failover:
+ description: 'Optional: only one of distribute,
+ failover or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating region.
+ type: string
+ to:
+ description: Destination region the traffic
+ will fail over to when endpoints in the
+ 'from' region becomes unhealthy.
+ type: string
+ type: object
+ type: array
+ failoverPriority:
+ description: failoverPriority is an ordered list
+ of labels used to sort endpoints to do priority
+ based load balancing.
+ items:
+ type: string
+ type: array
+ type: object
+ simple:
+ description: |2-
+
+
+ Valid Options: LEAST_CONN, RANDOM, PASSTHROUGH, ROUND_ROBIN, LEAST_REQUEST
+ enum:
+ - UNSPECIFIED
+ - LEAST_CONN
+ - RANDOM
+ - PASSTHROUGH
+ - ROUND_ROBIN
+ - LEAST_REQUEST
+ type: string
+ warmup:
+ description: Represents the warmup configuration of
+ Service.
+ properties:
+ aggression:
+ description: This parameter controls the speed of
+ traffic increase over the warmup duration.
+ format: double
+ minimum: 0
+ nullable: true
+ type: number
+ duration:
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ minimumPercent:
+ format: double
+ maximum: 100
+ minimum: 0
+ nullable: true
+ type: number
+ required:
+ - duration
+ type: object
+ warmupDurationSecs:
+ description: 'Deprecated: use `warmup` instead.'
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ outlierDetection:
+ properties:
+ baseEjectionTime:
+ description: Minimum ejection duration.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ consecutive5xxErrors:
+ description: Number of 5xx errors before a host is ejected
+ from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveErrors:
+ format: int32
+ type: integer
+ consecutiveGatewayErrors:
+ description: Number of gateway errors before a host
+ is ejected from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveLocalOriginFailures:
+ description: The number of consecutive locally originated
+ failures before ejection occurs.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ interval:
+ description: Time interval between ejection sweep analysis.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxEjectionPercent:
+ description: Maximum % of hosts in the load balancing
+ pool for the upstream service that can be ejected.
+ format: int32
+ type: integer
+ minHealthPercent:
+ description: Outlier detection will be enabled as long
+ as the associated load balancing pool has at least
+ `minHealthPercent` hosts in healthy mode.
+ format: int32
+ type: integer
+ splitExternalLocalOriginErrors:
+ description: Determines whether to distinguish local
+ origin failures from external errors.
+ type: boolean
+ type: object
+ port:
+ description: Specifies the number of a port on the destination
+ service on which this policy is being applied.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ tls:
+ description: TLS related settings for connections to the
+ upstream service.
+ properties:
+ caCertificates:
+ description: 'OPTIONAL: The path to the file containing
+ certificate authority certificates to use in verifying
+ a presented server certificate.'
+ type: string
+ caCrl:
+ description: 'OPTIONAL: The path to the file containing
+ the certificate revocation list (CRL) to use in verifying
+ a presented server certificate.'
+ type: string
+ clientCertificate:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ credentialName:
+ description: The name of the secret that holds the TLS
+ certs for the client including the CA certificates.
+ type: string
+ insecureSkipVerify:
+ description: '`insecureSkipVerify` specifies whether
+ the proxy should skip verifying the CA signature and
+ SAN for the server certificate corresponding to the
+ host.'
+ nullable: true
+ type: boolean
+ mode:
+ description: |-
+ Indicates whether connections to this port should be secured using TLS.
+
+ Valid Options: DISABLE, SIMPLE, MUTUAL, ISTIO_MUTUAL
+ enum:
+ - DISABLE
+ - SIMPLE
+ - MUTUAL
+ - ISTIO_MUTUAL
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ sni:
+ description: SNI string to present to the server during
+ TLS handshake.
+ type: string
+ subjectAltNames:
+ description: A list of alternate names to verify the
+ subject identity in the certificate.
+ items:
+ type: string
+ type: array
+ type: object
+ type: object
+ maxItems: 4096
+ type: array
+ proxyProtocol:
+ description: The upstream PROXY protocol settings.
+ properties:
+ version:
+ description: |-
+ The PROXY protocol version to use.
+
+ Valid Options: V1, V2
+ enum:
+ - V1
+ - V2
+ type: string
+ type: object
+ retryBudget:
+ description: Specifies a limit on concurrent retries in relation
+ to the number of active requests.
+ properties:
+ minRetryConcurrency:
+ description: Specifies the minimum retry concurrency allowed
+ for the retry budget.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ percent:
+ description: Specifies the limit on concurrent retries as
+ a percentage of the sum of active requests and active pending
+ requests.
+ format: double
+ maximum: 100
+ minimum: 0
+ nullable: true
+ type: number
+ type: object
+ tls:
+ description: TLS related settings for connections to the upstream
+ service.
+ properties:
+ caCertificates:
+ description: 'OPTIONAL: The path to the file containing certificate
+ authority certificates to use in verifying a presented server
+ certificate.'
+ type: string
+ caCrl:
+ description: 'OPTIONAL: The path to the file containing the
+ certificate revocation list (CRL) to use in verifying a
+ presented server certificate.'
+ type: string
+ clientCertificate:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ credentialName:
+ description: The name of the secret that holds the TLS certs
+ for the client including the CA certificates.
+ type: string
+ insecureSkipVerify:
+ description: '`insecureSkipVerify` specifies whether the proxy
+ should skip verifying the CA signature and SAN for the server
+ certificate corresponding to the host.'
+ nullable: true
+ type: boolean
+ mode:
+ description: |-
+ Indicates whether connections to this port should be secured using TLS.
+
+ Valid Options: DISABLE, SIMPLE, MUTUAL, ISTIO_MUTUAL
+ enum:
+ - DISABLE
+ - SIMPLE
+ - MUTUAL
+ - ISTIO_MUTUAL
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ sni:
+ description: SNI string to present to the server during TLS
+ handshake.
+ type: string
+ subjectAltNames:
+ description: A list of alternate names to verify the subject
+ identity in the certificate.
+ items:
+ type: string
+ type: array
+ type: object
+ tunnel:
+ description: Configuration of tunneling TCP over other transport
+ or application layers for the host configured in the DestinationRule.
+ properties:
+ protocol:
+ description: Specifies which protocol to use for tunneling
+ the downstream connection.
+ type: string
+ targetHost:
+ description: Specifies a host to which the downstream connection
+ is tunneled.
+ type: string
+ targetPort:
+ description: Specifies a port to which the downstream connection
+ is tunneled.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ required:
+ - targetHost
+ - targetPort
+ type: object
+ type: object
+ workloadSelector:
+ description: Criteria used to select the specific set of pods/VMs
+ on which this `DestinationRule` configuration should be applied.
+ properties:
+ matchLabels:
+ additionalProperties:
+ maxLength: 63
+ type: string
+ x-kubernetes-validations:
+ - message: wildcard not allowed in label value match
+ rule: '!self.contains("*")'
+ description: One or more labels that indicate a specific set of
+ pods/VMs on which a policy should be applied.
+ maxProperties: 4096
+ type: object
+ x-kubernetes-validations:
+ - message: wildcard not allowed in label key match
+ rule: self.all(key, !key.contains("*"))
+ - message: key must not be empty
+ rule: self.all(key, key.size() != 0)
+ type: object
+ required:
+ - host
+ type: object
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
+ - additionalPrinterColumns:
+ - description: The name of a service from the service registry
+ jsonPath: .spec.host
+ name: Host
+ type: string
+ - description: CreationTimestamp is a timestamp representing the server time when
+ this object was created. It is not guaranteed to be set in happens-before
+ order across separate operations. Clients may not set this value. It is represented
+ in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for
+ lists. For more information, see [Kubernetes API Conventions](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#metadata)
+ jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1alpha3
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Configuration affecting load balancing, outlier detection,
+ etc. See more details at: https://istio.io/docs/reference/config/networking/destination-rule.html'
+ properties:
+ exportTo:
+ description: A list of namespaces to which this destination rule is
+ exported.
+ items:
+ type: string
+ type: array
+ host:
+ description: The name of a service from the service registry.
+ type: string
+ subsets:
+ description: One or more named sets that represent individual versions
+ of a service.
+ items:
+ properties:
+ labels:
+ additionalProperties:
+ type: string
+ description: Labels apply a filter over the endpoints of a service
+ in the service registry.
+ type: object
+ name:
+ description: Name of the subset.
+ type: string
+ trafficPolicy:
+ description: Traffic policies that apply to this subset.
+ properties:
+ connectionPool:
+ properties:
+ http:
+ description: HTTP connection pool settings.
+ properties:
+ h2UpgradePolicy:
+ description: |-
+ Specify if http1.1 connection should be upgraded to http2 for the associated destination.
+
+ Valid Options: DEFAULT, DO_NOT_UPGRADE, UPGRADE
+ enum:
+ - DEFAULT
+ - DO_NOT_UPGRADE
+ - UPGRADE
+ type: string
+ http1MaxPendingRequests:
+ description: Maximum number of requests that will
+ be queued while waiting for a ready connection
+ pool connection.
+ format: int32
+ type: integer
+ http2MaxRequests:
+ description: Maximum number of active requests to
+ a destination.
+ format: int32
+ type: integer
+ idleTimeout:
+ description: The idle timeout for upstream connection
+ pool connections.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConcurrentStreams:
+ description: The maximum number of concurrent streams
+ allowed for a peer on one HTTP/2 connection.
+ format: int32
+ type: integer
+ maxRequestsPerConnection:
+ description: Maximum number of requests per connection
+ to a backend.
+ format: int32
+ type: integer
+ maxRetries:
+ description: Maximum number of retries that can
+ be outstanding to all hosts in a cluster at a
+ given time.
+ format: int32
+ type: integer
+ useClientProtocol:
+ description: If set to true, client protocol will
+ be preserved while initiating connection to backend.
+ type: boolean
+ type: object
+ tcp:
+ description: Settings common to both HTTP and TCP upstream
+ connections.
+ properties:
+ connectTimeout:
+ description: TCP connection timeout.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ idleTimeout:
+ description: The idle timeout for TCP connections.
+ type: string
+ maxConnectionDuration:
+ description: The maximum duration of a connection.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConnections:
+ description: Maximum number of HTTP1 /TCP connections
+ to a destination host.
+ format: int32
+ type: integer
+ tcpKeepalive:
+ description: If set then set SO_KEEPALIVE on the
+ socket to enable TCP Keepalives.
+ properties:
+ interval:
+ description: The time duration between keep-alive
+ probes.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ probes:
+ description: Maximum number of keepalive probes
+ to send without response before deciding the
+ connection is dead.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ time:
+ description: The time duration a connection
+ needs to be idle before keep-alive probes
+ start being sent.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ type: object
+ type: object
+ loadBalancer:
+ description: Settings controlling the load balancer algorithms.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ properties:
+ consistentHash:
+ allOf:
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ properties:
+ httpCookie:
+ description: Hash based on HTTP cookie.
+ properties:
+ attributes:
+ description: Additional attributes for the cookie.
+ items:
+ properties:
+ name:
+ description: The name of the cookie attribute.
+ type: string
+ value:
+ description: The optional value of the
+ cookie attribute.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ name:
+ description: Name of the cookie.
+ type: string
+ path:
+ description: Path to set for the cookie.
+ type: string
+ ttl:
+ description: Lifetime of the cookie.
+ type: string
+ required:
+ - name
+ type: object
+ httpHeaderName:
+ description: Hash based on a specific HTTP header.
+ type: string
+ httpQueryParameterName:
+ description: Hash based on a specific HTTP query
+ parameter.
+ type: string
+ maglev:
+ description: The Maglev load balancer implements
+ consistent hashing to backend hosts.
+ properties:
+ tableSize:
+ description: The table size for Maglev hashing.
+ minimum: 0
+ type: integer
+ type: object
+ minimumRingSize:
+ description: Deprecated.
+ minimum: 0
+ type: integer
+ ringHash:
+ description: The ring/modulo hash load balancer
+ implements consistent hashing to backend hosts.
+ properties:
+ minimumRingSize:
+ description: The minimum number of virtual nodes
+ to use for the hash ring.
+ minimum: 0
+ type: integer
+ type: object
+ useSourceIp:
+ description: Hash based on the source IP address.
+ type: boolean
+ type: object
+ localityLbSetting:
+ properties:
+ distribute:
+ description: 'Optional: only one of distribute,
+ failover or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating locality, '/' separated,
+ e.g.
+ type: string
+ to:
+ additionalProperties:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ description: Map of upstream localities to
+ traffic distribution weights.
+ type: object
+ type: object
+ type: array
+ enabled:
+ description: Enable locality load balancing.
+ nullable: true
+ type: boolean
+ failover:
+ description: 'Optional: only one of distribute,
+ failover or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating region.
+ type: string
+ to:
+ description: Destination region the traffic
+ will fail over to when endpoints in the
+ 'from' region becomes unhealthy.
+ type: string
+ type: object
+ type: array
+ failoverPriority:
+ description: failoverPriority is an ordered list
+ of labels used to sort endpoints to do priority
+ based load balancing.
+ items:
+ type: string
+ type: array
+ type: object
+ simple:
+ description: |2-
+
+
+ Valid Options: LEAST_CONN, RANDOM, PASSTHROUGH, ROUND_ROBIN, LEAST_REQUEST
+ enum:
+ - UNSPECIFIED
+ - LEAST_CONN
+ - RANDOM
+ - PASSTHROUGH
+ - ROUND_ROBIN
+ - LEAST_REQUEST
+ type: string
+ warmup:
+ description: Represents the warmup configuration of
+ Service.
+ properties:
+ aggression:
+ description: This parameter controls the speed of
+ traffic increase over the warmup duration.
+ format: double
+ minimum: 0
+ nullable: true
+ type: number
+ duration:
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ minimumPercent:
+ format: double
+ maximum: 100
+ minimum: 0
+ nullable: true
+ type: number
+ required:
+ - duration
+ type: object
+ warmupDurationSecs:
+ description: 'Deprecated: use `warmup` instead.'
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ outlierDetection:
+ properties:
+ baseEjectionTime:
+ description: Minimum ejection duration.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ consecutive5xxErrors:
+ description: Number of 5xx errors before a host is ejected
+ from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveErrors:
+ format: int32
+ type: integer
+ consecutiveGatewayErrors:
+ description: Number of gateway errors before a host
+ is ejected from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveLocalOriginFailures:
+ description: The number of consecutive locally originated
+ failures before ejection occurs.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ interval:
+ description: Time interval between ejection sweep analysis.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxEjectionPercent:
+ description: Maximum % of hosts in the load balancing
+ pool for the upstream service that can be ejected.
+ format: int32
+ type: integer
+ minHealthPercent:
+ description: Outlier detection will be enabled as long
+ as the associated load balancing pool has at least
+ `minHealthPercent` hosts in healthy mode.
+ format: int32
+ type: integer
+ splitExternalLocalOriginErrors:
+ description: Determines whether to distinguish local
+ origin failures from external errors.
+ type: boolean
+ type: object
+ portLevelSettings:
+ description: Traffic policies specific to individual ports.
+ items:
+ properties:
+ connectionPool:
+ properties:
+ http:
+ description: HTTP connection pool settings.
+ properties:
+ h2UpgradePolicy:
+ description: |-
+ Specify if http1.1 connection should be upgraded to http2 for the associated destination.
+
+ Valid Options: DEFAULT, DO_NOT_UPGRADE, UPGRADE
+ enum:
+ - DEFAULT
+ - DO_NOT_UPGRADE
+ - UPGRADE
+ type: string
+ http1MaxPendingRequests:
+ description: Maximum number of requests that
+ will be queued while waiting for a ready
+ connection pool connection.
+ format: int32
+ type: integer
+ http2MaxRequests:
+ description: Maximum number of active requests
+ to a destination.
+ format: int32
+ type: integer
+ idleTimeout:
+ description: The idle timeout for upstream
+ connection pool connections.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConcurrentStreams:
+ description: The maximum number of concurrent
+ streams allowed for a peer on one HTTP/2
+ connection.
+ format: int32
+ type: integer
+ maxRequestsPerConnection:
+ description: Maximum number of requests per
+ connection to a backend.
+ format: int32
+ type: integer
+ maxRetries:
+ description: Maximum number of retries that
+ can be outstanding to all hosts in a cluster
+ at a given time.
+ format: int32
+ type: integer
+ useClientProtocol:
+ description: If set to true, client protocol
+ will be preserved while initiating connection
+ to backend.
+ type: boolean
+ type: object
+ tcp:
+ description: Settings common to both HTTP and
+ TCP upstream connections.
+ properties:
+ connectTimeout:
+ description: TCP connection timeout.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ idleTimeout:
+ description: The idle timeout for TCP connections.
+ type: string
+ maxConnectionDuration:
+ description: The maximum duration of a connection.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConnections:
+ description: Maximum number of HTTP1 /TCP
+ connections to a destination host.
+ format: int32
+ type: integer
+ tcpKeepalive:
+ description: If set then set SO_KEEPALIVE
+ on the socket to enable TCP Keepalives.
+ properties:
+ interval:
+ description: The time duration between
+ keep-alive probes.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ probes:
+ description: Maximum number of keepalive
+ probes to send without response before
+ deciding the connection is dead.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ time:
+ description: The time duration a connection
+ needs to be idle before keep-alive probes
+ start being sent.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ type: object
+ type: object
+ loadBalancer:
+ description: Settings controlling the load balancer
+ algorithms.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ properties:
+ consistentHash:
+ allOf:
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ properties:
+ httpCookie:
+ description: Hash based on HTTP cookie.
+ properties:
+ attributes:
+ description: Additional attributes for
+ the cookie.
+ items:
+ properties:
+ name:
+ description: The name of the cookie
+ attribute.
+ type: string
+ value:
+ description: The optional value
+ of the cookie attribute.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ name:
+ description: Name of the cookie.
+ type: string
+ path:
+ description: Path to set for the cookie.
+ type: string
+ ttl:
+ description: Lifetime of the cookie.
+ type: string
+ required:
+ - name
+ type: object
+ httpHeaderName:
+ description: Hash based on a specific HTTP
+ header.
+ type: string
+ httpQueryParameterName:
+ description: Hash based on a specific HTTP
+ query parameter.
+ type: string
+ maglev:
+ description: The Maglev load balancer implements
+ consistent hashing to backend hosts.
+ properties:
+ tableSize:
+ description: The table size for Maglev
+ hashing.
+ minimum: 0
+ type: integer
+ type: object
+ minimumRingSize:
+ description: Deprecated.
+ minimum: 0
+ type: integer
+ ringHash:
+ description: The ring/modulo hash load balancer
+ implements consistent hashing to backend
+ hosts.
+ properties:
+ minimumRingSize:
+ description: The minimum number of virtual
+ nodes to use for the hash ring.
+ minimum: 0
+ type: integer
+ type: object
+ useSourceIp:
+ description: Hash based on the source IP address.
+ type: boolean
+ type: object
+ localityLbSetting:
+ properties:
+ distribute:
+ description: 'Optional: only one of distribute,
+ failover or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating locality, '/'
+ separated, e.g.
+ type: string
+ to:
+ additionalProperties:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ description: Map of upstream localities
+ to traffic distribution weights.
+ type: object
+ type: object
+ type: array
+ enabled:
+ description: Enable locality load balancing.
+ nullable: true
+ type: boolean
+ failover:
+ description: 'Optional: only one of distribute,
+ failover or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating region.
+ type: string
+ to:
+ description: Destination region the
+ traffic will fail over to when endpoints
+ in the 'from' region becomes unhealthy.
+ type: string
+ type: object
+ type: array
+ failoverPriority:
+ description: failoverPriority is an ordered
+ list of labels used to sort endpoints to
+ do priority based load balancing.
+ items:
+ type: string
+ type: array
+ type: object
+ simple:
+ description: |2-
+
+
+ Valid Options: LEAST_CONN, RANDOM, PASSTHROUGH, ROUND_ROBIN, LEAST_REQUEST
+ enum:
+ - UNSPECIFIED
+ - LEAST_CONN
+ - RANDOM
+ - PASSTHROUGH
+ - ROUND_ROBIN
+ - LEAST_REQUEST
+ type: string
+ warmup:
+ description: Represents the warmup configuration
+ of Service.
+ properties:
+ aggression:
+ description: This parameter controls the speed
+ of traffic increase over the warmup duration.
+ format: double
+ minimum: 0
+ nullable: true
+ type: number
+ duration:
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ minimumPercent:
+ format: double
+ maximum: 100
+ minimum: 0
+ nullable: true
+ type: number
+ required:
+ - duration
+ type: object
+ warmupDurationSecs:
+ description: 'Deprecated: use `warmup` instead.'
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ outlierDetection:
+ properties:
+ baseEjectionTime:
+ description: Minimum ejection duration.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ consecutive5xxErrors:
+ description: Number of 5xx errors before a host
+ is ejected from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveErrors:
+ format: int32
+ type: integer
+ consecutiveGatewayErrors:
+ description: Number of gateway errors before a
+ host is ejected from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveLocalOriginFailures:
+ description: The number of consecutive locally
+ originated failures before ejection occurs.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ interval:
+ description: Time interval between ejection sweep
+ analysis.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ maxEjectionPercent:
+ description: Maximum % of hosts in the load balancing
+ pool for the upstream service that can be ejected.
+ format: int32
+ type: integer
+ minHealthPercent:
+ description: Outlier detection will be enabled
+ as long as the associated load balancing pool
+ has at least `minHealthPercent` hosts in healthy
+ mode.
+ format: int32
+ type: integer
+ splitExternalLocalOriginErrors:
+ description: Determines whether to distinguish
+ local origin failures from external errors.
+ type: boolean
+ type: object
+ port:
+ description: Specifies the number of a port on the
+ destination service on which this policy is being
+ applied.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ tls:
+ description: TLS related settings for connections
+ to the upstream service.
+ properties:
+ caCertificates:
+ description: 'OPTIONAL: The path to the file containing
+ certificate authority certificates to use in
+ verifying a presented server certificate.'
+ type: string
+ caCrl:
+ description: 'OPTIONAL: The path to the file containing
+ the certificate revocation list (CRL) to use
+ in verifying a presented server certificate.'
+ type: string
+ clientCertificate:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ credentialName:
+ description: The name of the secret that holds
+ the TLS certs for the client including the CA
+ certificates.
+ type: string
+ insecureSkipVerify:
+ description: '`insecureSkipVerify` specifies whether
+ the proxy should skip verifying the CA signature
+ and SAN for the server certificate corresponding
+ to the host.'
+ nullable: true
+ type: boolean
+ mode:
+ description: |-
+ Indicates whether connections to this port should be secured using TLS.
+
+ Valid Options: DISABLE, SIMPLE, MUTUAL, ISTIO_MUTUAL
+ enum:
+ - DISABLE
+ - SIMPLE
+ - MUTUAL
+ - ISTIO_MUTUAL
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ sni:
+ description: SNI string to present to the server
+ during TLS handshake.
+ type: string
+ subjectAltNames:
+ description: A list of alternate names to verify
+ the subject identity in the certificate.
+ items:
+ type: string
+ type: array
+ type: object
+ type: object
+ maxItems: 4096
+ type: array
+ proxyProtocol:
+ description: The upstream PROXY protocol settings.
+ properties:
+ version:
+ description: |-
+ The PROXY protocol version to use.
+
+ Valid Options: V1, V2
+ enum:
+ - V1
+ - V2
+ type: string
+ type: object
+ retryBudget:
+ description: Specifies a limit on concurrent retries in
+ relation to the number of active requests.
+ properties:
+ minRetryConcurrency:
+ description: Specifies the minimum retry concurrency
+ allowed for the retry budget.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ percent:
+ description: Specifies the limit on concurrent retries
+ as a percentage of the sum of active requests and
+ active pending requests.
+ format: double
+ maximum: 100
+ minimum: 0
+ nullable: true
+ type: number
+ type: object
+ tls:
+ description: TLS related settings for connections to the
+ upstream service.
+ properties:
+ caCertificates:
+ description: 'OPTIONAL: The path to the file containing
+ certificate authority certificates to use in verifying
+ a presented server certificate.'
+ type: string
+ caCrl:
+ description: 'OPTIONAL: The path to the file containing
+ the certificate revocation list (CRL) to use in verifying
+ a presented server certificate.'
+ type: string
+ clientCertificate:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ credentialName:
+ description: The name of the secret that holds the TLS
+ certs for the client including the CA certificates.
+ type: string
+ insecureSkipVerify:
+ description: '`insecureSkipVerify` specifies whether
+ the proxy should skip verifying the CA signature and
+ SAN for the server certificate corresponding to the
+ host.'
+ nullable: true
+ type: boolean
+ mode:
+ description: |-
+ Indicates whether connections to this port should be secured using TLS.
+
+ Valid Options: DISABLE, SIMPLE, MUTUAL, ISTIO_MUTUAL
+ enum:
+ - DISABLE
+ - SIMPLE
+ - MUTUAL
+ - ISTIO_MUTUAL
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ sni:
+ description: SNI string to present to the server during
+ TLS handshake.
+ type: string
+ subjectAltNames:
+ description: A list of alternate names to verify the
+ subject identity in the certificate.
+ items:
+ type: string
+ type: array
+ type: object
+ tunnel:
+ description: Configuration of tunneling TCP over other transport
+ or application layers for the host configured in the DestinationRule.
+ properties:
+ protocol:
+ description: Specifies which protocol to use for tunneling
+ the downstream connection.
+ type: string
+ targetHost:
+ description: Specifies a host to which the downstream
+ connection is tunneled.
+ type: string
+ targetPort:
+ description: Specifies a port to which the downstream
+ connection is tunneled.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ required:
+ - targetHost
+ - targetPort
+ type: object
+ type: object
+ required:
+ - name
+ type: object
+ type: array
+ trafficPolicy:
+ description: Traffic policies to apply (load balancing policy, connection
+ pool sizes, outlier detection).
+ properties:
+ connectionPool:
+ properties:
+ http:
+ description: HTTP connection pool settings.
+ properties:
+ h2UpgradePolicy:
+ description: |-
+ Specify if http1.1 connection should be upgraded to http2 for the associated destination.
+
+ Valid Options: DEFAULT, DO_NOT_UPGRADE, UPGRADE
+ enum:
+ - DEFAULT
+ - DO_NOT_UPGRADE
+ - UPGRADE
+ type: string
+ http1MaxPendingRequests:
+ description: Maximum number of requests that will be queued
+ while waiting for a ready connection pool connection.
+ format: int32
+ type: integer
+ http2MaxRequests:
+ description: Maximum number of active requests to a destination.
+ format: int32
+ type: integer
+ idleTimeout:
+ description: The idle timeout for upstream connection
+ pool connections.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConcurrentStreams:
+ description: The maximum number of concurrent streams
+ allowed for a peer on one HTTP/2 connection.
+ format: int32
+ type: integer
+ maxRequestsPerConnection:
+ description: Maximum number of requests per connection
+ to a backend.
+ format: int32
+ type: integer
+ maxRetries:
+ description: Maximum number of retries that can be outstanding
+ to all hosts in a cluster at a given time.
+ format: int32
+ type: integer
+ useClientProtocol:
+ description: If set to true, client protocol will be preserved
+ while initiating connection to backend.
+ type: boolean
+ type: object
+ tcp:
+ description: Settings common to both HTTP and TCP upstream
+ connections.
+ properties:
+ connectTimeout:
+ description: TCP connection timeout.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ idleTimeout:
+ description: The idle timeout for TCP connections.
+ type: string
+ maxConnectionDuration:
+ description: The maximum duration of a connection.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConnections:
+ description: Maximum number of HTTP1 /TCP connections
+ to a destination host.
+ format: int32
+ type: integer
+ tcpKeepalive:
+ description: If set then set SO_KEEPALIVE on the socket
+ to enable TCP Keepalives.
+ properties:
+ interval:
+ description: The time duration between keep-alive
+ probes.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ probes:
+ description: Maximum number of keepalive probes to
+ send without response before deciding the connection
+ is dead.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ time:
+ description: The time duration a connection needs
+ to be idle before keep-alive probes start being
+ sent.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ type: object
+ type: object
+ loadBalancer:
+ description: Settings controlling the load balancer algorithms.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ properties:
+ consistentHash:
+ allOf:
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ properties:
+ httpCookie:
+ description: Hash based on HTTP cookie.
+ properties:
+ attributes:
+ description: Additional attributes for the cookie.
+ items:
+ properties:
+ name:
+ description: The name of the cookie attribute.
+ type: string
+ value:
+ description: The optional value of the cookie
+ attribute.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ name:
+ description: Name of the cookie.
+ type: string
+ path:
+ description: Path to set for the cookie.
+ type: string
+ ttl:
+ description: Lifetime of the cookie.
+ type: string
+ required:
+ - name
+ type: object
+ httpHeaderName:
+ description: Hash based on a specific HTTP header.
+ type: string
+ httpQueryParameterName:
+ description: Hash based on a specific HTTP query parameter.
+ type: string
+ maglev:
+ description: The Maglev load balancer implements consistent
+ hashing to backend hosts.
+ properties:
+ tableSize:
+ description: The table size for Maglev hashing.
+ minimum: 0
+ type: integer
+ type: object
+ minimumRingSize:
+ description: Deprecated.
+ minimum: 0
+ type: integer
+ ringHash:
+ description: The ring/modulo hash load balancer implements
+ consistent hashing to backend hosts.
+ properties:
+ minimumRingSize:
+ description: The minimum number of virtual nodes to
+ use for the hash ring.
+ minimum: 0
+ type: integer
+ type: object
+ useSourceIp:
+ description: Hash based on the source IP address.
+ type: boolean
+ type: object
+ localityLbSetting:
+ properties:
+ distribute:
+ description: 'Optional: only one of distribute, failover
+ or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating locality, '/' separated,
+ e.g.
+ type: string
+ to:
+ additionalProperties:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ description: Map of upstream localities to traffic
+ distribution weights.
+ type: object
+ type: object
+ type: array
+ enabled:
+ description: Enable locality load balancing.
+ nullable: true
+ type: boolean
+ failover:
+ description: 'Optional: only one of distribute, failover
+ or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating region.
+ type: string
+ to:
+ description: Destination region the traffic will
+ fail over to when endpoints in the 'from' region
+ becomes unhealthy.
+ type: string
+ type: object
+ type: array
+ failoverPriority:
+ description: failoverPriority is an ordered list of labels
+ used to sort endpoints to do priority based load balancing.
+ items:
+ type: string
+ type: array
+ type: object
+ simple:
+ description: |2-
+
+
+ Valid Options: LEAST_CONN, RANDOM, PASSTHROUGH, ROUND_ROBIN, LEAST_REQUEST
+ enum:
+ - UNSPECIFIED
+ - LEAST_CONN
+ - RANDOM
+ - PASSTHROUGH
+ - ROUND_ROBIN
+ - LEAST_REQUEST
+ type: string
+ warmup:
+ description: Represents the warmup configuration of Service.
+ properties:
+ aggression:
+ description: This parameter controls the speed of traffic
+ increase over the warmup duration.
+ format: double
+ minimum: 0
+ nullable: true
+ type: number
+ duration:
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ minimumPercent:
+ format: double
+ maximum: 100
+ minimum: 0
+ nullable: true
+ type: number
+ required:
+ - duration
+ type: object
+ warmupDurationSecs:
+ description: 'Deprecated: use `warmup` instead.'
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ outlierDetection:
+ properties:
+ baseEjectionTime:
+ description: Minimum ejection duration.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ consecutive5xxErrors:
+ description: Number of 5xx errors before a host is ejected
+ from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveErrors:
+ format: int32
+ type: integer
+ consecutiveGatewayErrors:
+ description: Number of gateway errors before a host is ejected
+ from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveLocalOriginFailures:
+ description: The number of consecutive locally originated
+ failures before ejection occurs.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ interval:
+ description: Time interval between ejection sweep analysis.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxEjectionPercent:
+ description: Maximum % of hosts in the load balancing pool
+ for the upstream service that can be ejected.
+ format: int32
+ type: integer
+ minHealthPercent:
+ description: Outlier detection will be enabled as long as
+ the associated load balancing pool has at least `minHealthPercent`
+ hosts in healthy mode.
+ format: int32
+ type: integer
+ splitExternalLocalOriginErrors:
+ description: Determines whether to distinguish local origin
+ failures from external errors.
+ type: boolean
+ type: object
+ portLevelSettings:
+ description: Traffic policies specific to individual ports.
+ items:
+ properties:
+ connectionPool:
+ properties:
+ http:
+ description: HTTP connection pool settings.
+ properties:
+ h2UpgradePolicy:
+ description: |-
+ Specify if http1.1 connection should be upgraded to http2 for the associated destination.
+
+ Valid Options: DEFAULT, DO_NOT_UPGRADE, UPGRADE
+ enum:
+ - DEFAULT
+ - DO_NOT_UPGRADE
+ - UPGRADE
+ type: string
+ http1MaxPendingRequests:
+ description: Maximum number of requests that will
+ be queued while waiting for a ready connection
+ pool connection.
+ format: int32
+ type: integer
+ http2MaxRequests:
+ description: Maximum number of active requests to
+ a destination.
+ format: int32
+ type: integer
+ idleTimeout:
+ description: The idle timeout for upstream connection
+ pool connections.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConcurrentStreams:
+ description: The maximum number of concurrent streams
+ allowed for a peer on one HTTP/2 connection.
+ format: int32
+ type: integer
+ maxRequestsPerConnection:
+ description: Maximum number of requests per connection
+ to a backend.
+ format: int32
+ type: integer
+ maxRetries:
+ description: Maximum number of retries that can
+ be outstanding to all hosts in a cluster at a
+ given time.
+ format: int32
+ type: integer
+ useClientProtocol:
+ description: If set to true, client protocol will
+ be preserved while initiating connection to backend.
+ type: boolean
+ type: object
+ tcp:
+ description: Settings common to both HTTP and TCP upstream
+ connections.
+ properties:
+ connectTimeout:
+ description: TCP connection timeout.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ idleTimeout:
+ description: The idle timeout for TCP connections.
+ type: string
+ maxConnectionDuration:
+ description: The maximum duration of a connection.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConnections:
+ description: Maximum number of HTTP1 /TCP connections
+ to a destination host.
+ format: int32
+ type: integer
+ tcpKeepalive:
+ description: If set then set SO_KEEPALIVE on the
+ socket to enable TCP Keepalives.
+ properties:
+ interval:
+ description: The time duration between keep-alive
+ probes.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ probes:
+ description: Maximum number of keepalive probes
+ to send without response before deciding the
+ connection is dead.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ time:
+ description: The time duration a connection
+ needs to be idle before keep-alive probes
+ start being sent.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ type: object
+ type: object
+ loadBalancer:
+ description: Settings controlling the load balancer algorithms.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ properties:
+ consistentHash:
+ allOf:
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ properties:
+ httpCookie:
+ description: Hash based on HTTP cookie.
+ properties:
+ attributes:
+ description: Additional attributes for the cookie.
+ items:
+ properties:
+ name:
+ description: The name of the cookie attribute.
+ type: string
+ value:
+ description: The optional value of the
+ cookie attribute.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ name:
+ description: Name of the cookie.
+ type: string
+ path:
+ description: Path to set for the cookie.
+ type: string
+ ttl:
+ description: Lifetime of the cookie.
+ type: string
+ required:
+ - name
+ type: object
+ httpHeaderName:
+ description: Hash based on a specific HTTP header.
+ type: string
+ httpQueryParameterName:
+ description: Hash based on a specific HTTP query
+ parameter.
+ type: string
+ maglev:
+ description: The Maglev load balancer implements
+ consistent hashing to backend hosts.
+ properties:
+ tableSize:
+ description: The table size for Maglev hashing.
+ minimum: 0
+ type: integer
+ type: object
+ minimumRingSize:
+ description: Deprecated.
+ minimum: 0
+ type: integer
+ ringHash:
+ description: The ring/modulo hash load balancer
+ implements consistent hashing to backend hosts.
+ properties:
+ minimumRingSize:
+ description: The minimum number of virtual nodes
+ to use for the hash ring.
+ minimum: 0
+ type: integer
+ type: object
+ useSourceIp:
+ description: Hash based on the source IP address.
+ type: boolean
+ type: object
+ localityLbSetting:
+ properties:
+ distribute:
+ description: 'Optional: only one of distribute,
+ failover or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating locality, '/' separated,
+ e.g.
+ type: string
+ to:
+ additionalProperties:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ description: Map of upstream localities to
+ traffic distribution weights.
+ type: object
+ type: object
+ type: array
+ enabled:
+ description: Enable locality load balancing.
+ nullable: true
+ type: boolean
+ failover:
+ description: 'Optional: only one of distribute,
+ failover or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating region.
+ type: string
+ to:
+ description: Destination region the traffic
+ will fail over to when endpoints in the
+ 'from' region becomes unhealthy.
+ type: string
+ type: object
+ type: array
+ failoverPriority:
+ description: failoverPriority is an ordered list
+ of labels used to sort endpoints to do priority
+ based load balancing.
+ items:
+ type: string
+ type: array
+ type: object
+ simple:
+ description: |2-
+
+
+ Valid Options: LEAST_CONN, RANDOM, PASSTHROUGH, ROUND_ROBIN, LEAST_REQUEST
+ enum:
+ - UNSPECIFIED
+ - LEAST_CONN
+ - RANDOM
+ - PASSTHROUGH
+ - ROUND_ROBIN
+ - LEAST_REQUEST
+ type: string
+ warmup:
+ description: Represents the warmup configuration of
+ Service.
+ properties:
+ aggression:
+ description: This parameter controls the speed of
+ traffic increase over the warmup duration.
+ format: double
+ minimum: 0
+ nullable: true
+ type: number
+ duration:
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ minimumPercent:
+ format: double
+ maximum: 100
+ minimum: 0
+ nullable: true
+ type: number
+ required:
+ - duration
+ type: object
+ warmupDurationSecs:
+ description: 'Deprecated: use `warmup` instead.'
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ outlierDetection:
+ properties:
+ baseEjectionTime:
+ description: Minimum ejection duration.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ consecutive5xxErrors:
+ description: Number of 5xx errors before a host is ejected
+ from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveErrors:
+ format: int32
+ type: integer
+ consecutiveGatewayErrors:
+ description: Number of gateway errors before a host
+ is ejected from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveLocalOriginFailures:
+ description: The number of consecutive locally originated
+ failures before ejection occurs.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ interval:
+ description: Time interval between ejection sweep analysis.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxEjectionPercent:
+ description: Maximum % of hosts in the load balancing
+ pool for the upstream service that can be ejected.
+ format: int32
+ type: integer
+ minHealthPercent:
+ description: Outlier detection will be enabled as long
+ as the associated load balancing pool has at least
+ `minHealthPercent` hosts in healthy mode.
+ format: int32
+ type: integer
+ splitExternalLocalOriginErrors:
+ description: Determines whether to distinguish local
+ origin failures from external errors.
+ type: boolean
+ type: object
+ port:
+ description: Specifies the number of a port on the destination
+ service on which this policy is being applied.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ tls:
+ description: TLS related settings for connections to the
+ upstream service.
+ properties:
+ caCertificates:
+ description: 'OPTIONAL: The path to the file containing
+ certificate authority certificates to use in verifying
+ a presented server certificate.'
+ type: string
+ caCrl:
+ description: 'OPTIONAL: The path to the file containing
+ the certificate revocation list (CRL) to use in verifying
+ a presented server certificate.'
+ type: string
+ clientCertificate:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ credentialName:
+ description: The name of the secret that holds the TLS
+ certs for the client including the CA certificates.
+ type: string
+ insecureSkipVerify:
+ description: '`insecureSkipVerify` specifies whether
+ the proxy should skip verifying the CA signature and
+ SAN for the server certificate corresponding to the
+ host.'
+ nullable: true
+ type: boolean
+ mode:
+ description: |-
+ Indicates whether connections to this port should be secured using TLS.
+
+ Valid Options: DISABLE, SIMPLE, MUTUAL, ISTIO_MUTUAL
+ enum:
+ - DISABLE
+ - SIMPLE
+ - MUTUAL
+ - ISTIO_MUTUAL
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ sni:
+ description: SNI string to present to the server during
+ TLS handshake.
+ type: string
+ subjectAltNames:
+ description: A list of alternate names to verify the
+ subject identity in the certificate.
+ items:
+ type: string
+ type: array
+ type: object
+ type: object
+ maxItems: 4096
+ type: array
+ proxyProtocol:
+ description: The upstream PROXY protocol settings.
+ properties:
+ version:
+ description: |-
+ The PROXY protocol version to use.
+
+ Valid Options: V1, V2
+ enum:
+ - V1
+ - V2
+ type: string
+ type: object
+ retryBudget:
+ description: Specifies a limit on concurrent retries in relation
+ to the number of active requests.
+ properties:
+ minRetryConcurrency:
+ description: Specifies the minimum retry concurrency allowed
+ for the retry budget.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ percent:
+ description: Specifies the limit on concurrent retries as
+ a percentage of the sum of active requests and active pending
+ requests.
+ format: double
+ maximum: 100
+ minimum: 0
+ nullable: true
+ type: number
+ type: object
+ tls:
+ description: TLS related settings for connections to the upstream
+ service.
+ properties:
+ caCertificates:
+ description: 'OPTIONAL: The path to the file containing certificate
+ authority certificates to use in verifying a presented server
+ certificate.'
+ type: string
+ caCrl:
+ description: 'OPTIONAL: The path to the file containing the
+ certificate revocation list (CRL) to use in verifying a
+ presented server certificate.'
+ type: string
+ clientCertificate:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ credentialName:
+ description: The name of the secret that holds the TLS certs
+ for the client including the CA certificates.
+ type: string
+ insecureSkipVerify:
+ description: '`insecureSkipVerify` specifies whether the proxy
+ should skip verifying the CA signature and SAN for the server
+ certificate corresponding to the host.'
+ nullable: true
+ type: boolean
+ mode:
+ description: |-
+ Indicates whether connections to this port should be secured using TLS.
+
+ Valid Options: DISABLE, SIMPLE, MUTUAL, ISTIO_MUTUAL
+ enum:
+ - DISABLE
+ - SIMPLE
+ - MUTUAL
+ - ISTIO_MUTUAL
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ sni:
+ description: SNI string to present to the server during TLS
+ handshake.
+ type: string
+ subjectAltNames:
+ description: A list of alternate names to verify the subject
+ identity in the certificate.
+ items:
+ type: string
+ type: array
+ type: object
+ tunnel:
+ description: Configuration of tunneling TCP over other transport
+ or application layers for the host configured in the DestinationRule.
+ properties:
+ protocol:
+ description: Specifies which protocol to use for tunneling
+ the downstream connection.
+ type: string
+ targetHost:
+ description: Specifies a host to which the downstream connection
+ is tunneled.
+ type: string
+ targetPort:
+ description: Specifies a port to which the downstream connection
+ is tunneled.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ required:
+ - targetHost
+ - targetPort
+ type: object
+ type: object
+ workloadSelector:
+ description: Criteria used to select the specific set of pods/VMs
+ on which this `DestinationRule` configuration should be applied.
+ properties:
+ matchLabels:
+ additionalProperties:
+ maxLength: 63
+ type: string
+ x-kubernetes-validations:
+ - message: wildcard not allowed in label value match
+ rule: '!self.contains("*")'
+ description: One or more labels that indicate a specific set of
+ pods/VMs on which a policy should be applied.
+ maxProperties: 4096
+ type: object
+ x-kubernetes-validations:
+ - message: wildcard not allowed in label key match
+ rule: self.all(key, !key.contains("*"))
+ - message: key must not be empty
+ rule: self.all(key, key.size() != 0)
+ type: object
+ required:
+ - host
+ type: object
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ type: object
+ served: true
+ storage: false
+ subresources:
+ status: {}
+ - additionalPrinterColumns:
+ - description: The name of a service from the service registry
+ jsonPath: .spec.host
+ name: Host
+ type: string
+ - description: CreationTimestamp is a timestamp representing the server time when
+ this object was created. It is not guaranteed to be set in happens-before
+ order across separate operations. Clients may not set this value. It is represented
+ in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for
+ lists. For more information, see [Kubernetes API Conventions](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#metadata)
+ jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1beta1
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Configuration affecting load balancing, outlier detection,
+ etc. See more details at: https://istio.io/docs/reference/config/networking/destination-rule.html'
+ properties:
+ exportTo:
+ description: A list of namespaces to which this destination rule is
+ exported.
+ items:
+ type: string
+ type: array
+ host:
+ description: The name of a service from the service registry.
+ type: string
+ subsets:
+ description: One or more named sets that represent individual versions
+ of a service.
+ items:
+ properties:
+ labels:
+ additionalProperties:
+ type: string
+ description: Labels apply a filter over the endpoints of a service
+ in the service registry.
+ type: object
+ name:
+ description: Name of the subset.
+ type: string
+ trafficPolicy:
+ description: Traffic policies that apply to this subset.
+ properties:
+ connectionPool:
+ properties:
+ http:
+ description: HTTP connection pool settings.
+ properties:
+ h2UpgradePolicy:
+ description: |-
+ Specify if http1.1 connection should be upgraded to http2 for the associated destination.
+
+ Valid Options: DEFAULT, DO_NOT_UPGRADE, UPGRADE
+ enum:
+ - DEFAULT
+ - DO_NOT_UPGRADE
+ - UPGRADE
+ type: string
+ http1MaxPendingRequests:
+ description: Maximum number of requests that will
+ be queued while waiting for a ready connection
+ pool connection.
+ format: int32
+ type: integer
+ http2MaxRequests:
+ description: Maximum number of active requests to
+ a destination.
+ format: int32
+ type: integer
+ idleTimeout:
+ description: The idle timeout for upstream connection
+ pool connections.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConcurrentStreams:
+ description: The maximum number of concurrent streams
+ allowed for a peer on one HTTP/2 connection.
+ format: int32
+ type: integer
+ maxRequestsPerConnection:
+ description: Maximum number of requests per connection
+ to a backend.
+ format: int32
+ type: integer
+ maxRetries:
+ description: Maximum number of retries that can
+ be outstanding to all hosts in a cluster at a
+ given time.
+ format: int32
+ type: integer
+ useClientProtocol:
+ description: If set to true, client protocol will
+ be preserved while initiating connection to backend.
+ type: boolean
+ type: object
+ tcp:
+ description: Settings common to both HTTP and TCP upstream
+ connections.
+ properties:
+ connectTimeout:
+ description: TCP connection timeout.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ idleTimeout:
+ description: The idle timeout for TCP connections.
+ type: string
+ maxConnectionDuration:
+ description: The maximum duration of a connection.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConnections:
+ description: Maximum number of HTTP1 /TCP connections
+ to a destination host.
+ format: int32
+ type: integer
+ tcpKeepalive:
+ description: If set then set SO_KEEPALIVE on the
+ socket to enable TCP Keepalives.
+ properties:
+ interval:
+ description: The time duration between keep-alive
+ probes.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ probes:
+ description: Maximum number of keepalive probes
+ to send without response before deciding the
+ connection is dead.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ time:
+ description: The time duration a connection
+ needs to be idle before keep-alive probes
+ start being sent.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ type: object
+ type: object
+ loadBalancer:
+ description: Settings controlling the load balancer algorithms.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ properties:
+ consistentHash:
+ allOf:
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ properties:
+ httpCookie:
+ description: Hash based on HTTP cookie.
+ properties:
+ attributes:
+ description: Additional attributes for the cookie.
+ items:
+ properties:
+ name:
+ description: The name of the cookie attribute.
+ type: string
+ value:
+ description: The optional value of the
+ cookie attribute.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ name:
+ description: Name of the cookie.
+ type: string
+ path:
+ description: Path to set for the cookie.
+ type: string
+ ttl:
+ description: Lifetime of the cookie.
+ type: string
+ required:
+ - name
+ type: object
+ httpHeaderName:
+ description: Hash based on a specific HTTP header.
+ type: string
+ httpQueryParameterName:
+ description: Hash based on a specific HTTP query
+ parameter.
+ type: string
+ maglev:
+ description: The Maglev load balancer implements
+ consistent hashing to backend hosts.
+ properties:
+ tableSize:
+ description: The table size for Maglev hashing.
+ minimum: 0
+ type: integer
+ type: object
+ minimumRingSize:
+ description: Deprecated.
+ minimum: 0
+ type: integer
+ ringHash:
+ description: The ring/modulo hash load balancer
+ implements consistent hashing to backend hosts.
+ properties:
+ minimumRingSize:
+ description: The minimum number of virtual nodes
+ to use for the hash ring.
+ minimum: 0
+ type: integer
+ type: object
+ useSourceIp:
+ description: Hash based on the source IP address.
+ type: boolean
+ type: object
+ localityLbSetting:
+ properties:
+ distribute:
+ description: 'Optional: only one of distribute,
+ failover or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating locality, '/' separated,
+ e.g.
+ type: string
+ to:
+ additionalProperties:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ description: Map of upstream localities to
+ traffic distribution weights.
+ type: object
+ type: object
+ type: array
+ enabled:
+ description: Enable locality load balancing.
+ nullable: true
+ type: boolean
+ failover:
+ description: 'Optional: only one of distribute,
+ failover or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating region.
+ type: string
+ to:
+ description: Destination region the traffic
+ will fail over to when endpoints in the
+ 'from' region becomes unhealthy.
+ type: string
+ type: object
+ type: array
+ failoverPriority:
+ description: failoverPriority is an ordered list
+ of labels used to sort endpoints to do priority
+ based load balancing.
+ items:
+ type: string
+ type: array
+ type: object
+ simple:
+ description: |2-
+
+
+ Valid Options: LEAST_CONN, RANDOM, PASSTHROUGH, ROUND_ROBIN, LEAST_REQUEST
+ enum:
+ - UNSPECIFIED
+ - LEAST_CONN
+ - RANDOM
+ - PASSTHROUGH
+ - ROUND_ROBIN
+ - LEAST_REQUEST
+ type: string
+ warmup:
+ description: Represents the warmup configuration of
+ Service.
+ properties:
+ aggression:
+ description: This parameter controls the speed of
+ traffic increase over the warmup duration.
+ format: double
+ minimum: 0
+ nullable: true
+ type: number
+ duration:
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ minimumPercent:
+ format: double
+ maximum: 100
+ minimum: 0
+ nullable: true
+ type: number
+ required:
+ - duration
+ type: object
+ warmupDurationSecs:
+ description: 'Deprecated: use `warmup` instead.'
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ outlierDetection:
+ properties:
+ baseEjectionTime:
+ description: Minimum ejection duration.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ consecutive5xxErrors:
+ description: Number of 5xx errors before a host is ejected
+ from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveErrors:
+ format: int32
+ type: integer
+ consecutiveGatewayErrors:
+ description: Number of gateway errors before a host
+ is ejected from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveLocalOriginFailures:
+ description: The number of consecutive locally originated
+ failures before ejection occurs.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ interval:
+ description: Time interval between ejection sweep analysis.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxEjectionPercent:
+ description: Maximum % of hosts in the load balancing
+ pool for the upstream service that can be ejected.
+ format: int32
+ type: integer
+ minHealthPercent:
+ description: Outlier detection will be enabled as long
+ as the associated load balancing pool has at least
+ `minHealthPercent` hosts in healthy mode.
+ format: int32
+ type: integer
+ splitExternalLocalOriginErrors:
+ description: Determines whether to distinguish local
+ origin failures from external errors.
+ type: boolean
+ type: object
+ portLevelSettings:
+ description: Traffic policies specific to individual ports.
+ items:
+ properties:
+ connectionPool:
+ properties:
+ http:
+ description: HTTP connection pool settings.
+ properties:
+ h2UpgradePolicy:
+ description: |-
+ Specify if http1.1 connection should be upgraded to http2 for the associated destination.
+
+ Valid Options: DEFAULT, DO_NOT_UPGRADE, UPGRADE
+ enum:
+ - DEFAULT
+ - DO_NOT_UPGRADE
+ - UPGRADE
+ type: string
+ http1MaxPendingRequests:
+ description: Maximum number of requests that
+ will be queued while waiting for a ready
+ connection pool connection.
+ format: int32
+ type: integer
+ http2MaxRequests:
+ description: Maximum number of active requests
+ to a destination.
+ format: int32
+ type: integer
+ idleTimeout:
+ description: The idle timeout for upstream
+ connection pool connections.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConcurrentStreams:
+ description: The maximum number of concurrent
+ streams allowed for a peer on one HTTP/2
+ connection.
+ format: int32
+ type: integer
+ maxRequestsPerConnection:
+ description: Maximum number of requests per
+ connection to a backend.
+ format: int32
+ type: integer
+ maxRetries:
+ description: Maximum number of retries that
+ can be outstanding to all hosts in a cluster
+ at a given time.
+ format: int32
+ type: integer
+ useClientProtocol:
+ description: If set to true, client protocol
+ will be preserved while initiating connection
+ to backend.
+ type: boolean
+ type: object
+ tcp:
+ description: Settings common to both HTTP and
+ TCP upstream connections.
+ properties:
+ connectTimeout:
+ description: TCP connection timeout.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ idleTimeout:
+ description: The idle timeout for TCP connections.
+ type: string
+ maxConnectionDuration:
+ description: The maximum duration of a connection.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConnections:
+ description: Maximum number of HTTP1 /TCP
+ connections to a destination host.
+ format: int32
+ type: integer
+ tcpKeepalive:
+ description: If set then set SO_KEEPALIVE
+ on the socket to enable TCP Keepalives.
+ properties:
+ interval:
+ description: The time duration between
+ keep-alive probes.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ probes:
+ description: Maximum number of keepalive
+ probes to send without response before
+ deciding the connection is dead.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ time:
+ description: The time duration a connection
+ needs to be idle before keep-alive probes
+ start being sent.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ type: object
+ type: object
+ loadBalancer:
+ description: Settings controlling the load balancer
+ algorithms.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ properties:
+ consistentHash:
+ allOf:
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ properties:
+ httpCookie:
+ description: Hash based on HTTP cookie.
+ properties:
+ attributes:
+ description: Additional attributes for
+ the cookie.
+ items:
+ properties:
+ name:
+ description: The name of the cookie
+ attribute.
+ type: string
+ value:
+ description: The optional value
+ of the cookie attribute.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ name:
+ description: Name of the cookie.
+ type: string
+ path:
+ description: Path to set for the cookie.
+ type: string
+ ttl:
+ description: Lifetime of the cookie.
+ type: string
+ required:
+ - name
+ type: object
+ httpHeaderName:
+ description: Hash based on a specific HTTP
+ header.
+ type: string
+ httpQueryParameterName:
+ description: Hash based on a specific HTTP
+ query parameter.
+ type: string
+ maglev:
+ description: The Maglev load balancer implements
+ consistent hashing to backend hosts.
+ properties:
+ tableSize:
+ description: The table size for Maglev
+ hashing.
+ minimum: 0
+ type: integer
+ type: object
+ minimumRingSize:
+ description: Deprecated.
+ minimum: 0
+ type: integer
+ ringHash:
+ description: The ring/modulo hash load balancer
+ implements consistent hashing to backend
+ hosts.
+ properties:
+ minimumRingSize:
+ description: The minimum number of virtual
+ nodes to use for the hash ring.
+ minimum: 0
+ type: integer
+ type: object
+ useSourceIp:
+ description: Hash based on the source IP address.
+ type: boolean
+ type: object
+ localityLbSetting:
+ properties:
+ distribute:
+ description: 'Optional: only one of distribute,
+ failover or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating locality, '/'
+ separated, e.g.
+ type: string
+ to:
+ additionalProperties:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ description: Map of upstream localities
+ to traffic distribution weights.
+ type: object
+ type: object
+ type: array
+ enabled:
+ description: Enable locality load balancing.
+ nullable: true
+ type: boolean
+ failover:
+ description: 'Optional: only one of distribute,
+ failover or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating region.
+ type: string
+ to:
+ description: Destination region the
+ traffic will fail over to when endpoints
+ in the 'from' region becomes unhealthy.
+ type: string
+ type: object
+ type: array
+ failoverPriority:
+ description: failoverPriority is an ordered
+ list of labels used to sort endpoints to
+ do priority based load balancing.
+ items:
+ type: string
+ type: array
+ type: object
+ simple:
+ description: |2-
+
+
+ Valid Options: LEAST_CONN, RANDOM, PASSTHROUGH, ROUND_ROBIN, LEAST_REQUEST
+ enum:
+ - UNSPECIFIED
+ - LEAST_CONN
+ - RANDOM
+ - PASSTHROUGH
+ - ROUND_ROBIN
+ - LEAST_REQUEST
+ type: string
+ warmup:
+ description: Represents the warmup configuration
+ of Service.
+ properties:
+ aggression:
+ description: This parameter controls the speed
+ of traffic increase over the warmup duration.
+ format: double
+ minimum: 0
+ nullable: true
+ type: number
+ duration:
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ minimumPercent:
+ format: double
+ maximum: 100
+ minimum: 0
+ nullable: true
+ type: number
+ required:
+ - duration
+ type: object
+ warmupDurationSecs:
+ description: 'Deprecated: use `warmup` instead.'
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ outlierDetection:
+ properties:
+ baseEjectionTime:
+ description: Minimum ejection duration.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ consecutive5xxErrors:
+ description: Number of 5xx errors before a host
+ is ejected from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveErrors:
+ format: int32
+ type: integer
+ consecutiveGatewayErrors:
+ description: Number of gateway errors before a
+ host is ejected from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveLocalOriginFailures:
+ description: The number of consecutive locally
+ originated failures before ejection occurs.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ interval:
+ description: Time interval between ejection sweep
+ analysis.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ maxEjectionPercent:
+ description: Maximum % of hosts in the load balancing
+ pool for the upstream service that can be ejected.
+ format: int32
+ type: integer
+ minHealthPercent:
+ description: Outlier detection will be enabled
+ as long as the associated load balancing pool
+ has at least `minHealthPercent` hosts in healthy
+ mode.
+ format: int32
+ type: integer
+ splitExternalLocalOriginErrors:
+ description: Determines whether to distinguish
+ local origin failures from external errors.
+ type: boolean
+ type: object
+ port:
+ description: Specifies the number of a port on the
+ destination service on which this policy is being
+ applied.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ tls:
+ description: TLS related settings for connections
+ to the upstream service.
+ properties:
+ caCertificates:
+ description: 'OPTIONAL: The path to the file containing
+ certificate authority certificates to use in
+ verifying a presented server certificate.'
+ type: string
+ caCrl:
+ description: 'OPTIONAL: The path to the file containing
+ the certificate revocation list (CRL) to use
+ in verifying a presented server certificate.'
+ type: string
+ clientCertificate:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ credentialName:
+ description: The name of the secret that holds
+ the TLS certs for the client including the CA
+ certificates.
+ type: string
+ insecureSkipVerify:
+ description: '`insecureSkipVerify` specifies whether
+ the proxy should skip verifying the CA signature
+ and SAN for the server certificate corresponding
+ to the host.'
+ nullable: true
+ type: boolean
+ mode:
+ description: |-
+ Indicates whether connections to this port should be secured using TLS.
+
+ Valid Options: DISABLE, SIMPLE, MUTUAL, ISTIO_MUTUAL
+ enum:
+ - DISABLE
+ - SIMPLE
+ - MUTUAL
+ - ISTIO_MUTUAL
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ sni:
+ description: SNI string to present to the server
+ during TLS handshake.
+ type: string
+ subjectAltNames:
+ description: A list of alternate names to verify
+ the subject identity in the certificate.
+ items:
+ type: string
+ type: array
+ type: object
+ type: object
+ maxItems: 4096
+ type: array
+ proxyProtocol:
+ description: The upstream PROXY protocol settings.
+ properties:
+ version:
+ description: |-
+ The PROXY protocol version to use.
+
+ Valid Options: V1, V2
+ enum:
+ - V1
+ - V2
+ type: string
+ type: object
+ retryBudget:
+ description: Specifies a limit on concurrent retries in
+ relation to the number of active requests.
+ properties:
+ minRetryConcurrency:
+ description: Specifies the minimum retry concurrency
+ allowed for the retry budget.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ percent:
+ description: Specifies the limit on concurrent retries
+ as a percentage of the sum of active requests and
+ active pending requests.
+ format: double
+ maximum: 100
+ minimum: 0
+ nullable: true
+ type: number
+ type: object
+ tls:
+ description: TLS related settings for connections to the
+ upstream service.
+ properties:
+ caCertificates:
+ description: 'OPTIONAL: The path to the file containing
+ certificate authority certificates to use in verifying
+ a presented server certificate.'
+ type: string
+ caCrl:
+ description: 'OPTIONAL: The path to the file containing
+ the certificate revocation list (CRL) to use in verifying
+ a presented server certificate.'
+ type: string
+ clientCertificate:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ credentialName:
+ description: The name of the secret that holds the TLS
+ certs for the client including the CA certificates.
+ type: string
+ insecureSkipVerify:
+ description: '`insecureSkipVerify` specifies whether
+ the proxy should skip verifying the CA signature and
+ SAN for the server certificate corresponding to the
+ host.'
+ nullable: true
+ type: boolean
+ mode:
+ description: |-
+ Indicates whether connections to this port should be secured using TLS.
+
+ Valid Options: DISABLE, SIMPLE, MUTUAL, ISTIO_MUTUAL
+ enum:
+ - DISABLE
+ - SIMPLE
+ - MUTUAL
+ - ISTIO_MUTUAL
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ sni:
+ description: SNI string to present to the server during
+ TLS handshake.
+ type: string
+ subjectAltNames:
+ description: A list of alternate names to verify the
+ subject identity in the certificate.
+ items:
+ type: string
+ type: array
+ type: object
+ tunnel:
+ description: Configuration of tunneling TCP over other transport
+ or application layers for the host configured in the DestinationRule.
+ properties:
+ protocol:
+ description: Specifies which protocol to use for tunneling
+ the downstream connection.
+ type: string
+ targetHost:
+ description: Specifies a host to which the downstream
+ connection is tunneled.
+ type: string
+ targetPort:
+ description: Specifies a port to which the downstream
+ connection is tunneled.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ required:
+ - targetHost
+ - targetPort
+ type: object
+ type: object
+ required:
+ - name
+ type: object
+ type: array
+ trafficPolicy:
+ description: Traffic policies to apply (load balancing policy, connection
+ pool sizes, outlier detection).
+ properties:
+ connectionPool:
+ properties:
+ http:
+ description: HTTP connection pool settings.
+ properties:
+ h2UpgradePolicy:
+ description: |-
+ Specify if http1.1 connection should be upgraded to http2 for the associated destination.
+
+ Valid Options: DEFAULT, DO_NOT_UPGRADE, UPGRADE
+ enum:
+ - DEFAULT
+ - DO_NOT_UPGRADE
+ - UPGRADE
+ type: string
+ http1MaxPendingRequests:
+ description: Maximum number of requests that will be queued
+ while waiting for a ready connection pool connection.
+ format: int32
+ type: integer
+ http2MaxRequests:
+ description: Maximum number of active requests to a destination.
+ format: int32
+ type: integer
+ idleTimeout:
+ description: The idle timeout for upstream connection
+ pool connections.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConcurrentStreams:
+ description: The maximum number of concurrent streams
+ allowed for a peer on one HTTP/2 connection.
+ format: int32
+ type: integer
+ maxRequestsPerConnection:
+ description: Maximum number of requests per connection
+ to a backend.
+ format: int32
+ type: integer
+ maxRetries:
+ description: Maximum number of retries that can be outstanding
+ to all hosts in a cluster at a given time.
+ format: int32
+ type: integer
+ useClientProtocol:
+ description: If set to true, client protocol will be preserved
+ while initiating connection to backend.
+ type: boolean
+ type: object
+ tcp:
+ description: Settings common to both HTTP and TCP upstream
+ connections.
+ properties:
+ connectTimeout:
+ description: TCP connection timeout.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ idleTimeout:
+ description: The idle timeout for TCP connections.
+ type: string
+ maxConnectionDuration:
+ description: The maximum duration of a connection.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConnections:
+ description: Maximum number of HTTP1 /TCP connections
+ to a destination host.
+ format: int32
+ type: integer
+ tcpKeepalive:
+ description: If set then set SO_KEEPALIVE on the socket
+ to enable TCP Keepalives.
+ properties:
+ interval:
+ description: The time duration between keep-alive
+ probes.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ probes:
+ description: Maximum number of keepalive probes to
+ send without response before deciding the connection
+ is dead.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ time:
+ description: The time duration a connection needs
+ to be idle before keep-alive probes start being
+ sent.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ type: object
+ type: object
+ loadBalancer:
+ description: Settings controlling the load balancer algorithms.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ properties:
+ consistentHash:
+ allOf:
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ properties:
+ httpCookie:
+ description: Hash based on HTTP cookie.
+ properties:
+ attributes:
+ description: Additional attributes for the cookie.
+ items:
+ properties:
+ name:
+ description: The name of the cookie attribute.
+ type: string
+ value:
+ description: The optional value of the cookie
+ attribute.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ name:
+ description: Name of the cookie.
+ type: string
+ path:
+ description: Path to set for the cookie.
+ type: string
+ ttl:
+ description: Lifetime of the cookie.
+ type: string
+ required:
+ - name
+ type: object
+ httpHeaderName:
+ description: Hash based on a specific HTTP header.
+ type: string
+ httpQueryParameterName:
+ description: Hash based on a specific HTTP query parameter.
+ type: string
+ maglev:
+ description: The Maglev load balancer implements consistent
+ hashing to backend hosts.
+ properties:
+ tableSize:
+ description: The table size for Maglev hashing.
+ minimum: 0
+ type: integer
+ type: object
+ minimumRingSize:
+ description: Deprecated.
+ minimum: 0
+ type: integer
+ ringHash:
+ description: The ring/modulo hash load balancer implements
+ consistent hashing to backend hosts.
+ properties:
+ minimumRingSize:
+ description: The minimum number of virtual nodes to
+ use for the hash ring.
+ minimum: 0
+ type: integer
+ type: object
+ useSourceIp:
+ description: Hash based on the source IP address.
+ type: boolean
+ type: object
+ localityLbSetting:
+ properties:
+ distribute:
+ description: 'Optional: only one of distribute, failover
+ or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating locality, '/' separated,
+ e.g.
+ type: string
+ to:
+ additionalProperties:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ description: Map of upstream localities to traffic
+ distribution weights.
+ type: object
+ type: object
+ type: array
+ enabled:
+ description: Enable locality load balancing.
+ nullable: true
+ type: boolean
+ failover:
+ description: 'Optional: only one of distribute, failover
+ or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating region.
+ type: string
+ to:
+ description: Destination region the traffic will
+ fail over to when endpoints in the 'from' region
+ becomes unhealthy.
+ type: string
+ type: object
+ type: array
+ failoverPriority:
+ description: failoverPriority is an ordered list of labels
+ used to sort endpoints to do priority based load balancing.
+ items:
+ type: string
+ type: array
+ type: object
+ simple:
+ description: |2-
+
+
+ Valid Options: LEAST_CONN, RANDOM, PASSTHROUGH, ROUND_ROBIN, LEAST_REQUEST
+ enum:
+ - UNSPECIFIED
+ - LEAST_CONN
+ - RANDOM
+ - PASSTHROUGH
+ - ROUND_ROBIN
+ - LEAST_REQUEST
+ type: string
+ warmup:
+ description: Represents the warmup configuration of Service.
+ properties:
+ aggression:
+ description: This parameter controls the speed of traffic
+ increase over the warmup duration.
+ format: double
+ minimum: 0
+ nullable: true
+ type: number
+ duration:
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ minimumPercent:
+ format: double
+ maximum: 100
+ minimum: 0
+ nullable: true
+ type: number
+ required:
+ - duration
+ type: object
+ warmupDurationSecs:
+ description: 'Deprecated: use `warmup` instead.'
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ outlierDetection:
+ properties:
+ baseEjectionTime:
+ description: Minimum ejection duration.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ consecutive5xxErrors:
+ description: Number of 5xx errors before a host is ejected
+ from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveErrors:
+ format: int32
+ type: integer
+ consecutiveGatewayErrors:
+ description: Number of gateway errors before a host is ejected
+ from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveLocalOriginFailures:
+ description: The number of consecutive locally originated
+ failures before ejection occurs.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ interval:
+ description: Time interval between ejection sweep analysis.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxEjectionPercent:
+ description: Maximum % of hosts in the load balancing pool
+ for the upstream service that can be ejected.
+ format: int32
+ type: integer
+ minHealthPercent:
+ description: Outlier detection will be enabled as long as
+ the associated load balancing pool has at least `minHealthPercent`
+ hosts in healthy mode.
+ format: int32
+ type: integer
+ splitExternalLocalOriginErrors:
+ description: Determines whether to distinguish local origin
+ failures from external errors.
+ type: boolean
+ type: object
+ portLevelSettings:
+ description: Traffic policies specific to individual ports.
+ items:
+ properties:
+ connectionPool:
+ properties:
+ http:
+ description: HTTP connection pool settings.
+ properties:
+ h2UpgradePolicy:
+ description: |-
+ Specify if http1.1 connection should be upgraded to http2 for the associated destination.
+
+ Valid Options: DEFAULT, DO_NOT_UPGRADE, UPGRADE
+ enum:
+ - DEFAULT
+ - DO_NOT_UPGRADE
+ - UPGRADE
+ type: string
+ http1MaxPendingRequests:
+ description: Maximum number of requests that will
+ be queued while waiting for a ready connection
+ pool connection.
+ format: int32
+ type: integer
+ http2MaxRequests:
+ description: Maximum number of active requests to
+ a destination.
+ format: int32
+ type: integer
+ idleTimeout:
+ description: The idle timeout for upstream connection
+ pool connections.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConcurrentStreams:
+ description: The maximum number of concurrent streams
+ allowed for a peer on one HTTP/2 connection.
+ format: int32
+ type: integer
+ maxRequestsPerConnection:
+ description: Maximum number of requests per connection
+ to a backend.
+ format: int32
+ type: integer
+ maxRetries:
+ description: Maximum number of retries that can
+ be outstanding to all hosts in a cluster at a
+ given time.
+ format: int32
+ type: integer
+ useClientProtocol:
+ description: If set to true, client protocol will
+ be preserved while initiating connection to backend.
+ type: boolean
+ type: object
+ tcp:
+ description: Settings common to both HTTP and TCP upstream
+ connections.
+ properties:
+ connectTimeout:
+ description: TCP connection timeout.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ idleTimeout:
+ description: The idle timeout for TCP connections.
+ type: string
+ maxConnectionDuration:
+ description: The maximum duration of a connection.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConnections:
+ description: Maximum number of HTTP1 /TCP connections
+ to a destination host.
+ format: int32
+ type: integer
+ tcpKeepalive:
+ description: If set then set SO_KEEPALIVE on the
+ socket to enable TCP Keepalives.
+ properties:
+ interval:
+ description: The time duration between keep-alive
+ probes.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ probes:
+ description: Maximum number of keepalive probes
+ to send without response before deciding the
+ connection is dead.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ time:
+ description: The time duration a connection
+ needs to be idle before keep-alive probes
+ start being sent.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater
+ than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ type: object
+ type: object
+ loadBalancer:
+ description: Settings controlling the load balancer algorithms.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ - required:
+ - simple
+ - required:
+ - consistentHash
+ properties:
+ consistentHash:
+ allOf:
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - required:
+ - httpHeaderName
+ - required:
+ - httpCookie
+ - required:
+ - useSourceIp
+ - required:
+ - httpQueryParameterName
+ - oneOf:
+ - not:
+ anyOf:
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ - required:
+ - ringHash
+ - required:
+ - maglev
+ properties:
+ httpCookie:
+ description: Hash based on HTTP cookie.
+ properties:
+ attributes:
+ description: Additional attributes for the cookie.
+ items:
+ properties:
+ name:
+ description: The name of the cookie attribute.
+ type: string
+ value:
+ description: The optional value of the
+ cookie attribute.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ name:
+ description: Name of the cookie.
+ type: string
+ path:
+ description: Path to set for the cookie.
+ type: string
+ ttl:
+ description: Lifetime of the cookie.
+ type: string
+ required:
+ - name
+ type: object
+ httpHeaderName:
+ description: Hash based on a specific HTTP header.
+ type: string
+ httpQueryParameterName:
+ description: Hash based on a specific HTTP query
+ parameter.
+ type: string
+ maglev:
+ description: The Maglev load balancer implements
+ consistent hashing to backend hosts.
+ properties:
+ tableSize:
+ description: The table size for Maglev hashing.
+ minimum: 0
+ type: integer
+ type: object
+ minimumRingSize:
+ description: Deprecated.
+ minimum: 0
+ type: integer
+ ringHash:
+ description: The ring/modulo hash load balancer
+ implements consistent hashing to backend hosts.
+ properties:
+ minimumRingSize:
+ description: The minimum number of virtual nodes
+ to use for the hash ring.
+ minimum: 0
+ type: integer
+ type: object
+ useSourceIp:
+ description: Hash based on the source IP address.
+ type: boolean
+ type: object
+ localityLbSetting:
+ properties:
+ distribute:
+ description: 'Optional: only one of distribute,
+ failover or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating locality, '/' separated,
+ e.g.
+ type: string
+ to:
+ additionalProperties:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ description: Map of upstream localities to
+ traffic distribution weights.
+ type: object
+ type: object
+ type: array
+ enabled:
+ description: Enable locality load balancing.
+ nullable: true
+ type: boolean
+ failover:
+ description: 'Optional: only one of distribute,
+ failover or failoverPriority can be set.'
+ items:
+ properties:
+ from:
+ description: Originating region.
+ type: string
+ to:
+ description: Destination region the traffic
+ will fail over to when endpoints in the
+ 'from' region becomes unhealthy.
+ type: string
+ type: object
+ type: array
+ failoverPriority:
+ description: failoverPriority is an ordered list
+ of labels used to sort endpoints to do priority
+ based load balancing.
+ items:
+ type: string
+ type: array
+ type: object
+ simple:
+ description: |2-
+
+
+ Valid Options: LEAST_CONN, RANDOM, PASSTHROUGH, ROUND_ROBIN, LEAST_REQUEST
+ enum:
+ - UNSPECIFIED
+ - LEAST_CONN
+ - RANDOM
+ - PASSTHROUGH
+ - ROUND_ROBIN
+ - LEAST_REQUEST
+ type: string
+ warmup:
+ description: Represents the warmup configuration of
+ Service.
+ properties:
+ aggression:
+ description: This parameter controls the speed of
+ traffic increase over the warmup duration.
+ format: double
+ minimum: 0
+ nullable: true
+ type: number
+ duration:
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ minimumPercent:
+ format: double
+ maximum: 100
+ minimum: 0
+ nullable: true
+ type: number
+ required:
+ - duration
+ type: object
+ warmupDurationSecs:
+ description: 'Deprecated: use `warmup` instead.'
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ outlierDetection:
+ properties:
+ baseEjectionTime:
+ description: Minimum ejection duration.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ consecutive5xxErrors:
+ description: Number of 5xx errors before a host is ejected
+ from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveErrors:
+ format: int32
+ type: integer
+ consecutiveGatewayErrors:
+ description: Number of gateway errors before a host
+ is ejected from the connection pool.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ consecutiveLocalOriginFailures:
+ description: The number of consecutive locally originated
+ failures before ejection occurs.
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ interval:
+ description: Time interval between ejection sweep analysis.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxEjectionPercent:
+ description: Maximum % of hosts in the load balancing
+ pool for the upstream service that can be ejected.
+ format: int32
+ type: integer
+ minHealthPercent:
+ description: Outlier detection will be enabled as long
+ as the associated load balancing pool has at least
+ `minHealthPercent` hosts in healthy mode.
+ format: int32
+ type: integer
+ splitExternalLocalOriginErrors:
+ description: Determines whether to distinguish local
+ origin failures from external errors.
+ type: boolean
+ type: object
+ port:
+ description: Specifies the number of a port on the destination
+ service on which this policy is being applied.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ tls:
+ description: TLS related settings for connections to the
+ upstream service.
+ properties:
+ caCertificates:
+ description: 'OPTIONAL: The path to the file containing
+ certificate authority certificates to use in verifying
+ a presented server certificate.'
+ type: string
+ caCrl:
+ description: 'OPTIONAL: The path to the file containing
+ the certificate revocation list (CRL) to use in verifying
+ a presented server certificate.'
+ type: string
+ clientCertificate:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ credentialName:
+ description: The name of the secret that holds the TLS
+ certs for the client including the CA certificates.
+ type: string
+ insecureSkipVerify:
+ description: '`insecureSkipVerify` specifies whether
+ the proxy should skip verifying the CA signature and
+ SAN for the server certificate corresponding to the
+ host.'
+ nullable: true
+ type: boolean
+ mode:
+ description: |-
+ Indicates whether connections to this port should be secured using TLS.
+
+ Valid Options: DISABLE, SIMPLE, MUTUAL, ISTIO_MUTUAL
+ enum:
+ - DISABLE
+ - SIMPLE
+ - MUTUAL
+ - ISTIO_MUTUAL
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ sni:
+ description: SNI string to present to the server during
+ TLS handshake.
+ type: string
+ subjectAltNames:
+ description: A list of alternate names to verify the
+ subject identity in the certificate.
+ items:
+ type: string
+ type: array
+ type: object
+ type: object
+ maxItems: 4096
+ type: array
+ proxyProtocol:
+ description: The upstream PROXY protocol settings.
+ properties:
+ version:
+ description: |-
+ The PROXY protocol version to use.
+
+ Valid Options: V1, V2
+ enum:
+ - V1
+ - V2
+ type: string
+ type: object
+ retryBudget:
+ description: Specifies a limit on concurrent retries in relation
+ to the number of active requests.
+ properties:
+ minRetryConcurrency:
+ description: Specifies the minimum retry concurrency allowed
+ for the retry budget.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ percent:
+ description: Specifies the limit on concurrent retries as
+ a percentage of the sum of active requests and active pending
+ requests.
+ format: double
+ maximum: 100
+ minimum: 0
+ nullable: true
+ type: number
+ type: object
+ tls:
+ description: TLS related settings for connections to the upstream
+ service.
+ properties:
+ caCertificates:
+ description: 'OPTIONAL: The path to the file containing certificate
+ authority certificates to use in verifying a presented server
+ certificate.'
+ type: string
+ caCrl:
+ description: 'OPTIONAL: The path to the file containing the
+ certificate revocation list (CRL) to use in verifying a
+ presented server certificate.'
+ type: string
+ clientCertificate:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ credentialName:
+ description: The name of the secret that holds the TLS certs
+ for the client including the CA certificates.
+ type: string
+ insecureSkipVerify:
+ description: '`insecureSkipVerify` specifies whether the proxy
+ should skip verifying the CA signature and SAN for the server
+ certificate corresponding to the host.'
+ nullable: true
+ type: boolean
+ mode:
+ description: |-
+ Indicates whether connections to this port should be secured using TLS.
+
+ Valid Options: DISABLE, SIMPLE, MUTUAL, ISTIO_MUTUAL
+ enum:
+ - DISABLE
+ - SIMPLE
+ - MUTUAL
+ - ISTIO_MUTUAL
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `MUTUAL`.
+ type: string
+ sni:
+ description: SNI string to present to the server during TLS
+ handshake.
+ type: string
+ subjectAltNames:
+ description: A list of alternate names to verify the subject
+ identity in the certificate.
+ items:
+ type: string
+ type: array
+ type: object
+ tunnel:
+ description: Configuration of tunneling TCP over other transport
+ or application layers for the host configured in the DestinationRule.
+ properties:
+ protocol:
+ description: Specifies which protocol to use for tunneling
+ the downstream connection.
+ type: string
+ targetHost:
+ description: Specifies a host to which the downstream connection
+ is tunneled.
+ type: string
+ targetPort:
+ description: Specifies a port to which the downstream connection
+ is tunneled.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ required:
+ - targetHost
+ - targetPort
+ type: object
+ type: object
+ workloadSelector:
+ description: Criteria used to select the specific set of pods/VMs
+ on which this `DestinationRule` configuration should be applied.
+ properties:
+ matchLabels:
+ additionalProperties:
+ maxLength: 63
+ type: string
+ x-kubernetes-validations:
+ - message: wildcard not allowed in label value match
+ rule: '!self.contains("*")'
+ description: One or more labels that indicate a specific set of
+ pods/VMs on which a policy should be applied.
+ maxProperties: 4096
+ type: object
+ x-kubernetes-validations:
+ - message: wildcard not allowed in label key match
+ rule: self.all(key, !key.contains("*"))
+ - message: key must not be empty
+ rule: self.all(key, key.size() != 0)
+ type: object
+ required:
+ - host
+ type: object
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ type: object
+ served: true
+ storage: false
+ subresources:
+ status: {}
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_envoyfilters.yaml b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_envoyfilters.yaml
new file mode 100644
index 0000000000..6f0e329bbf
--- /dev/null
+++ b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_envoyfilters.yaml
@@ -0,0 +1,450 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ "helm.sh/resource-policy": keep
+ labels:
+ app: istio-pilot
+ chart: istio
+ heritage: Tiller
+ release: istio
+ name: envoyfilters.networking.istio.io
+spec:
+ group: networking.istio.io
+ names:
+ categories:
+ - istio-io
+ - networking-istio-io
+ kind: EnvoyFilter
+ listKind: EnvoyFilterList
+ plural: envoyfilters
+ singular: envoyfilter
+ scope: Namespaced
+ versions:
+ - name: v1alpha3
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Customizing Envoy configuration generated by Istio. See
+ more details at: https://istio.io/docs/reference/config/networking/envoy-filter.html'
+ properties:
+ configPatches:
+ description: One or more patches with match conditions.
+ items:
+ properties:
+ applyTo:
+ description: |-
+ Specifies where in the Envoy configuration, the patch should be applied.
+
+ Valid Options: LISTENER, FILTER_CHAIN, NETWORK_FILTER, HTTP_FILTER, ROUTE_CONFIGURATION, VIRTUAL_HOST, HTTP_ROUTE, CLUSTER, EXTENSION_CONFIG, BOOTSTRAP, LISTENER_FILTER
+ enum:
+ - INVALID
+ - LISTENER
+ - FILTER_CHAIN
+ - NETWORK_FILTER
+ - HTTP_FILTER
+ - ROUTE_CONFIGURATION
+ - VIRTUAL_HOST
+ - HTTP_ROUTE
+ - CLUSTER
+ - EXTENSION_CONFIG
+ - BOOTSTRAP
+ - LISTENER_FILTER
+ type: string
+ match:
+ description: Match on listener/route configuration/cluster.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - listener
+ - required:
+ - routeConfiguration
+ - required:
+ - cluster
+ - required:
+ - waypoint
+ - required:
+ - listener
+ - required:
+ - routeConfiguration
+ - required:
+ - cluster
+ - required:
+ - waypoint
+ properties:
+ cluster:
+ description: Match on envoy cluster attributes.
+ properties:
+ name:
+ description: The exact name of the cluster to match.
+ type: string
+ portNumber:
+ description: The service port for which this cluster
+ was generated.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ service:
+ description: The fully qualified service name for this
+ cluster.
+ type: string
+ subset:
+ description: The subset associated with the service.
+ type: string
+ type: object
+ context:
+ description: |-
+ The specific config generation context to match on.
+
+ Valid Options: ANY, SIDECAR_INBOUND, SIDECAR_OUTBOUND, GATEWAY, WAYPOINT
+ enum:
+ - ANY
+ - SIDECAR_INBOUND
+ - SIDECAR_OUTBOUND
+ - GATEWAY
+ - WAYPOINT
+ type: string
+ listener:
+ description: Match on envoy listener attributes.
+ properties:
+ filterChain:
+ description: Match a specific filter chain in a listener.
+ properties:
+ applicationProtocols:
+ description: Applies only to sidecars.
+ type: string
+ destinationPort:
+ description: The destination_port value used by
+ a filter chain's match condition.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ filter:
+ description: The name of a specific filter to apply
+ the patch to.
+ properties:
+ name:
+ description: The filter name to match on.
+ type: string
+ subFilter:
+ description: The next level filter within this
+ filter to match upon.
+ properties:
+ name:
+ description: The filter name to match on.
+ type: string
+ type: object
+ type: object
+ name:
+ description: The name assigned to the filter chain.
+ type: string
+ sni:
+ description: The SNI value used by a filter chain's
+ match condition.
+ type: string
+ transportProtocol:
+ description: Applies only to `SIDECAR_INBOUND` context.
+ type: string
+ type: object
+ listenerFilter:
+ description: Match a specific listener filter.
+ type: string
+ name:
+ description: Match a specific listener by its name.
+ type: string
+ portName:
+ type: string
+ portNumber:
+ description: The service port/gateway port to which
+ traffic is being sent/received.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ proxy:
+ description: Match on properties associated with a proxy.
+ properties:
+ metadata:
+ additionalProperties:
+ type: string
+ description: Match on the node metadata supplied by
+ a proxy when connecting to istiod.
+ type: object
+ proxyVersion:
+ description: A regular expression in golang regex format
+ (RE2) that can be used to select proxies using a specific
+ version of istio proxy.
+ type: string
+ type: object
+ routeConfiguration:
+ description: Match on envoy HTTP route configuration attributes.
+ properties:
+ gateway:
+ description: The Istio gateway config's namespace/name
+ for which this route configuration was generated.
+ type: string
+ name:
+ description: Route configuration name to match on.
+ type: string
+ portName:
+ description: Applicable only for GATEWAY context.
+ type: string
+ portNumber:
+ description: The service port number or gateway server
+ port number for which this route configuration was
+ generated.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ vhost:
+ description: Match a specific virtual host in a route
+ configuration and apply the patch to the virtual host.
+ properties:
+ domainName:
+ description: Match a domain name in a virtual host.
+ type: string
+ name:
+ description: The VirtualHosts objects generated
+ by Istio are named as host:port, where the host
+ typically corresponds to the VirtualService's
+ host field or the hostname of a service in the
+ registry.
+ type: string
+ route:
+ description: Match a specific route within the virtual
+ host.
+ properties:
+ action:
+ description: |-
+ Match a route with specific action type.
+
+ Valid Options: ANY, ROUTE, REDIRECT, DIRECT_RESPONSE
+ enum:
+ - ANY
+ - ROUTE
+ - REDIRECT
+ - DIRECT_RESPONSE
+ type: string
+ name:
+ description: The Route objects generated by
+ default are named as default.
+ type: string
+ type: object
+ type: object
+ type: object
+ waypoint:
+ properties:
+ filter:
+ description: The name of a specific filter to apply
+ the patch to.
+ properties:
+ name:
+ description: The filter name to match on.
+ type: string
+ subFilter:
+ description: The next level filter within this filter
+ to match on.
+ properties:
+ name:
+ description: The filter name to match on.
+ type: string
+ type: object
+ type: object
+ portNumber:
+ description: The service port to match on.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 6553
+ route:
+ description: Match a specific route.
+ properties:
+ name:
+ description: The Route objects generated by default
+ are named as default.
+ type: string
+ type: object
+ type: object
+ type: object
+ x-kubernetes-validations:
+ - message: only support waypointMatch when context is WAYPOINT
+ rule: 'has(self.context) ? ((self.context == "WAYPOINT") ?
+ has(self.waypoint) : !has(self.waypoint)) : !has(self.waypoint)'
+ patch:
+ description: The patch to apply along with the operation.
+ properties:
+ filterClass:
+ description: |-
+ Determines the filter insertion order.
+
+ Valid Options: AUTHN, AUTHZ, STATS
+ enum:
+ - UNSPECIFIED
+ - AUTHN
+ - AUTHZ
+ - STATS
+ type: string
+ operation:
+ description: |-
+ Determines how the patch should be applied.
+
+ Valid Options: MERGE, ADD, REMOVE, INSERT_BEFORE, INSERT_AFTER, INSERT_FIRST, REPLACE
+ enum:
+ - INVALID
+ - MERGE
+ - ADD
+ - REMOVE
+ - INSERT_BEFORE
+ - INSERT_AFTER
+ - INSERT_FIRST
+ - REPLACE
+ type: string
+ value:
+ description: The JSON config of the object being patched.
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ type: object
+ type: object
+ type: array
+ priority:
+ description: Priority defines the order in which patch sets are applied
+ within a context.
+ format: int32
+ type: integer
+ targetRefs:
+ description: Optional.
+ items:
+ properties:
+ group:
+ description: group is the group of the target resource.
+ maxLength: 253
+ pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+ type: string
+ kind:
+ description: kind is kind of the target resource.
+ maxLength: 63
+ minLength: 1
+ pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$
+ type: string
+ name:
+ description: name is the name of the target resource.
+ maxLength: 253
+ minLength: 1
+ type: string
+ namespace:
+ description: namespace is the namespace of the referent.
+ type: string
+ x-kubernetes-validations:
+ - message: cross namespace referencing is not currently supported
+ rule: self.size() == 0
+ required:
+ - kind
+ - name
+ type: object
+ maxItems: 16
+ type: array
+ workloadSelector:
+ description: Criteria used to select the specific set of pods/VMs
+ on which this patch configuration should be applied.
+ properties:
+ labels:
+ additionalProperties:
+ maxLength: 63
+ type: string
+ x-kubernetes-validations:
+ - message: wildcard is not supported in selector
+ rule: '!self.contains("*")'
+ description: One or more labels that indicate a specific set of
+ pods/VMs on which the configuration should be applied.
+ maxProperties: 256
+ type: object
+ type: object
+ type: object
+ x-kubernetes-validations:
+ - message: only one of targetRefs or workloadSelector can be set
+ rule: '(has(self.workloadSelector) ? 1 : 0) + (has(self.targetRefs)
+ ? 1 : 0) <= 1'
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_gateways.yaml b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_gateways.yaml
new file mode 100644
index 0000000000..5e064d2a9d
--- /dev/null
+++ b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_gateways.yaml
@@ -0,0 +1,850 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ "helm.sh/resource-policy": keep
+ labels:
+ app: istio-pilot
+ chart: istio
+ heritage: Tiller
+ release: istio
+ name: gateways.networking.istio.io
+spec:
+ group: networking.istio.io
+ names:
+ categories:
+ - istio-io
+ - networking-istio-io
+ kind: Gateway
+ listKind: GatewayList
+ plural: gateways
+ shortNames:
+ - gw
+ singular: gateway
+ scope: Namespaced
+ versions:
+ - name: v1
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Configuration affecting edge load balancer. See more details
+ at: https://istio.io/docs/reference/config/networking/gateway.html'
+ properties:
+ selector:
+ additionalProperties:
+ type: string
+ description: One or more labels that indicate a specific set of pods/VMs
+ on which this gateway configuration should be applied.
+ type: object
+ servers:
+ description: A list of server specifications.
+ items:
+ properties:
+ bind:
+ description: The ip or the Unix domain socket to which the listener
+ should be bound to.
+ type: string
+ defaultEndpoint:
+ type: string
+ hosts:
+ description: One or more hosts exposed by this gateway.
+ items:
+ type: string
+ type: array
+ name:
+ description: An optional name of the server, when set must be
+ unique across all servers.
+ type: string
+ port:
+ description: The Port on which the proxy should listen for incoming
+ connections.
+ properties:
+ name:
+ description: Label assigned to the port.
+ type: string
+ number:
+ description: A valid non-negative integer port number.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ protocol:
+ description: The protocol exposed on the port.
+ type: string
+ targetPort:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ required:
+ - number
+ - protocol
+ - name
+ type: object
+ tls:
+ description: Set of TLS related options that govern the server's
+ behavior.
+ properties:
+ caCertCredentialName:
+ description: For mutual TLS, the name of the secret or the
+ configmap that holds CA certificates.
+ type: string
+ caCertificates:
+ description: REQUIRED if mode is `MUTUAL` or `OPTIONAL_MUTUAL`.
+ type: string
+ caCrl:
+ description: 'OPTIONAL: The path to the file containing
+ the certificate revocation list (CRL) to use in verifying
+ a presented client side certificate.'
+ type: string
+ cipherSuites:
+ description: 'Optional: If specified, only support the specified
+ cipher list.'
+ items:
+ type: string
+ type: array
+ credentialName:
+ description: For gateways running on Kubernetes, the name
+ of the secret that holds the TLS certs including the CA
+ certificates.
+ type: string
+ credentialNames:
+ description: Same as CredentialName but for multiple certificates.
+ items:
+ type: string
+ maxItems: 2
+ minItems: 1
+ type: array
+ httpsRedirect:
+ description: If set to true, the load balancer will send
+ a 301 redirect for all http connections, asking the clients
+ to use HTTPS.
+ type: boolean
+ maxProtocolVersion:
+ description: |-
+ Optional: Maximum TLS protocol version.
+
+ Valid Options: TLS_AUTO, TLSV1_0, TLSV1_1, TLSV1_2, TLSV1_3
+ enum:
+ - TLS_AUTO
+ - TLSV1_0
+ - TLSV1_1
+ - TLSV1_2
+ - TLSV1_3
+ type: string
+ minProtocolVersion:
+ description: |-
+ Optional: Minimum TLS protocol version.
+
+ Valid Options: TLS_AUTO, TLSV1_0, TLSV1_1, TLSV1_2, TLSV1_3
+ enum:
+ - TLS_AUTO
+ - TLSV1_0
+ - TLSV1_1
+ - TLSV1_2
+ - TLSV1_3
+ type: string
+ mode:
+ description: |-
+ Optional: Indicates whether connections to this port should be secured using TLS.
+
+ Valid Options: PASSTHROUGH, SIMPLE, MUTUAL, AUTO_PASSTHROUGH, ISTIO_MUTUAL, OPTIONAL_MUTUAL
+ enum:
+ - PASSTHROUGH
+ - SIMPLE
+ - MUTUAL
+ - AUTO_PASSTHROUGH
+ - ISTIO_MUTUAL
+ - OPTIONAL_MUTUAL
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ serverCertificate:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ subjectAltNames:
+ description: A list of alternate names to verify the subject
+ identity in the certificate presented by the client.
+ items:
+ type: string
+ type: array
+ tlsCertificates:
+ description: Only one of `server_certificate`, `private_key`
+ or `credential_name` or `credential_names` or `tls_certificates`
+ should be specified.
+ items:
+ properties:
+ caCertificates:
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ serverCertificate:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ type: object
+ maxItems: 2
+ minItems: 1
+ type: array
+ verifyCertificateHash:
+ description: An optional list of hex-encoded SHA-256 hashes
+ of the authorized client certificates.
+ items:
+ type: string
+ type: array
+ verifyCertificateSpki:
+ description: An optional list of base64-encoded SHA-256
+ hashes of the SPKIs of authorized client certificates.
+ items:
+ type: string
+ type: array
+ type: object
+ x-kubernetes-validations:
+ - message: only one of credentialNames or tlsCertificates can
+ be set
+ rule: '(has(self.tlsCertificates) ? 1 : 0) + (has(self.credentialNames)
+ ? 1 : 0) <= 1'
+ - message: only one of credentialName or credentialNames can
+ be set
+ rule: '(has(self.credentialName) ? 1 : 0) + (has(self.credentialNames)
+ ? 1 : 0) <= 1'
+ - message: only one of credentialName or tlsCertificates can
+ be set
+ rule: '(has(self.credentialNames) ? 1 : 0) + (has(self.tlsCertificates)
+ ? 1 : 0) <= 1'
+ required:
+ - port
+ - hosts
+ type: object
+ type: array
+ type: object
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
+ - name: v1alpha3
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Configuration affecting edge load balancer. See more details
+ at: https://istio.io/docs/reference/config/networking/gateway.html'
+ properties:
+ selector:
+ additionalProperties:
+ type: string
+ description: One or more labels that indicate a specific set of pods/VMs
+ on which this gateway configuration should be applied.
+ type: object
+ servers:
+ description: A list of server specifications.
+ items:
+ properties:
+ bind:
+ description: The ip or the Unix domain socket to which the listener
+ should be bound to.
+ type: string
+ defaultEndpoint:
+ type: string
+ hosts:
+ description: One or more hosts exposed by this gateway.
+ items:
+ type: string
+ type: array
+ name:
+ description: An optional name of the server, when set must be
+ unique across all servers.
+ type: string
+ port:
+ description: The Port on which the proxy should listen for incoming
+ connections.
+ properties:
+ name:
+ description: Label assigned to the port.
+ type: string
+ number:
+ description: A valid non-negative integer port number.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ protocol:
+ description: The protocol exposed on the port.
+ type: string
+ targetPort:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ required:
+ - number
+ - protocol
+ - name
+ type: object
+ tls:
+ description: Set of TLS related options that govern the server's
+ behavior.
+ properties:
+ caCertCredentialName:
+ description: For mutual TLS, the name of the secret or the
+ configmap that holds CA certificates.
+ type: string
+ caCertificates:
+ description: REQUIRED if mode is `MUTUAL` or `OPTIONAL_MUTUAL`.
+ type: string
+ caCrl:
+ description: 'OPTIONAL: The path to the file containing
+ the certificate revocation list (CRL) to use in verifying
+ a presented client side certificate.'
+ type: string
+ cipherSuites:
+ description: 'Optional: If specified, only support the specified
+ cipher list.'
+ items:
+ type: string
+ type: array
+ credentialName:
+ description: For gateways running on Kubernetes, the name
+ of the secret that holds the TLS certs including the CA
+ certificates.
+ type: string
+ credentialNames:
+ description: Same as CredentialName but for multiple certificates.
+ items:
+ type: string
+ maxItems: 2
+ minItems: 1
+ type: array
+ httpsRedirect:
+ description: If set to true, the load balancer will send
+ a 301 redirect for all http connections, asking the clients
+ to use HTTPS.
+ type: boolean
+ maxProtocolVersion:
+ description: |-
+ Optional: Maximum TLS protocol version.
+
+ Valid Options: TLS_AUTO, TLSV1_0, TLSV1_1, TLSV1_2, TLSV1_3
+ enum:
+ - TLS_AUTO
+ - TLSV1_0
+ - TLSV1_1
+ - TLSV1_2
+ - TLSV1_3
+ type: string
+ minProtocolVersion:
+ description: |-
+ Optional: Minimum TLS protocol version.
+
+ Valid Options: TLS_AUTO, TLSV1_0, TLSV1_1, TLSV1_2, TLSV1_3
+ enum:
+ - TLS_AUTO
+ - TLSV1_0
+ - TLSV1_1
+ - TLSV1_2
+ - TLSV1_3
+ type: string
+ mode:
+ description: |-
+ Optional: Indicates whether connections to this port should be secured using TLS.
+
+ Valid Options: PASSTHROUGH, SIMPLE, MUTUAL, AUTO_PASSTHROUGH, ISTIO_MUTUAL, OPTIONAL_MUTUAL
+ enum:
+ - PASSTHROUGH
+ - SIMPLE
+ - MUTUAL
+ - AUTO_PASSTHROUGH
+ - ISTIO_MUTUAL
+ - OPTIONAL_MUTUAL
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ serverCertificate:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ subjectAltNames:
+ description: A list of alternate names to verify the subject
+ identity in the certificate presented by the client.
+ items:
+ type: string
+ type: array
+ tlsCertificates:
+ description: Only one of `server_certificate`, `private_key`
+ or `credential_name` or `credential_names` or `tls_certificates`
+ should be specified.
+ items:
+ properties:
+ caCertificates:
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ serverCertificate:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ type: object
+ maxItems: 2
+ minItems: 1
+ type: array
+ verifyCertificateHash:
+ description: An optional list of hex-encoded SHA-256 hashes
+ of the authorized client certificates.
+ items:
+ type: string
+ type: array
+ verifyCertificateSpki:
+ description: An optional list of base64-encoded SHA-256
+ hashes of the SPKIs of authorized client certificates.
+ items:
+ type: string
+ type: array
+ type: object
+ x-kubernetes-validations:
+ - message: only one of credentialNames or tlsCertificates can
+ be set
+ rule: '(has(self.tlsCertificates) ? 1 : 0) + (has(self.credentialNames)
+ ? 1 : 0) <= 1'
+ - message: only one of credentialName or credentialNames can
+ be set
+ rule: '(has(self.credentialName) ? 1 : 0) + (has(self.credentialNames)
+ ? 1 : 0) <= 1'
+ - message: only one of credentialName or tlsCertificates can
+ be set
+ rule: '(has(self.credentialNames) ? 1 : 0) + (has(self.tlsCertificates)
+ ? 1 : 0) <= 1'
+ required:
+ - port
+ - hosts
+ type: object
+ type: array
+ type: object
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ type: object
+ served: true
+ storage: false
+ subresources:
+ status: {}
+ - name: v1beta1
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Configuration affecting edge load balancer. See more details
+ at: https://istio.io/docs/reference/config/networking/gateway.html'
+ properties:
+ selector:
+ additionalProperties:
+ type: string
+ description: One or more labels that indicate a specific set of pods/VMs
+ on which this gateway configuration should be applied.
+ type: object
+ servers:
+ description: A list of server specifications.
+ items:
+ properties:
+ bind:
+ description: The ip or the Unix domain socket to which the listener
+ should be bound to.
+ type: string
+ defaultEndpoint:
+ type: string
+ hosts:
+ description: One or more hosts exposed by this gateway.
+ items:
+ type: string
+ type: array
+ name:
+ description: An optional name of the server, when set must be
+ unique across all servers.
+ type: string
+ port:
+ description: The Port on which the proxy should listen for incoming
+ connections.
+ properties:
+ name:
+ description: Label assigned to the port.
+ type: string
+ number:
+ description: A valid non-negative integer port number.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ protocol:
+ description: The protocol exposed on the port.
+ type: string
+ targetPort:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ required:
+ - number
+ - protocol
+ - name
+ type: object
+ tls:
+ description: Set of TLS related options that govern the server's
+ behavior.
+ properties:
+ caCertCredentialName:
+ description: For mutual TLS, the name of the secret or the
+ configmap that holds CA certificates.
+ type: string
+ caCertificates:
+ description: REQUIRED if mode is `MUTUAL` or `OPTIONAL_MUTUAL`.
+ type: string
+ caCrl:
+ description: 'OPTIONAL: The path to the file containing
+ the certificate revocation list (CRL) to use in verifying
+ a presented client side certificate.'
+ type: string
+ cipherSuites:
+ description: 'Optional: If specified, only support the specified
+ cipher list.'
+ items:
+ type: string
+ type: array
+ credentialName:
+ description: For gateways running on Kubernetes, the name
+ of the secret that holds the TLS certs including the CA
+ certificates.
+ type: string
+ credentialNames:
+ description: Same as CredentialName but for multiple certificates.
+ items:
+ type: string
+ maxItems: 2
+ minItems: 1
+ type: array
+ httpsRedirect:
+ description: If set to true, the load balancer will send
+ a 301 redirect for all http connections, asking the clients
+ to use HTTPS.
+ type: boolean
+ maxProtocolVersion:
+ description: |-
+ Optional: Maximum TLS protocol version.
+
+ Valid Options: TLS_AUTO, TLSV1_0, TLSV1_1, TLSV1_2, TLSV1_3
+ enum:
+ - TLS_AUTO
+ - TLSV1_0
+ - TLSV1_1
+ - TLSV1_2
+ - TLSV1_3
+ type: string
+ minProtocolVersion:
+ description: |-
+ Optional: Minimum TLS protocol version.
+
+ Valid Options: TLS_AUTO, TLSV1_0, TLSV1_1, TLSV1_2, TLSV1_3
+ enum:
+ - TLS_AUTO
+ - TLSV1_0
+ - TLSV1_1
+ - TLSV1_2
+ - TLSV1_3
+ type: string
+ mode:
+ description: |-
+ Optional: Indicates whether connections to this port should be secured using TLS.
+
+ Valid Options: PASSTHROUGH, SIMPLE, MUTUAL, AUTO_PASSTHROUGH, ISTIO_MUTUAL, OPTIONAL_MUTUAL
+ enum:
+ - PASSTHROUGH
+ - SIMPLE
+ - MUTUAL
+ - AUTO_PASSTHROUGH
+ - ISTIO_MUTUAL
+ - OPTIONAL_MUTUAL
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ serverCertificate:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ subjectAltNames:
+ description: A list of alternate names to verify the subject
+ identity in the certificate presented by the client.
+ items:
+ type: string
+ type: array
+ tlsCertificates:
+ description: Only one of `server_certificate`, `private_key`
+ or `credential_name` or `credential_names` or `tls_certificates`
+ should be specified.
+ items:
+ properties:
+ caCertificates:
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ serverCertificate:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ type: object
+ maxItems: 2
+ minItems: 1
+ type: array
+ verifyCertificateHash:
+ description: An optional list of hex-encoded SHA-256 hashes
+ of the authorized client certificates.
+ items:
+ type: string
+ type: array
+ verifyCertificateSpki:
+ description: An optional list of base64-encoded SHA-256
+ hashes of the SPKIs of authorized client certificates.
+ items:
+ type: string
+ type: array
+ type: object
+ x-kubernetes-validations:
+ - message: only one of credentialNames or tlsCertificates can
+ be set
+ rule: '(has(self.tlsCertificates) ? 1 : 0) + (has(self.credentialNames)
+ ? 1 : 0) <= 1'
+ - message: only one of credentialName or credentialNames can
+ be set
+ rule: '(has(self.credentialName) ? 1 : 0) + (has(self.credentialNames)
+ ? 1 : 0) <= 1'
+ - message: only one of credentialName or tlsCertificates can
+ be set
+ rule: '(has(self.credentialNames) ? 1 : 0) + (has(self.tlsCertificates)
+ ? 1 : 0) <= 1'
+ required:
+ - port
+ - hosts
+ type: object
+ type: array
+ type: object
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ type: object
+ served: true
+ storage: false
+ subresources:
+ status: {}
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_proxyconfigs.yaml b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_proxyconfigs.yaml
new file mode 100644
index 0000000000..ff7c7d9ccd
--- /dev/null
+++ b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_proxyconfigs.yaml
@@ -0,0 +1,151 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ "helm.sh/resource-policy": keep
+ labels:
+ app: istio-pilot
+ chart: istio
+ heritage: Tiller
+ release: istio
+ name: proxyconfigs.networking.istio.io
+spec:
+ group: networking.istio.io
+ names:
+ categories:
+ - istio-io
+ - networking-istio-io
+ kind: ProxyConfig
+ listKind: ProxyConfigList
+ plural: proxyconfigs
+ singular: proxyconfig
+ scope: Namespaced
+ versions:
+ - name: v1beta1
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Provides configuration for individual workloads. See more
+ details at: https://istio.io/docs/reference/config/networking/proxy-config.html'
+ properties:
+ concurrency:
+ description: The number of worker threads to run.
+ format: int32
+ minimum: 0
+ nullable: true
+ type: integer
+ environmentVariables:
+ additionalProperties:
+ maxLength: 2048
+ type: string
+ description: Additional environment variables for the proxy.
+ type: object
+ image:
+ description: Specifies the details of the proxy image.
+ properties:
+ imageType:
+ description: The image type of the image.
+ type: string
+ type: object
+ selector:
+ description: Optional.
+ properties:
+ matchLabels:
+ additionalProperties:
+ maxLength: 63
+ type: string
+ x-kubernetes-validations:
+ - message: wildcard not allowed in label value match
+ rule: '!self.contains("*")'
+ description: One or more labels that indicate a specific set of
+ pods/VMs on which a policy should be applied.
+ maxProperties: 4096
+ type: object
+ x-kubernetes-validations:
+ - message: wildcard not allowed in label key match
+ rule: self.all(key, !key.contains("*"))
+ - message: key must not be empty
+ rule: self.all(key, key.size() != 0)
+ type: object
+ type: object
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_serviceentries.yaml b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_serviceentries.yaml
new file mode 100644
index 0000000000..fa28464a9b
--- /dev/null
+++ b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_serviceentries.yaml
@@ -0,0 +1,922 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ "helm.sh/resource-policy": keep
+ labels:
+ app: istio-pilot
+ chart: istio
+ heritage: Tiller
+ release: istio
+ name: serviceentries.networking.istio.io
+spec:
+ group: networking.istio.io
+ names:
+ categories:
+ - istio-io
+ - networking-istio-io
+ kind: ServiceEntry
+ listKind: ServiceEntryList
+ plural: serviceentries
+ shortNames:
+ - se
+ singular: serviceentry
+ scope: Namespaced
+ versions:
+ - additionalPrinterColumns:
+ - description: The hosts associated with the ServiceEntry
+ jsonPath: .spec.hosts
+ name: Hosts
+ type: string
+ - description: Whether the service is external to the mesh or part of the mesh
+ (MESH_EXTERNAL or MESH_INTERNAL)
+ jsonPath: .spec.location
+ name: Location
+ type: string
+ - description: Service resolution mode for the hosts (NONE, STATIC, or DNS)
+ jsonPath: .spec.resolution
+ name: Resolution
+ type: string
+ - description: 'CreationTimestamp is a timestamp representing the server time
+ when this object was created. It is not guaranteed to be set in happens-before
+ order across separate operations. Clients may not set this value. It is represented
+ in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for
+ lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata'
+ jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Configuration affecting service registry. See more details
+ at: https://istio.io/docs/reference/config/networking/service-entry.html'
+ properties:
+ addresses:
+ description: The virtual IP addresses associated with the service.
+ items:
+ maxLength: 64
+ type: string
+ maxItems: 256
+ type: array
+ endpoints:
+ description: One or more endpoints associated with the service.
+ items:
+ properties:
+ address:
+ description: Address associated with the network endpoint without
+ the port.
+ maxLength: 256
+ type: string
+ x-kubernetes-validations:
+ - message: UDS must be an absolute path or abstract socket
+ rule: 'self.startsWith("unix://") ? (self.substring(7, 8)
+ == "/" || self.substring(7, 8) == "@") : true'
+ - message: UDS may not be a dir
+ rule: 'self.startsWith("unix://") ? !self.endsWith("/") :
+ true'
+ labels:
+ additionalProperties:
+ type: string
+ description: One or more labels associated with the endpoint.
+ maxProperties: 256
+ type: object
+ locality:
+ description: The locality associated with the endpoint.
+ maxLength: 2048
+ type: string
+ network:
+ description: Network enables Istio to group endpoints resident
+ in the same L3 domain/network.
+ maxLength: 2048
+ type: string
+ ports:
+ additionalProperties:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ description: Set of ports associated with the endpoint.
+ maxProperties: 128
+ type: object
+ x-kubernetes-validations:
+ - message: port name must be valid
+ rule: self.all(key, size(key) < 63 && key.matches("^[a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?$"))
+ serviceAccount:
+ description: The service account associated with the workload
+ if a sidecar is present in the workload.
+ maxLength: 253
+ type: string
+ weight:
+ description: The load balancing weight associated with the endpoint.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ x-kubernetes-validations:
+ - message: Address is required
+ rule: has(self.address) || has(self.network)
+ - message: UDS may not include ports
+ rule: '(has(self.address) ? self.address : "").startsWith("unix://")
+ ? !has(self.ports) : true'
+ maxItems: 4096
+ type: array
+ exportTo:
+ description: A list of namespaces to which this service is exported.
+ items:
+ type: string
+ type: array
+ hosts:
+ description: The hosts associated with the ServiceEntry.
+ items:
+ type: string
+ x-kubernetes-validations:
+ - message: hostname cannot be wildcard
+ rule: self != "*"
+ maxItems: 256
+ minItems: 1
+ type: array
+ location:
+ description: |-
+ Specify whether the service should be considered external to the mesh or part of the mesh.
+
+ Valid Options: MESH_EXTERNAL, MESH_INTERNAL
+ enum:
+ - MESH_EXTERNAL
+ - MESH_INTERNAL
+ type: string
+ ports:
+ description: The ports associated with the external service.
+ items:
+ properties:
+ name:
+ description: Label assigned to the port.
+ maxLength: 256
+ type: string
+ number:
+ description: A valid non-negative integer port number.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ protocol:
+ description: The protocol exposed on the port.
+ maxLength: 256
+ type: string
+ targetPort:
+ description: The port number on the endpoint where the traffic
+ will be received.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ required:
+ - number
+ - name
+ type: object
+ maxItems: 256
+ type: array
+ x-kubernetes-list-map-keys:
+ - name
+ x-kubernetes-list-type: map
+ x-kubernetes-validations:
+ - message: port number cannot be duplicated
+ rule: self.all(l1, self.exists_one(l2, l1.number == l2.number))
+ resolution:
+ description: |-
+ Service resolution mode for the hosts.
+
+ Valid Options: NONE, STATIC, DNS, DNS_ROUND_ROBIN, DYNAMIC_DNS
+ enum:
+ - NONE
+ - STATIC
+ - DNS
+ - DNS_ROUND_ROBIN
+ - DYNAMIC_DNS
+ type: string
+ subjectAltNames:
+ description: If specified, the proxy will verify that the server certificate's
+ subject alternate name matches one of the specified values.
+ items:
+ type: string
+ type: array
+ workloadSelector:
+ description: Applicable only for MESH_INTERNAL services.
+ properties:
+ labels:
+ additionalProperties:
+ maxLength: 63
+ type: string
+ x-kubernetes-validations:
+ - message: wildcard is not supported in selector
+ rule: '!self.contains("*")'
+ description: One or more labels that indicate a specific set of
+ pods/VMs on which the configuration should be applied.
+ maxProperties: 256
+ type: object
+ type: object
+ required:
+ - hosts
+ type: object
+ x-kubernetes-validations:
+ - message: only one of WorkloadSelector or Endpoints can be set
+ rule: '(has(self.workloadSelector) ? 1 : 0) + (has(self.endpoints) ?
+ 1 : 0) <= 1'
+ - message: CIDR addresses are allowed only for NONE/STATIC resolution
+ types
+ rule: '!((has(self.addresses) ? self.addresses : []).exists(k, k.contains("/"))
+ && !((has(self.resolution) ? self.resolution : "NONE") in ["STATIC",
+ "NONE"]))'
+ - message: NONE mode cannot set endpoints
+ rule: '((has(self.resolution) ? self.resolution : "NONE") == "NONE")
+ ? !has(self.endpoints) : true'
+ - message: DNS_ROUND_ROBIN mode cannot have multiple endpoints
+ rule: '((has(self.resolution) ? self.resolution : "") == "DNS_ROUND_ROBIN")
+ ? ((has(self.endpoints) ? self.endpoints : []).size() <= 1) : true'
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - spec
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
+ - additionalPrinterColumns:
+ - description: The hosts associated with the ServiceEntry
+ jsonPath: .spec.hosts
+ name: Hosts
+ type: string
+ - description: Whether the service is external to the mesh or part of the mesh
+ (MESH_EXTERNAL or MESH_INTERNAL)
+ jsonPath: .spec.location
+ name: Location
+ type: string
+ - description: Service resolution mode for the hosts (NONE, STATIC, or DNS)
+ jsonPath: .spec.resolution
+ name: Resolution
+ type: string
+ - description: 'CreationTimestamp is a timestamp representing the server time
+ when this object was created. It is not guaranteed to be set in happens-before
+ order across separate operations. Clients may not set this value. It is represented
+ in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for
+ lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata'
+ jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1alpha3
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Configuration affecting service registry. See more details
+ at: https://istio.io/docs/reference/config/networking/service-entry.html'
+ properties:
+ addresses:
+ description: The virtual IP addresses associated with the service.
+ items:
+ maxLength: 64
+ type: string
+ maxItems: 256
+ type: array
+ endpoints:
+ description: One or more endpoints associated with the service.
+ items:
+ properties:
+ address:
+ description: Address associated with the network endpoint without
+ the port.
+ maxLength: 256
+ type: string
+ x-kubernetes-validations:
+ - message: UDS must be an absolute path or abstract socket
+ rule: 'self.startsWith("unix://") ? (self.substring(7, 8)
+ == "/" || self.substring(7, 8) == "@") : true'
+ - message: UDS may not be a dir
+ rule: 'self.startsWith("unix://") ? !self.endsWith("/") :
+ true'
+ labels:
+ additionalProperties:
+ type: string
+ description: One or more labels associated with the endpoint.
+ maxProperties: 256
+ type: object
+ locality:
+ description: The locality associated with the endpoint.
+ maxLength: 2048
+ type: string
+ network:
+ description: Network enables Istio to group endpoints resident
+ in the same L3 domain/network.
+ maxLength: 2048
+ type: string
+ ports:
+ additionalProperties:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ description: Set of ports associated with the endpoint.
+ maxProperties: 128
+ type: object
+ x-kubernetes-validations:
+ - message: port name must be valid
+ rule: self.all(key, size(key) < 63 && key.matches("^[a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?$"))
+ serviceAccount:
+ description: The service account associated with the workload
+ if a sidecar is present in the workload.
+ maxLength: 253
+ type: string
+ weight:
+ description: The load balancing weight associated with the endpoint.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ x-kubernetes-validations:
+ - message: Address is required
+ rule: has(self.address) || has(self.network)
+ - message: UDS may not include ports
+ rule: '(has(self.address) ? self.address : "").startsWith("unix://")
+ ? !has(self.ports) : true'
+ maxItems: 4096
+ type: array
+ exportTo:
+ description: A list of namespaces to which this service is exported.
+ items:
+ type: string
+ type: array
+ hosts:
+ description: The hosts associated with the ServiceEntry.
+ items:
+ type: string
+ x-kubernetes-validations:
+ - message: hostname cannot be wildcard
+ rule: self != "*"
+ maxItems: 256
+ minItems: 1
+ type: array
+ location:
+ description: |-
+ Specify whether the service should be considered external to the mesh or part of the mesh.
+
+ Valid Options: MESH_EXTERNAL, MESH_INTERNAL
+ enum:
+ - MESH_EXTERNAL
+ - MESH_INTERNAL
+ type: string
+ ports:
+ description: The ports associated with the external service.
+ items:
+ properties:
+ name:
+ description: Label assigned to the port.
+ maxLength: 256
+ type: string
+ number:
+ description: A valid non-negative integer port number.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ protocol:
+ description: The protocol exposed on the port.
+ maxLength: 256
+ type: string
+ targetPort:
+ description: The port number on the endpoint where the traffic
+ will be received.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ required:
+ - number
+ - name
+ type: object
+ maxItems: 256
+ type: array
+ x-kubernetes-list-map-keys:
+ - name
+ x-kubernetes-list-type: map
+ x-kubernetes-validations:
+ - message: port number cannot be duplicated
+ rule: self.all(l1, self.exists_one(l2, l1.number == l2.number))
+ resolution:
+ description: |-
+ Service resolution mode for the hosts.
+
+ Valid Options: NONE, STATIC, DNS, DNS_ROUND_ROBIN, DYNAMIC_DNS
+ enum:
+ - NONE
+ - STATIC
+ - DNS
+ - DNS_ROUND_ROBIN
+ - DYNAMIC_DNS
+ type: string
+ subjectAltNames:
+ description: If specified, the proxy will verify that the server certificate's
+ subject alternate name matches one of the specified values.
+ items:
+ type: string
+ type: array
+ workloadSelector:
+ description: Applicable only for MESH_INTERNAL services.
+ properties:
+ labels:
+ additionalProperties:
+ maxLength: 63
+ type: string
+ x-kubernetes-validations:
+ - message: wildcard is not supported in selector
+ rule: '!self.contains("*")'
+ description: One or more labels that indicate a specific set of
+ pods/VMs on which the configuration should be applied.
+ maxProperties: 256
+ type: object
+ type: object
+ required:
+ - hosts
+ type: object
+ x-kubernetes-validations:
+ - message: only one of WorkloadSelector or Endpoints can be set
+ rule: '(has(self.workloadSelector) ? 1 : 0) + (has(self.endpoints) ?
+ 1 : 0) <= 1'
+ - message: CIDR addresses are allowed only for NONE/STATIC resolution
+ types
+ rule: '!((has(self.addresses) ? self.addresses : []).exists(k, k.contains("/"))
+ && !((has(self.resolution) ? self.resolution : "NONE") in ["STATIC",
+ "NONE"]))'
+ - message: NONE mode cannot set endpoints
+ rule: '((has(self.resolution) ? self.resolution : "NONE") == "NONE")
+ ? !has(self.endpoints) : true'
+ - message: DNS_ROUND_ROBIN mode cannot have multiple endpoints
+ rule: '((has(self.resolution) ? self.resolution : "") == "DNS_ROUND_ROBIN")
+ ? ((has(self.endpoints) ? self.endpoints : []).size() <= 1) : true'
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - spec
+ type: object
+ served: true
+ storage: false
+ subresources:
+ status: {}
+ - additionalPrinterColumns:
+ - description: The hosts associated with the ServiceEntry
+ jsonPath: .spec.hosts
+ name: Hosts
+ type: string
+ - description: Whether the service is external to the mesh or part of the mesh
+ (MESH_EXTERNAL or MESH_INTERNAL)
+ jsonPath: .spec.location
+ name: Location
+ type: string
+ - description: Service resolution mode for the hosts (NONE, STATIC, or DNS)
+ jsonPath: .spec.resolution
+ name: Resolution
+ type: string
+ - description: 'CreationTimestamp is a timestamp representing the server time
+ when this object was created. It is not guaranteed to be set in happens-before
+ order across separate operations. Clients may not set this value. It is represented
+ in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for
+ lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata'
+ jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1beta1
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Configuration affecting service registry. See more details
+ at: https://istio.io/docs/reference/config/networking/service-entry.html'
+ properties:
+ addresses:
+ description: The virtual IP addresses associated with the service.
+ items:
+ maxLength: 64
+ type: string
+ maxItems: 256
+ type: array
+ endpoints:
+ description: One or more endpoints associated with the service.
+ items:
+ properties:
+ address:
+ description: Address associated with the network endpoint without
+ the port.
+ maxLength: 256
+ type: string
+ x-kubernetes-validations:
+ - message: UDS must be an absolute path or abstract socket
+ rule: 'self.startsWith("unix://") ? (self.substring(7, 8)
+ == "/" || self.substring(7, 8) == "@") : true'
+ - message: UDS may not be a dir
+ rule: 'self.startsWith("unix://") ? !self.endsWith("/") :
+ true'
+ labels:
+ additionalProperties:
+ type: string
+ description: One or more labels associated with the endpoint.
+ maxProperties: 256
+ type: object
+ locality:
+ description: The locality associated with the endpoint.
+ maxLength: 2048
+ type: string
+ network:
+ description: Network enables Istio to group endpoints resident
+ in the same L3 domain/network.
+ maxLength: 2048
+ type: string
+ ports:
+ additionalProperties:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ description: Set of ports associated with the endpoint.
+ maxProperties: 128
+ type: object
+ x-kubernetes-validations:
+ - message: port name must be valid
+ rule: self.all(key, size(key) < 63 && key.matches("^[a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?$"))
+ serviceAccount:
+ description: The service account associated with the workload
+ if a sidecar is present in the workload.
+ maxLength: 253
+ type: string
+ weight:
+ description: The load balancing weight associated with the endpoint.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ x-kubernetes-validations:
+ - message: Address is required
+ rule: has(self.address) || has(self.network)
+ - message: UDS may not include ports
+ rule: '(has(self.address) ? self.address : "").startsWith("unix://")
+ ? !has(self.ports) : true'
+ maxItems: 4096
+ type: array
+ exportTo:
+ description: A list of namespaces to which this service is exported.
+ items:
+ type: string
+ type: array
+ hosts:
+ description: The hosts associated with the ServiceEntry.
+ items:
+ type: string
+ x-kubernetes-validations:
+ - message: hostname cannot be wildcard
+ rule: self != "*"
+ maxItems: 256
+ minItems: 1
+ type: array
+ location:
+ description: |-
+ Specify whether the service should be considered external to the mesh or part of the mesh.
+
+ Valid Options: MESH_EXTERNAL, MESH_INTERNAL
+ enum:
+ - MESH_EXTERNAL
+ - MESH_INTERNAL
+ type: string
+ ports:
+ description: The ports associated with the external service.
+ items:
+ properties:
+ name:
+ description: Label assigned to the port.
+ maxLength: 256
+ type: string
+ number:
+ description: A valid non-negative integer port number.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ protocol:
+ description: The protocol exposed on the port.
+ maxLength: 256
+ type: string
+ targetPort:
+ description: The port number on the endpoint where the traffic
+ will be received.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ required:
+ - number
+ - name
+ type: object
+ maxItems: 256
+ type: array
+ x-kubernetes-list-map-keys:
+ - name
+ x-kubernetes-list-type: map
+ x-kubernetes-validations:
+ - message: port number cannot be duplicated
+ rule: self.all(l1, self.exists_one(l2, l1.number == l2.number))
+ resolution:
+ description: |-
+ Service resolution mode for the hosts.
+
+ Valid Options: NONE, STATIC, DNS, DNS_ROUND_ROBIN, DYNAMIC_DNS
+ enum:
+ - NONE
+ - STATIC
+ - DNS
+ - DNS_ROUND_ROBIN
+ - DYNAMIC_DNS
+ type: string
+ subjectAltNames:
+ description: If specified, the proxy will verify that the server certificate's
+ subject alternate name matches one of the specified values.
+ items:
+ type: string
+ type: array
+ workloadSelector:
+ description: Applicable only for MESH_INTERNAL services.
+ properties:
+ labels:
+ additionalProperties:
+ maxLength: 63
+ type: string
+ x-kubernetes-validations:
+ - message: wildcard is not supported in selector
+ rule: '!self.contains("*")'
+ description: One or more labels that indicate a specific set of
+ pods/VMs on which the configuration should be applied.
+ maxProperties: 256
+ type: object
+ type: object
+ required:
+ - hosts
+ type: object
+ x-kubernetes-validations:
+ - message: only one of WorkloadSelector or Endpoints can be set
+ rule: '(has(self.workloadSelector) ? 1 : 0) + (has(self.endpoints) ?
+ 1 : 0) <= 1'
+ - message: CIDR addresses are allowed only for NONE/STATIC resolution
+ types
+ rule: '!((has(self.addresses) ? self.addresses : []).exists(k, k.contains("/"))
+ && !((has(self.resolution) ? self.resolution : "NONE") in ["STATIC",
+ "NONE"]))'
+ - message: NONE mode cannot set endpoints
+ rule: '((has(self.resolution) ? self.resolution : "NONE") == "NONE")
+ ? !has(self.endpoints) : true'
+ - message: DNS_ROUND_ROBIN mode cannot have multiple endpoints
+ rule: '((has(self.resolution) ? self.resolution : "") == "DNS_ROUND_ROBIN")
+ ? ((has(self.endpoints) ? self.endpoints : []).size() <= 1) : true'
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - spec
+ type: object
+ served: true
+ storage: false
+ subresources:
+ status: {}
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_sidecars.yaml b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_sidecars.yaml
new file mode 100644
index 0000000000..e531c557c4
--- /dev/null
+++ b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_sidecars.yaml
@@ -0,0 +1,1757 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ "helm.sh/resource-policy": keep
+ labels:
+ app: istio-pilot
+ chart: istio
+ heritage: Tiller
+ release: istio
+ name: sidecars.networking.istio.io
+spec:
+ group: networking.istio.io
+ names:
+ categories:
+ - istio-io
+ - networking-istio-io
+ kind: Sidecar
+ listKind: SidecarList
+ plural: sidecars
+ singular: sidecar
+ scope: Namespaced
+ versions:
+ - name: v1
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Configuration affecting network reachability of a sidecar.
+ See more details at: https://istio.io/docs/reference/config/networking/sidecar.html'
+ properties:
+ egress:
+ description: Egress specifies the configuration of the sidecar for
+ processing outbound traffic from the attached workload instance
+ to other services in the mesh.
+ items:
+ properties:
+ bind:
+ description: The IP(IPv4 or IPv6) or the Unix domain socket
+ to which the listener should be bound to.
+ type: string
+ captureMode:
+ description: |-
+ When the bind address is an IP, the captureMode option dictates how traffic to the listener is expected to be captured (or not).
+
+ Valid Options: DEFAULT, IPTABLES, NONE
+ enum:
+ - DEFAULT
+ - IPTABLES
+ - NONE
+ type: string
+ hosts:
+ description: One or more service hosts exposed by the listener
+ in `namespace/dnsName` format.
+ items:
+ type: string
+ type: array
+ port:
+ description: The port associated with the listener.
+ properties:
+ name:
+ description: Label assigned to the port.
+ type: string
+ number:
+ description: A valid non-negative integer port number.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ protocol:
+ description: The protocol exposed on the port.
+ type: string
+ targetPort:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ required:
+ - hosts
+ type: object
+ type: array
+ inboundConnectionPool:
+ description: Settings controlling the volume of connections Envoy
+ will accept from the network.
+ properties:
+ http:
+ description: HTTP connection pool settings.
+ properties:
+ h2UpgradePolicy:
+ description: |-
+ Specify if http1.1 connection should be upgraded to http2 for the associated destination.
+
+ Valid Options: DEFAULT, DO_NOT_UPGRADE, UPGRADE
+ enum:
+ - DEFAULT
+ - DO_NOT_UPGRADE
+ - UPGRADE
+ type: string
+ http1MaxPendingRequests:
+ description: Maximum number of requests that will be queued
+ while waiting for a ready connection pool connection.
+ format: int32
+ type: integer
+ http2MaxRequests:
+ description: Maximum number of active requests to a destination.
+ format: int32
+ type: integer
+ idleTimeout:
+ description: The idle timeout for upstream connection pool
+ connections.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConcurrentStreams:
+ description: The maximum number of concurrent streams allowed
+ for a peer on one HTTP/2 connection.
+ format: int32
+ type: integer
+ maxRequestsPerConnection:
+ description: Maximum number of requests per connection to
+ a backend.
+ format: int32
+ type: integer
+ maxRetries:
+ description: Maximum number of retries that can be outstanding
+ to all hosts in a cluster at a given time.
+ format: int32
+ type: integer
+ useClientProtocol:
+ description: If set to true, client protocol will be preserved
+ while initiating connection to backend.
+ type: boolean
+ type: object
+ tcp:
+ description: Settings common to both HTTP and TCP upstream connections.
+ properties:
+ connectTimeout:
+ description: TCP connection timeout.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ idleTimeout:
+ description: The idle timeout for TCP connections.
+ type: string
+ maxConnectionDuration:
+ description: The maximum duration of a connection.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConnections:
+ description: Maximum number of HTTP1 /TCP connections to a
+ destination host.
+ format: int32
+ type: integer
+ tcpKeepalive:
+ description: If set then set SO_KEEPALIVE on the socket to
+ enable TCP Keepalives.
+ properties:
+ interval:
+ description: The time duration between keep-alive probes.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ probes:
+ description: Maximum number of keepalive probes to send
+ without response before deciding the connection is dead.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ time:
+ description: The time duration a connection needs to be
+ idle before keep-alive probes start being sent.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ type: object
+ type: object
+ ingress:
+ description: Ingress specifies the configuration of the sidecar for
+ processing inbound traffic to the attached workload instance.
+ items:
+ properties:
+ bind:
+ description: The IP(IPv4 or IPv6) to which the listener should
+ be bound.
+ type: string
+ captureMode:
+ description: |-
+ The captureMode option dictates how traffic to the listener is expected to be captured (or not).
+
+ Valid Options: DEFAULT, IPTABLES, NONE
+ enum:
+ - DEFAULT
+ - IPTABLES
+ - NONE
+ type: string
+ connectionPool:
+ description: Settings controlling the volume of connections
+ Envoy will accept from the network.
+ properties:
+ http:
+ description: HTTP connection pool settings.
+ properties:
+ h2UpgradePolicy:
+ description: |-
+ Specify if http1.1 connection should be upgraded to http2 for the associated destination.
+
+ Valid Options: DEFAULT, DO_NOT_UPGRADE, UPGRADE
+ enum:
+ - DEFAULT
+ - DO_NOT_UPGRADE
+ - UPGRADE
+ type: string
+ http1MaxPendingRequests:
+ description: Maximum number of requests that will be
+ queued while waiting for a ready connection pool connection.
+ format: int32
+ type: integer
+ http2MaxRequests:
+ description: Maximum number of active requests to a
+ destination.
+ format: int32
+ type: integer
+ idleTimeout:
+ description: The idle timeout for upstream connection
+ pool connections.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConcurrentStreams:
+ description: The maximum number of concurrent streams
+ allowed for a peer on one HTTP/2 connection.
+ format: int32
+ type: integer
+ maxRequestsPerConnection:
+ description: Maximum number of requests per connection
+ to a backend.
+ format: int32
+ type: integer
+ maxRetries:
+ description: Maximum number of retries that can be outstanding
+ to all hosts in a cluster at a given time.
+ format: int32
+ type: integer
+ useClientProtocol:
+ description: If set to true, client protocol will be
+ preserved while initiating connection to backend.
+ type: boolean
+ type: object
+ tcp:
+ description: Settings common to both HTTP and TCP upstream
+ connections.
+ properties:
+ connectTimeout:
+ description: TCP connection timeout.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ idleTimeout:
+ description: The idle timeout for TCP connections.
+ type: string
+ maxConnectionDuration:
+ description: The maximum duration of a connection.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConnections:
+ description: Maximum number of HTTP1 /TCP connections
+ to a destination host.
+ format: int32
+ type: integer
+ tcpKeepalive:
+ description: If set then set SO_KEEPALIVE on the socket
+ to enable TCP Keepalives.
+ properties:
+ interval:
+ description: The time duration between keep-alive
+ probes.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ probes:
+ description: Maximum number of keepalive probes
+ to send without response before deciding the connection
+ is dead.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ time:
+ description: The time duration a connection needs
+ to be idle before keep-alive probes start being
+ sent.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ type: object
+ type: object
+ defaultEndpoint:
+ description: The IP endpoint or Unix domain socket to which
+ traffic should be forwarded to.
+ type: string
+ port:
+ description: The port associated with the listener.
+ properties:
+ name:
+ description: Label assigned to the port.
+ type: string
+ number:
+ description: A valid non-negative integer port number.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ protocol:
+ description: The protocol exposed on the port.
+ type: string
+ targetPort:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ tls:
+ description: Set of TLS related options that will enable TLS
+ termination on the sidecar for requests originating from outside
+ the mesh.
+ properties:
+ caCertCredentialName:
+ description: For mutual TLS, the name of the secret or the
+ configmap that holds CA certificates.
+ type: string
+ caCertificates:
+ description: REQUIRED if mode is `MUTUAL` or `OPTIONAL_MUTUAL`.
+ type: string
+ caCrl:
+ description: 'OPTIONAL: The path to the file containing
+ the certificate revocation list (CRL) to use in verifying
+ a presented client side certificate.'
+ type: string
+ cipherSuites:
+ description: 'Optional: If specified, only support the specified
+ cipher list.'
+ items:
+ type: string
+ type: array
+ credentialName:
+ description: For gateways running on Kubernetes, the name
+ of the secret that holds the TLS certs including the CA
+ certificates.
+ type: string
+ credentialNames:
+ description: Same as CredentialName but for multiple certificates.
+ items:
+ type: string
+ maxItems: 2
+ minItems: 1
+ type: array
+ httpsRedirect:
+ description: If set to true, the load balancer will send
+ a 301 redirect for all http connections, asking the clients
+ to use HTTPS.
+ type: boolean
+ maxProtocolVersion:
+ description: |-
+ Optional: Maximum TLS protocol version.
+
+ Valid Options: TLS_AUTO, TLSV1_0, TLSV1_1, TLSV1_2, TLSV1_3
+ enum:
+ - TLS_AUTO
+ - TLSV1_0
+ - TLSV1_1
+ - TLSV1_2
+ - TLSV1_3
+ type: string
+ minProtocolVersion:
+ description: |-
+ Optional: Minimum TLS protocol version.
+
+ Valid Options: TLS_AUTO, TLSV1_0, TLSV1_1, TLSV1_2, TLSV1_3
+ enum:
+ - TLS_AUTO
+ - TLSV1_0
+ - TLSV1_1
+ - TLSV1_2
+ - TLSV1_3
+ type: string
+ mode:
+ description: |-
+ Optional: Indicates whether connections to this port should be secured using TLS.
+
+ Valid Options: PASSTHROUGH, SIMPLE, MUTUAL, AUTO_PASSTHROUGH, ISTIO_MUTUAL, OPTIONAL_MUTUAL
+ enum:
+ - PASSTHROUGH
+ - SIMPLE
+ - MUTUAL
+ - AUTO_PASSTHROUGH
+ - ISTIO_MUTUAL
+ - OPTIONAL_MUTUAL
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ serverCertificate:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ subjectAltNames:
+ description: A list of alternate names to verify the subject
+ identity in the certificate presented by the client.
+ items:
+ type: string
+ type: array
+ tlsCertificates:
+ description: Only one of `server_certificate`, `private_key`
+ or `credential_name` or `credential_names` or `tls_certificates`
+ should be specified.
+ items:
+ properties:
+ caCertificates:
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ serverCertificate:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ type: object
+ maxItems: 2
+ minItems: 1
+ type: array
+ verifyCertificateHash:
+ description: An optional list of hex-encoded SHA-256 hashes
+ of the authorized client certificates.
+ items:
+ type: string
+ type: array
+ verifyCertificateSpki:
+ description: An optional list of base64-encoded SHA-256
+ hashes of the SPKIs of authorized client certificates.
+ items:
+ type: string
+ type: array
+ type: object
+ x-kubernetes-validations:
+ - message: only one of credentialNames or tlsCertificates can
+ be set
+ rule: '(has(self.tlsCertificates) ? 1 : 0) + (has(self.credentialNames)
+ ? 1 : 0) <= 1'
+ - message: only one of credentialName or credentialNames can
+ be set
+ rule: '(has(self.credentialName) ? 1 : 0) + (has(self.credentialNames)
+ ? 1 : 0) <= 1'
+ - message: only one of credentialName or tlsCertificates can
+ be set
+ rule: '(has(self.credentialNames) ? 1 : 0) + (has(self.tlsCertificates)
+ ? 1 : 0) <= 1'
+ required:
+ - port
+ type: object
+ type: array
+ outboundTrafficPolicy:
+ description: Set the default behavior of the sidecar for handling
+ outbound traffic from the application.
+ properties:
+ egressProxy:
+ properties:
+ host:
+ description: The name of a service from the service registry.
+ type: string
+ port:
+ description: Specifies the port on the host that is being
+ addressed.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ subset:
+ description: The name of a subset within the service.
+ type: string
+ required:
+ - host
+ type: object
+ mode:
+ description: |2-
+
+
+ Valid Options: REGISTRY_ONLY, ALLOW_ANY
+ enum:
+ - REGISTRY_ONLY
+ - ALLOW_ANY
+ type: string
+ type: object
+ workloadSelector:
+ description: Criteria used to select the specific set of pods/VMs
+ on which this `Sidecar` configuration should be applied.
+ properties:
+ labels:
+ additionalProperties:
+ maxLength: 63
+ type: string
+ x-kubernetes-validations:
+ - message: wildcard is not supported in selector
+ rule: '!self.contains("*")'
+ description: One or more labels that indicate a specific set of
+ pods/VMs on which the configuration should be applied.
+ maxProperties: 256
+ type: object
+ type: object
+ type: object
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
+ - name: v1alpha3
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Configuration affecting network reachability of a sidecar.
+ See more details at: https://istio.io/docs/reference/config/networking/sidecar.html'
+ properties:
+ egress:
+ description: Egress specifies the configuration of the sidecar for
+ processing outbound traffic from the attached workload instance
+ to other services in the mesh.
+ items:
+ properties:
+ bind:
+ description: The IP(IPv4 or IPv6) or the Unix domain socket
+ to which the listener should be bound to.
+ type: string
+ captureMode:
+ description: |-
+ When the bind address is an IP, the captureMode option dictates how traffic to the listener is expected to be captured (or not).
+
+ Valid Options: DEFAULT, IPTABLES, NONE
+ enum:
+ - DEFAULT
+ - IPTABLES
+ - NONE
+ type: string
+ hosts:
+ description: One or more service hosts exposed by the listener
+ in `namespace/dnsName` format.
+ items:
+ type: string
+ type: array
+ port:
+ description: The port associated with the listener.
+ properties:
+ name:
+ description: Label assigned to the port.
+ type: string
+ number:
+ description: A valid non-negative integer port number.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ protocol:
+ description: The protocol exposed on the port.
+ type: string
+ targetPort:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ required:
+ - hosts
+ type: object
+ type: array
+ inboundConnectionPool:
+ description: Settings controlling the volume of connections Envoy
+ will accept from the network.
+ properties:
+ http:
+ description: HTTP connection pool settings.
+ properties:
+ h2UpgradePolicy:
+ description: |-
+ Specify if http1.1 connection should be upgraded to http2 for the associated destination.
+
+ Valid Options: DEFAULT, DO_NOT_UPGRADE, UPGRADE
+ enum:
+ - DEFAULT
+ - DO_NOT_UPGRADE
+ - UPGRADE
+ type: string
+ http1MaxPendingRequests:
+ description: Maximum number of requests that will be queued
+ while waiting for a ready connection pool connection.
+ format: int32
+ type: integer
+ http2MaxRequests:
+ description: Maximum number of active requests to a destination.
+ format: int32
+ type: integer
+ idleTimeout:
+ description: The idle timeout for upstream connection pool
+ connections.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConcurrentStreams:
+ description: The maximum number of concurrent streams allowed
+ for a peer on one HTTP/2 connection.
+ format: int32
+ type: integer
+ maxRequestsPerConnection:
+ description: Maximum number of requests per connection to
+ a backend.
+ format: int32
+ type: integer
+ maxRetries:
+ description: Maximum number of retries that can be outstanding
+ to all hosts in a cluster at a given time.
+ format: int32
+ type: integer
+ useClientProtocol:
+ description: If set to true, client protocol will be preserved
+ while initiating connection to backend.
+ type: boolean
+ type: object
+ tcp:
+ description: Settings common to both HTTP and TCP upstream connections.
+ properties:
+ connectTimeout:
+ description: TCP connection timeout.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ idleTimeout:
+ description: The idle timeout for TCP connections.
+ type: string
+ maxConnectionDuration:
+ description: The maximum duration of a connection.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConnections:
+ description: Maximum number of HTTP1 /TCP connections to a
+ destination host.
+ format: int32
+ type: integer
+ tcpKeepalive:
+ description: If set then set SO_KEEPALIVE on the socket to
+ enable TCP Keepalives.
+ properties:
+ interval:
+ description: The time duration between keep-alive probes.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ probes:
+ description: Maximum number of keepalive probes to send
+ without response before deciding the connection is dead.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ time:
+ description: The time duration a connection needs to be
+ idle before keep-alive probes start being sent.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ type: object
+ type: object
+ ingress:
+ description: Ingress specifies the configuration of the sidecar for
+ processing inbound traffic to the attached workload instance.
+ items:
+ properties:
+ bind:
+ description: The IP(IPv4 or IPv6) to which the listener should
+ be bound.
+ type: string
+ captureMode:
+ description: |-
+ The captureMode option dictates how traffic to the listener is expected to be captured (or not).
+
+ Valid Options: DEFAULT, IPTABLES, NONE
+ enum:
+ - DEFAULT
+ - IPTABLES
+ - NONE
+ type: string
+ connectionPool:
+ description: Settings controlling the volume of connections
+ Envoy will accept from the network.
+ properties:
+ http:
+ description: HTTP connection pool settings.
+ properties:
+ h2UpgradePolicy:
+ description: |-
+ Specify if http1.1 connection should be upgraded to http2 for the associated destination.
+
+ Valid Options: DEFAULT, DO_NOT_UPGRADE, UPGRADE
+ enum:
+ - DEFAULT
+ - DO_NOT_UPGRADE
+ - UPGRADE
+ type: string
+ http1MaxPendingRequests:
+ description: Maximum number of requests that will be
+ queued while waiting for a ready connection pool connection.
+ format: int32
+ type: integer
+ http2MaxRequests:
+ description: Maximum number of active requests to a
+ destination.
+ format: int32
+ type: integer
+ idleTimeout:
+ description: The idle timeout for upstream connection
+ pool connections.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConcurrentStreams:
+ description: The maximum number of concurrent streams
+ allowed for a peer on one HTTP/2 connection.
+ format: int32
+ type: integer
+ maxRequestsPerConnection:
+ description: Maximum number of requests per connection
+ to a backend.
+ format: int32
+ type: integer
+ maxRetries:
+ description: Maximum number of retries that can be outstanding
+ to all hosts in a cluster at a given time.
+ format: int32
+ type: integer
+ useClientProtocol:
+ description: If set to true, client protocol will be
+ preserved while initiating connection to backend.
+ type: boolean
+ type: object
+ tcp:
+ description: Settings common to both HTTP and TCP upstream
+ connections.
+ properties:
+ connectTimeout:
+ description: TCP connection timeout.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ idleTimeout:
+ description: The idle timeout for TCP connections.
+ type: string
+ maxConnectionDuration:
+ description: The maximum duration of a connection.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConnections:
+ description: Maximum number of HTTP1 /TCP connections
+ to a destination host.
+ format: int32
+ type: integer
+ tcpKeepalive:
+ description: If set then set SO_KEEPALIVE on the socket
+ to enable TCP Keepalives.
+ properties:
+ interval:
+ description: The time duration between keep-alive
+ probes.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ probes:
+ description: Maximum number of keepalive probes
+ to send without response before deciding the connection
+ is dead.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ time:
+ description: The time duration a connection needs
+ to be idle before keep-alive probes start being
+ sent.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ type: object
+ type: object
+ defaultEndpoint:
+ description: The IP endpoint or Unix domain socket to which
+ traffic should be forwarded to.
+ type: string
+ port:
+ description: The port associated with the listener.
+ properties:
+ name:
+ description: Label assigned to the port.
+ type: string
+ number:
+ description: A valid non-negative integer port number.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ protocol:
+ description: The protocol exposed on the port.
+ type: string
+ targetPort:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ tls:
+ description: Set of TLS related options that will enable TLS
+ termination on the sidecar for requests originating from outside
+ the mesh.
+ properties:
+ caCertCredentialName:
+ description: For mutual TLS, the name of the secret or the
+ configmap that holds CA certificates.
+ type: string
+ caCertificates:
+ description: REQUIRED if mode is `MUTUAL` or `OPTIONAL_MUTUAL`.
+ type: string
+ caCrl:
+ description: 'OPTIONAL: The path to the file containing
+ the certificate revocation list (CRL) to use in verifying
+ a presented client side certificate.'
+ type: string
+ cipherSuites:
+ description: 'Optional: If specified, only support the specified
+ cipher list.'
+ items:
+ type: string
+ type: array
+ credentialName:
+ description: For gateways running on Kubernetes, the name
+ of the secret that holds the TLS certs including the CA
+ certificates.
+ type: string
+ credentialNames:
+ description: Same as CredentialName but for multiple certificates.
+ items:
+ type: string
+ maxItems: 2
+ minItems: 1
+ type: array
+ httpsRedirect:
+ description: If set to true, the load balancer will send
+ a 301 redirect for all http connections, asking the clients
+ to use HTTPS.
+ type: boolean
+ maxProtocolVersion:
+ description: |-
+ Optional: Maximum TLS protocol version.
+
+ Valid Options: TLS_AUTO, TLSV1_0, TLSV1_1, TLSV1_2, TLSV1_3
+ enum:
+ - TLS_AUTO
+ - TLSV1_0
+ - TLSV1_1
+ - TLSV1_2
+ - TLSV1_3
+ type: string
+ minProtocolVersion:
+ description: |-
+ Optional: Minimum TLS protocol version.
+
+ Valid Options: TLS_AUTO, TLSV1_0, TLSV1_1, TLSV1_2, TLSV1_3
+ enum:
+ - TLS_AUTO
+ - TLSV1_0
+ - TLSV1_1
+ - TLSV1_2
+ - TLSV1_3
+ type: string
+ mode:
+ description: |-
+ Optional: Indicates whether connections to this port should be secured using TLS.
+
+ Valid Options: PASSTHROUGH, SIMPLE, MUTUAL, AUTO_PASSTHROUGH, ISTIO_MUTUAL, OPTIONAL_MUTUAL
+ enum:
+ - PASSTHROUGH
+ - SIMPLE
+ - MUTUAL
+ - AUTO_PASSTHROUGH
+ - ISTIO_MUTUAL
+ - OPTIONAL_MUTUAL
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ serverCertificate:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ subjectAltNames:
+ description: A list of alternate names to verify the subject
+ identity in the certificate presented by the client.
+ items:
+ type: string
+ type: array
+ tlsCertificates:
+ description: Only one of `server_certificate`, `private_key`
+ or `credential_name` or `credential_names` or `tls_certificates`
+ should be specified.
+ items:
+ properties:
+ caCertificates:
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ serverCertificate:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ type: object
+ maxItems: 2
+ minItems: 1
+ type: array
+ verifyCertificateHash:
+ description: An optional list of hex-encoded SHA-256 hashes
+ of the authorized client certificates.
+ items:
+ type: string
+ type: array
+ verifyCertificateSpki:
+ description: An optional list of base64-encoded SHA-256
+ hashes of the SPKIs of authorized client certificates.
+ items:
+ type: string
+ type: array
+ type: object
+ x-kubernetes-validations:
+ - message: only one of credentialNames or tlsCertificates can
+ be set
+ rule: '(has(self.tlsCertificates) ? 1 : 0) + (has(self.credentialNames)
+ ? 1 : 0) <= 1'
+ - message: only one of credentialName or credentialNames can
+ be set
+ rule: '(has(self.credentialName) ? 1 : 0) + (has(self.credentialNames)
+ ? 1 : 0) <= 1'
+ - message: only one of credentialName or tlsCertificates can
+ be set
+ rule: '(has(self.credentialNames) ? 1 : 0) + (has(self.tlsCertificates)
+ ? 1 : 0) <= 1'
+ required:
+ - port
+ type: object
+ type: array
+ outboundTrafficPolicy:
+ description: Set the default behavior of the sidecar for handling
+ outbound traffic from the application.
+ properties:
+ egressProxy:
+ properties:
+ host:
+ description: The name of a service from the service registry.
+ type: string
+ port:
+ description: Specifies the port on the host that is being
+ addressed.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ subset:
+ description: The name of a subset within the service.
+ type: string
+ required:
+ - host
+ type: object
+ mode:
+ description: |2-
+
+
+ Valid Options: REGISTRY_ONLY, ALLOW_ANY
+ enum:
+ - REGISTRY_ONLY
+ - ALLOW_ANY
+ type: string
+ type: object
+ workloadSelector:
+ description: Criteria used to select the specific set of pods/VMs
+ on which this `Sidecar` configuration should be applied.
+ properties:
+ labels:
+ additionalProperties:
+ maxLength: 63
+ type: string
+ x-kubernetes-validations:
+ - message: wildcard is not supported in selector
+ rule: '!self.contains("*")'
+ description: One or more labels that indicate a specific set of
+ pods/VMs on which the configuration should be applied.
+ maxProperties: 256
+ type: object
+ type: object
+ type: object
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ type: object
+ served: true
+ storage: false
+ subresources:
+ status: {}
+ - name: v1beta1
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Configuration affecting network reachability of a sidecar.
+ See more details at: https://istio.io/docs/reference/config/networking/sidecar.html'
+ properties:
+ egress:
+ description: Egress specifies the configuration of the sidecar for
+ processing outbound traffic from the attached workload instance
+ to other services in the mesh.
+ items:
+ properties:
+ bind:
+ description: The IP(IPv4 or IPv6) or the Unix domain socket
+ to which the listener should be bound to.
+ type: string
+ captureMode:
+ description: |-
+ When the bind address is an IP, the captureMode option dictates how traffic to the listener is expected to be captured (or not).
+
+ Valid Options: DEFAULT, IPTABLES, NONE
+ enum:
+ - DEFAULT
+ - IPTABLES
+ - NONE
+ type: string
+ hosts:
+ description: One or more service hosts exposed by the listener
+ in `namespace/dnsName` format.
+ items:
+ type: string
+ type: array
+ port:
+ description: The port associated with the listener.
+ properties:
+ name:
+ description: Label assigned to the port.
+ type: string
+ number:
+ description: A valid non-negative integer port number.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ protocol:
+ description: The protocol exposed on the port.
+ type: string
+ targetPort:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ required:
+ - hosts
+ type: object
+ type: array
+ inboundConnectionPool:
+ description: Settings controlling the volume of connections Envoy
+ will accept from the network.
+ properties:
+ http:
+ description: HTTP connection pool settings.
+ properties:
+ h2UpgradePolicy:
+ description: |-
+ Specify if http1.1 connection should be upgraded to http2 for the associated destination.
+
+ Valid Options: DEFAULT, DO_NOT_UPGRADE, UPGRADE
+ enum:
+ - DEFAULT
+ - DO_NOT_UPGRADE
+ - UPGRADE
+ type: string
+ http1MaxPendingRequests:
+ description: Maximum number of requests that will be queued
+ while waiting for a ready connection pool connection.
+ format: int32
+ type: integer
+ http2MaxRequests:
+ description: Maximum number of active requests to a destination.
+ format: int32
+ type: integer
+ idleTimeout:
+ description: The idle timeout for upstream connection pool
+ connections.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConcurrentStreams:
+ description: The maximum number of concurrent streams allowed
+ for a peer on one HTTP/2 connection.
+ format: int32
+ type: integer
+ maxRequestsPerConnection:
+ description: Maximum number of requests per connection to
+ a backend.
+ format: int32
+ type: integer
+ maxRetries:
+ description: Maximum number of retries that can be outstanding
+ to all hosts in a cluster at a given time.
+ format: int32
+ type: integer
+ useClientProtocol:
+ description: If set to true, client protocol will be preserved
+ while initiating connection to backend.
+ type: boolean
+ type: object
+ tcp:
+ description: Settings common to both HTTP and TCP upstream connections.
+ properties:
+ connectTimeout:
+ description: TCP connection timeout.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ idleTimeout:
+ description: The idle timeout for TCP connections.
+ type: string
+ maxConnectionDuration:
+ description: The maximum duration of a connection.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConnections:
+ description: Maximum number of HTTP1 /TCP connections to a
+ destination host.
+ format: int32
+ type: integer
+ tcpKeepalive:
+ description: If set then set SO_KEEPALIVE on the socket to
+ enable TCP Keepalives.
+ properties:
+ interval:
+ description: The time duration between keep-alive probes.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ probes:
+ description: Maximum number of keepalive probes to send
+ without response before deciding the connection is dead.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ time:
+ description: The time duration a connection needs to be
+ idle before keep-alive probes start being sent.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ type: object
+ type: object
+ ingress:
+ description: Ingress specifies the configuration of the sidecar for
+ processing inbound traffic to the attached workload instance.
+ items:
+ properties:
+ bind:
+ description: The IP(IPv4 or IPv6) to which the listener should
+ be bound.
+ type: string
+ captureMode:
+ description: |-
+ The captureMode option dictates how traffic to the listener is expected to be captured (or not).
+
+ Valid Options: DEFAULT, IPTABLES, NONE
+ enum:
+ - DEFAULT
+ - IPTABLES
+ - NONE
+ type: string
+ connectionPool:
+ description: Settings controlling the volume of connections
+ Envoy will accept from the network.
+ properties:
+ http:
+ description: HTTP connection pool settings.
+ properties:
+ h2UpgradePolicy:
+ description: |-
+ Specify if http1.1 connection should be upgraded to http2 for the associated destination.
+
+ Valid Options: DEFAULT, DO_NOT_UPGRADE, UPGRADE
+ enum:
+ - DEFAULT
+ - DO_NOT_UPGRADE
+ - UPGRADE
+ type: string
+ http1MaxPendingRequests:
+ description: Maximum number of requests that will be
+ queued while waiting for a ready connection pool connection.
+ format: int32
+ type: integer
+ http2MaxRequests:
+ description: Maximum number of active requests to a
+ destination.
+ format: int32
+ type: integer
+ idleTimeout:
+ description: The idle timeout for upstream connection
+ pool connections.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConcurrentStreams:
+ description: The maximum number of concurrent streams
+ allowed for a peer on one HTTP/2 connection.
+ format: int32
+ type: integer
+ maxRequestsPerConnection:
+ description: Maximum number of requests per connection
+ to a backend.
+ format: int32
+ type: integer
+ maxRetries:
+ description: Maximum number of retries that can be outstanding
+ to all hosts in a cluster at a given time.
+ format: int32
+ type: integer
+ useClientProtocol:
+ description: If set to true, client protocol will be
+ preserved while initiating connection to backend.
+ type: boolean
+ type: object
+ tcp:
+ description: Settings common to both HTTP and TCP upstream
+ connections.
+ properties:
+ connectTimeout:
+ description: TCP connection timeout.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ idleTimeout:
+ description: The idle timeout for TCP connections.
+ type: string
+ maxConnectionDuration:
+ description: The maximum duration of a connection.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ maxConnections:
+ description: Maximum number of HTTP1 /TCP connections
+ to a destination host.
+ format: int32
+ type: integer
+ tcpKeepalive:
+ description: If set then set SO_KEEPALIVE on the socket
+ to enable TCP Keepalives.
+ properties:
+ interval:
+ description: The time duration between keep-alive
+ probes.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ probes:
+ description: Maximum number of keepalive probes
+ to send without response before deciding the connection
+ is dead.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ time:
+ description: The time duration a connection needs
+ to be idle before keep-alive probes start being
+ sent.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than
+ 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ type: object
+ type: object
+ defaultEndpoint:
+ description: The IP endpoint or Unix domain socket to which
+ traffic should be forwarded to.
+ type: string
+ port:
+ description: The port associated with the listener.
+ properties:
+ name:
+ description: Label assigned to the port.
+ type: string
+ number:
+ description: A valid non-negative integer port number.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ protocol:
+ description: The protocol exposed on the port.
+ type: string
+ targetPort:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ tls:
+ description: Set of TLS related options that will enable TLS
+ termination on the sidecar for requests originating from outside
+ the mesh.
+ properties:
+ caCertCredentialName:
+ description: For mutual TLS, the name of the secret or the
+ configmap that holds CA certificates.
+ type: string
+ caCertificates:
+ description: REQUIRED if mode is `MUTUAL` or `OPTIONAL_MUTUAL`.
+ type: string
+ caCrl:
+ description: 'OPTIONAL: The path to the file containing
+ the certificate revocation list (CRL) to use in verifying
+ a presented client side certificate.'
+ type: string
+ cipherSuites:
+ description: 'Optional: If specified, only support the specified
+ cipher list.'
+ items:
+ type: string
+ type: array
+ credentialName:
+ description: For gateways running on Kubernetes, the name
+ of the secret that holds the TLS certs including the CA
+ certificates.
+ type: string
+ credentialNames:
+ description: Same as CredentialName but for multiple certificates.
+ items:
+ type: string
+ maxItems: 2
+ minItems: 1
+ type: array
+ httpsRedirect:
+ description: If set to true, the load balancer will send
+ a 301 redirect for all http connections, asking the clients
+ to use HTTPS.
+ type: boolean
+ maxProtocolVersion:
+ description: |-
+ Optional: Maximum TLS protocol version.
+
+ Valid Options: TLS_AUTO, TLSV1_0, TLSV1_1, TLSV1_2, TLSV1_3
+ enum:
+ - TLS_AUTO
+ - TLSV1_0
+ - TLSV1_1
+ - TLSV1_2
+ - TLSV1_3
+ type: string
+ minProtocolVersion:
+ description: |-
+ Optional: Minimum TLS protocol version.
+
+ Valid Options: TLS_AUTO, TLSV1_0, TLSV1_1, TLSV1_2, TLSV1_3
+ enum:
+ - TLS_AUTO
+ - TLSV1_0
+ - TLSV1_1
+ - TLSV1_2
+ - TLSV1_3
+ type: string
+ mode:
+ description: |-
+ Optional: Indicates whether connections to this port should be secured using TLS.
+
+ Valid Options: PASSTHROUGH, SIMPLE, MUTUAL, AUTO_PASSTHROUGH, ISTIO_MUTUAL, OPTIONAL_MUTUAL
+ enum:
+ - PASSTHROUGH
+ - SIMPLE
+ - MUTUAL
+ - AUTO_PASSTHROUGH
+ - ISTIO_MUTUAL
+ - OPTIONAL_MUTUAL
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ serverCertificate:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ subjectAltNames:
+ description: A list of alternate names to verify the subject
+ identity in the certificate presented by the client.
+ items:
+ type: string
+ type: array
+ tlsCertificates:
+ description: Only one of `server_certificate`, `private_key`
+ or `credential_name` or `credential_names` or `tls_certificates`
+ should be specified.
+ items:
+ properties:
+ caCertificates:
+ type: string
+ privateKey:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ serverCertificate:
+ description: REQUIRED if mode is `SIMPLE` or `MUTUAL`.
+ type: string
+ type: object
+ maxItems: 2
+ minItems: 1
+ type: array
+ verifyCertificateHash:
+ description: An optional list of hex-encoded SHA-256 hashes
+ of the authorized client certificates.
+ items:
+ type: string
+ type: array
+ verifyCertificateSpki:
+ description: An optional list of base64-encoded SHA-256
+ hashes of the SPKIs of authorized client certificates.
+ items:
+ type: string
+ type: array
+ type: object
+ x-kubernetes-validations:
+ - message: only one of credentialNames or tlsCertificates can
+ be set
+ rule: '(has(self.tlsCertificates) ? 1 : 0) + (has(self.credentialNames)
+ ? 1 : 0) <= 1'
+ - message: only one of credentialName or credentialNames can
+ be set
+ rule: '(has(self.credentialName) ? 1 : 0) + (has(self.credentialNames)
+ ? 1 : 0) <= 1'
+ - message: only one of credentialName or tlsCertificates can
+ be set
+ rule: '(has(self.credentialNames) ? 1 : 0) + (has(self.tlsCertificates)
+ ? 1 : 0) <= 1'
+ required:
+ - port
+ type: object
+ type: array
+ outboundTrafficPolicy:
+ description: Set the default behavior of the sidecar for handling
+ outbound traffic from the application.
+ properties:
+ egressProxy:
+ properties:
+ host:
+ description: The name of a service from the service registry.
+ type: string
+ port:
+ description: Specifies the port on the host that is being
+ addressed.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ subset:
+ description: The name of a subset within the service.
+ type: string
+ required:
+ - host
+ type: object
+ mode:
+ description: |2-
+
+
+ Valid Options: REGISTRY_ONLY, ALLOW_ANY
+ enum:
+ - REGISTRY_ONLY
+ - ALLOW_ANY
+ type: string
+ type: object
+ workloadSelector:
+ description: Criteria used to select the specific set of pods/VMs
+ on which this `Sidecar` configuration should be applied.
+ properties:
+ labels:
+ additionalProperties:
+ maxLength: 63
+ type: string
+ x-kubernetes-validations:
+ - message: wildcard is not supported in selector
+ rule: '!self.contains("*")'
+ description: One or more labels that indicate a specific set of
+ pods/VMs on which the configuration should be applied.
+ maxProperties: 256
+ type: object
+ type: object
+ type: object
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ type: object
+ served: true
+ storage: false
+ subresources:
+ status: {}
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_virtualservices.yaml b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_virtualservices.yaml
new file mode 100644
index 0000000000..8d26d69d2d
--- /dev/null
+++ b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_virtualservices.yaml
@@ -0,0 +1,3181 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ "helm.sh/resource-policy": keep
+ labels:
+ app: istio-pilot
+ chart: istio
+ heritage: Tiller
+ release: istio
+ name: virtualservices.networking.istio.io
+spec:
+ group: networking.istio.io
+ names:
+ categories:
+ - istio-io
+ - networking-istio-io
+ kind: VirtualService
+ listKind: VirtualServiceList
+ plural: virtualservices
+ shortNames:
+ - vs
+ singular: virtualservice
+ scope: Namespaced
+ versions:
+ - additionalPrinterColumns:
+ - description: The names of gateways and sidecars that should apply these routes
+ jsonPath: .spec.gateways
+ name: Gateways
+ type: string
+ - description: The destination hosts to which traffic is being sent
+ jsonPath: .spec.hosts
+ name: Hosts
+ type: string
+ - description: 'CreationTimestamp is a timestamp representing the server time
+ when this object was created. It is not guaranteed to be set in happens-before
+ order across separate operations. Clients may not set this value. It is represented
+ in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for
+ lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata'
+ jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Configuration affecting label/content routing, sni routing,
+ etc. See more details at: https://istio.io/docs/reference/config/networking/virtual-service.html'
+ properties:
+ exportTo:
+ description: A list of namespaces to which this virtual service is
+ exported.
+ items:
+ type: string
+ type: array
+ gateways:
+ description: The names of gateways and sidecars that should apply
+ these routes.
+ items:
+ type: string
+ type: array
+ hosts:
+ description: The destination hosts to which traffic is being sent.
+ items:
+ type: string
+ type: array
+ http:
+ description: An ordered list of route rules for HTTP traffic.
+ items:
+ properties:
+ corsPolicy:
+ description: Cross-Origin Resource Sharing policy (CORS).
+ properties:
+ allowCredentials:
+ description: Indicates whether the caller is allowed to
+ send the actual request (not the preflight) using credentials.
+ nullable: true
+ type: boolean
+ allowHeaders:
+ description: List of HTTP headers that can be used when
+ requesting the resource.
+ items:
+ type: string
+ type: array
+ allowMethods:
+ description: List of HTTP methods allowed to access the
+ resource.
+ items:
+ type: string
+ type: array
+ allowOrigin:
+ items:
+ type: string
+ type: array
+ allowOrigins:
+ description: String patterns that match allowed origins.
+ items:
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ type: array
+ exposeHeaders:
+ description: A list of HTTP headers that the browsers are
+ allowed to access.
+ items:
+ type: string
+ type: array
+ maxAge:
+ description: Specifies how long the results of a preflight
+ request can be cached.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ unmatchedPreflights:
+ description: |-
+ Indicates whether preflight requests not matching the configured allowed origin shouldn't be forwarded to the upstream.
+
+ Valid Options: FORWARD, IGNORE
+ enum:
+ - UNSPECIFIED
+ - FORWARD
+ - IGNORE
+ type: string
+ type: object
+ delegate:
+ description: Delegate is used to specify the particular VirtualService
+ which can be used to define delegate HTTPRoute.
+ properties:
+ name:
+ description: Name specifies the name of the delegate VirtualService.
+ type: string
+ namespace:
+ description: Namespace specifies the namespace where the
+ delegate VirtualService resides.
+ type: string
+ type: object
+ directResponse:
+ description: A HTTP rule can either return a direct_response,
+ redirect or forward (default) traffic.
+ properties:
+ body:
+ description: Specifies the content of the response body.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - string
+ - required:
+ - bytes
+ - required:
+ - string
+ - required:
+ - bytes
+ properties:
+ bytes:
+ description: response body as base64 encoded bytes.
+ format: byte
+ type: string
+ string:
+ type: string
+ type: object
+ status:
+ description: Specifies the HTTP response status to be returned.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ required:
+ - status
+ type: object
+ fault:
+ description: Fault injection policy to apply on HTTP traffic
+ at the client side.
+ properties:
+ abort:
+ description: Abort Http request attempts and return error
+ codes back to downstream service, giving the impression
+ that the upstream service is faulty.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - httpStatus
+ - required:
+ - grpcStatus
+ - required:
+ - http2Error
+ - required:
+ - httpStatus
+ - required:
+ - grpcStatus
+ - required:
+ - http2Error
+ properties:
+ grpcStatus:
+ description: GRPC status code to use to abort the request.
+ type: string
+ http2Error:
+ type: string
+ httpStatus:
+ description: HTTP status code to use to abort the Http
+ request.
+ format: int32
+ type: integer
+ percentage:
+ description: Percentage of requests to be aborted with
+ the error code provided.
+ properties:
+ value:
+ format: double
+ type: number
+ type: object
+ type: object
+ delay:
+ description: Delay requests before forwarding, emulating
+ various failures such as network issues, overloaded upstream
+ service, etc.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - fixedDelay
+ - required:
+ - exponentialDelay
+ - required:
+ - fixedDelay
+ - required:
+ - exponentialDelay
+ properties:
+ exponentialDelay:
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ fixedDelay:
+ description: Add a fixed delay before forwarding the
+ request.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ percent:
+ description: Percentage of requests on which the delay
+ will be injected (0-100).
+ format: int32
+ type: integer
+ percentage:
+ description: Percentage of requests on which the delay
+ will be injected.
+ properties:
+ value:
+ format: double
+ type: number
+ type: object
+ type: object
+ type: object
+ headers:
+ properties:
+ request:
+ properties:
+ add:
+ additionalProperties:
+ type: string
+ type: object
+ remove:
+ items:
+ type: string
+ type: array
+ set:
+ additionalProperties:
+ type: string
+ type: object
+ type: object
+ response:
+ properties:
+ add:
+ additionalProperties:
+ type: string
+ type: object
+ remove:
+ items:
+ type: string
+ type: array
+ set:
+ additionalProperties:
+ type: string
+ type: object
+ type: object
+ type: object
+ match:
+ description: Match conditions to be satisfied for the rule to
+ be activated.
+ items:
+ properties:
+ authority:
+ description: 'HTTP Authority values are case-sensitive
+ and formatted as follows: - `exact: "value"` for exact
+ string match - `prefix: "value"` for prefix-based match
+ - `regex: "value"` for [RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ gateways:
+ description: Names of gateways where the rule should be
+ applied.
+ items:
+ type: string
+ type: array
+ headers:
+ additionalProperties:
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ description: The header keys must be lowercase and use
+ hyphen as the separator, e.g.
+ type: object
+ ignoreUriCase:
+ description: Flag to specify whether the URI matching
+ should be case-insensitive.
+ type: boolean
+ method:
+ description: 'HTTP Method values are case-sensitive and
+ formatted as follows: - `exact: "value"` for exact string
+ match - `prefix: "value"` for prefix-based match - `regex:
+ "value"` for [RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ name:
+ description: The name assigned to a match.
+ type: string
+ port:
+ description: Specifies the ports on the host that is being
+ addressed.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ queryParams:
+ additionalProperties:
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ description: Query parameters for matching.
+ type: object
+ scheme:
+ description: 'URI Scheme values are case-sensitive and
+ formatted as follows: - `exact: "value"` for exact string
+ match - `prefix: "value"` for prefix-based match - `regex:
+ "value"` for [RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ sourceLabels:
+ additionalProperties:
+ type: string
+ description: One or more labels that constrain the applicability
+ of a rule to source (client) workloads with the given
+ labels.
+ type: object
+ sourceNamespace:
+ description: Source namespace constraining the applicability
+ of a rule to workloads in that namespace.
+ type: string
+ statPrefix:
+ description: The human readable prefix to use when emitting
+ statistics for this route.
+ type: string
+ uri:
+ description: 'URI to match values are case-sensitive and
+ formatted as follows: - `exact: "value"` for exact string
+ match - `prefix: "value"` for prefix-based match - `regex:
+ "value"` for [RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ withoutHeaders:
+ additionalProperties:
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ description: withoutHeader has the same syntax with the
+ header, but has opposite meaning.
+ type: object
+ type: object
+ type: array
+ mirror:
+ description: Mirror HTTP traffic to a another destination in
+ addition to forwarding the requests to the intended destination.
+ properties:
+ host:
+ description: The name of a service from the service registry.
+ type: string
+ port:
+ description: Specifies the port on the host that is being
+ addressed.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ subset:
+ description: The name of a subset within the service.
+ type: string
+ required:
+ - host
+ type: object
+ mirror_percent:
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ mirrorPercent:
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ mirrorPercentage:
+ description: Percentage of the traffic to be mirrored by the
+ `mirror` field.
+ properties:
+ value:
+ format: double
+ type: number
+ type: object
+ mirrors:
+ description: Specifies the destinations to mirror HTTP traffic
+ in addition to the original destination.
+ items:
+ properties:
+ destination:
+ description: Destination specifies the target of the mirror
+ operation.
+ properties:
+ host:
+ description: The name of a service from the service
+ registry.
+ type: string
+ port:
+ description: Specifies the port on the host that is
+ being addressed.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ subset:
+ description: The name of a subset within the service.
+ type: string
+ required:
+ - host
+ type: object
+ percentage:
+ description: Percentage of the traffic to be mirrored
+ by the `destination` field.
+ properties:
+ value:
+ format: double
+ type: number
+ type: object
+ required:
+ - destination
+ type: object
+ type: array
+ name:
+ description: The name assigned to the route for debugging purposes.
+ type: string
+ redirect:
+ description: A HTTP rule can either return a direct_response,
+ redirect or forward (default) traffic.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - port
+ - required:
+ - derivePort
+ - required:
+ - port
+ - required:
+ - derivePort
+ properties:
+ authority:
+ description: On a redirect, overwrite the Authority/Host
+ portion of the URL with this value.
+ type: string
+ derivePort:
+ description: |-
+ On a redirect, dynamically set the port: * FROM_PROTOCOL_DEFAULT: automatically set to 80 for HTTP and 443 for HTTPS.
+
+ Valid Options: FROM_PROTOCOL_DEFAULT, FROM_REQUEST_PORT
+ enum:
+ - FROM_PROTOCOL_DEFAULT
+ - FROM_REQUEST_PORT
+ type: string
+ port:
+ description: On a redirect, overwrite the port portion of
+ the URL with this value.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ redirectCode:
+ description: On a redirect, Specifies the HTTP status code
+ to use in the redirect response.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ scheme:
+ description: On a redirect, overwrite the scheme portion
+ of the URL with this value.
+ type: string
+ uri:
+ description: On a redirect, overwrite the Path portion of
+ the URL with this value.
+ type: string
+ type: object
+ retries:
+ description: Retry policy for HTTP requests.
+ properties:
+ attempts:
+ description: Number of retries to be allowed for a given
+ request.
+ format: int32
+ type: integer
+ backoff:
+ description: Specifies the minimum duration between retry
+ attempts.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ perTryTimeout:
+ description: Timeout per attempt for a given request, including
+ the initial call and any retries.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ retryIgnorePreviousHosts:
+ description: Flag to specify whether the retries should
+ ignore previously tried hosts during retry.
+ nullable: true
+ type: boolean
+ retryOn:
+ description: Specifies the conditions under which retry
+ takes place.
+ type: string
+ retryRemoteLocalities:
+ description: Flag to specify whether the retries should
+ retry to other localities.
+ nullable: true
+ type: boolean
+ type: object
+ rewrite:
+ description: Rewrite HTTP URIs and Authority headers.
+ properties:
+ authority:
+ description: rewrite the Authority/Host header with this
+ value.
+ type: string
+ uri:
+ description: rewrite the path (or the prefix) portion of
+ the URI with this value.
+ type: string
+ uriRegexRewrite:
+ description: rewrite the path portion of the URI with the
+ specified regex.
+ properties:
+ match:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ rewrite:
+ description: The string that should replace into matching
+ portions of original URI.
+ type: string
+ type: object
+ type: object
+ route:
+ description: A HTTP rule can either return a direct_response,
+ redirect or forward (default) traffic.
+ items:
+ properties:
+ destination:
+ description: Destination uniquely identifies the instances
+ of a service to which the request/connection should
+ be forwarded to.
+ properties:
+ host:
+ description: The name of a service from the service
+ registry.
+ type: string
+ port:
+ description: Specifies the port on the host that is
+ being addressed.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ subset:
+ description: The name of a subset within the service.
+ type: string
+ required:
+ - host
+ type: object
+ headers:
+ properties:
+ request:
+ properties:
+ add:
+ additionalProperties:
+ type: string
+ type: object
+ remove:
+ items:
+ type: string
+ type: array
+ set:
+ additionalProperties:
+ type: string
+ type: object
+ type: object
+ response:
+ properties:
+ add:
+ additionalProperties:
+ type: string
+ type: object
+ remove:
+ items:
+ type: string
+ type: array
+ set:
+ additionalProperties:
+ type: string
+ type: object
+ type: object
+ type: object
+ weight:
+ description: Weight specifies the relative proportion
+ of traffic to be forwarded to the destination.
+ format: int32
+ type: integer
+ required:
+ - destination
+ type: object
+ type: array
+ timeout:
+ description: Timeout for HTTP requests, default is disabled.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ type: array
+ tcp:
+ description: An ordered list of route rules for opaque TCP traffic.
+ items:
+ properties:
+ match:
+ description: Match conditions to be satisfied for the rule to
+ be activated.
+ items:
+ properties:
+ destinationSubnets:
+ description: IPv4 or IPv6 ip addresses of destination
+ with optional subnet.
+ items:
+ type: string
+ type: array
+ gateways:
+ description: Names of gateways where the rule should be
+ applied.
+ items:
+ type: string
+ type: array
+ port:
+ description: Specifies the port on the host that is being
+ addressed.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ sourceLabels:
+ additionalProperties:
+ type: string
+ description: One or more labels that constrain the applicability
+ of a rule to workloads with the given labels.
+ type: object
+ sourceNamespace:
+ description: Source namespace constraining the applicability
+ of a rule to workloads in that namespace.
+ type: string
+ sourceSubnet:
+ type: string
+ type: object
+ type: array
+ route:
+ description: The destination to which the connection should
+ be forwarded to.
+ items:
+ properties:
+ destination:
+ description: Destination uniquely identifies the instances
+ of a service to which the request/connection should
+ be forwarded to.
+ properties:
+ host:
+ description: The name of a service from the service
+ registry.
+ type: string
+ port:
+ description: Specifies the port on the host that is
+ being addressed.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ subset:
+ description: The name of a subset within the service.
+ type: string
+ required:
+ - host
+ type: object
+ weight:
+ description: Weight specifies the relative proportion
+ of traffic to be forwarded to the destination.
+ format: int32
+ type: integer
+ required:
+ - destination
+ type: object
+ type: array
+ type: object
+ type: array
+ tls:
+ description: An ordered list of route rule for non-terminated TLS
+ & HTTPS traffic.
+ items:
+ properties:
+ match:
+ description: Match conditions to be satisfied for the rule to
+ be activated.
+ items:
+ properties:
+ destinationSubnets:
+ description: IPv4 or IPv6 ip addresses of destination
+ with optional subnet.
+ items:
+ type: string
+ type: array
+ gateways:
+ description: Names of gateways where the rule should be
+ applied.
+ items:
+ type: string
+ type: array
+ port:
+ description: Specifies the port on the host that is being
+ addressed.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ sniHosts:
+ description: SNI (server name indicator) to match on.
+ items:
+ type: string
+ type: array
+ sourceLabels:
+ additionalProperties:
+ type: string
+ description: One or more labels that constrain the applicability
+ of a rule to workloads with the given labels.
+ type: object
+ sourceNamespace:
+ description: Source namespace constraining the applicability
+ of a rule to workloads in that namespace.
+ type: string
+ required:
+ - sniHosts
+ type: object
+ type: array
+ route:
+ description: The destination to which the connection should
+ be forwarded to.
+ items:
+ properties:
+ destination:
+ description: Destination uniquely identifies the instances
+ of a service to which the request/connection should
+ be forwarded to.
+ properties:
+ host:
+ description: The name of a service from the service
+ registry.
+ type: string
+ port:
+ description: Specifies the port on the host that is
+ being addressed.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ subset:
+ description: The name of a subset within the service.
+ type: string
+ required:
+ - host
+ type: object
+ weight:
+ description: Weight specifies the relative proportion
+ of traffic to be forwarded to the destination.
+ format: int32
+ type: integer
+ required:
+ - destination
+ type: object
+ type: array
+ required:
+ - match
+ type: object
+ type: array
+ type: object
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
+ - additionalPrinterColumns:
+ - description: The names of gateways and sidecars that should apply these routes
+ jsonPath: .spec.gateways
+ name: Gateways
+ type: string
+ - description: The destination hosts to which traffic is being sent
+ jsonPath: .spec.hosts
+ name: Hosts
+ type: string
+ - description: 'CreationTimestamp is a timestamp representing the server time
+ when this object was created. It is not guaranteed to be set in happens-before
+ order across separate operations. Clients may not set this value. It is represented
+ in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for
+ lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata'
+ jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1alpha3
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Configuration affecting label/content routing, sni routing,
+ etc. See more details at: https://istio.io/docs/reference/config/networking/virtual-service.html'
+ properties:
+ exportTo:
+ description: A list of namespaces to which this virtual service is
+ exported.
+ items:
+ type: string
+ type: array
+ gateways:
+ description: The names of gateways and sidecars that should apply
+ these routes.
+ items:
+ type: string
+ type: array
+ hosts:
+ description: The destination hosts to which traffic is being sent.
+ items:
+ type: string
+ type: array
+ http:
+ description: An ordered list of route rules for HTTP traffic.
+ items:
+ properties:
+ corsPolicy:
+ description: Cross-Origin Resource Sharing policy (CORS).
+ properties:
+ allowCredentials:
+ description: Indicates whether the caller is allowed to
+ send the actual request (not the preflight) using credentials.
+ nullable: true
+ type: boolean
+ allowHeaders:
+ description: List of HTTP headers that can be used when
+ requesting the resource.
+ items:
+ type: string
+ type: array
+ allowMethods:
+ description: List of HTTP methods allowed to access the
+ resource.
+ items:
+ type: string
+ type: array
+ allowOrigin:
+ items:
+ type: string
+ type: array
+ allowOrigins:
+ description: String patterns that match allowed origins.
+ items:
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ type: array
+ exposeHeaders:
+ description: A list of HTTP headers that the browsers are
+ allowed to access.
+ items:
+ type: string
+ type: array
+ maxAge:
+ description: Specifies how long the results of a preflight
+ request can be cached.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ unmatchedPreflights:
+ description: |-
+ Indicates whether preflight requests not matching the configured allowed origin shouldn't be forwarded to the upstream.
+
+ Valid Options: FORWARD, IGNORE
+ enum:
+ - UNSPECIFIED
+ - FORWARD
+ - IGNORE
+ type: string
+ type: object
+ delegate:
+ description: Delegate is used to specify the particular VirtualService
+ which can be used to define delegate HTTPRoute.
+ properties:
+ name:
+ description: Name specifies the name of the delegate VirtualService.
+ type: string
+ namespace:
+ description: Namespace specifies the namespace where the
+ delegate VirtualService resides.
+ type: string
+ type: object
+ directResponse:
+ description: A HTTP rule can either return a direct_response,
+ redirect or forward (default) traffic.
+ properties:
+ body:
+ description: Specifies the content of the response body.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - string
+ - required:
+ - bytes
+ - required:
+ - string
+ - required:
+ - bytes
+ properties:
+ bytes:
+ description: response body as base64 encoded bytes.
+ format: byte
+ type: string
+ string:
+ type: string
+ type: object
+ status:
+ description: Specifies the HTTP response status to be returned.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ required:
+ - status
+ type: object
+ fault:
+ description: Fault injection policy to apply on HTTP traffic
+ at the client side.
+ properties:
+ abort:
+ description: Abort Http request attempts and return error
+ codes back to downstream service, giving the impression
+ that the upstream service is faulty.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - httpStatus
+ - required:
+ - grpcStatus
+ - required:
+ - http2Error
+ - required:
+ - httpStatus
+ - required:
+ - grpcStatus
+ - required:
+ - http2Error
+ properties:
+ grpcStatus:
+ description: GRPC status code to use to abort the request.
+ type: string
+ http2Error:
+ type: string
+ httpStatus:
+ description: HTTP status code to use to abort the Http
+ request.
+ format: int32
+ type: integer
+ percentage:
+ description: Percentage of requests to be aborted with
+ the error code provided.
+ properties:
+ value:
+ format: double
+ type: number
+ type: object
+ type: object
+ delay:
+ description: Delay requests before forwarding, emulating
+ various failures such as network issues, overloaded upstream
+ service, etc.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - fixedDelay
+ - required:
+ - exponentialDelay
+ - required:
+ - fixedDelay
+ - required:
+ - exponentialDelay
+ properties:
+ exponentialDelay:
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ fixedDelay:
+ description: Add a fixed delay before forwarding the
+ request.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ percent:
+ description: Percentage of requests on which the delay
+ will be injected (0-100).
+ format: int32
+ type: integer
+ percentage:
+ description: Percentage of requests on which the delay
+ will be injected.
+ properties:
+ value:
+ format: double
+ type: number
+ type: object
+ type: object
+ type: object
+ headers:
+ properties:
+ request:
+ properties:
+ add:
+ additionalProperties:
+ type: string
+ type: object
+ remove:
+ items:
+ type: string
+ type: array
+ set:
+ additionalProperties:
+ type: string
+ type: object
+ type: object
+ response:
+ properties:
+ add:
+ additionalProperties:
+ type: string
+ type: object
+ remove:
+ items:
+ type: string
+ type: array
+ set:
+ additionalProperties:
+ type: string
+ type: object
+ type: object
+ type: object
+ match:
+ description: Match conditions to be satisfied for the rule to
+ be activated.
+ items:
+ properties:
+ authority:
+ description: 'HTTP Authority values are case-sensitive
+ and formatted as follows: - `exact: "value"` for exact
+ string match - `prefix: "value"` for prefix-based match
+ - `regex: "value"` for [RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ gateways:
+ description: Names of gateways where the rule should be
+ applied.
+ items:
+ type: string
+ type: array
+ headers:
+ additionalProperties:
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ description: The header keys must be lowercase and use
+ hyphen as the separator, e.g.
+ type: object
+ ignoreUriCase:
+ description: Flag to specify whether the URI matching
+ should be case-insensitive.
+ type: boolean
+ method:
+ description: 'HTTP Method values are case-sensitive and
+ formatted as follows: - `exact: "value"` for exact string
+ match - `prefix: "value"` for prefix-based match - `regex:
+ "value"` for [RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ name:
+ description: The name assigned to a match.
+ type: string
+ port:
+ description: Specifies the ports on the host that is being
+ addressed.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ queryParams:
+ additionalProperties:
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ description: Query parameters for matching.
+ type: object
+ scheme:
+ description: 'URI Scheme values are case-sensitive and
+ formatted as follows: - `exact: "value"` for exact string
+ match - `prefix: "value"` for prefix-based match - `regex:
+ "value"` for [RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ sourceLabels:
+ additionalProperties:
+ type: string
+ description: One or more labels that constrain the applicability
+ of a rule to source (client) workloads with the given
+ labels.
+ type: object
+ sourceNamespace:
+ description: Source namespace constraining the applicability
+ of a rule to workloads in that namespace.
+ type: string
+ statPrefix:
+ description: The human readable prefix to use when emitting
+ statistics for this route.
+ type: string
+ uri:
+ description: 'URI to match values are case-sensitive and
+ formatted as follows: - `exact: "value"` for exact string
+ match - `prefix: "value"` for prefix-based match - `regex:
+ "value"` for [RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ withoutHeaders:
+ additionalProperties:
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ description: withoutHeader has the same syntax with the
+ header, but has opposite meaning.
+ type: object
+ type: object
+ type: array
+ mirror:
+ description: Mirror HTTP traffic to a another destination in
+ addition to forwarding the requests to the intended destination.
+ properties:
+ host:
+ description: The name of a service from the service registry.
+ type: string
+ port:
+ description: Specifies the port on the host that is being
+ addressed.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ subset:
+ description: The name of a subset within the service.
+ type: string
+ required:
+ - host
+ type: object
+ mirror_percent:
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ mirrorPercent:
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ mirrorPercentage:
+ description: Percentage of the traffic to be mirrored by the
+ `mirror` field.
+ properties:
+ value:
+ format: double
+ type: number
+ type: object
+ mirrors:
+ description: Specifies the destinations to mirror HTTP traffic
+ in addition to the original destination.
+ items:
+ properties:
+ destination:
+ description: Destination specifies the target of the mirror
+ operation.
+ properties:
+ host:
+ description: The name of a service from the service
+ registry.
+ type: string
+ port:
+ description: Specifies the port on the host that is
+ being addressed.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ subset:
+ description: The name of a subset within the service.
+ type: string
+ required:
+ - host
+ type: object
+ percentage:
+ description: Percentage of the traffic to be mirrored
+ by the `destination` field.
+ properties:
+ value:
+ format: double
+ type: number
+ type: object
+ required:
+ - destination
+ type: object
+ type: array
+ name:
+ description: The name assigned to the route for debugging purposes.
+ type: string
+ redirect:
+ description: A HTTP rule can either return a direct_response,
+ redirect or forward (default) traffic.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - port
+ - required:
+ - derivePort
+ - required:
+ - port
+ - required:
+ - derivePort
+ properties:
+ authority:
+ description: On a redirect, overwrite the Authority/Host
+ portion of the URL with this value.
+ type: string
+ derivePort:
+ description: |-
+ On a redirect, dynamically set the port: * FROM_PROTOCOL_DEFAULT: automatically set to 80 for HTTP and 443 for HTTPS.
+
+ Valid Options: FROM_PROTOCOL_DEFAULT, FROM_REQUEST_PORT
+ enum:
+ - FROM_PROTOCOL_DEFAULT
+ - FROM_REQUEST_PORT
+ type: string
+ port:
+ description: On a redirect, overwrite the port portion of
+ the URL with this value.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ redirectCode:
+ description: On a redirect, Specifies the HTTP status code
+ to use in the redirect response.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ scheme:
+ description: On a redirect, overwrite the scheme portion
+ of the URL with this value.
+ type: string
+ uri:
+ description: On a redirect, overwrite the Path portion of
+ the URL with this value.
+ type: string
+ type: object
+ retries:
+ description: Retry policy for HTTP requests.
+ properties:
+ attempts:
+ description: Number of retries to be allowed for a given
+ request.
+ format: int32
+ type: integer
+ backoff:
+ description: Specifies the minimum duration between retry
+ attempts.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ perTryTimeout:
+ description: Timeout per attempt for a given request, including
+ the initial call and any retries.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ retryIgnorePreviousHosts:
+ description: Flag to specify whether the retries should
+ ignore previously tried hosts during retry.
+ nullable: true
+ type: boolean
+ retryOn:
+ description: Specifies the conditions under which retry
+ takes place.
+ type: string
+ retryRemoteLocalities:
+ description: Flag to specify whether the retries should
+ retry to other localities.
+ nullable: true
+ type: boolean
+ type: object
+ rewrite:
+ description: Rewrite HTTP URIs and Authority headers.
+ properties:
+ authority:
+ description: rewrite the Authority/Host header with this
+ value.
+ type: string
+ uri:
+ description: rewrite the path (or the prefix) portion of
+ the URI with this value.
+ type: string
+ uriRegexRewrite:
+ description: rewrite the path portion of the URI with the
+ specified regex.
+ properties:
+ match:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ rewrite:
+ description: The string that should replace into matching
+ portions of original URI.
+ type: string
+ type: object
+ type: object
+ route:
+ description: A HTTP rule can either return a direct_response,
+ redirect or forward (default) traffic.
+ items:
+ properties:
+ destination:
+ description: Destination uniquely identifies the instances
+ of a service to which the request/connection should
+ be forwarded to.
+ properties:
+ host:
+ description: The name of a service from the service
+ registry.
+ type: string
+ port:
+ description: Specifies the port on the host that is
+ being addressed.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ subset:
+ description: The name of a subset within the service.
+ type: string
+ required:
+ - host
+ type: object
+ headers:
+ properties:
+ request:
+ properties:
+ add:
+ additionalProperties:
+ type: string
+ type: object
+ remove:
+ items:
+ type: string
+ type: array
+ set:
+ additionalProperties:
+ type: string
+ type: object
+ type: object
+ response:
+ properties:
+ add:
+ additionalProperties:
+ type: string
+ type: object
+ remove:
+ items:
+ type: string
+ type: array
+ set:
+ additionalProperties:
+ type: string
+ type: object
+ type: object
+ type: object
+ weight:
+ description: Weight specifies the relative proportion
+ of traffic to be forwarded to the destination.
+ format: int32
+ type: integer
+ required:
+ - destination
+ type: object
+ type: array
+ timeout:
+ description: Timeout for HTTP requests, default is disabled.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ type: array
+ tcp:
+ description: An ordered list of route rules for opaque TCP traffic.
+ items:
+ properties:
+ match:
+ description: Match conditions to be satisfied for the rule to
+ be activated.
+ items:
+ properties:
+ destinationSubnets:
+ description: IPv4 or IPv6 ip addresses of destination
+ with optional subnet.
+ items:
+ type: string
+ type: array
+ gateways:
+ description: Names of gateways where the rule should be
+ applied.
+ items:
+ type: string
+ type: array
+ port:
+ description: Specifies the port on the host that is being
+ addressed.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ sourceLabels:
+ additionalProperties:
+ type: string
+ description: One or more labels that constrain the applicability
+ of a rule to workloads with the given labels.
+ type: object
+ sourceNamespace:
+ description: Source namespace constraining the applicability
+ of a rule to workloads in that namespace.
+ type: string
+ sourceSubnet:
+ type: string
+ type: object
+ type: array
+ route:
+ description: The destination to which the connection should
+ be forwarded to.
+ items:
+ properties:
+ destination:
+ description: Destination uniquely identifies the instances
+ of a service to which the request/connection should
+ be forwarded to.
+ properties:
+ host:
+ description: The name of a service from the service
+ registry.
+ type: string
+ port:
+ description: Specifies the port on the host that is
+ being addressed.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ subset:
+ description: The name of a subset within the service.
+ type: string
+ required:
+ - host
+ type: object
+ weight:
+ description: Weight specifies the relative proportion
+ of traffic to be forwarded to the destination.
+ format: int32
+ type: integer
+ required:
+ - destination
+ type: object
+ type: array
+ type: object
+ type: array
+ tls:
+ description: An ordered list of route rule for non-terminated TLS
+ & HTTPS traffic.
+ items:
+ properties:
+ match:
+ description: Match conditions to be satisfied for the rule to
+ be activated.
+ items:
+ properties:
+ destinationSubnets:
+ description: IPv4 or IPv6 ip addresses of destination
+ with optional subnet.
+ items:
+ type: string
+ type: array
+ gateways:
+ description: Names of gateways where the rule should be
+ applied.
+ items:
+ type: string
+ type: array
+ port:
+ description: Specifies the port on the host that is being
+ addressed.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ sniHosts:
+ description: SNI (server name indicator) to match on.
+ items:
+ type: string
+ type: array
+ sourceLabels:
+ additionalProperties:
+ type: string
+ description: One or more labels that constrain the applicability
+ of a rule to workloads with the given labels.
+ type: object
+ sourceNamespace:
+ description: Source namespace constraining the applicability
+ of a rule to workloads in that namespace.
+ type: string
+ required:
+ - sniHosts
+ type: object
+ type: array
+ route:
+ description: The destination to which the connection should
+ be forwarded to.
+ items:
+ properties:
+ destination:
+ description: Destination uniquely identifies the instances
+ of a service to which the request/connection should
+ be forwarded to.
+ properties:
+ host:
+ description: The name of a service from the service
+ registry.
+ type: string
+ port:
+ description: Specifies the port on the host that is
+ being addressed.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ subset:
+ description: The name of a subset within the service.
+ type: string
+ required:
+ - host
+ type: object
+ weight:
+ description: Weight specifies the relative proportion
+ of traffic to be forwarded to the destination.
+ format: int32
+ type: integer
+ required:
+ - destination
+ type: object
+ type: array
+ required:
+ - match
+ type: object
+ type: array
+ type: object
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ type: object
+ served: true
+ storage: false
+ subresources:
+ status: {}
+ - additionalPrinterColumns:
+ - description: The names of gateways and sidecars that should apply these routes
+ jsonPath: .spec.gateways
+ name: Gateways
+ type: string
+ - description: The destination hosts to which traffic is being sent
+ jsonPath: .spec.hosts
+ name: Hosts
+ type: string
+ - description: 'CreationTimestamp is a timestamp representing the server time
+ when this object was created. It is not guaranteed to be set in happens-before
+ order across separate operations. Clients may not set this value. It is represented
+ in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for
+ lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata'
+ jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1beta1
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Configuration affecting label/content routing, sni routing,
+ etc. See more details at: https://istio.io/docs/reference/config/networking/virtual-service.html'
+ properties:
+ exportTo:
+ description: A list of namespaces to which this virtual service is
+ exported.
+ items:
+ type: string
+ type: array
+ gateways:
+ description: The names of gateways and sidecars that should apply
+ these routes.
+ items:
+ type: string
+ type: array
+ hosts:
+ description: The destination hosts to which traffic is being sent.
+ items:
+ type: string
+ type: array
+ http:
+ description: An ordered list of route rules for HTTP traffic.
+ items:
+ properties:
+ corsPolicy:
+ description: Cross-Origin Resource Sharing policy (CORS).
+ properties:
+ allowCredentials:
+ description: Indicates whether the caller is allowed to
+ send the actual request (not the preflight) using credentials.
+ nullable: true
+ type: boolean
+ allowHeaders:
+ description: List of HTTP headers that can be used when
+ requesting the resource.
+ items:
+ type: string
+ type: array
+ allowMethods:
+ description: List of HTTP methods allowed to access the
+ resource.
+ items:
+ type: string
+ type: array
+ allowOrigin:
+ items:
+ type: string
+ type: array
+ allowOrigins:
+ description: String patterns that match allowed origins.
+ items:
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ type: array
+ exposeHeaders:
+ description: A list of HTTP headers that the browsers are
+ allowed to access.
+ items:
+ type: string
+ type: array
+ maxAge:
+ description: Specifies how long the results of a preflight
+ request can be cached.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ unmatchedPreflights:
+ description: |-
+ Indicates whether preflight requests not matching the configured allowed origin shouldn't be forwarded to the upstream.
+
+ Valid Options: FORWARD, IGNORE
+ enum:
+ - UNSPECIFIED
+ - FORWARD
+ - IGNORE
+ type: string
+ type: object
+ delegate:
+ description: Delegate is used to specify the particular VirtualService
+ which can be used to define delegate HTTPRoute.
+ properties:
+ name:
+ description: Name specifies the name of the delegate VirtualService.
+ type: string
+ namespace:
+ description: Namespace specifies the namespace where the
+ delegate VirtualService resides.
+ type: string
+ type: object
+ directResponse:
+ description: A HTTP rule can either return a direct_response,
+ redirect or forward (default) traffic.
+ properties:
+ body:
+ description: Specifies the content of the response body.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - string
+ - required:
+ - bytes
+ - required:
+ - string
+ - required:
+ - bytes
+ properties:
+ bytes:
+ description: response body as base64 encoded bytes.
+ format: byte
+ type: string
+ string:
+ type: string
+ type: object
+ status:
+ description: Specifies the HTTP response status to be returned.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ required:
+ - status
+ type: object
+ fault:
+ description: Fault injection policy to apply on HTTP traffic
+ at the client side.
+ properties:
+ abort:
+ description: Abort Http request attempts and return error
+ codes back to downstream service, giving the impression
+ that the upstream service is faulty.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - httpStatus
+ - required:
+ - grpcStatus
+ - required:
+ - http2Error
+ - required:
+ - httpStatus
+ - required:
+ - grpcStatus
+ - required:
+ - http2Error
+ properties:
+ grpcStatus:
+ description: GRPC status code to use to abort the request.
+ type: string
+ http2Error:
+ type: string
+ httpStatus:
+ description: HTTP status code to use to abort the Http
+ request.
+ format: int32
+ type: integer
+ percentage:
+ description: Percentage of requests to be aborted with
+ the error code provided.
+ properties:
+ value:
+ format: double
+ type: number
+ type: object
+ type: object
+ delay:
+ description: Delay requests before forwarding, emulating
+ various failures such as network issues, overloaded upstream
+ service, etc.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - fixedDelay
+ - required:
+ - exponentialDelay
+ - required:
+ - fixedDelay
+ - required:
+ - exponentialDelay
+ properties:
+ exponentialDelay:
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ fixedDelay:
+ description: Add a fixed delay before forwarding the
+ request.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ percent:
+ description: Percentage of requests on which the delay
+ will be injected (0-100).
+ format: int32
+ type: integer
+ percentage:
+ description: Percentage of requests on which the delay
+ will be injected.
+ properties:
+ value:
+ format: double
+ type: number
+ type: object
+ type: object
+ type: object
+ headers:
+ properties:
+ request:
+ properties:
+ add:
+ additionalProperties:
+ type: string
+ type: object
+ remove:
+ items:
+ type: string
+ type: array
+ set:
+ additionalProperties:
+ type: string
+ type: object
+ type: object
+ response:
+ properties:
+ add:
+ additionalProperties:
+ type: string
+ type: object
+ remove:
+ items:
+ type: string
+ type: array
+ set:
+ additionalProperties:
+ type: string
+ type: object
+ type: object
+ type: object
+ match:
+ description: Match conditions to be satisfied for the rule to
+ be activated.
+ items:
+ properties:
+ authority:
+ description: 'HTTP Authority values are case-sensitive
+ and formatted as follows: - `exact: "value"` for exact
+ string match - `prefix: "value"` for prefix-based match
+ - `regex: "value"` for [RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ gateways:
+ description: Names of gateways where the rule should be
+ applied.
+ items:
+ type: string
+ type: array
+ headers:
+ additionalProperties:
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ description: The header keys must be lowercase and use
+ hyphen as the separator, e.g.
+ type: object
+ ignoreUriCase:
+ description: Flag to specify whether the URI matching
+ should be case-insensitive.
+ type: boolean
+ method:
+ description: 'HTTP Method values are case-sensitive and
+ formatted as follows: - `exact: "value"` for exact string
+ match - `prefix: "value"` for prefix-based match - `regex:
+ "value"` for [RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ name:
+ description: The name assigned to a match.
+ type: string
+ port:
+ description: Specifies the ports on the host that is being
+ addressed.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ queryParams:
+ additionalProperties:
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ description: Query parameters for matching.
+ type: object
+ scheme:
+ description: 'URI Scheme values are case-sensitive and
+ formatted as follows: - `exact: "value"` for exact string
+ match - `prefix: "value"` for prefix-based match - `regex:
+ "value"` for [RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ sourceLabels:
+ additionalProperties:
+ type: string
+ description: One or more labels that constrain the applicability
+ of a rule to source (client) workloads with the given
+ labels.
+ type: object
+ sourceNamespace:
+ description: Source namespace constraining the applicability
+ of a rule to workloads in that namespace.
+ type: string
+ statPrefix:
+ description: The human readable prefix to use when emitting
+ statistics for this route.
+ type: string
+ uri:
+ description: 'URI to match values are case-sensitive and
+ formatted as follows: - `exact: "value"` for exact string
+ match - `prefix: "value"` for prefix-based match - `regex:
+ "value"` for [RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ withoutHeaders:
+ additionalProperties:
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ - required:
+ - exact
+ - required:
+ - prefix
+ - required:
+ - regex
+ properties:
+ exact:
+ type: string
+ prefix:
+ type: string
+ regex:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ type: object
+ description: withoutHeader has the same syntax with the
+ header, but has opposite meaning.
+ type: object
+ type: object
+ type: array
+ mirror:
+ description: Mirror HTTP traffic to a another destination in
+ addition to forwarding the requests to the intended destination.
+ properties:
+ host:
+ description: The name of a service from the service registry.
+ type: string
+ port:
+ description: Specifies the port on the host that is being
+ addressed.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ subset:
+ description: The name of a subset within the service.
+ type: string
+ required:
+ - host
+ type: object
+ mirror_percent:
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ mirrorPercent:
+ maximum: 4294967295
+ minimum: 0
+ nullable: true
+ type: integer
+ mirrorPercentage:
+ description: Percentage of the traffic to be mirrored by the
+ `mirror` field.
+ properties:
+ value:
+ format: double
+ type: number
+ type: object
+ mirrors:
+ description: Specifies the destinations to mirror HTTP traffic
+ in addition to the original destination.
+ items:
+ properties:
+ destination:
+ description: Destination specifies the target of the mirror
+ operation.
+ properties:
+ host:
+ description: The name of a service from the service
+ registry.
+ type: string
+ port:
+ description: Specifies the port on the host that is
+ being addressed.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ subset:
+ description: The name of a subset within the service.
+ type: string
+ required:
+ - host
+ type: object
+ percentage:
+ description: Percentage of the traffic to be mirrored
+ by the `destination` field.
+ properties:
+ value:
+ format: double
+ type: number
+ type: object
+ required:
+ - destination
+ type: object
+ type: array
+ name:
+ description: The name assigned to the route for debugging purposes.
+ type: string
+ redirect:
+ description: A HTTP rule can either return a direct_response,
+ redirect or forward (default) traffic.
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - port
+ - required:
+ - derivePort
+ - required:
+ - port
+ - required:
+ - derivePort
+ properties:
+ authority:
+ description: On a redirect, overwrite the Authority/Host
+ portion of the URL with this value.
+ type: string
+ derivePort:
+ description: |-
+ On a redirect, dynamically set the port: * FROM_PROTOCOL_DEFAULT: automatically set to 80 for HTTP and 443 for HTTPS.
+
+ Valid Options: FROM_PROTOCOL_DEFAULT, FROM_REQUEST_PORT
+ enum:
+ - FROM_PROTOCOL_DEFAULT
+ - FROM_REQUEST_PORT
+ type: string
+ port:
+ description: On a redirect, overwrite the port portion of
+ the URL with this value.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ redirectCode:
+ description: On a redirect, Specifies the HTTP status code
+ to use in the redirect response.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ scheme:
+ description: On a redirect, overwrite the scheme portion
+ of the URL with this value.
+ type: string
+ uri:
+ description: On a redirect, overwrite the Path portion of
+ the URL with this value.
+ type: string
+ type: object
+ retries:
+ description: Retry policy for HTTP requests.
+ properties:
+ attempts:
+ description: Number of retries to be allowed for a given
+ request.
+ format: int32
+ type: integer
+ backoff:
+ description: Specifies the minimum duration between retry
+ attempts.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ perTryTimeout:
+ description: Timeout per attempt for a given request, including
+ the initial call and any retries.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ retryIgnorePreviousHosts:
+ description: Flag to specify whether the retries should
+ ignore previously tried hosts during retry.
+ nullable: true
+ type: boolean
+ retryOn:
+ description: Specifies the conditions under which retry
+ takes place.
+ type: string
+ retryRemoteLocalities:
+ description: Flag to specify whether the retries should
+ retry to other localities.
+ nullable: true
+ type: boolean
+ type: object
+ rewrite:
+ description: Rewrite HTTP URIs and Authority headers.
+ properties:
+ authority:
+ description: rewrite the Authority/Host header with this
+ value.
+ type: string
+ uri:
+ description: rewrite the path (or the prefix) portion of
+ the URI with this value.
+ type: string
+ uriRegexRewrite:
+ description: rewrite the path portion of the URI with the
+ specified regex.
+ properties:
+ match:
+ description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).'
+ type: string
+ rewrite:
+ description: The string that should replace into matching
+ portions of original URI.
+ type: string
+ type: object
+ type: object
+ route:
+ description: A HTTP rule can either return a direct_response,
+ redirect or forward (default) traffic.
+ items:
+ properties:
+ destination:
+ description: Destination uniquely identifies the instances
+ of a service to which the request/connection should
+ be forwarded to.
+ properties:
+ host:
+ description: The name of a service from the service
+ registry.
+ type: string
+ port:
+ description: Specifies the port on the host that is
+ being addressed.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ subset:
+ description: The name of a subset within the service.
+ type: string
+ required:
+ - host
+ type: object
+ headers:
+ properties:
+ request:
+ properties:
+ add:
+ additionalProperties:
+ type: string
+ type: object
+ remove:
+ items:
+ type: string
+ type: array
+ set:
+ additionalProperties:
+ type: string
+ type: object
+ type: object
+ response:
+ properties:
+ add:
+ additionalProperties:
+ type: string
+ type: object
+ remove:
+ items:
+ type: string
+ type: array
+ set:
+ additionalProperties:
+ type: string
+ type: object
+ type: object
+ type: object
+ weight:
+ description: Weight specifies the relative proportion
+ of traffic to be forwarded to the destination.
+ format: int32
+ type: integer
+ required:
+ - destination
+ type: object
+ type: array
+ timeout:
+ description: Timeout for HTTP requests, default is disabled.
+ type: string
+ x-kubernetes-validations:
+ - message: must be a valid duration greater than 1ms
+ rule: duration(self) >= duration('1ms')
+ type: object
+ type: array
+ tcp:
+ description: An ordered list of route rules for opaque TCP traffic.
+ items:
+ properties:
+ match:
+ description: Match conditions to be satisfied for the rule to
+ be activated.
+ items:
+ properties:
+ destinationSubnets:
+ description: IPv4 or IPv6 ip addresses of destination
+ with optional subnet.
+ items:
+ type: string
+ type: array
+ gateways:
+ description: Names of gateways where the rule should be
+ applied.
+ items:
+ type: string
+ type: array
+ port:
+ description: Specifies the port on the host that is being
+ addressed.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ sourceLabels:
+ additionalProperties:
+ type: string
+ description: One or more labels that constrain the applicability
+ of a rule to workloads with the given labels.
+ type: object
+ sourceNamespace:
+ description: Source namespace constraining the applicability
+ of a rule to workloads in that namespace.
+ type: string
+ sourceSubnet:
+ type: string
+ type: object
+ type: array
+ route:
+ description: The destination to which the connection should
+ be forwarded to.
+ items:
+ properties:
+ destination:
+ description: Destination uniquely identifies the instances
+ of a service to which the request/connection should
+ be forwarded to.
+ properties:
+ host:
+ description: The name of a service from the service
+ registry.
+ type: string
+ port:
+ description: Specifies the port on the host that is
+ being addressed.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ subset:
+ description: The name of a subset within the service.
+ type: string
+ required:
+ - host
+ type: object
+ weight:
+ description: Weight specifies the relative proportion
+ of traffic to be forwarded to the destination.
+ format: int32
+ type: integer
+ required:
+ - destination
+ type: object
+ type: array
+ type: object
+ type: array
+ tls:
+ description: An ordered list of route rule for non-terminated TLS
+ & HTTPS traffic.
+ items:
+ properties:
+ match:
+ description: Match conditions to be satisfied for the rule to
+ be activated.
+ items:
+ properties:
+ destinationSubnets:
+ description: IPv4 or IPv6 ip addresses of destination
+ with optional subnet.
+ items:
+ type: string
+ type: array
+ gateways:
+ description: Names of gateways where the rule should be
+ applied.
+ items:
+ type: string
+ type: array
+ port:
+ description: Specifies the port on the host that is being
+ addressed.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ sniHosts:
+ description: SNI (server name indicator) to match on.
+ items:
+ type: string
+ type: array
+ sourceLabels:
+ additionalProperties:
+ type: string
+ description: One or more labels that constrain the applicability
+ of a rule to workloads with the given labels.
+ type: object
+ sourceNamespace:
+ description: Source namespace constraining the applicability
+ of a rule to workloads in that namespace.
+ type: string
+ required:
+ - sniHosts
+ type: object
+ type: array
+ route:
+ description: The destination to which the connection should
+ be forwarded to.
+ items:
+ properties:
+ destination:
+ description: Destination uniquely identifies the instances
+ of a service to which the request/connection should
+ be forwarded to.
+ properties:
+ host:
+ description: The name of a service from the service
+ registry.
+ type: string
+ port:
+ description: Specifies the port on the host that is
+ being addressed.
+ properties:
+ number:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ subset:
+ description: The name of a subset within the service.
+ type: string
+ required:
+ - host
+ type: object
+ weight:
+ description: Weight specifies the relative proportion
+ of traffic to be forwarded to the destination.
+ format: int32
+ type: integer
+ required:
+ - destination
+ type: object
+ type: array
+ required:
+ - match
+ type: object
+ type: array
+ type: object
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ type: object
+ served: true
+ storage: false
+ subresources:
+ status: {}
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_workloadentries.yaml b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_workloadentries.yaml
new file mode 100644
index 0000000000..4e254f3683
--- /dev/null
+++ b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_workloadentries.yaml
@@ -0,0 +1,505 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ "helm.sh/resource-policy": keep
+ labels:
+ app: istio-pilot
+ chart: istio
+ heritage: Tiller
+ release: istio
+ name: workloadentries.networking.istio.io
+spec:
+ group: networking.istio.io
+ names:
+ categories:
+ - istio-io
+ - networking-istio-io
+ kind: WorkloadEntry
+ listKind: WorkloadEntryList
+ plural: workloadentries
+ shortNames:
+ - we
+ singular: workloadentry
+ scope: Namespaced
+ versions:
+ - additionalPrinterColumns:
+ - description: 'CreationTimestamp is a timestamp representing the server time
+ when this object was created. It is not guaranteed to be set in happens-before
+ order across separate operations. Clients may not set this value. It is represented
+ in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for
+ lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata'
+ jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ - description: Address associated with the network endpoint.
+ jsonPath: .spec.address
+ name: Address
+ type: string
+ name: v1
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Configuration affecting VMs onboarded into the mesh. See
+ more details at: https://istio.io/docs/reference/config/networking/workload-entry.html'
+ properties:
+ address:
+ description: Address associated with the network endpoint without
+ the port.
+ maxLength: 256
+ type: string
+ x-kubernetes-validations:
+ - message: UDS must be an absolute path or abstract socket
+ rule: 'self.startsWith("unix://") ? (self.substring(7, 8) == "/"
+ || self.substring(7, 8) == "@") : true'
+ - message: UDS may not be a dir
+ rule: 'self.startsWith("unix://") ? !self.endsWith("/") : true'
+ labels:
+ additionalProperties:
+ type: string
+ description: One or more labels associated with the endpoint.
+ maxProperties: 256
+ type: object
+ locality:
+ description: The locality associated with the endpoint.
+ maxLength: 2048
+ type: string
+ network:
+ description: Network enables Istio to group endpoints resident in
+ the same L3 domain/network.
+ maxLength: 2048
+ type: string
+ ports:
+ additionalProperties:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ description: Set of ports associated with the endpoint.
+ maxProperties: 128
+ type: object
+ x-kubernetes-validations:
+ - message: port name must be valid
+ rule: self.all(key, size(key) < 63 && key.matches("^[a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?$"))
+ serviceAccount:
+ description: The service account associated with the workload if a
+ sidecar is present in the workload.
+ maxLength: 253
+ type: string
+ weight:
+ description: The load balancing weight associated with the endpoint.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ x-kubernetes-validations:
+ - message: Address is required
+ rule: has(self.address) || has(self.network)
+ - message: UDS may not include ports
+ rule: '(has(self.address) ? self.address : "").startsWith("unix://")
+ ? !has(self.ports) : true'
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - spec
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
+ - additionalPrinterColumns:
+ - description: 'CreationTimestamp is a timestamp representing the server time
+ when this object was created. It is not guaranteed to be set in happens-before
+ order across separate operations. Clients may not set this value. It is represented
+ in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for
+ lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata'
+ jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ - description: Address associated with the network endpoint.
+ jsonPath: .spec.address
+ name: Address
+ type: string
+ name: v1alpha3
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Configuration affecting VMs onboarded into the mesh. See
+ more details at: https://istio.io/docs/reference/config/networking/workload-entry.html'
+ properties:
+ address:
+ description: Address associated with the network endpoint without
+ the port.
+ maxLength: 256
+ type: string
+ x-kubernetes-validations:
+ - message: UDS must be an absolute path or abstract socket
+ rule: 'self.startsWith("unix://") ? (self.substring(7, 8) == "/"
+ || self.substring(7, 8) == "@") : true'
+ - message: UDS may not be a dir
+ rule: 'self.startsWith("unix://") ? !self.endsWith("/") : true'
+ labels:
+ additionalProperties:
+ type: string
+ description: One or more labels associated with the endpoint.
+ maxProperties: 256
+ type: object
+ locality:
+ description: The locality associated with the endpoint.
+ maxLength: 2048
+ type: string
+ network:
+ description: Network enables Istio to group endpoints resident in
+ the same L3 domain/network.
+ maxLength: 2048
+ type: string
+ ports:
+ additionalProperties:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ description: Set of ports associated with the endpoint.
+ maxProperties: 128
+ type: object
+ x-kubernetes-validations:
+ - message: port name must be valid
+ rule: self.all(key, size(key) < 63 && key.matches("^[a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?$"))
+ serviceAccount:
+ description: The service account associated with the workload if a
+ sidecar is present in the workload.
+ maxLength: 253
+ type: string
+ weight:
+ description: The load balancing weight associated with the endpoint.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ x-kubernetes-validations:
+ - message: Address is required
+ rule: has(self.address) || has(self.network)
+ - message: UDS may not include ports
+ rule: '(has(self.address) ? self.address : "").startsWith("unix://")
+ ? !has(self.ports) : true'
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - spec
+ type: object
+ served: true
+ storage: false
+ subresources:
+ status: {}
+ - additionalPrinterColumns:
+ - description: 'CreationTimestamp is a timestamp representing the server time
+ when this object was created. It is not guaranteed to be set in happens-before
+ order across separate operations. Clients may not set this value. It is represented
+ in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for
+ lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata'
+ jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ - description: Address associated with the network endpoint.
+ jsonPath: .spec.address
+ name: Address
+ type: string
+ name: v1beta1
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Configuration affecting VMs onboarded into the mesh. See
+ more details at: https://istio.io/docs/reference/config/networking/workload-entry.html'
+ properties:
+ address:
+ description: Address associated with the network endpoint without
+ the port.
+ maxLength: 256
+ type: string
+ x-kubernetes-validations:
+ - message: UDS must be an absolute path or abstract socket
+ rule: 'self.startsWith("unix://") ? (self.substring(7, 8) == "/"
+ || self.substring(7, 8) == "@") : true'
+ - message: UDS may not be a dir
+ rule: 'self.startsWith("unix://") ? !self.endsWith("/") : true'
+ labels:
+ additionalProperties:
+ type: string
+ description: One or more labels associated with the endpoint.
+ maxProperties: 256
+ type: object
+ locality:
+ description: The locality associated with the endpoint.
+ maxLength: 2048
+ type: string
+ network:
+ description: Network enables Istio to group endpoints resident in
+ the same L3 domain/network.
+ maxLength: 2048
+ type: string
+ ports:
+ additionalProperties:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ description: Set of ports associated with the endpoint.
+ maxProperties: 128
+ type: object
+ x-kubernetes-validations:
+ - message: port name must be valid
+ rule: self.all(key, size(key) < 63 && key.matches("^[a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?$"))
+ serviceAccount:
+ description: The service account associated with the workload if a
+ sidecar is present in the workload.
+ maxLength: 253
+ type: string
+ weight:
+ description: The load balancing weight associated with the endpoint.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ x-kubernetes-validations:
+ - message: Address is required
+ rule: has(self.address) || has(self.network)
+ - message: UDS may not include ports
+ rule: '(has(self.address) ? self.address : "").startsWith("unix://")
+ ? !has(self.ports) : true'
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - spec
+ type: object
+ served: true
+ storage: false
+ subresources:
+ status: {}
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_workloadgroups.yaml b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_workloadgroups.yaml
new file mode 100644
index 0000000000..c1e02618f9
--- /dev/null
+++ b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/networking.istio.io_workloadgroups.yaml
@@ -0,0 +1,949 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ "helm.sh/resource-policy": keep
+ labels:
+ app: istio-pilot
+ chart: istio
+ heritage: Tiller
+ release: istio
+ name: workloadgroups.networking.istio.io
+spec:
+ group: networking.istio.io
+ names:
+ categories:
+ - istio-io
+ - networking-istio-io
+ kind: WorkloadGroup
+ listKind: WorkloadGroupList
+ plural: workloadgroups
+ shortNames:
+ - wg
+ singular: workloadgroup
+ scope: Namespaced
+ versions:
+ - additionalPrinterColumns:
+ - description: 'CreationTimestamp is a timestamp representing the server time
+ when this object was created. It is not guaranteed to be set in happens-before
+ order across separate operations. Clients may not set this value. It is represented
+ in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for
+ lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata'
+ jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Describes a collection of workload instances. See more details
+ at: https://istio.io/docs/reference/config/networking/workload-group.html'
+ properties:
+ metadata:
+ description: Metadata that will be used for all corresponding `WorkloadEntries`.
+ properties:
+ annotations:
+ additionalProperties:
+ type: string
+ maxProperties: 256
+ type: object
+ labels:
+ additionalProperties:
+ type: string
+ maxProperties: 256
+ type: object
+ type: object
+ probe:
+ description: '`ReadinessProbe` describes the configuration the user
+ must provide for healthchecking on their workload.'
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - httpGet
+ - required:
+ - tcpSocket
+ - required:
+ - exec
+ - required:
+ - grpc
+ - required:
+ - httpGet
+ - required:
+ - tcpSocket
+ - required:
+ - exec
+ - required:
+ - grpc
+ properties:
+ exec:
+ description: Health is determined by how the command that is executed
+ exited.
+ properties:
+ command:
+ description: Command to run.
+ items:
+ minLength: 1
+ type: string
+ type: array
+ required:
+ - command
+ type: object
+ failureThreshold:
+ description: Minimum consecutive failures for the probe to be
+ considered failed after having succeeded.
+ format: int32
+ minimum: 0
+ type: integer
+ grpc:
+ description: GRPC call is made and response/error is used to determine
+ health.
+ properties:
+ port:
+ description: Port on which the endpoint lives.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ service:
+ type: string
+ type: object
+ httpGet:
+ description: '`httpGet` is performed to a given endpoint and the
+ status/able to connect determines health.'
+ properties:
+ host:
+ description: Host name to connect to, defaults to the pod
+ IP.
+ type: string
+ httpHeaders:
+ description: Headers the proxy will pass on to make the request.
+ items:
+ properties:
+ name:
+ pattern: ^[-_A-Za-z0-9]+$
+ type: string
+ value:
+ type: string
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ description: Port on which the endpoint lives.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ scheme:
+ type: string
+ x-kubernetes-validations:
+ - message: scheme must be one of [HTTP, HTTPS]
+ rule: self in ["", "HTTP", "HTTPS"]
+ required:
+ - port
+ type: object
+ initialDelaySeconds:
+ description: Number of seconds after the container has started
+ before readiness probes are initiated.
+ format: int32
+ minimum: 0
+ type: integer
+ periodSeconds:
+ description: How often (in seconds) to perform the probe.
+ format: int32
+ minimum: 0
+ type: integer
+ successThreshold:
+ description: Minimum consecutive successes for the probe to be
+ considered successful after having failed.
+ format: int32
+ minimum: 0
+ type: integer
+ tcpSocket:
+ description: Health is determined by if the proxy is able to connect.
+ properties:
+ host:
+ type: string
+ port:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ required:
+ - port
+ type: object
+ timeoutSeconds:
+ description: Number of seconds after which the probe times out.
+ format: int32
+ minimum: 0
+ type: integer
+ type: object
+ template:
+ description: Template to be used for the generation of `WorkloadEntry`
+ resources that belong to this `WorkloadGroup`.
+ properties:
+ address:
+ description: Address associated with the network endpoint without
+ the port.
+ maxLength: 256
+ type: string
+ x-kubernetes-validations:
+ - message: UDS must be an absolute path or abstract socket
+ rule: 'self.startsWith("unix://") ? (self.substring(7, 8) ==
+ "/" || self.substring(7, 8) == "@") : true'
+ - message: UDS may not be a dir
+ rule: 'self.startsWith("unix://") ? !self.endsWith("/") : true'
+ labels:
+ additionalProperties:
+ type: string
+ description: One or more labels associated with the endpoint.
+ maxProperties: 256
+ type: object
+ locality:
+ description: The locality associated with the endpoint.
+ maxLength: 2048
+ type: string
+ network:
+ description: Network enables Istio to group endpoints resident
+ in the same L3 domain/network.
+ maxLength: 2048
+ type: string
+ ports:
+ additionalProperties:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ description: Set of ports associated with the endpoint.
+ maxProperties: 128
+ type: object
+ x-kubernetes-validations:
+ - message: port name must be valid
+ rule: self.all(key, size(key) < 63 && key.matches("^[a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?$"))
+ serviceAccount:
+ description: The service account associated with the workload
+ if a sidecar is present in the workload.
+ maxLength: 253
+ type: string
+ weight:
+ description: The load balancing weight associated with the endpoint.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ x-kubernetes-validations:
+ - message: UDS may not include ports
+ rule: '(has(self.address) ? self.address : "").startsWith("unix://")
+ ? !has(self.ports) : true'
+ required:
+ - template
+ type: object
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - spec
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
+ - additionalPrinterColumns:
+ - description: 'CreationTimestamp is a timestamp representing the server time
+ when this object was created. It is not guaranteed to be set in happens-before
+ order across separate operations. Clients may not set this value. It is represented
+ in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for
+ lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata'
+ jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1alpha3
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Describes a collection of workload instances. See more details
+ at: https://istio.io/docs/reference/config/networking/workload-group.html'
+ properties:
+ metadata:
+ description: Metadata that will be used for all corresponding `WorkloadEntries`.
+ properties:
+ annotations:
+ additionalProperties:
+ type: string
+ maxProperties: 256
+ type: object
+ labels:
+ additionalProperties:
+ type: string
+ maxProperties: 256
+ type: object
+ type: object
+ probe:
+ description: '`ReadinessProbe` describes the configuration the user
+ must provide for healthchecking on their workload.'
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - httpGet
+ - required:
+ - tcpSocket
+ - required:
+ - exec
+ - required:
+ - grpc
+ - required:
+ - httpGet
+ - required:
+ - tcpSocket
+ - required:
+ - exec
+ - required:
+ - grpc
+ properties:
+ exec:
+ description: Health is determined by how the command that is executed
+ exited.
+ properties:
+ command:
+ description: Command to run.
+ items:
+ minLength: 1
+ type: string
+ type: array
+ required:
+ - command
+ type: object
+ failureThreshold:
+ description: Minimum consecutive failures for the probe to be
+ considered failed after having succeeded.
+ format: int32
+ minimum: 0
+ type: integer
+ grpc:
+ description: GRPC call is made and response/error is used to determine
+ health.
+ properties:
+ port:
+ description: Port on which the endpoint lives.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ service:
+ type: string
+ type: object
+ httpGet:
+ description: '`httpGet` is performed to a given endpoint and the
+ status/able to connect determines health.'
+ properties:
+ host:
+ description: Host name to connect to, defaults to the pod
+ IP.
+ type: string
+ httpHeaders:
+ description: Headers the proxy will pass on to make the request.
+ items:
+ properties:
+ name:
+ pattern: ^[-_A-Za-z0-9]+$
+ type: string
+ value:
+ type: string
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ description: Port on which the endpoint lives.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ scheme:
+ type: string
+ x-kubernetes-validations:
+ - message: scheme must be one of [HTTP, HTTPS]
+ rule: self in ["", "HTTP", "HTTPS"]
+ required:
+ - port
+ type: object
+ initialDelaySeconds:
+ description: Number of seconds after the container has started
+ before readiness probes are initiated.
+ format: int32
+ minimum: 0
+ type: integer
+ periodSeconds:
+ description: How often (in seconds) to perform the probe.
+ format: int32
+ minimum: 0
+ type: integer
+ successThreshold:
+ description: Minimum consecutive successes for the probe to be
+ considered successful after having failed.
+ format: int32
+ minimum: 0
+ type: integer
+ tcpSocket:
+ description: Health is determined by if the proxy is able to connect.
+ properties:
+ host:
+ type: string
+ port:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ required:
+ - port
+ type: object
+ timeoutSeconds:
+ description: Number of seconds after which the probe times out.
+ format: int32
+ minimum: 0
+ type: integer
+ type: object
+ template:
+ description: Template to be used for the generation of `WorkloadEntry`
+ resources that belong to this `WorkloadGroup`.
+ properties:
+ address:
+ description: Address associated with the network endpoint without
+ the port.
+ maxLength: 256
+ type: string
+ x-kubernetes-validations:
+ - message: UDS must be an absolute path or abstract socket
+ rule: 'self.startsWith("unix://") ? (self.substring(7, 8) ==
+ "/" || self.substring(7, 8) == "@") : true'
+ - message: UDS may not be a dir
+ rule: 'self.startsWith("unix://") ? !self.endsWith("/") : true'
+ labels:
+ additionalProperties:
+ type: string
+ description: One or more labels associated with the endpoint.
+ maxProperties: 256
+ type: object
+ locality:
+ description: The locality associated with the endpoint.
+ maxLength: 2048
+ type: string
+ network:
+ description: Network enables Istio to group endpoints resident
+ in the same L3 domain/network.
+ maxLength: 2048
+ type: string
+ ports:
+ additionalProperties:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ description: Set of ports associated with the endpoint.
+ maxProperties: 128
+ type: object
+ x-kubernetes-validations:
+ - message: port name must be valid
+ rule: self.all(key, size(key) < 63 && key.matches("^[a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?$"))
+ serviceAccount:
+ description: The service account associated with the workload
+ if a sidecar is present in the workload.
+ maxLength: 253
+ type: string
+ weight:
+ description: The load balancing weight associated with the endpoint.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ x-kubernetes-validations:
+ - message: UDS may not include ports
+ rule: '(has(self.address) ? self.address : "").startsWith("unix://")
+ ? !has(self.ports) : true'
+ required:
+ - template
+ type: object
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - spec
+ type: object
+ served: true
+ storage: false
+ subresources:
+ status: {}
+ - additionalPrinterColumns:
+ - description: 'CreationTimestamp is a timestamp representing the server time
+ when this object was created. It is not guaranteed to be set in happens-before
+ order across separate operations. Clients may not set this value. It is represented
+ in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for
+ lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata'
+ jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1beta1
+ schema:
+ openAPIV3Schema:
+ properties:
+ spec:
+ description: 'Describes a collection of workload instances. See more details
+ at: https://istio.io/docs/reference/config/networking/workload-group.html'
+ properties:
+ metadata:
+ description: Metadata that will be used for all corresponding `WorkloadEntries`.
+ properties:
+ annotations:
+ additionalProperties:
+ type: string
+ maxProperties: 256
+ type: object
+ labels:
+ additionalProperties:
+ type: string
+ maxProperties: 256
+ type: object
+ type: object
+ probe:
+ description: '`ReadinessProbe` describes the configuration the user
+ must provide for healthchecking on their workload.'
+ oneOf:
+ - not:
+ anyOf:
+ - required:
+ - httpGet
+ - required:
+ - tcpSocket
+ - required:
+ - exec
+ - required:
+ - grpc
+ - required:
+ - httpGet
+ - required:
+ - tcpSocket
+ - required:
+ - exec
+ - required:
+ - grpc
+ properties:
+ exec:
+ description: Health is determined by how the command that is executed
+ exited.
+ properties:
+ command:
+ description: Command to run.
+ items:
+ minLength: 1
+ type: string
+ type: array
+ required:
+ - command
+ type: object
+ failureThreshold:
+ description: Minimum consecutive failures for the probe to be
+ considered failed after having succeeded.
+ format: int32
+ minimum: 0
+ type: integer
+ grpc:
+ description: GRPC call is made and response/error is used to determine
+ health.
+ properties:
+ port:
+ description: Port on which the endpoint lives.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ service:
+ type: string
+ type: object
+ httpGet:
+ description: '`httpGet` is performed to a given endpoint and the
+ status/able to connect determines health.'
+ properties:
+ host:
+ description: Host name to connect to, defaults to the pod
+ IP.
+ type: string
+ httpHeaders:
+ description: Headers the proxy will pass on to make the request.
+ items:
+ properties:
+ name:
+ pattern: ^[-_A-Za-z0-9]+$
+ type: string
+ value:
+ type: string
+ type: object
+ type: array
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ description: Port on which the endpoint lives.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ scheme:
+ type: string
+ x-kubernetes-validations:
+ - message: scheme must be one of [HTTP, HTTPS]
+ rule: self in ["", "HTTP", "HTTPS"]
+ required:
+ - port
+ type: object
+ initialDelaySeconds:
+ description: Number of seconds after the container has started
+ before readiness probes are initiated.
+ format: int32
+ minimum: 0
+ type: integer
+ periodSeconds:
+ description: How often (in seconds) to perform the probe.
+ format: int32
+ minimum: 0
+ type: integer
+ successThreshold:
+ description: Minimum consecutive successes for the probe to be
+ considered successful after having failed.
+ format: int32
+ minimum: 0
+ type: integer
+ tcpSocket:
+ description: Health is determined by if the proxy is able to connect.
+ properties:
+ host:
+ type: string
+ port:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ required:
+ - port
+ type: object
+ timeoutSeconds:
+ description: Number of seconds after which the probe times out.
+ format: int32
+ minimum: 0
+ type: integer
+ type: object
+ template:
+ description: Template to be used for the generation of `WorkloadEntry`
+ resources that belong to this `WorkloadGroup`.
+ properties:
+ address:
+ description: Address associated with the network endpoint without
+ the port.
+ maxLength: 256
+ type: string
+ x-kubernetes-validations:
+ - message: UDS must be an absolute path or abstract socket
+ rule: 'self.startsWith("unix://") ? (self.substring(7, 8) ==
+ "/" || self.substring(7, 8) == "@") : true'
+ - message: UDS may not be a dir
+ rule: 'self.startsWith("unix://") ? !self.endsWith("/") : true'
+ labels:
+ additionalProperties:
+ type: string
+ description: One or more labels associated with the endpoint.
+ maxProperties: 256
+ type: object
+ locality:
+ description: The locality associated with the endpoint.
+ maxLength: 2048
+ type: string
+ network:
+ description: Network enables Istio to group endpoints resident
+ in the same L3 domain/network.
+ maxLength: 2048
+ type: string
+ ports:
+ additionalProperties:
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ x-kubernetes-validations:
+ - message: port must be between 1-65535
+ rule: 0 < self && self <= 65535
+ description: Set of ports associated with the endpoint.
+ maxProperties: 128
+ type: object
+ x-kubernetes-validations:
+ - message: port name must be valid
+ rule: self.all(key, size(key) < 63 && key.matches("^[a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?$"))
+ serviceAccount:
+ description: The service account associated with the workload
+ if a sidecar is present in the workload.
+ maxLength: 253
+ type: string
+ weight:
+ description: The load balancing weight associated with the endpoint.
+ maximum: 4294967295
+ minimum: 0
+ type: integer
+ type: object
+ x-kubernetes-validations:
+ - message: UDS may not include ports
+ rule: '(has(self.address) ? self.address : "").startsWith("unix://")
+ ? !has(self.ports) : true'
+ required:
+ - template
+ type: object
+ status:
+ properties:
+ conditions:
+ description: Current service state of the resource.
+ items:
+ properties:
+ lastProbeTime:
+ description: Last time we probed the condition.
+ format: date-time
+ type: string
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ last transition.
+ type: string
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Resource Generation to which the Condition refers.
+ x-kubernetes-int-or-string: true
+ reason:
+ description: Unique, one-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: Status is the status of the condition.
+ type: string
+ type:
+ description: Type is the type of the condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ anyOf:
+ - type: integer
+ - type: string
+ x-kubernetes-int-or-string: true
+ validationMessages:
+ description: Includes any errors or warnings detected by Istio's analyzers.
+ items:
+ properties:
+ documentationUrl:
+ description: A url pointing to the Istio documentation for this
+ specific error type.
+ type: string
+ level:
+ description: |-
+ Represents how severe a message is.
+
+ Valid Options: UNKNOWN, ERROR, WARNING, INFO
+ enum:
+ - UNKNOWN
+ - ERROR
+ - WARNING
+ - INFO
+ type: string
+ type:
+ properties:
+ code:
+ description: A 7 character code matching `^IST[0-9]{4}$`
+ intended to uniquely identify the message type.
+ type: string
+ name:
+ description: A human-readable name for the message type.
+ type: string
+ type: object
+ type: object
+ type: array
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - spec
+ type: object
+ served: true
+ storage: false
+ subresources:
+ status: {}
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/sailoperator.io_istiocnis.yaml b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/sailoperator.io_istiocnis.yaml
new file mode 100644
index 0000000000..61871b3bbf
--- /dev/null
+++ b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/sailoperator.io_istiocnis.yaml
@@ -0,0 +1,1577 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.20.0
+ name: istiocnis.sailoperator.io
+spec:
+ group: sailoperator.io
+ names:
+ categories:
+ - istio-io
+ kind: IstioCNI
+ listKind: IstioCNIList
+ plural: istiocnis
+ singular: istiocni
+ scope: Cluster
+ versions:
+ - additionalPrinterColumns:
+ - description: The namespace of the istio-cni-node DaemonSet.
+ jsonPath: .spec.namespace
+ name: Namespace
+ type: string
+ - description: The selected profile (collection of value presets).
+ jsonPath: .spec.profile
+ name: Profile
+ type: string
+ - description: Whether the Istio CNI installation is ready to handle requests.
+ jsonPath: .status.conditions[?(@.type=="Ready")].status
+ name: Ready
+ type: string
+ - description: The current state of this object.
+ jsonPath: .status.state
+ name: Status
+ type: string
+ - description: The version of the Istio CNI installation.
+ jsonPath: .spec.version
+ name: Version
+ type: string
+ - description: The age of the object
+ jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1
+ schema:
+ openAPIV3Schema:
+ description: IstioCNI represents a deployment of the Istio CNI component.
+ properties:
+ apiVersion:
+ description: |-
+ APIVersion defines the versioned schema of this representation of an object.
+ Servers should convert recognized schemas to the latest internal value, and
+ may reject unrecognized values.
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
+ type: string
+ kind:
+ description: |-
+ Kind is a string value representing the REST resource this object represents.
+ Servers may infer this from the endpoint the client submits requests to.
+ Cannot be updated.
+ In CamelCase.
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
+ type: string
+ metadata:
+ type: object
+ spec:
+ default:
+ namespace: istio-cni
+ version: v1.28.3
+ description: IstioCNISpec defines the desired state of IstioCNI
+ properties:
+ namespace:
+ default: istio-cni
+ description: Namespace to which the Istio CNI component should be
+ installed. Note that this field is immutable.
+ type: string
+ x-kubernetes-validations:
+ - message: Value is immutable
+ rule: self == oldSelf
+ profile:
+ description: |-
+ The built-in installation configuration profile to use.
+ The 'default' profile is always applied. On OpenShift, the 'openshift' profile is also applied on top of 'default'.
+ Must be one of: ambient, default, demo, empty, openshift, openshift-ambient, preview, remote, stable.
+ enum:
+ - ambient
+ - default
+ - demo
+ - empty
+ - external
+ - openshift
+ - openshift-ambient
+ - preview
+ - remote
+ - stable
+ type: string
+ values:
+ description: Defines the values to be passed to the Helm charts when
+ installing Istio CNI.
+ properties:
+ cni:
+ description: Configuration for the Istio CNI plugin.
+ properties:
+ affinity:
+ description: K8s affinity to set on the istio-cni Pods. Can
+ be used to exclude istio-cni from being scheduled on specified
+ nodes.
+ properties:
+ nodeAffinity:
+ description: Describes node affinity scheduling rules
+ for the pod.
+ properties:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ The scheduler will prefer to schedule pods to nodes that satisfy
+ the affinity expressions specified by this field, but it may choose
+ a node that violates one or more of the expressions. The node that is
+ most preferred is the one with the greatest sum of weights, i.e.
+ for each node that meets all of the scheduling requirements (resource
+ request, requiredDuringScheduling affinity expressions, etc.),
+ compute a sum by iterating through the elements of this field and adding
+ "weight" to the sum if the node matches the corresponding matchExpressions; the
+ node(s) with the highest sum are the most preferred.
+ items:
+ description: |-
+ An empty preferred scheduling term matches all objects with implicit weight 0
+ (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op).
+ properties:
+ preference:
+ description: A node selector term, associated
+ with the corresponding weight.
+ properties:
+ matchExpressions:
+ description: A list of node selector requirements
+ by node's labels.
+ items:
+ description: |-
+ A node selector requirement is a selector that contains values, a key, and an operator
+ that relates the key and values.
+ properties:
+ key:
+ description: The label key that the
+ selector applies to.
+ type: string
+ operator:
+ description: |-
+ Represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
+ type: string
+ values:
+ description: |-
+ An array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. If the operator is Gt or Lt, the values
+ array must have a single element, which will be interpreted as an integer.
+ This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchFields:
+ description: A list of node selector requirements
+ by node's fields.
+ items:
+ description: |-
+ A node selector requirement is a selector that contains values, a key, and an operator
+ that relates the key and values.
+ properties:
+ key:
+ description: The label key that the
+ selector applies to.
+ type: string
+ operator:
+ description: |-
+ Represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
+ type: string
+ values:
+ description: |-
+ An array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. If the operator is Gt or Lt, the values
+ array must have a single element, which will be interpreted as an integer.
+ This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ x-kubernetes-map-type: atomic
+ weight:
+ description: Weight associated with matching
+ the corresponding nodeSelectorTerm, in the
+ range 1-100.
+ format: int32
+ type: integer
+ required:
+ - preference
+ - weight
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ requiredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ If the affinity requirements specified by this field are not met at
+ scheduling time, the pod will not be scheduled onto the node.
+ If the affinity requirements specified by this field cease to be met
+ at some point during pod execution (e.g. due to an update), the system
+ may or may not try to eventually evict the pod from its node.
+ properties:
+ nodeSelectorTerms:
+ description: Required. A list of node selector
+ terms. The terms are ORed.
+ items:
+ description: |-
+ A null or empty node selector term matches no objects. The requirements of
+ them are ANDed.
+ The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.
+ properties:
+ matchExpressions:
+ description: A list of node selector requirements
+ by node's labels.
+ items:
+ description: |-
+ A node selector requirement is a selector that contains values, a key, and an operator
+ that relates the key and values.
+ properties:
+ key:
+ description: The label key that the
+ selector applies to.
+ type: string
+ operator:
+ description: |-
+ Represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
+ type: string
+ values:
+ description: |-
+ An array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. If the operator is Gt or Lt, the values
+ array must have a single element, which will be interpreted as an integer.
+ This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchFields:
+ description: A list of node selector requirements
+ by node's fields.
+ items:
+ description: |-
+ A node selector requirement is a selector that contains values, a key, and an operator
+ that relates the key and values.
+ properties:
+ key:
+ description: The label key that the
+ selector applies to.
+ type: string
+ operator:
+ description: |-
+ Represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
+ type: string
+ values:
+ description: |-
+ An array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. If the operator is Gt or Lt, the values
+ array must have a single element, which will be interpreted as an integer.
+ This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ x-kubernetes-map-type: atomic
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - nodeSelectorTerms
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ podAffinity:
+ description: Describes pod affinity scheduling rules (e.g.
+ co-locate this pod in the same node, zone, etc. as some
+ other pod(s)).
+ properties:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ The scheduler will prefer to schedule pods to nodes that satisfy
+ the affinity expressions specified by this field, but it may choose
+ a node that violates one or more of the expressions. The node that is
+ most preferred is the one with the greatest sum of weights, i.e.
+ for each node that meets all of the scheduling requirements (resource
+ request, requiredDuringScheduling affinity expressions, etc.),
+ compute a sum by iterating through the elements of this field and adding
+ "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the
+ node(s) with the highest sum are the most preferred.
+ items:
+ description: The weights of all of the matched WeightedPodAffinityTerm
+ fields are added per-node to find the most preferred
+ node(s)
+ properties:
+ podAffinityTerm:
+ description: Required. A pod affinity term,
+ associated with the corresponding weight.
+ properties:
+ labelSelector:
+ description: |-
+ A label query over a set of resources, in this case pods.
+ If it's null, this PodAffinityTerm matches with no Pods.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The
+ requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ matchLabelKeys:
+ description: |-
+ MatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both matchLabelKeys and labelSelector.
+ Also, matchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ mismatchLabelKeys:
+ description: |-
+ MismatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
+ Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ namespaceSelector:
+ description: |-
+ A label query over the set of namespaces that the term applies to.
+ The term is applied to the union of the namespaces selected by this field
+ and the ones listed in the namespaces field.
+ null selector and null or empty namespaces list means "this pod's namespace".
+ An empty selector ({}) matches all namespaces.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The
+ requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: |-
+ namespaces specifies a static list of namespace names that the term applies to.
+ The term is applied to the union of the namespaces listed in this field
+ and the ones selected by namespaceSelector.
+ null or empty namespaces list and null namespaceSelector means "this pod's namespace".
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ topologyKey:
+ description: |-
+ This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
+ the labelSelector in the specified namespaces, where co-located is defined as running on a node
+ whose value of the label with key topologyKey matches that of any node on which any of the
+ selected pods is running.
+ Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ weight:
+ description: |-
+ weight associated with matching the corresponding podAffinityTerm,
+ in the range 1-100.
+ format: int32
+ type: integer
+ required:
+ - podAffinityTerm
+ - weight
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ requiredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ If the affinity requirements specified by this field are not met at
+ scheduling time, the pod will not be scheduled onto the node.
+ If the affinity requirements specified by this field cease to be met
+ at some point during pod execution (e.g. due to a pod label update), the
+ system may or may not try to eventually evict the pod from its node.
+ When there are multiple elements, the lists of nodes corresponding to each
+ podAffinityTerm are intersected, i.e. all terms must be satisfied.
+ items:
+ description: |-
+ Defines a set of pods (namely those matching the labelSelector
+ relative to the given namespace(s)) that this pod should be
+ co-located (affinity) or not co-located (anti-affinity) with,
+ where co-located is defined as running on a node whose value of
+ the label with key matches that of any node on which
+ a pod of the set of pods is running
+ properties:
+ labelSelector:
+ description: |-
+ A label query over a set of resources, in this case pods.
+ If it's null, this PodAffinityTerm matches with no Pods.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The requirements
+ are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label key
+ that the selector applies to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ matchLabelKeys:
+ description: |-
+ MatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both matchLabelKeys and labelSelector.
+ Also, matchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ mismatchLabelKeys:
+ description: |-
+ MismatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
+ Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ namespaceSelector:
+ description: |-
+ A label query over the set of namespaces that the term applies to.
+ The term is applied to the union of the namespaces selected by this field
+ and the ones listed in the namespaces field.
+ null selector and null or empty namespaces list means "this pod's namespace".
+ An empty selector ({}) matches all namespaces.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The requirements
+ are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label key
+ that the selector applies to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: |-
+ namespaces specifies a static list of namespace names that the term applies to.
+ The term is applied to the union of the namespaces listed in this field
+ and the ones selected by namespaceSelector.
+ null or empty namespaces list and null namespaceSelector means "this pod's namespace".
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ topologyKey:
+ description: |-
+ This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
+ the labelSelector in the specified namespaces, where co-located is defined as running on a node
+ whose value of the label with key topologyKey matches that of any node on which any of the
+ selected pods is running.
+ Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ podAntiAffinity:
+ description: Describes pod anti-affinity scheduling rules
+ (e.g. avoid putting this pod in the same node, zone,
+ etc. as some other pod(s)).
+ properties:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ The scheduler will prefer to schedule pods to nodes that satisfy
+ the anti-affinity expressions specified by this field, but it may choose
+ a node that violates one or more of the expressions. The node that is
+ most preferred is the one with the greatest sum of weights, i.e.
+ for each node that meets all of the scheduling requirements (resource
+ request, requiredDuringScheduling anti-affinity expressions, etc.),
+ compute a sum by iterating through the elements of this field and subtracting
+ "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the
+ node(s) with the highest sum are the most preferred.
+ items:
+ description: The weights of all of the matched WeightedPodAffinityTerm
+ fields are added per-node to find the most preferred
+ node(s)
+ properties:
+ podAffinityTerm:
+ description: Required. A pod affinity term,
+ associated with the corresponding weight.
+ properties:
+ labelSelector:
+ description: |-
+ A label query over a set of resources, in this case pods.
+ If it's null, this PodAffinityTerm matches with no Pods.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The
+ requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ matchLabelKeys:
+ description: |-
+ MatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both matchLabelKeys and labelSelector.
+ Also, matchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ mismatchLabelKeys:
+ description: |-
+ MismatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
+ Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ namespaceSelector:
+ description: |-
+ A label query over the set of namespaces that the term applies to.
+ The term is applied to the union of the namespaces selected by this field
+ and the ones listed in the namespaces field.
+ null selector and null or empty namespaces list means "this pod's namespace".
+ An empty selector ({}) matches all namespaces.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The
+ requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: |-
+ namespaces specifies a static list of namespace names that the term applies to.
+ The term is applied to the union of the namespaces listed in this field
+ and the ones selected by namespaceSelector.
+ null or empty namespaces list and null namespaceSelector means "this pod's namespace".
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ topologyKey:
+ description: |-
+ This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
+ the labelSelector in the specified namespaces, where co-located is defined as running on a node
+ whose value of the label with key topologyKey matches that of any node on which any of the
+ selected pods is running.
+ Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ weight:
+ description: |-
+ weight associated with matching the corresponding podAffinityTerm,
+ in the range 1-100.
+ format: int32
+ type: integer
+ required:
+ - podAffinityTerm
+ - weight
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ requiredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ If the anti-affinity requirements specified by this field are not met at
+ scheduling time, the pod will not be scheduled onto the node.
+ If the anti-affinity requirements specified by this field cease to be met
+ at some point during pod execution (e.g. due to a pod label update), the
+ system may or may not try to eventually evict the pod from its node.
+ When there are multiple elements, the lists of nodes corresponding to each
+ podAffinityTerm are intersected, i.e. all terms must be satisfied.
+ items:
+ description: |-
+ Defines a set of pods (namely those matching the labelSelector
+ relative to the given namespace(s)) that this pod should be
+ co-located (affinity) or not co-located (anti-affinity) with,
+ where co-located is defined as running on a node whose value of
+ the label with key matches that of any node on which
+ a pod of the set of pods is running
+ properties:
+ labelSelector:
+ description: |-
+ A label query over a set of resources, in this case pods.
+ If it's null, this PodAffinityTerm matches with no Pods.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The requirements
+ are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label key
+ that the selector applies to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ matchLabelKeys:
+ description: |-
+ MatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both matchLabelKeys and labelSelector.
+ Also, matchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ mismatchLabelKeys:
+ description: |-
+ MismatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
+ Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ namespaceSelector:
+ description: |-
+ A label query over the set of namespaces that the term applies to.
+ The term is applied to the union of the namespaces selected by this field
+ and the ones listed in the namespaces field.
+ null selector and null or empty namespaces list means "this pod's namespace".
+ An empty selector ({}) matches all namespaces.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The requirements
+ are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label key
+ that the selector applies to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: |-
+ namespaces specifies a static list of namespace names that the term applies to.
+ The term is applied to the union of the namespaces listed in this field
+ and the ones selected by namespaceSelector.
+ null or empty namespaces list and null namespaceSelector means "this pod's namespace".
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ topologyKey:
+ description: |-
+ This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
+ the labelSelector in the specified namespaces, where co-located is defined as running on a node
+ whose value of the label with key topologyKey matches that of any node on which any of the
+ selected pods is running.
+ Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ type: object
+ ambient:
+ description: Configuration for Istio Ambient.
+ properties:
+ configDir:
+ description: The directory path containing the configuration
+ files for Ambient. Defaults to /etc/ambient-config.
+ type: string
+ dnsCapture:
+ description: If enabled, and ambient is enabled, DNS redirection
+ will be enabled.
+ type: boolean
+ enabled:
+ description: Controls whether ambient redirection is enabled
+ type: boolean
+ ipv6:
+ description: 'UNSTABLE: If enabled, and ambient is enabled,
+ enables ipv6 support'
+ type: boolean
+ reconcileIptablesOnStartup:
+ description: If enabled, and ambient is enabled, iptables
+ reconciliation will be enabled.
+ type: boolean
+ type: object
+ chained:
+ description: |-
+ Configure the plugin as a chained CNI plugin. When true, the configuration is added to the CNI chain; when false,
+ the configuration is added as a standalone file in the CNI configuration directory.
+ type: boolean
+ cniBinDir:
+ description: The directory path within the cluster node's
+ filesystem where the CNI binaries are to be installed. Typically
+ /var/lib/cni/bin.
+ type: string
+ cniConfDir:
+ description: The directory path within the cluster node's
+ filesystem where the CNI configuration files are to be installed.
+ Typically /etc/cni/net.d.
+ type: string
+ cniConfFileName:
+ description: The name of the CNI plugin configuration file.
+ Defaults to istio-cni.conf.
+ type: string
+ cniNetnsDir:
+ description: |-
+ The directory path within the cluster node's filesystem where network namespaces are located.
+ Defaults to '/var/run/netns', in minikube/docker/others can be '/var/run/docker/netns'.
+ type: string
+ daemonSetLabels:
+ additionalProperties:
+ type: string
+ description: Additional labels to apply to the istio-cni DaemonSet.
+ type: object
+ env:
+ additionalProperties:
+ type: string
+ description: "Environment variables passed to the CNI container.\n\nExamples:\nenv:\n\n\tENV_VAR_1:
+ value1\n\tENV_VAR_2: value2"
+ type: object
+ excludeNamespaces:
+ description: List of namespaces that should be ignored by
+ the CNI plugin.
+ items:
+ type: string
+ type: array
+ hub:
+ description: Hub to pull the container image from. Image will
+ be `Hub/Image:Tag-Variant`.
+ type: string
+ image:
+ description: |-
+ Image name to pull from. Image will be `Hub/Image:Tag-Variant`.
+ If Image contains a "/", it will replace the entire `image` in the pod.
+ type: string
+ istioOwnedCNIConfig:
+ description: Specifies if an Istio owned CNI config should
+ be created.
+ type: boolean
+ istioOwnedCNIConfigFileName:
+ type: string
+ logging:
+ description: Same as `global.logging.level`, but will override
+ it if set
+ properties:
+ level:
+ description: |-
+ Comma-separated minimum per-scope logging level of messages to output, in the form of :,:
+ The control plane has different scopes depending on component, but can configure default log level across all components
+ If empty, default scope and level will be used as configured in code
+ type: string
+ type: object
+ podAnnotations:
+ additionalProperties:
+ type: string
+ description: |-
+ Additional annotations to apply to the istio-cni Pods.
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ type: object
+ podLabels:
+ additionalProperties:
+ type: string
+ description: Additional labels to apply to the istio-cni Pods.
+ type: object
+ privileged:
+ description: |-
+ No longer used for CNI. See: https://github.com/istio/istio/issues/49004
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ type: boolean
+ provider:
+ description: |-
+ Specifies the CNI provider. Can be either "default" or "multus". When set to "multus", an additional
+ NetworkAttachmentDefinition resource is deployed to the cluster to allow the istio-cni plugin to be
+ invoked in a cluster using the Multus CNI plugin.
+ type: string
+ psp_cluster_role:
+ description: PodSecurityPolicy cluster role. No longer used
+ anywhere.
+ type: string
+ pullPolicy:
+ description: |-
+ Specifies the image pull policy. one of Always, Never, IfNotPresent.
+ Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated.
+
+ More info: https://kubernetes.io/docs/concepts/containers/images#updating-images
+ enum:
+ - Always
+ - Never
+ - IfNotPresent
+ type: string
+ repair:
+ description: Configuration for the CNI Repair controller.
+ properties:
+ brokenPodLabelKey:
+ description: The label key to apply to a broken pod when
+ the controller is in labelPods mode.
+ type: string
+ brokenPodLabelValue:
+ description: The label value to apply to a broken pod
+ when the controller is in labelPods mode.
+ type: string
+ createEvents:
+ description: |-
+ No longer used.
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ type: string
+ deletePods:
+ description: |-
+ The Repair controller has 3 modes (labelPods, deletePods, and repairPods). Pick which one meets your use cases. Note only one may be used.
+ The mode defines the action the controller will take when a pod is detected as broken.
+ If deletePods is true, the controller will delete the broken pod. The pod will then be rescheduled, hopefully onto a node that is fully ready.
+ Note this gives the DaemonSet a relatively high privilege, as it can delete any Pod.
+ type: boolean
+ enabled:
+ description: Controls whether repair behavior is enabled.
+ type: boolean
+ hub:
+ description: Hub to pull the container image from. Image
+ will be `Hub/Image:Tag-Variant`.
+ type: string
+ image:
+ description: |-
+ Image name to pull from. Image will be `Hub/Image:Tag-Variant`.
+ If Image contains a "/", it will replace the entire `image` in the pod.
+ type: string
+ initContainerName:
+ description: The name of the init container to use for
+ the repairPods mode.
+ type: string
+ labelPods:
+ description: |-
+ The Repair controller has 3 modes (labelPods, deletePods, and repairPods). Pick which one meets your use cases. Note only one may be used.
+ The mode defines the action the controller will take when a pod is detected as broken.
+ If labelPods is true, the controller will label all broken pods with =.
+ This is only capable of identifying broken pods; the user is responsible for fixing them (generally, by deleting them).
+ Note this gives the DaemonSet a relatively high privilege, as modifying pod metadata/status can have wider impacts.
+ type: boolean
+ repairPods:
+ description: |-
+ The Repair controller has 3 modes (labelPods, deletePods, and repairPods). Pick which one meets your use cases. Note only one may be used.
+ The mode defines the action the controller will take when a pod is detected as broken.
+ If repairPods is true, the controller will dynamically repair any broken pod by setting up the pod networking configuration even after it has started.
+ Note the pod will be crashlooping, so this may take a few minutes to become fully functional based on when the retry occurs.
+ This requires no RBAC privilege, but will require the CNI agent to run as a privileged pod.
+ type: boolean
+ tag:
+ description: The container image tag to pull. Image will
+ be `Hub/Image:Tag-Variant`.
+ type: string
+ type: object
+ resource_quotas:
+ description: The resource quotas configuration for the CNI
+ DaemonSet.
+ properties:
+ enabled:
+ description: Controls whether to create resource quotas
+ or not for the CNI DaemonSet.
+ type: boolean
+ pods:
+ description: The hard limit on the number of pods in the
+ namespace where the CNI DaemonSet is deployed.
+ format: int64
+ type: integer
+ type: object
+ resources:
+ description: The k8s resource requests and limits for the
+ istio-cni Pods.
+ properties:
+ claims:
+ description: |-
+ Claims lists the names of resources, defined in spec.resourceClaims,
+ that are used by this container.
+
+ This field depends on the
+ DynamicResourceAllocation feature gate.
+
+ This field is immutable. It can only be set for containers.
+ items:
+ description: ResourceClaim references one entry in PodSpec.ResourceClaims.
+ properties:
+ name:
+ description: |-
+ Name must match the name of one entry in pod.spec.resourceClaims of
+ the Pod where this field is used. It makes that resource available
+ inside a container.
+ type: string
+ request:
+ description: |-
+ Request is the name chosen for a request in the referenced claim.
+ If empty, everything from the claim is made available, otherwise
+ only the result of this request.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - name
+ x-kubernetes-list-type: map
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Limits describes the maximum amount of compute resources allowed.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Requests describes the minimum amount of compute resources required.
+ If Requests is omitted for a container, it defaults to Limits if that is explicitly specified,
+ otherwise to an implementation-defined value. Requests cannot exceed Limits.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ type: object
+ rollingMaxUnavailable:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ The number of pods that can be unavailable during a rolling update of the CNI DaemonSet (see
+ `updateStrategy.rollingUpdate.maxUnavailable` here:
+ https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/daemon-set-v1/#DaemonSetSpec).
+ May be specified as a number of pods or as a percent of the total number
+ of pods at the start of the update.
+ x-kubernetes-int-or-string: true
+ seccompProfile:
+ description: |-
+ The Container seccompProfile
+
+ See: https://kubernetes.io/docs/tutorials/security/seccomp/
+ properties:
+ localhostProfile:
+ description: |-
+ localhostProfile indicates a profile defined in a file on the node should be used.
+ The profile must be preconfigured on the node to work.
+ Must be a descending path, relative to the kubelet's configured seccomp profile location.
+ Must be set if type is "Localhost". Must NOT be set for any other type.
+ type: string
+ type:
+ description: |-
+ type indicates which kind of seccomp profile will be applied.
+ Valid options are:
+
+ Localhost - a profile defined in a file on the node should be used.
+ RuntimeDefault - the container runtime default profile should be used.
+ Unconfined - no profile should be applied.
+ type: string
+ required:
+ - type
+ type: object
+ tag:
+ description: The container image tag to pull. Image will be
+ `Hub/Image:Tag-Variant`.
+ type: string
+ variant:
+ description: The container image variant to pull. Options
+ are "debug" or "distroless". Unset will use the default
+ for the given version.
+ type: string
+ type: object
+ global:
+ description: Part of the global configuration applicable to the
+ Istio CNI component.
+ properties:
+ defaultResources:
+ description: |-
+ See https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ properties:
+ claims:
+ description: |-
+ Claims lists the names of resources, defined in spec.resourceClaims,
+ that are used by this container.
+
+ This field depends on the
+ DynamicResourceAllocation feature gate.
+
+ This field is immutable. It can only be set for containers.
+ items:
+ description: ResourceClaim references one entry in PodSpec.ResourceClaims.
+ properties:
+ name:
+ description: |-
+ Name must match the name of one entry in pod.spec.resourceClaims of
+ the Pod where this field is used. It makes that resource available
+ inside a container.
+ type: string
+ request:
+ description: |-
+ Request is the name chosen for a request in the referenced claim.
+ If empty, everything from the claim is made available, otherwise
+ only the result of this request.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - name
+ x-kubernetes-list-type: map
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Limits describes the maximum amount of compute resources allowed.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Requests describes the minimum amount of compute resources required.
+ If Requests is omitted for a container, it defaults to Limits if that is explicitly specified,
+ otherwise to an implementation-defined value. Requests cannot exceed Limits.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ type: object
+ hub:
+ description: Specifies the docker hub for Istio images.
+ type: string
+ imagePullPolicy:
+ description: |-
+ Specifies the image pull policy for the Istio images. one of Always, Never, IfNotPresent.
+ Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated.
+
+ More info: https://kubernetes.io/docs/concepts/containers/images#updating-images
+ enum:
+ - Always
+ - Never
+ - IfNotPresent
+ type: string
+ imagePullSecrets:
+ description: |-
+ ImagePullSecrets for the control plane ServiceAccount, list of secrets in the same namespace
+ to use for pulling any images in pods that reference this ServiceAccount.
+ Must be set for any cluster configured with private docker registry.
+ items:
+ type: string
+ type: array
+ logAsJson:
+ description: Specifies whether istio components should output
+ logs in json format by adding --log_as_json argument to
+ each container.
+ type: boolean
+ logging:
+ description: Specifies the global logging level settings for
+ the Istio control plane components.
+ properties:
+ level:
+ description: |-
+ Comma-separated minimum per-scope logging level of messages to output, in the form of :,:
+ The control plane has different scopes depending on component, but can configure default log level across all components
+ If empty, default scope and level will be used as configured in code
+ type: string
+ type: object
+ nativeNftables:
+ description: Specifies whether native nftables rules should
+ be used instead of iptables rules for traffic redirection.
+ type: boolean
+ platform:
+ description: |-
+ Platform in which Istio is deployed. Possible values are: "openshift" and "gcp"
+ An empty value means it is a vanilla Kubernetes distribution, therefore no special
+ treatment will be considered.
+ type: string
+ tag:
+ description: Specifies the tag for the Istio docker images.
+ type: string
+ variant:
+ description: The variant of the Istio container images to
+ use. Options are "debug" or "distroless". Unset will use
+ the default for the given version.
+ type: string
+ type: object
+ type: object
+ version:
+ default: v1.28.3
+ description: |-
+ Defines the version of Istio to install.
+ Must be one of: v1.28-latest, v1.28.3, v1.28.2, v1.28.1, v1.28.0, v1.27-latest, v1.27.5, v1.27.4, v1.27.3, v1.27.2, v1.27.1, v1.27.0, master, v1.30-alpha.a30ad733.
+ enum:
+ - v1.28-latest
+ - v1.28.3
+ - v1.28.2
+ - v1.28.1
+ - v1.28.0
+ - v1.27-latest
+ - v1.27.5
+ - v1.27.4
+ - v1.27.3
+ - v1.27.2
+ - v1.27.1
+ - v1.27.0
+ - v1.26-latest
+ - v1.26.8
+ - v1.26.7
+ - v1.26.6
+ - v1.26.5
+ - v1.26.4
+ - v1.26.3
+ - v1.26.2
+ - v1.26.1
+ - v1.26.0
+ - v1.25-latest
+ - v1.25.5
+ - v1.25.4
+ - v1.25.3
+ - v1.25.2
+ - v1.25.1
+ - v1.24-latest
+ - v1.24.6
+ - v1.24.5
+ - v1.24.4
+ - v1.24.3
+ - v1.24.2
+ - v1.24.1
+ - v1.24.0
+ - v1.23-latest
+ - v1.23.6
+ - v1.23.5
+ - v1.23.4
+ - v1.23.3
+ - v1.23.2
+ - v1.22-latest
+ - v1.22.8
+ - v1.22.7
+ - v1.22.6
+ - v1.22.5
+ - v1.21.6
+ - master
+ - v1.30-alpha.a30ad733
+ type: string
+ required:
+ - namespace
+ - version
+ type: object
+ status:
+ description: IstioCNIStatus defines the observed state of IstioCNI
+ properties:
+ conditions:
+ description: Represents the latest available observations of the object's
+ current state.
+ items:
+ description: IstioCNICondition represents a specific observation
+ of the IstioCNI object's state.
+ properties:
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ the last transition.
+ type: string
+ reason:
+ description: Unique, single-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: The status of this condition. Can be True, False
+ or Unknown.
+ type: string
+ type:
+ description: The type of this condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ description: |-
+ ObservedGeneration is the most recent generation observed for this
+ IstioCNI object. It corresponds to the object's generation, which is
+ updated on mutation by the API Server. The information in the status
+ pertains to this particular generation of the object.
+ format: int64
+ type: integer
+ state:
+ description: Reports the current state of the object.
+ type: string
+ type: object
+ type: object
+ x-kubernetes-validations:
+ - message: metadata.name must be 'default'
+ rule: self.metadata.name == 'default'
+ served: true
+ storage: true
+ subresources:
+ status: {}
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/sailoperator.io_istiorevisions.yaml b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/sailoperator.io_istiorevisions.yaml
new file mode 100644
index 0000000000..44ba32d2a7
--- /dev/null
+++ b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/sailoperator.io_istiorevisions.yaml
@@ -0,0 +1,10230 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.20.0
+ name: istiorevisions.sailoperator.io
+spec:
+ group: sailoperator.io
+ names:
+ categories:
+ - istio-io
+ kind: IstioRevision
+ listKind: IstioRevisionList
+ plural: istiorevisions
+ shortNames:
+ - istiorev
+ singular: istiorevision
+ scope: Cluster
+ versions:
+ - additionalPrinterColumns:
+ - description: The namespace for the control plane components.
+ jsonPath: .spec.namespace
+ name: Namespace
+ type: string
+ - description: The selected profile (collection of value presets).
+ jsonPath: .spec.values.profile
+ name: Profile
+ type: string
+ - description: Whether the control plane installation is ready to handle requests.
+ jsonPath: .status.conditions[?(@.type=="Ready")].status
+ name: Ready
+ type: string
+ - description: The current state of this object.
+ jsonPath: .status.state
+ name: Status
+ type: string
+ - description: Whether the revision is being used by workloads.
+ jsonPath: .status.conditions[?(@.type=="InUse")].status
+ name: In use
+ type: string
+ - description: The version of the control plane installation.
+ jsonPath: .spec.version
+ name: Version
+ type: string
+ - description: The age of the object
+ jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1
+ schema:
+ openAPIV3Schema:
+ description: |-
+ IstioRevision represents a single revision of an Istio Service Mesh deployment.
+ Users shouldn't create IstioRevision objects directly. Instead, they should
+ create an Istio object and allow the operator to create the underlying
+ IstioRevision object(s).
+ properties:
+ apiVersion:
+ description: |-
+ APIVersion defines the versioned schema of this representation of an object.
+ Servers should convert recognized schemas to the latest internal value, and
+ may reject unrecognized values.
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
+ type: string
+ kind:
+ description: |-
+ Kind is a string value representing the REST resource this object represents.
+ Servers may infer this from the endpoint the client submits requests to.
+ Cannot be updated.
+ In CamelCase.
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
+ type: string
+ metadata:
+ type: object
+ spec:
+ description: IstioRevisionSpec defines the desired state of IstioRevision
+ properties:
+ namespace:
+ description: Namespace to which the Istio components should be installed.
+ type: string
+ x-kubernetes-validations:
+ - message: Value is immutable
+ rule: self == oldSelf
+ values:
+ description: Defines the values to be passed to the Helm charts when
+ installing Istio.
+ properties:
+ base:
+ description: Configuration for the base component.
+ properties:
+ excludedCRDs:
+ description: CRDs to exclude. Requires `enableCRDTemplates`
+ items:
+ type: string
+ type: array
+ validationCABundle:
+ description: validation webhook CA bundle
+ type: string
+ validationURL:
+ description: URL to use for validating webhook.
+ type: string
+ type: object
+ compatibilityVersion:
+ description: |-
+ Specifies the compatibility version to use. When this is set, the control plane will
+ be configured with the same defaults as the specified version.
+ type: string
+ defaultRevision:
+ description: |-
+ The name of the default revision in the cluster.
+ Deprecated: This field is ignored. The default revision is expected to be configurable elsewhere.
+ type: string
+ experimental:
+ description: Specifies experimental helm fields that could be
+ removed or changed in the future
+ x-kubernetes-preserve-unknown-fields: true
+ gatewayClasses:
+ description: Configuration for Gateway Classes
+ x-kubernetes-preserve-unknown-fields: true
+ global:
+ description: Global configuration for Istio components.
+ properties:
+ agentgateway:
+ description: Specifies how proxies are configured within Istio.
+ properties:
+ image:
+ type: string
+ type: object
+ arch:
+ description: "Specifies pod scheduling arch(amd64, ppc64le,
+ s390x, arm64) and weight as follows:\n\n\t0 - Never scheduled\n\t1
+ - Least preferred\n\t2 - No preference\n\t3 - Most preferred\n\nDeprecated:
+ replaced by the affinity k8s settings which allows architecture
+ nodeAffinity configuration of this behavior.\n\nDeprecated:
+ Marked as deprecated in pkg/apis/values_types.proto."
+ properties:
+ amd64:
+ description: Sets pod scheduling weight for amd64 arch
+ format: int32
+ type: integer
+ arm64:
+ description: Sets pod scheduling weight for arm64 arch.
+ format: int32
+ type: integer
+ ppc64le:
+ description: Sets pod scheduling weight for ppc64le arch.
+ format: int32
+ type: integer
+ s390x:
+ description: Sets pod scheduling weight for s390x arch.
+ format: int32
+ type: integer
+ type: object
+ caAddress:
+ description: The address of the CA for CSR.
+ type: string
+ caName:
+ description: |-
+ The name of the CA for workloads.
+ For example, when caName=GkeWorkloadCertificate, GKE workload certificates
+ will be used as the certificates for workloads.
+ The default value is "" and when caName="", the CA will be configured by other
+ mechanisms (e.g., environmental variable CA_PROVIDER).
+ type: string
+ certSigners:
+ description: List of certSigners to allow "approve" action
+ in the ClusterRole
+ items:
+ type: string
+ type: array
+ configCluster:
+ description: Controls whether a remote cluster is the config
+ cluster for an external istiod
+ type: boolean
+ configValidation:
+ description: Controls whether the server-side validation is
+ enabled.
+ type: boolean
+ defaultNodeSelector:
+ additionalProperties:
+ type: string
+ description: |-
+ Default k8s node selector for all the Istio control plane components
+
+ See https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ type: object
+ defaultPodDisruptionBudget:
+ description: Specifies the default pod disruption budget configuration.
+ properties:
+ enabled:
+ description: Controls whether a PodDisruptionBudget with
+ a default minAvailable value of 1 is created for each
+ deployment.
+ type: boolean
+ type: object
+ defaultResources:
+ description: |-
+ Default k8s resources settings for all Istio control plane components.
+
+ See https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ properties:
+ claims:
+ description: |-
+ Claims lists the names of resources, defined in spec.resourceClaims,
+ that are used by this container.
+
+ This field depends on the
+ DynamicResourceAllocation feature gate.
+
+ This field is immutable. It can only be set for containers.
+ items:
+ description: ResourceClaim references one entry in PodSpec.ResourceClaims.
+ properties:
+ name:
+ description: |-
+ Name must match the name of one entry in pod.spec.resourceClaims of
+ the Pod where this field is used. It makes that resource available
+ inside a container.
+ type: string
+ request:
+ description: |-
+ Request is the name chosen for a request in the referenced claim.
+ If empty, everything from the claim is made available, otherwise
+ only the result of this request.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - name
+ x-kubernetes-list-type: map
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Limits describes the maximum amount of compute resources allowed.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Requests describes the minimum amount of compute resources required.
+ If Requests is omitted for a container, it defaults to Limits if that is explicitly specified,
+ otherwise to an implementation-defined value. Requests cannot exceed Limits.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ type: object
+ defaultTolerations:
+ description: |-
+ Default node tolerations to be applied to all deployments so that all pods can be
+ scheduled to nodes with matching taints. Each component can overwrite
+ these default values by adding its tolerations block in the relevant section below
+ and setting the desired values.
+ Configure this field in case that all pods of Istio control plane are expected to
+ be scheduled to particular nodes with specified taints.
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ items:
+ description: |-
+ The pod this Toleration is attached to tolerates any taint that matches
+ the triple using the matching operator .
+ properties:
+ effect:
+ description: |-
+ Effect indicates the taint effect to match. Empty means match all taint effects.
+ When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.
+ type: string
+ key:
+ description: |-
+ Key is the taint key that the toleration applies to. Empty means match all taint keys.
+ If the key is empty, operator must be Exists; this combination means to match all values and all keys.
+ type: string
+ operator:
+ description: |-
+ Operator represents a key's relationship to the value.
+ Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal.
+ Exists is equivalent to wildcard for value, so that a pod can
+ tolerate all taints of a particular category.
+ Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators).
+ type: string
+ tolerationSeconds:
+ description: |-
+ TolerationSeconds represents the period of time the toleration (which must be
+ of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default,
+ it is not set, which means tolerate the taint forever (do not evict). Zero and
+ negative values will be treated as 0 (evict immediately) by the system.
+ format: int64
+ type: integer
+ value:
+ description: |-
+ Value is the taint value the toleration matches to.
+ If the operator is Exists, the value should be empty, otherwise just a regular string.
+ type: string
+ type: object
+ type: array
+ externalIstiod:
+ description: Controls whether one external istiod is enabled.
+ type: boolean
+ hub:
+ description: Specifies the docker hub for Istio images.
+ type: string
+ imagePullPolicy:
+ description: |-
+ Specifies the image pull policy for the Istio images. one of Always, Never, IfNotPresent.
+ Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated.
+
+ More info: https://kubernetes.io/docs/concepts/containers/images#updating-images
+ enum:
+ - Always
+ - Never
+ - IfNotPresent
+ type: string
+ imagePullSecrets:
+ description: |-
+ ImagePullSecrets for the control plane ServiceAccount, list of secrets in the same namespace
+ to use for pulling any images in pods that reference this ServiceAccount.
+ Must be set for any cluster configured with private docker registry.
+ items:
+ type: string
+ type: array
+ ipFamilies:
+ description: |-
+ Defines which IP family to use for single stack or the order of IP families for dual-stack.
+ Valid list items are "IPv4", "IPv6".
+ More info: https://kubernetes.io/docs/concepts/services-networking/dual-stack/#services
+ items:
+ type: string
+ type: array
+ ipFamilyPolicy:
+ description: |-
+ Controls whether Services are configured to use IPv4, IPv6, or both. Valid options
+ are PreferDualStack, RequireDualStack, and SingleStack.
+ More info: https://kubernetes.io/docs/concepts/services-networking/dual-stack/#services
+ type: string
+ istioNamespace:
+ description: Specifies the default namespace for the Istio
+ control plane components.
+ type: string
+ istiod:
+ description: Specifies the configution of istiod
+ properties:
+ enableAnalysis:
+ description: If enabled, istiod will perform config analysis
+ type: boolean
+ type: object
+ jwtPolicy:
+ description: |-
+ Configure the policy for validating JWT.
+ This is deprecated and has no effect.
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ type: string
+ logAsJson:
+ description: Specifies whether istio components should output
+ logs in json format by adding --log_as_json argument to
+ each container.
+ type: boolean
+ logging:
+ description: Specifies the global logging level settings for
+ the Istio control plane components.
+ properties:
+ level:
+ description: |-
+ Comma-separated minimum per-scope logging level of messages to output, in the form of :,:
+ The control plane has different scopes depending on component, but can configure default log level across all components
+ If empty, default scope and level will be used as configured in code
+ type: string
+ type: object
+ meshID:
+ description: |-
+ The Mesh Identifier. It should be unique within the scope where
+ meshes will interact with each other, but it is not required to be
+ globally/universally unique. For example, if any of the following are true,
+ then two meshes must have different Mesh IDs:
+ - Meshes will have their telemetry aggregated in one place
+ - Meshes will be federated together
+ - Policy will be written referencing one mesh from the other
+
+ If an administrator expects that any of these conditions may become true in
+ the future, they should ensure their meshes have different Mesh IDs
+ assigned.
+
+ Within a multicluster mesh, each cluster must be (manually or auto)
+ configured to have the same Mesh ID value. If an existing cluster 'joins' a
+ multicluster mesh, it will need to be migrated to the new mesh ID. Details
+ of migration TBD, and it may be a disruptive operation to change the Mesh
+ ID post-install.
+
+ If the mesh admin does not specify a value, Istio will use the value of the
+ mesh's Trust Domain. The best practice is to select a proper Trust Domain
+ value.
+ type: string
+ meshNetworks:
+ additionalProperties:
+ description: |-
+ Network provides information about the endpoints in a routable L3
+ network. A single routable L3 network can have one or more service
+ registries. Note that the network has no relation to the locality of the
+ endpoint. The endpoint locality will be obtained from the service
+ registry.
+ properties:
+ endpoints:
+ description: |-
+ The list of endpoints in the network (obtained through the
+ constituent service registries or from CIDR ranges). All endpoints in
+ the network are directly accessible to one another.
+ items:
+ description: "NetworkEndpoints describes how the network
+ associated with an endpoint\nshould be inferred.
+ An endpoint will be assigned to a network based
+ on\nthe following rules:\n\n1. Implicitly: If the
+ registry explicitly provides information about\nthe
+ network to which the endpoint belongs to. In some
+ cases, its\npossible to indicate the network associated
+ with the endpoint by\nadding the `ISTIO_META_NETWORK`
+ environment variable to the sidecar.\n\n2. Explicitly:\n\n\ta.
+ By matching the registry name with one of the \"fromRegistry\"\n\tin
+ the mesh config. A \"fromRegistry\" can only be
+ assigned to a\n\tsingle network.\n\n\tb. By matching
+ the IP against one of the CIDR ranges in a mesh\n\tconfig
+ network. The CIDR ranges must not overlap and be
+ assigned to\n\ta single network.\n\n(2) will override
+ (1) if both are present."
+ properties:
+ fromCidr:
+ description: |-
+ A CIDR range for the set of endpoints in this network. The CIDR
+ ranges for endpoints from different networks must not overlap.
+ type: string
+ fromRegistry:
+ description: |-
+ Add all endpoints from the specified registry into this network.
+ The names of the registries should correspond to the kubeconfig file name
+ inside the secret that was used to configure the registry (Kubernetes
+ multicluster) or supplied by MCP server.
+ type: string
+ type: object
+ x-kubernetes-validations:
+ - message: At most one of [fromCidr fromRegistry]
+ should be set
+ rule: (has(self.fromCidr)?1:0) + (has(self.fromRegistry)?1:0)
+ <= 1
+ type: array
+ gateways:
+ description: Set of gateways associated with the network.
+ items:
+ description: |-
+ The gateway associated with this network. Traffic from remote networks
+ will arrive at the specified gateway:port. All incoming traffic must
+ use mTLS.
+ properties:
+ address:
+ description: IP address or externally resolvable
+ DNS address associated with the gateway.
+ type: string
+ locality:
+ description: The locality associated with an explicitly
+ specified gateway (i.e. ip)
+ type: string
+ port:
+ format: int32
+ type: integer
+ registryServiceName:
+ description: |-
+ A fully qualified domain name of the gateway service. istiod will
+ lookup the service from the service registries in the network and
+ obtain the endpoint IPs of the gateway from the service
+ registry. Note that while the service name is a fully qualified
+ domain name, it need not be resolvable outside the orchestration
+ platform for the registry. e.g., this could be
+ istio-ingressgateway.istio-system.svc.cluster.local.
+ type: string
+ type: object
+ x-kubernetes-validations:
+ - message: At most one of [registryServiceName address]
+ should be set
+ rule: (has(self.registryServiceName)?1:0) + (has(self.address)?1:0)
+ <= 1
+ type: array
+ type: object
+ description: "Configure the mesh networks to be used by the
+ Split Horizon EDS.\n\nThe following example defines two
+ networks with different endpoints association methods.\nFor
+ `network1` all endpoints that their IP belongs to the provided
+ CIDR range will be\nmapped to network1. The gateway for
+ this network example is specified by its public IP\naddress
+ and port.\nThe second network, `network2`, in this example
+ is defined differently with all endpoints\nretrieved through
+ the specified Multi-Cluster registry being mapped to network2.
+ The\ngateway is also defined differently with the name of
+ the gateway service on the remote\ncluster. The public IP
+ for the gateway will be determined from that remote service
+ (only\nLoadBalancer gateway service type is currently supported,
+ for a NodePort type gateway service,\nit still need to be
+ configured manually).\n\nmeshNetworks:\n\n\tnetwork1:\n\t
+ \ endpoints:\n\t - fromCidr: \"192.168.0.1/24\"\n\t gateways:\n\t
+ \ - address: 1.1.1.1\n\t port: 80\n\tnetwork2:\n\t endpoints:\n\t
+ \ - fromRegistry: reg1\n\t gateways:\n\t - registryServiceName:
+ istio-ingressgateway.istio-system.svc.cluster.local\n\t
+ \ port: 443"
+ type: object
+ mountMtlsCerts:
+ description: Controls whether the in-cluster MTLS key and
+ certs are loaded from the secret volume mounts.
+ type: boolean
+ multiCluster:
+ description: Specifies the Configuration for Istio mesh across
+ multiple clusters through Istio gateways.
+ properties:
+ clusterName:
+ description: |-
+ The name of the cluster this installation will run in. This is required for sidecar injection
+ to properly label proxies
+ type: string
+ enabled:
+ description: |-
+ Enables the connection between two kubernetes clusters via their respective ingressgateway services.
+ Use if the pods in each cluster cannot directly talk to one another.
+ type: boolean
+ globalDomainSuffix:
+ description: The suffix for global service names.
+ type: string
+ includeEnvoyFilter:
+ description: Enable envoy filter to translate `globalDomainSuffix`
+ to cluster local suffix for cross cluster communication.
+ type: boolean
+ type: object
+ nativeNftables:
+ description: Specifies whether native nftables rules should
+ be used instead of iptables rules for traffic redirection.
+ type: boolean
+ network:
+ description: |-
+ Network defines the network this cluster belong to. This name
+ corresponds to the networks in the map of mesh networks.
+ type: string
+ networkPolicy:
+ description: Settings related to Kubernetes NetworkPolicy.
+ properties:
+ enabled:
+ description: Controls whether default NetworkPolicy resources
+ will be created.
+ type: boolean
+ type: object
+ omitSidecarInjectorConfigMap:
+ description: |-
+ Controls whether the creation of the sidecar injector ConfigMap should be skipped.
+ Defaults to false. When set to true, the sidecar injector ConfigMap will not be created.
+ type: boolean
+ operatorManageWebhooks:
+ description: |-
+ Controls whether the WebhookConfiguration resource(s) should be created. The current behavior
+ of Istiod is to manage its own webhook configurations.
+ When this option is set to true, Istio Operator, instead of webhooks, manages the
+ webhook configurations. When this option is set as false, webhooks manage their
+ own webhook configurations.
+ type: boolean
+ pilotCertProvider:
+ description: |-
+ Configure the Pilot certificate provider.
+ Currently, four providers are supported: "kubernetes", "istiod", "custom" and "none".
+ type: string
+ platform:
+ description: |-
+ Platform in which Istio is deployed. Possible values are: "openshift" and "gcp"
+ An empty value means it is a vanilla Kubernetes distribution, therefore no special
+ treatment will be considered.
+ type: string
+ podDNSSearchNamespaces:
+ description: |-
+ Custom DNS config for the pod to resolve names of services in other
+ clusters. Use this to add additional search domains, and other settings.
+ see https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#dns-config
+ This does not apply to gateway pods as they typically need a different
+ set of DNS settings than the normal application pods (e.g. in multicluster scenarios).
+ items:
+ type: string
+ type: array
+ priorityClassName:
+ description: |-
+ Specifies the k8s priorityClassName for the istio control plane components.
+
+ See https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ type: string
+ proxy:
+ description: Specifies how proxies are configured within Istio.
+ properties:
+ autoInject:
+ description: Controls the 'policy' in the sidecar injector.
+ type: string
+ clusterDomain:
+ description: |-
+ Domain for the cluster, default: "cluster.local".
+
+ K8s allows this to be customized, see https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/
+ type: string
+ componentLogLevel:
+ description: |-
+ Per Component log level for proxy, applies to gateways and sidecars.
+
+ If a component level is not set, then the global "logLevel" will be used. If left empty, "misc:error" is used.
+ type: string
+ enableCoreDump:
+ description: |-
+ Enables core dumps for newly injected sidecars.
+
+ If set, newly injected sidecars will have core dumps enabled.
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ type: boolean
+ excludeIPRanges:
+ description: Lists the excluded IP ranges of Istio egress
+ traffic that the sidecar captures.
+ type: string
+ excludeInboundPorts:
+ description: Specifies the Istio ingress ports not to
+ capture.
+ type: string
+ excludeOutboundPorts:
+ description: A comma separated list of outbound ports
+ to be excluded from redirection to Envoy.
+ type: string
+ holdApplicationUntilProxyStarts:
+ description: |-
+ Controls if sidecar is injected at the front of the container list and blocks the start of the other containers until the proxy is ready
+
+ Deprecated: replaced by ProxyConfig setting which allows per-pod configuration of this behavior.
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ type: boolean
+ image:
+ description: |-
+ Image name or path for the proxy, default: "proxyv2".
+
+ If registry or tag are not specified, global.hub and global.tag are used.
+
+ Examples: my-proxy (uses global.hub/tag), docker.io/myrepo/my-proxy:v1.0.0
+ type: string
+ includeIPRanges:
+ description: |-
+ Lists the IP ranges of Istio egress traffic that the sidecar captures.
+
+ Example: "172.30.0.0/16,172.20.0.0/16"
+ This would only capture egress traffic on those two IP Ranges, all other outbound traffic would # be allowed by the sidecar."
+ type: string
+ includeInboundPorts:
+ description: |-
+ A comma separated list of inbound ports for which traffic is to be redirected to Envoy.
+ The wildcard character '*' can be used to configure redirection for all ports.
+ type: string
+ includeOutboundPorts:
+ description: A comma separated list of outbound ports
+ for which traffic is to be redirected to Envoy, regardless
+ of the destination IP.
+ type: string
+ lifecycle:
+ description: |-
+ The k8s lifecycle hooks definition (pod.spec.containers.lifecycle) for the proxy container.
+ More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks
+ properties:
+ postStart:
+ description: |-
+ PostStart is called immediately after a container is created. If the handler fails,
+ the container is terminated and restarted according to its restart policy.
+ Other management of the container blocks until the hook completes.
+ More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks
+ properties:
+ exec:
+ description: Exec specifies a command to execute
+ in the container.
+ properties:
+ command:
+ description: |-
+ Command is the command line to execute inside the container, the working directory for the
+ command is root ('/') in the container's filesystem. The command is simply exec'd, it is
+ not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use
+ a shell, you need to explicitly call out to that shell.
+ Exit status of 0 is treated as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ httpGet:
+ description: HTTPGet specifies an HTTP GET request
+ to perform.
+ properties:
+ host:
+ description: |-
+ Host name to connect to, defaults to the pod IP. You probably want to set
+ "Host" in httpHeaders instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the
+ request. HTTP allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom
+ header to be used in HTTP probes
+ properties:
+ name:
+ description: |-
+ The header field name.
+ This will be canonicalized upon output, so case-variant names will be understood as the same header.
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ Name or number of the port to access on the container.
+ Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: |-
+ Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ sleep:
+ description: Sleep represents a duration that
+ the container should sleep.
+ properties:
+ seconds:
+ description: Seconds is the number of seconds
+ to sleep.
+ format: int64
+ type: integer
+ required:
+ - seconds
+ type: object
+ tcpSocket:
+ description: |-
+ Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept
+ for backward compatibility. There is no validation of this field and
+ lifecycle hooks will fail at runtime when it is specified.
+ properties:
+ host:
+ description: 'Optional: Host name to connect
+ to, defaults to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ Number or name of the port to access on the container.
+ Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ type: object
+ preStop:
+ description: |-
+ PreStop is called immediately before a container is terminated due to an
+ API request or management event such as liveness/startup probe failure,
+ preemption, resource contention, etc. The handler is not called if the
+ container crashes or exits. The Pod's termination grace period countdown begins before the
+ PreStop hook is executed. Regardless of the outcome of the handler, the
+ container will eventually terminate within the Pod's termination grace
+ period (unless delayed by finalizers). Other management of the container blocks until the hook completes
+ or until the termination grace period is reached.
+ More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks
+ properties:
+ exec:
+ description: Exec specifies a command to execute
+ in the container.
+ properties:
+ command:
+ description: |-
+ Command is the command line to execute inside the container, the working directory for the
+ command is root ('/') in the container's filesystem. The command is simply exec'd, it is
+ not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use
+ a shell, you need to explicitly call out to that shell.
+ Exit status of 0 is treated as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ httpGet:
+ description: HTTPGet specifies an HTTP GET request
+ to perform.
+ properties:
+ host:
+ description: |-
+ Host name to connect to, defaults to the pod IP. You probably want to set
+ "Host" in httpHeaders instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the
+ request. HTTP allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom
+ header to be used in HTTP probes
+ properties:
+ name:
+ description: |-
+ The header field name.
+ This will be canonicalized upon output, so case-variant names will be understood as the same header.
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ Name or number of the port to access on the container.
+ Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: |-
+ Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ sleep:
+ description: Sleep represents a duration that
+ the container should sleep.
+ properties:
+ seconds:
+ description: Seconds is the number of seconds
+ to sleep.
+ format: int64
+ type: integer
+ required:
+ - seconds
+ type: object
+ tcpSocket:
+ description: |-
+ Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept
+ for backward compatibility. There is no validation of this field and
+ lifecycle hooks will fail at runtime when it is specified.
+ properties:
+ host:
+ description: 'Optional: Host name to connect
+ to, defaults to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ Number or name of the port to access on the container.
+ Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ type: object
+ stopSignal:
+ description: |-
+ StopSignal defines which signal will be sent to a container when it is being stopped.
+ If not specified, the default is defined by the container runtime in use.
+ StopSignal can only be set for Pods with a non-empty .spec.os.name
+ type: string
+ type: object
+ logLevel:
+ description: 'Log level for proxy, applies to gateways
+ and sidecars. If left empty, "warning" is used. Expected
+ values are: trace\|debug\|info\|warning\|error\|critical\|off'
+ type: string
+ outlierLogPath:
+ description: |-
+ Path to the file to which the proxy will write outlier detection logs.
+
+ Example: "/dev/stdout"
+ This would write the logs to standard output.
+ type: string
+ privileged:
+ description: |-
+ Enables privileged securityContext for the istio-proxy container.
+
+ See https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
+ type: boolean
+ readinessFailureThreshold:
+ description: Sets the number of successive failed probes
+ before indicating readiness failure.
+ format: int32
+ type: integer
+ readinessInitialDelaySeconds:
+ description: Sets the initial delay for readiness probes
+ in seconds.
+ format: int32
+ type: integer
+ readinessPeriodSeconds:
+ description: Sets the interval between readiness probes
+ in seconds.
+ format: int32
+ type: integer
+ resources:
+ description: |-
+ K8s resources settings.
+
+ See https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ properties:
+ claims:
+ description: |-
+ Claims lists the names of resources, defined in spec.resourceClaims,
+ that are used by this container.
+
+ This field depends on the
+ DynamicResourceAllocation feature gate.
+
+ This field is immutable. It can only be set for containers.
+ items:
+ description: ResourceClaim references one entry
+ in PodSpec.ResourceClaims.
+ properties:
+ name:
+ description: |-
+ Name must match the name of one entry in pod.spec.resourceClaims of
+ the Pod where this field is used. It makes that resource available
+ inside a container.
+ type: string
+ request:
+ description: |-
+ Request is the name chosen for a request in the referenced claim.
+ If empty, everything from the claim is made available, otherwise
+ only the result of this request.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - name
+ x-kubernetes-list-type: map
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Limits describes the maximum amount of compute resources allowed.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Requests describes the minimum amount of compute resources required.
+ If Requests is omitted for a container, it defaults to Limits if that is explicitly specified,
+ otherwise to an implementation-defined value. Requests cannot exceed Limits.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ type: object
+ seccompProfile:
+ description: |-
+ Configures the seccomp profile for the istio-validation and istio-proxy containers.
+
+ See: https://kubernetes.io/docs/tutorials/security/seccomp/
+ properties:
+ localhostProfile:
+ description: |-
+ localhostProfile indicates a profile defined in a file on the node should be used.
+ The profile must be preconfigured on the node to work.
+ Must be a descending path, relative to the kubelet's configured seccomp profile location.
+ Must be set if type is "Localhost". Must NOT be set for any other type.
+ type: string
+ type:
+ description: |-
+ type indicates which kind of seccomp profile will be applied.
+ Valid options are:
+
+ Localhost - a profile defined in a file on the node should be used.
+ RuntimeDefault - the container runtime default profile should be used.
+ Unconfined - no profile should be applied.
+ type: string
+ required:
+ - type
+ type: object
+ startupProbe:
+ description: Configures the startup probe for the istio-proxy
+ container.
+ properties:
+ enabled:
+ description: |-
+ Enables or disables a startup probe.
+ For optimal startup times, changing this should be tied to the readiness probe values.
+
+ If the probe is enabled, it is recommended to have delay=0s,period=15s,failureThreshold=4.
+ This ensures the pod is marked ready immediately after the startup probe passes (which has a 1s poll interval),
+ and doesn't spam the readiness endpoint too much
+
+ If the probe is disabled, it is recommended to have delay=1s,period=2s,failureThreshold=30.
+ This ensures the startup is reasonable fast (polling every 2s). 1s delay is used since the startup is not often ready instantly.
+ type: boolean
+ failureThreshold:
+ description: Minimum consecutive failures for the
+ probe to be considered failed after having succeeded.
+ format: int32
+ type: integer
+ type: object
+ statusPort:
+ description: Default port used for the Pilot agent's health
+ checks.
+ format: int32
+ type: integer
+ tracer:
+ description: |-
+ Specify which tracer to use. One of: zipkin, lightstep, datadog, stackdriver.
+ If using stackdriver tracer outside GCP, set env GOOGLE_APPLICATION_CREDENTIALS to the GCP credential file.
+ enum:
+ - zipkin
+ - lightstep
+ - datadog
+ - stackdriver
+ - openCensusAgent
+ - none
+ type: string
+ type: object
+ proxy_init:
+ description: Specifies the Configuration for proxy_init container
+ which sets the pods' networking to intercept the inbound/outbound
+ traffic.
+ properties:
+ image:
+ description: Specifies the image for the proxy_init container.
+ type: string
+ resources:
+ description: |-
+ K8s resources settings.
+
+ See https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ properties:
+ claims:
+ description: |-
+ Claims lists the names of resources, defined in spec.resourceClaims,
+ that are used by this container.
+
+ This field depends on the
+ DynamicResourceAllocation feature gate.
+
+ This field is immutable. It can only be set for containers.
+ items:
+ description: ResourceClaim references one entry
+ in PodSpec.ResourceClaims.
+ properties:
+ name:
+ description: |-
+ Name must match the name of one entry in pod.spec.resourceClaims of
+ the Pod where this field is used. It makes that resource available
+ inside a container.
+ type: string
+ request:
+ description: |-
+ Request is the name chosen for a request in the referenced claim.
+ If empty, everything from the claim is made available, otherwise
+ only the result of this request.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - name
+ x-kubernetes-list-type: map
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Limits describes the maximum amount of compute resources allowed.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Requests describes the minimum amount of compute resources required.
+ If Requests is omitted for a container, it defaults to Limits if that is explicitly specified,
+ otherwise to an implementation-defined value. Requests cannot exceed Limits.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ type: object
+ type: object
+ remotePilotAddress:
+ description: Specifies the Istio control plane’s pilot Pod
+ IP address or remote cluster DNS resolvable hostname.
+ type: string
+ resourceScope:
+ description: |-
+ Specifies resource scope for discovery selectors.
+ This is useful when installing Istio on a cluster where some resources need to be owned by a cluster administrator and some can be owned by the mesh administrator.
+ enum:
+ - undefined
+ - all
+ - cluster
+ - namespace
+ type: string
+ revision:
+ description: Configures the revision this control plane is
+ a part of
+ type: string
+ sds:
+ description: Specifies the Configuration for the SecretDiscoveryService
+ instead of using K8S secrets to mount the certificates.
+ properties:
+ token:
+ description: 'Deprecated: Marked as deprecated in pkg/apis/values_types.proto.'
+ properties:
+ aud:
+ type: string
+ type: object
+ type: object
+ sts:
+ description: Specifies the configuration for Security Token
+ Service.
+ properties:
+ servicePort:
+ format: int32
+ type: integer
+ type: object
+ tag:
+ description: Specifies the tag for the Istio docker images.
+ type: string
+ tracer:
+ description: Specifies the Configuration for each of the supported
+ tracers.
+ properties:
+ datadog:
+ description: Configuration for the datadog tracing service.
+ properties:
+ address:
+ description: Address in host:port format for reporting
+ trace data to the Datadog agent.
+ type: string
+ type: object
+ lightstep:
+ description: Configuration for the lightstep tracing service.
+ properties:
+ accessToken:
+ description: Sets the lightstep access token.
+ type: string
+ address:
+ description: Sets the lightstep satellite pool address
+ in host:port format for reporting trace data.
+ type: string
+ type: object
+ stackdriver:
+ description: Configuration for the stackdriver tracing
+ service.
+ properties:
+ debug:
+ description: enables trace output to stdout.
+ type: boolean
+ maxNumberOfAnnotations:
+ description: The global default max number of annotation
+ events per span.
+ format: int32
+ type: integer
+ maxNumberOfAttributes:
+ description: The global default max number of attributes
+ per span.
+ format: int32
+ type: integer
+ maxNumberOfMessageEvents:
+ description: The global default max number of message
+ events per span.
+ format: int32
+ type: integer
+ type: object
+ zipkin:
+ description: Configuration for the zipkin tracing service.
+ properties:
+ address:
+ description: |-
+ Address of zipkin instance in host:port format for reporting trace data.
+
+ Example: .:941
+ type: string
+ type: object
+ type: object
+ trustBundleName:
+ description: Select a custom name for istiod's CA Root Cert
+ ConfigMap.
+ type: string
+ variant:
+ description: The variant of the Istio container images to
+ use. Options are "debug" or "distroless". Unset will use
+ the default for the given version.
+ type: string
+ waypoint:
+ description: Specifies how waypoints are configured within
+ Istio.
+ properties:
+ affinity:
+ description: |-
+ K8s affinity settings for waypoint pods.
+
+ See https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity
+ properties:
+ nodeAffinity:
+ description: Describes node affinity scheduling rules
+ for the pod.
+ properties:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ The scheduler will prefer to schedule pods to nodes that satisfy
+ the affinity expressions specified by this field, but it may choose
+ a node that violates one or more of the expressions. The node that is
+ most preferred is the one with the greatest sum of weights, i.e.
+ for each node that meets all of the scheduling requirements (resource
+ request, requiredDuringScheduling affinity expressions, etc.),
+ compute a sum by iterating through the elements of this field and adding
+ "weight" to the sum if the node matches the corresponding matchExpressions; the
+ node(s) with the highest sum are the most preferred.
+ items:
+ description: |-
+ An empty preferred scheduling term matches all objects with implicit weight 0
+ (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op).
+ properties:
+ preference:
+ description: A node selector term, associated
+ with the corresponding weight.
+ properties:
+ matchExpressions:
+ description: A list of node selector
+ requirements by node's labels.
+ items:
+ description: |-
+ A node selector requirement is a selector that contains values, a key, and an operator
+ that relates the key and values.
+ properties:
+ key:
+ description: The label key that
+ the selector applies to.
+ type: string
+ operator:
+ description: |-
+ Represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
+ type: string
+ values:
+ description: |-
+ An array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. If the operator is Gt or Lt, the values
+ array must have a single element, which will be interpreted as an integer.
+ This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchFields:
+ description: A list of node selector
+ requirements by node's fields.
+ items:
+ description: |-
+ A node selector requirement is a selector that contains values, a key, and an operator
+ that relates the key and values.
+ properties:
+ key:
+ description: The label key that
+ the selector applies to.
+ type: string
+ operator:
+ description: |-
+ Represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
+ type: string
+ values:
+ description: |-
+ An array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. If the operator is Gt or Lt, the values
+ array must have a single element, which will be interpreted as an integer.
+ This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ x-kubernetes-map-type: atomic
+ weight:
+ description: Weight associated with matching
+ the corresponding nodeSelectorTerm, in
+ the range 1-100.
+ format: int32
+ type: integer
+ required:
+ - preference
+ - weight
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ requiredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ If the affinity requirements specified by this field are not met at
+ scheduling time, the pod will not be scheduled onto the node.
+ If the affinity requirements specified by this field cease to be met
+ at some point during pod execution (e.g. due to an update), the system
+ may or may not try to eventually evict the pod from its node.
+ properties:
+ nodeSelectorTerms:
+ description: Required. A list of node selector
+ terms. The terms are ORed.
+ items:
+ description: |-
+ A null or empty node selector term matches no objects. The requirements of
+ them are ANDed.
+ The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.
+ properties:
+ matchExpressions:
+ description: A list of node selector
+ requirements by node's labels.
+ items:
+ description: |-
+ A node selector requirement is a selector that contains values, a key, and an operator
+ that relates the key and values.
+ properties:
+ key:
+ description: The label key that
+ the selector applies to.
+ type: string
+ operator:
+ description: |-
+ Represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
+ type: string
+ values:
+ description: |-
+ An array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. If the operator is Gt or Lt, the values
+ array must have a single element, which will be interpreted as an integer.
+ This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchFields:
+ description: A list of node selector
+ requirements by node's fields.
+ items:
+ description: |-
+ A node selector requirement is a selector that contains values, a key, and an operator
+ that relates the key and values.
+ properties:
+ key:
+ description: The label key that
+ the selector applies to.
+ type: string
+ operator:
+ description: |-
+ Represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
+ type: string
+ values:
+ description: |-
+ An array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. If the operator is Gt or Lt, the values
+ array must have a single element, which will be interpreted as an integer.
+ This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ x-kubernetes-map-type: atomic
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - nodeSelectorTerms
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ podAffinity:
+ description: Describes pod affinity scheduling rules
+ (e.g. co-locate this pod in the same node, zone,
+ etc. as some other pod(s)).
+ properties:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ The scheduler will prefer to schedule pods to nodes that satisfy
+ the affinity expressions specified by this field, but it may choose
+ a node that violates one or more of the expressions. The node that is
+ most preferred is the one with the greatest sum of weights, i.e.
+ for each node that meets all of the scheduling requirements (resource
+ request, requiredDuringScheduling affinity expressions, etc.),
+ compute a sum by iterating through the elements of this field and adding
+ "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the
+ node(s) with the highest sum are the most preferred.
+ items:
+ description: The weights of all of the matched
+ WeightedPodAffinityTerm fields are added per-node
+ to find the most preferred node(s)
+ properties:
+ podAffinityTerm:
+ description: Required. A pod affinity term,
+ associated with the corresponding weight.
+ properties:
+ labelSelector:
+ description: |-
+ A label query over a set of resources, in this case pods.
+ If it's null, this PodAffinityTerm matches with no Pods.
+ properties:
+ matchExpressions:
+ description: matchExpressions is
+ a list of label selector requirements.
+ The requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ matchLabelKeys:
+ description: |-
+ MatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both matchLabelKeys and labelSelector.
+ Also, matchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ mismatchLabelKeys:
+ description: |-
+ MismatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
+ Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ namespaceSelector:
+ description: |-
+ A label query over the set of namespaces that the term applies to.
+ The term is applied to the union of the namespaces selected by this field
+ and the ones listed in the namespaces field.
+ null selector and null or empty namespaces list means "this pod's namespace".
+ An empty selector ({}) matches all namespaces.
+ properties:
+ matchExpressions:
+ description: matchExpressions is
+ a list of label selector requirements.
+ The requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: |-
+ namespaces specifies a static list of namespace names that the term applies to.
+ The term is applied to the union of the namespaces listed in this field
+ and the ones selected by namespaceSelector.
+ null or empty namespaces list and null namespaceSelector means "this pod's namespace".
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ topologyKey:
+ description: |-
+ This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
+ the labelSelector in the specified namespaces, where co-located is defined as running on a node
+ whose value of the label with key topologyKey matches that of any node on which any of the
+ selected pods is running.
+ Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ weight:
+ description: |-
+ weight associated with matching the corresponding podAffinityTerm,
+ in the range 1-100.
+ format: int32
+ type: integer
+ required:
+ - podAffinityTerm
+ - weight
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ requiredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ If the affinity requirements specified by this field are not met at
+ scheduling time, the pod will not be scheduled onto the node.
+ If the affinity requirements specified by this field cease to be met
+ at some point during pod execution (e.g. due to a pod label update), the
+ system may or may not try to eventually evict the pod from its node.
+ When there are multiple elements, the lists of nodes corresponding to each
+ podAffinityTerm are intersected, i.e. all terms must be satisfied.
+ items:
+ description: |-
+ Defines a set of pods (namely those matching the labelSelector
+ relative to the given namespace(s)) that this pod should be
+ co-located (affinity) or not co-located (anti-affinity) with,
+ where co-located is defined as running on a node whose value of
+ the label with key matches that of any node on which
+ a pod of the set of pods is running
+ properties:
+ labelSelector:
+ description: |-
+ A label query over a set of resources, in this case pods.
+ If it's null, this PodAffinityTerm matches with no Pods.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The
+ requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ matchLabelKeys:
+ description: |-
+ MatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both matchLabelKeys and labelSelector.
+ Also, matchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ mismatchLabelKeys:
+ description: |-
+ MismatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
+ Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ namespaceSelector:
+ description: |-
+ A label query over the set of namespaces that the term applies to.
+ The term is applied to the union of the namespaces selected by this field
+ and the ones listed in the namespaces field.
+ null selector and null or empty namespaces list means "this pod's namespace".
+ An empty selector ({}) matches all namespaces.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The
+ requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: |-
+ namespaces specifies a static list of namespace names that the term applies to.
+ The term is applied to the union of the namespaces listed in this field
+ and the ones selected by namespaceSelector.
+ null or empty namespaces list and null namespaceSelector means "this pod's namespace".
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ topologyKey:
+ description: |-
+ This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
+ the labelSelector in the specified namespaces, where co-located is defined as running on a node
+ whose value of the label with key topologyKey matches that of any node on which any of the
+ selected pods is running.
+ Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ podAntiAffinity:
+ description: Describes pod anti-affinity scheduling
+ rules (e.g. avoid putting this pod in the same node,
+ zone, etc. as some other pod(s)).
+ properties:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ The scheduler will prefer to schedule pods to nodes that satisfy
+ the anti-affinity expressions specified by this field, but it may choose
+ a node that violates one or more of the expressions. The node that is
+ most preferred is the one with the greatest sum of weights, i.e.
+ for each node that meets all of the scheduling requirements (resource
+ request, requiredDuringScheduling anti-affinity expressions, etc.),
+ compute a sum by iterating through the elements of this field and subtracting
+ "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the
+ node(s) with the highest sum are the most preferred.
+ items:
+ description: The weights of all of the matched
+ WeightedPodAffinityTerm fields are added per-node
+ to find the most preferred node(s)
+ properties:
+ podAffinityTerm:
+ description: Required. A pod affinity term,
+ associated with the corresponding weight.
+ properties:
+ labelSelector:
+ description: |-
+ A label query over a set of resources, in this case pods.
+ If it's null, this PodAffinityTerm matches with no Pods.
+ properties:
+ matchExpressions:
+ description: matchExpressions is
+ a list of label selector requirements.
+ The requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ matchLabelKeys:
+ description: |-
+ MatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both matchLabelKeys and labelSelector.
+ Also, matchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ mismatchLabelKeys:
+ description: |-
+ MismatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
+ Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ namespaceSelector:
+ description: |-
+ A label query over the set of namespaces that the term applies to.
+ The term is applied to the union of the namespaces selected by this field
+ and the ones listed in the namespaces field.
+ null selector and null or empty namespaces list means "this pod's namespace".
+ An empty selector ({}) matches all namespaces.
+ properties:
+ matchExpressions:
+ description: matchExpressions is
+ a list of label selector requirements.
+ The requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: |-
+ namespaces specifies a static list of namespace names that the term applies to.
+ The term is applied to the union of the namespaces listed in this field
+ and the ones selected by namespaceSelector.
+ null or empty namespaces list and null namespaceSelector means "this pod's namespace".
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ topologyKey:
+ description: |-
+ This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
+ the labelSelector in the specified namespaces, where co-located is defined as running on a node
+ whose value of the label with key topologyKey matches that of any node on which any of the
+ selected pods is running.
+ Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ weight:
+ description: |-
+ weight associated with matching the corresponding podAffinityTerm,
+ in the range 1-100.
+ format: int32
+ type: integer
+ required:
+ - podAffinityTerm
+ - weight
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ requiredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ If the anti-affinity requirements specified by this field are not met at
+ scheduling time, the pod will not be scheduled onto the node.
+ If the anti-affinity requirements specified by this field cease to be met
+ at some point during pod execution (e.g. due to a pod label update), the
+ system may or may not try to eventually evict the pod from its node.
+ When there are multiple elements, the lists of nodes corresponding to each
+ podAffinityTerm are intersected, i.e. all terms must be satisfied.
+ items:
+ description: |-
+ Defines a set of pods (namely those matching the labelSelector
+ relative to the given namespace(s)) that this pod should be
+ co-located (affinity) or not co-located (anti-affinity) with,
+ where co-located is defined as running on a node whose value of
+ the label with key matches that of any node on which
+ a pod of the set of pods is running
+ properties:
+ labelSelector:
+ description: |-
+ A label query over a set of resources, in this case pods.
+ If it's null, this PodAffinityTerm matches with no Pods.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The
+ requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ matchLabelKeys:
+ description: |-
+ MatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both matchLabelKeys and labelSelector.
+ Also, matchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ mismatchLabelKeys:
+ description: |-
+ MismatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
+ Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ namespaceSelector:
+ description: |-
+ A label query over the set of namespaces that the term applies to.
+ The term is applied to the union of the namespaces selected by this field
+ and the ones listed in the namespaces field.
+ null selector and null or empty namespaces list means "this pod's namespace".
+ An empty selector ({}) matches all namespaces.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The
+ requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: |-
+ namespaces specifies a static list of namespace names that the term applies to.
+ The term is applied to the union of the namespaces listed in this field
+ and the ones selected by namespaceSelector.
+ null or empty namespaces list and null namespaceSelector means "this pod's namespace".
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ topologyKey:
+ description: |-
+ This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
+ the labelSelector in the specified namespaces, where co-located is defined as running on a node
+ whose value of the label with key topologyKey matches that of any node on which any of the
+ selected pods is running.
+ Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ type: object
+ nodeSelector:
+ description: |-
+ K8s node labels settings.
+
+ See https://kubernetes.io/docs/user-guide/node-selection/
+ properties:
+ nodeSelectorTerms:
+ description: Required. A list of node selector terms.
+ The terms are ORed.
+ items:
+ description: |-
+ A null or empty node selector term matches no objects. The requirements of
+ them are ANDed.
+ The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.
+ properties:
+ matchExpressions:
+ description: A list of node selector requirements
+ by node's labels.
+ items:
+ description: |-
+ A node selector requirement is a selector that contains values, a key, and an operator
+ that relates the key and values.
+ properties:
+ key:
+ description: The label key that the selector
+ applies to.
+ type: string
+ operator:
+ description: |-
+ Represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
+ type: string
+ values:
+ description: |-
+ An array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. If the operator is Gt or Lt, the values
+ array must have a single element, which will be interpreted as an integer.
+ This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchFields:
+ description: A list of node selector requirements
+ by node's fields.
+ items:
+ description: |-
+ A node selector requirement is a selector that contains values, a key, and an operator
+ that relates the key and values.
+ properties:
+ key:
+ description: The label key that the selector
+ applies to.
+ type: string
+ operator:
+ description: |-
+ Represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
+ type: string
+ values:
+ description: |-
+ An array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. If the operator is Gt or Lt, the values
+ array must have a single element, which will be interpreted as an integer.
+ This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ x-kubernetes-map-type: atomic
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - nodeSelectorTerms
+ type: object
+ x-kubernetes-map-type: atomic
+ resources:
+ description: |-
+ K8s resource settings.
+
+ See https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container
+ properties:
+ claims:
+ description: |-
+ Claims lists the names of resources, defined in spec.resourceClaims,
+ that are used by this container.
+
+ This field depends on the
+ DynamicResourceAllocation feature gate.
+
+ This field is immutable. It can only be set for containers.
+ items:
+ description: ResourceClaim references one entry
+ in PodSpec.ResourceClaims.
+ properties:
+ name:
+ description: |-
+ Name must match the name of one entry in pod.spec.resourceClaims of
+ the Pod where this field is used. It makes that resource available
+ inside a container.
+ type: string
+ request:
+ description: |-
+ Request is the name chosen for a request in the referenced claim.
+ If empty, everything from the claim is made available, otherwise
+ only the result of this request.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - name
+ x-kubernetes-list-type: map
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Limits describes the maximum amount of compute resources allowed.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Requests describes the minimum amount of compute resources required.
+ If Requests is omitted for a container, it defaults to Limits if that is explicitly specified,
+ otherwise to an implementation-defined value. Requests cannot exceed Limits.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ type: object
+ toleration:
+ description: |-
+ K8s tolerations settings.
+
+ See https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
+ items:
+ description: |-
+ The pod this Toleration is attached to tolerates any taint that matches
+ the triple using the matching operator .
+ properties:
+ effect:
+ description: |-
+ Effect indicates the taint effect to match. Empty means match all taint effects.
+ When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.
+ type: string
+ key:
+ description: |-
+ Key is the taint key that the toleration applies to. Empty means match all taint keys.
+ If the key is empty, operator must be Exists; this combination means to match all values and all keys.
+ type: string
+ operator:
+ description: |-
+ Operator represents a key's relationship to the value.
+ Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal.
+ Exists is equivalent to wildcard for value, so that a pod can
+ tolerate all taints of a particular category.
+ Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators).
+ type: string
+ tolerationSeconds:
+ description: |-
+ TolerationSeconds represents the period of time the toleration (which must be
+ of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default,
+ it is not set, which means tolerate the taint forever (do not evict). Zero and
+ negative values will be treated as 0 (evict immediately) by the system.
+ format: int64
+ type: integer
+ value:
+ description: |-
+ Value is the taint value the toleration matches to.
+ If the operator is Exists, the value should be empty, otherwise just a regular string.
+ type: string
+ type: object
+ type: array
+ topologySpreadConstraints:
+ description: |-
+ K8s topology spread constraints settings.
+
+ See https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/
+ items:
+ description: TopologySpreadConstraint specifies how
+ to spread matching pods among the given topology.
+ properties:
+ labelSelector:
+ description: |-
+ LabelSelector is used to find matching pods.
+ Pods that match this label selector are counted to determine the number of pods
+ in their corresponding topology domain.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label
+ selector requirements. The requirements are
+ ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label key that
+ the selector applies to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ matchLabelKeys:
+ description: |-
+ MatchLabelKeys is a set of pod label keys to select the pods over which
+ spreading will be calculated. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are ANDed with labelSelector
+ to select the group of existing pods over which spreading will be calculated
+ for the incoming pod. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector.
+ MatchLabelKeys cannot be set when LabelSelector isn't set.
+ Keys that don't exist in the incoming pod labels will
+ be ignored. A null or empty list means only match against labelSelector.
+
+ This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default).
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ maxSkew:
+ description: |-
+ MaxSkew describes the degree to which pods may be unevenly distributed.
+ When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference
+ between the number of matching pods in the target topology and the global minimum.
+ The global minimum is the minimum number of matching pods in an eligible domain
+ or zero if the number of eligible domains is less than MinDomains.
+ For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same
+ labelSelector spread as 2/2/1:
+ In this case, the global minimum is 1.
+ | zone1 | zone2 | zone3 |
+ | P P | P P | P |
+ - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2;
+ scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2)
+ violate MaxSkew(1).
+ - if MaxSkew is 2, incoming pod can be scheduled onto any zone.
+ When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence
+ to topologies that satisfy it.
+ It's a required field. Default value is 1 and 0 is not allowed.
+ format: int32
+ type: integer
+ minDomains:
+ description: |-
+ MinDomains indicates a minimum number of eligible domains.
+ When the number of eligible domains with matching topology keys is less than minDomains,
+ Pod Topology Spread treats "global minimum" as 0, and then the calculation of Skew is performed.
+ And when the number of eligible domains with matching topology keys equals or greater than minDomains,
+ this value has no effect on scheduling.
+ As a result, when the number of eligible domains is less than minDomains,
+ scheduler won't schedule more than maxSkew Pods to those domains.
+ If value is nil, the constraint behaves as if MinDomains is equal to 1.
+ Valid values are integers greater than 0.
+ When value is not nil, WhenUnsatisfiable must be DoNotSchedule.
+
+ For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same
+ labelSelector spread as 2/2/2:
+ | zone1 | zone2 | zone3 |
+ | P P | P P | P P |
+ The number of domains is less than 5(MinDomains), so "global minimum" is treated as 0.
+ In this situation, new pod with the same labelSelector cannot be scheduled,
+ because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones,
+ it will violate MaxSkew.
+ format: int32
+ type: integer
+ nodeAffinityPolicy:
+ description: |-
+ NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector
+ when calculating pod topology spread skew. Options are:
+ - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations.
+ - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations.
+
+ If this value is nil, the behavior is equivalent to the Honor policy.
+ type: string
+ nodeTaintsPolicy:
+ description: |-
+ NodeTaintsPolicy indicates how we will treat node taints when calculating
+ pod topology spread skew. Options are:
+ - Honor: nodes without taints, along with tainted nodes for which the incoming pod
+ has a toleration, are included.
+ - Ignore: node taints are ignored. All nodes are included.
+
+ If this value is nil, the behavior is equivalent to the Ignore policy.
+ type: string
+ topologyKey:
+ description: |-
+ TopologyKey is the key of node labels. Nodes that have a label with this key
+ and identical values are considered to be in the same topology.
+ We consider each as a "bucket", and try to put balanced number
+ of pods into each bucket.
+ We define a domain as a particular instance of a topology.
+ Also, we define an eligible domain as a domain whose nodes meet the requirements of
+ nodeAffinityPolicy and nodeTaintsPolicy.
+ e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology.
+ And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology.
+ It's a required field.
+ type: string
+ whenUnsatisfiable:
+ description: |-
+ WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy
+ the spread constraint.
+ - DoNotSchedule (default) tells the scheduler not to schedule it.
+ - ScheduleAnyway tells the scheduler to schedule the pod in any location,
+ but giving higher precedence to topologies that would help reduce the
+ skew.
+ A constraint is considered "Unsatisfiable" for an incoming pod
+ if and only if every possible node assignment for that pod would violate
+ "MaxSkew" on some topology.
+ For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same
+ labelSelector spread as 3/1/1:
+ | zone1 | zone2 | zone3 |
+ | P P P | P | P |
+ If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled
+ to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies
+ MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler
+ won't make it *more* imbalanced.
+ It's a required field.
+ type: string
+ required:
+ - maxSkew
+ - topologyKey
+ - whenUnsatisfiable
+ type: object
+ type: array
+ type: object
+ type: object
+ istiodRemote:
+ description: |-
+ Configuration for istiod-remote.
+ DEPRECATED - istiod-remote chart is removed and replaced with
+ `istio-discovery --set values.istiodRemote.enabled=true`
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ properties:
+ enabled:
+ description: Indicates if this cluster/install should consume
+ a "remote" istiod instance,
+ type: boolean
+ enabledLocalInjectorIstiod:
+ description: |-
+ If `true`, indicates that this cluster/install should consume a "local istiod" installation,
+ local istiod inject sidecars
+ type: boolean
+ injectionCABundle:
+ description: injector ca bundle
+ type: string
+ injectionPath:
+ description: Path to use for the sidecar injector webhook
+ service.
+ type: string
+ injectionURL:
+ description: URL to use for sidecar injector webhook.
+ type: string
+ type: object
+ meshConfig:
+ description: |-
+ Defines runtime configuration of components, including Istiod and istio-agent behavior.
+ See https://istio.io/docs/reference/config/istio.mesh.v1alpha1/ for all available options.
+ properties:
+ accessLogEncoding:
+ description: |-
+ Encoding for the proxy access log (`TEXT` or `JSON`).
+ Default value is `TEXT`.
+ enum:
+ - TEXT
+ - JSON
+ type: string
+ accessLogFile:
+ description: |-
+ File address for the proxy access log (e.g. /dev/stdout).
+ Empty value disables access logging.
+ type: string
+ accessLogFormat:
+ description: |-
+ Format for the proxy access log
+ Empty value results in proxy's default access log format
+ type: string
+ ca:
+ description: |-
+ If specified, Istiod will authorize and forward the CSRs from the workloads to the specified external CA
+ using the Istio CA gRPC API.
+ properties:
+ address:
+ description: |-
+ REQUIRED. Address of the CA server implementing the Istio CA gRPC API.
+ Can be IP address or a fully qualified DNS name with port
+ Eg: custom-ca.default.svc.cluster.local:8932, 192.168.23.2:9000
+ type: string
+ istiodSide:
+ description: |-
+ Use istiodSide to specify CA Server integrate to Istiod side or Agent side
+ Default: true
+ type: boolean
+ requestTimeout:
+ description: |-
+ timeout for forward CSR requests from Istiod to External CA
+ Default: 10s
+ type: string
+ tlsSettings:
+ description: |-
+ Use the tlsSettings to specify the tls mode to use.
+ Regarding tlsSettings:
+ - DISABLE MODE is legitimate for the case Istiod is making the request via an Envoy sidecar.
+ DISABLE MODE can also be used for testing
+ - TLS MUTUAL MODE be on by default. If the CA certificates
+ (cert bundle to verify the CA server's certificate) is omitted, Istiod will
+ use the system root certs to verify the CA server's certificate.
+ properties:
+ caCertificates:
+ description: |-
+ OPTIONAL: The path to the file containing certificate authority
+ certificates to use in verifying a presented server certificate. If
+ omitted, the proxy will verify the server's certificate using
+ the OS CA certificates.
+ Should be empty if mode is `ISTIO_MUTUAL`.
+ type: string
+ caCrl:
+ description: |-
+ OPTIONAL: The path to the file containing the certificate revocation list (CRL)
+ to use in verifying a presented server certificate. `CRL` is a list of certificates
+ that have been revoked by the CA (Certificate Authority) before their scheduled expiration date.
+ If specified, the proxy will verify if the presented certificate is part of the revoked list of certificates.
+ If omitted, the proxy will not verify the certificate against the `crl`. Note that if `credentialName` is set,
+ `CRL` cannot be specified using `caCrl`, rather it has to be specified inside the credential.
+ type: string
+ clientCertificate:
+ description: |-
+ REQUIRED if mode is `MUTUAL`. The path to the file holding the
+ client-side TLS certificate to use.
+ Should be empty if mode is `ISTIO_MUTUAL`.
+ type: string
+ credentialName:
+ description: |-
+ The name of the secret that holds the TLS certs for the
+ client including the CA certificates. This secret must exist in
+ the namespace of the proxy using the certificates.
+ An Opaque secret should contain the following keys and values:
+ `key: `, `cert: `, `cacert: `,
+ `crl: `
+ Here CACertificate is used to verify the server certificate.
+ For mutual TLS, `cacert: ` can be provided in the
+ same secret or a separate secret named `-cacert`.
+ A TLS secret for client certificates with an additional
+ `ca.crt` key for CA certificates and `ca.crl` key for
+ certificate revocation list(CRL) is also supported.
+ Only one of client certificates and CA certificate
+ or credentialName can be specified.
+
+ **NOTE:** This field is applicable at sidecars only if
+ `DestinationRule` has a `workloadSelector` specified.
+ Otherwise the field will be applicable only at gateways, and
+ sidecars will continue to use the certificate paths.
+ type: string
+ insecureSkipVerify:
+ description: |-
+ `insecureSkipVerify` specifies whether the proxy should skip verifying the
+ CA signature and SAN for the server certificate corresponding to the host.
+ The default value of this field is false.
+ type: boolean
+ mode:
+ description: |-
+ Indicates whether connections to this port should be secured
+ using TLS. The value of this field determines how TLS is enforced.
+ enum:
+ - DISABLE
+ - SIMPLE
+ - MUTUAL
+ - ISTIO_MUTUAL
+ type: string
+ privateKey:
+ description: |-
+ REQUIRED if mode is `MUTUAL`. The path to the file holding the
+ client's private key.
+ Should be empty if mode is `ISTIO_MUTUAL`.
+ type: string
+ sni:
+ description: |-
+ SNI string to present to the server during TLS handshake.
+ If unspecified, SNI will be automatically set based on downstream HTTP
+ host/authority header for SIMPLE and MUTUAL TLS modes.
+ type: string
+ subjectAltNames:
+ description: |-
+ A list of alternate names to verify the subject identity in the
+ certificate. If specified, the proxy will verify that the server
+ certificate's subject alt name matches one of the specified values.
+ If specified, this list overrides the value of `subjectAltNames`
+ from the `ServiceEntry`. If unspecified, automatic validation of upstream
+ presented certificate for new upstream connections will be done based on the
+ downstream HTTP host/authority header.
+ items:
+ type: string
+ type: array
+ type: object
+ required:
+ - address
+ type: object
+ caCertificates:
+ description: |-
+ The extra root certificates for workload-to-workload communication.
+ The plugin certificates (the 'cacerts' secret) or self-signed certificates (the 'istio-ca-secret' secret)
+ are automatically added by Istiod.
+ The CA certificate that signs the workload certificates is automatically added by Istio Agent.
+ items:
+ properties:
+ certSigners:
+ description: |-
+ when Istiod is acting as RA(registration authority)
+ If set, they are used for these signers. Otherwise, this trustAnchor is used for all signers.
+ items:
+ type: string
+ type: array
+ pem:
+ description: The PEM data of the certificate.
+ type: string
+ spiffeBundleUrl:
+ description: |-
+ The SPIFFE bundle endpoint URL that complies to:
+ https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE_Trust_Domain_and_Bundle.md#the-spiffe-trust-domain-and-bundle
+ The endpoint should support authentication based on Web PKI:
+ https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE_Trust_Domain_and_Bundle.md#521-web-pki
+ The certificate is retrieved from the endpoint.
+ type: string
+ trustDomains:
+ description: |-
+ Optional. Specify the list of trust domains to which this trustAnchor data belongs.
+ If set, they are used for these trust domains. Otherwise, this trustAnchor is used for default trust domain
+ and its aliases.
+ Note that we can have multiple trustAnchor data for a same trustDomain.
+ In that case, trustAnchors with a same trust domain will be merged and used together to verify peer certificates.
+ If neither certSigners nor trustDomains is set, this trustAnchor is used for all trust domains and all signers.
+ If only trustDomains is set, this trustAnchor is used for these trustDomains and all signers.
+ If only certSigners is set, this trustAnchor is used for these certSigners and all trust domains.
+ If both certSigners and trustDomains is set, this trustAnchor is only used for these signers and trust domains.
+ items:
+ type: string
+ type: array
+ type: object
+ x-kubernetes-validations:
+ - message: At most one of [pem spiffeBundleUrl] should be
+ set
+ rule: (has(self.pem)?1:0) + (has(self.spiffeBundleUrl)?1:0)
+ <= 1
+ type: array
+ certificates:
+ description: |-
+ Configure the provision of certificates.
+
+ Note: Deprecated, please refer to Cert-Manager or other cert provisioning solutions to sign DNS certificates.
+
+ Deprecated: Marked as deprecated in mesh/v1alpha1/config.proto.
+ items:
+ description: "Certificate configures the provision of a
+ certificate and its key.\nExample 1: key and cert stored
+ in a secret\n```\n{ secretName: galley-cert\n\n\t secretNamespace:
+ istio-system\n\t dnsNames:\n\t - galley.istio-system.svc\n\t
+ \ - galley.mydomain.com\n\t}\n\n```\nExample 2: key
+ and cert stored in a directory\n```\n{ dnsNames:\n -
+ pilot.istio-system\n - pilot.istio-system.svc\n - pilot.mydomain.com\n
+ \ }\n\n```"
+ properties:
+ dnsNames:
+ description: |-
+ The DNS names for the certificate. A certificate may contain
+ multiple DNS names.
+ items:
+ type: string
+ type: array
+ secretName:
+ description: |-
+ Name of the secret the certificate and its key will be stored into.
+ If it is empty, it will not be stored into a secret.
+ Instead, the certificate and its key will be stored into a hard-coded directory.
+ type: string
+ type: object
+ type: array
+ configSources:
+ description: |-
+ ConfigSource describes a source of configuration data for networking
+ rules, and other Istio configuration artifacts. Multiple data sources
+ can be configured for a single control plane.
+ items:
+ description: |-
+ ConfigSource describes information about a configuration store inside a
+ mesh. A single control plane instance can interact with one or more data
+ sources.
+ properties:
+ address:
+ description: |-
+ Address of the server implementing the Istio Mesh Configuration
+ protocol (MCP). Can be IP address or a fully qualified DNS name.
+ Use xds:// to specify a grpc-based xds backend, k8s:// to specify a k8s controller or
+ fs:/// to specify a file-based backend with absolute path to the directory.
+ type: string
+ subscribedResources:
+ description: Describes the source of configuration,
+ if nothing is specified default is MCP
+ items:
+ description: Resource describes the source of configuration
+ enum:
+ - SERVICE_REGISTRY
+ type: string
+ type: array
+ tlsSettings:
+ description: |-
+ Use the tlsSettings to specify the tls mode to use. If the MCP server
+ uses Istio mutual TLS and shares the root CA with istiod, specify the TLS
+ mode as `ISTIO_MUTUAL`.
+ properties:
+ caCertificates:
+ description: |-
+ OPTIONAL: The path to the file containing certificate authority
+ certificates to use in verifying a presented server certificate. If
+ omitted, the proxy will verify the server's certificate using
+ the OS CA certificates.
+ Should be empty if mode is `ISTIO_MUTUAL`.
+ type: string
+ caCrl:
+ description: |-
+ OPTIONAL: The path to the file containing the certificate revocation list (CRL)
+ to use in verifying a presented server certificate. `CRL` is a list of certificates
+ that have been revoked by the CA (Certificate Authority) before their scheduled expiration date.
+ If specified, the proxy will verify if the presented certificate is part of the revoked list of certificates.
+ If omitted, the proxy will not verify the certificate against the `crl`. Note that if `credentialName` is set,
+ `CRL` cannot be specified using `caCrl`, rather it has to be specified inside the credential.
+ type: string
+ clientCertificate:
+ description: |-
+ REQUIRED if mode is `MUTUAL`. The path to the file holding the
+ client-side TLS certificate to use.
+ Should be empty if mode is `ISTIO_MUTUAL`.
+ type: string
+ credentialName:
+ description: |-
+ The name of the secret that holds the TLS certs for the
+ client including the CA certificates. This secret must exist in
+ the namespace of the proxy using the certificates.
+ An Opaque secret should contain the following keys and values:
+ `key: `, `cert: `, `cacert: `,
+ `crl: `
+ Here CACertificate is used to verify the server certificate.
+ For mutual TLS, `cacert: ` can be provided in the
+ same secret or a separate secret named `-cacert`.
+ A TLS secret for client certificates with an additional
+ `ca.crt` key for CA certificates and `ca.crl` key for
+ certificate revocation list(CRL) is also supported.
+ Only one of client certificates and CA certificate
+ or credentialName can be specified.
+
+ **NOTE:** This field is applicable at sidecars only if
+ `DestinationRule` has a `workloadSelector` specified.
+ Otherwise the field will be applicable only at gateways, and
+ sidecars will continue to use the certificate paths.
+ type: string
+ insecureSkipVerify:
+ description: |-
+ `insecureSkipVerify` specifies whether the proxy should skip verifying the
+ CA signature and SAN for the server certificate corresponding to the host.
+ The default value of this field is false.
+ type: boolean
+ mode:
+ description: |-
+ Indicates whether connections to this port should be secured
+ using TLS. The value of this field determines how TLS is enforced.
+ enum:
+ - DISABLE
+ - SIMPLE
+ - MUTUAL
+ - ISTIO_MUTUAL
+ type: string
+ privateKey:
+ description: |-
+ REQUIRED if mode is `MUTUAL`. The path to the file holding the
+ client's private key.
+ Should be empty if mode is `ISTIO_MUTUAL`.
+ type: string
+ sni:
+ description: |-
+ SNI string to present to the server during TLS handshake.
+ If unspecified, SNI will be automatically set based on downstream HTTP
+ host/authority header for SIMPLE and MUTUAL TLS modes.
+ type: string
+ subjectAltNames:
+ description: |-
+ A list of alternate names to verify the subject identity in the
+ certificate. If specified, the proxy will verify that the server
+ certificate's subject alt name matches one of the specified values.
+ If specified, this list overrides the value of `subjectAltNames`
+ from the `ServiceEntry`. If unspecified, automatic validation of upstream
+ presented certificate for new upstream connections will be done based on the
+ downstream HTTP host/authority header.
+ items:
+ type: string
+ type: array
+ type: object
+ type: object
+ type: array
+ connectTimeout:
+ description: |-
+ Connection timeout used by Envoy. (MUST be >=1ms)
+ Default timeout is 10s.
+ type: string
+ defaultConfig:
+ description: |-
+ Default proxy config used by gateway and sidecars.
+ In case of Kubernetes, the proxy config is applied once during the injection process,
+ and remain constant for the duration of the pod. The rest of the mesh config can be changed
+ at runtime and config gets distributed dynamically.
+ On Kubernetes, this can be overridden on individual pods with the `proxy.istio.io/config` annotation.
+ properties:
+ availabilityZone:
+ description: 'Deprecated: Marked as deprecated in mesh/v1alpha1/proxy.proto.'
+ type: string
+ binaryPath:
+ description: Path to the proxy binary
+ type: string
+ caCertificatesPem:
+ description: |-
+ The PEM data of the extra root certificates for workload-to-workload communication.
+ This includes the certificates defined in MeshConfig and any other certificates that Istiod uses as CA.
+ The plugin certificates (the 'cacerts' secret), self-signed certificates (the 'istio-ca-secret' secret)
+ are added automatically by Istiod.
+ items:
+ type: string
+ type: array
+ concurrency:
+ description: |-
+ The number of worker threads to run.
+ If unset, which is recommended, this will be automatically determined based on CPU requests/limits.
+ If set to 0, all cores on the machine will be used, ignoring CPU requests or limits. This can lead to major performance
+ issues if CPU limits are also set.
+ format: int32
+ type: integer
+ configPath:
+ description: |-
+ Path to the generated configuration file directory.
+ Proxy agent generates the actual configuration and stores it in this directory.
+ type: string
+ controlPlaneAuthPolicy:
+ description: |-
+ AuthenticationPolicy defines how the proxy is authenticated when it connects to the control plane.
+ Default is set to `MUTUAL_TLS`.
+ enum:
+ - NONE
+ - MUTUAL_TLS
+ - INHERIT
+ type: string
+ customConfigFile:
+ description: |-
+ File path of custom proxy configuration, currently used by proxies
+ in front of istiod.
+ type: string
+ discoveryAddress:
+ description: |-
+ Address of the discovery service exposing xDS with mTLS connection.
+ The inject configuration may override this value.
+ type: string
+ discoveryRefreshDelay:
+ description: 'Deprecated: Marked as deprecated in mesh/v1alpha1/proxy.proto.'
+ type: string
+ drainDuration:
+ description: |-
+ restart. MUST be >=1s (e.g., _1s/1m/1h_)
+ Default drain duration is `45s`.
+ type: string
+ envoyAccessLogService:
+ description: |-
+ Address of the service to which access logs from Envoys should be
+ sent. (e.g. `accesslog-service:15000`). See [Access Log
+ Service](https://www.envoyproxy.io/docs/envoy/latest/api-v2/config/accesslog/v2/als.proto)
+ for details about Envoy's gRPC Access Log Service API.
+ properties:
+ address:
+ description: |-
+ Address of a remove service used for various purposes (access log
+ receiver, metrics receiver, etc.). Can be IP address or a fully
+ qualified DNS name.
+ type: string
+ tcpKeepalive:
+ description: If set then set `SO_KEEPALIVE` on the
+ socket to enable TCP Keepalives.
+ properties:
+ interval:
+ description: |-
+ The time duration between keep-alive probes.
+ Default is to use the OS level configuration
+ (unless overridden, Linux defaults to 75s.)
+ type: string
+ probes:
+ description: |-
+ Maximum number of keepalive probes to send without response before
+ deciding the connection is dead. Default is to use the OS level configuration
+ (unless overridden, Linux defaults to 9.)
+ format: int32
+ type: integer
+ time:
+ description: |-
+ The time duration a connection needs to be idle before keep-alive
+ probes start being sent. Default is to use the OS level configuration
+ (unless overridden, Linux defaults to 7200s (ie 2 hours.)
+ type: string
+ type: object
+ tlsSettings:
+ description: |-
+ Use the `tlsSettings` to specify the tls mode to use. If the remote service
+ uses Istio mutual TLS and shares the root CA with istiod, specify the TLS
+ mode as `ISTIO_MUTUAL`.
+ properties:
+ caCertificates:
+ description: |-
+ OPTIONAL: The path to the file containing certificate authority
+ certificates to use in verifying a presented server certificate. If
+ omitted, the proxy will verify the server's certificate using
+ the OS CA certificates.
+ Should be empty if mode is `ISTIO_MUTUAL`.
+ type: string
+ caCrl:
+ description: |-
+ OPTIONAL: The path to the file containing the certificate revocation list (CRL)
+ to use in verifying a presented server certificate. `CRL` is a list of certificates
+ that have been revoked by the CA (Certificate Authority) before their scheduled expiration date.
+ If specified, the proxy will verify if the presented certificate is part of the revoked list of certificates.
+ If omitted, the proxy will not verify the certificate against the `crl`. Note that if `credentialName` is set,
+ `CRL` cannot be specified using `caCrl`, rather it has to be specified inside the credential.
+ type: string
+ clientCertificate:
+ description: |-
+ REQUIRED if mode is `MUTUAL`. The path to the file holding the
+ client-side TLS certificate to use.
+ Should be empty if mode is `ISTIO_MUTUAL`.
+ type: string
+ credentialName:
+ description: |-
+ The name of the secret that holds the TLS certs for the
+ client including the CA certificates. This secret must exist in
+ the namespace of the proxy using the certificates.
+ An Opaque secret should contain the following keys and values:
+ `key: `, `cert: `, `cacert: `,
+ `crl: `
+ Here CACertificate is used to verify the server certificate.
+ For mutual TLS, `cacert: ` can be provided in the
+ same secret or a separate secret named `-cacert`.
+ A TLS secret for client certificates with an additional
+ `ca.crt` key for CA certificates and `ca.crl` key for
+ certificate revocation list(CRL) is also supported.
+ Only one of client certificates and CA certificate
+ or credentialName can be specified.
+
+ **NOTE:** This field is applicable at sidecars only if
+ `DestinationRule` has a `workloadSelector` specified.
+ Otherwise the field will be applicable only at gateways, and
+ sidecars will continue to use the certificate paths.
+ type: string
+ insecureSkipVerify:
+ description: |-
+ `insecureSkipVerify` specifies whether the proxy should skip verifying the
+ CA signature and SAN for the server certificate corresponding to the host.
+ The default value of this field is false.
+ type: boolean
+ mode:
+ description: |-
+ Indicates whether connections to this port should be secured
+ using TLS. The value of this field determines how TLS is enforced.
+ enum:
+ - DISABLE
+ - SIMPLE
+ - MUTUAL
+ - ISTIO_MUTUAL
+ type: string
+ privateKey:
+ description: |-
+ REQUIRED if mode is `MUTUAL`. The path to the file holding the
+ client's private key.
+ Should be empty if mode is `ISTIO_MUTUAL`.
+ type: string
+ sni:
+ description: |-
+ SNI string to present to the server during TLS handshake.
+ If unspecified, SNI will be automatically set based on downstream HTTP
+ host/authority header for SIMPLE and MUTUAL TLS modes.
+ type: string
+ subjectAltNames:
+ description: |-
+ A list of alternate names to verify the subject identity in the
+ certificate. If specified, the proxy will verify that the server
+ certificate's subject alt name matches one of the specified values.
+ If specified, this list overrides the value of `subjectAltNames`
+ from the `ServiceEntry`. If unspecified, automatic validation of upstream
+ presented certificate for new upstream connections will be done based on the
+ downstream HTTP host/authority header.
+ items:
+ type: string
+ type: array
+ type: object
+ type: object
+ envoyMetricsService:
+ description: |-
+ Address of the Envoy Metrics Service implementation (e.g. `metrics-service:15000`).
+ See [Metric Service](https://www.envoyproxy.io/docs/envoy/latest/api-v2/config/metrics/v2/metrics_service.proto)
+ for details about Envoy's Metrics Service API.
+ properties:
+ address:
+ description: |-
+ Address of a remove service used for various purposes (access log
+ receiver, metrics receiver, etc.). Can be IP address or a fully
+ qualified DNS name.
+ type: string
+ tcpKeepalive:
+ description: If set then set `SO_KEEPALIVE` on the
+ socket to enable TCP Keepalives.
+ properties:
+ interval:
+ description: |-
+ The time duration between keep-alive probes.
+ Default is to use the OS level configuration
+ (unless overridden, Linux defaults to 75s.)
+ type: string
+ probes:
+ description: |-
+ Maximum number of keepalive probes to send without response before
+ deciding the connection is dead. Default is to use the OS level configuration
+ (unless overridden, Linux defaults to 9.)
+ format: int32
+ type: integer
+ time:
+ description: |-
+ The time duration a connection needs to be idle before keep-alive
+ probes start being sent. Default is to use the OS level configuration
+ (unless overridden, Linux defaults to 7200s (ie 2 hours.)
+ type: string
+ type: object
+ tlsSettings:
+ description: |-
+ Use the `tlsSettings` to specify the tls mode to use. If the remote service
+ uses Istio mutual TLS and shares the root CA with istiod, specify the TLS
+ mode as `ISTIO_MUTUAL`.
+ properties:
+ caCertificates:
+ description: |-
+ OPTIONAL: The path to the file containing certificate authority
+ certificates to use in verifying a presented server certificate. If
+ omitted, the proxy will verify the server's certificate using
+ the OS CA certificates.
+ Should be empty if mode is `ISTIO_MUTUAL`.
+ type: string
+ caCrl:
+ description: |-
+ OPTIONAL: The path to the file containing the certificate revocation list (CRL)
+ to use in verifying a presented server certificate. `CRL` is a list of certificates
+ that have been revoked by the CA (Certificate Authority) before their scheduled expiration date.
+ If specified, the proxy will verify if the presented certificate is part of the revoked list of certificates.
+ If omitted, the proxy will not verify the certificate against the `crl`. Note that if `credentialName` is set,
+ `CRL` cannot be specified using `caCrl`, rather it has to be specified inside the credential.
+ type: string
+ clientCertificate:
+ description: |-
+ REQUIRED if mode is `MUTUAL`. The path to the file holding the
+ client-side TLS certificate to use.
+ Should be empty if mode is `ISTIO_MUTUAL`.
+ type: string
+ credentialName:
+ description: |-
+ The name of the secret that holds the TLS certs for the
+ client including the CA certificates. This secret must exist in
+ the namespace of the proxy using the certificates.
+ An Opaque secret should contain the following keys and values:
+ `key: `, `cert: `, `cacert: `,
+ `crl: `
+ Here CACertificate is used to verify the server certificate.
+ For mutual TLS, `cacert: ` can be provided in the
+ same secret or a separate secret named `-cacert`.
+ A TLS secret for client certificates with an additional
+ `ca.crt` key for CA certificates and `ca.crl` key for
+ certificate revocation list(CRL) is also supported.
+ Only one of client certificates and CA certificate
+ or credentialName can be specified.
+
+ **NOTE:** This field is applicable at sidecars only if
+ `DestinationRule` has a `workloadSelector` specified.
+ Otherwise the field will be applicable only at gateways, and
+ sidecars will continue to use the certificate paths.
+ type: string
+ insecureSkipVerify:
+ description: |-
+ `insecureSkipVerify` specifies whether the proxy should skip verifying the
+ CA signature and SAN for the server certificate corresponding to the host.
+ The default value of this field is false.
+ type: boolean
+ mode:
+ description: |-
+ Indicates whether connections to this port should be secured
+ using TLS. The value of this field determines how TLS is enforced.
+ enum:
+ - DISABLE
+ - SIMPLE
+ - MUTUAL
+ - ISTIO_MUTUAL
+ type: string
+ privateKey:
+ description: |-
+ REQUIRED if mode is `MUTUAL`. The path to the file holding the
+ client's private key.
+ Should be empty if mode is `ISTIO_MUTUAL`.
+ type: string
+ sni:
+ description: |-
+ SNI string to present to the server during TLS handshake.
+ If unspecified, SNI will be automatically set based on downstream HTTP
+ host/authority header for SIMPLE and MUTUAL TLS modes.
+ type: string
+ subjectAltNames:
+ description: |-
+ A list of alternate names to verify the subject identity in the
+ certificate. If specified, the proxy will verify that the server
+ certificate's subject alt name matches one of the specified values.
+ If specified, this list overrides the value of `subjectAltNames`
+ from the `ServiceEntry`. If unspecified, automatic validation of upstream
+ presented certificate for new upstream connections will be done based on the
+ downstream HTTP host/authority header.
+ items:
+ type: string
+ type: array
+ type: object
+ type: object
+ envoyMetricsServiceAddress:
+ description: 'Deprecated: Marked as deprecated in mesh/v1alpha1/proxy.proto.'
+ type: string
+ extraStatTags:
+ description: |-
+ An additional list of tags to extract from the in-proxy Istio telemetry. These extra tags can be
+ added by configuring the telemetry extension. Each additional tag needs to be present in this list.
+ Extra tags emitted by the telemetry extensions must be listed here so that they can be processed
+ and exposed as Prometheus metrics.
+ Deprecated: `istio.stats` is a native filter now, this field is no longer needed.
+ items:
+ type: string
+ type: array
+ fileFlushInterval:
+ description: |-
+ File flush interval for envoy flushes buffers to disk in milliseconds.
+ The duration needs to be set to a value greater than or equal to 1 millisecond.
+ Default is 1000ms.
+ Optional.
+ type: string
+ fileFlushMinSizeKb:
+ description: |-
+ File flush buffer size for envoy flushes buffers to disk in kilobytes.
+ Defaults to 64.
+ Optional.
+ format: int32
+ type: integer
+ gatewayTopology:
+ description: |-
+ Topology encapsulates the configuration which describes where the proxy is
+ located i.e. behind a (or N) trusted proxy (proxies) or directly exposed
+ to the internet. This configuration only effects gateways and is applied
+ to all the gateways in the cluster unless overridden via annotations of the
+ gateway workloads.
+ properties:
+ forwardClientCertDetails:
+ description: |-
+ Configures how the gateway proxy handles x-forwarded-client-cert (XFCC)
+ header in the incoming request.
+ enum:
+ - UNDEFINED
+ - SANITIZE
+ - FORWARD_ONLY
+ - APPEND_FORWARD
+ - SANITIZE_SET
+ - ALWAYS_FORWARD_ONLY
+ type: string
+ numTrustedProxies:
+ description: |-
+ Number of trusted proxies deployed in front of the Istio gateway proxy.
+ When this option is set to value N greater than zero, the trusted client
+ address is assumed to be the Nth address from the right end of the
+ X-Forwarded-For (XFF) header from the incoming request. If the
+ X-Forwarded-For (XFF) header is missing or has fewer than N addresses, the
+ gateway proxy falls back to using the immediate downstream connection's
+ source address as the trusted client address.
+ Note that the gateway proxy will append the downstream connection's source
+ address to the X-Forwarded-For (XFF) address and set the
+ X-Envoy-External-Address header to the trusted client address before
+ forwarding it to the upstream services in the cluster.
+ The default value of numTrustedProxies is 0.
+ See [Envoy XFF](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers#config-http-conn-man-headers-x-forwarded-for)
+ header handling for more details.
+ format: int32
+ type: integer
+ proxyProtocol:
+ description: |-
+ Enables [PROXY protocol](http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt) for
+ downstream connections on a gateway.
+ type: object
+ type: object
+ holdApplicationUntilProxyStarts:
+ description: |-
+ Boolean flag for enabling/disabling the holdApplicationUntilProxyStarts behavior.
+ This feature adds hooks to delay application startup until the pod proxy
+ is ready to accept traffic, mitigating some startup race conditions.
+ Default value is 'false'.
+ type: boolean
+ image:
+ description: Specifies the details of the proxy image.
+ properties:
+ imageType:
+ description: |-
+ The image type of the image.
+ Istio publishes default, debug, and distroless images.
+ Other values are allowed if those image types (example: centos) are published to the specified hub.
+ supported values: default, debug, distroless.
+ type: string
+ type: object
+ interceptionMode:
+ description: The mode used to redirect inbound traffic
+ to Envoy.
+ enum:
+ - REDIRECT
+ - TPROXY
+ - NONE
+ type: string
+ meshId:
+ description: |-
+ The unique identifier for the [service mesh](https://istio.io/docs/reference/glossary/#service-mesh)
+ All control planes running in the same service mesh should specify the same mesh ID.
+ Mesh ID is used to label telemetry reports for cases where telemetry from multiple meshes is mixed together.
+ type: string
+ privateKeyProvider:
+ description: Specifies the details of the Private Key
+ Provider configuration for gateway and sidecar proxies.
+ properties:
+ cryptomb:
+ description: Use CryptoMb private key provider
+ properties:
+ fallback:
+ description: |-
+ If the private key provider isn’t available (eg. the required hardware capability doesn’t existed)
+ Envoy will fallback to the BoringSSL default implementation when the fallback is true.
+ The default value is false.
+ type: boolean
+ pollDelay:
+ description: |-
+ How long to wait until the per-thread processing queue should be processed. If the processing queue
+ gets full (eight sign or decrypt requests are received) it is processed immediately.
+ However, if the queue is not filled before the delay has expired, the requests already in the queue
+ are processed, even if the queue is not full.
+ In effect, this value controls the balance between latency and throughput.
+ The duration needs to be set to a value greater than or equal to 1 millisecond.
+ type: string
+ type: object
+ qat:
+ description: Use QAT private key provider
+ properties:
+ fallback:
+ description: |-
+ If the private key provider isn’t available (eg. the required hardware capability doesn’t existed)
+ Envoy will fallback to the BoringSSL default implementation when the fallback is true.
+ The default value is false.
+ type: boolean
+ pollDelay:
+ description: |-
+ How long to wait before polling the hardware accelerator after a request has been submitted there.
+ Having a small value leads to quicker answers from the hardware but causes more polling loop spins,
+ leading to potentially larger CPU usage.
+ The duration needs to be set to a value greater than or equal to 1 millisecond.
+ type: string
+ type: object
+ type: object
+ x-kubernetes-validations:
+ - message: At most one of [cryptomb qat] should be set
+ rule: (has(self.cryptomb)?1:0) + (has(self.qat)?1:0)
+ <= 1
+ proxyAdminPort:
+ description: |-
+ Port on which Envoy should listen for administrative commands.
+ Default port is `15000`.
+ format: int32
+ type: integer
+ proxyBootstrapTemplatePath:
+ description: Path to the proxy bootstrap template file
+ type: string
+ proxyHeaders:
+ description: "Define the set of headers to add/modify
+ for HTTP request/responses.\n\nTo enable an optional
+ header, simply set the field. If no specific configuration
+ is required, an empty object (`{}`) will enable it.\nNote:
+ currently all headers are enabled by default.\n\nBelow
+ shows an example of customizing the `server` header
+ and disabling the `X-Envoy-Attempt-Count` header:\n\n```yaml\nproxyHeaders:\n\n\tserver:\n\t
+ \ value: \"my-custom-server\"\n\t# Explicitly enable
+ Request IDs.\n\t# As this is the default, this has no
+ effect.\n\trequestId: {}\n\tattemptCount:\n\t disabled:
+ true\n\n```\n\n# Below shows an example of preserving
+ the header case for HTTP 1.x requests\n\n```yaml\nproxyHeaders:\n\n\tpreserveHttp1HeaderCase:
+ true\n\n```\n\nSome headers are enabled by default,
+ and require explicitly disabling. See below for an example
+ of disabling all default-enabled headers:\n\n```yaml\nproxyHeaders:\n\n\tforwardedClientCert:
+ SANITIZE\n\tserver:\n\t disabled: true\n\trequestId:\n\t
+ \ disabled: true\n\tattemptCount:\n\t disabled: true\n\tenvoyDebugHeaders:\n\t
+ \ disabled: true\n\tmetadataExchangeHeaders:\n\t mode:
+ IN_MESH\n\n```"
+ properties:
+ attemptCount:
+ description: |-
+ Controls the `X-Envoy-Attempt-Count` header.
+ If enabled, this header will be added on outbound request headers (including gateways) that have retries configured.
+ If disabled, this header will not be set. If it is already present, it will be preserved.
+ This header is enabled by default if not configured.
+ properties:
+ disabled:
+ type: boolean
+ type: object
+ envoyDebugHeaders:
+ description: |-
+ Controls various `X-Envoy-*` headers, such as `X-Envoy-Overloaded` and `X-Envoy-Upstream-Service-Time`. If enabled,
+ these headers will be included.
+ If disabled, these headers will not be set. If they are already present, they will be preserved.
+ See the [Envoy documentation](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/router/v3/router.proto#envoy-v3-api-field-extensions-filters-http-router-v3-router-suppress-envoy-headers) for more details.
+ These headers are enabled by default if not configured.
+ properties:
+ disabled:
+ type: boolean
+ type: object
+ forwardedClientCert:
+ description: |-
+ Controls the `X-Forwarded-Client-Cert` header for inbound sidecar requests. To set this on gateways, use the `Topology` setting.
+ To disable the header, configure either `SANITIZE` (to always remove the header, if present) or `FORWARD_ONLY` (to leave the header as-is).
+ By default, `APPEND_FORWARD` will be used.
+ enum:
+ - UNDEFINED
+ - SANITIZE
+ - FORWARD_ONLY
+ - APPEND_FORWARD
+ - SANITIZE_SET
+ - ALWAYS_FORWARD_ONLY
+ type: string
+ metadataExchangeHeaders:
+ description: |-
+ Controls Istio metadata exchange headers `X-Envoy-Peer-Metadata` and `X-Envoy-Peer-Metadata-Id`.
+ By default, the behavior is unspecified.
+ If IN_MESH, these headers will not be appended to outbound requests from sidecars to services not in-mesh.
+ properties:
+ mode:
+ enum:
+ - UNDEFINED
+ - IN_MESH
+ type: string
+ type: object
+ preserveHttp1HeaderCase:
+ description: |-
+ When true, the original case of HTTP/1.x headers will be preserved
+ as they pass through the proxy, rather than normalizing them to lowercase.
+ This field is particularly useful for applications that require case-sensitive
+ headers for interoperability with downstream systems or APIs that expect specific
+ casing.
+ The preserve_http1_header_case option only applies to HTTP/1.x traffic, as HTTP/2 requires all headers
+ to be lowercase per the protocol specification. Envoy will ignore this field for HTTP/2
+ requests and automatically normalize headers to lowercase, ensuring compliance with HTTP/2
+ standards.
+ type: boolean
+ requestId:
+ description: |-
+ Controls the `X-Request-Id` header. If enabled, a request ID is generated for each request if one is not already set.
+ This applies to all types of traffic (inbound, outbound, and gateways).
+ If disabled, no request ID will be generate for the request. If it is already present, it will be preserved.
+ Warning: request IDs are a critical component to mesh tracing and logging, so disabling this is not recommended.
+ This header is enabled by default if not configured.
+ properties:
+ disabled:
+ type: boolean
+ type: object
+ server:
+ description: |-
+ Controls the `server` header. If enabled, the `Server: istio-envoy` header is set in response headers for inbound traffic (including gateways).
+ If disabled, the `Server` header is not modified. If it is already present, it will be preserved.
+ properties:
+ disabled:
+ type: boolean
+ value:
+ description: If set, and the server header is
+ enabled, this value will be set as the server
+ header. By default, `istio-envoy` will be used.
+ type: string
+ type: object
+ setCurrentClientCertDetails:
+ description: |-
+ This field is valid only when forward_client_cert_details is APPEND_FORWARD or SANITIZE_SET
+ and the client connection is mTLS. It specifies the fields in
+ the client certificate to be forwarded. Note that `Hash` is always set, and
+ `By` is always set when the client certificate presents the URI type Subject Alternative Name value.
+ properties:
+ cert:
+ description: |-
+ Whether to forward the entire client cert in URL encoded PEM format. This will appear in the
+ XFCC header comma separated from other values with the value Cert="PEM".
+ Defaults to false.
+ type: boolean
+ chain:
+ description: |-
+ Whether to forward the entire client cert chain (including the leaf cert) in URL encoded PEM
+ format. This will appear in the XFCC header comma separated from other values with the value
+ Chain="PEM".
+ Defaults to false.
+ type: boolean
+ dns:
+ description: |-
+ Whether to forward the DNS type Subject Alternative Names of the client cert.
+ Defaults to true.
+ type: boolean
+ subject:
+ description: Whether to forward the subject of
+ the client cert. Defaults to true.
+ type: boolean
+ uri:
+ description: |-
+ Whether to forward the URI type Subject Alternative Name of the client cert. Defaults to
+ true.
+ type: boolean
+ type: object
+ xForwardedHost:
+ description: |-
+ Controls the `X-Forwarded-Host` header. If enabled, the `X-Forwarded-Host` header is appended
+ with the original host when it is rewritten.
+ This header is disabled by default.
+ properties:
+ enabled:
+ type: boolean
+ type: object
+ xForwardedPort:
+ description: |-
+ Controls the `X-Forwarded-Port` header. If enabled, the `X-Forwarded-Port` header is header with the port value
+ client used to connect to Envoy. It will be ignored if the “x-forwarded-port“ header has been set by any
+ trusted proxy in front of Envoy.
+ This header is disabled by default.
+ properties:
+ enabled:
+ type: boolean
+ type: object
+ type: object
+ proxyMetadata:
+ additionalProperties:
+ type: string
+ description: |-
+ Additional environment variables for the proxy.
+ Names starting with `ISTIO_META_` will be included in the generated bootstrap and sent to the XDS server.
+ type: object
+ proxyStatsMatcher:
+ description: "Proxy stats matcher defines configuration
+ for reporting custom Envoy stats.\nTo reduce memory
+ and CPU overhead from Envoy stats system, Istio proxies
+ by\ndefault create and expose only a subset of Envoy
+ stats. This option is to\ncontrol creation of additional
+ Envoy stats with prefix, suffix, and regex\nexpressions
+ match on the name of the stats. This replaces the stats\ninclusion
+ annotations\n(`sidecar.istio.io/statsInclusionPrefixes`,\n`sidecar.istio.io/statsInclusionRegexps`,
+ and\n`sidecar.istio.io/statsInclusionSuffixes`). For
+ example, to enable stats\nfor circuit breakers, request
+ retries, upstream connections, and request timeouts,\nyou
+ can specify stats matcher as follows:\n```yaml\nproxyStatsMatcher:\n\n\tinclusionRegexps:\n\t
+ \ - .*outlier_detection.*\n\t - .*upstream_rq_retry.*\n\t
+ \ - .*upstream_cx_.*\n\tinclusionSuffixes:\n\t - upstream_rq_timeout\n\n```\nNote
+ including more Envoy stats might increase number of
+ time series\ncollected by prometheus significantly.
+ Care needs to be taken on Prometheus\nresource provision
+ and configuration to reduce cardinality."
+ properties:
+ inclusionPrefixes:
+ description: Proxy stats name prefix matcher for inclusion.
+ items:
+ type: string
+ type: array
+ inclusionRegexps:
+ description: Proxy stats name regexps matcher for
+ inclusion.
+ items:
+ type: string
+ type: array
+ inclusionSuffixes:
+ description: Proxy stats name suffix matcher for inclusion.
+ items:
+ type: string
+ type: array
+ type: object
+ readinessProbe:
+ description: |-
+ VM Health Checking readiness probe. This health check config exactly mirrors the
+ kubernetes readiness probe configuration both in schema and logic.
+ Only one health check method of 3 can be set at a time.
+ properties:
+ exec:
+ description: Exec specifies a command to execute in
+ the container.
+ properties:
+ command:
+ description: |-
+ Command is the command line to execute inside the container, the working directory for the
+ command is root ('/') in the container's filesystem. The command is simply exec'd, it is
+ not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use
+ a shell, you need to explicitly call out to that shell.
+ Exit status of 0 is treated as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ failureThreshold:
+ description: |-
+ Minimum consecutive failures for the probe to be considered failed after having succeeded.
+ Defaults to 3. Minimum value is 1.
+ format: int32
+ type: integer
+ grpc:
+ description: GRPC specifies a GRPC HealthCheckRequest.
+ properties:
+ port:
+ description: Port number of the gRPC service.
+ Number must be in the range 1 to 65535.
+ format: int32
+ type: integer
+ service:
+ default: ""
+ description: |-
+ Service is the name of the service to place in the gRPC HealthCheckRequest
+ (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
+
+ If this is not specified, the default behavior is defined by gRPC.
+ type: string
+ required:
+ - port
+ type: object
+ httpGet:
+ description: HTTPGet specifies an HTTP GET request
+ to perform.
+ properties:
+ host:
+ description: |-
+ Host name to connect to, defaults to the pod IP. You probably want to set
+ "Host" in httpHeaders instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the request.
+ HTTP allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom header
+ to be used in HTTP probes
+ properties:
+ name:
+ description: |-
+ The header field name.
+ This will be canonicalized upon output, so case-variant names will be understood as the same header.
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ Name or number of the port to access on the container.
+ Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: |-
+ Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ initialDelaySeconds:
+ description: |-
+ Number of seconds after the container has started before liveness probes are initiated.
+ More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes
+ format: int32
+ type: integer
+ periodSeconds:
+ description: |-
+ How often (in seconds) to perform the probe.
+ Default to 10 seconds. Minimum value is 1.
+ format: int32
+ type: integer
+ successThreshold:
+ description: |-
+ Minimum consecutive successes for the probe to be considered successful after having failed.
+ Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1.
+ format: int32
+ type: integer
+ tcpSocket:
+ description: TCPSocket specifies a connection to a
+ TCP port.
+ properties:
+ host:
+ description: 'Optional: Host name to connect to,
+ defaults to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ Number or name of the port to access on the container.
+ Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ terminationGracePeriodSeconds:
+ description: |-
+ Optional duration in seconds the pod needs to terminate gracefully upon probe failure.
+ The grace period is the duration in seconds after the processes running in the pod are sent
+ a termination signal and the time when the processes are forcibly halted with a kill signal.
+ Set this value longer than the expected cleanup time for your process.
+ If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this
+ value overrides the value provided by the pod spec.
+ Value must be non-negative integer. The value zero indicates stop immediately via
+ the kill signal (no opportunity to shut down).
+ This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate.
+ Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset.
+ format: int64
+ type: integer
+ timeoutSeconds:
+ description: |-
+ Number of seconds after which the probe times out.
+ Defaults to 1 second. Minimum value is 1.
+ More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes
+ format: int32
+ type: integer
+ type: object
+ runtimeValues:
+ additionalProperties:
+ type: string
+ description: |-
+ Envoy [runtime configuration](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/operations/runtime) to set during bootstrapping.
+ This enables setting experimental, unsafe, unsupported, and deprecated features that should be used with extreme caution.
+ type: object
+ sds:
+ description: |-
+ Secret Discovery Service(SDS) configuration to be used by the proxy.
+
+ Deprecated: Marked as deprecated in mesh/v1alpha1/proxy.proto.
+ properties:
+ enabled:
+ description: True if SDS is enabled.
+ type: boolean
+ k8sSaJwtPath:
+ description: Path of k8s service account JWT path.
+ type: string
+ type: object
+ serviceCluster:
+ description: |-
+ Service cluster defines the name for the `service_cluster` that is
+ shared by all Envoy instances. This setting corresponds to
+ `--service-cluster` flag in Envoy. In a typical Envoy deployment, the
+ `service-cluster` flag is used to identify the caller, for
+ source-based routing scenarios.
+
+ Since Istio does not assign a local `service/service` version to each
+ Envoy instance, the name is same for all of them. However, the
+ source/caller's identity (e.g., IP address) is encoded in the
+ `--service-node` flag when launching Envoy. When the RDS service
+ receives API calls from Envoy, it uses the value of the `service-node`
+ flag to compute routes that are relative to the service instances
+ located at that IP address.
+ type: string
+ statNameLength:
+ description: |-
+ Maximum length of name field in Envoy's metrics. The length of the name field
+ is determined by the length of a name field in a service and the set of labels that
+ comprise a particular version of the service. The default value is set to 189 characters.
+ Envoy's internal metrics take up 67 characters, for a total of 256 character name per metric.
+ Increase the value of this field if you find that the metrics from Envoys are truncated.
+ format: int32
+ type: integer
+ statsCompression:
+ description: |-
+ Offer HTTP compression for stats
+ Defaults to true.
+ Optional.
+ type: boolean
+ statsdUdpAddress:
+ description: IP Address and Port of a statsd UDP listener
+ (e.g. `10.75.241.127:9125`).
+ type: string
+ statusPort:
+ description: |-
+ Port on which the agent should listen for administrative commands such as readiness probe.
+ Default is set to port `15020`.
+ format: int32
+ type: integer
+ terminationDrainDuration:
+ description: |-
+ The amount of time allowed for connections to complete on proxy shutdown.
+ On receiving `SIGTERM` or `SIGINT`, `istio-agent` tells the active Envoy to start gracefully draining,
+ discouraging any new connections and allowing existing connections to complete. It then
+ sleeps for the `terminationDrainDuration` and then kills any remaining active Envoy processes.
+ If not set, a default of `5s` will be applied.
+ type: string
+ tracing:
+ description: Tracing configuration to be used by the proxy.
+ properties:
+ customTags:
+ additionalProperties:
+ description: |-
+ Configure custom tags that will be added to any active span.
+ Tags can be generated via literals, environment variables or an incoming request header.
+ properties:
+ environment:
+ description: |-
+ The custom tag's value should be populated from an environmental
+ variable
+ properties:
+ defaultValue:
+ description: |-
+ When the environment variable is not found,
+ the tag's value will be populated with this default value if specified,
+ otherwise the tag will not be populated.
+ type: string
+ name:
+ description: Name of the environment variable
+ used to populate the tag's value
+ type: string
+ type: object
+ header:
+ description: |-
+ The custom tag's value is populated by an http header from
+ an incoming request.
+ properties:
+ defaultValue:
+ description: |-
+ Default value to be used for the tag when the named HTTP header does not exist.
+ The tag will be skipped if no default value is provided.
+ type: string
+ name:
+ description: HTTP header name used to obtain
+ the value from to populate the tag value.
+ type: string
+ type: object
+ literal:
+ description: The custom tag's value is the specified
+ literal.
+ properties:
+ value:
+ description: Static literal value used to
+ populate the tag value.
+ type: string
+ type: object
+ type: object
+ x-kubernetes-validations:
+ - message: At most one of [literal environment header]
+ should be set
+ rule: (has(self.literal)?1:0) + (has(self.environment)?1:0)
+ + (has(self.header)?1:0) <= 1
+ description: "and gateways).\nThe key represents the
+ name of the tag.\nEx:\n```yaml\ncustom_tags:\n\n\tnew_tag_name:\n\t
+ \ header:\n\t name: custom-http-header-name\n\t
+ \ default_value: defaulted-value-from-custom-header\n\n```"
+ type: object
+ datadog:
+ description: Use a Datadog tracer.
+ properties:
+ address:
+ description: Address of the Datadog Agent.
+ type: string
+ type: object
+ enableIstioTags:
+ description: |-
+ Determines whether or not trace spans generated by Envoy will include Istio specific tags.
+ By default Istio specific tags are included in the trace spans.
+ type: boolean
+ lightstep:
+ description: |-
+ Use a Lightstep tracer.
+ NOTE: For Istio 1.15+, this configuration option will result
+ in using OpenTelemetry-based Lightstep integration.
+ properties:
+ accessToken:
+ description: The Lightstep access token.
+ type: string
+ address:
+ description: Address of the Lightstep Satellite
+ pool.
+ type: string
+ type: object
+ maxPathTagLength:
+ description: |-
+ Configures the maximum length of the request path to extract and include in the
+ HttpUrl tag. Used to truncate length request paths to meet the needs of tracing
+ backend. If not set, then a length of 256 will be used.
+ format: int32
+ type: integer
+ openCensusAgent:
+ description: Use an OpenCensus tracer exporting to
+ an OpenCensus agent.
+ properties:
+ address:
+ description: |-
+ gRPC address for the OpenCensus agent (e.g. dns://authority/host:port or
+ unix:path). See [gRPC naming
+ docs](https://github.com/grpc/grpc/blob/master/doc/naming.md) for
+ details.
+ type: string
+ context:
+ description: |-
+ Specifies the set of context propagation headers used for distributed
+ tracing. Default is `["W3C_TRACE_CONTEXT"]`. If multiple values are specified,
+ the proxy will attempt to read each header for each request and will
+ write all headers.
+ items:
+ description: |-
+ TraceContext selects the context propagation headers used for
+ distributed tracing.
+ enum:
+ - UNSPECIFIED
+ - W3C_TRACE_CONTEXT
+ - GRPC_BIN
+ - CLOUD_TRACE_CONTEXT
+ - B3
+ type: string
+ type: array
+ type: object
+ sampling:
+ description: |-
+ The percentage of requests (0.0 - 100.0) that will be randomly selected for trace generation,
+ if not requested by the client or not forced. Default is 1.0.
+ type: number
+ stackdriver:
+ description: Use a Stackdriver tracer.
+ properties:
+ debug:
+ description: debug enables trace output to stdout.
+ type: boolean
+ maxNumberOfAnnotations:
+ description: |-
+ The global default max number of annotation events per span.
+ default is 200.
+ format: int64
+ type: integer
+ maxNumberOfAttributes:
+ description: |-
+ The global default max number of attributes per span.
+ default is 200.
+ format: int64
+ type: integer
+ maxNumberOfMessageEvents:
+ description: |-
+ The global default max number of message events per span.
+ default is 200.
+ format: int64
+ type: integer
+ type: object
+ tlsSettings:
+ description: |-
+ Use the tlsSettings to specify the tls mode to use. If the remote tracing service
+ uses Istio mutual TLS and shares the root CA with istiod, specify the TLS
+ mode as `ISTIO_MUTUAL`.
+ properties:
+ caCertificates:
+ description: |-
+ OPTIONAL: The path to the file containing certificate authority
+ certificates to use in verifying a presented server certificate. If
+ omitted, the proxy will verify the server's certificate using
+ the OS CA certificates.
+ Should be empty if mode is `ISTIO_MUTUAL`.
+ type: string
+ caCrl:
+ description: |-
+ OPTIONAL: The path to the file containing the certificate revocation list (CRL)
+ to use in verifying a presented server certificate. `CRL` is a list of certificates
+ that have been revoked by the CA (Certificate Authority) before their scheduled expiration date.
+ If specified, the proxy will verify if the presented certificate is part of the revoked list of certificates.
+ If omitted, the proxy will not verify the certificate against the `crl`. Note that if `credentialName` is set,
+ `CRL` cannot be specified using `caCrl`, rather it has to be specified inside the credential.
+ type: string
+ clientCertificate:
+ description: |-
+ REQUIRED if mode is `MUTUAL`. The path to the file holding the
+ client-side TLS certificate to use.
+ Should be empty if mode is `ISTIO_MUTUAL`.
+ type: string
+ credentialName:
+ description: |-
+ The name of the secret that holds the TLS certs for the
+ client including the CA certificates. This secret must exist in
+ the namespace of the proxy using the certificates.
+ An Opaque secret should contain the following keys and values:
+ `key: `, `cert: `, `cacert: `,
+ `crl: `
+ Here CACertificate is used to verify the server certificate.
+ For mutual TLS, `cacert: ` can be provided in the
+ same secret or a separate secret named `-cacert`.
+ A TLS secret for client certificates with an additional
+ `ca.crt` key for CA certificates and `ca.crl` key for
+ certificate revocation list(CRL) is also supported.
+ Only one of client certificates and CA certificate
+ or credentialName can be specified.
+
+ **NOTE:** This field is applicable at sidecars only if
+ `DestinationRule` has a `workloadSelector` specified.
+ Otherwise the field will be applicable only at gateways, and
+ sidecars will continue to use the certificate paths.
+ type: string
+ insecureSkipVerify:
+ description: |-
+ `insecureSkipVerify` specifies whether the proxy should skip verifying the
+ CA signature and SAN for the server certificate corresponding to the host.
+ The default value of this field is false.
+ type: boolean
+ mode:
+ description: |-
+ Indicates whether connections to this port should be secured
+ using TLS. The value of this field determines how TLS is enforced.
+ enum:
+ - DISABLE
+ - SIMPLE
+ - MUTUAL
+ - ISTIO_MUTUAL
+ type: string
+ privateKey:
+ description: |-
+ REQUIRED if mode is `MUTUAL`. The path to the file holding the
+ client's private key.
+ Should be empty if mode is `ISTIO_MUTUAL`.
+ type: string
+ sni:
+ description: |-
+ SNI string to present to the server during TLS handshake.
+ If unspecified, SNI will be automatically set based on downstream HTTP
+ host/authority header for SIMPLE and MUTUAL TLS modes.
+ type: string
+ subjectAltNames:
+ description: |-
+ A list of alternate names to verify the subject identity in the
+ certificate. If specified, the proxy will verify that the server
+ certificate's subject alt name matches one of the specified values.
+ If specified, this list overrides the value of `subjectAltNames`
+ from the `ServiceEntry`. If unspecified, automatic validation of upstream
+ presented certificate for new upstream connections will be done based on the
+ downstream HTTP host/authority header.
+ items:
+ type: string
+ type: array
+ type: object
+ zipkin:
+ description: Use a Zipkin tracer.
+ properties:
+ address:
+ description: Address of the Zipkin service (e.g.
+ _zipkin:9411_).
+ type: string
+ type: object
+ type: object
+ x-kubernetes-validations:
+ - message: At most one of [zipkin lightstep datadog stackdriver
+ openCensusAgent] should be set
+ rule: (has(self.zipkin)?1:0) + (has(self.lightstep)?1:0)
+ + (has(self.datadog)?1:0) + (has(self.stackdriver)?1:0)
+ + (has(self.openCensusAgent)?1:0) <= 1
+ tracingServiceName:
+ description: |-
+ Used by Envoy proxies to assign the values for the service names in trace
+ spans.
+ enum:
+ - APP_LABEL_AND_NAMESPACE
+ - CANONICAL_NAME_ONLY
+ - CANONICAL_NAME_AND_NAMESPACE
+ type: string
+ zipkinAddress:
+ description: |-
+ Address of the Zipkin service (e.g. _zipkin:9411_).
+ DEPRECATED: Use [tracing][istio.mesh.v1alpha1.ProxyConfig.tracing] instead.
+
+ Deprecated: Marked as deprecated in mesh/v1alpha1/proxy.proto.
+ type: string
+ type: object
+ x-kubernetes-validations:
+ - message: At most one of [serviceCluster tracingServiceName]
+ should be set
+ rule: (has(self.serviceCluster)?1:0) + (has(self.tracingServiceName)?1:0)
+ <= 1
+ defaultDestinationRuleExportTo:
+ description: |-
+ The default value for the `DestinationRule.exportTo` field. Has the same
+ syntax as `defaultServiceExportTo`.
+
+ If not set the system will use "*" as the default value which implies that
+ destination rules are exported to all namespaces
+ items:
+ type: string
+ type: array
+ defaultHttpRetryPolicy:
+ description: "Configure the default HTTP retry policy.\nThe
+ default number of retry attempts is set at 2 for these errors:\n\n\t\"connect-failure,refused-stream,unavailable,cancelled,retriable-status-codes\".\n\nSetting
+ the number of attempts to 0 disables retry policy globally.\nThis
+ setting can be overridden on a per-host basis using the
+ Virtual Service\nAPI.\nAll settings in the retry policy
+ except `perTryTimeout` can currently be\nconfigured globally
+ via this field."
+ properties:
+ attempts:
+ description: |-
+ Number of retries to be allowed for a given request. The interval
+ between retries will be determined automatically (25ms+). When request
+ `timeout` of the [HTTP route](https://istio.io/docs/reference/config/networking/virtual-service/#HTTPRoute)
+ or `per_try_timeout` is configured, the actual number of retries attempted also depends on
+ the specified request `timeout` and `per_try_timeout` values. MUST be >= 0. If `0`, retries will be disabled.
+ The maximum possible number of requests made will be 1 + `attempts`.
+ format: int32
+ type: integer
+ backoff:
+ description: |-
+ Specifies the minimum duration between retry attempts.
+ If unset, default minimum duration of 25ms is used as base interval for exponetial backoff.
+ This has an impact on the total number of retries that will be attempted based on the `attempts` field
+ and route timeout. For example, with attempts is set to 3, backoff to 2s and timeout to 3s, the request will
+ be retried only once.
+ type: string
+ perTryTimeout:
+ description: |-
+ Timeout per attempt for a given request, including the initial call and any retries. Format: 1h/1m/1s/1ms. MUST be >=1ms.
+ Default is same value as request
+ `timeout` of the [HTTP route](https://istio.io/docs/reference/config/networking/virtual-service/#HTTPRoute),
+ which means no timeout.
+ type: string
+ retryIgnorePreviousHosts:
+ description: |-
+ Flag to specify whether the retries should ignore previously tried hosts during retry.
+ Defaults to true.
+ type: boolean
+ retryOn:
+ description: |-
+ Specifies the conditions under which retry takes place.
+ One or more policies can be specified using a ‘,’ delimited list.
+ See the [retry policies](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/router_filter#x-envoy-retry-on)
+ and [gRPC retry policies](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/router_filter#x-envoy-retry-grpc-on) for more details.
+
+ In addition to the policies specified above, a list of HTTP status codes can be passed, such as `retryOn: "503,reset"`.
+ Note these status codes refer to the actual responses received from the destination.
+ For example, if a connection is reset, Istio will translate this to 503 for it's response.
+ However, the destination did not return a 503 error, so this would not match `"503"` (it would, however, match `"reset"`).
+
+ If not specified, this defaults to `connect-failure,refused-stream,unavailable,cancelled`.
+ type: string
+ retryRemoteLocalities:
+ description: |-
+ Flag to specify whether the retries should retry to other localities.
+ See the [retry plugin configuration](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/http/http_connection_management#retry-plugin-configuration) for more details.
+ type: boolean
+ type: object
+ defaultProviders:
+ description: Specifies extension providers to use by default
+ in Istio configuration resources.
+ properties:
+ accessLogging:
+ description: Name of the default provider(s) for access
+ logging.
+ items:
+ type: string
+ type: array
+ metrics:
+ description: Name of the default provider(s) for metrics.
+ items:
+ type: string
+ type: array
+ tracing:
+ description: Name of the default provider(s) for tracing.
+ items:
+ type: string
+ type: array
+ type: object
+ defaultServiceExportTo:
+ description: |-
+ The default value for the ServiceEntry.exportTo field and services
+ imported through container registry integrations, e.g. this applies to
+ Kubernetes Service resources. The value is a list of namespace names and
+ reserved namespace aliases. The allowed namespace aliases are:
+ ```
+ * - All Namespaces
+ . - Current Namespace
+ ~ - No Namespace
+ ```
+ If not set the system will use "*" as the default value which implies that
+ services are exported to all namespaces.
+
+ `All namespaces` is a reasonable default for implementations that don't
+ need to restrict access or visibility of services across namespace
+ boundaries. If that requirement is present it is generally good practice to
+ make the default `Current namespace` so that services are only visible
+ within their own namespaces by default. Operators can then expand the
+ visibility of services to other namespaces as needed. Use of `No Namespace`
+ is expected to be rare but can have utility for deployments where
+ dependency management needs to be precise even within the scope of a single
+ namespace.
+
+ For further discussion see the reference documentation for `ServiceEntry`,
+ `Sidecar`, and `Gateway`.
+ items:
+ type: string
+ type: array
+ defaultVirtualServiceExportTo:
+ description: |-
+ The default value for the VirtualService.exportTo field. Has the same
+ syntax as `defaultServiceExportTo`.
+
+ If not set the system will use "*" as the default value which implies that
+ virtual services are exported to all namespaces
+ items:
+ type: string
+ type: array
+ disableEnvoyListenerLog:
+ description: |-
+ This flag disables Envoy Listener logs.
+ See [Listener Access Log](https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/listener/v3/listener.proto#envoy-v3-api-field-config-listener-v3-listener-access-log)
+ Istio Enables Envoy's listener access logs on "NoRoute" response flag.
+ Default value is `false`.
+ type: boolean
+ discoverySelectors:
+ description: |-
+ A list of Kubernetes selectors that specify the set of namespaces that Istio considers when
+ computing configuration updates for sidecars. This can be used to reduce Istio's computational load
+ by limiting the number of entities (including services, pods, and endpoints) that are watched and processed.
+ If omitted, Istio will use the default behavior of processing all namespaces in the cluster.
+ Elements in the list are disjunctive (OR semantics), i.e. a namespace will be included if it matches any selector.
+ The following example selects any namespace that matches either below:
+ 1. The namespace has both of these labels: `env: prod` and `region: us-east1`
+ 2. The namespace has label `app` equal to `cassandra` or `spark`.
+ ```yaml
+ discoverySelectors:
+ - matchLabels:
+ env: prod
+ region: us-east1
+ - matchExpressions:
+ - key: app
+ operator: In
+ values:
+ - cassandra
+ - spark
+
+ ```
+ Refer to the [Kubernetes selector docs](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors)
+ for additional detail on selector semantics.
+ items:
+ description: |-
+ A label selector is a label query over a set of resources. The result of matchLabels and
+ matchExpressions are ANDed. An empty label selector matches all objects. A null
+ label selector matches no objects.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label selector
+ requirements. The requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label key that the selector
+ applies to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ type: array
+ dnsRefreshRate:
+ description: |-
+ Configures DNS refresh rate for Envoy clusters of type `STRICT_DNS`
+ Default refresh rate is `60s`.
+ type: string
+ enableAutoMtls:
+ description: |-
+ This flag is used to enable mutual `TLS` automatically for service to service communication
+ within the mesh, default true.
+ If set to true, and a given service does not have a corresponding `DestinationRule` configured,
+ or its `DestinationRule` does not have ClientTLSSettings specified, Istio configures client side
+ TLS configuration appropriately. More specifically,
+ If the upstream authentication policy is in `STRICT` mode, use Istio provisioned certificate
+ for mutual `TLS` to connect to upstream.
+ If upstream service is in plain text mode, use plain text.
+ If the upstream authentication policy is in PERMISSIVE mode, Istio configures clients to use
+ mutual `TLS` when server sides are capable of accepting mutual `TLS` traffic.
+ If service `DestinationRule` exists and has `ClientTLSSettings` specified, that is always used instead.
+ type: boolean
+ enableEnvoyAccessLogService:
+ description: |-
+ This flag enables Envoy's gRPC Access Log Service.
+ See [Access Log Service](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/access_loggers/grpc/v3/als.proto)
+ for details about Envoy's gRPC Access Log Service API.
+ Default value is `false`.
+ type: boolean
+ enablePrometheusMerge:
+ description: |-
+ If enabled, Istio agent will merge metrics exposed by the application with metrics from Envoy
+ and Istio agent. The sidecar injection will replace `prometheus.io` annotations present on the pod
+ and redirect them towards Istio agent, which will then merge metrics of from the application with Istio metrics.
+ This relies on the annotations `prometheus.io/scrape`, `prometheus.io/port`, and
+ `prometheus.io/path` annotations.
+ If you are running a separately managed Envoy with an Istio sidecar, this may cause issues, as the metrics will collide.
+ In this case, it is recommended to disable aggregation on that deployment with the
+ `prometheus.istio.io/merge-metrics: "false"` annotation.
+ If not specified, this will be enabled by default.
+ type: boolean
+ enableTracing:
+ description: |-
+ Flag to control generation of trace spans and request IDs.
+ Requires a trace span collector defined in the proxy configuration.
+ type: boolean
+ extensionProviders:
+ description: |-
+ Defines a list of extension providers that extend Istio's functionality. For example, the AuthorizationPolicy
+ can be used with an extension provider to delegate the authorization decision to a custom authorization system.
+ items:
+ properties:
+ datadog:
+ description: Configures a Datadog tracing provider.
+ properties:
+ maxTagLength:
+ description: |-
+ Optional. Controls the overall path length allowed in a reported span.
+ NOTE: currently only controls max length of the path tag.
+ format: int32
+ type: integer
+ port:
+ description: REQUIRED. Specifies the port of the
+ service.
+ format: int32
+ type: integer
+ service:
+ description: |-
+ REQUIRED. Specifies the service for the Datadog agent.
+ The format is `[/]`. The specification of `` is required only when it is insufficient
+ to unambiguously resolve a service in the service registry. The `` is a fully qualified host name of a
+ service defined by the Kubernetes service or ServiceEntry.
+
+ Example: "datadog.default.svc.cluster.local" or "bar/datadog.example.com".
+ type: string
+ required:
+ - port
+ - service
+ type: object
+ envoyExtAuthzGrpc:
+ description: Configures an external authorizer that
+ implements the Envoy ext_authz filter authorization
+ check service using the gRPC API.
+ properties:
+ clearRouteCache:
+ description: |-
+ If true, clears route cache in order to allow the external authorization service to correctly affect routing decisions.
+ If true, recalculate routes with the new ExtAuthZ added/removed headers.
+ Default is false
+ type: boolean
+ failOpen:
+ description: |-
+ If true, the HTTP request or TCP connection will be allowed even if the communication with the authorization service has failed,
+ or if the authorization service has returned a HTTP 5xx error.
+ Default is false. For HTTP request, it will be rejected with 403 (HTTP Forbidden). For TCP connection, it will be closed immediately.
+ type: boolean
+ includeRequestBodyInCheck:
+ description: If set, the client request body will
+ be included in the authorization request sent
+ to the authorization service.
+ properties:
+ allowPartialMessage:
+ description: |-
+ When this field is true, ext-authz filter will buffer the message until maxRequestBytes is reached.
+ The authorization request will be dispatched and no 413 HTTP error will be returned by the filter.
+ A "x-envoy-auth-partial-body: false|true" metadata header will be added to the authorization request message
+ indicating if the body data is partial.
+ type: boolean
+ maxRequestBytes:
+ description: |-
+ Sets the maximum size of a message body that the ext-authz filter will hold in memory.
+ If maxRequestBytes is reached, and allowPartialMessage is false, Envoy will return a 413 (Payload Too Large).
+ Otherwise the request will be sent to the provider with a partial message.
+ Note that this setting will have precedence over the failOpen field, the 413 will be returned even when the
+ failOpen is set to true.
+ format: int32
+ type: integer
+ packAsBytes:
+ description: |-
+ If true, the body sent to the external authorization service in the gRPC authorization request is set with raw bytes
+ in the [raw_body field](https://github.com/envoyproxy/envoy/blame/cffb095d59d7935abda12b9509bcd136808367bb/api/envoy/service/auth/v3/attribute_context.proto#L153).
+ Otherwise, it will be filled with UTF-8 string in the [body field](https://github.com/envoyproxy/envoy/blame/cffb095d59d7935abda12b9509bcd136808367bb/api/envoy/service/auth/v3/attribute_context.proto#L147).
+ This field only works with the envoyExtAuthzGrpc provider and has no effect for the envoyExtAuthzHttp provider.
+ type: boolean
+ type: object
+ port:
+ description: REQUIRED. Specifies the port of the
+ service.
+ format: int32
+ type: integer
+ service:
+ description: |-
+ REQUIRED. Specifies the service that implements the Envoy ext_authz gRPC authorization service.
+ The format is `[/]`. The specification of `` is required only when it is insufficient
+ to unambiguously resolve a service in the service registry. The `` is a fully qualified host name of a
+ service defined by the Kubernetes service or ServiceEntry.
+
+ Example: "my-ext-authz.foo.svc.cluster.local" or "bar/my-ext-authz.example.com".
+ type: string
+ statusOnError:
+ description: |-
+ Sets the HTTP status that is returned to the client when there is a network error to the authorization service.
+ The default status is "403" (HTTP Forbidden).
+ type: string
+ timeout:
+ description: |-
+ The maximum duration that the proxy will wait for a response from the provider, this is the timeout for a specific request (default timeout: 600s).
+ When this timeout condition is met, the proxy marks the communication to the authorization service as failure.
+ In this situation, the response sent back to the client will depend on the configured `failOpen` field.
+ type: string
+ required:
+ - port
+ - service
+ type: object
+ envoyExtAuthzHttp:
+ description: Configures an external authorizer that
+ implements the Envoy ext_authz filter authorization
+ check service using the HTTP API.
+ properties:
+ clearRouteCache:
+ description: |-
+ If true, clears route cache in order to allow the external authorization service to correctly affect routing decisions.
+ If true, recalculate routes with the new ExtAuthZ added/removed headers.
+ Default is false
+ type: boolean
+ failOpen:
+ description: |-
+ If true, the user request will be allowed even if the communication with the authorization service has failed,
+ or if the authorization service has returned a HTTP 5xx error.
+ Default is false and the request will be rejected with "Forbidden" response.
+ type: boolean
+ headersToDownstreamOnAllow:
+ description: |-
+ List of headers from the authorization service that should be forwarded to downstream when the authorization
+ check result is allowed (HTTP code 200).
+ If not specified, the original response will not be modified and forwarded to downstream as-is.
+ Note, any existing headers will be overridden.
+
+ Exact, prefix and suffix matches are supported (similar to the
+ [authorization policy rule syntax](https://istio.io/latest/docs/reference/config/security/authorization-policy/#Rule)
+ except the presence match):
+ - Exact match: "abc" will match on value "abc".
+ - Prefix match: "abc*" will match on value "abc" and "abcd".
+ - Suffix match: "*abc" will match on value "abc" and "xabc".
+ items:
+ type: string
+ type: array
+ headersToDownstreamOnDeny:
+ description: |-
+ List of headers from the authorization service that should be forwarded to downstream when the authorization
+ check result is not allowed (HTTP code other than 200).
+ If not specified, all the authorization response headers, except *Authority (Host)* will be in the response to
+ the downstream.
+ When a header is included in this list, *Path*, *Status*, *Content-Length*, *WWWAuthenticate* and *Location* are
+ automatically added.
+ Note, the body from the authorization service is always included in the response to downstream.
+
+ Exact, prefix and suffix matches are supported (similar to the
+ [authorization policy rule syntax](https://istio.io/latest/docs/reference/config/security/authorization-policy/#Rule)
+ except the presence match):
+ - Exact match: "abc" will match on value "abc".
+ - Prefix match: "abc*" will match on value "abc" and "abcd".
+ - Suffix match: "*abc" will match on value "abc" and "xabc".
+ items:
+ type: string
+ type: array
+ headersToUpstreamOnAllow:
+ description: |-
+ List of headers from the authorization service that should be added or overridden in the original request and
+ forwarded to the upstream when the authorization check result is allowed (HTTP code 200).
+ If not specified, the original request will not be modified and forwarded to backend as-is.
+ Note, any existing headers will be overridden.
+
+ Exact, prefix and suffix matches are supported (similar to the
+ [authorization policy rule syntax](https://istio.io/latest/docs/reference/config/security/authorization-policy/#Rule)
+ except the presence match):
+ - Exact match: "abc" will match on value "abc".
+ - Prefix match: "abc*" will match on value "abc" and "abcd".
+ - Suffix match: "*abc" will match on value "abc" and "xabc".
+ items:
+ type: string
+ type: array
+ includeAdditionalHeadersInCheck:
+ additionalProperties:
+ type: string
+ description: |-
+ Set of additional fixed headers that should be included in the authorization request sent to the authorization service.
+ Key is the header name and value is the header value.
+ Note that client request of the same key or headers specified in includeRequestHeadersInCheck will be overridden.
+ type: object
+ includeHeadersInCheck:
+ description: |-
+ DEPRECATED. Use includeRequestHeadersInCheck instead.
+
+ Deprecated: Marked as deprecated in mesh/v1alpha1/config.proto.
+ items:
+ type: string
+ type: array
+ includeRequestBodyInCheck:
+ description: If set, the client request body will
+ be included in the authorization request sent
+ to the authorization service.
+ properties:
+ allowPartialMessage:
+ description: |-
+ When this field is true, ext-authz filter will buffer the message until maxRequestBytes is reached.
+ The authorization request will be dispatched and no 413 HTTP error will be returned by the filter.
+ A "x-envoy-auth-partial-body: false|true" metadata header will be added to the authorization request message
+ indicating if the body data is partial.
+ type: boolean
+ maxRequestBytes:
+ description: |-
+ Sets the maximum size of a message body that the ext-authz filter will hold in memory.
+ If maxRequestBytes is reached, and allowPartialMessage is false, Envoy will return a 413 (Payload Too Large).
+ Otherwise the request will be sent to the provider with a partial message.
+ Note that this setting will have precedence over the failOpen field, the 413 will be returned even when the
+ failOpen is set to true.
+ format: int32
+ type: integer
+ packAsBytes:
+ description: |-
+ If true, the body sent to the external authorization service in the gRPC authorization request is set with raw bytes
+ in the [raw_body field](https://github.com/envoyproxy/envoy/blame/cffb095d59d7935abda12b9509bcd136808367bb/api/envoy/service/auth/v3/attribute_context.proto#L153).
+ Otherwise, it will be filled with UTF-8 string in the [body field](https://github.com/envoyproxy/envoy/blame/cffb095d59d7935abda12b9509bcd136808367bb/api/envoy/service/auth/v3/attribute_context.proto#L147).
+ This field only works with the envoyExtAuthzGrpc provider and has no effect for the envoyExtAuthzHttp provider.
+ type: boolean
+ type: object
+ includeRequestHeadersInCheck:
+ description: |-
+ List of client request headers that should be included in the authorization request sent to the authorization service.
+ Note that in addition to the headers specified here following headers are included by default:
+ 1. *Host*, *Method*, *Path* and *Content-Length* are automatically sent.
+ 2. *Content-Length* will be set to 0 and the request will not have a message body. However, the authorization
+ request can include the buffered client request body (controlled by includeRequestBodyInCheck setting),
+ consequently the value of Content-Length of the authorization request reflects the size of its payload size.
+
+ Exact, prefix and suffix matches are supported (similar to the
+ [authorization policy rule syntax](https://istio.io/latest/docs/reference/config/security/authorization-policy/#Rule)
+ except the presence match):
+ - Exact match: "abc" will match on value "abc".
+ - Prefix match: "abc*" will match on value "abc" and "abcd".
+ - Suffix match: "*abc" will match on value "abc" and "xabc".
+ items:
+ type: string
+ type: array
+ pathPrefix:
+ description: |-
+ Sets a prefix to the value of authorization request header *Path*.
+ For example, setting this to "/check" for an original user request at path "/admin" will cause the
+ authorization check request to be sent to the authorization service at the path "/check/admin" instead of "/admin".
+ type: string
+ port:
+ description: REQUIRED. Specifies the port of the
+ service.
+ format: int32
+ type: integer
+ service:
+ description: |-
+ REQUIRED. Specifies the service that implements the Envoy ext_authz HTTP authorization service.
+ The format is `[/]`. The specification of `` is required only when it is insufficient
+ to unambiguously resolve a service in the service registry. The `` is a fully qualified host name of a
+ service defined by the Kubernetes service or ServiceEntry.
+
+ Example: "my-ext-authz.foo.svc.cluster.local" or "bar/my-ext-authz.example.com".
+ type: string
+ statusOnError:
+ description: |-
+ Sets the HTTP status that is returned to the client when there is a network error to the authorization service.
+ The default status is "403" (HTTP Forbidden).
+ type: string
+ timeout:
+ description: |-
+ The maximum duration that the proxy will wait for a response from the provider (default timeout: 600s).
+ When this timeout condition is met, the proxy marks the communication to the authorization service as failure.
+ In this situation, the response sent back to the client will depend on the configured `failOpen` field.
+ type: string
+ required:
+ - port
+ - service
+ type: object
+ envoyFileAccessLog:
+ description: Configures an Envoy File Access Log provider.
+ properties:
+ logFormat:
+ description: Optional. Allows overriding of the
+ default access log format.
+ properties:
+ labels:
+ additionalProperties:
+ type: string
+ description: "JSON structured format for the
+ envoy access logs. Envoy [command operators](https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#command-operators)\ncan
+ be used as values for fields within the Struct.
+ Values are rendered\nas strings, numbers,
+ or boolean values, as appropriate\n(see: [format
+ dictionaries](https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#config-access-log-format-dictionaries)).
+ Nested JSON is\nsupported for some command
+ operators (e.g. `FILTER_STATE` or `DYNAMIC_METADATA`).\nUse
+ `labels: {}` for default envoy JSON log format.\n\nExample:\n```\nlabels:\n\n\tstatus:
+ \"%RESPONSE_CODE%\"\n\tmessage: \"%LOCAL_REPLY_BODY%\"\n\n```"
+ type: object
+ text:
+ description: |-
+ Textual format for the envoy access logs. Envoy [command operators](https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#command-operators) may be
+ used in the format. The [format string documentation](https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#config-access-log-format-strings)
+ provides more information.
+
+ NOTE: Istio will insert a newline ('\n') on all formats (if missing).
+
+ Example: `text: "%LOCAL_REPLY_BODY%:%RESPONSE_CODE%:path=%REQ(:path)%"`
+ type: string
+ type: object
+ x-kubernetes-validations:
+ - message: At most one of [text labels] should be
+ set
+ rule: (has(self.text)?1:0) + (has(self.labels)?1:0)
+ <= 1
+ omitEmptyValues:
+ description: |-
+ Optional. If set to true, when command operators are evaluated to null,
+ For text format, the output of the empty operator is changed from "-" to an empty string.
+ For json format, the keys with null values are omitted in the output structure.
+ type: boolean
+ path:
+ description: |-
+ Path to a local file to write the access log entries.
+ This may be used to write to streams, via `/dev/stderr` and `/dev/stdout`
+ If unspecified, defaults to `/dev/stdout`.
+ type: string
+ type: object
+ envoyHttpAls:
+ description: Configures an Envoy Access Logging Service
+ provider for HTTP traffic.
+ properties:
+ additionalRequestHeadersToLog:
+ description: Optional. Additional request headers
+ to log.
+ items:
+ type: string
+ type: array
+ additionalResponseHeadersToLog:
+ description: Optional. Additional response headers
+ to log.
+ items:
+ type: string
+ type: array
+ additionalResponseTrailersToLog:
+ description: Optional. Additional response trailers
+ to log.
+ items:
+ type: string
+ type: array
+ filterStateObjectsToLog:
+ description: Optional. Additional filter state objects
+ to log.
+ items:
+ type: string
+ type: array
+ logName:
+ description: |-
+ Optional. The friendly name of the access log.
+ Defaults:
+ - "http_envoy_accesslog"
+ - "listener_envoy_accesslog"
+ type: string
+ port:
+ description: REQUIRED. Specifies the port of the
+ service.
+ format: int32
+ type: integer
+ service:
+ description: |-
+ REQUIRED. Specifies the service that implements the Envoy ALS gRPC authorization service.
+ The format is `[/]`. The specification of `` is required only when it is insufficient
+ to unambiguously resolve a service in the service registry. The `` is a fully qualified host name of a
+ service defined by the Kubernetes service or ServiceEntry.
+
+ Example: "envoy-als.foo.svc.cluster.local" or "bar/envoy-als.example.com".
+ type: string
+ required:
+ - port
+ - service
+ type: object
+ envoyOtelAls:
+ description: Configures an Envoy Open Telemetry Access
+ Logging Service provider.
+ properties:
+ logFormat:
+ description: |-
+ Optional. Format for the proxy access log
+ Empty value results in proxy's default access log format, following Envoy access logging formatting.
+ properties:
+ labels:
+ additionalProperties:
+ type: string
+ description: "Optional. Additional attributes
+ that describe the specific event occurrence.\nStructured
+ format for the envoy access logs. Envoy [command
+ operators](https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#command-operators)\ncan
+ be used as values for fields within the Struct.
+ Values are rendered\nas strings, numbers,
+ or boolean values, as appropriate\n(see: [format
+ dictionaries](https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#config-access-log-format-dictionaries)).
+ Nested JSON is\nsupported for some command
+ operators (e.g. FILTER_STATE or DYNAMIC_METADATA).\nAlias
+ to `attributes` field in [Open Telemetry](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/access_loggers/open_telemetry/v3/logs_service.proto)\n\nExample:\n```\nlabels:\n\n\tstatus:
+ \"%RESPONSE_CODE%\"\n\tmessage: \"%LOCAL_REPLY_BODY%\"\n\n```"
+ type: object
+ text:
+ description: |-
+ Textual format for the envoy access logs. Envoy [command operators](https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#command-operators) may be
+ used in the format. The [format string documentation](https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#config-access-log-format-strings)
+ provides more information.
+ Alias to `body` field in [Open Telemetry](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/access_loggers/open_telemetry/v3/logs_service.proto)
+ Example: `text: "%LOCAL_REPLY_BODY%:%RESPONSE_CODE%:path=%REQ(:path)%"`
+ type: string
+ type: object
+ logName:
+ description: |-
+ Optional. The friendly name of the access log.
+ Defaults:
+ - "otel_envoy_accesslog"
+ type: string
+ port:
+ description: REQUIRED. Specifies the port of the
+ service.
+ format: int32
+ type: integer
+ service:
+ description: |-
+ REQUIRED. Specifies the service that implements the Envoy ALS gRPC authorization service.
+ The format is `[/]`. The specification of `` is required only when it is insufficient
+ to unambiguously resolve a service in the service registry. The `` is a fully qualified host name of a
+ service defined by the Kubernetes service or ServiceEntry.
+
+ Example: "envoy-als.foo.svc.cluster.local" or "bar/envoy-als.example.com".
+ type: string
+ required:
+ - port
+ - service
+ type: object
+ envoyTcpAls:
+ description: Configures an Envoy Access Logging Service
+ provider for TCP traffic.
+ properties:
+ filterStateObjectsToLog:
+ description: Optional. Additional filter state objects
+ to log.
+ items:
+ type: string
+ type: array
+ logName:
+ description: |-
+ Optional. The friendly name of the access log.
+ Defaults:
+ - "tcp_envoy_accesslog"
+ - "listener_envoy_accesslog"
+ type: string
+ port:
+ description: REQUIRED. Specifies the port of the
+ service.
+ format: int32
+ type: integer
+ service:
+ description: |-
+ REQUIRED. Specifies the service that implements the Envoy ALS gRPC authorization service.
+ The format is `[/]`. The specification of `` is required only when it is insufficient
+ to unambiguously resolve a service in the service registry. The `` is a fully qualified host name of a
+ service defined by the Kubernetes service or ServiceEntry.
+
+ Example: "envoy-als.foo.svc.cluster.local" or "bar/envoy-als.example.com".
+ type: string
+ required:
+ - port
+ - service
+ type: object
+ lightstep:
+ description: |-
+ Configures a Lightstep tracing provider.
+ Deprecated: For Istio 1.15+, please use an OpenTelemetryTracingProvider instead, more details can be found at https://github.com/istio/istio/issues/40027
+
+ Deprecated: Marked as deprecated in mesh/v1alpha1/config.proto.
+ properties:
+ accessToken:
+ description: The Lightstep access token.
+ type: string
+ maxTagLength:
+ description: |-
+ Optional. Controls the overall path length allowed in a reported span.
+ NOTE: currently only controls max length of the path tag.
+ format: int32
+ type: integer
+ port:
+ description: REQUIRED. Specifies the port of the
+ service.
+ format: int32
+ type: integer
+ service:
+ description: |-
+ REQUIRED. Specifies the service for the Lightstep collector.
+ The format is `[/]`. The specification of `` is required only when it is insufficient
+ to unambiguously resolve a service in the service registry. The `` is a fully qualified host name of a
+ service defined by the Kubernetes service or ServiceEntry.
+
+ Example: "lightstep.default.svc.cluster.local" or "bar/lightstep.example.com".
+ type: string
+ required:
+ - port
+ - service
+ type: object
+ name:
+ description: REQUIRED. A unique name identifying the
+ extension provider.
+ type: string
+ opencensus:
+ description: |-
+ Configures an OpenCensusAgent tracing provider.
+ Deprecated: OpenCensus is deprecated, more details can be found at https://opentelemetry.io/blog/2023/sunsetting-opencensus/
+
+ Deprecated: Marked as deprecated in mesh/v1alpha1/config.proto.
+ properties:
+ context:
+ description: |-
+ Specifies the set of context propagation headers used for distributed
+ tracing. Default is `["W3C_TRACE_CONTEXT"]`. If multiple values are specified,
+ the proxy will attempt to read each header for each request and will
+ write all headers.
+ items:
+ description: |-
+ TraceContext selects the context propagation headers used for
+ distributed tracing.
+ enum:
+ - UNSPECIFIED
+ - W3C_TRACE_CONTEXT
+ - GRPC_BIN
+ - CLOUD_TRACE_CONTEXT
+ - B3
+ type: string
+ type: array
+ maxTagLength:
+ description: |-
+ Optional. Controls the overall path length allowed in a reported span.
+ NOTE: currently only controls max length of the path tag.
+ format: int32
+ type: integer
+ port:
+ description: REQUIRED. Specifies the port of the
+ service.
+ format: int32
+ type: integer
+ service:
+ description: |-
+ REQUIRED. Specifies the service for the OpenCensusAgent.
+ The format is `[/]`. The specification of `` is required only when it is insufficient
+ to unambiguously resolve a service in the service registry. The `` is a fully qualified host name of a
+ service defined by the Kubernetes service or ServiceEntry.
+
+ Example: "ocagent.default.svc.cluster.local" or "bar/ocagent.example.com".
+ type: string
+ required:
+ - port
+ - service
+ type: object
+ opentelemetry:
+ description: Configures an OpenTelemetry tracing provider.
+ properties:
+ dynatraceSampler:
+ description: |-
+ The Dynatrace adaptive traffic management (ATM) sampler.
+
+ Example configuration:
+
+ ```yaml
+ - name: otel-tracing
+ opentelemetry:
+ port: 443
+ service: "{your-environment-id}.live.dynatrace.com"
+ http:
+ path: "/api/v2/otlp/v1/traces"
+ timeout: 10s
+ headers:
+ - name: "Authorization"
+ value: "Api-Token dt0c01."
+ resourceDetectors:
+ dynatrace: {}
+ dynatraceSampler:
+ tenant: "{your-environment-id}"
+ clusterId: 1234
+ properties:
+ clusterId:
+ description: |-
+ REQUIRED. The identifier of the cluster in the Dynatrace platform.
+ The cluster here is Dynatrace-specific concept and not related to the cluster concept in Istio/Envoy.
+
+ The value can be obtained from the Istio deployment page in Dynatrace.
+ format: int32
+ type: integer
+ httpService:
+ description: |-
+ Optional. Dynatrace HTTP API to obtain sampling configuration.
+
+ When not provided, the Dynatrace Sampler will re-use the configuration from the OpenTelemetryTracingProvider HTTP Exporter
+ (`service`, `port` and `http`), including the access token.
+ properties:
+ http:
+ description: REQUIRED. Specifies sampling
+ configuration URI.
+ properties:
+ headers:
+ description: |-
+ Optional. Allows specifying custom HTTP headers that will be added
+ to each HTTP request sent.
+ items:
+ properties:
+ envName:
+ description: |-
+ The HTTP header value from the environment variable.
+
+ Warning:
+ - The environment variable must be set in the istiod pod spec.
+ - This is not a end-to-end secure.
+ type: string
+ name:
+ description: REQUIRED. The HTTP
+ header name.
+ type: string
+ value:
+ description: The HTTP header value.
+ type: string
+ required:
+ - name
+ type: object
+ x-kubernetes-validations:
+ - message: At most one of [value envName]
+ should be set
+ rule: (has(self.value)?1:0) + (has(self.envName)?1:0)
+ <= 1
+ type: array
+ path:
+ description: REQUIRED. Specifies the
+ path on the service.
+ type: string
+ timeout:
+ description: |-
+ Optional. Specifies the timeout for the HTTP request.
+ If not specified, the default is 3s.
+ type: string
+ required:
+ - path
+ type: object
+ port:
+ description: REQUIRED. Specifies the port
+ of the service.
+ format: int32
+ type: integer
+ service:
+ description: |-
+ REQUIRED. Specifies the Dynatrace environment to obtain the sampling configuration.
+ The format is ``, where `` is the fully qualified Dynatrace environment
+ host name defined in the ServiceEntry.
+
+ Example: "{your-environment-id}.live.dynatrace.com".
+ type: string
+ required:
+ - http
+ - port
+ - service
+ type: object
+ rootSpansPerMinute:
+ description: |-
+ Optional. Number of sampled spans per minute to be used
+ when the adaptive value cannot be obtained from the Dynatrace API.
+
+ A default value of `1000` is used when:
+
+ - `rootSpansPerMinute` is unset
+ - `rootSpansPerMinute` is set to 0
+ format: int32
+ type: integer
+ tenant:
+ description: |-
+ REQUIRED. The Dynatrace customer's tenant identifier.
+
+ The value can be obtained from the Istio deployment page in Dynatrace.
+ type: string
+ required:
+ - clusterId
+ - tenant
+ type: object
+ grpc:
+ description: "Optional. Specifies the configuration
+ for exporting OTLP traces via GRPC.\nWhen empty,
+ traces will check whether HTTP is set.\nIf not,
+ traces will use default GRPC configurations.\n\nThe
+ following example shows how to configure the OpenTelemetry
+ ExtensionProvider to export via GRPC:\n\n1. Add/change
+ the OpenTelemetry extension provider in `MeshConfig`\n```yaml\n
+ \ - name: opentelemetry\n opentelemetry:\n
+ \ port: 8090\n service: tracing.example.com\n
+ \ grpc:\n timeout: 10s\n initialMetadata:\n
+ \ - name: \"Authentication\"\n value: \"token-xxxxx\"\n\n```\n\n2.
+ Deploy a `ServiceEntry` for the observability
+ back-end\n```yaml\napiVersion: networking.istio.io/v1alpha3\nkind:
+ ServiceEntry\nmetadata:\n\n\tname: tracing-grpc\n\nspec:\n\n\thosts:\n\t-
+ tracing.example.com\n\tports:\n\t- number: 8090\n\t
+ \ name: grpc-port\n\t protocol: GRPC\n\tresolution:
+ DNS\n\tlocation: MESH_EXTERNAL\n\n```"
+ properties:
+ initialMetadata:
+ description: |-
+ Optional. Additional metadata to include in streams initiated to the GrpcService. This can be used for
+ scenarios in which additional ad hoc authorization headers (e.g. "x-foo-bar: baz-key") are to
+ be injected.
+ items:
+ properties:
+ envName:
+ description: |-
+ The HTTP header value from the environment variable.
+
+ Warning:
+ - The environment variable must be set in the istiod pod spec.
+ - This is not a end-to-end secure.
+ type: string
+ name:
+ description: REQUIRED. The HTTP header
+ name.
+ type: string
+ value:
+ description: The HTTP header value.
+ type: string
+ required:
+ - name
+ type: object
+ x-kubernetes-validations:
+ - message: At most one of [value envName]
+ should be set
+ rule: (has(self.value)?1:0) + (has(self.envName)?1:0)
+ <= 1
+ type: array
+ timeout:
+ description: Optional. Specifies the timeout
+ for the GRPC request.
+ type: string
+ type: object
+ http:
+ description: "Optional. Specifies the configuration
+ for exporting OTLP traces via HTTP.\nWhen empty,
+ traces will be exported via gRPC.\n\nThe following
+ example shows how to configure the OpenTelemetry
+ ExtensionProvider to export via HTTP:\n\n1. Add/change
+ the OpenTelemetry extension provider in `MeshConfig`\n```yaml\n
+ \ - name: otel-tracing\n opentelemetry:\n port:
+ 443\n service: my.olly-backend.com\n http:\n
+ \ path: \"/api/otlp/traces\"\n timeout: 10s\n
+ \ headers:\n - name: \"my-custom-header\"\n
+ \ value: \"some value\"\n\n```\n\n2. Deploy
+ a `ServiceEntry` for the observability back-end\n```yaml\napiVersion:
+ networking.istio.io/v1alpha3\nkind: ServiceEntry\nmetadata:\n\n\tname:
+ my-olly-backend\n\nspec:\n\n\thosts:\n\t- my.olly-backend.com\n\tports:\n\t-
+ number: 443\n\t name: https-port\n\t protocol:
+ HTTPS\n\tresolution: DNS\n\tlocation: MESH_EXTERNAL\n\n---\napiVersion:
+ networking.istio.io/v1alpha3\nkind: DestinationRule\nmetadata:\n\n\tname:
+ my-olly-backend\n\nspec:\n\n\thost: my.olly-backend.com\n\ttrafficPolicy:\n\t
+ \ portLevelSettings:\n\t - port:\n\t number:
+ 443\n\t tls:\n\t mode: SIMPLE\n\n```"
+ properties:
+ headers:
+ description: |-
+ Optional. Allows specifying custom HTTP headers that will be added
+ to each HTTP request sent.
+ items:
+ properties:
+ envName:
+ description: |-
+ The HTTP header value from the environment variable.
+
+ Warning:
+ - The environment variable must be set in the istiod pod spec.
+ - This is not a end-to-end secure.
+ type: string
+ name:
+ description: REQUIRED. The HTTP header
+ name.
+ type: string
+ value:
+ description: The HTTP header value.
+ type: string
+ required:
+ - name
+ type: object
+ x-kubernetes-validations:
+ - message: At most one of [value envName]
+ should be set
+ rule: (has(self.value)?1:0) + (has(self.envName)?1:0)
+ <= 1
+ type: array
+ path:
+ description: REQUIRED. Specifies the path on
+ the service.
+ type: string
+ timeout:
+ description: |-
+ Optional. Specifies the timeout for the HTTP request.
+ If not specified, the default is 3s.
+ type: string
+ required:
+ - path
+ type: object
+ maxTagLength:
+ description: |-
+ Optional. Controls the overall path length allowed in a reported span.
+ NOTE: currently only controls max length of the path tag.
+ format: int32
+ type: integer
+ port:
+ description: REQUIRED. Specifies the port of the
+ service.
+ format: int32
+ type: integer
+ resourceDetectors:
+ description: |-
+ Optional. Specifies [Resource Detectors](https://opentelemetry.io/docs/specs/otel/resource/sdk/)
+ to be used by the OpenTelemetry Tracer. When multiple resources are provided, they are merged
+ according to the OpenTelemetry [Resource specification](https://opentelemetry.io/docs/specs/otel/resource/sdk/#merge).
+
+ The following example shows how to configure the Environment Resource Detector, that will
+ read the attributes from the environment variable `OTEL_RESOURCE_ATTRIBUTES`:
+
+ ```yaml
+ - name: otel-tracing
+ opentelemetry:
+ port: 443
+ service: my.olly-backend.com
+ resourceDetectors:
+ environment: {}
+
+ ```
+ properties:
+ dynatrace:
+ description: |-
+ Dynatrace Resource Detector.
+ The resource detector reads from the Dynatrace enrichment files
+ and adds host/process related attributes to the OpenTelemetry resource.
+
+ See: [Enrich ingested data with Dynatrace-specific dimensions](https://docs.dynatrace.com/docs/shortlink/enrichment-files)
+ type: object
+ environment:
+ description: |-
+ OpenTelemetry Environment Resource Detector.
+ The resource detector reads attributes from the environment variable `OTEL_RESOURCE_ATTRIBUTES`
+ and adds them to the OpenTelemetry resource.
+
+ See: [Resource specification](https://opentelemetry.io/docs/specs/otel/resource/sdk/#specifying-resource-information-via-an-environment-variable)
+ type: object
+ type: object
+ service:
+ description: |-
+ REQUIRED. Specifies the OpenTelemetry endpoint that will receive OTLP traces.
+ The format is `[/]`. The specification of `` is required only when it is insufficient
+ to unambiguously resolve a service in the service registry. The `` is a fully qualified host name of a
+ service defined by the Kubernetes service or ServiceEntry.
+
+ Example: "otlp.default.svc.cluster.local" or "bar/otlp.example.com".
+ type: string
+ required:
+ - port
+ - service
+ type: object
+ x-kubernetes-validations:
+ - message: At most one of [dynatraceSampler] should
+ be set
+ rule: (has(self.dynatraceSampler)?1:0) <= 1
+ prometheus:
+ description: Configures a Prometheus metrics provider.
+ type: object
+ sds:
+ description: |-
+ Configures an Extension Provider for SDS. This can be used to
+ configure an external SDS service to supply secrets for certain Gateways for example.
+ This is useful for scenarios where the secrets are stored in an external secret store like Vault.
+ The secret should be configured with sds://provider-name format.
+ properties:
+ name:
+ description: REQUIRED. Specifies the name of the
+ provider. This should be used to configure the
+ Gateway SDS.
+ type: string
+ port:
+ description: REQUIRED. Specifies the port of the
+ service.
+ format: int32
+ type: integer
+ service:
+ description: |-
+ REQUIRED. Specifies the service that implements the SDS service.
+ The format is `[/]`. The specification of `` is required only when it is insufficient
+ to unambiguously resolve a service in the service registry. The `` is a fully qualified host name of a
+ service defined by the Kubernetes service or ServiceEntry.
+
+ Example: "gateway-sds.foo.svc.cluster.local" or "bar/gateway-sds.example.com".
+ type: string
+ required:
+ - name
+ - port
+ - service
+ type: object
+ skywalking:
+ description: Configures a Apache SkyWalking provider.
+ properties:
+ accessToken:
+ description: Optional. The SkyWalking OAP access
+ token.
+ type: string
+ port:
+ description: REQUIRED. Specifies the port of the
+ service.
+ format: int32
+ type: integer
+ service:
+ description: |-
+ REQUIRED. Specifies the service for the SkyWalking receiver.
+ The format is `[/]`. The specification of `` is required only when it is insufficient
+ to unambiguously resolve a service in the service registry. The `` is a fully qualified host name of a
+ service defined by the Kubernetes service or ServiceEntry.
+
+ Example: "skywalking.default.svc.cluster.local" or "bar/skywalking.example.com".
+ type: string
+ required:
+ - port
+ - service
+ type: object
+ stackdriver:
+ description: Configures a Stackdriver provider.
+ properties:
+ debug:
+ description: |-
+ debug enables trace output to stdout.
+
+ Deprecated: Marked as deprecated in mesh/v1alpha1/config.proto.
+ type: boolean
+ logging:
+ description: Optional. Controls Stackdriver logging
+ behavior.
+ properties:
+ labels:
+ additionalProperties:
+ type: string
+ description: "Collection of tag names and tag
+ expressions to include in the log\nentry.
+ Conflicts are resolved by the tag name by
+ overriding previously\nsupplied values.\n\nExample:\n\n\tlabels:\n\t
+ \ path: request.url_path\n\t foo: request.headers['x-foo']"
+ type: object
+ type: object
+ maxNumberOfAnnotations:
+ description: |-
+ The global default max number of annotation events per span.
+ default is 200.
+
+ Deprecated: Marked as deprecated in mesh/v1alpha1/config.proto.
+ format: int64
+ type: integer
+ maxNumberOfAttributes:
+ description: |-
+ The global default max number of attributes per span.
+ default is 200.
+
+ Deprecated: Marked as deprecated in mesh/v1alpha1/config.proto.
+ format: int64
+ type: integer
+ maxNumberOfMessageEvents:
+ description: |-
+ The global default max number of message events per span.
+ default is 200.
+
+ Deprecated: Marked as deprecated in mesh/v1alpha1/config.proto.
+ format: int64
+ type: integer
+ maxTagLength:
+ description: |-
+ Optional. Controls the overall path length allowed in a reported span.
+ NOTE: currently only controls max length of the path tag.
+ format: int32
+ type: integer
+ type: object
+ zipkin:
+ description: Configures a tracing provider that uses
+ the Zipkin API.
+ properties:
+ enable64bitTraceId:
+ description: |-
+ Optional. A 128 bit trace id will be used in Istio.
+ If true, will result in a 64 bit trace id being used.
+ type: boolean
+ headers:
+ description: |-
+ Optional. Additional HTTP headers to include in the request to the Zipkin collector.
+ These headers will be added to the HTTP request when sending spans to the collector.
+ items:
+ properties:
+ envName:
+ description: |-
+ The HTTP header value from the environment variable.
+
+ Warning:
+ - The environment variable must be set in the istiod pod spec.
+ - This is not a end-to-end secure.
+ type: string
+ name:
+ description: REQUIRED. The HTTP header name.
+ type: string
+ value:
+ description: The HTTP header value.
+ type: string
+ required:
+ - name
+ type: object
+ x-kubernetes-validations:
+ - message: At most one of [value envName] should
+ be set
+ rule: (has(self.value)?1:0) + (has(self.envName)?1:0)
+ <= 1
+ type: array
+ maxTagLength:
+ description: |-
+ Optional. Controls the overall path length allowed in a reported span.
+ NOTE: currently only controls max length of the path tag.
+ format: int32
+ type: integer
+ path:
+ description: |-
+ Optional. Specifies the endpoint of Zipkin API.
+ The default value is "/api/v2/spans".
+ type: string
+ port:
+ description: REQUIRED. Specifies the port of the
+ service.
+ format: int32
+ type: integer
+ service:
+ description: |-
+ REQUIRED. Specifies the service that the Zipkin API.
+ The format is `[/]`. The specification of `` is required only when it is insufficient
+ to unambiguously resolve a service in the service registry. The `` is a fully qualified host name of a
+ service defined by the Kubernetes service or ServiceEntry.
+
+ Example: "zipkin.default.svc.cluster.local" or "bar/zipkin.example.com".
+ type: string
+ timeout:
+ description: |-
+ Optional. The timeout for the HTTP request to the Zipkin collector.
+ If not specified, the default timeout from Envoy's configuration will be used (which is 5 seconds currently).
+ type: string
+ traceContextOption:
+ description: |-
+ Optional. Determines which trace context format to use for trace header extraction and propagation.
+ This controls both downstream request header extraction and upstream request header injection.
+ The default value is USE_B3 to maintain backward compatibility.
+ enum:
+ - USE_B3
+ - USE_B3_WITH_W3C_PROPAGATION
+ type: string
+ required:
+ - port
+ - service
+ type: object
+ required:
+ - name
+ type: object
+ x-kubernetes-validations:
+ - message: At most one of [envoyExtAuthzHttp envoyExtAuthzGrpc
+ zipkin lightstep datadog stackdriver opencensus skywalking
+ opentelemetry prometheus envoyFileAccessLog envoyHttpAls
+ envoyTcpAls envoyOtelAls sds] should be set
+ rule: (has(self.envoyExtAuthzHttp)?1:0) + (has(self.envoyExtAuthzGrpc)?1:0)
+ + (has(self.zipkin)?1:0) + (has(self.lightstep)?1:0)
+ + (has(self.datadog)?1:0) + (has(self.stackdriver)?1:0)
+ + (has(self.opencensus)?1:0) + (has(self.skywalking)?1:0)
+ + (has(self.opentelemetry)?1:0) + (has(self.prometheus)?1:0)
+ + (has(self.envoyFileAccessLog)?1:0) + (has(self.envoyHttpAls)?1:0)
+ + (has(self.envoyTcpAls)?1:0) + (has(self.envoyOtelAls)?1:0)
+ + (has(self.sds)?1:0) <= 1
+ maxItems: 1000
+ type: array
+ h2UpgradePolicy:
+ description: |-
+ Specify if http1.1 connections should be upgraded to http2 by default.
+ if sidecar is installed on all pods in the mesh, then this should be set to `UPGRADE`.
+ If one or more services or namespaces do not have sidecar(s), then this should be set to `DO_NOT_UPGRADE`.
+ It can be enabled by destination using the `destinationRule.trafficPolicy.connectionPool.http.h2UpgradePolicy` override.
+ enum:
+ - DO_NOT_UPGRADE
+ - UPGRADE
+ type: string
+ hboneIdleTimeout:
+ description: |-
+ Idle timeout configured on Envoy proxies for their connection pools to ztunnel via HBONE.
+ This controls how long Envoy will keep idle connections to ztunnel before closing them.
+ Note: This setting is applied only on the Envoy proxy side; ztunnel does not use it.
+ Default timeout is 1 hour (3600s).
+ For environments with aggressive IP address reuse, it is recommended to set
+ this to a value less than the CNI IP cooldown period to prevent stale connection reuse.
+ For example, if your CNI has a 30s cooldown period, setting this to 15s is recommended.
+ type: string
+ inboundClusterStatName:
+ description: |-
+ Name to be used while emitting statistics for inbound clusters. The same pattern is used while computing stat prefix for
+ network filters like TCP and Redis.
+ By default, Istio emits statistics with the pattern `inbound|||`.
+ For example `inbound|7443|grpc-reviews|reviews.prod.svc.cluster.local`. This can be used to override that pattern.
+
+ A Pattern can be composed of various pre-defined variables. The following variables are supported.
+
+ - `%SERVICE%` - Will be substituted with short hostname of the service.
+ - `%SERVICE_NAME%` - Will be substituted with name of the service.
+ - `%SERVICE_FQDN%` - Will be substituted with FQDN of the service.
+ - `%SERVICE_PORT%` - Will be substituted with port of the service.
+ - `%TARGET_PORT%` - Will be substituted with the target port of the service.
+ - `%SERVICE_PORT_NAME%` - Will be substituted with port name of the service.
+
+ Following are some examples of supported patterns for reviews:
+
+ - `%SERVICE_FQDN%_%SERVICE_PORT%` will use reviews.prod.svc.cluster.local_7443 as the stats name.
+ - `%SERVICE%` will use reviews.prod as the stats name.
+ type: string
+ inboundTrafficPolicy:
+ description: |-
+ Set the default behavior of the sidecar for handling inbound
+ traffic to the application. If your application listens on
+ localhost, you will need to set this to `LOCALHOST`.
+ properties:
+ mode:
+ enum:
+ - PASSTHROUGH
+ - LOCALHOST
+ type: string
+ type: object
+ ingressClass:
+ description: |-
+ Class of ingress resources to be processed by Istio ingress
+ controller. This corresponds to the value of
+ `kubernetes.io/ingress.class` annotation.
+ type: string
+ ingressControllerMode:
+ description: |-
+ Defines whether to use Istio ingress controller for annotated or all ingress resources.
+ Default mode is `STRICT`.
+ enum:
+ - UNSPECIFIED
+ - "OFF"
+ - DEFAULT
+ - STRICT
+ type: string
+ ingressSelector:
+ description: |-
+ Defines which gateway deployment to use as the Ingress controller. This field corresponds to
+ the Gateway.selector field, and will be set as `istio: INGRESS_SELECTOR`.
+ By default, `ingressgateway` is used, which will select the default IngressGateway as it has the
+ `istio: ingressgateway` labels.
+ It is recommended that this is the same value as ingressService.
+ type: string
+ ingressService:
+ description: |-
+ Name of the Kubernetes service used for the istio ingress controller.
+ If no ingress controller is specified, the default value `istio-ingressgateway` is used.
+ type: string
+ localityLbSetting:
+ description: |-
+ Locality based load balancing distribution or failover settings.
+ If unspecified, locality based load balancing will be enabled by default.
+ However, this requires outlierDetection to actually take effect for a particular
+ service, see https://istio.io/latest/docs/tasks/traffic-management/locality-load-balancing/failover/
+ properties:
+ distribute:
+ description: |-
+ Optional: only one of distribute, failover or failoverPriority can be set.
+ Explicitly specify loadbalancing weight across different zones and geographical locations.
+ Refer to [Locality weighted load balancing](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/upstream/load_balancing/locality_weight)
+ If empty, the locality weight is set according to the endpoints number within it.
+ items:
+ description: |-
+ Describes how traffic originating in the 'from' zone or sub-zone is
+ distributed over a set of 'to' zones. Syntax for specifying a zone is
+ {region}/{zone}/{sub-zone} and terminal wildcards are allowed on any
+ segment of the specification. Examples:
+
+ `*` - matches all localities
+
+ `us-west/*` - all zones and sub-zones within the us-west region
+
+ `us-west/zone-1/*` - all sub-zones within us-west/zone-1
+ properties:
+ from:
+ description: Originating locality, '/' separated,
+ e.g. 'region/zone/sub_zone'.
+ type: string
+ to:
+ additionalProperties:
+ format: int32
+ type: integer
+ description: |-
+ Map of upstream localities to traffic distribution weights. The sum of
+ all weights should be 100. Any locality not present will
+ receive no traffic.
+ type: object
+ type: object
+ type: array
+ enabled:
+ description: |-
+ Enable locality load balancing. This is DestinationRule-level and will override mesh-wide settings in entirety.
+ e.g. true means that turn on locality load balancing for this DestinationRule no matter what mesh-wide settings is.
+ type: boolean
+ failover:
+ description: |-
+ Optional: only one of distribute, failover or failoverPriority can be set.
+ Explicitly specify the region traffic will land on when endpoints in local region becomes unhealthy.
+ Should be used together with OutlierDetection to detect unhealthy endpoints.
+ Note: if no OutlierDetection specified, this will not take effect.
+ items:
+ description: |-
+ Specify the traffic failover policy across regions. Since zone and sub-zone
+ failover is supported by default this only needs to be specified for
+ regions when the operator needs to constrain traffic failover so that
+ the default behavior of failing over to any endpoint globally does not
+ apply. This is useful when failing over traffic across regions would not
+ improve service health or may need to be restricted for other reasons
+ like regulatory controls.
+ properties:
+ from:
+ description: Originating region.
+ type: string
+ to:
+ description: |-
+ Destination region the traffic will fail over to when endpoints in
+ the 'from' region becomes unhealthy.
+ type: string
+ type: object
+ type: array
+ failoverPriority:
+ description: |-
+ failoverPriority is an ordered list of labels used to sort endpoints to do priority based load balancing.
+ This is to support traffic failover across different groups of endpoints.
+ Two kinds of labels can be specified:
+
+ - Specify only label keys `[key1, key2, key3]`, istio would compare the label values of client with endpoints.
+ Suppose there are total N label keys `[key1, key2, key3, ...keyN]` specified:
+
+ 1. Endpoints matching all N labels with the client proxy have priority P(0) i.e. the highest priority.
+ 2. Endpoints matching the first N-1 labels with the client proxy have priority P(1) i.e. second highest priority.
+ 3. By extension of this logic, endpoints matching only the first label with the client proxy has priority P(N-1) i.e. second lowest priority.
+ 4. All the other endpoints have priority P(N) i.e. lowest priority.
+
+ - Specify labels with key and value `[key1=value1, key2=value2, key3=value3]`, istio would compare the labels with endpoints.
+ Suppose there are total N labels `[key1=value1, key2=value2, key3=value3, ...keyN=valueN]` specified:
+
+ 1. Endpoints matching all N labels have priority P(0) i.e. the highest priority.
+ 2. Endpoints matching the first N-1 labels have priority P(1) i.e. second highest priority.
+ 3. By extension of this logic, endpoints matching only the first label has priority P(N-1) i.e. second lowest priority.
+ 4. All the other endpoints have priority P(N) i.e. lowest priority.
+
+ Note: For a label to be considered for match, the previous labels must match, i.e. nth label would be considered matched only if first n-1 labels match.
+
+ It can be any label specified on both client and server workloads.
+ The following labels which have special semantic meaning are also supported:
+
+ - `topology.istio.io/network` is used to match the network metadata of an endpoint, which can be specified by pod/namespace label `topology.istio.io/network`, sidecar env `ISTIO_META_NETWORK` or MeshNetworks.
+ - `topology.istio.io/cluster` is used to match the clusterID of an endpoint, which can be specified by pod label `topology.istio.io/cluster` or pod env `ISTIO_META_CLUSTER_ID`.
+ - `topology.kubernetes.io/region` is used to match the region metadata of an endpoint, which maps to Kubernetes node label `topology.kubernetes.io/region` or the deprecated label `failure-domain.beta.kubernetes.io/region`.
+ - `topology.kubernetes.io/zone` is used to match the zone metadata of an endpoint, which maps to Kubernetes node label `topology.kubernetes.io/zone` or the deprecated label `failure-domain.beta.kubernetes.io/zone`.
+ - `topology.istio.io/subzone` is used to match the subzone metadata of an endpoint, which maps to Istio node label `topology.istio.io/subzone`.
+ - `kubernetes.io/hostname` is used to match the current node of an endpoint, which maps to Kubernetes node label `kubernetes.io/hostname`.
+
+ The below topology config indicates the following priority levels:
+
+ ```yaml
+ failoverPriority:
+ - "topology.istio.io/network"
+ - "topology.kubernetes.io/region"
+ - "topology.kubernetes.io/zone"
+ - "topology.istio.io/subzone"
+ ```
+
+ 1. endpoints match same [network, region, zone, subzone] label with the client proxy have the highest priority.
+ 2. endpoints have same [network, region, zone] label but different [subzone] label with the client proxy have the second highest priority.
+ 3. endpoints have same [network, region] label but different [zone] label with the client proxy have the third highest priority.
+ 4. endpoints have same [network] but different [region] labels with the client proxy have the fourth highest priority.
+ 5. all the other endpoints have the same lowest priority.
+
+ Suppose a service associated endpoints reside in multi clusters, the below example represents:
+ 1. endpoints in `clusterA` and has `version=v1` label have P(0) priority.
+ 2. endpoints not in `clusterA` but has `version=v1` label have P(1) priority.
+ 2. all the other endpoints have P(2) priority.
+
+ ```yaml
+ failoverPriority:
+ - "version=v1"
+ - "topology.istio.io/cluster=clusterA"
+ ```
+
+ Optional: only one of distribute, failover or failoverPriority can be set.
+ And it should be used together with `OutlierDetection` to detect unhealthy endpoints, otherwise has no effect.
+ items:
+ type: string
+ type: array
+ type: object
+ meshMTLS:
+ description: "The below configuration parameters can be used
+ to specify TLSConfig for mesh traffic.\nFor example, a user
+ could enable min TLS version for ISTIO_MUTUAL traffic and
+ specify a curve for non ISTIO_MUTUAL traffic like below:\n```yaml\nmeshConfig:\n\n\tmeshMTLS:\n\t
+ \ minProtocolVersion: TLSV1_3\n\ttlsDefaults:\n\t Note:
+ applicable only for non ISTIO_MUTUAL scenarios\n\t ecdhCurves:\n\t
+ \ - P-256\n\t - P-512\n\n```\nConfiguration of mTLS
+ for traffic between workloads with ISTIO_MUTUAL TLS traffic.\n\nNote:
+ Mesh mTLS does not respect ECDH curves."
+ properties:
+ cipherSuites:
+ description: |-
+ Optional: If specified, the TLS connection will only support the specified cipher list when negotiating TLS 1.0-1.2.
+ If not specified, the following cipher suites will be used:
+ ```
+ ECDHE-ECDSA-AES256-GCM-SHA384
+ ECDHE-RSA-AES256-GCM-SHA384
+ ECDHE-ECDSA-AES128-GCM-SHA256
+ ECDHE-RSA-AES128-GCM-SHA256
+ AES256-GCM-SHA384
+ AES128-GCM-SHA256
+ ```
+ items:
+ type: string
+ type: array
+ ecdhCurves:
+ description: |-
+ Optional: If specified, the TLS connection will only support the specified ECDH curves for the DH key exchange.
+ If not specified, the default curves enforced by Envoy will be used. For details about the default curves, refer to
+ [Ecdh Curves](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/transport_sockets/tls/v3/common.proto).
+ items:
+ type: string
+ type: array
+ minProtocolVersion:
+ description: |-
+ Optional: the minimum TLS protocol version. The default minimum
+ TLS version will be TLS 1.2. As servers may not be Envoy and be
+ set to TLS 1.2 (e.g., workloads using mTLS without sidecars), the
+ minimum TLS version for clients may also be TLS 1.2.
+ In the current Istio implementation, the maximum TLS protocol version
+ is TLS 1.3.
+ enum:
+ - TLS_AUTO
+ - TLSV1_2
+ - TLSV1_3
+ type: string
+ type: object
+ outboundClusterStatName:
+ description: |-
+ Name to be used while emitting statistics for outbound clusters. The same pattern is used while computing stat prefix for
+ network filters like TCP and Redis.
+ By default, Istio emits statistics with the pattern `outbound|||`.
+ For example `outbound|8080|v2|reviews.prod.svc.cluster.local`. This can be used to override that pattern.
+
+ A Pattern can be composed of various pre-defined variables. The following variables are supported.
+
+ - `%SERVICE%` - Will be substituted with short hostname of the service.
+ - `%SERVICE_NAME%` - Will be substituted with name of the service.
+ - `%SERVICE_FQDN%` - Will be substituted with FQDN of the service.
+ - `%SERVICE_PORT%` - Will be substituted with port of the service.
+ - `%SERVICE_PORT_NAME%` - Will be substituted with port name of the service.
+ - `%SUBSET_NAME%` - Will be substituted with subset.
+
+ Following are some examples of supported patterns for reviews:
+
+ - `%SERVICE_FQDN%_%SERVICE_PORT%` will use `reviews.prod.svc.cluster.local_7443` as the stats name.
+ - `%SERVICE%` will use reviews.prod as the stats name.
+ type: string
+ outboundTrafficPolicy:
+ description: |-
+ Set the default behavior of the sidecar for handling outbound
+ traffic from the application.
+
+ Can be overridden at a Sidecar level by setting the `OutboundTrafficPolicy` in the
+ [Sidecar API](https://istio.io/docs/reference/config/networking/sidecar/#OutboundTrafficPolicy).
+
+ Default mode is `ALLOW_ANY`, which means outbound traffic to unknown destinations will be allowed.
+ properties:
+ mode:
+ enum:
+ - REGISTRY_ONLY
+ - ALLOW_ANY
+ type: string
+ type: object
+ pathNormalization:
+ description: |-
+ ProxyPathNormalization configures how URL paths in incoming and outgoing HTTP requests are
+ normalized by the sidecars and gateways.
+ The normalized paths will be used in all aspects through the requests' lifetime on the
+ sidecars and gateways, which includes routing decisions in outbound direction (client proxy),
+ authorization policy match and enforcement in inbound direction (server proxy), and the URL
+ path proxied to the upstream service.
+ If not set, the NormalizationType.DEFAULT configuration will be used.
+ properties:
+ normalization:
+ enum:
+ - DEFAULT
+ - NONE
+ - BASE
+ - MERGE_SLASHES
+ - DECODE_AND_MERGE_SLASHES
+ type: string
+ type: object
+ protocolDetectionTimeout:
+ description: |-
+ Automatic protocol detection uses a set of heuristics to
+ determine whether the connection is using TLS or not (on the
+ server side), as well as the application protocol being used
+ (e.g., http vs tcp). These heuristics rely on the client sending
+ the first bits of data. For server first protocols like MySQL,
+ MongoDB, etc. Envoy will timeout on the protocol detection after
+ the specified period, defaulting to non mTLS plain TCP
+ traffic. Set this field to tweak the period that Envoy will wait
+ for the client to send the first bits of data. (MUST be >=1ms or
+ 0s to disable). Default detection timeout is 0s (no timeout).
+
+ Setting a timeout is not recommended nor safe. Even high timeouts (>5s) will be hit
+ occasionally, and when they occur the result is typically broken traffic that may not
+ recover on its own. Exceptionally high values might solve this, but injecting 60s delays
+ onto new connections is generally not tenable anyways.
+ type: string
+ proxyHttpPort:
+ description: Port on which Envoy should listen for HTTP PROXY
+ requests if set.
+ format: int32
+ type: integer
+ proxyInboundListenPort:
+ description: |-
+ Port on which Envoy should listen for all inbound traffic to the pod/vm will be captured to.
+ Default port is 15006.
+ format: int32
+ type: integer
+ proxyListenPort:
+ description: |-
+ Port on which Envoy should listen for all outbound traffic to other services.
+ Default port is 15001.
+ format: int32
+ type: integer
+ rootNamespace:
+ description: |-
+ The namespace to treat as the administrative root namespace for
+ Istio configuration. When processing a leaf namespace Istio will search for
+ declarations in that namespace first and if none are found it will
+ search in the root namespace. Any matching declaration found in the root
+ namespace is processed as if it were declared in the leaf namespace.
+
+ The precise semantics of this processing are documented on each resource
+ type.
+ type: string
+ serviceScopeConfigs:
+ description: Scope to be applied to select services.
+ items:
+ description: |-
+ Configuration for ambient mode multicluster service scope. This setting allows mesh administrators
+ to define the criteria by which the cluster's control plane determines which services in other
+ clusters in the mesh are treated as global (accessible across multiple clusters) versus local
+ (restricted to a single cluster). The configuration can be applied to services based on namespace
+ and/or other matching criteria. This is particularly useful in multicluster service mesh deployments
+ to control service visibility and access across clusters. This API is not intended to enforce
+ security policies. Resources like DestinationRules should be used to enforce authorization policies.
+ If a service matches a global service scope selector, the service's endpoints will be globally
+ exposed. If a service is locally scoped, its endpoints will only be exposed to local cluster
+ services.
+
+ For example, the following configures the scope of all services with the "istio.io/global" label
+ in matching namespaces to be available globally:
+
+ ```yaml
+ serviceScopeConfigs:
+ - namespacesSelector:
+ matchExpressions:
+ - key: istio.io/global
+ operator: In
+ values: [true]
+ servicesSelector:
+ matchExpressions:
+ - key: istio.io/global
+ operator: Exists
+ scope: GLOBAL
+
+ ```
+ properties:
+ namespaceSelector:
+ description: Match expression for namespaces.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label
+ selector requirements. The requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label key that the
+ selector applies to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ scope:
+ description: Specifics the available scope for matching
+ services.
+ enum:
+ - LOCAL
+ - GLOBAL
+ type: string
+ servicesSelector:
+ description: Match expression for serivces.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label
+ selector requirements. The requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label key that the
+ selector applies to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ type: array
+ serviceSettings:
+ description: Settings to be applied to select services.
+ items:
+ description: |-
+ Settings to be applied to select services.
+
+ For example, the following configures all services in namespace "foo" as well as the
+ "bar" service in namespace "baz" to be considered cluster-local:
+
+ ```yaml
+ serviceSettings:
+ - settings:
+ clusterLocal: true
+ hosts:
+ - "*.foo.svc.cluster.local"
+ - "bar.baz.svc.cluster.local"
+
+ ```
+
+ When in ambient mode, if ServiceSettings are defined they will be considered in addition to the
+ ServiceScopeConfigs. If a service is defined by ServiceSetting to be cluster local and matches a
+ global service scope selector, the service will be considered cluster local. If a service is
+ considered global by ServiceSettings and does not match a global service scope selector
+ the serive will be considered local. Local scope takes precedence over global scope. Since
+ ServiceScopeConfigs is local by default, all services are considered local unless it is considered
+ global by ServiceSettings AND ServiceScopeConfigs.
+ properties:
+ hosts:
+ description: |-
+ The services to which the Settings should be applied. Services are selected using the hostname
+ matching rules used by DestinationRule.
+
+ For example: foo.bar.svc.cluster.local, *.baz.svc.cluster.local
+ items:
+ type: string
+ type: array
+ settings:
+ description: The settings to apply to the selected services.
+ properties:
+ clusterLocal:
+ description: |-
+ If true, specifies that the client and service endpoints must reside in the same cluster.
+ By default, in multi-cluster deployments, the Istio control plane assumes all service
+ endpoints to be reachable from any client in any of the clusters which are part of the
+ mesh. This configuration option limits the set of service endpoints visible to a client
+ to be cluster scoped.
+
+ There are some common scenarios when this can be useful:
+
+ - A service (or group of services) is inherently local to the cluster and has local storage
+ for that cluster. For example, the kube-system namespace (e.g. the Kube API Server).
+ - A mesh administrator wants to slowly migrate services to Istio. They might start by first
+ having services cluster-local and then slowly transition them to mesh-wide. They could do
+ this service-by-service (e.g. mysvc.myns.svc.cluster.local) or as a group
+ (e.g. *.myns.svc.cluster.local).
+
+ By default Istio will consider kubernetes.default.svc (i.e. the API Server) as well as all
+ services in the kube-system namespace to be cluster-local, unless explicitly overridden here.
+ type: boolean
+ type: object
+ type: object
+ type: array
+ tcpKeepalive:
+ description: If set then set `SO_KEEPALIVE` on the socket
+ to enable TCP Keepalives.
+ properties:
+ interval:
+ description: |-
+ The time duration between keep-alive probes.
+ Default is to use the OS level configuration
+ (unless overridden, Linux defaults to 75s.)
+ type: string
+ probes:
+ description: |-
+ Maximum number of keepalive probes to send without response before
+ deciding the connection is dead. Default is to use the OS level configuration
+ (unless overridden, Linux defaults to 9.)
+ format: int32
+ type: integer
+ time:
+ description: |-
+ The time duration a connection needs to be idle before keep-alive
+ probes start being sent. Default is to use the OS level configuration
+ (unless overridden, Linux defaults to 7200s (ie 2 hours.)
+ type: string
+ type: object
+ tlsDefaults:
+ description: |-
+ Configuration of TLS for all traffic except for ISTIO_MUTUAL mode.
+ For ISTIO_MUTUAL TLS settings, use meshMTLS configuration.
+ properties:
+ cipherSuites:
+ description: |-
+ Optional: If specified, the TLS connection will only support the specified cipher list when negotiating TLS 1.0-1.2.
+ If not specified, the following cipher suites will be used:
+ ```
+ ECDHE-ECDSA-AES256-GCM-SHA384
+ ECDHE-RSA-AES256-GCM-SHA384
+ ECDHE-ECDSA-AES128-GCM-SHA256
+ ECDHE-RSA-AES128-GCM-SHA256
+ AES256-GCM-SHA384
+ AES128-GCM-SHA256
+ ```
+ items:
+ type: string
+ type: array
+ ecdhCurves:
+ description: |-
+ Optional: If specified, the TLS connection will only support the specified ECDH curves for the DH key exchange.
+ If not specified, the default curves enforced by Envoy will be used. For details about the default curves, refer to
+ [Ecdh Curves](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/transport_sockets/tls/v3/common.proto).
+ items:
+ type: string
+ type: array
+ minProtocolVersion:
+ description: |-
+ Optional: the minimum TLS protocol version. The default minimum
+ TLS version will be TLS 1.2. As servers may not be Envoy and be
+ set to TLS 1.2 (e.g., workloads using mTLS without sidecars), the
+ minimum TLS version for clients may also be TLS 1.2.
+ In the current Istio implementation, the maximum TLS protocol version
+ is TLS 1.3.
+ enum:
+ - TLS_AUTO
+ - TLSV1_2
+ - TLSV1_3
+ type: string
+ type: object
+ trustDomain:
+ description: |-
+ The trust domain corresponds to the trust root of a system.
+ Refer to [SPIFFE-ID](https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE-ID.md#21-trust-domain)
+ type: string
+ trustDomainAliases:
+ description: |-
+ The trust domain aliases represent the aliases of `trustDomain`.
+ For example, if we have
+ ```yaml
+ trustDomain: td1
+ trustDomainAliases: ["td2", "td3"]
+ ```
+ Any service with the identity `td1/ns/foo/sa/a-service-account`, `td2/ns/foo/sa/a-service-account`,
+ or `td3/ns/foo/sa/a-service-account` will be treated the same in the Istio mesh.
+ items:
+ type: string
+ type: array
+ verifyCertificateAtClient:
+ description: |-
+ `VerifyCertificateAtClient` sets the mesh global default for peer certificate validation
+ at the client-side proxy when `SIMPLE` TLS or `MUTUAL` TLS (non `ISTIO_MUTUAL`) origination
+ modes are used. This setting can be overridden at the host level via DestinationRule API.
+ By default, `VerifyCertificateAtClient` is `true`.
+
+ `CaCertificates`: If set, proxy verifies CA signature based on given CaCertificates. If unset,
+ and VerifyCertificateAtClient is true, proxy uses default System CA bundle. If unset and
+ `VerifyCertificateAtClient` is false, proxy will not verify the CA.
+
+ `SubjectAltNames`: If set, proxy verifies subject alt names are present in the SAN. If unset,
+ and `VerifyCertificateAtClient` is true, proxy uses host in destination rule to verify the SANs.
+ If unset, and `VerifyCertificateAtClient` is false, proxy does not verify SANs.
+
+ For SAN, client-side proxy will exact match host in `DestinationRule` as well as one level
+ wildcard if the specified host in DestinationRule doesn't contain a wildcard.
+ For example, if the host in `DestinationRule` is `x.y.com`, client-side proxy will
+ match either `x.y.com` or `*.y.com` for the SAN in the presented server certificate.
+ For wildcard host name in DestinationRule, client-side proxy will do a suffix match. For example,
+ if host is `*.x.y.com`, client-side proxy will verify the presented server certificate SAN matches
+ `.x.y.com` suffix.
+
+ Deprecated: Marked as deprecated in mesh/v1alpha1/config.proto.
+ type: boolean
+ type: object
+ pilot:
+ description: Configuration for the Pilot component.
+ properties:
+ affinity:
+ description: K8s affinity to set on the Pilot Pods.
+ properties:
+ nodeAffinity:
+ description: Describes node affinity scheduling rules
+ for the pod.
+ properties:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ The scheduler will prefer to schedule pods to nodes that satisfy
+ the affinity expressions specified by this field, but it may choose
+ a node that violates one or more of the expressions. The node that is
+ most preferred is the one with the greatest sum of weights, i.e.
+ for each node that meets all of the scheduling requirements (resource
+ request, requiredDuringScheduling affinity expressions, etc.),
+ compute a sum by iterating through the elements of this field and adding
+ "weight" to the sum if the node matches the corresponding matchExpressions; the
+ node(s) with the highest sum are the most preferred.
+ items:
+ description: |-
+ An empty preferred scheduling term matches all objects with implicit weight 0
+ (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op).
+ properties:
+ preference:
+ description: A node selector term, associated
+ with the corresponding weight.
+ properties:
+ matchExpressions:
+ description: A list of node selector requirements
+ by node's labels.
+ items:
+ description: |-
+ A node selector requirement is a selector that contains values, a key, and an operator
+ that relates the key and values.
+ properties:
+ key:
+ description: The label key that the
+ selector applies to.
+ type: string
+ operator:
+ description: |-
+ Represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
+ type: string
+ values:
+ description: |-
+ An array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. If the operator is Gt or Lt, the values
+ array must have a single element, which will be interpreted as an integer.
+ This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchFields:
+ description: A list of node selector requirements
+ by node's fields.
+ items:
+ description: |-
+ A node selector requirement is a selector that contains values, a key, and an operator
+ that relates the key and values.
+ properties:
+ key:
+ description: The label key that the
+ selector applies to.
+ type: string
+ operator:
+ description: |-
+ Represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
+ type: string
+ values:
+ description: |-
+ An array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. If the operator is Gt or Lt, the values
+ array must have a single element, which will be interpreted as an integer.
+ This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ x-kubernetes-map-type: atomic
+ weight:
+ description: Weight associated with matching
+ the corresponding nodeSelectorTerm, in the
+ range 1-100.
+ format: int32
+ type: integer
+ required:
+ - preference
+ - weight
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ requiredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ If the affinity requirements specified by this field are not met at
+ scheduling time, the pod will not be scheduled onto the node.
+ If the affinity requirements specified by this field cease to be met
+ at some point during pod execution (e.g. due to an update), the system
+ may or may not try to eventually evict the pod from its node.
+ properties:
+ nodeSelectorTerms:
+ description: Required. A list of node selector
+ terms. The terms are ORed.
+ items:
+ description: |-
+ A null or empty node selector term matches no objects. The requirements of
+ them are ANDed.
+ The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.
+ properties:
+ matchExpressions:
+ description: A list of node selector requirements
+ by node's labels.
+ items:
+ description: |-
+ A node selector requirement is a selector that contains values, a key, and an operator
+ that relates the key and values.
+ properties:
+ key:
+ description: The label key that the
+ selector applies to.
+ type: string
+ operator:
+ description: |-
+ Represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
+ type: string
+ values:
+ description: |-
+ An array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. If the operator is Gt or Lt, the values
+ array must have a single element, which will be interpreted as an integer.
+ This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchFields:
+ description: A list of node selector requirements
+ by node's fields.
+ items:
+ description: |-
+ A node selector requirement is a selector that contains values, a key, and an operator
+ that relates the key and values.
+ properties:
+ key:
+ description: The label key that the
+ selector applies to.
+ type: string
+ operator:
+ description: |-
+ Represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
+ type: string
+ values:
+ description: |-
+ An array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. If the operator is Gt or Lt, the values
+ array must have a single element, which will be interpreted as an integer.
+ This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ x-kubernetes-map-type: atomic
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - nodeSelectorTerms
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ podAffinity:
+ description: Describes pod affinity scheduling rules (e.g.
+ co-locate this pod in the same node, zone, etc. as some
+ other pod(s)).
+ properties:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ The scheduler will prefer to schedule pods to nodes that satisfy
+ the affinity expressions specified by this field, but it may choose
+ a node that violates one or more of the expressions. The node that is
+ most preferred is the one with the greatest sum of weights, i.e.
+ for each node that meets all of the scheduling requirements (resource
+ request, requiredDuringScheduling affinity expressions, etc.),
+ compute a sum by iterating through the elements of this field and adding
+ "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the
+ node(s) with the highest sum are the most preferred.
+ items:
+ description: The weights of all of the matched WeightedPodAffinityTerm
+ fields are added per-node to find the most preferred
+ node(s)
+ properties:
+ podAffinityTerm:
+ description: Required. A pod affinity term,
+ associated with the corresponding weight.
+ properties:
+ labelSelector:
+ description: |-
+ A label query over a set of resources, in this case pods.
+ If it's null, this PodAffinityTerm matches with no Pods.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The
+ requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ matchLabelKeys:
+ description: |-
+ MatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both matchLabelKeys and labelSelector.
+ Also, matchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ mismatchLabelKeys:
+ description: |-
+ MismatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
+ Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ namespaceSelector:
+ description: |-
+ A label query over the set of namespaces that the term applies to.
+ The term is applied to the union of the namespaces selected by this field
+ and the ones listed in the namespaces field.
+ null selector and null or empty namespaces list means "this pod's namespace".
+ An empty selector ({}) matches all namespaces.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The
+ requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: |-
+ namespaces specifies a static list of namespace names that the term applies to.
+ The term is applied to the union of the namespaces listed in this field
+ and the ones selected by namespaceSelector.
+ null or empty namespaces list and null namespaceSelector means "this pod's namespace".
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ topologyKey:
+ description: |-
+ This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
+ the labelSelector in the specified namespaces, where co-located is defined as running on a node
+ whose value of the label with key topologyKey matches that of any node on which any of the
+ selected pods is running.
+ Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ weight:
+ description: |-
+ weight associated with matching the corresponding podAffinityTerm,
+ in the range 1-100.
+ format: int32
+ type: integer
+ required:
+ - podAffinityTerm
+ - weight
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ requiredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ If the affinity requirements specified by this field are not met at
+ scheduling time, the pod will not be scheduled onto the node.
+ If the affinity requirements specified by this field cease to be met
+ at some point during pod execution (e.g. due to a pod label update), the
+ system may or may not try to eventually evict the pod from its node.
+ When there are multiple elements, the lists of nodes corresponding to each
+ podAffinityTerm are intersected, i.e. all terms must be satisfied.
+ items:
+ description: |-
+ Defines a set of pods (namely those matching the labelSelector
+ relative to the given namespace(s)) that this pod should be
+ co-located (affinity) or not co-located (anti-affinity) with,
+ where co-located is defined as running on a node whose value of
+ the label with key matches that of any node on which
+ a pod of the set of pods is running
+ properties:
+ labelSelector:
+ description: |-
+ A label query over a set of resources, in this case pods.
+ If it's null, this PodAffinityTerm matches with no Pods.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The requirements
+ are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label key
+ that the selector applies to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ matchLabelKeys:
+ description: |-
+ MatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both matchLabelKeys and labelSelector.
+ Also, matchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ mismatchLabelKeys:
+ description: |-
+ MismatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
+ Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ namespaceSelector:
+ description: |-
+ A label query over the set of namespaces that the term applies to.
+ The term is applied to the union of the namespaces selected by this field
+ and the ones listed in the namespaces field.
+ null selector and null or empty namespaces list means "this pod's namespace".
+ An empty selector ({}) matches all namespaces.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The requirements
+ are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label key
+ that the selector applies to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: |-
+ namespaces specifies a static list of namespace names that the term applies to.
+ The term is applied to the union of the namespaces listed in this field
+ and the ones selected by namespaceSelector.
+ null or empty namespaces list and null namespaceSelector means "this pod's namespace".
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ topologyKey:
+ description: |-
+ This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
+ the labelSelector in the specified namespaces, where co-located is defined as running on a node
+ whose value of the label with key topologyKey matches that of any node on which any of the
+ selected pods is running.
+ Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ podAntiAffinity:
+ description: Describes pod anti-affinity scheduling rules
+ (e.g. avoid putting this pod in the same node, zone,
+ etc. as some other pod(s)).
+ properties:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ The scheduler will prefer to schedule pods to nodes that satisfy
+ the anti-affinity expressions specified by this field, but it may choose
+ a node that violates one or more of the expressions. The node that is
+ most preferred is the one with the greatest sum of weights, i.e.
+ for each node that meets all of the scheduling requirements (resource
+ request, requiredDuringScheduling anti-affinity expressions, etc.),
+ compute a sum by iterating through the elements of this field and subtracting
+ "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the
+ node(s) with the highest sum are the most preferred.
+ items:
+ description: The weights of all of the matched WeightedPodAffinityTerm
+ fields are added per-node to find the most preferred
+ node(s)
+ properties:
+ podAffinityTerm:
+ description: Required. A pod affinity term,
+ associated with the corresponding weight.
+ properties:
+ labelSelector:
+ description: |-
+ A label query over a set of resources, in this case pods.
+ If it's null, this PodAffinityTerm matches with no Pods.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The
+ requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ matchLabelKeys:
+ description: |-
+ MatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both matchLabelKeys and labelSelector.
+ Also, matchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ mismatchLabelKeys:
+ description: |-
+ MismatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
+ Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ namespaceSelector:
+ description: |-
+ A label query over the set of namespaces that the term applies to.
+ The term is applied to the union of the namespaces selected by this field
+ and the ones listed in the namespaces field.
+ null selector and null or empty namespaces list means "this pod's namespace".
+ An empty selector ({}) matches all namespaces.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The
+ requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: |-
+ namespaces specifies a static list of namespace names that the term applies to.
+ The term is applied to the union of the namespaces listed in this field
+ and the ones selected by namespaceSelector.
+ null or empty namespaces list and null namespaceSelector means "this pod's namespace".
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ topologyKey:
+ description: |-
+ This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
+ the labelSelector in the specified namespaces, where co-located is defined as running on a node
+ whose value of the label with key topologyKey matches that of any node on which any of the
+ selected pods is running.
+ Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ weight:
+ description: |-
+ weight associated with matching the corresponding podAffinityTerm,
+ in the range 1-100.
+ format: int32
+ type: integer
+ required:
+ - podAffinityTerm
+ - weight
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ requiredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ If the anti-affinity requirements specified by this field are not met at
+ scheduling time, the pod will not be scheduled onto the node.
+ If the anti-affinity requirements specified by this field cease to be met
+ at some point during pod execution (e.g. due to a pod label update), the
+ system may or may not try to eventually evict the pod from its node.
+ When there are multiple elements, the lists of nodes corresponding to each
+ podAffinityTerm are intersected, i.e. all terms must be satisfied.
+ items:
+ description: |-
+ Defines a set of pods (namely those matching the labelSelector
+ relative to the given namespace(s)) that this pod should be
+ co-located (affinity) or not co-located (anti-affinity) with,
+ where co-located is defined as running on a node whose value of
+ the label with key matches that of any node on which
+ a pod of the set of pods is running
+ properties:
+ labelSelector:
+ description: |-
+ A label query over a set of resources, in this case pods.
+ If it's null, this PodAffinityTerm matches with no Pods.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The requirements
+ are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label key
+ that the selector applies to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ matchLabelKeys:
+ description: |-
+ MatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both matchLabelKeys and labelSelector.
+ Also, matchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ mismatchLabelKeys:
+ description: |-
+ MismatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
+ Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ namespaceSelector:
+ description: |-
+ A label query over the set of namespaces that the term applies to.
+ The term is applied to the union of the namespaces selected by this field
+ and the ones listed in the namespaces field.
+ null selector and null or empty namespaces list means "this pod's namespace".
+ An empty selector ({}) matches all namespaces.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The requirements
+ are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label key
+ that the selector applies to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: |-
+ namespaces specifies a static list of namespace names that the term applies to.
+ The term is applied to the union of the namespaces listed in this field
+ and the ones selected by namespaceSelector.
+ null or empty namespaces list and null namespaceSelector means "this pod's namespace".
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ topologyKey:
+ description: |-
+ This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
+ the labelSelector in the specified namespaces, where co-located is defined as running on a node
+ whose value of the label with key topologyKey matches that of any node on which any of the
+ selected pods is running.
+ Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ type: object
+ autoscaleBehavior:
+ description: See https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#configurable-scaling-behavior
+ properties:
+ scaleDown:
+ description: |-
+ scaleDown is scaling policy for scaling Down.
+ If not set, the default value is to allow to scale down to minReplicas pods, with a
+ 300 second stabilization window (i.e., the highest recommendation for
+ the last 300sec is used).
+ properties:
+ policies:
+ description: |-
+ policies is a list of potential scaling polices which can be used during scaling.
+ If not set, use the default values:
+ - For scale up: allow doubling the number of pods, or an absolute change of 4 pods in a 15s window.
+ - For scale down: allow all pods to be removed in a 15s window.
+ items:
+ description: HPAScalingPolicy is a single policy
+ which must hold true for a specified past interval.
+ properties:
+ periodSeconds:
+ description: |-
+ periodSeconds specifies the window of time for which the policy should hold true.
+ PeriodSeconds must be greater than zero and less than or equal to 1800 (30 min).
+ format: int32
+ type: integer
+ type:
+ description: type is used to specify the scaling
+ policy.
+ type: string
+ value:
+ description: |-
+ value contains the amount of change which is permitted by the policy.
+ It must be greater than zero
+ format: int32
+ type: integer
+ required:
+ - periodSeconds
+ - type
+ - value
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ selectPolicy:
+ description: |-
+ selectPolicy is used to specify which policy should be used.
+ If not set, the default value Max is used.
+ type: string
+ stabilizationWindowSeconds:
+ description: |-
+ stabilizationWindowSeconds is the number of seconds for which past recommendations should be
+ considered while scaling up or scaling down.
+ StabilizationWindowSeconds must be greater than or equal to zero and less than or equal to 3600 (one hour).
+ If not set, use the default values:
+ - For scale up: 0 (i.e. no stabilization is done).
+ - For scale down: 300 (i.e. the stabilization window is 300 seconds long).
+ format: int32
+ type: integer
+ tolerance:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ tolerance is the tolerance on the ratio between the current and desired
+ metric value under which no updates are made to the desired number of
+ replicas (e.g. 0.01 for 1%). Must be greater than or equal to zero. If not
+ set, the default cluster-wide tolerance is applied (by default 10%).
+
+ For example, if autoscaling is configured with a memory consumption target of 100Mi,
+ and scale-down and scale-up tolerances of 5% and 1% respectively, scaling will be
+ triggered when the actual consumption falls below 95Mi or exceeds 101Mi.
+
+ This is an beta field and requires the HPAConfigurableTolerance feature
+ gate to be enabled.
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ type: object
+ scaleUp:
+ description: |-
+ scaleUp is scaling policy for scaling Up.
+ If not set, the default value is the higher of:
+ * increase no more than 4 pods per 60 seconds
+ * double the number of pods per 60 seconds
+ No stabilization is used.
+ properties:
+ policies:
+ description: |-
+ policies is a list of potential scaling polices which can be used during scaling.
+ If not set, use the default values:
+ - For scale up: allow doubling the number of pods, or an absolute change of 4 pods in a 15s window.
+ - For scale down: allow all pods to be removed in a 15s window.
+ items:
+ description: HPAScalingPolicy is a single policy
+ which must hold true for a specified past interval.
+ properties:
+ periodSeconds:
+ description: |-
+ periodSeconds specifies the window of time for which the policy should hold true.
+ PeriodSeconds must be greater than zero and less than or equal to 1800 (30 min).
+ format: int32
+ type: integer
+ type:
+ description: type is used to specify the scaling
+ policy.
+ type: string
+ value:
+ description: |-
+ value contains the amount of change which is permitted by the policy.
+ It must be greater than zero
+ format: int32
+ type: integer
+ required:
+ - periodSeconds
+ - type
+ - value
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ selectPolicy:
+ description: |-
+ selectPolicy is used to specify which policy should be used.
+ If not set, the default value Max is used.
+ type: string
+ stabilizationWindowSeconds:
+ description: |-
+ stabilizationWindowSeconds is the number of seconds for which past recommendations should be
+ considered while scaling up or scaling down.
+ StabilizationWindowSeconds must be greater than or equal to zero and less than or equal to 3600 (one hour).
+ If not set, use the default values:
+ - For scale up: 0 (i.e. no stabilization is done).
+ - For scale down: 300 (i.e. the stabilization window is 300 seconds long).
+ format: int32
+ type: integer
+ tolerance:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ tolerance is the tolerance on the ratio between the current and desired
+ metric value under which no updates are made to the desired number of
+ replicas (e.g. 0.01 for 1%). Must be greater than or equal to zero. If not
+ set, the default cluster-wide tolerance is applied (by default 10%).
+
+ For example, if autoscaling is configured with a memory consumption target of 100Mi,
+ and scale-down and scale-up tolerances of 5% and 1% respectively, scaling will be
+ triggered when the actual consumption falls below 95Mi or exceeds 101Mi.
+
+ This is an beta field and requires the HPAConfigurableTolerance feature
+ gate to be enabled.
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ type: object
+ type: object
+ autoscaleEnabled:
+ description: Controls whether a HorizontalPodAutoscaler is
+ installed for Pilot.
+ type: boolean
+ autoscaleMax:
+ description: Maximum number of replicas in the HorizontalPodAutoscaler
+ for Pilot.
+ format: int32
+ type: integer
+ autoscaleMin:
+ description: Minimum number of replicas in the HorizontalPodAutoscaler
+ for Pilot.
+ format: int32
+ type: integer
+ cni:
+ description: Configures whether to use an existing CNI installation
+ for workloads
+ properties:
+ enabled:
+ description: Controls whether CNI should be used.
+ type: boolean
+ provider:
+ description: |-
+ Specifies the CNI provider. Can be either "default" or "multus". When set to "multus", an annotation
+ `k8s.v1.cni.cncf.io/networks` is set on injected pods to point to a NetworkAttachmentDefinition
+ type: string
+ type: object
+ configMap:
+ description: |-
+ Configuration settings passed to Pilot as a ConfigMap.
+
+ This controls whether the mesh config map, generated from values.yaml is generated.
+ If false, pilot wil use default values or user-supplied values, in that order of preference.
+ type: boolean
+ cpu:
+ description: |-
+ Target CPU utilization used in HorizontalPodAutoscaler.
+
+ See https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ properties:
+ targetAverageUtilization:
+ description: |-
+ K8s utilization setting for HorizontalPodAutoscaler target.
+
+ See https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/
+ format: int32
+ type: integer
+ type: object
+ crlConfigMapName:
+ description: Select a custom name for istiod's plugged-in
+ CA CRL ConfigMap.
+ type: string
+ deploymentLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ Labels that are added to Pilot deployment.
+
+ See https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
+ type: object
+ enabled:
+ description: Controls whether Pilot is enabled.
+ type: boolean
+ env:
+ additionalProperties:
+ type: string
+ description: "Environment variables passed to the Pilot container.\n\nExamples:\nenv:\n\n\tENV_VAR_1:
+ value1\n\tENV_VAR_2: value2"
+ type: object
+ envVarFrom:
+ description: Configuration for the istio-discovery chart
+ items:
+ description: EnvVar represents an environment variable present
+ in a Container.
+ properties:
+ name:
+ description: |-
+ Name of the environment variable.
+ May consist of any printable ASCII characters except '='.
+ type: string
+ value:
+ description: |-
+ Variable references $(VAR_NAME) are expanded
+ using the previously defined environment variables in the container and
+ any service environment variables. If a variable cannot be resolved,
+ the reference in the input string will be unchanged. Double $$ are reduced
+ to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e.
+ "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)".
+ Escaped references will never be expanded, regardless of whether the variable
+ exists or not.
+ Defaults to "".
+ type: string
+ valueFrom:
+ description: Source for the environment variable's value.
+ Cannot be used if value is not empty.
+ properties:
+ configMapKeyRef:
+ description: Selects a key of a ConfigMap.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the ConfigMap or
+ its key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ fieldRef:
+ description: |-
+ Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`,
+ spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.
+ properties:
+ apiVersion:
+ description: Version of the schema the FieldPath
+ is written in terms of, defaults to "v1".
+ type: string
+ fieldPath:
+ description: Path of the field to select in
+ the specified API version.
+ type: string
+ required:
+ - fieldPath
+ type: object
+ x-kubernetes-map-type: atomic
+ fileKeyRef:
+ description: |-
+ FileKeyRef selects a key of the env file.
+ Requires the EnvFiles feature gate to be enabled.
+ properties:
+ key:
+ description: |-
+ The key within the env file. An invalid key will prevent the pod from starting.
+ The keys defined within a source may consist of any printable ASCII characters except '='.
+ During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.
+ type: string
+ optional:
+ default: false
+ description: |-
+ Specify whether the file or its key must be defined. If the file or key
+ does not exist, then the env var is not published.
+ If optional is set to true and the specified key does not exist,
+ the environment variable will not be set in the Pod's containers.
+
+ If optional is set to false and the specified key does not exist,
+ an error will be returned during Pod creation.
+ type: boolean
+ path:
+ description: |-
+ The path within the volume from which to select the file.
+ Must be relative and may not contain the '..' path or start with '..'.
+ type: string
+ volumeName:
+ description: The name of the volume mount containing
+ the env file.
+ type: string
+ required:
+ - key
+ - path
+ - volumeName
+ type: object
+ x-kubernetes-map-type: atomic
+ resourceFieldRef:
+ description: |-
+ Selects a resource of the container: only resources limits and requests
+ (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.
+ properties:
+ containerName:
+ description: 'Container name: required for volumes,
+ optional for env vars'
+ type: string
+ divisor:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Specifies the output format of
+ the exposed resources, defaults to "1"
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ resource:
+ description: 'Required: resource to select'
+ type: string
+ required:
+ - resource
+ type: object
+ x-kubernetes-map-type: atomic
+ secretKeyRef:
+ description: Selects a key of a secret in the pod's
+ namespace
+ properties:
+ key:
+ description: The key of the secret to select
+ from. Must be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ required:
+ - name
+ type: object
+ type: array
+ extraContainerArgs:
+ description: Additional container arguments for the Pilot
+ container.
+ items:
+ type: string
+ type: array
+ hub:
+ description: Hub to pull the container image from. Image will
+ be `Hub/Image:Tag-Variant`.
+ type: string
+ image:
+ description: |-
+ Image name used for Pilot.
+
+ This can be set either to image name if hub is also set, or can be set to the full hub:name string.
+
+ Examples: custom-pilot, docker.io/someuser:custom-pilot
+ type: string
+ ipFamilies:
+ description: |-
+ Defines which IP family to use for single stack or the order of IP families for dual-stack.
+ Valid list items are "IPv4", "IPv6".
+ More info: https://kubernetes.io/docs/concepts/services-networking/dual-stack/#services
+ items:
+ type: string
+ type: array
+ ipFamilyPolicy:
+ description: |-
+ Controls whether Services are configured to use IPv4, IPv6, or both. Valid options
+ are PreferDualStack, RequireDualStack, and SingleStack.
+ More info: https://kubernetes.io/docs/concepts/services-networking/dual-stack/#services
+ type: string
+ istiodRemote:
+ description: Configuration for the istio-discovery chart when
+ istiod is running in a remote cluster (e.g. "remote control
+ plane").
+ properties:
+ enabled:
+ description: Indicates if this cluster/install should
+ consume a "remote" istiod instance,
+ type: boolean
+ enabledLocalInjectorIstiod:
+ description: |-
+ If `true`, indicates that this cluster/install should consume a "local istiod" installation,
+ local istiod inject sidecars
+ type: boolean
+ injectionCABundle:
+ description: injector ca bundle
+ type: string
+ injectionPath:
+ description: Path to use for the sidecar injector webhook
+ service.
+ type: string
+ injectionURL:
+ description: URL to use for sidecar injector webhook.
+ type: string
+ type: object
+ jwksResolverExtraRootCA:
+ description: |-
+ Specifies an extra root certificate in PEM format. This certificate will be trusted
+ by pilot when resolving JWKS URIs.
+ type: string
+ keepaliveMaxServerConnectionAge:
+ description: |-
+ Maximum duration that a sidecar can be connected to a pilot.
+
+ This setting balances out load across pilot instances, but adds some resource overhead.
+
+ Examples: 300s, 30m, 1h
+ type: string
+ memory:
+ description: |-
+ Target memory utilization used in HorizontalPodAutoscaler.
+
+ See https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ properties:
+ targetAverageUtilization:
+ description: |-
+ K8s utilization setting for HorizontalPodAutoscaler target.
+
+ See https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/
+ format: int32
+ type: integer
+ type: object
+ nodeSelector:
+ additionalProperties:
+ type: string
+ description: |-
+ K8s node selector.
+
+ See https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ type: object
+ podAnnotations:
+ additionalProperties:
+ type: string
+ description: |-
+ K8s annotations for pods.
+
+ See: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ type: object
+ podLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ Labels that are added to Pilot pods.
+
+ See https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
+ type: object
+ replicaCount:
+ description: |-
+ Number of replicas in the Pilot Deployment.
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ format: int32
+ type: integer
+ resources:
+ description: |-
+ K8s resources settings.
+
+ See https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ properties:
+ claims:
+ description: |-
+ Claims lists the names of resources, defined in spec.resourceClaims,
+ that are used by this container.
+
+ This field depends on the
+ DynamicResourceAllocation feature gate.
+
+ This field is immutable. It can only be set for containers.
+ items:
+ description: ResourceClaim references one entry in PodSpec.ResourceClaims.
+ properties:
+ name:
+ description: |-
+ Name must match the name of one entry in pod.spec.resourceClaims of
+ the Pod where this field is used. It makes that resource available
+ inside a container.
+ type: string
+ request:
+ description: |-
+ Request is the name chosen for a request in the referenced claim.
+ If empty, everything from the claim is made available, otherwise
+ only the result of this request.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - name
+ x-kubernetes-list-type: map
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Limits describes the maximum amount of compute resources allowed.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Requests describes the minimum amount of compute resources required.
+ If Requests is omitted for a container, it defaults to Limits if that is explicitly specified,
+ otherwise to an implementation-defined value. Requests cannot exceed Limits.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ type: object
+ rollingMaxSurge:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ K8s rolling update strategy
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ x-kubernetes-int-or-string: true
+ rollingMaxUnavailable:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ The number of pods that can be unavailable during a rolling update (see
+ `strategy.rollingUpdate.maxUnavailable` here:
+ https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/deployment-v1/#DeploymentSpec).
+ May be specified as a number of pods or as a percent of the total number
+ of pods at the start of the update.
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ x-kubernetes-int-or-string: true
+ seccompProfile:
+ description: |-
+ The seccompProfile for the Pilot container.
+
+ See: https://kubernetes.io/docs/tutorials/security/seccomp/
+ properties:
+ localhostProfile:
+ description: |-
+ localhostProfile indicates a profile defined in a file on the node should be used.
+ The profile must be preconfigured on the node to work.
+ Must be a descending path, relative to the kubelet's configured seccomp profile location.
+ Must be set if type is "Localhost". Must NOT be set for any other type.
+ type: string
+ type:
+ description: |-
+ type indicates which kind of seccomp profile will be applied.
+ Valid options are:
+
+ Localhost - a profile defined in a file on the node should be used.
+ RuntimeDefault - the container runtime default profile should be used.
+ Unconfined - no profile should be applied.
+ type: string
+ required:
+ - type
+ type: object
+ serviceAccountAnnotations:
+ additionalProperties:
+ type: string
+ description: K8s annotations for the service account
+ type: object
+ serviceAnnotations:
+ additionalProperties:
+ type: string
+ description: |-
+ K8s annotations for the Service.
+
+ See: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
+ type: object
+ tag:
+ description: The container image tag to pull. Image will be
+ `Hub/Image:Tag-Variant`.
+ type: string
+ taint:
+ properties:
+ enabled:
+ description: |-
+ Enable the untaint controller for new nodes. This aims to solve a race for CNI installation on
+ new nodes. For this to work, the newly added nodes need to have the istio CNI taint as they are
+ added to the cluster. This is usually done by configuring the cluster infra provider.
+ type: boolean
+ namespace:
+ description: The namespace of the CNI daemonset, incase
+ it's not the same as istiod.
+ type: string
+ type: object
+ tolerations:
+ description: |-
+ The node tolerations to be applied to the Pilot deployment so that it can be
+ scheduled to particular nodes with matching taints.
+ More info: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#scheduling
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ items:
+ description: |-
+ The pod this Toleration is attached to tolerates any taint that matches
+ the triple using the matching operator .
+ properties:
+ effect:
+ description: |-
+ Effect indicates the taint effect to match. Empty means match all taint effects.
+ When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.
+ type: string
+ key:
+ description: |-
+ Key is the taint key that the toleration applies to. Empty means match all taint keys.
+ If the key is empty, operator must be Exists; this combination means to match all values and all keys.
+ type: string
+ operator:
+ description: |-
+ Operator represents a key's relationship to the value.
+ Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal.
+ Exists is equivalent to wildcard for value, so that a pod can
+ tolerate all taints of a particular category.
+ Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators).
+ type: string
+ tolerationSeconds:
+ description: |-
+ TolerationSeconds represents the period of time the toleration (which must be
+ of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default,
+ it is not set, which means tolerate the taint forever (do not evict). Zero and
+ negative values will be treated as 0 (evict immediately) by the system.
+ format: int64
+ type: integer
+ value:
+ description: |-
+ Value is the taint value the toleration matches to.
+ If the operator is Exists, the value should be empty, otherwise just a regular string.
+ type: string
+ type: object
+ type: array
+ topologySpreadConstraints:
+ description: The k8s topologySpreadConstraints for the Pilot
+ pods.
+ items:
+ description: TopologySpreadConstraint specifies how to spread
+ matching pods among the given topology.
+ properties:
+ labelSelector:
+ description: |-
+ LabelSelector is used to find matching pods.
+ Pods that match this label selector are counted to determine the number of pods
+ in their corresponding topology domain.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label
+ selector requirements. The requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label key that the
+ selector applies to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ matchLabelKeys:
+ description: |-
+ MatchLabelKeys is a set of pod label keys to select the pods over which
+ spreading will be calculated. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are ANDed with labelSelector
+ to select the group of existing pods over which spreading will be calculated
+ for the incoming pod. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector.
+ MatchLabelKeys cannot be set when LabelSelector isn't set.
+ Keys that don't exist in the incoming pod labels will
+ be ignored. A null or empty list means only match against labelSelector.
+
+ This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default).
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ maxSkew:
+ description: |-
+ MaxSkew describes the degree to which pods may be unevenly distributed.
+ When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference
+ between the number of matching pods in the target topology and the global minimum.
+ The global minimum is the minimum number of matching pods in an eligible domain
+ or zero if the number of eligible domains is less than MinDomains.
+ For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same
+ labelSelector spread as 2/2/1:
+ In this case, the global minimum is 1.
+ | zone1 | zone2 | zone3 |
+ | P P | P P | P |
+ - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2;
+ scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2)
+ violate MaxSkew(1).
+ - if MaxSkew is 2, incoming pod can be scheduled onto any zone.
+ When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence
+ to topologies that satisfy it.
+ It's a required field. Default value is 1 and 0 is not allowed.
+ format: int32
+ type: integer
+ minDomains:
+ description: |-
+ MinDomains indicates a minimum number of eligible domains.
+ When the number of eligible domains with matching topology keys is less than minDomains,
+ Pod Topology Spread treats "global minimum" as 0, and then the calculation of Skew is performed.
+ And when the number of eligible domains with matching topology keys equals or greater than minDomains,
+ this value has no effect on scheduling.
+ As a result, when the number of eligible domains is less than minDomains,
+ scheduler won't schedule more than maxSkew Pods to those domains.
+ If value is nil, the constraint behaves as if MinDomains is equal to 1.
+ Valid values are integers greater than 0.
+ When value is not nil, WhenUnsatisfiable must be DoNotSchedule.
+
+ For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same
+ labelSelector spread as 2/2/2:
+ | zone1 | zone2 | zone3 |
+ | P P | P P | P P |
+ The number of domains is less than 5(MinDomains), so "global minimum" is treated as 0.
+ In this situation, new pod with the same labelSelector cannot be scheduled,
+ because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones,
+ it will violate MaxSkew.
+ format: int32
+ type: integer
+ nodeAffinityPolicy:
+ description: |-
+ NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector
+ when calculating pod topology spread skew. Options are:
+ - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations.
+ - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations.
+
+ If this value is nil, the behavior is equivalent to the Honor policy.
+ type: string
+ nodeTaintsPolicy:
+ description: |-
+ NodeTaintsPolicy indicates how we will treat node taints when calculating
+ pod topology spread skew. Options are:
+ - Honor: nodes without taints, along with tainted nodes for which the incoming pod
+ has a toleration, are included.
+ - Ignore: node taints are ignored. All nodes are included.
+
+ If this value is nil, the behavior is equivalent to the Ignore policy.
+ type: string
+ topologyKey:
+ description: |-
+ TopologyKey is the key of node labels. Nodes that have a label with this key
+ and identical values are considered to be in the same topology.
+ We consider each as a "bucket", and try to put balanced number
+ of pods into each bucket.
+ We define a domain as a particular instance of a topology.
+ Also, we define an eligible domain as a domain whose nodes meet the requirements of
+ nodeAffinityPolicy and nodeTaintsPolicy.
+ e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology.
+ And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology.
+ It's a required field.
+ type: string
+ whenUnsatisfiable:
+ description: |-
+ WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy
+ the spread constraint.
+ - DoNotSchedule (default) tells the scheduler not to schedule it.
+ - ScheduleAnyway tells the scheduler to schedule the pod in any location,
+ but giving higher precedence to topologies that would help reduce the
+ skew.
+ A constraint is considered "Unsatisfiable" for an incoming pod
+ if and only if every possible node assignment for that pod would violate
+ "MaxSkew" on some topology.
+ For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same
+ labelSelector spread as 3/1/1:
+ | zone1 | zone2 | zone3 |
+ | P P P | P | P |
+ If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled
+ to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies
+ MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler
+ won't make it *more* imbalanced.
+ It's a required field.
+ type: string
+ required:
+ - maxSkew
+ - topologyKey
+ - whenUnsatisfiable
+ type: object
+ type: array
+ traceSampling:
+ description: |-
+ Trace sampling fraction.
+
+ Used to set the fraction of time that traces are sampled. Higher values are more accurate but add CPU overhead.
+
+ Allowed values: 0.0 to 1.0
+ type: number
+ trustedZtunnelNamespace:
+ description: |-
+ If set, `istiod` will allow connections from trusted node proxy ztunnels
+ in the provided namespace.
+ type: string
+ variant:
+ description: The container image variant to pull. Options
+ are "debug" or "distroless". Unset will use the default
+ for the given version.
+ type: string
+ volumeMounts:
+ description: Additional volumeMounts to add to the Pilot container.
+ items:
+ description: VolumeMount describes a mounting of a Volume
+ within a container.
+ properties:
+ mountPath:
+ description: |-
+ Path within the container at which the volume should be mounted. Must
+ not contain ':'.
+ type: string
+ mountPropagation:
+ description: |-
+ mountPropagation determines how mounts are propagated from the host
+ to container and the other way around.
+ When not set, MountPropagationNone is used.
+ This field is beta in 1.10.
+ When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified
+ (which defaults to None).
+ type: string
+ name:
+ description: This must match the Name of a Volume.
+ type: string
+ readOnly:
+ description: |-
+ Mounted read-only if true, read-write otherwise (false or unspecified).
+ Defaults to false.
+ type: boolean
+ recursiveReadOnly:
+ description: |-
+ RecursiveReadOnly specifies whether read-only mounts should be handled
+ recursively.
+
+ If ReadOnly is false, this field has no meaning and must be unspecified.
+
+ If ReadOnly is true, and this field is set to Disabled, the mount is not made
+ recursively read-only. If this field is set to IfPossible, the mount is made
+ recursively read-only, if it is supported by the container runtime. If this
+ field is set to Enabled, the mount is made recursively read-only if it is
+ supported by the container runtime, otherwise the pod will not be started and
+ an error will be generated to indicate the reason.
+
+ If this field is set to IfPossible or Enabled, MountPropagation must be set to
+ None (or be unspecified, which defaults to None).
+
+ If this field is not specified, it is treated as an equivalent of Disabled.
+ type: string
+ subPath:
+ description: |-
+ Path within the volume from which the container's volume should be mounted.
+ Defaults to "" (volume's root).
+ type: string
+ subPathExpr:
+ description: |-
+ Expanded path within the volume from which the container's volume should be mounted.
+ Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment.
+ Defaults to "" (volume's root).
+ SubPathExpr and SubPath are mutually exclusive.
+ type: string
+ required:
+ - mountPath
+ - name
+ type: object
+ type: array
+ volumes:
+ description: Additional volumes to add to the Pilot Pod.
+ items:
+ description: Volume represents a named volume in a pod that
+ may be accessed by any container in the pod.
+ properties:
+ awsElasticBlockStore:
+ description: |-
+ awsElasticBlockStore represents an AWS Disk resource that is attached to a
+ kubelet's host machine and then exposed to the pod.
+ Deprecated: AWSElasticBlockStore is deprecated. All operations for the in-tree
+ awsElasticBlockStore type are redirected to the ebs.csi.aws.com CSI driver.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore
+ properties:
+ fsType:
+ description: |-
+ fsType is the filesystem type of the volume that you want to mount.
+ Tip: Ensure that the filesystem type is supported by the host operating system.
+ Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore
+ type: string
+ partition:
+ description: |-
+ partition is the partition in the volume that you want to mount.
+ If omitted, the default is to mount by volume name.
+ Examples: For volume /dev/sda1, you specify the partition as "1".
+ Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty).
+ format: int32
+ type: integer
+ readOnly:
+ description: |-
+ readOnly value true will force the readOnly setting in VolumeMounts.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore
+ type: boolean
+ volumeID:
+ description: |-
+ volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume).
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore
+ type: string
+ required:
+ - volumeID
+ type: object
+ azureDisk:
+ description: |-
+ azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.
+ Deprecated: AzureDisk is deprecated. All operations for the in-tree azureDisk type
+ are redirected to the disk.csi.azure.com CSI driver.
+ properties:
+ cachingMode:
+ description: 'cachingMode is the Host Caching mode:
+ None, Read Only, Read Write.'
+ type: string
+ diskName:
+ description: diskName is the Name of the data disk
+ in the blob storage
+ type: string
+ diskURI:
+ description: diskURI is the URI of data disk in
+ the blob storage
+ type: string
+ fsType:
+ default: ext4
+ description: |-
+ fsType is Filesystem type to mount.
+ Must be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified.
+ type: string
+ kind:
+ description: 'kind expected values are Shared: multiple
+ blob disks per storage account Dedicated: single
+ blob disk per storage account Managed: azure
+ managed data disk (only in managed availability
+ set). defaults to shared'
+ type: string
+ readOnly:
+ default: false
+ description: |-
+ readOnly Defaults to false (read/write). ReadOnly here will force
+ the ReadOnly setting in VolumeMounts.
+ type: boolean
+ required:
+ - diskName
+ - diskURI
+ type: object
+ azureFile:
+ description: |-
+ azureFile represents an Azure File Service mount on the host and bind mount to the pod.
+ Deprecated: AzureFile is deprecated. All operations for the in-tree azureFile type
+ are redirected to the file.csi.azure.com CSI driver.
+ properties:
+ readOnly:
+ description: |-
+ readOnly defaults to false (read/write). ReadOnly here will force
+ the ReadOnly setting in VolumeMounts.
+ type: boolean
+ secretName:
+ description: secretName is the name of secret that
+ contains Azure Storage Account Name and Key
+ type: string
+ shareName:
+ description: shareName is the azure share Name
+ type: string
+ required:
+ - secretName
+ - shareName
+ type: object
+ cephfs:
+ description: |-
+ cephFS represents a Ceph FS mount on the host that shares a pod's lifetime.
+ Deprecated: CephFS is deprecated and the in-tree cephfs type is no longer supported.
+ properties:
+ monitors:
+ description: |-
+ monitors is Required: Monitors is a collection of Ceph monitors
+ More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ path:
+ description: 'path is Optional: Used as the mounted
+ root, rather than the full Ceph tree, default
+ is /'
+ type: string
+ readOnly:
+ description: |-
+ readOnly is Optional: Defaults to false (read/write). ReadOnly here will force
+ the ReadOnly setting in VolumeMounts.
+ More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it
+ type: boolean
+ secretFile:
+ description: |-
+ secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret
+ More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it
+ type: string
+ secretRef:
+ description: |-
+ secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty.
+ More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it
+ properties:
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ user:
+ description: |-
+ user is optional: User is the rados user name, default is admin
+ More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it
+ type: string
+ required:
+ - monitors
+ type: object
+ cinder:
+ description: |-
+ cinder represents a cinder volume attached and mounted on kubelets host machine.
+ Deprecated: Cinder is deprecated. All operations for the in-tree cinder type
+ are redirected to the cinder.csi.openstack.org CSI driver.
+ More info: https://examples.k8s.io/mysql-cinder-pd/README.md
+ properties:
+ fsType:
+ description: |-
+ fsType is the filesystem type to mount.
+ Must be a filesystem type supported by the host operating system.
+ Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified.
+ More info: https://examples.k8s.io/mysql-cinder-pd/README.md
+ type: string
+ readOnly:
+ description: |-
+ readOnly defaults to false (read/write). ReadOnly here will force
+ the ReadOnly setting in VolumeMounts.
+ More info: https://examples.k8s.io/mysql-cinder-pd/README.md
+ type: boolean
+ secretRef:
+ description: |-
+ secretRef is optional: points to a secret object containing parameters used to connect
+ to OpenStack.
+ properties:
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ volumeID:
+ description: |-
+ volumeID used to identify the volume in cinder.
+ More info: https://examples.k8s.io/mysql-cinder-pd/README.md
+ type: string
+ required:
+ - volumeID
+ type: object
+ configMap:
+ description: configMap represents a configMap that should
+ populate this volume
+ properties:
+ defaultMode:
+ description: |-
+ defaultMode is optional: mode bits used to set permissions on created files by default.
+ Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511.
+ YAML accepts both octal and decimal values, JSON requires decimal values for mode bits.
+ Defaults to 0644.
+ Directories within the path are not affected by this setting.
+ This might be in conflict with other options that affect the file
+ mode, like fsGroup, and the result can be other mode bits set.
+ format: int32
+ type: integer
+ items:
+ description: |-
+ items if unspecified, each key-value pair in the Data field of the referenced
+ ConfigMap will be projected into the volume as a file whose name is the
+ key and content is the value. If specified, the listed keys will be
+ projected into the specified paths, and unlisted keys will not be
+ present. If a key is specified which is not present in the ConfigMap,
+ the volume setup will error unless it is marked optional. Paths must be
+ relative and may not contain the '..' path or start with '..'.
+ items:
+ description: Maps a string key to a path within
+ a volume.
+ properties:
+ key:
+ description: key is the key to project.
+ type: string
+ mode:
+ description: |-
+ mode is Optional: mode bits used to set permissions on this file.
+ Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511.
+ YAML accepts both octal and decimal values, JSON requires decimal values for mode bits.
+ If not specified, the volume defaultMode will be used.
+ This might be in conflict with other options that affect the file
+ mode, like fsGroup, and the result can be other mode bits set.
+ format: int32
+ type: integer
+ path:
+ description: |-
+ path is the relative path of the file to map the key to.
+ May not be an absolute path.
+ May not contain the path element '..'.
+ May not start with the string '..'.
+ type: string
+ required:
+ - key
+ - path
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: optional specify whether the ConfigMap
+ or its keys must be defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ csi:
+ description: csi (Container Storage Interface) represents
+ ephemeral storage that is handled by certain external
+ CSI drivers.
+ properties:
+ driver:
+ description: |-
+ driver is the name of the CSI driver that handles this volume.
+ Consult with your admin for the correct name as registered in the cluster.
+ type: string
+ fsType:
+ description: |-
+ fsType to mount. Ex. "ext4", "xfs", "ntfs".
+ If not provided, the empty value is passed to the associated CSI driver
+ which will determine the default filesystem to apply.
+ type: string
+ nodePublishSecretRef:
+ description: |-
+ nodePublishSecretRef is a reference to the secret object containing
+ sensitive information to pass to the CSI driver to complete the CSI
+ NodePublishVolume and NodeUnpublishVolume calls.
+ This field is optional, and may be empty if no secret is required. If the
+ secret object contains more than one secret, all secret references are passed.
+ properties:
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ readOnly:
+ description: |-
+ readOnly specifies a read-only configuration for the volume.
+ Defaults to false (read/write).
+ type: boolean
+ volumeAttributes:
+ additionalProperties:
+ type: string
+ description: |-
+ volumeAttributes stores driver-specific properties that are passed to the CSI
+ driver. Consult your driver's documentation for supported values.
+ type: object
+ required:
+ - driver
+ type: object
+ downwardAPI:
+ description: downwardAPI represents downward API about
+ the pod that should populate this volume
+ properties:
+ defaultMode:
+ description: |-
+ Optional: mode bits to use on created files by default. Must be a
+ Optional: mode bits used to set permissions on created files by default.
+ Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511.
+ YAML accepts both octal and decimal values, JSON requires decimal values for mode bits.
+ Defaults to 0644.
+ Directories within the path are not affected by this setting.
+ This might be in conflict with other options that affect the file
+ mode, like fsGroup, and the result can be other mode bits set.
+ format: int32
+ type: integer
+ items:
+ description: Items is a list of downward API volume
+ file
+ items:
+ description: DownwardAPIVolumeFile represents
+ information to create the file containing the
+ pod field
+ properties:
+ fieldRef:
+ description: 'Required: Selects a field of
+ the pod: only annotations, labels, name,
+ namespace and uid are supported.'
+ properties:
+ apiVersion:
+ description: Version of the schema the
+ FieldPath is written in terms of, defaults
+ to "v1".
+ type: string
+ fieldPath:
+ description: Path of the field to select
+ in the specified API version.
+ type: string
+ required:
+ - fieldPath
+ type: object
+ x-kubernetes-map-type: atomic
+ mode:
+ description: |-
+ Optional: mode bits used to set permissions on this file, must be an octal value
+ between 0000 and 0777 or a decimal value between 0 and 511.
+ YAML accepts both octal and decimal values, JSON requires decimal values for mode bits.
+ If not specified, the volume defaultMode will be used.
+ This might be in conflict with other options that affect the file
+ mode, like fsGroup, and the result can be other mode bits set.
+ format: int32
+ type: integer
+ path:
+ description: 'Required: Path is the relative
+ path name of the file to be created. Must
+ not be absolute or contain the ''..'' path.
+ Must be utf-8 encoded. The first item of
+ the relative path must not start with ''..'''
+ type: string
+ resourceFieldRef:
+ description: |-
+ Selects a resource of the container: only resources limits and requests
+ (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.
+ properties:
+ containerName:
+ description: 'Container name: required
+ for volumes, optional for env vars'
+ type: string
+ divisor:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Specifies the output format
+ of the exposed resources, defaults to
+ "1"
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ resource:
+ description: 'Required: resource to select'
+ type: string
+ required:
+ - resource
+ type: object
+ x-kubernetes-map-type: atomic
+ required:
+ - path
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ emptyDir:
+ description: |-
+ emptyDir represents a temporary directory that shares a pod's lifetime.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir
+ properties:
+ medium:
+ description: |-
+ medium represents what type of storage medium should back this directory.
+ The default is "" which means to use the node's default medium.
+ Must be an empty string (default) or Memory.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir
+ type: string
+ sizeLimit:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ sizeLimit is the total amount of local storage required for this EmptyDir volume.
+ The size limit is also applicable for memory medium.
+ The maximum usage on memory medium EmptyDir would be the minimum value between
+ the SizeLimit specified here and the sum of memory limits of all containers in a pod.
+ The default is nil which means that the limit is undefined.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ type: object
+ ephemeral:
+ description: |-
+ ephemeral represents a volume that is handled by a cluster storage driver.
+ The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts,
+ and deleted when the pod is removed.
+
+ Use this if:
+ a) the volume is only needed while the pod runs,
+ b) features of normal volumes like restoring from snapshot or capacity
+ tracking are needed,
+ c) the storage driver is specified through a storage class, and
+ d) the storage driver supports dynamic volume provisioning through
+ a PersistentVolumeClaim (see EphemeralVolumeSource for more
+ information on the connection between this volume type
+ and PersistentVolumeClaim).
+
+ Use PersistentVolumeClaim or one of the vendor-specific
+ APIs for volumes that persist for longer than the lifecycle
+ of an individual pod.
+
+ Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to
+ be used that way - see the documentation of the driver for
+ more information.
+
+ A pod can use both types of ephemeral volumes and
+ persistent volumes at the same time.
+ properties:
+ volumeClaimTemplate:
+ description: |-
+ Will be used to create a stand-alone PVC to provision the volume.
+ The pod in which this EphemeralVolumeSource is embedded will be the
+ owner of the PVC, i.e. the PVC will be deleted together with the
+ pod. The name of the PVC will be `-` where
+ `` is the name from the `PodSpec.Volumes` array
+ entry. Pod validation will reject the pod if the concatenated name
+ is not valid for a PVC (for example, too long).
+
+ An existing PVC with that name that is not owned by the pod
+ will *not* be used for the pod to avoid using an unrelated
+ volume by mistake. Starting the pod is then blocked until
+ the unrelated PVC is removed. If such a pre-created PVC is
+ meant to be used by the pod, the PVC has to updated with an
+ owner reference to the pod once the pod exists. Normally
+ this should not be necessary, but it may be useful when
+ manually reconstructing a broken cluster.
+
+ This field is read-only and no changes will be made by Kubernetes
+ to the PVC after it has been created.
+
+ Required, must not be nil.
+ properties:
+ metadata:
+ description: |-
+ May contain labels and annotations that will be copied into the PVC
+ when creating it. No other fields are allowed and will be rejected during
+ validation.
+ type: object
+ spec:
+ description: |-
+ The specification for the PersistentVolumeClaim. The entire content is
+ copied unchanged into the PVC that gets created from this
+ template. The same fields as in a PersistentVolumeClaim
+ are also valid here.
+ properties:
+ accessModes:
+ description: |-
+ accessModes contains the desired access modes the volume should have.
+ More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ dataSource:
+ description: |-
+ dataSource field can be used to specify either:
+ * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot)
+ * An existing PVC (PersistentVolumeClaim)
+ If the provisioner or an external controller can support the specified data source,
+ it will create a new volume based on the contents of the specified data source.
+ When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef,
+ and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified.
+ If the namespace is specified, then dataSourceRef will not be copied to dataSource.
+ properties:
+ apiGroup:
+ description: |-
+ APIGroup is the group for the resource being referenced.
+ If APIGroup is not specified, the specified Kind must be in the core API group.
+ For any other third-party types, APIGroup is required.
+ type: string
+ kind:
+ description: Kind is the type of resource
+ being referenced
+ type: string
+ name:
+ description: Name is the name of resource
+ being referenced
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ x-kubernetes-map-type: atomic
+ dataSourceRef:
+ description: |-
+ dataSourceRef specifies the object from which to populate the volume with data, if a non-empty
+ volume is desired. This may be any object from a non-empty API group (non
+ core object) or a PersistentVolumeClaim object.
+ When this field is specified, volume binding will only succeed if the type of
+ the specified object matches some installed volume populator or dynamic
+ provisioner.
+ This field will replace the functionality of the dataSource field and as such
+ if both fields are non-empty, they must have the same value. For backwards
+ compatibility, when namespace isn't specified in dataSourceRef,
+ both fields (dataSource and dataSourceRef) will be set to the same
+ value automatically if one of them is empty and the other is non-empty.
+ When namespace is specified in dataSourceRef,
+ dataSource isn't set to the same value and must be empty.
+ There are three important differences between dataSource and dataSourceRef:
+ * While dataSource only allows two specific types of objects, dataSourceRef
+ allows any non-core object, as well as PersistentVolumeClaim objects.
+ * While dataSource ignores disallowed values (dropping them), dataSourceRef
+ preserves all values, and generates an error if a disallowed value is
+ specified.
+ * While dataSource only allows local objects, dataSourceRef allows objects
+ in any namespaces.
+ (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled.
+ (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled.
+ properties:
+ apiGroup:
+ description: |-
+ APIGroup is the group for the resource being referenced.
+ If APIGroup is not specified, the specified Kind must be in the core API group.
+ For any other third-party types, APIGroup is required.
+ type: string
+ kind:
+ description: Kind is the type of resource
+ being referenced
+ type: string
+ name:
+ description: Name is the name of resource
+ being referenced
+ type: string
+ namespace:
+ description: |-
+ Namespace is the namespace of resource being referenced
+ Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details.
+ (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled.
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ resources:
+ description: |-
+ resources represents the minimum resources the volume should have.
+ Users are allowed to specify resource requirements
+ that are lower than previous value but must still be higher than capacity recorded in the
+ status field of the claim.
+ More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources
+ properties:
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Limits describes the maximum amount of compute resources allowed.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Requests describes the minimum amount of compute resources required.
+ If Requests is omitted for a container, it defaults to Limits if that is explicitly specified,
+ otherwise to an implementation-defined value. Requests cannot exceed Limits.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ type: object
+ selector:
+ description: selector is a label query over
+ volumes to consider for binding.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The
+ requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ storageClassName:
+ description: |-
+ storageClassName is the name of the StorageClass required by the claim.
+ More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1
+ type: string
+ volumeAttributesClassName:
+ description: |-
+ volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim.
+ If specified, the CSI driver will create or update the volume with the attributes defined
+ in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName,
+ it can be changed after the claim is created. An empty string or nil value indicates that no
+ VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state,
+ this field can be reset to its previous value (including nil) to cancel the modification.
+ If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be
+ set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource
+ exists.
+ More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/
+ type: string
+ volumeMode:
+ description: |-
+ volumeMode defines what type of volume is required by the claim.
+ Value of Filesystem is implied when not included in claim spec.
+ type: string
+ volumeName:
+ description: volumeName is the binding reference
+ to the PersistentVolume backing this claim.
+ type: string
+ type: object
+ required:
+ - spec
+ type: object
+ type: object
+ fc:
+ description: fc represents a Fibre Channel resource
+ that is attached to a kubelet's host machine and then
+ exposed to the pod.
+ properties:
+ fsType:
+ description: |-
+ fsType is the filesystem type to mount.
+ Must be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified.
+ type: string
+ lun:
+ description: 'lun is Optional: FC target lun number'
+ format: int32
+ type: integer
+ readOnly:
+ description: |-
+ readOnly is Optional: Defaults to false (read/write). ReadOnly here will force
+ the ReadOnly setting in VolumeMounts.
+ type: boolean
+ targetWWNs:
+ description: 'targetWWNs is Optional: FC target
+ worldwide names (WWNs)'
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ wwids:
+ description: |-
+ wwids Optional: FC volume world wide identifiers (wwids)
+ Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ flexVolume:
+ description: |-
+ flexVolume represents a generic volume resource that is
+ provisioned/attached using an exec based plugin.
+ Deprecated: FlexVolume is deprecated. Consider using a CSIDriver instead.
+ properties:
+ driver:
+ description: driver is the name of the driver to
+ use for this volume.
+ type: string
+ fsType:
+ description: |-
+ fsType is the filesystem type to mount.
+ Must be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script.
+ type: string
+ options:
+ additionalProperties:
+ type: string
+ description: 'options is Optional: this field holds
+ extra command options if any.'
+ type: object
+ readOnly:
+ description: |-
+ readOnly is Optional: defaults to false (read/write). ReadOnly here will force
+ the ReadOnly setting in VolumeMounts.
+ type: boolean
+ secretRef:
+ description: |-
+ secretRef is Optional: secretRef is reference to the secret object containing
+ sensitive information to pass to the plugin scripts. This may be
+ empty if no secret object is specified. If the secret object
+ contains more than one secret, all secrets are passed to the plugin
+ scripts.
+ properties:
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ required:
+ - driver
+ type: object
+ flocker:
+ description: |-
+ flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running.
+ Deprecated: Flocker is deprecated and the in-tree flocker type is no longer supported.
+ properties:
+ datasetName:
+ description: |-
+ datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker
+ should be considered as deprecated
+ type: string
+ datasetUUID:
+ description: datasetUUID is the UUID of the dataset.
+ This is unique identifier of a Flocker dataset
+ type: string
+ type: object
+ gcePersistentDisk:
+ description: |-
+ gcePersistentDisk represents a GCE Disk resource that is attached to a
+ kubelet's host machine and then exposed to the pod.
+ Deprecated: GCEPersistentDisk is deprecated. All operations for the in-tree
+ gcePersistentDisk type are redirected to the pd.csi.storage.gke.io CSI driver.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk
+ properties:
+ fsType:
+ description: |-
+ fsType is filesystem type of the volume that you want to mount.
+ Tip: Ensure that the filesystem type is supported by the host operating system.
+ Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk
+ type: string
+ partition:
+ description: |-
+ partition is the partition in the volume that you want to mount.
+ If omitted, the default is to mount by volume name.
+ Examples: For volume /dev/sda1, you specify the partition as "1".
+ Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty).
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk
+ format: int32
+ type: integer
+ pdName:
+ description: |-
+ pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk
+ type: string
+ readOnly:
+ description: |-
+ readOnly here will force the ReadOnly setting in VolumeMounts.
+ Defaults to false.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk
+ type: boolean
+ required:
+ - pdName
+ type: object
+ gitRepo:
+ description: |-
+ gitRepo represents a git repository at a particular revision.
+ Deprecated: GitRepo is deprecated. To provision a container with a git repo, mount an
+ EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir
+ into the Pod's container.
+ properties:
+ directory:
+ description: |-
+ directory is the target directory name.
+ Must not contain or start with '..'. If '.' is supplied, the volume directory will be the
+ git repository. Otherwise, if specified, the volume will contain the git repository in
+ the subdirectory with the given name.
+ type: string
+ repository:
+ description: repository is the URL
+ type: string
+ revision:
+ description: revision is the commit hash for the
+ specified revision.
+ type: string
+ required:
+ - repository
+ type: object
+ glusterfs:
+ description: |-
+ glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime.
+ Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported.
+ properties:
+ endpoints:
+ description: endpoints is the endpoint name that
+ details Glusterfs topology.
+ type: string
+ path:
+ description: |-
+ path is the Glusterfs volume path.
+ More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod
+ type: string
+ readOnly:
+ description: |-
+ readOnly here will force the Glusterfs volume to be mounted with read-only permissions.
+ Defaults to false.
+ More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod
+ type: boolean
+ required:
+ - endpoints
+ - path
+ type: object
+ hostPath:
+ description: |-
+ hostPath represents a pre-existing file or directory on the host
+ machine that is directly exposed to the container. This is generally
+ used for system agents or other privileged things that are allowed
+ to see the host machine. Most containers will NOT need this.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath
+ properties:
+ path:
+ description: |-
+ path of the directory on the host.
+ If the path is a symlink, it will follow the link to the real path.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath
+ type: string
+ type:
+ description: |-
+ type for HostPath Volume
+ Defaults to ""
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath
+ type: string
+ required:
+ - path
+ type: object
+ image:
+ description: |-
+ image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine.
+ The volume is resolved at pod startup depending on which PullPolicy value is provided:
+
+ - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails.
+ - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present.
+ - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails.
+
+ The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation.
+ A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message.
+ The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.
+ The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.
+ The volume will be mounted read-only (ro) and non-executable files (noexec).
+ Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.
+ The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.
+ properties:
+ pullPolicy:
+ description: |-
+ Policy for pulling OCI objects. Possible values are:
+ Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails.
+ Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present.
+ IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails.
+ Defaults to Always if :latest tag is specified, or IfNotPresent otherwise.
+ type: string
+ reference:
+ description: |-
+ Required: Image or artifact reference to be used.
+ Behaves in the same way as pod.spec.containers[*].image.
+ Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets.
+ More info: https://kubernetes.io/docs/concepts/containers/images
+ This field is optional to allow higher level config management to default or override
+ container images in workload controllers like Deployments and StatefulSets.
+ type: string
+ type: object
+ iscsi:
+ description: |-
+ iscsi represents an ISCSI Disk resource that is attached to a
+ kubelet's host machine and then exposed to the pod.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes/#iscsi
+ properties:
+ chapAuthDiscovery:
+ description: chapAuthDiscovery defines whether support
+ iSCSI Discovery CHAP authentication
+ type: boolean
+ chapAuthSession:
+ description: chapAuthSession defines whether support
+ iSCSI Session CHAP authentication
+ type: boolean
+ fsType:
+ description: |-
+ fsType is the filesystem type of the volume that you want to mount.
+ Tip: Ensure that the filesystem type is supported by the host operating system.
+ Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi
+ type: string
+ initiatorName:
+ description: |-
+ initiatorName is the custom iSCSI Initiator Name.
+ If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface
+ : will be created for the connection.
+ type: string
+ iqn:
+ description: iqn is the target iSCSI Qualified Name.
+ type: string
+ iscsiInterface:
+ default: default
+ description: |-
+ iscsiInterface is the interface Name that uses an iSCSI transport.
+ Defaults to 'default' (tcp).
+ type: string
+ lun:
+ description: lun represents iSCSI Target Lun number.
+ format: int32
+ type: integer
+ portals:
+ description: |-
+ portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port
+ is other than default (typically TCP ports 860 and 3260).
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ readOnly:
+ description: |-
+ readOnly here will force the ReadOnly setting in VolumeMounts.
+ Defaults to false.
+ type: boolean
+ secretRef:
+ description: secretRef is the CHAP Secret for iSCSI
+ target and initiator authentication
+ properties:
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ targetPortal:
+ description: |-
+ targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port
+ is other than default (typically TCP ports 860 and 3260).
+ type: string
+ required:
+ - iqn
+ - lun
+ - targetPortal
+ type: object
+ name:
+ description: |-
+ name of the volume.
+ Must be a DNS_LABEL and unique within the pod.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ nfs:
+ description: |-
+ nfs represents an NFS mount on the host that shares a pod's lifetime
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs
+ properties:
+ path:
+ description: |-
+ path that is exported by the NFS server.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs
+ type: string
+ readOnly:
+ description: |-
+ readOnly here will force the NFS export to be mounted with read-only permissions.
+ Defaults to false.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs
+ type: boolean
+ server:
+ description: |-
+ server is the hostname or IP address of the NFS server.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs
+ type: string
+ required:
+ - path
+ - server
+ type: object
+ persistentVolumeClaim:
+ description: |-
+ persistentVolumeClaimVolumeSource represents a reference to a
+ PersistentVolumeClaim in the same namespace.
+ More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims
+ properties:
+ claimName:
+ description: |-
+ claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume.
+ More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims
+ type: string
+ readOnly:
+ description: |-
+ readOnly Will force the ReadOnly setting in VolumeMounts.
+ Default false.
+ type: boolean
+ required:
+ - claimName
+ type: object
+ photonPersistentDisk:
+ description: |-
+ photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine.
+ Deprecated: PhotonPersistentDisk is deprecated and the in-tree photonPersistentDisk type is no longer supported.
+ properties:
+ fsType:
+ description: |-
+ fsType is the filesystem type to mount.
+ Must be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified.
+ type: string
+ pdID:
+ description: pdID is the ID that identifies Photon
+ Controller persistent disk
+ type: string
+ required:
+ - pdID
+ type: object
+ portworxVolume:
+ description: |-
+ portworxVolume represents a portworx volume attached and mounted on kubelets host machine.
+ Deprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type
+ are redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate
+ is on.
+ properties:
+ fsType:
+ description: |-
+ fSType represents the filesystem type to mount
+ Must be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified.
+ type: string
+ readOnly:
+ description: |-
+ readOnly defaults to false (read/write). ReadOnly here will force
+ the ReadOnly setting in VolumeMounts.
+ type: boolean
+ volumeID:
+ description: volumeID uniquely identifies a Portworx
+ volume
+ type: string
+ required:
+ - volumeID
+ type: object
+ projected:
+ description: projected items for all in one resources
+ secrets, configmaps, and downward API
+ properties:
+ defaultMode:
+ description: |-
+ defaultMode are the mode bits used to set permissions on created files by default.
+ Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511.
+ YAML accepts both octal and decimal values, JSON requires decimal values for mode bits.
+ Directories within the path are not affected by this setting.
+ This might be in conflict with other options that affect the file
+ mode, like fsGroup, and the result can be other mode bits set.
+ format: int32
+ type: integer
+ sources:
+ description: |-
+ sources is the list of volume projections. Each entry in this list
+ handles one source.
+ items:
+ description: |-
+ Projection that may be projected along with other supported volume types.
+ Exactly one of these fields must be set.
+ properties:
+ clusterTrustBundle:
+ description: |-
+ ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field
+ of ClusterTrustBundle objects in an auto-updating file.
+
+ Alpha, gated by the ClusterTrustBundleProjection feature gate.
+
+ ClusterTrustBundle objects can either be selected by name, or by the
+ combination of signer name and a label selector.
+
+ Kubelet performs aggressive normalization of the PEM contents written
+ into the pod filesystem. Esoteric PEM features such as inter-block
+ comments and block headers are stripped. Certificates are deduplicated.
+ The ordering of certificates within the file is arbitrary, and Kubelet
+ may change the order over time.
+ properties:
+ labelSelector:
+ description: |-
+ Select all ClusterTrustBundles that match this label selector. Only has
+ effect if signerName is set. Mutually-exclusive with name. If unset,
+ interpreted as "match nothing". If set but empty, interpreted as "match
+ everything".
+ properties:
+ matchExpressions:
+ description: matchExpressions is a
+ list of label selector requirements.
+ The requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ name:
+ description: |-
+ Select a single ClusterTrustBundle by object name. Mutually-exclusive
+ with signerName and labelSelector.
+ type: string
+ optional:
+ description: |-
+ If true, don't block pod startup if the referenced ClusterTrustBundle(s)
+ aren't available. If using name, then the named ClusterTrustBundle is
+ allowed not to exist. If using signerName, then the combination of
+ signerName and labelSelector is allowed to match zero
+ ClusterTrustBundles.
+ type: boolean
+ path:
+ description: Relative path from the volume
+ root to write the bundle.
+ type: string
+ signerName:
+ description: |-
+ Select all ClusterTrustBundles that match this signer name.
+ Mutually-exclusive with name. The contents of all selected
+ ClusterTrustBundles will be unified and deduplicated.
+ type: string
+ required:
+ - path
+ type: object
+ configMap:
+ description: configMap information about the
+ configMap data to project
+ properties:
+ items:
+ description: |-
+ items if unspecified, each key-value pair in the Data field of the referenced
+ ConfigMap will be projected into the volume as a file whose name is the
+ key and content is the value. If specified, the listed keys will be
+ projected into the specified paths, and unlisted keys will not be
+ present. If a key is specified which is not present in the ConfigMap,
+ the volume setup will error unless it is marked optional. Paths must be
+ relative and may not contain the '..' path or start with '..'.
+ items:
+ description: Maps a string key to a
+ path within a volume.
+ properties:
+ key:
+ description: key is the key to project.
+ type: string
+ mode:
+ description: |-
+ mode is Optional: mode bits used to set permissions on this file.
+ Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511.
+ YAML accepts both octal and decimal values, JSON requires decimal values for mode bits.
+ If not specified, the volume defaultMode will be used.
+ This might be in conflict with other options that affect the file
+ mode, like fsGroup, and the result can be other mode bits set.
+ format: int32
+ type: integer
+ path:
+ description: |-
+ path is the relative path of the file to map the key to.
+ May not be an absolute path.
+ May not contain the path element '..'.
+ May not start with the string '..'.
+ type: string
+ required:
+ - key
+ - path
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: optional specify whether
+ the ConfigMap or its keys must be defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ downwardAPI:
+ description: downwardAPI information about
+ the downwardAPI data to project
+ properties:
+ items:
+ description: Items is a list of DownwardAPIVolume
+ file
+ items:
+ description: DownwardAPIVolumeFile represents
+ information to create the file containing
+ the pod field
+ properties:
+ fieldRef:
+ description: 'Required: Selects
+ a field of the pod: only annotations,
+ labels, name, namespace and uid
+ are supported.'
+ properties:
+ apiVersion:
+ description: Version of the
+ schema the FieldPath is written
+ in terms of, defaults to "v1".
+ type: string
+ fieldPath:
+ description: Path of the field
+ to select in the specified
+ API version.
+ type: string
+ required:
+ - fieldPath
+ type: object
+ x-kubernetes-map-type: atomic
+ mode:
+ description: |-
+ Optional: mode bits used to set permissions on this file, must be an octal value
+ between 0000 and 0777 or a decimal value between 0 and 511.
+ YAML accepts both octal and decimal values, JSON requires decimal values for mode bits.
+ If not specified, the volume defaultMode will be used.
+ This might be in conflict with other options that affect the file
+ mode, like fsGroup, and the result can be other mode bits set.
+ format: int32
+ type: integer
+ path:
+ description: 'Required: Path is the
+ relative path name of the file
+ to be created. Must not be absolute
+ or contain the ''..'' path. Must
+ be utf-8 encoded. The first item
+ of the relative path must not
+ start with ''..'''
+ type: string
+ resourceFieldRef:
+ description: |-
+ Selects a resource of the container: only resources limits and requests
+ (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.
+ properties:
+ containerName:
+ description: 'Container name:
+ required for volumes, optional
+ for env vars'
+ type: string
+ divisor:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Specifies the output
+ format of the exposed resources,
+ defaults to "1"
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ resource:
+ description: 'Required: resource
+ to select'
+ type: string
+ required:
+ - resource
+ type: object
+ x-kubernetes-map-type: atomic
+ required:
+ - path
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ podCertificate:
+ description: |-
+ Projects an auto-rotating credential bundle (private key and certificate
+ chain) that the pod can use either as a TLS client or server.
+
+ Kubelet generates a private key and uses it to send a
+ PodCertificateRequest to the named signer. Once the signer approves the
+ request and issues a certificate chain, Kubelet writes the key and
+ certificate chain to the pod filesystem. The pod does not start until
+ certificates have been issued for each podCertificate projected volume
+ source in its spec.
+
+ Kubelet will begin trying to rotate the certificate at the time indicated
+ by the signer using the PodCertificateRequest.Status.BeginRefreshAt
+ timestamp.
+
+ Kubelet can write a single file, indicated by the credentialBundlePath
+ field, or separate files, indicated by the keyPath and
+ certificateChainPath fields.
+
+ The credential bundle is a single file in PEM format. The first PEM
+ entry is the private key (in PKCS#8 format), and the remaining PEM
+ entries are the certificate chain issued by the signer (typically,
+ signers will return their certificate chain in leaf-to-root order).
+
+ Prefer using the credential bundle format, since your application code
+ can read it atomically. If you use keyPath and certificateChainPath,
+ your application must make two separate file reads. If these coincide
+ with a certificate rotation, it is possible that the private key and leaf
+ certificate you read may not correspond to each other. Your application
+ will need to check for this condition, and re-read until they are
+ consistent.
+
+ The named signer controls chooses the format of the certificate it
+ issues; consult the signer implementation's documentation to learn how to
+ use the certificates it issues.
+ properties:
+ certificateChainPath:
+ description: |-
+ Write the certificate chain at this path in the projected volume.
+
+ Most applications should use credentialBundlePath. When using keyPath
+ and certificateChainPath, your application needs to check that the key
+ and leaf certificate are consistent, because it is possible to read the
+ files mid-rotation.
+ type: string
+ credentialBundlePath:
+ description: |-
+ Write the credential bundle at this path in the projected volume.
+
+ The credential bundle is a single file that contains multiple PEM blocks.
+ The first PEM block is a PRIVATE KEY block, containing a PKCS#8 private
+ key.
+
+ The remaining blocks are CERTIFICATE blocks, containing the issued
+ certificate chain from the signer (leaf and any intermediates).
+
+ Using credentialBundlePath lets your Pod's application code make a single
+ atomic read that retrieves a consistent key and certificate chain. If you
+ project them to separate files, your application code will need to
+ additionally check that the leaf certificate was issued to the key.
+ type: string
+ keyPath:
+ description: |-
+ Write the key at this path in the projected volume.
+
+ Most applications should use credentialBundlePath. When using keyPath
+ and certificateChainPath, your application needs to check that the key
+ and leaf certificate are consistent, because it is possible to read the
+ files mid-rotation.
+ type: string
+ keyType:
+ description: |-
+ The type of keypair Kubelet will generate for the pod.
+
+ Valid values are "RSA3072", "RSA4096", "ECDSAP256", "ECDSAP384",
+ "ECDSAP521", and "ED25519".
+ type: string
+ maxExpirationSeconds:
+ description: |-
+ maxExpirationSeconds is the maximum lifetime permitted for the
+ certificate.
+
+ Kubelet copies this value verbatim into the PodCertificateRequests it
+ generates for this projection.
+
+ If omitted, kube-apiserver will set it to 86400(24 hours). kube-apiserver
+ will reject values shorter than 3600 (1 hour). The maximum allowable
+ value is 7862400 (91 days).
+
+ The signer implementation is then free to issue a certificate with any
+ lifetime *shorter* than MaxExpirationSeconds, but no shorter than 3600
+ seconds (1 hour). This constraint is enforced by kube-apiserver.
+ `kubernetes.io` signers will never issue certificates with a lifetime
+ longer than 24 hours.
+ format: int32
+ type: integer
+ signerName:
+ description: Kubelet's generated CSRs
+ will be addressed to this signer.
+ type: string
+ userAnnotations:
+ additionalProperties:
+ type: string
+ description: |-
+ userAnnotations allow pod authors to pass additional information to
+ the signer implementation. Kubernetes does not restrict or validate this
+ metadata in any way.
+
+ These values are copied verbatim into the `spec.unverifiedUserAnnotations` field of
+ the PodCertificateRequest objects that Kubelet creates.
+
+ Entries are subject to the same validation as object metadata annotations,
+ with the addition that all keys must be domain-prefixed. No restrictions
+ are placed on values, except an overall size limitation on the entire field.
+
+ Signers should document the keys and values they support. Signers should
+ deny requests that contain keys they do not recognize.
+ type: object
+ required:
+ - keyType
+ - signerName
+ type: object
+ secret:
+ description: secret information about the
+ secret data to project
+ properties:
+ items:
+ description: |-
+ items if unspecified, each key-value pair in the Data field of the referenced
+ Secret will be projected into the volume as a file whose name is the
+ key and content is the value. If specified, the listed keys will be
+ projected into the specified paths, and unlisted keys will not be
+ present. If a key is specified which is not present in the Secret,
+ the volume setup will error unless it is marked optional. Paths must be
+ relative and may not contain the '..' path or start with '..'.
+ items:
+ description: Maps a string key to a
+ path within a volume.
+ properties:
+ key:
+ description: key is the key to project.
+ type: string
+ mode:
+ description: |-
+ mode is Optional: mode bits used to set permissions on this file.
+ Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511.
+ YAML accepts both octal and decimal values, JSON requires decimal values for mode bits.
+ If not specified, the volume defaultMode will be used.
+ This might be in conflict with other options that affect the file
+ mode, like fsGroup, and the result can be other mode bits set.
+ format: int32
+ type: integer
+ path:
+ description: |-
+ path is the relative path of the file to map the key to.
+ May not be an absolute path.
+ May not contain the path element '..'.
+ May not start with the string '..'.
+ type: string
+ required:
+ - key
+ - path
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: optional field specify whether
+ the Secret or its key must be defined
+ type: boolean
+ type: object
+ x-kubernetes-map-type: atomic
+ serviceAccountToken:
+ description: serviceAccountToken is information
+ about the serviceAccountToken data to project
+ properties:
+ audience:
+ description: |-
+ audience is the intended audience of the token. A recipient of a token
+ must identify itself with an identifier specified in the audience of the
+ token, and otherwise should reject the token. The audience defaults to the
+ identifier of the apiserver.
+ type: string
+ expirationSeconds:
+ description: |-
+ expirationSeconds is the requested duration of validity of the service
+ account token. As the token approaches expiration, the kubelet volume
+ plugin will proactively rotate the service account token. The kubelet will
+ start trying to rotate the token if the token is older than 80 percent of
+ its time to live or if the token is older than 24 hours.Defaults to 1 hour
+ and must be at least 10 minutes.
+ format: int64
+ type: integer
+ path:
+ description: |-
+ path is the path relative to the mount point of the file to project the
+ token into.
+ type: string
+ required:
+ - path
+ type: object
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ quobyte:
+ description: |-
+ quobyte represents a Quobyte mount on the host that shares a pod's lifetime.
+ Deprecated: Quobyte is deprecated and the in-tree quobyte type is no longer supported.
+ properties:
+ group:
+ description: |-
+ group to map volume access to
+ Default is no group
+ type: string
+ readOnly:
+ description: |-
+ readOnly here will force the Quobyte volume to be mounted with read-only permissions.
+ Defaults to false.
+ type: boolean
+ registry:
+ description: |-
+ registry represents a single or multiple Quobyte Registry services
+ specified as a string as host:port pair (multiple entries are separated with commas)
+ which acts as the central registry for volumes
+ type: string
+ tenant:
+ description: |-
+ tenant owning the given Quobyte volume in the Backend
+ Used with dynamically provisioned Quobyte volumes, value is set by the plugin
+ type: string
+ user:
+ description: |-
+ user to map volume access to
+ Defaults to serivceaccount user
+ type: string
+ volume:
+ description: volume is a string that references
+ an already created Quobyte volume by name.
+ type: string
+ required:
+ - registry
+ - volume
+ type: object
+ rbd:
+ description: |-
+ rbd represents a Rados Block Device mount on the host that shares a pod's lifetime.
+ Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported.
+ properties:
+ fsType:
+ description: |-
+ fsType is the filesystem type of the volume that you want to mount.
+ Tip: Ensure that the filesystem type is supported by the host operating system.
+ Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd
+ type: string
+ image:
+ description: |-
+ image is the rados image name.
+ More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it
+ type: string
+ keyring:
+ default: /etc/ceph/keyring
+ description: |-
+ keyring is the path to key ring for RBDUser.
+ Default is /etc/ceph/keyring.
+ More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it
+ type: string
+ monitors:
+ description: |-
+ monitors is a collection of Ceph monitors.
+ More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ pool:
+ default: rbd
+ description: |-
+ pool is the rados pool name.
+ Default is rbd.
+ More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it
+ type: string
+ readOnly:
+ description: |-
+ readOnly here will force the ReadOnly setting in VolumeMounts.
+ Defaults to false.
+ More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it
+ type: boolean
+ secretRef:
+ description: |-
+ secretRef is name of the authentication secret for RBDUser. If provided
+ overrides keyring.
+ Default is nil.
+ More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it
+ properties:
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ user:
+ default: admin
+ description: |-
+ user is the rados user name.
+ Default is admin.
+ More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it
+ type: string
+ required:
+ - image
+ - monitors
+ type: object
+ scaleIO:
+ description: |-
+ scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes.
+ Deprecated: ScaleIO is deprecated and the in-tree scaleIO type is no longer supported.
+ properties:
+ fsType:
+ default: xfs
+ description: |-
+ fsType is the filesystem type to mount.
+ Must be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs".
+ Default is "xfs".
+ type: string
+ gateway:
+ description: gateway is the host address of the
+ ScaleIO API Gateway.
+ type: string
+ protectionDomain:
+ description: protectionDomain is the name of the
+ ScaleIO Protection Domain for the configured storage.
+ type: string
+ readOnly:
+ description: |-
+ readOnly Defaults to false (read/write). ReadOnly here will force
+ the ReadOnly setting in VolumeMounts.
+ type: boolean
+ secretRef:
+ description: |-
+ secretRef references to the secret for ScaleIO user and other
+ sensitive information. If this is not provided, Login operation will fail.
+ properties:
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ sslEnabled:
+ description: sslEnabled Flag enable/disable SSL
+ communication with Gateway, default false
+ type: boolean
+ storageMode:
+ default: ThinProvisioned
+ description: |-
+ storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned.
+ Default is ThinProvisioned.
+ type: string
+ storagePool:
+ description: storagePool is the ScaleIO Storage
+ Pool associated with the protection domain.
+ type: string
+ system:
+ description: system is the name of the storage system
+ as configured in ScaleIO.
+ type: string
+ volumeName:
+ description: |-
+ volumeName is the name of a volume already created in the ScaleIO system
+ that is associated with this volume source.
+ type: string
+ required:
+ - gateway
+ - secretRef
+ - system
+ type: object
+ secret:
+ description: |-
+ secret represents a secret that should populate this volume.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#secret
+ properties:
+ defaultMode:
+ description: |-
+ defaultMode is Optional: mode bits used to set permissions on created files by default.
+ Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511.
+ YAML accepts both octal and decimal values, JSON requires decimal values
+ for mode bits. Defaults to 0644.
+ Directories within the path are not affected by this setting.
+ This might be in conflict with other options that affect the file
+ mode, like fsGroup, and the result can be other mode bits set.
+ format: int32
+ type: integer
+ items:
+ description: |-
+ items If unspecified, each key-value pair in the Data field of the referenced
+ Secret will be projected into the volume as a file whose name is the
+ key and content is the value. If specified, the listed keys will be
+ projected into the specified paths, and unlisted keys will not be
+ present. If a key is specified which is not present in the Secret,
+ the volume setup will error unless it is marked optional. Paths must be
+ relative and may not contain the '..' path or start with '..'.
+ items:
+ description: Maps a string key to a path within
+ a volume.
+ properties:
+ key:
+ description: key is the key to project.
+ type: string
+ mode:
+ description: |-
+ mode is Optional: mode bits used to set permissions on this file.
+ Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511.
+ YAML accepts both octal and decimal values, JSON requires decimal values for mode bits.
+ If not specified, the volume defaultMode will be used.
+ This might be in conflict with other options that affect the file
+ mode, like fsGroup, and the result can be other mode bits set.
+ format: int32
+ type: integer
+ path:
+ description: |-
+ path is the relative path of the file to map the key to.
+ May not be an absolute path.
+ May not contain the path element '..'.
+ May not start with the string '..'.
+ type: string
+ required:
+ - key
+ - path
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ optional:
+ description: optional field specify whether the
+ Secret or its keys must be defined
+ type: boolean
+ secretName:
+ description: |-
+ secretName is the name of the secret in the pod's namespace to use.
+ More info: https://kubernetes.io/docs/concepts/storage/volumes#secret
+ type: string
+ type: object
+ storageos:
+ description: |-
+ storageOS represents a StorageOS volume attached and mounted on Kubernetes nodes.
+ Deprecated: StorageOS is deprecated and the in-tree storageos type is no longer supported.
+ properties:
+ fsType:
+ description: |-
+ fsType is the filesystem type to mount.
+ Must be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified.
+ type: string
+ readOnly:
+ description: |-
+ readOnly defaults to false (read/write). ReadOnly here will force
+ the ReadOnly setting in VolumeMounts.
+ type: boolean
+ secretRef:
+ description: |-
+ secretRef specifies the secret to use for obtaining the StorageOS API
+ credentials. If not specified, default values will be attempted.
+ properties:
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ volumeName:
+ description: |-
+ volumeName is the human-readable name of the StorageOS volume. Volume
+ names are only unique within a namespace.
+ type: string
+ volumeNamespace:
+ description: |-
+ volumeNamespace specifies the scope of the volume within StorageOS. If no
+ namespace is specified then the Pod's namespace will be used. This allows the
+ Kubernetes name scoping to be mirrored within StorageOS for tighter integration.
+ Set VolumeName to any name to override the default behaviour.
+ Set to "default" if you are not using namespaces within StorageOS.
+ Namespaces that do not pre-exist within StorageOS will be created.
+ type: string
+ type: object
+ vsphereVolume:
+ description: |-
+ vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine.
+ Deprecated: VsphereVolume is deprecated. All operations for the in-tree vsphereVolume type
+ are redirected to the csi.vsphere.vmware.com CSI driver.
+ properties:
+ fsType:
+ description: |-
+ fsType is filesystem type to mount.
+ Must be a filesystem type supported by the host operating system.
+ Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified.
+ type: string
+ storagePolicyID:
+ description: storagePolicyID is the storage Policy
+ Based Management (SPBM) profile ID associated
+ with the StoragePolicyName.
+ type: string
+ storagePolicyName:
+ description: storagePolicyName is the storage Policy
+ Based Management (SPBM) profile name.
+ type: string
+ volumePath:
+ description: volumePath is the path that identifies
+ vSphere volume vmdk
+ type: string
+ required:
+ - volumePath
+ type: object
+ required:
+ - name
+ type: object
+ type: array
+ type: object
+ profile:
+ description: Specifies which installation configuration profile
+ to apply.
+ type: string
+ revision:
+ description: Identifies the revision this installation is associated
+ with.
+ type: string
+ sidecarInjectorWebhook:
+ description: Configuration for the sidecar injector webhook.
+ properties:
+ alwaysInjectSelector:
+ description: See NeverInjectSelector.
+ items:
+ description: |-
+ A label selector is a label query over a set of resources. The result of matchLabels and
+ matchExpressions are ANDed. An empty label selector matches all objects. A null
+ label selector matches no objects.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label selector
+ requirements. The requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label key that the selector
+ applies to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ type: array
+ defaultTemplates:
+ description: 'defaultTemplates: ["sidecar", "hello"]'
+ items:
+ type: string
+ type: array
+ enableNamespacesByDefault:
+ description: Enables sidecar auto-injection in namespaces
+ by default.
+ type: boolean
+ injectedAnnotations:
+ additionalProperties:
+ type: string
+ description: |-
+ injectedAnnotations are additional annotations that will be added to the pod spec after injection
+ This is primarily to support PSP annotations.
+ type: object
+ injectionURL:
+ description: Configure the injection url for sidecar injector
+ webhook
+ type: string
+ neverInjectSelector:
+ description: |-
+ Instructs Istio to not inject the sidecar on those pods, based on labels that are present in those pods.
+
+ Annotations in the pods have higher precedence than the label selectors.
+ Order of evaluation: Pod Annotations → NeverInjectSelector → AlwaysInjectSelector → Default Policy.
+ See https://istio.io/docs/setup/kubernetes/additional-setup/sidecar-injection/#more-control-adding-exceptions
+ items:
+ description: |-
+ A label selector is a label query over a set of resources. The result of matchLabels and
+ matchExpressions are ANDed. An empty label selector matches all objects. A null
+ label selector matches no objects.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label selector
+ requirements. The requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label key that the selector
+ applies to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ type: array
+ reinvocationPolicy:
+ description: 'Setting this to `IfNeeded` will result in the
+ sidecar injector being run again if additional mutations
+ occur. Default: Never'
+ type: string
+ rewriteAppHTTPProbe:
+ description: If true, webhook or istioctl injector will rewrite
+ PodSpec for liveness health check to redirect request to
+ sidecar. This makes liveness check work even when mTLS is
+ enabled.
+ type: boolean
+ templates:
+ additionalProperties:
+ type: string
+ description: "Templates defines a set of custom injection
+ templates that can be used. For example, defining:\n\ntemplates:\n\n\thello:
+ |\n\t metadata:\n\t labels:\n\t hello: world\n\nThen
+ starting a pod with the `inject.istio.io/templates: hello`
+ annotation, will result in the pod\nbeing injected with
+ the hello=world labels.\nThis is intended for advanced configuration
+ only; most users should use the built in template"
+ type: object
+ type: object
+ telemetry:
+ description: Controls whether telemetry is exported for Pilot.
+ properties:
+ enabled:
+ description: Controls whether telemetry is exported for Pilot.
+ type: boolean
+ v2:
+ description: Configuration for Telemetry v2.
+ properties:
+ enabled:
+ description: Controls whether pilot will configure telemetry
+ v2.
+ type: boolean
+ prometheus:
+ description: Telemetry v2 settings for prometheus.
+ properties:
+ enabled:
+ description: Controls whether stats envoyfilter would
+ be enabled or not.
+ type: boolean
+ type: object
+ stackdriver:
+ description: Telemetry v2 settings for stackdriver.
+ properties:
+ enabled:
+ type: boolean
+ type: object
+ type: object
+ type: object
+ type: object
+ version:
+ description: |-
+ Defines the version of Istio to install.
+ Must be one of: v1.28.3, v1.28.2, v1.28.1, v1.28.0, v1.27.5, v1.27.4, v1.27.3, v1.27.2, v1.27.1, v1.27.0, v1.30-alpha.a30ad733.
+ enum:
+ - v1.28.3
+ - v1.28.2
+ - v1.28.1
+ - v1.28.0
+ - v1.27.5
+ - v1.27.4
+ - v1.27.3
+ - v1.27.2
+ - v1.27.1
+ - v1.27.0
+ - v1.26.8
+ - v1.26.7
+ - v1.26.6
+ - v1.26.5
+ - v1.26.4
+ - v1.26.3
+ - v1.26.2
+ - v1.26.1
+ - v1.26.0
+ - v1.25.5
+ - v1.25.4
+ - v1.25.3
+ - v1.25.2
+ - v1.25.1
+ - v1.24.6
+ - v1.24.5
+ - v1.24.4
+ - v1.24.3
+ - v1.24.2
+ - v1.24.1
+ - v1.24.0
+ - v1.23.6
+ - v1.23.5
+ - v1.23.4
+ - v1.23.3
+ - v1.23.2
+ - v1.22.8
+ - v1.22.7
+ - v1.22.6
+ - v1.22.5
+ - v1.21.6
+ - v1.30-alpha.a30ad733
+ type: string
+ required:
+ - namespace
+ - version
+ type: object
+ x-kubernetes-validations:
+ - message: spec.values.global.istioNamespace must match spec.namespace
+ rule: self.values.global.istioNamespace == self.__namespace__
+ status:
+ description: IstioRevisionStatus defines the observed state of IstioRevision
+ properties:
+ conditions:
+ description: Represents the latest available observations of the object's
+ current state.
+ items:
+ description: IstioRevisionCondition represents a specific observation
+ of the IstioRevision object's state.
+ properties:
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ the last transition.
+ type: string
+ reason:
+ description: Unique, single-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: The status of this condition. Can be True, False
+ or Unknown.
+ type: string
+ type:
+ description: The type of this condition.
+ type: string
+ type: object
+ type: array
+ observedGeneration:
+ description: |-
+ ObservedGeneration is the most recent generation observed for this
+ IstioRevision object. It corresponds to the object's generation, which is
+ updated on mutation by the API Server. The information in the status
+ pertains to this particular generation of the object.
+ format: int64
+ type: integer
+ state:
+ description: Reports the current state of the object.
+ type: string
+ type: object
+ type: object
+ x-kubernetes-validations:
+ - message: spec.values.revision must match metadata.name or be empty when
+ the name is 'default'
+ rule: 'self.metadata.name == ''default'' ? (!has(self.spec.values.revision)
+ || size(self.spec.values.revision) == 0) : self.spec.values.revision ==
+ self.metadata.name'
+ served: true
+ storage: true
+ subresources:
+ status: {}
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/sailoperator.io_istiorevisiontags.yaml b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/sailoperator.io_istiorevisiontags.yaml
new file mode 100644
index 0000000000..02b3c65657
--- /dev/null
+++ b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/sailoperator.io_istiorevisiontags.yaml
@@ -0,0 +1,147 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.20.0
+ name: istiorevisiontags.sailoperator.io
+spec:
+ group: sailoperator.io
+ names:
+ categories:
+ - istio-io
+ kind: IstioRevisionTag
+ listKind: IstioRevisionTagList
+ plural: istiorevisiontags
+ shortNames:
+ - istiorevtag
+ singular: istiorevisiontag
+ scope: Cluster
+ versions:
+ - additionalPrinterColumns:
+ - description: The current state of this object.
+ jsonPath: .status.state
+ name: Status
+ type: string
+ - description: Whether the tag is being used by workloads.
+ jsonPath: .status.conditions[?(@.type=="InUse")].status
+ name: In use
+ type: string
+ - description: The IstioRevision this object is referencing.
+ jsonPath: .status.istioRevision
+ name: Revision
+ type: string
+ - description: The age of the object
+ jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1
+ schema:
+ openAPIV3Schema:
+ description: IstioRevisionTag references an Istio or IstioRevision object
+ and serves as an alias for sidecar injection. It can be used to manage stable
+ revision tags without having to use istioctl or helm directly. See https://istio.io/latest/docs/setup/upgrade/canary/#stable-revision-labels
+ for more information on the concept.
+ properties:
+ apiVersion:
+ description: |-
+ APIVersion defines the versioned schema of this representation of an object.
+ Servers should convert recognized schemas to the latest internal value, and
+ may reject unrecognized values.
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
+ type: string
+ kind:
+ description: |-
+ Kind is a string value representing the REST resource this object represents.
+ Servers may infer this from the endpoint the client submits requests to.
+ Cannot be updated.
+ In CamelCase.
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
+ type: string
+ metadata:
+ type: object
+ spec:
+ description: IstioRevisionTagSpec defines the desired state of IstioRevisionTag
+ properties:
+ targetRef:
+ description: IstioRevisionTagTargetReference can reference either
+ Istio or IstioRevision objects in the cluster. In the case of referencing
+ an Istio object, the Sail Operator will automatically update the
+ reference to the Istio object's Active Revision.
+ properties:
+ kind:
+ description: Kind is the kind of the target resource.
+ maxLength: 253
+ minLength: 1
+ type: string
+ name:
+ description: Name is the name of the target resource.
+ maxLength: 253
+ minLength: 1
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ required:
+ - targetRef
+ type: object
+ status:
+ description: IstioRevisionStatus defines the observed state of IstioRevision
+ properties:
+ conditions:
+ description: Represents the latest available observations of the object's
+ current state.
+ items:
+ description: IstioRevisionCondition represents a specific observation
+ of the IstioRevision object's state.
+ properties:
+ lastTransitionTime:
+ description: Last time the condition transitioned from one status
+ to another.
+ format: date-time
+ type: string
+ message:
+ description: Human-readable message indicating details about
+ the last transition.
+ type: string
+ reason:
+ description: Unique, single-word, CamelCase reason for the condition's
+ last transition.
+ type: string
+ status:
+ description: The status of this condition. Can be True, False
+ or Unknown.
+ type: string
+ type:
+ description: The type of this condition.
+ type: string
+ type: object
+ type: array
+ istioRevision:
+ description: IstioRevision stores the name of the referenced IstioRevision
+ type: string
+ istiodNamespace:
+ description: IstiodNamespace stores the namespace of the corresponding
+ Istiod instance
+ type: string
+ observedGeneration:
+ description: |-
+ ObservedGeneration is the most recent generation observed for this
+ IstioRevisionTag object. It corresponds to the object's generation, which is
+ updated on mutation by the API Server. The information in the status
+ pertains to this particular generation of the object.
+ format: int64
+ type: integer
+ state:
+ description: Reports the current state of the object.
+ type: string
+ required:
+ - istioRevision
+ - istiodNamespace
+ type: object
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
diff --git a/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/sailoperator.io_istios.yaml b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/sailoperator.io_istios.yaml
new file mode 100644
index 0000000000..c5660a7c74
--- /dev/null
+++ b/vendor/github.com/istio-ecosystem/sail-operator/chart/crds/sailoperator.io_istios.yaml
@@ -0,0 +1,10331 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.20.0
+ name: istios.sailoperator.io
+spec:
+ group: sailoperator.io
+ names:
+ categories:
+ - istio-io
+ kind: Istio
+ listKind: IstioList
+ plural: istios
+ singular: istio
+ scope: Cluster
+ versions:
+ - additionalPrinterColumns:
+ - description: The namespace for the control plane components.
+ jsonPath: .spec.namespace
+ name: Namespace
+ type: string
+ - description: The selected profile (collection of value presets).
+ jsonPath: .spec.profile
+ name: Profile
+ type: string
+ - description: Total number of IstioRevision objects currently associated with
+ this object.
+ jsonPath: .status.revisions.total
+ name: Revisions
+ type: string
+ - description: Number of revisions that are ready.
+ jsonPath: .status.revisions.ready
+ name: Ready
+ type: string
+ - description: Number of revisions that are currently being used by workloads.
+ jsonPath: .status.revisions.inUse
+ name: In use
+ type: string
+ - description: The name of the currently active revision.
+ jsonPath: .status.activeRevisionName
+ name: Active Revision
+ type: string
+ - description: The current state of the active revision.
+ jsonPath: .status.state
+ name: Status
+ type: string
+ - description: The version of the control plane installation.
+ jsonPath: .spec.version
+ name: Version
+ type: string
+ - description: The age of the object
+ jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1
+ schema:
+ openAPIV3Schema:
+ description: |-
+ Istio represents an Istio Service Mesh deployment consisting of one or more
+ control plane instances (represented by one or more IstioRevision objects).
+ To deploy an Istio Service Mesh, a user creates an Istio object with the
+ desired Istio version and configuration. The operator then creates
+ an IstioRevision object, which in turn creates the underlying Deployment
+ objects for istiod and other control plane components, similar to how a
+ Deployment object in Kubernetes creates ReplicaSets that create the Pods.
+ properties:
+ apiVersion:
+ description: |-
+ APIVersion defines the versioned schema of this representation of an object.
+ Servers should convert recognized schemas to the latest internal value, and
+ may reject unrecognized values.
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
+ type: string
+ kind:
+ description: |-
+ Kind is a string value representing the REST resource this object represents.
+ Servers may infer this from the endpoint the client submits requests to.
+ Cannot be updated.
+ In CamelCase.
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
+ type: string
+ metadata:
+ type: object
+ spec:
+ default:
+ namespace: istio-system
+ updateStrategy:
+ type: InPlace
+ version: v1.28.3
+ description: IstioSpec defines the desired state of Istio
+ properties:
+ namespace:
+ default: istio-system
+ description: Namespace to which the Istio components should be installed.
+ Note that this field is immutable.
+ type: string
+ x-kubernetes-validations:
+ - message: Value is immutable
+ rule: self == oldSelf
+ profile:
+ description: |-
+ The built-in installation configuration profile to use.
+ The 'default' profile is always applied. On OpenShift, the 'openshift' profile is also applied on top of 'default'.
+ Must be one of: ambient, default, demo, empty, openshift, openshift-ambient, preview, remote, stable.
+ enum:
+ - ambient
+ - default
+ - demo
+ - empty
+ - external
+ - openshift
+ - openshift-ambient
+ - preview
+ - remote
+ - stable
+ type: string
+ updateStrategy:
+ default:
+ type: InPlace
+ description: Defines the update strategy to use when the version in
+ the Istio CR is updated.
+ properties:
+ inactiveRevisionDeletionGracePeriodSeconds:
+ description: |-
+ Defines how many seconds the operator should wait before removing a non-active revision after all
+ the workloads have stopped using it. You may want to set this value on the order of minutes.
+ The minimum is 0 and the default value is 30.
+ format: int64
+ minimum: 0
+ type: integer
+ type:
+ default: InPlace
+ description: "Type of strategy to use. Can be \"InPlace\" or \"RevisionBased\".
+ When the \"InPlace\" strategy\nis used, the existing Istio control
+ plane is updated in-place. The workloads therefore\ndon't need
+ to be moved from one control plane instance to another. When
+ the \"RevisionBased\"\nstrategy is used, a new Istio control
+ plane instance is created for every change to the\nIstio.spec.version
+ field. The old control plane remains in place until all workloads
+ have\nbeen moved to the new control plane instance.\n\nThe \"InPlace\"
+ strategy is the default.\tTODO: change default to \"RevisionBased\""
+ enum:
+ - InPlace
+ - RevisionBased
+ type: string
+ updateWorkloads:
+ description: |-
+ Defines whether the workloads should be moved from one control plane instance to another
+ automatically. If updateWorkloads is true, the operator moves the workloads from the old
+ control plane instance to the new one after the new control plane is ready.
+ If updateWorkloads is false, the user must move the workloads manually by updating the
+ istio.io/rev labels on the namespace and/or the pods.
+ Defaults to false.
+ type: boolean
+ type: object
+ values:
+ description: Defines the values to be passed to the Helm charts when
+ installing Istio.
+ properties:
+ base:
+ description: Configuration for the base component.
+ properties:
+ excludedCRDs:
+ description: CRDs to exclude. Requires `enableCRDTemplates`
+ items:
+ type: string
+ type: array
+ validationCABundle:
+ description: validation webhook CA bundle
+ type: string
+ validationURL:
+ description: URL to use for validating webhook.
+ type: string
+ type: object
+ compatibilityVersion:
+ description: |-
+ Specifies the compatibility version to use. When this is set, the control plane will
+ be configured with the same defaults as the specified version.
+ type: string
+ defaultRevision:
+ description: |-
+ The name of the default revision in the cluster.
+ Deprecated: This field is ignored. The default revision is expected to be configurable elsewhere.
+ type: string
+ experimental:
+ description: Specifies experimental helm fields that could be
+ removed or changed in the future
+ x-kubernetes-preserve-unknown-fields: true
+ gatewayClasses:
+ description: Configuration for Gateway Classes
+ x-kubernetes-preserve-unknown-fields: true
+ global:
+ description: Global configuration for Istio components.
+ properties:
+ agentgateway:
+ description: Specifies how proxies are configured within Istio.
+ properties:
+ image:
+ type: string
+ type: object
+ arch:
+ description: "Specifies pod scheduling arch(amd64, ppc64le,
+ s390x, arm64) and weight as follows:\n\n\t0 - Never scheduled\n\t1
+ - Least preferred\n\t2 - No preference\n\t3 - Most preferred\n\nDeprecated:
+ replaced by the affinity k8s settings which allows architecture
+ nodeAffinity configuration of this behavior.\n\nDeprecated:
+ Marked as deprecated in pkg/apis/values_types.proto."
+ properties:
+ amd64:
+ description: Sets pod scheduling weight for amd64 arch
+ format: int32
+ type: integer
+ arm64:
+ description: Sets pod scheduling weight for arm64 arch.
+ format: int32
+ type: integer
+ ppc64le:
+ description: Sets pod scheduling weight for ppc64le arch.
+ format: int32
+ type: integer
+ s390x:
+ description: Sets pod scheduling weight for s390x arch.
+ format: int32
+ type: integer
+ type: object
+ caAddress:
+ description: The address of the CA for CSR.
+ type: string
+ caName:
+ description: |-
+ The name of the CA for workloads.
+ For example, when caName=GkeWorkloadCertificate, GKE workload certificates
+ will be used as the certificates for workloads.
+ The default value is "" and when caName="", the CA will be configured by other
+ mechanisms (e.g., environmental variable CA_PROVIDER).
+ type: string
+ certSigners:
+ description: List of certSigners to allow "approve" action
+ in the ClusterRole
+ items:
+ type: string
+ type: array
+ configCluster:
+ description: Controls whether a remote cluster is the config
+ cluster for an external istiod
+ type: boolean
+ configValidation:
+ description: Controls whether the server-side validation is
+ enabled.
+ type: boolean
+ defaultNodeSelector:
+ additionalProperties:
+ type: string
+ description: |-
+ Default k8s node selector for all the Istio control plane components
+
+ See https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ type: object
+ defaultPodDisruptionBudget:
+ description: Specifies the default pod disruption budget configuration.
+ properties:
+ enabled:
+ description: Controls whether a PodDisruptionBudget with
+ a default minAvailable value of 1 is created for each
+ deployment.
+ type: boolean
+ type: object
+ defaultResources:
+ description: |-
+ Default k8s resources settings for all Istio control plane components.
+
+ See https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ properties:
+ claims:
+ description: |-
+ Claims lists the names of resources, defined in spec.resourceClaims,
+ that are used by this container.
+
+ This field depends on the
+ DynamicResourceAllocation feature gate.
+
+ This field is immutable. It can only be set for containers.
+ items:
+ description: ResourceClaim references one entry in PodSpec.ResourceClaims.
+ properties:
+ name:
+ description: |-
+ Name must match the name of one entry in pod.spec.resourceClaims of
+ the Pod where this field is used. It makes that resource available
+ inside a container.
+ type: string
+ request:
+ description: |-
+ Request is the name chosen for a request in the referenced claim.
+ If empty, everything from the claim is made available, otherwise
+ only the result of this request.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - name
+ x-kubernetes-list-type: map
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Limits describes the maximum amount of compute resources allowed.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Requests describes the minimum amount of compute resources required.
+ If Requests is omitted for a container, it defaults to Limits if that is explicitly specified,
+ otherwise to an implementation-defined value. Requests cannot exceed Limits.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ type: object
+ defaultTolerations:
+ description: |-
+ Default node tolerations to be applied to all deployments so that all pods can be
+ scheduled to nodes with matching taints. Each component can overwrite
+ these default values by adding its tolerations block in the relevant section below
+ and setting the desired values.
+ Configure this field in case that all pods of Istio control plane are expected to
+ be scheduled to particular nodes with specified taints.
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ items:
+ description: |-
+ The pod this Toleration is attached to tolerates any taint that matches
+ the triple using the matching operator .
+ properties:
+ effect:
+ description: |-
+ Effect indicates the taint effect to match. Empty means match all taint effects.
+ When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.
+ type: string
+ key:
+ description: |-
+ Key is the taint key that the toleration applies to. Empty means match all taint keys.
+ If the key is empty, operator must be Exists; this combination means to match all values and all keys.
+ type: string
+ operator:
+ description: |-
+ Operator represents a key's relationship to the value.
+ Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal.
+ Exists is equivalent to wildcard for value, so that a pod can
+ tolerate all taints of a particular category.
+ Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators).
+ type: string
+ tolerationSeconds:
+ description: |-
+ TolerationSeconds represents the period of time the toleration (which must be
+ of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default,
+ it is not set, which means tolerate the taint forever (do not evict). Zero and
+ negative values will be treated as 0 (evict immediately) by the system.
+ format: int64
+ type: integer
+ value:
+ description: |-
+ Value is the taint value the toleration matches to.
+ If the operator is Exists, the value should be empty, otherwise just a regular string.
+ type: string
+ type: object
+ type: array
+ externalIstiod:
+ description: Controls whether one external istiod is enabled.
+ type: boolean
+ hub:
+ description: Specifies the docker hub for Istio images.
+ type: string
+ imagePullPolicy:
+ description: |-
+ Specifies the image pull policy for the Istio images. one of Always, Never, IfNotPresent.
+ Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated.
+
+ More info: https://kubernetes.io/docs/concepts/containers/images#updating-images
+ enum:
+ - Always
+ - Never
+ - IfNotPresent
+ type: string
+ imagePullSecrets:
+ description: |-
+ ImagePullSecrets for the control plane ServiceAccount, list of secrets in the same namespace
+ to use for pulling any images in pods that reference this ServiceAccount.
+ Must be set for any cluster configured with private docker registry.
+ items:
+ type: string
+ type: array
+ ipFamilies:
+ description: |-
+ Defines which IP family to use for single stack or the order of IP families for dual-stack.
+ Valid list items are "IPv4", "IPv6".
+ More info: https://kubernetes.io/docs/concepts/services-networking/dual-stack/#services
+ items:
+ type: string
+ type: array
+ ipFamilyPolicy:
+ description: |-
+ Controls whether Services are configured to use IPv4, IPv6, or both. Valid options
+ are PreferDualStack, RequireDualStack, and SingleStack.
+ More info: https://kubernetes.io/docs/concepts/services-networking/dual-stack/#services
+ type: string
+ istioNamespace:
+ description: Specifies the default namespace for the Istio
+ control plane components.
+ type: string
+ istiod:
+ description: Specifies the configution of istiod
+ properties:
+ enableAnalysis:
+ description: If enabled, istiod will perform config analysis
+ type: boolean
+ type: object
+ jwtPolicy:
+ description: |-
+ Configure the policy for validating JWT.
+ This is deprecated and has no effect.
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ type: string
+ logAsJson:
+ description: Specifies whether istio components should output
+ logs in json format by adding --log_as_json argument to
+ each container.
+ type: boolean
+ logging:
+ description: Specifies the global logging level settings for
+ the Istio control plane components.
+ properties:
+ level:
+ description: |-
+ Comma-separated minimum per-scope logging level of messages to output, in the form of :,:
+ The control plane has different scopes depending on component, but can configure default log level across all components
+ If empty, default scope and level will be used as configured in code
+ type: string
+ type: object
+ meshID:
+ description: |-
+ The Mesh Identifier. It should be unique within the scope where
+ meshes will interact with each other, but it is not required to be
+ globally/universally unique. For example, if any of the following are true,
+ then two meshes must have different Mesh IDs:
+ - Meshes will have their telemetry aggregated in one place
+ - Meshes will be federated together
+ - Policy will be written referencing one mesh from the other
+
+ If an administrator expects that any of these conditions may become true in
+ the future, they should ensure their meshes have different Mesh IDs
+ assigned.
+
+ Within a multicluster mesh, each cluster must be (manually or auto)
+ configured to have the same Mesh ID value. If an existing cluster 'joins' a
+ multicluster mesh, it will need to be migrated to the new mesh ID. Details
+ of migration TBD, and it may be a disruptive operation to change the Mesh
+ ID post-install.
+
+ If the mesh admin does not specify a value, Istio will use the value of the
+ mesh's Trust Domain. The best practice is to select a proper Trust Domain
+ value.
+ type: string
+ meshNetworks:
+ additionalProperties:
+ description: |-
+ Network provides information about the endpoints in a routable L3
+ network. A single routable L3 network can have one or more service
+ registries. Note that the network has no relation to the locality of the
+ endpoint. The endpoint locality will be obtained from the service
+ registry.
+ properties:
+ endpoints:
+ description: |-
+ The list of endpoints in the network (obtained through the
+ constituent service registries or from CIDR ranges). All endpoints in
+ the network are directly accessible to one another.
+ items:
+ description: "NetworkEndpoints describes how the network
+ associated with an endpoint\nshould be inferred.
+ An endpoint will be assigned to a network based
+ on\nthe following rules:\n\n1. Implicitly: If the
+ registry explicitly provides information about\nthe
+ network to which the endpoint belongs to. In some
+ cases, its\npossible to indicate the network associated
+ with the endpoint by\nadding the `ISTIO_META_NETWORK`
+ environment variable to the sidecar.\n\n2. Explicitly:\n\n\ta.
+ By matching the registry name with one of the \"fromRegistry\"\n\tin
+ the mesh config. A \"fromRegistry\" can only be
+ assigned to a\n\tsingle network.\n\n\tb. By matching
+ the IP against one of the CIDR ranges in a mesh\n\tconfig
+ network. The CIDR ranges must not overlap and be
+ assigned to\n\ta single network.\n\n(2) will override
+ (1) if both are present."
+ properties:
+ fromCidr:
+ description: |-
+ A CIDR range for the set of endpoints in this network. The CIDR
+ ranges for endpoints from different networks must not overlap.
+ type: string
+ fromRegistry:
+ description: |-
+ Add all endpoints from the specified registry into this network.
+ The names of the registries should correspond to the kubeconfig file name
+ inside the secret that was used to configure the registry (Kubernetes
+ multicluster) or supplied by MCP server.
+ type: string
+ type: object
+ x-kubernetes-validations:
+ - message: At most one of [fromCidr fromRegistry]
+ should be set
+ rule: (has(self.fromCidr)?1:0) + (has(self.fromRegistry)?1:0)
+ <= 1
+ type: array
+ gateways:
+ description: Set of gateways associated with the network.
+ items:
+ description: |-
+ The gateway associated with this network. Traffic from remote networks
+ will arrive at the specified gateway:port. All incoming traffic must
+ use mTLS.
+ properties:
+ address:
+ description: IP address or externally resolvable
+ DNS address associated with the gateway.
+ type: string
+ locality:
+ description: The locality associated with an explicitly
+ specified gateway (i.e. ip)
+ type: string
+ port:
+ format: int32
+ type: integer
+ registryServiceName:
+ description: |-
+ A fully qualified domain name of the gateway service. istiod will
+ lookup the service from the service registries in the network and
+ obtain the endpoint IPs of the gateway from the service
+ registry. Note that while the service name is a fully qualified
+ domain name, it need not be resolvable outside the orchestration
+ platform for the registry. e.g., this could be
+ istio-ingressgateway.istio-system.svc.cluster.local.
+ type: string
+ type: object
+ x-kubernetes-validations:
+ - message: At most one of [registryServiceName address]
+ should be set
+ rule: (has(self.registryServiceName)?1:0) + (has(self.address)?1:0)
+ <= 1
+ type: array
+ type: object
+ description: "Configure the mesh networks to be used by the
+ Split Horizon EDS.\n\nThe following example defines two
+ networks with different endpoints association methods.\nFor
+ `network1` all endpoints that their IP belongs to the provided
+ CIDR range will be\nmapped to network1. The gateway for
+ this network example is specified by its public IP\naddress
+ and port.\nThe second network, `network2`, in this example
+ is defined differently with all endpoints\nretrieved through
+ the specified Multi-Cluster registry being mapped to network2.
+ The\ngateway is also defined differently with the name of
+ the gateway service on the remote\ncluster. The public IP
+ for the gateway will be determined from that remote service
+ (only\nLoadBalancer gateway service type is currently supported,
+ for a NodePort type gateway service,\nit still need to be
+ configured manually).\n\nmeshNetworks:\n\n\tnetwork1:\n\t
+ \ endpoints:\n\t - fromCidr: \"192.168.0.1/24\"\n\t gateways:\n\t
+ \ - address: 1.1.1.1\n\t port: 80\n\tnetwork2:\n\t endpoints:\n\t
+ \ - fromRegistry: reg1\n\t gateways:\n\t - registryServiceName:
+ istio-ingressgateway.istio-system.svc.cluster.local\n\t
+ \ port: 443"
+ type: object
+ mountMtlsCerts:
+ description: Controls whether the in-cluster MTLS key and
+ certs are loaded from the secret volume mounts.
+ type: boolean
+ multiCluster:
+ description: Specifies the Configuration for Istio mesh across
+ multiple clusters through Istio gateways.
+ properties:
+ clusterName:
+ description: |-
+ The name of the cluster this installation will run in. This is required for sidecar injection
+ to properly label proxies
+ type: string
+ enabled:
+ description: |-
+ Enables the connection between two kubernetes clusters via their respective ingressgateway services.
+ Use if the pods in each cluster cannot directly talk to one another.
+ type: boolean
+ globalDomainSuffix:
+ description: The suffix for global service names.
+ type: string
+ includeEnvoyFilter:
+ description: Enable envoy filter to translate `globalDomainSuffix`
+ to cluster local suffix for cross cluster communication.
+ type: boolean
+ type: object
+ nativeNftables:
+ description: Specifies whether native nftables rules should
+ be used instead of iptables rules for traffic redirection.
+ type: boolean
+ network:
+ description: |-
+ Network defines the network this cluster belong to. This name
+ corresponds to the networks in the map of mesh networks.
+ type: string
+ networkPolicy:
+ description: Settings related to Kubernetes NetworkPolicy.
+ properties:
+ enabled:
+ description: Controls whether default NetworkPolicy resources
+ will be created.
+ type: boolean
+ type: object
+ omitSidecarInjectorConfigMap:
+ description: |-
+ Controls whether the creation of the sidecar injector ConfigMap should be skipped.
+ Defaults to false. When set to true, the sidecar injector ConfigMap will not be created.
+ type: boolean
+ operatorManageWebhooks:
+ description: |-
+ Controls whether the WebhookConfiguration resource(s) should be created. The current behavior
+ of Istiod is to manage its own webhook configurations.
+ When this option is set to true, Istio Operator, instead of webhooks, manages the
+ webhook configurations. When this option is set as false, webhooks manage their
+ own webhook configurations.
+ type: boolean
+ pilotCertProvider:
+ description: |-
+ Configure the Pilot certificate provider.
+ Currently, four providers are supported: "kubernetes", "istiod", "custom" and "none".
+ type: string
+ platform:
+ description: |-
+ Platform in which Istio is deployed. Possible values are: "openshift" and "gcp"
+ An empty value means it is a vanilla Kubernetes distribution, therefore no special
+ treatment will be considered.
+ type: string
+ podDNSSearchNamespaces:
+ description: |-
+ Custom DNS config for the pod to resolve names of services in other
+ clusters. Use this to add additional search domains, and other settings.
+ see https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#dns-config
+ This does not apply to gateway pods as they typically need a different
+ set of DNS settings than the normal application pods (e.g. in multicluster scenarios).
+ items:
+ type: string
+ type: array
+ priorityClassName:
+ description: |-
+ Specifies the k8s priorityClassName for the istio control plane components.
+
+ See https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ type: string
+ proxy:
+ description: Specifies how proxies are configured within Istio.
+ properties:
+ autoInject:
+ description: Controls the 'policy' in the sidecar injector.
+ type: string
+ clusterDomain:
+ description: |-
+ Domain for the cluster, default: "cluster.local".
+
+ K8s allows this to be customized, see https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/
+ type: string
+ componentLogLevel:
+ description: |-
+ Per Component log level for proxy, applies to gateways and sidecars.
+
+ If a component level is not set, then the global "logLevel" will be used. If left empty, "misc:error" is used.
+ type: string
+ enableCoreDump:
+ description: |-
+ Enables core dumps for newly injected sidecars.
+
+ If set, newly injected sidecars will have core dumps enabled.
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ type: boolean
+ excludeIPRanges:
+ description: Lists the excluded IP ranges of Istio egress
+ traffic that the sidecar captures.
+ type: string
+ excludeInboundPorts:
+ description: Specifies the Istio ingress ports not to
+ capture.
+ type: string
+ excludeOutboundPorts:
+ description: A comma separated list of outbound ports
+ to be excluded from redirection to Envoy.
+ type: string
+ holdApplicationUntilProxyStarts:
+ description: |-
+ Controls if sidecar is injected at the front of the container list and blocks the start of the other containers until the proxy is ready
+
+ Deprecated: replaced by ProxyConfig setting which allows per-pod configuration of this behavior.
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ type: boolean
+ image:
+ description: |-
+ Image name or path for the proxy, default: "proxyv2".
+
+ If registry or tag are not specified, global.hub and global.tag are used.
+
+ Examples: my-proxy (uses global.hub/tag), docker.io/myrepo/my-proxy:v1.0.0
+ type: string
+ includeIPRanges:
+ description: |-
+ Lists the IP ranges of Istio egress traffic that the sidecar captures.
+
+ Example: "172.30.0.0/16,172.20.0.0/16"
+ This would only capture egress traffic on those two IP Ranges, all other outbound traffic would # be allowed by the sidecar."
+ type: string
+ includeInboundPorts:
+ description: |-
+ A comma separated list of inbound ports for which traffic is to be redirected to Envoy.
+ The wildcard character '*' can be used to configure redirection for all ports.
+ type: string
+ includeOutboundPorts:
+ description: A comma separated list of outbound ports
+ for which traffic is to be redirected to Envoy, regardless
+ of the destination IP.
+ type: string
+ lifecycle:
+ description: |-
+ The k8s lifecycle hooks definition (pod.spec.containers.lifecycle) for the proxy container.
+ More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks
+ properties:
+ postStart:
+ description: |-
+ PostStart is called immediately after a container is created. If the handler fails,
+ the container is terminated and restarted according to its restart policy.
+ Other management of the container blocks until the hook completes.
+ More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks
+ properties:
+ exec:
+ description: Exec specifies a command to execute
+ in the container.
+ properties:
+ command:
+ description: |-
+ Command is the command line to execute inside the container, the working directory for the
+ command is root ('/') in the container's filesystem. The command is simply exec'd, it is
+ not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use
+ a shell, you need to explicitly call out to that shell.
+ Exit status of 0 is treated as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ httpGet:
+ description: HTTPGet specifies an HTTP GET request
+ to perform.
+ properties:
+ host:
+ description: |-
+ Host name to connect to, defaults to the pod IP. You probably want to set
+ "Host" in httpHeaders instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the
+ request. HTTP allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom
+ header to be used in HTTP probes
+ properties:
+ name:
+ description: |-
+ The header field name.
+ This will be canonicalized upon output, so case-variant names will be understood as the same header.
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ Name or number of the port to access on the container.
+ Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: |-
+ Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ sleep:
+ description: Sleep represents a duration that
+ the container should sleep.
+ properties:
+ seconds:
+ description: Seconds is the number of seconds
+ to sleep.
+ format: int64
+ type: integer
+ required:
+ - seconds
+ type: object
+ tcpSocket:
+ description: |-
+ Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept
+ for backward compatibility. There is no validation of this field and
+ lifecycle hooks will fail at runtime when it is specified.
+ properties:
+ host:
+ description: 'Optional: Host name to connect
+ to, defaults to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ Number or name of the port to access on the container.
+ Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ type: object
+ preStop:
+ description: |-
+ PreStop is called immediately before a container is terminated due to an
+ API request or management event such as liveness/startup probe failure,
+ preemption, resource contention, etc. The handler is not called if the
+ container crashes or exits. The Pod's termination grace period countdown begins before the
+ PreStop hook is executed. Regardless of the outcome of the handler, the
+ container will eventually terminate within the Pod's termination grace
+ period (unless delayed by finalizers). Other management of the container blocks until the hook completes
+ or until the termination grace period is reached.
+ More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks
+ properties:
+ exec:
+ description: Exec specifies a command to execute
+ in the container.
+ properties:
+ command:
+ description: |-
+ Command is the command line to execute inside the container, the working directory for the
+ command is root ('/') in the container's filesystem. The command is simply exec'd, it is
+ not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use
+ a shell, you need to explicitly call out to that shell.
+ Exit status of 0 is treated as live/healthy and non-zero is unhealthy.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ httpGet:
+ description: HTTPGet specifies an HTTP GET request
+ to perform.
+ properties:
+ host:
+ description: |-
+ Host name to connect to, defaults to the pod IP. You probably want to set
+ "Host" in httpHeaders instead.
+ type: string
+ httpHeaders:
+ description: Custom headers to set in the
+ request. HTTP allows repeated headers.
+ items:
+ description: HTTPHeader describes a custom
+ header to be used in HTTP probes
+ properties:
+ name:
+ description: |-
+ The header field name.
+ This will be canonicalized upon output, so case-variant names will be understood as the same header.
+ type: string
+ value:
+ description: The header field value
+ type: string
+ required:
+ - name
+ - value
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ path:
+ description: Path to access on the HTTP server.
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ Name or number of the port to access on the container.
+ Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ scheme:
+ description: |-
+ Scheme to use for connecting to the host.
+ Defaults to HTTP.
+ type: string
+ required:
+ - port
+ type: object
+ sleep:
+ description: Sleep represents a duration that
+ the container should sleep.
+ properties:
+ seconds:
+ description: Seconds is the number of seconds
+ to sleep.
+ format: int64
+ type: integer
+ required:
+ - seconds
+ type: object
+ tcpSocket:
+ description: |-
+ Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept
+ for backward compatibility. There is no validation of this field and
+ lifecycle hooks will fail at runtime when it is specified.
+ properties:
+ host:
+ description: 'Optional: Host name to connect
+ to, defaults to the pod IP.'
+ type: string
+ port:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ Number or name of the port to access on the container.
+ Number must be in the range 1 to 65535.
+ Name must be an IANA_SVC_NAME.
+ x-kubernetes-int-or-string: true
+ required:
+ - port
+ type: object
+ type: object
+ stopSignal:
+ description: |-
+ StopSignal defines which signal will be sent to a container when it is being stopped.
+ If not specified, the default is defined by the container runtime in use.
+ StopSignal can only be set for Pods with a non-empty .spec.os.name
+ type: string
+ type: object
+ logLevel:
+ description: 'Log level for proxy, applies to gateways
+ and sidecars. If left empty, "warning" is used. Expected
+ values are: trace\|debug\|info\|warning\|error\|critical\|off'
+ type: string
+ outlierLogPath:
+ description: |-
+ Path to the file to which the proxy will write outlier detection logs.
+
+ Example: "/dev/stdout"
+ This would write the logs to standard output.
+ type: string
+ privileged:
+ description: |-
+ Enables privileged securityContext for the istio-proxy container.
+
+ See https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
+ type: boolean
+ readinessFailureThreshold:
+ description: Sets the number of successive failed probes
+ before indicating readiness failure.
+ format: int32
+ type: integer
+ readinessInitialDelaySeconds:
+ description: Sets the initial delay for readiness probes
+ in seconds.
+ format: int32
+ type: integer
+ readinessPeriodSeconds:
+ description: Sets the interval between readiness probes
+ in seconds.
+ format: int32
+ type: integer
+ resources:
+ description: |-
+ K8s resources settings.
+
+ See https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ properties:
+ claims:
+ description: |-
+ Claims lists the names of resources, defined in spec.resourceClaims,
+ that are used by this container.
+
+ This field depends on the
+ DynamicResourceAllocation feature gate.
+
+ This field is immutable. It can only be set for containers.
+ items:
+ description: ResourceClaim references one entry
+ in PodSpec.ResourceClaims.
+ properties:
+ name:
+ description: |-
+ Name must match the name of one entry in pod.spec.resourceClaims of
+ the Pod where this field is used. It makes that resource available
+ inside a container.
+ type: string
+ request:
+ description: |-
+ Request is the name chosen for a request in the referenced claim.
+ If empty, everything from the claim is made available, otherwise
+ only the result of this request.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - name
+ x-kubernetes-list-type: map
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Limits describes the maximum amount of compute resources allowed.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Requests describes the minimum amount of compute resources required.
+ If Requests is omitted for a container, it defaults to Limits if that is explicitly specified,
+ otherwise to an implementation-defined value. Requests cannot exceed Limits.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ type: object
+ seccompProfile:
+ description: |-
+ Configures the seccomp profile for the istio-validation and istio-proxy containers.
+
+ See: https://kubernetes.io/docs/tutorials/security/seccomp/
+ properties:
+ localhostProfile:
+ description: |-
+ localhostProfile indicates a profile defined in a file on the node should be used.
+ The profile must be preconfigured on the node to work.
+ Must be a descending path, relative to the kubelet's configured seccomp profile location.
+ Must be set if type is "Localhost". Must NOT be set for any other type.
+ type: string
+ type:
+ description: |-
+ type indicates which kind of seccomp profile will be applied.
+ Valid options are:
+
+ Localhost - a profile defined in a file on the node should be used.
+ RuntimeDefault - the container runtime default profile should be used.
+ Unconfined - no profile should be applied.
+ type: string
+ required:
+ - type
+ type: object
+ startupProbe:
+ description: Configures the startup probe for the istio-proxy
+ container.
+ properties:
+ enabled:
+ description: |-
+ Enables or disables a startup probe.
+ For optimal startup times, changing this should be tied to the readiness probe values.
+
+ If the probe is enabled, it is recommended to have delay=0s,period=15s,failureThreshold=4.
+ This ensures the pod is marked ready immediately after the startup probe passes (which has a 1s poll interval),
+ and doesn't spam the readiness endpoint too much
+
+ If the probe is disabled, it is recommended to have delay=1s,period=2s,failureThreshold=30.
+ This ensures the startup is reasonable fast (polling every 2s). 1s delay is used since the startup is not often ready instantly.
+ type: boolean
+ failureThreshold:
+ description: Minimum consecutive failures for the
+ probe to be considered failed after having succeeded.
+ format: int32
+ type: integer
+ type: object
+ statusPort:
+ description: Default port used for the Pilot agent's health
+ checks.
+ format: int32
+ type: integer
+ tracer:
+ description: |-
+ Specify which tracer to use. One of: zipkin, lightstep, datadog, stackdriver.
+ If using stackdriver tracer outside GCP, set env GOOGLE_APPLICATION_CREDENTIALS to the GCP credential file.
+ enum:
+ - zipkin
+ - lightstep
+ - datadog
+ - stackdriver
+ - openCensusAgent
+ - none
+ type: string
+ type: object
+ proxy_init:
+ description: Specifies the Configuration for proxy_init container
+ which sets the pods' networking to intercept the inbound/outbound
+ traffic.
+ properties:
+ image:
+ description: Specifies the image for the proxy_init container.
+ type: string
+ resources:
+ description: |-
+ K8s resources settings.
+
+ See https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ properties:
+ claims:
+ description: |-
+ Claims lists the names of resources, defined in spec.resourceClaims,
+ that are used by this container.
+
+ This field depends on the
+ DynamicResourceAllocation feature gate.
+
+ This field is immutable. It can only be set for containers.
+ items:
+ description: ResourceClaim references one entry
+ in PodSpec.ResourceClaims.
+ properties:
+ name:
+ description: |-
+ Name must match the name of one entry in pod.spec.resourceClaims of
+ the Pod where this field is used. It makes that resource available
+ inside a container.
+ type: string
+ request:
+ description: |-
+ Request is the name chosen for a request in the referenced claim.
+ If empty, everything from the claim is made available, otherwise
+ only the result of this request.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - name
+ x-kubernetes-list-type: map
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Limits describes the maximum amount of compute resources allowed.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Requests describes the minimum amount of compute resources required.
+ If Requests is omitted for a container, it defaults to Limits if that is explicitly specified,
+ otherwise to an implementation-defined value. Requests cannot exceed Limits.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ type: object
+ type: object
+ remotePilotAddress:
+ description: Specifies the Istio control plane’s pilot Pod
+ IP address or remote cluster DNS resolvable hostname.
+ type: string
+ resourceScope:
+ description: |-
+ Specifies resource scope for discovery selectors.
+ This is useful when installing Istio on a cluster where some resources need to be owned by a cluster administrator and some can be owned by the mesh administrator.
+ enum:
+ - undefined
+ - all
+ - cluster
+ - namespace
+ type: string
+ revision:
+ description: Configures the revision this control plane is
+ a part of
+ type: string
+ sds:
+ description: Specifies the Configuration for the SecretDiscoveryService
+ instead of using K8S secrets to mount the certificates.
+ properties:
+ token:
+ description: 'Deprecated: Marked as deprecated in pkg/apis/values_types.proto.'
+ properties:
+ aud:
+ type: string
+ type: object
+ type: object
+ sts:
+ description: Specifies the configuration for Security Token
+ Service.
+ properties:
+ servicePort:
+ format: int32
+ type: integer
+ type: object
+ tag:
+ description: Specifies the tag for the Istio docker images.
+ type: string
+ tracer:
+ description: Specifies the Configuration for each of the supported
+ tracers.
+ properties:
+ datadog:
+ description: Configuration for the datadog tracing service.
+ properties:
+ address:
+ description: Address in host:port format for reporting
+ trace data to the Datadog agent.
+ type: string
+ type: object
+ lightstep:
+ description: Configuration for the lightstep tracing service.
+ properties:
+ accessToken:
+ description: Sets the lightstep access token.
+ type: string
+ address:
+ description: Sets the lightstep satellite pool address
+ in host:port format for reporting trace data.
+ type: string
+ type: object
+ stackdriver:
+ description: Configuration for the stackdriver tracing
+ service.
+ properties:
+ debug:
+ description: enables trace output to stdout.
+ type: boolean
+ maxNumberOfAnnotations:
+ description: The global default max number of annotation
+ events per span.
+ format: int32
+ type: integer
+ maxNumberOfAttributes:
+ description: The global default max number of attributes
+ per span.
+ format: int32
+ type: integer
+ maxNumberOfMessageEvents:
+ description: The global default max number of message
+ events per span.
+ format: int32
+ type: integer
+ type: object
+ zipkin:
+ description: Configuration for the zipkin tracing service.
+ properties:
+ address:
+ description: |-
+ Address of zipkin instance in host:port format for reporting trace data.
+
+ Example: .:941
+ type: string
+ type: object
+ type: object
+ trustBundleName:
+ description: Select a custom name for istiod's CA Root Cert
+ ConfigMap.
+ type: string
+ variant:
+ description: The variant of the Istio container images to
+ use. Options are "debug" or "distroless". Unset will use
+ the default for the given version.
+ type: string
+ waypoint:
+ description: Specifies how waypoints are configured within
+ Istio.
+ properties:
+ affinity:
+ description: |-
+ K8s affinity settings for waypoint pods.
+
+ See https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity
+ properties:
+ nodeAffinity:
+ description: Describes node affinity scheduling rules
+ for the pod.
+ properties:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ The scheduler will prefer to schedule pods to nodes that satisfy
+ the affinity expressions specified by this field, but it may choose
+ a node that violates one or more of the expressions. The node that is
+ most preferred is the one with the greatest sum of weights, i.e.
+ for each node that meets all of the scheduling requirements (resource
+ request, requiredDuringScheduling affinity expressions, etc.),
+ compute a sum by iterating through the elements of this field and adding
+ "weight" to the sum if the node matches the corresponding matchExpressions; the
+ node(s) with the highest sum are the most preferred.
+ items:
+ description: |-
+ An empty preferred scheduling term matches all objects with implicit weight 0
+ (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op).
+ properties:
+ preference:
+ description: A node selector term, associated
+ with the corresponding weight.
+ properties:
+ matchExpressions:
+ description: A list of node selector
+ requirements by node's labels.
+ items:
+ description: |-
+ A node selector requirement is a selector that contains values, a key, and an operator
+ that relates the key and values.
+ properties:
+ key:
+ description: The label key that
+ the selector applies to.
+ type: string
+ operator:
+ description: |-
+ Represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
+ type: string
+ values:
+ description: |-
+ An array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. If the operator is Gt or Lt, the values
+ array must have a single element, which will be interpreted as an integer.
+ This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchFields:
+ description: A list of node selector
+ requirements by node's fields.
+ items:
+ description: |-
+ A node selector requirement is a selector that contains values, a key, and an operator
+ that relates the key and values.
+ properties:
+ key:
+ description: The label key that
+ the selector applies to.
+ type: string
+ operator:
+ description: |-
+ Represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
+ type: string
+ values:
+ description: |-
+ An array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. If the operator is Gt or Lt, the values
+ array must have a single element, which will be interpreted as an integer.
+ This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ x-kubernetes-map-type: atomic
+ weight:
+ description: Weight associated with matching
+ the corresponding nodeSelectorTerm, in
+ the range 1-100.
+ format: int32
+ type: integer
+ required:
+ - preference
+ - weight
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ requiredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ If the affinity requirements specified by this field are not met at
+ scheduling time, the pod will not be scheduled onto the node.
+ If the affinity requirements specified by this field cease to be met
+ at some point during pod execution (e.g. due to an update), the system
+ may or may not try to eventually evict the pod from its node.
+ properties:
+ nodeSelectorTerms:
+ description: Required. A list of node selector
+ terms. The terms are ORed.
+ items:
+ description: |-
+ A null or empty node selector term matches no objects. The requirements of
+ them are ANDed.
+ The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.
+ properties:
+ matchExpressions:
+ description: A list of node selector
+ requirements by node's labels.
+ items:
+ description: |-
+ A node selector requirement is a selector that contains values, a key, and an operator
+ that relates the key and values.
+ properties:
+ key:
+ description: The label key that
+ the selector applies to.
+ type: string
+ operator:
+ description: |-
+ Represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
+ type: string
+ values:
+ description: |-
+ An array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. If the operator is Gt or Lt, the values
+ array must have a single element, which will be interpreted as an integer.
+ This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchFields:
+ description: A list of node selector
+ requirements by node's fields.
+ items:
+ description: |-
+ A node selector requirement is a selector that contains values, a key, and an operator
+ that relates the key and values.
+ properties:
+ key:
+ description: The label key that
+ the selector applies to.
+ type: string
+ operator:
+ description: |-
+ Represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
+ type: string
+ values:
+ description: |-
+ An array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. If the operator is Gt or Lt, the values
+ array must have a single element, which will be interpreted as an integer.
+ This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ x-kubernetes-map-type: atomic
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - nodeSelectorTerms
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ podAffinity:
+ description: Describes pod affinity scheduling rules
+ (e.g. co-locate this pod in the same node, zone,
+ etc. as some other pod(s)).
+ properties:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ The scheduler will prefer to schedule pods to nodes that satisfy
+ the affinity expressions specified by this field, but it may choose
+ a node that violates one or more of the expressions. The node that is
+ most preferred is the one with the greatest sum of weights, i.e.
+ for each node that meets all of the scheduling requirements (resource
+ request, requiredDuringScheduling affinity expressions, etc.),
+ compute a sum by iterating through the elements of this field and adding
+ "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the
+ node(s) with the highest sum are the most preferred.
+ items:
+ description: The weights of all of the matched
+ WeightedPodAffinityTerm fields are added per-node
+ to find the most preferred node(s)
+ properties:
+ podAffinityTerm:
+ description: Required. A pod affinity term,
+ associated with the corresponding weight.
+ properties:
+ labelSelector:
+ description: |-
+ A label query over a set of resources, in this case pods.
+ If it's null, this PodAffinityTerm matches with no Pods.
+ properties:
+ matchExpressions:
+ description: matchExpressions is
+ a list of label selector requirements.
+ The requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ matchLabelKeys:
+ description: |-
+ MatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both matchLabelKeys and labelSelector.
+ Also, matchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ mismatchLabelKeys:
+ description: |-
+ MismatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
+ Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ namespaceSelector:
+ description: |-
+ A label query over the set of namespaces that the term applies to.
+ The term is applied to the union of the namespaces selected by this field
+ and the ones listed in the namespaces field.
+ null selector and null or empty namespaces list means "this pod's namespace".
+ An empty selector ({}) matches all namespaces.
+ properties:
+ matchExpressions:
+ description: matchExpressions is
+ a list of label selector requirements.
+ The requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: |-
+ namespaces specifies a static list of namespace names that the term applies to.
+ The term is applied to the union of the namespaces listed in this field
+ and the ones selected by namespaceSelector.
+ null or empty namespaces list and null namespaceSelector means "this pod's namespace".
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ topologyKey:
+ description: |-
+ This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
+ the labelSelector in the specified namespaces, where co-located is defined as running on a node
+ whose value of the label with key topologyKey matches that of any node on which any of the
+ selected pods is running.
+ Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ weight:
+ description: |-
+ weight associated with matching the corresponding podAffinityTerm,
+ in the range 1-100.
+ format: int32
+ type: integer
+ required:
+ - podAffinityTerm
+ - weight
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ requiredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ If the affinity requirements specified by this field are not met at
+ scheduling time, the pod will not be scheduled onto the node.
+ If the affinity requirements specified by this field cease to be met
+ at some point during pod execution (e.g. due to a pod label update), the
+ system may or may not try to eventually evict the pod from its node.
+ When there are multiple elements, the lists of nodes corresponding to each
+ podAffinityTerm are intersected, i.e. all terms must be satisfied.
+ items:
+ description: |-
+ Defines a set of pods (namely those matching the labelSelector
+ relative to the given namespace(s)) that this pod should be
+ co-located (affinity) or not co-located (anti-affinity) with,
+ where co-located is defined as running on a node whose value of
+ the label with key matches that of any node on which
+ a pod of the set of pods is running
+ properties:
+ labelSelector:
+ description: |-
+ A label query over a set of resources, in this case pods.
+ If it's null, this PodAffinityTerm matches with no Pods.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The
+ requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ matchLabelKeys:
+ description: |-
+ MatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both matchLabelKeys and labelSelector.
+ Also, matchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ mismatchLabelKeys:
+ description: |-
+ MismatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
+ Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ namespaceSelector:
+ description: |-
+ A label query over the set of namespaces that the term applies to.
+ The term is applied to the union of the namespaces selected by this field
+ and the ones listed in the namespaces field.
+ null selector and null or empty namespaces list means "this pod's namespace".
+ An empty selector ({}) matches all namespaces.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The
+ requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: |-
+ namespaces specifies a static list of namespace names that the term applies to.
+ The term is applied to the union of the namespaces listed in this field
+ and the ones selected by namespaceSelector.
+ null or empty namespaces list and null namespaceSelector means "this pod's namespace".
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ topologyKey:
+ description: |-
+ This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
+ the labelSelector in the specified namespaces, where co-located is defined as running on a node
+ whose value of the label with key topologyKey matches that of any node on which any of the
+ selected pods is running.
+ Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ podAntiAffinity:
+ description: Describes pod anti-affinity scheduling
+ rules (e.g. avoid putting this pod in the same node,
+ zone, etc. as some other pod(s)).
+ properties:
+ preferredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ The scheduler will prefer to schedule pods to nodes that satisfy
+ the anti-affinity expressions specified by this field, but it may choose
+ a node that violates one or more of the expressions. The node that is
+ most preferred is the one with the greatest sum of weights, i.e.
+ for each node that meets all of the scheduling requirements (resource
+ request, requiredDuringScheduling anti-affinity expressions, etc.),
+ compute a sum by iterating through the elements of this field and subtracting
+ "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the
+ node(s) with the highest sum are the most preferred.
+ items:
+ description: The weights of all of the matched
+ WeightedPodAffinityTerm fields are added per-node
+ to find the most preferred node(s)
+ properties:
+ podAffinityTerm:
+ description: Required. A pod affinity term,
+ associated with the corresponding weight.
+ properties:
+ labelSelector:
+ description: |-
+ A label query over a set of resources, in this case pods.
+ If it's null, this PodAffinityTerm matches with no Pods.
+ properties:
+ matchExpressions:
+ description: matchExpressions is
+ a list of label selector requirements.
+ The requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ matchLabelKeys:
+ description: |-
+ MatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both matchLabelKeys and labelSelector.
+ Also, matchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ mismatchLabelKeys:
+ description: |-
+ MismatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
+ Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ namespaceSelector:
+ description: |-
+ A label query over the set of namespaces that the term applies to.
+ The term is applied to the union of the namespaces selected by this field
+ and the ones listed in the namespaces field.
+ null selector and null or empty namespaces list means "this pod's namespace".
+ An empty selector ({}) matches all namespaces.
+ properties:
+ matchExpressions:
+ description: matchExpressions is
+ a list of label selector requirements.
+ The requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: |-
+ namespaces specifies a static list of namespace names that the term applies to.
+ The term is applied to the union of the namespaces listed in this field
+ and the ones selected by namespaceSelector.
+ null or empty namespaces list and null namespaceSelector means "this pod's namespace".
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ topologyKey:
+ description: |-
+ This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
+ the labelSelector in the specified namespaces, where co-located is defined as running on a node
+ whose value of the label with key topologyKey matches that of any node on which any of the
+ selected pods is running.
+ Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ weight:
+ description: |-
+ weight associated with matching the corresponding podAffinityTerm,
+ in the range 1-100.
+ format: int32
+ type: integer
+ required:
+ - podAffinityTerm
+ - weight
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ requiredDuringSchedulingIgnoredDuringExecution:
+ description: |-
+ If the anti-affinity requirements specified by this field are not met at
+ scheduling time, the pod will not be scheduled onto the node.
+ If the anti-affinity requirements specified by this field cease to be met
+ at some point during pod execution (e.g. due to a pod label update), the
+ system may or may not try to eventually evict the pod from its node.
+ When there are multiple elements, the lists of nodes corresponding to each
+ podAffinityTerm are intersected, i.e. all terms must be satisfied.
+ items:
+ description: |-
+ Defines a set of pods (namely those matching the labelSelector
+ relative to the given namespace(s)) that this pod should be
+ co-located (affinity) or not co-located (anti-affinity) with,
+ where co-located is defined as running on a node whose value of
+ the label with key matches that of any node on which
+ a pod of the set of pods is running
+ properties:
+ labelSelector:
+ description: |-
+ A label query over a set of resources, in this case pods.
+ If it's null, this PodAffinityTerm matches with no Pods.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The
+ requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ matchLabelKeys:
+ description: |-
+ MatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both matchLabelKeys and labelSelector.
+ Also, matchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ mismatchLabelKeys:
+ description: |-
+ MismatchLabelKeys is a set of pod label keys to select which pods will
+ be taken into consideration. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`
+ to select the group of existing pods which pods will be taken into consideration
+ for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming
+ pod labels will be ignored. The default value is empty.
+ The same key is forbidden to exist in both mismatchLabelKeys and labelSelector.
+ Also, mismatchLabelKeys cannot be set when labelSelector isn't set.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ namespaceSelector:
+ description: |-
+ A label query over the set of namespaces that the term applies to.
+ The term is applied to the union of the namespaces selected by this field
+ and the ones listed in the namespaces field.
+ null selector and null or empty namespaces list means "this pod's namespace".
+ An empty selector ({}) matches all namespaces.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list
+ of label selector requirements. The
+ requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label
+ key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ namespaces:
+ description: |-
+ namespaces specifies a static list of namespace names that the term applies to.
+ The term is applied to the union of the namespaces listed in this field
+ and the ones selected by namespaceSelector.
+ null or empty namespaces list and null namespaceSelector means "this pod's namespace".
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ topologyKey:
+ description: |-
+ This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching
+ the labelSelector in the specified namespaces, where co-located is defined as running on a node
+ whose value of the label with key topologyKey matches that of any node on which any of the
+ selected pods is running.
+ Empty topologyKey is not allowed.
+ type: string
+ required:
+ - topologyKey
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ type: object
+ nodeSelector:
+ description: |-
+ K8s node labels settings.
+
+ See https://kubernetes.io/docs/user-guide/node-selection/
+ properties:
+ nodeSelectorTerms:
+ description: Required. A list of node selector terms.
+ The terms are ORed.
+ items:
+ description: |-
+ A null or empty node selector term matches no objects. The requirements of
+ them are ANDed.
+ The TopologySelectorTerm type implements a subset of the NodeSelectorTerm.
+ properties:
+ matchExpressions:
+ description: A list of node selector requirements
+ by node's labels.
+ items:
+ description: |-
+ A node selector requirement is a selector that contains values, a key, and an operator
+ that relates the key and values.
+ properties:
+ key:
+ description: The label key that the selector
+ applies to.
+ type: string
+ operator:
+ description: |-
+ Represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
+ type: string
+ values:
+ description: |-
+ An array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. If the operator is Gt or Lt, the values
+ array must have a single element, which will be interpreted as an integer.
+ This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchFields:
+ description: A list of node selector requirements
+ by node's fields.
+ items:
+ description: |-
+ A node selector requirement is a selector that contains values, a key, and an operator
+ that relates the key and values.
+ properties:
+ key:
+ description: The label key that the selector
+ applies to.
+ type: string
+ operator:
+ description: |-
+ Represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
+ type: string
+ values:
+ description: |-
+ An array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. If the operator is Gt or Lt, the values
+ array must have a single element, which will be interpreted as an integer.
+ This array is replaced during a strategic merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ type: object
+ x-kubernetes-map-type: atomic
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - nodeSelectorTerms
+ type: object
+ x-kubernetes-map-type: atomic
+ resources:
+ description: |-
+ K8s resource settings.
+
+ See https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container
+ properties:
+ claims:
+ description: |-
+ Claims lists the names of resources, defined in spec.resourceClaims,
+ that are used by this container.
+
+ This field depends on the
+ DynamicResourceAllocation feature gate.
+
+ This field is immutable. It can only be set for containers.
+ items:
+ description: ResourceClaim references one entry
+ in PodSpec.ResourceClaims.
+ properties:
+ name:
+ description: |-
+ Name must match the name of one entry in pod.spec.resourceClaims of
+ the Pod where this field is used. It makes that resource available
+ inside a container.
+ type: string
+ request:
+ description: |-
+ Request is the name chosen for a request in the referenced claim.
+ If empty, everything from the claim is made available, otherwise
+ only the result of this request.
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - name
+ x-kubernetes-list-type: map
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Limits describes the maximum amount of compute resources allowed.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: |-
+ Requests describes the minimum amount of compute resources required.
+ If Requests is omitted for a container, it defaults to Limits if that is explicitly specified,
+ otherwise to an implementation-defined value. Requests cannot exceed Limits.
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+ type: object
+ type: object
+ toleration:
+ description: |-
+ K8s tolerations settings.
+
+ See https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
+ items:
+ description: |-
+ The pod this Toleration is attached to tolerates any taint that matches
+ the triple using the matching operator .
+ properties:
+ effect:
+ description: |-
+ Effect indicates the taint effect to match. Empty means match all taint effects.
+ When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.
+ type: string
+ key:
+ description: |-
+ Key is the taint key that the toleration applies to. Empty means match all taint keys.
+ If the key is empty, operator must be Exists; this combination means to match all values and all keys.
+ type: string
+ operator:
+ description: |-
+ Operator represents a key's relationship to the value.
+ Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal.
+ Exists is equivalent to wildcard for value, so that a pod can
+ tolerate all taints of a particular category.
+ Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators).
+ type: string
+ tolerationSeconds:
+ description: |-
+ TolerationSeconds represents the period of time the toleration (which must be
+ of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default,
+ it is not set, which means tolerate the taint forever (do not evict). Zero and
+ negative values will be treated as 0 (evict immediately) by the system.
+ format: int64
+ type: integer
+ value:
+ description: |-
+ Value is the taint value the toleration matches to.
+ If the operator is Exists, the value should be empty, otherwise just a regular string.
+ type: string
+ type: object
+ type: array
+ topologySpreadConstraints:
+ description: |-
+ K8s topology spread constraints settings.
+
+ See https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/
+ items:
+ description: TopologySpreadConstraint specifies how
+ to spread matching pods among the given topology.
+ properties:
+ labelSelector:
+ description: |-
+ LabelSelector is used to find matching pods.
+ Pods that match this label selector are counted to determine the number of pods
+ in their corresponding topology domain.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label
+ selector requirements. The requirements are
+ ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label key that
+ the selector applies to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ matchLabelKeys:
+ description: |-
+ MatchLabelKeys is a set of pod label keys to select the pods over which
+ spreading will be calculated. The keys are used to lookup values from the
+ incoming pod labels, those key-value labels are ANDed with labelSelector
+ to select the group of existing pods over which spreading will be calculated
+ for the incoming pod. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector.
+ MatchLabelKeys cannot be set when LabelSelector isn't set.
+ Keys that don't exist in the incoming pod labels will
+ be ignored. A null or empty list means only match against labelSelector.
+
+ This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default).
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ maxSkew:
+ description: |-
+ MaxSkew describes the degree to which pods may be unevenly distributed.
+ When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference
+ between the number of matching pods in the target topology and the global minimum.
+ The global minimum is the minimum number of matching pods in an eligible domain
+ or zero if the number of eligible domains is less than MinDomains.
+ For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same
+ labelSelector spread as 2/2/1:
+ In this case, the global minimum is 1.
+ | zone1 | zone2 | zone3 |
+ | P P | P P | P |
+ - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2;
+ scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2)
+ violate MaxSkew(1).
+ - if MaxSkew is 2, incoming pod can be scheduled onto any zone.
+ When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence
+ to topologies that satisfy it.
+ It's a required field. Default value is 1 and 0 is not allowed.
+ format: int32
+ type: integer
+ minDomains:
+ description: |-
+ MinDomains indicates a minimum number of eligible domains.
+ When the number of eligible domains with matching topology keys is less than minDomains,
+ Pod Topology Spread treats "global minimum" as 0, and then the calculation of Skew is performed.
+ And when the number of eligible domains with matching topology keys equals or greater than minDomains,
+ this value has no effect on scheduling.
+ As a result, when the number of eligible domains is less than minDomains,
+ scheduler won't schedule more than maxSkew Pods to those domains.
+ If value is nil, the constraint behaves as if MinDomains is equal to 1.
+ Valid values are integers greater than 0.
+ When value is not nil, WhenUnsatisfiable must be DoNotSchedule.
+
+ For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same
+ labelSelector spread as 2/2/2:
+ | zone1 | zone2 | zone3 |
+ | P P | P P | P P |
+ The number of domains is less than 5(MinDomains), so "global minimum" is treated as 0.
+ In this situation, new pod with the same labelSelector cannot be scheduled,
+ because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones,
+ it will violate MaxSkew.
+ format: int32
+ type: integer
+ nodeAffinityPolicy:
+ description: |-
+ NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector
+ when calculating pod topology spread skew. Options are:
+ - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations.
+ - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations.
+
+ If this value is nil, the behavior is equivalent to the Honor policy.
+ type: string
+ nodeTaintsPolicy:
+ description: |-
+ NodeTaintsPolicy indicates how we will treat node taints when calculating
+ pod topology spread skew. Options are:
+ - Honor: nodes without taints, along with tainted nodes for which the incoming pod
+ has a toleration, are included.
+ - Ignore: node taints are ignored. All nodes are included.
+
+ If this value is nil, the behavior is equivalent to the Ignore policy.
+ type: string
+ topologyKey:
+ description: |-
+ TopologyKey is the key of node labels. Nodes that have a label with this key
+ and identical values are considered to be in the same topology.
+ We consider each as a "bucket", and try to put balanced number
+ of pods into each bucket.
+ We define a domain as a particular instance of a topology.
+ Also, we define an eligible domain as a domain whose nodes meet the requirements of
+ nodeAffinityPolicy and nodeTaintsPolicy.
+ e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology.
+ And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology.
+ It's a required field.
+ type: string
+ whenUnsatisfiable:
+ description: |-
+ WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy
+ the spread constraint.
+ - DoNotSchedule (default) tells the scheduler not to schedule it.
+ - ScheduleAnyway tells the scheduler to schedule the pod in any location,
+ but giving higher precedence to topologies that would help reduce the
+ skew.
+ A constraint is considered "Unsatisfiable" for an incoming pod
+ if and only if every possible node assignment for that pod would violate
+ "MaxSkew" on some topology.
+ For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same
+ labelSelector spread as 3/1/1:
+ | zone1 | zone2 | zone3 |
+ | P P P | P | P |
+ If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled
+ to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies
+ MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler
+ won't make it *more* imbalanced.
+ It's a required field.
+ type: string
+ required:
+ - maxSkew
+ - topologyKey
+ - whenUnsatisfiable
+ type: object
+ type: array
+ type: object
+ type: object
+ istiodRemote:
+ description: |-
+ Configuration for istiod-remote.
+ DEPRECATED - istiod-remote chart is removed and replaced with
+ `istio-discovery --set values.istiodRemote.enabled=true`
+
+ Deprecated: Marked as deprecated in pkg/apis/values_types.proto.
+ properties:
+ enabled:
+ description: Indicates if this cluster/install should consume
+ a "remote" istiod instance,
+ type: boolean
+ enabledLocalInjectorIstiod:
+ description: |-
+ If `true`, indicates that this cluster/install should consume a "local istiod" installation,
+ local istiod inject sidecars
+ type: boolean
+ injectionCABundle:
+ description: injector ca bundle
+ type: string
+ injectionPath:
+ description: Path to use for the sidecar injector webhook
+ service.
+ type: string
+ injectionURL:
+ description: URL to use for sidecar injector webhook.
+ type: string
+ type: object
+ meshConfig:
+ description: |-
+ Defines runtime configuration of components, including Istiod and istio-agent behavior.
+ See https://istio.io/docs/reference/config/istio.mesh.v1alpha1/ for all available options.
+ properties:
+ accessLogEncoding:
+ description: |-
+ Encoding for the proxy access log (`TEXT` or `JSON`).
+ Default value is `TEXT`.
+ enum:
+ - TEXT
+ - JSON
+ type: string
+ accessLogFile:
+ description: |-
+ File address for the proxy access log (e.g. /dev/stdout).
+ Empty value disables access logging.
+ type: string
+ accessLogFormat:
+ description: |-
+ Format for the proxy access log
+ Empty value results in proxy's default access log format
+ type: string
+ ca:
+ description: |-
+ If specified, Istiod will authorize and forward the CSRs from the workloads to the specified external CA
+ using the Istio CA gRPC API.
+ properties:
+ address:
+ description: |-
+ REQUIRED. Address of the CA server implementing the Istio CA gRPC API.
+ Can be IP address or a fully qualified DNS name with port
+ Eg: custom-ca.default.svc.cluster.local:8932, 192.168.23.2:9000
+ type: string
+ istiodSide:
+ description: |-
+ Use istiodSide to specify CA Server integrate to Istiod side or Agent side
+ Default: true
+ type: boolean
+ requestTimeout:
+ description: |-
+ timeout for forward CSR requests from Istiod to External CA
+ Default: 10s
+ type: string
+ tlsSettings:
+ description: |-
+ Use the tlsSettings to specify the tls mode to use.
+ Regarding tlsSettings:
+ - DISABLE MODE is legitimate for the case Istiod is making the request via an Envoy sidecar.
+ DISABLE MODE can also be used for testing
+ - TLS MUTUAL MODE be on by default. If the CA certificates
+ (cert bundle to verify the CA server's certificate) is omitted, Istiod will
+ use the system root certs to verify the CA server's certificate.
+ properties:
+ caCertificates:
+ description: |-
+ OPTIONAL: The path to the file containing certificate authority
+ certificates to use in verifying a presented server certificate. If
+ omitted, the proxy will verify the server's certificate using
+ the OS CA certificates.
+ Should be empty if mode is `ISTIO_MUTUAL`.
+ type: string
+ caCrl:
+ description: |-
+ OPTIONAL: The path to the file containing the certificate revocation list (CRL)
+ to use in verifying a presented server certificate. `CRL` is a list of certificates
+ that have been revoked by the CA (Certificate Authority) before their scheduled expiration date.
+ If specified, the proxy will verify if the presented certificate is part of the revoked list of certificates.
+ If omitted, the proxy will not verify the certificate against the `crl`. Note that if `credentialName` is set,
+ `CRL` cannot be specified using `caCrl`, rather it has to be specified inside the credential.
+ type: string
+ clientCertificate:
+ description: |-
+ REQUIRED if mode is `MUTUAL`. The path to the file holding the
+ client-side TLS certificate to use.
+ Should be empty if mode is `ISTIO_MUTUAL`.
+ type: string
+ credentialName:
+ description: |-
+ The name of the secret that holds the TLS certs for the
+ client including the CA certificates. This secret must exist in
+ the namespace of the proxy using the certificates.
+ An Opaque secret should contain the following keys and values:
+ `key: `, `cert: `, `cacert: `,
+ `crl: `
+ Here CACertificate is used to verify the server certificate.
+ For mutual TLS, `cacert: ` can be provided in the
+ same secret or a separate secret named `