Compare commits

..

17 Commits

Author SHA1 Message Date
Kubernetes Publisher
569d08962b Fix Godeps.json to point to kubernetes-1.10.12 tags 2018-12-19 15:27:58 +00:00
Kubernetes Publisher
16a8a034ed Merge pull request #71334 from cheftako/automated-cherry-pick-of-#71325-upstream-release-1.10
Automated cherry pick of #70753, #70676 and #70971 upstream release 1.10

Kubernetes-commit: 15008f083eac370234b015cc66f66a00e2303947
2018-12-13 03:04:09 +00:00
Walter Fender
751eb6abb5 Report KCM as unhealthy if leader election is wedged. Feedback from lavalamp and deads2k. Changed Check() logic to be central to LeaderElector. Further changes, especially cleaning up the test code.
Kubernetes-commit: 393fa065155a5d12f6e4a212cb66a46e8dbee2c3
2018-11-12 18:45:21 -08:00
Kubernetes Publisher
745ca83003 Merge pull request #67393 from nikhita/automated-cherry-pick-of-#66249-upstream-release-1.10
Automatic merge from submit-queue.

Automated cherry pick of #66249: fill in normal restmapping info with the legacy guess

Fixes 1.10 part of https://github.com/kubernetes/kubernetes/issues/67235

Cherry pick of #66249 on release-1.10.

#66249: fill in normal restmapping info with the legacy guess

```release-note
Fix creation of custom resources when the CRD contains non-conventional pluralization and subresources
```

Kubernetes-commit: b16193f435cefa70de14823738a2c5af3d99b7ca
2018-08-17 17:43:22 +00:00
Kubernetes Publisher
56edb76093 Merge pull request #67163 from dekkagaijin/automated-cherry-pick-of-#65799-upstream-release-1.10
Automatic merge from submit-queue.

Automated cherry pick of #65799: Escape illegal characters in remote extra keys

Cherry pick of #65799 on release-1.10.

#65799: Escape illegal characters in remote extra keys

Kubernetes-commit: c79ade8468953f95011c0d565454119f8356ce2d
2018-08-16 13:47:51 +00:00
David Eads
a9a2ba84e6 fill in normal restmapping info with the legacy guess
Kubernetes-commit: 5a757b07887a6f84acfe82e090d3ec757ee51989
2018-07-16 13:38:43 -04:00
Jake Sanders
fa6525815c Escape illegal characters in remote extra keys
Signed-off-by: Jake Sanders <jsand@google.com>

Kubernetes-commit: 3d5d7ef5b22837103e17fb57795aeafaee882058
2018-07-03 21:19:15 -07:00
Kubernetes Publisher
a312bfe35c Merge pull request #65157 from caesarxuchao/cherrypick-65034-1.10
Automatic merge from submit-queue.

Manually cherrypick #65034 to 1.10

Manually cherrypicking #65034. Using hack/cherry_pick_pull.sh to cherrypick is difficult because that requires cherrypicking #63059 first.

This PR imported the latest jsoniterator library so that case sensitivity during unmarhsaling is optional. The PR also set Kubernetes json serializer to be case sensitive.

Fix #64612.

```release-notes
Kubernetes json deserializer is now case-sensitive to restore compatibility with pre-1.8 servers.
If your config files contains fields with wrong case, the config files will be now invalid.
```

Kubernetes-commit: 32ac1c9073b132b8ba18aa830f46b77dcceb0723
2018-06-19 23:27:44 +00:00
Chao Xu
805e310466 use the latest json-iter
Kubernetes-commit: 0bf82f28ff092cd2a2efea324a139b4a1bd9f436
2018-06-15 10:46:42 -07:00
Kubernetes Publisher
26a26f55b2 Merge pull request #63448 from dims/automated-cherry-pick-of-#62505-upstream-release-1.10
Automatic merge from submit-queue.

Automated cherry pick of #62505: update godeps to use latest pflag

Cherry pick of #62505 on release-1.10.

#62505: update godeps to use latest pflag

```release-note
Show help for deprecated Kubelet flags
```

Kubernetes-commit: 8959a0aa87adf07c4ff821bf6d79714b3d615e8a
2018-06-01 18:43:21 +00:00
Kubernetes Publisher
0be17c78bf Merge pull request #63627 from roycaihw/release-1.10
Automatic merge from submit-queue.

Manual cherrypick of kube-openapi changes for release-1.10

**What this PR does / why we need it**:
Cherry-picks kubernetes/kube-openapi#64 and kubernetes/kube-openapi#67
Fixes bugs that make apiserver panic when aggregating valid but not well formed OpenAPI spec (with empty `Paths`/`Definitions`)

**Release note**:

```release-note
Fixes bugs that make apiserver panic when aggregating valid but not well formed OpenAPI spec
```

/cc @MaciekPytel
/sig api-machinery

Kubernetes-commit: 42b63c8b19d1ad96399ec3f5a409da67e2fd19bd
2018-05-15 18:50:12 +00:00
Haowei Cai
1d79704297 generated
Kubernetes-commit: 56d903a426f6cdaf420a507f0c36d45058a5bcc0
2018-05-09 14:46:14 -07:00
Kubernetes Publisher
33f2870a2b Merge pull request #62654 from liggitt/automated-cherry-pick-of-#62649-upstream-release-1.10
Automatic merge from submit-queue.

Automated cherry pick of #62649: Ensure service routing resolves kubernetes.default.svc

Cherry pick of #62649 on release-1.10.

#62649: Ensure service routing resolves kubernetes.default.svc

Kubernetes-commit: 5f050faa9d28b3013a11344682038cae26059cdd
2018-04-24 14:15:16 -07:00
Kubernetes Publisher
27ca8df003 sync: update godeps 2018-04-17 14:44:47 +00:00
Jordan Liggitt
262ea94a59 ensure tls server name is used in transport
Kubernetes-commit: 22cc5683fd1b9e24f90a36a937f53a54c1730cff
2018-04-17 00:59:27 -04:00
Jordan Liggitt
345769d958 distinguish custom dialers in transport cache
Kubernetes-commit: 5b02bce088255a9b8705e3b775487cddfc6f7b9d
2018-04-17 00:58:56 -04:00
Michael Taufen
ac76ac5060 update godeps to use latest pflag
Kubernetes-commit: a58a84cfc006401910396b049b410cfb80676169
2018-04-12 17:12:43 -07:00
12 changed files with 634 additions and 109 deletions

180
Godeps/Godeps.json generated
View File

@@ -1,7 +1,7 @@
{
"ImportPath": "k8s.io/client-go",
"GoVersion": "go1.9",
"GodepVersion": "v79",
"GodepVersion": "v80",
"Packages": [
"./..."
],
@@ -148,7 +148,15 @@
},
{
"ImportPath": "github.com/json-iterator/go",
"Rev": "13f86432b882000a51c6e610c620974462691a97"
"Rev": "f2b4162afba35581b6d4a50d3b8f34e33c144682"
},
{
"ImportPath": "github.com/modern-go/concurrent",
"Rev": "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94"
},
{
"ImportPath": "github.com/modern-go/reflect2",
"Rev": "05fbef0ca5da472bbf96c9322b84a53edc03c9fd"
},
{
"ImportPath": "github.com/pmezard/go-difflib/difflib",
@@ -156,7 +164,7 @@
},
{
"ImportPath": "github.com/spf13/pflag",
"Rev": "4c012f6dcd9546820e378d0bdda4d8fc772cdfea"
"Rev": "583c0c0531f06d5278b7d917446061adc344b5cd"
},
{
"ImportPath": "github.com/stretchr/testify/assert",
@@ -248,335 +256,335 @@
},
{
"ImportPath": "k8s.io/api/admissionregistration/v1alpha1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/admissionregistration/v1beta1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/apps/v1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/apps/v1beta1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/apps/v1beta2",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/authentication/v1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/authentication/v1beta1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/authorization/v1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/authorization/v1beta1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/autoscaling/v1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/autoscaling/v2beta1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/batch/v1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/batch/v1beta1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/batch/v2alpha1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/certificates/v1beta1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/core/v1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/events/v1beta1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/extensions/v1beta1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/imagepolicy/v1alpha1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/networking/v1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/policy/v1beta1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/rbac/v1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/rbac/v1alpha1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/rbac/v1beta1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/scheduling/v1alpha1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/settings/v1alpha1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/storage/v1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/storage/v1alpha1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/api/storage/v1beta1",
"Rev": "73d903622b7391f3312dcbac6483fed484e185f8"
"Rev": "38287c0991a57e8e741db42c0c4eca21386722b8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/equality",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/errors",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/meta",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/resource",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/testing",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/testing/fuzzer",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/testing/roundtrip",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apimachinery",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apimachinery/announced",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apimachinery/registered",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/fuzzer",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/internalversion",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1beta1",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/conversion",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/conversion/queryparams",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/fields",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/labels",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/schema",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/json",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/protobuf",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/recognizer",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/streaming",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/versioning",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/selection",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/types",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/cache",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/clock",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/diff",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/errors",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/framer",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/httpstream",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/httpstream/spdy",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/intstr",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/json",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/mergepatch",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/net",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/remotecommand",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/runtime",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/sets",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/strategicpatch",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/validation",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/validation/field",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/wait",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/yaml",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/version",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/watch",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/json",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/netutil",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/reflect",
"Rev": "302974c03f7e50f16561ba237db776ab93594ef6"
"Rev": "688d824527473e1e3f6c3f0b01171308393bdfe3"
},
{
"ImportPath": "k8s.io/kube-openapi/pkg/util/proto",
"Rev": "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
"Rev": "39cb288412c48cb533ba4be5d6c28620b9a0c1b4"
}
]
}

View File

@@ -98,18 +98,20 @@ func NewRESTMapper(groupResources []*APIGroupResources, versionInterfaces meta.V
scope = meta.RESTScopeRoot
}
// this is for legacy resources and servers which don't list singular forms. For those we must still guess.
if len(resource.SingularName) == 0 {
versionMapper.Add(gv.WithKind(resource.Kind), scope)
// TODO this is producing unsafe guesses that don't actually work, but it matches previous behavior
versionMapper.Add(gv.WithKind(resource.Kind+"List"), scope)
// if we have a slash, then this is a subresource and we shouldn't create mappings for those.
if strings.Contains(resource.Name, "/") {
continue
}
plural := gv.WithResource(resource.Name)
singular := gv.WithResource(resource.SingularName)
versionMapper.AddSpecific(gv.WithKind(resource.Kind), plural, singular, scope)
// this is for legacy resources and servers which don't list singular forms. For those we must still guess.
if len(resource.SingularName) == 0 {
_, singular = meta.UnsafeGuessKindToResource(gv.WithKind(resource.Kind))
}
versionMapper.AddSpecific(gv.WithKind(strings.ToLower(resource.Kind)), plural, singular, scope)
versionMapper.AddSpecific(gv.WithKind(resource.Kind), plural, singular, scope)
// TODO this is producing unsafe guesses that don't actually work, but it matches previous behavior
versionMapper.Add(gv.WithKind(resource.Kind+"List"), scope)
}

View File

@@ -0,0 +1,69 @@
/*
Copyright 2015 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package leaderelection
import (
"net/http"
"sync"
"time"
)
// HealthzAdaptor associates the /healthz endpoint with the LeaderElection object.
// It helps deal with the /healthz endpoint being set up prior to the LeaderElection.
// This contains the code needed to act as an adaptor between the leader
// election code the health check code. It allows us to provide health
// status about the leader election. Most specifically about if the leader
// has failed to renew without exiting the process. In that case we should
// report not healthy and rely on the kubelet to take down the process.
type HealthzAdaptor struct {
pointerLock sync.Mutex
le *LeaderElector
timeout time.Duration
}
// Name returns the name of the health check we are implementing.
func (l *HealthzAdaptor) Name() string {
return "leaderElection"
}
// Check is called by the healthz endpoint handler.
// It fails (returns an error) if we own the lease but had not been able to renew it.
func (l *HealthzAdaptor) Check(req *http.Request) error {
l.pointerLock.Lock()
defer l.pointerLock.Unlock()
if l.le == nil {
return nil
}
return l.le.Check(l.timeout)
}
// SetLeaderElection ties a leader election object to a HealthzAdaptor
func (l *HealthzAdaptor) SetLeaderElection(le *LeaderElector) {
l.pointerLock.Lock()
defer l.pointerLock.Unlock()
l.le = le
}
// NewLeaderHealthzAdaptor creates a basic healthz adaptor to monitor a leader election.
// timeout determines the time beyond the lease expiry to be allowed for timeout.
// checks within the timeout period after the lease expires will still return healthy.
func NewLeaderHealthzAdaptor(timeout time.Duration) *HealthzAdaptor {
result := &HealthzAdaptor{
timeout: timeout,
}
return result
}

View File

@@ -0,0 +1,175 @@
/*
Copyright 2015 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package leaderelection
import (
"fmt"
"testing"
"time"
"k8s.io/apimachinery/pkg/util/clock"
rl "k8s.io/client-go/tools/leaderelection/resourcelock"
"net/http"
)
type fakeLock struct {
identity string
}
// Get is a dummy to allow us to have a fakeLock for testing.
func (fl *fakeLock) Get() (ler *rl.LeaderElectionRecord, err error) {
return nil, nil
}
// Create is a dummy to allow us to have a fakeLock for testing.
func (fl *fakeLock) Create(ler rl.LeaderElectionRecord) error {
return nil
}
// Update is a dummy to allow us to have a fakeLock for testing.
func (fl *fakeLock) Update(ler rl.LeaderElectionRecord) error {
return nil
}
// RecordEvent is a dummy to allow us to have a fakeLock for testing.
func (fl *fakeLock) RecordEvent(string) {}
// Identity is a dummy to allow us to have a fakeLock for testing.
func (fl *fakeLock) Identity() string {
return fl.identity
}
// Describe is a dummy to allow us to have a fakeLock for testing.
func (fl *fakeLock) Describe() string {
return "Dummy implementation of lock for testing"
}
// TestLeaderElectionHealthChecker tests that the healthcheck for leader election handles its edge cases.
func TestLeaderElectionHealthChecker(t *testing.T) {
current := time.Now()
req := &http.Request{}
tests := []struct {
description string
expected error
adaptorTimeout time.Duration
elector *LeaderElector
}{
{
description: "call check before leader elector initialized",
expected: nil,
adaptorTimeout: time.Second * 20,
elector: nil,
},
{
description: "call check when the the lease is far expired",
expected: fmt.Errorf("failed election to renew leadership on lease %s", "foo"),
adaptorTimeout: time.Second * 20,
elector: &LeaderElector{
config: LeaderElectionConfig{
Lock: &fakeLock{identity: "healthTest"},
LeaseDuration: time.Minute,
Name: "foo",
},
observedRecord: rl.LeaderElectionRecord{
HolderIdentity: "healthTest",
},
observedTime: current,
clock: clock.NewFakeClock(current.Add(time.Hour)),
},
},
{
description: "call check when the the lease is far expired but held by another server",
expected: nil,
adaptorTimeout: time.Second * 20,
elector: &LeaderElector{
config: LeaderElectionConfig{
Lock: &fakeLock{identity: "healthTest"},
LeaseDuration: time.Minute,
Name: "foo",
},
observedRecord: rl.LeaderElectionRecord{
HolderIdentity: "otherServer",
},
observedTime: current,
clock: clock.NewFakeClock(current.Add(time.Hour)),
},
},
{
description: "call check when the the lease is not expired",
expected: nil,
adaptorTimeout: time.Second * 20,
elector: &LeaderElector{
config: LeaderElectionConfig{
Lock: &fakeLock{identity: "healthTest"},
LeaseDuration: time.Minute,
Name: "foo",
},
observedRecord: rl.LeaderElectionRecord{
HolderIdentity: "healthTest",
},
observedTime: current,
clock: clock.NewFakeClock(current),
},
},
{
description: "call check when the the lease is expired but inside the timeout",
expected: nil,
adaptorTimeout: time.Second * 20,
elector: &LeaderElector{
config: LeaderElectionConfig{
Lock: &fakeLock{identity: "healthTest"},
LeaseDuration: time.Minute,
Name: "foo",
},
observedRecord: rl.LeaderElectionRecord{
HolderIdentity: "healthTest",
},
observedTime: current,
clock: clock.NewFakeClock(current.Add(time.Minute).Add(time.Second)),
},
},
}
for _, test := range tests {
adaptor := NewLeaderHealthzAdaptor(test.adaptorTimeout)
if adaptor.le != nil {
t.Errorf("[%s] leaderChecker started with a LeaderElector %v", test.description, adaptor.le)
}
if test.elector != nil {
test.elector.config.WatchDog = adaptor
adaptor.SetLeaderElection(test.elector)
if adaptor.le == nil {
t.Errorf("[%s] adaptor failed to set the LeaderElector", test.description)
}
}
err := adaptor.Check(req)
if test.expected == nil {
if err == nil {
continue
}
t.Errorf("[%s] called check, expected no error but received \"%v\"", test.description, err)
} else {
if err == nil {
t.Errorf("[%s] called check and failed to received the expected error \"%v\"", test.description, test.expected)
}
if err.Error() != test.expected.Error() {
t.Errorf("[%s] called check, expected %v, received %v", test.description, test.expected, err)
}
}
}
}

View File

@@ -55,6 +55,7 @@ import (
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/clock"
"k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
rl "k8s.io/client-go/tools/leaderelection/resourcelock"
@@ -79,6 +80,7 @@ func NewLeaderElector(lec LeaderElectionConfig) (*LeaderElector, error) {
}
return &LeaderElector{
config: lec,
clock: clock.RealClock{},
}, nil
}
@@ -100,6 +102,13 @@ type LeaderElectionConfig struct {
// Callbacks are callbacks that are triggered during certain lifecycle
// events of the LeaderElector
Callbacks LeaderCallbacks
// WatchDog is the associated health checker
// WatchDog may be null if its not needed/configured.
WatchDog *HealthzAdaptor
// Name is the name of the resource lock for debugging
Name string
}
// LeaderCallbacks are callbacks that are triggered during certain
@@ -132,6 +141,12 @@ type LeaderElector struct {
// value observedRecord.HolderIdentity if the transition has
// not yet been reported.
reportedLeader string
// clock is wrapper around time to allow for less flaky testing
clock clock.Clock
// name is the name of the resource lock for debugging
name string
}
// Run starts the leader election loop
@@ -154,6 +169,9 @@ func RunOrDie(lec LeaderElectionConfig) {
if err != nil {
panic(err)
}
if lec.WatchDog != nil {
lec.WatchDog.SetLeaderElection(le)
}
le.Run()
}
@@ -229,14 +247,14 @@ func (le *LeaderElector) tryAcquireOrRenew() bool {
return false
}
le.observedRecord = leaderElectionRecord
le.observedTime = time.Now()
le.observedTime = le.clock.Now()
return true
}
// 2. Record obtained, check the Identity & Time
if !reflect.DeepEqual(le.observedRecord, *oldLeaderElectionRecord) {
le.observedRecord = *oldLeaderElectionRecord
le.observedTime = time.Now()
le.observedTime = le.clock.Now()
}
if le.observedTime.Add(le.config.LeaseDuration).After(now.Time) &&
oldLeaderElectionRecord.HolderIdentity != le.config.Lock.Identity() {
@@ -259,7 +277,7 @@ func (le *LeaderElector) tryAcquireOrRenew() bool {
return false
}
le.observedRecord = leaderElectionRecord
le.observedTime = time.Now()
le.observedTime = le.clock.Now()
return true
}
@@ -272,3 +290,19 @@ func (l *LeaderElector) maybeReportTransition() {
go l.config.Callbacks.OnNewLeader(l.reportedLeader)
}
}
// Check will determine if the current lease is expired by more than timeout.
func (le *LeaderElector) Check(maxTolerableExpiredLease time.Duration) error {
if !le.IsLeader() {
// Currently not concerned with the case that we are hot standby
return nil
}
// If we are more than timeout seconds after the lease duration that is past the timeout
// on the lease renew. Time to start reporting ourselves as unhealthy. We should have
// died but conditions like deadlock can prevent this. (See #70819)
if le.clock.Since(le.observedTime) > le.config.LeaseDuration+maxTolerableExpiredLease {
return fmt.Errorf("failed election to renew leadership on lease %s", le.config.Name)
}
return nil
}

View File

@@ -26,6 +26,7 @@ import (
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/clock"
fakecorev1 "k8s.io/client-go/kubernetes/typed/core/v1/fake"
core "k8s.io/client-go/testing"
rl "k8s.io/client-go/tools/leaderelection/resourcelock"
@@ -257,6 +258,7 @@ func testTryAcquireOrRenew(t *testing.T, objectType string) {
config: lec,
observedRecord: test.observedRecord,
observedTime: test.observedTime,
clock: clock.RealClock{},
}
if test.expectSuccess != le.tryAcquireOrRenew() {

View File

@@ -44,6 +44,7 @@ type tlsCacheKey struct {
certData string
keyData string
serverName string
dial string
}
func (t tlsCacheKey) String() string {
@@ -51,7 +52,7 @@ func (t tlsCacheKey) String() string {
if len(t.keyData) > 0 {
keyText = "<redacted>"
}
return fmt.Sprintf("insecure:%v, caData:%#v, certData:%#v, keyData:%s, serverName:%s", t.insecure, t.caData, t.certData, keyText, t.serverName)
return fmt.Sprintf("insecure:%v, caData:%#v, certData:%#v, keyData:%s, serverName:%s, dial:%s", t.insecure, t.caData, t.certData, keyText, t.serverName, t.dial)
}
func (c *tlsTransportCache) get(config *Config) (http.RoundTripper, error) {
@@ -75,7 +76,7 @@ func (c *tlsTransportCache) get(config *Config) (http.RoundTripper, error) {
return nil, err
}
// The options didn't require a custom TLS config
if tlsConfig == nil {
if tlsConfig == nil && config.Dial == nil {
return http.DefaultTransport, nil
}
@@ -109,5 +110,6 @@ func tlsConfigKey(c *Config) (tlsCacheKey, error) {
certData: string(c.TLS.CertData),
keyData: string(c.TLS.KeyData),
serverName: c.TLS.ServerName,
dial: fmt.Sprintf("%p", c.Dial),
}, nil
}

View File

@@ -17,6 +17,7 @@ limitations under the License.
package transport
import (
"net"
"net/http"
"testing"
)
@@ -53,6 +54,8 @@ func TestTLSConfigKey(t *testing.T) {
// Make sure config fields that affect the tls config affect the cache key
uniqueConfigurations := map[string]*Config{
"no tls": {},
"dialer": {Dial: net.Dial},
"dialer2": {Dial: func(network, address string) (net.Conn, error) { return nil, nil }},
"insecure": {TLS: TLSConfig{Insecure: true}},
"cadata 1": {TLS: TLSConfig{CAData: []byte{1}}},
"cadata 2": {TLS: TLSConfig{CAData: []byte{2}}},
@@ -104,11 +107,6 @@ func TestTLSConfigKey(t *testing.T) {
}
for nameA, valueA := range uniqueConfigurations {
for nameB, valueB := range uniqueConfigurations {
// Don't compare to ourselves
if nameA == nameB {
continue
}
keyA, err := tlsConfigKey(valueA)
if err != nil {
t.Errorf("Unexpected error for %q: %v", nameA, err)
@@ -119,6 +117,15 @@ func TestTLSConfigKey(t *testing.T) {
t.Errorf("Unexpected error for %q: %v", nameB, err)
continue
}
// Make sure we get the same key on the same config
if nameA == nameB {
if keyA != keyB {
t.Errorf("Expected identical cache keys for %q and %q, got:\n\t%s\n\t%s", nameA, nameB, keyA, keyB)
}
continue
}
if keyA == keyB {
t.Errorf("Expected unique cache keys for %q and %q, got:\n\t%s\n\t%s", nameA, nameB, keyA, keyB)
continue

View File

@@ -17,6 +17,7 @@ limitations under the License.
package transport
import (
"bytes"
"fmt"
"net/http"
"strings"
@@ -129,7 +130,7 @@ func SetAuthProxyHeaders(req *http.Request, username string, groups []string, ex
}
for key, values := range extra {
for _, value := range values {
req.Header.Add("X-Remote-Extra-"+key, value)
req.Header.Add("X-Remote-Extra-"+headerKeyEscape(key), value)
}
}
}
@@ -246,7 +247,7 @@ func (rt *impersonatingRoundTripper) RoundTrip(req *http.Request) (*http.Respons
}
for k, vv := range rt.impersonate.Extra {
for _, v := range vv {
req.Header.Add(ImpersonateUserExtraHeaderPrefix+k, v)
req.Header.Add(ImpersonateUserExtraHeaderPrefix+headerKeyEscape(k), v)
}
}
@@ -422,3 +423,110 @@ func (rt *debuggingRoundTripper) RoundTrip(req *http.Request) (*http.Response, e
func (rt *debuggingRoundTripper) WrappedRoundTripper() http.RoundTripper {
return rt.delegatedRoundTripper
}
func legalHeaderByte(b byte) bool {
return int(b) < len(legalHeaderKeyBytes) && legalHeaderKeyBytes[b]
}
func shouldEscape(b byte) bool {
// url.PathUnescape() returns an error if any '%' is not followed by two
// hexadecimal digits, so we'll intentionally encode it.
return !legalHeaderByte(b) || b == '%'
}
func headerKeyEscape(key string) string {
var buf bytes.Buffer
for i := 0; i < len(key); i++ {
b := key[i]
if shouldEscape(b) {
// %-encode bytes that should be escaped:
// https://tools.ietf.org/html/rfc3986#section-2.1
fmt.Fprintf(&buf, "%%%02X", b)
continue
}
buf.WriteByte(b)
}
return buf.String()
}
// legalHeaderKeyBytes was copied from net/http/lex.go's isTokenTable.
// See https://httpwg.github.io/specs/rfc7230.html#rule.token.separators
var legalHeaderKeyBytes = [127]bool{
'%': true,
'!': true,
'#': true,
'$': true,
'&': true,
'\'': true,
'*': true,
'+': true,
'-': true,
'.': true,
'0': true,
'1': true,
'2': true,
'3': true,
'4': true,
'5': true,
'6': true,
'7': true,
'8': true,
'9': true,
'A': true,
'B': true,
'C': true,
'D': true,
'E': true,
'F': true,
'G': true,
'H': true,
'I': true,
'J': true,
'K': true,
'L': true,
'M': true,
'N': true,
'O': true,
'P': true,
'Q': true,
'R': true,
'S': true,
'T': true,
'U': true,
'W': true,
'V': true,
'X': true,
'Y': true,
'Z': true,
'^': true,
'_': true,
'`': true,
'a': true,
'b': true,
'c': true,
'd': true,
'e': true,
'f': true,
'g': true,
'h': true,
'i': true,
'j': true,
'k': true,
'l': true,
'm': true,
'n': true,
'o': true,
'p': true,
'q': true,
'r': true,
's': true,
't': true,
'u': true,
'v': true,
'w': true,
'x': true,
'y': true,
'z': true,
'|': true,
'~': true,
}

View File

@@ -18,6 +18,7 @@ package transport
import (
"net/http"
"net/url"
"reflect"
"strings"
"testing"
@@ -125,6 +126,32 @@ func TestImpersonationRoundTripper(t *testing.T) {
ImpersonateUserExtraHeaderPrefix + "Second": {"B", "b"},
},
},
{
name: "escape handling",
impersonationConfig: ImpersonationConfig{
UserName: "user",
Extra: map[string][]string{
"test.example.com/thing.thing": {"A", "a"},
},
},
expected: map[string][]string{
ImpersonateUserHeader: {"user"},
ImpersonateUserExtraHeaderPrefix + `Test.example.com%2fthing.thing`: {"A", "a"},
},
},
{
name: "double escape handling",
impersonationConfig: ImpersonationConfig{
UserName: "user",
Extra: map[string][]string{
"test.example.com/thing.thing%20another.thing": {"A", "a"},
},
},
expected: map[string][]string{
ImpersonateUserHeader: {"user"},
ImpersonateUserExtraHeaderPrefix + `Test.example.com%2fthing.thing%2520another.thing`: {"A", "a"},
},
},
}
for _, tc := range tcs {
@@ -159,9 +186,10 @@ func TestImpersonationRoundTripper(t *testing.T) {
func TestAuthProxyRoundTripper(t *testing.T) {
for n, tc := range map[string]struct {
username string
groups []string
extra map[string][]string
username string
groups []string
extra map[string][]string
expectedExtra map[string][]string
}{
"allfields": {
username: "user",
@@ -170,6 +198,34 @@ func TestAuthProxyRoundTripper(t *testing.T) {
"one": {"alpha", "bravo"},
"two": {"charlie", "delta"},
},
expectedExtra: map[string][]string{
"one": {"alpha", "bravo"},
"two": {"charlie", "delta"},
},
},
"escaped extra": {
username: "user",
groups: []string{"groupA", "groupB"},
extra: map[string][]string{
"one": {"alpha", "bravo"},
"example.com/two": {"charlie", "delta"},
},
expectedExtra: map[string][]string{
"one": {"alpha", "bravo"},
"example.com%2ftwo": {"charlie", "delta"},
},
},
"double escaped extra": {
username: "user",
groups: []string{"groupA", "groupB"},
extra: map[string][]string{
"one": {"alpha", "bravo"},
"example.com/two%20three": {"charlie", "delta"},
},
expectedExtra: map[string][]string{
"one": {"alpha", "bravo"},
"example.com%2ftwo%2520three": {"charlie", "delta"},
},
},
} {
rt := &testRoundTripper{}
@@ -210,9 +266,64 @@ func TestAuthProxyRoundTripper(t *testing.T) {
actualExtra[extraKey] = append(actualExtra[key], values...)
}
}
if e, a := tc.extra, actualExtra; !reflect.DeepEqual(e, a) {
if e, a := tc.expectedExtra, actualExtra; !reflect.DeepEqual(e, a) {
t.Errorf("%s expected %v, got %v", n, e, a)
continue
}
}
}
// TestHeaderEscapeRoundTrip tests to see if foo == url.PathUnescape(headerEscape(foo))
// This behavior is important for client -> API server transmission of extra values.
func TestHeaderEscapeRoundTrip(t *testing.T) {
t.Parallel()
testCases := []struct {
name string
key string
}{
{
name: "alpha",
key: "alphabetical",
},
{
name: "alphanumeric",
key: "alph4num3r1c",
},
{
name: "percent encoded",
key: "percent%20encoded",
},
{
name: "almost percent encoded",
key: "almost%zzpercent%xxencoded",
},
{
name: "illegal char & percent encoding",
key: "example.com/percent%20encoded",
},
{
name: "weird unicode stuff",
key: "example.com/ᛒᚥᛏᛖᚥᚢとロビン",
},
{
name: "header legal chars",
key: "abc123!#$+.-_*\\^`~|'",
},
{
name: "legal path, illegal header",
key: "@=:",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
escaped := headerKeyEscape(tc.key)
unescaped, err := url.PathUnescape(escaped)
if err != nil {
t.Fatalf("url.PathUnescape(%q) returned error: %v", escaped, err)
}
if tc.key != unescaped {
t.Errorf("url.PathUnescape(headerKeyEscape(%q)) returned %q, wanted %q", tc.key, unescaped, tc.key)
}
})
}
}

View File

@@ -52,7 +52,7 @@ func New(config *Config) (http.RoundTripper, error) {
// TLSConfigFor returns a tls.Config that will provide the transport level security defined
// by the provided Config. Will return nil if no transport level security is requested.
func TLSConfigFor(c *Config) (*tls.Config, error) {
if !(c.HasCA() || c.HasCertAuth() || c.TLS.Insecure) {
if !(c.HasCA() || c.HasCertAuth() || c.TLS.Insecure || len(c.TLS.ServerName) > 0) {
return nil, nil
}
if c.HasCA() && c.TLS.Insecure {

View File

@@ -101,6 +101,13 @@ func TestNew(t *testing.T) {
Config: &Config{},
},
"server name": {
TLS: true,
Config: &Config{TLS: TLSConfig{
ServerName: "foo",
}},
},
"ca transport": {
TLS: true,
Config: &Config{