Compare commits

...

56 Commits

Author SHA1 Message Date
Kubernetes Publisher
3ab43aa31c Update dependencies to v0.19.6 tag 2020-12-18 17:18:24 +00:00
Kubernetes Publisher
e02e32bc73 Merge pull request #95353 from sfowl/automated-cherry-pick-of-#95316-upstream-release-1.19
Automated cherry pick of #95316: Mask bearer token in logs when logLevel >= 9

Kubernetes-commit: 8463d625c784f0027029fa77b8e3cc0b366df726
2020-12-14 17:20:00 +00:00
Kubernetes Publisher
6f060a2946 Merge pull request #96778 from caesarxuchao/cherrypick-95981-119
Cherrypick #95981 to 1.19, Enables HTTP/2 health check

Kubernetes-commit: 352ce39b5ed5c1f18c06bbc9bd1570c3bafdca90
2020-11-30 09:03:47 +00:00
Chao Xu
eb7665e713 Add a unit test testing the HTTP/2 health check help the REST client
detects broken TCP connections.

Kubernetes-commit: 21e018b02ec44f68e31cfbc9902b68fc13ab111f
2020-10-29 23:03:14 -07:00
Chao Xu
4528de7a82 update golang.org/x/net and golang.org/x/sys, equivalent of #96549
Kubernetes-commit: 5201ec00ac2535c9583d1fae131d28b33826db31
2020-11-21 05:19:42 +00:00
Kubernetes Publisher
a3f42c98ed Merge pull request #96201 from brianpursley/automated-cherry-pick-of-#95933-upstream-release-1.19
Automated cherry pick of #95933: Fix bug in JSON path parser where an error occurs when a

Kubernetes-commit: c902abad10b9c58ca0cddf36e01aa20d30961ffa
2020-11-17 17:10:15 +00:00
Kubernetes Publisher
4fcdf7e289 Merge pull request #95963 from dprotaso/automated-cherry-pick-of-#95939-upstream-release-1.19
Automated cherry pick of #95939: Address scenario where releasing a resource lock fails if a prior update fails or gets cancelled

Kubernetes-commit: c92290add7b0071f06a9ea4d9030b8eb2e67dd7c
2020-11-05 12:36:51 -08:00
brianpursley
377de3d217 Fix bug in JSON path parser where an error occurs when a range is empty
Kubernetes-commit: d67a36d1daa42660f23253e1b77061454daa7689
2020-11-01 10:41:19 -05:00
Dave Protasowski
a7c6cd2afe Re-add the event recorder in the release test
Prior having a mock recorder would cause panics since the lock
would be set to nil on update failures. Now the recorder will
use the cached lock

Kubernetes-commit: 7622eb6a89cb7f7d62a5c7d1d845959fdc8e268b
2020-10-27 22:45:33 -04:00
Dave Protasowski
478748cad1 Don't clear the cached resourcelock when errors occurs on updates
This allows the lock to be release normally - even with a
potentially stale lock. This flow should only occur when we're
the lease holders.

Kubernetes-commit: 1d10ae05c17e86befdab23cf24c3d0493b832881
2020-10-27 22:41:39 -04:00
Dave Protasowski
eedba609c5 Add failing test showing release is not working properly
Kubernetes-commit: b0bb48abe05d81ce83dcca071057d039832edff6
2020-10-27 22:29:22 -04:00
Kubernetes Publisher
79fff9604c Merge pull request #95926 from dprotaso/automated-cherry-pick-of-#80954-upstream-release-1.19
Automated cherry pick of #80954: Generate complete leader election record to resolve

Kubernetes-commit: 5f1a8f61bf7d5e0cbbbd5dab35e4c3f02218c200
2020-10-28 08:21:57 -07:00
Sam Fowler
44e1a07f2d Mask bearer token in logs when logLevel >= 9
Kubernetes-commit: 5d1b08e4cd270d84152fdde0b13d643b1bca0576
2020-10-06 11:10:38 +10:00
Zachary Seguin
e65aa52ba1 Add lease release tests in leader election
Kubernetes-commit: e94ec96e39a3f91d70fa76b5a060b28c79e8d9a9
2020-04-22 18:52:44 -04:00
Zachary Seguin
b32de8e148 Generate complete leader election record to resolve leader election issues with LeaseLocks
Kubernetes-commit: acadf81c6832dc55e109bba729da71cd69247958
2019-08-03 17:40:03 -04:00
Kubernetes Publisher
fa0b9c68e8 Merge pull request #95618 from roycaihw/automated-cherry-pick-of-#95427-upstream-release-1.19
Automated cherry pick of #95427: don't cache transports for incomparable configs

Kubernetes-commit: f88d259a46257141584312c7b38069a982cd90cc
2020-10-20 10:35:58 +00:00
Haowei Cai
400bca4e0c don't cache transports for incomparable configs
Co-authored-by: Jordan Liggitt <liggitt@google.com>

Kubernetes-commit: f8607b0449ea8dc9d5c7cbc6e829dfec2f8764fc
2020-10-07 15:44:27 -07:00
Kubernetes Publisher
bb0bc934b5 Merge pull request #94431 from janeczku/automated-cherry-pick-of-#94316-upstream-release-1.19
Automated cherry pick of #94316: Fixed reflector not recovering from "Too large resource

Kubernetes-commit: 8331637da07131bd5dfef49c8f8deaf248ee6669
2020-09-04 05:34:52 +00:00
Kubernetes Publisher
d3292e7379 Merge pull request #94427 from gobomb/automated-cherry-pick-of-#93646-origin-release-1.19
Automated cherry pick of #93646: let panics propagate up when processLoop panic

Kubernetes-commit: f61113118fd447e9e15174aa4f804d7754a9e495
2020-09-04 01:35:57 +00:00
janeczku
85ff1af514 Fixed reflector not recovering from "Too large resource version" errors with API servers 1.17.0-1.18.5
Kubernetes-commit: e21e490535fb7a5abd2f6f2c03a11613767e4800
2020-08-28 21:17:27 +02:00
Kubernetes Publisher
3e55cca68b Merge remote-tracking branch 'origin/master' into release-1.19
Kubernetes-commit: 6acb6808a4ce366f66037811a4009d285db951f0
2020-08-21 17:27:42 +00:00
Jordan Liggitt
811a8b132d Update json-patch to v4.9.0 tagged release
Kubernetes-commit: 245064a3518c7a42fe830316da2fbfd2667db01d
2020-08-20 17:05:24 -04:00
Kubernetes Publisher
f28aff3575 Merge remote-tracking branch 'origin/master' into release-1.19
Kubernetes-commit: eedb7d6eb9948a015e45ff6bbb7a0e36144c181f
2020-08-13 17:27:17 +00:00
Antoine Pelisse
5f89fb22eb Update SMD to v4.0.1 and kube-openapi
Kubernetes-commit: f4c145511a0bb62ea7ee1f2154945c84c17ffcd5
2020-08-10 13:02:25 -07:00
Kubernetes Publisher
16ae2a83e3 Merge remote-tracking branch 'origin/master' into release-1.19
Kubernetes-commit: bbb37e6328b99a3bd1ff3e371aff3655656952c1
2020-08-09 07:43:54 +00:00
Kubernetes Publisher
26eb6c9d58 Merge pull request #93810 from liggitt/json-patch-4.8.0
Update to json-patch 4.8.0

Kubernetes-commit: 9b78bd59796d3937986934582230174606403780
2020-08-09 09:18:15 +00:00
Jordan Liggitt
cf763b338e Update to json-patch 4.8.0
Kubernetes-commit: cc6814f83ccad671c79570b44c84b280709b4c74
2020-08-08 09:53:56 -04:00
Jordan Liggitt
ecd4cf4948 [go1.15] Use errors.As to unwrap net errors
Kubernetes-commit: c61c60eb1f59c92b0628484b55c640e585555aab
2020-08-07 15:22:54 -04:00
gobomb
705dbea9c0 let panics propagate up when processLoop panic
Kubernetes-commit: c9d4923fa5438bc820bcf3b6a34cb747befaf59a
2020-08-03 09:30:39 +00:00
Kubernetes Publisher
470e5168e5 Merge remote-tracking branch 'origin/master' into release-1.19
Kubernetes-commit: 313e6e71a0631d58c7f9e710035df38855f2bcdb
2020-08-02 12:40:02 +00:00
Kubernetes Publisher
56a75924ba Merge pull request #93408 from joelsmith/master
jsonpath: disallow multiple immediate recursive descent

Kubernetes-commit: c0ec2eee41794796dee230f75478602b707f2be2
2020-08-02 13:32:13 +00:00
Jordan Liggitt
9aa38c9438 Update k8s.io/utils
Kubernetes-commit: c11e52f410603d2e8eaf6591b4c83ab19d233b17
2020-07-31 10:44:33 -04:00
Joel Smith
b1bdc49a82 jsonpath: disallow multiple immediate recursive descent (e.g. ....Foo)
Kubernetes-commit: 8c702254938c40a48b2e3db78fcc944ca50fdc65
2020-07-30 10:53:12 -06:00
Kubernetes Publisher
7f42acdcbb Merge remote-tracking branch 'origin/master' into release-1.19
Kubernetes-commit: d01fde696783fa58430253dfc3bc375d677c4ba3
2020-07-27 09:17:51 +00:00
Jordan Liggitt
7bd7537673 generated: hack/update-vendor.sh
Kubernetes-commit: 6c2d18369f688b7200cefdca71709bb698081e84
2020-07-25 15:27:12 -04:00
Jordan Liggitt
1221114e9d [go1.15] go.mod: update to go1.15
Kubernetes-commit: 247fcdfda5311bfc446c61c7bda67803e3527fdd
2020-07-25 15:02:16 -04:00
Kubernetes Publisher
ec99fbd776 Merge pull request #93425 from liggitt/string-cast
Fix int->string casts

Kubernetes-commit: 19caf386650b80ce9d288cc8c42efcf2f0fd87b1
2020-07-27 09:17:49 +00:00
Jordan Liggitt
4c8f8d9828 Fix int->string casts
Kubernetes-commit: 124a5ddf725c4862520d8619017cac9db7a03522
2020-07-24 11:13:07 -04:00
Nikhita Raghunath
4f0de5593f Revert "Merge pull request #93156 from logicalhan/triage-api-machinery"
This reverts commit 32438cf26938091bea56e7ca7c3fcf4215652f9c, reversing
changes made to bb6a6aa3915cc9f7efaaf2291f6adac8333fd33c.

Kubernetes-commit: c00dae060731f6286ee3743db24782f09c33945a
2020-07-24 13:01:02 +05:30
Kubernetes Publisher
970cddeeea Merge remote-tracking branch 'origin/master' into release-1.19
Kubernetes-commit: babcb237e1287bd591a2a3a644483ef2e7a7edd8
2020-07-22 12:51:35 +00:00
Kubernetes Publisher
4f322be2e9 Merge pull request #93156 from logicalhan/triage-api-machinery
automatically assign triage labels to api-machinery tagged PRs

Kubernetes-commit: 32438cf26938091bea56e7ca7c3fcf4215652f9c
2020-07-22 13:21:20 +00:00
Kubernetes Publisher
b6011de30e Merge remote-tracking branch 'origin/master' into release-1.19
Kubernetes-commit: 223a4e974f77c585bd47ce008c3d6f80ded653dd
2020-07-21 13:21:09 +00:00
Jordan Liggitt
d3dc2f4702 Update k8s.io/utils
Kubernetes-commit: 7aacbeac144a7772fa8eac5582bbd64bc52804a4
2020-07-20 11:12:29 -04:00
Han Kang
acfd65636a automatically assign triage labels to api-machinery tagged PRs
Change-Id: Ifcc8a85d190d6370423af27f6e6c4c90b8472981

Kubernetes-commit: 9129dbc98bd847be9d96b39733a3b28107c920a1
2020-07-16 13:13:59 -07:00
Kubernetes Publisher
b501d6e7bb Merge remote-tracking branch 'origin/master' into release-1.19
Kubernetes-commit: 4c700f46775d035b3a926b16f1a536e100706848
2020-07-12 17:12:29 +00:00
Kubernetes Publisher
69f0a18004 Merge pull request #92926 from detiber/FixFakeScaleClientUpdate
[client-go] Fix argument ordering for fake scale client update

Kubernetes-commit: 165a221b1c8eea44dd1a6281bc9c8ff5ee3a33d3
2020-07-13 13:19:45 +00:00
Kubernetes Publisher
e8a27546e8 Merge pull request #92919 from dashpole/update_cadvisor
Update cAdvisor to v0.37.0

Kubernetes-commit: 6b5dc3770851fdc1f356e36fd17810c744181fb1
2020-07-13 13:19:43 +00:00
Kubernetes Publisher
10b99a8ee8 Merge pull request #92910 from soltysh/kubectl_cache
Setup cache dirs properly based on --cache-dir value

Kubernetes-commit: 7d1daa09383d32fe7a325d6275d9bd51cba45ee5
2020-07-13 13:19:42 +00:00
Kubernetes Publisher
63841cef17 Merge pull request #92874 from chelseychen/event-api
Fix a few places where source field is empty when creating events via events/v1

Kubernetes-commit: c23a4b08d704156db724769a32edc71c921095d4
2020-07-13 13:19:41 +00:00
Kubernetes Publisher
33f5fff4a5 Merge pull request #92768 from deads2k/security-contacts
update security contacts for apimachinery repos

Kubernetes-commit: 0cc96859473a21eb7d4f44f355d50881e12925ad
2020-07-13 13:19:39 +00:00
Kubernetes Publisher
367809baaa Merge pull request #92661 from jpbetz/smd-bump-field-unsetting
Bump to SMD PR#166 to pick up unsetting field changes and add integration tests

Kubernetes-commit: 49dced762da7bc9f74474e9f8f3efe198ff46767
2020-07-13 13:19:38 +00:00
David Ashpole
157fd1a595 update cAdvisor to v0.37.0
Kubernetes-commit: 1f70708f6cc85985725c11cd69c4965c1f97b314
2020-07-09 10:23:10 -07:00
Jason DeTiberus
f98e990e6f [client-go] Fix argument ordering for fake scale client update
Fixes the argument order used when calling testing.NewUpdateSubresourceAction
within the fake scale client. This was causing the generated action to swap the values
of the Namespace and Subresource in the Action.

Kubernetes-commit: 34a446d812c423da7a306963f250f4002dac9be8
2020-07-08 20:27:13 -04:00
Maciej Szulik
76326df43e Setup cache dirs properly based on --cache-dir value
Kubernetes-commit: 6c6cd2deeb03040d458b00824fd6c1a900a81b51
2020-07-08 15:43:25 +02:00
Chelsey Chen
c0b8411f2d Update conversion between ReportingController and Source.Component
Kubernetes-commit: e010436e2acc96d710620a91ceaaa86becca4060
2020-07-07 13:38:48 -04:00
David Eads
1a3f7941d8 update security contacts for apimachinery repos
Kubernetes-commit: 29c4e858b0017f8aa328d487adbbe910b8205cf8
2020-07-02 16:00:53 -04:00
28 changed files with 696 additions and 136 deletions

22
Godeps/Godeps.json generated
View File

@@ -128,7 +128,7 @@
},
{
"ImportPath": "github.com/evanphx/json-patch",
"Rev": "e83c0a1c26c8"
"Rev": "v4.9.0"
},
{
"ImportPath": "github.com/fsnotify/fsnotify",
@@ -240,7 +240,7 @@
},
{
"ImportPath": "github.com/json-iterator/go",
"Rev": "v1.1.9"
"Rev": "v1.1.10"
},
{
"ImportPath": "github.com/jstemmer/go-junit-report",
@@ -336,7 +336,7 @@
},
{
"ImportPath": "golang.org/x/crypto",
"Rev": "bac4c82f6975"
"Rev": "75b288015ac9"
},
{
"ImportPath": "golang.org/x/exp",
@@ -360,7 +360,7 @@
},
{
"ImportPath": "golang.org/x/net",
"Rev": "d3edc9973b7e"
"Rev": "69a78807bb2b"
},
{
"ImportPath": "golang.org/x/oauth2",
@@ -372,7 +372,7 @@
},
{
"ImportPath": "golang.org/x/sys",
"Rev": "ed371f2e16b4"
"Rev": "5cba982894dd"
},
{
"ImportPath": "golang.org/x/text",
@@ -440,11 +440,11 @@
},
{
"ImportPath": "k8s.io/api",
"Rev": "02047b7ecbbf"
"Rev": "v0.19.6"
},
{
"ImportPath": "k8s.io/apimachinery",
"Rev": "106aebdc1c0a"
"Rev": "v0.19.6"
},
{
"ImportPath": "k8s.io/gengo",
@@ -456,19 +456,19 @@
},
{
"ImportPath": "k8s.io/kube-openapi",
"Rev": "656914f816f9"
"Rev": "6aeccd4b50c6"
},
{
"ImportPath": "k8s.io/utils",
"Rev": "6e3d28b6ed19"
"Rev": "d5654de09c73"
},
{
"ImportPath": "rsc.io/binaryregexp",
"Rev": "v0.2.0"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/v3",
"Rev": "v3.0.0"
"ImportPath": "sigs.k8s.io/structured-merge-diff/v4",
"Rev": "v4.0.1"
},
{
"ImportPath": "sigs.k8s.io/yaml",

View File

@@ -10,9 +10,7 @@
# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE
# INSTRUCTIONS AT https://kubernetes.io/security/
cjcullen
joelsmith
liggitt
philips
caesarxuchao
deads2k
lavalamp
sttts
tallclair

View File

@@ -268,8 +268,6 @@ func (d *CachedDiscoveryClient) Invalidate() {
// CachedDiscoveryClient cache data. If httpCacheDir is empty, the restconfig's transport will not
// be updated with a roundtripper that understands cache responses.
// If discoveryCacheDir is empty, cached server resource data will be looked up in the current directory.
// TODO(juanvallejo): the value of "--cache-dir" should be honored. Consolidate discoveryCacheDir with httpCacheDir
// so that server resources and http-cache data are stored in the same location, provided via config flags.
func NewCachedDiscoveryClientForConfig(config *restclient.Config, discoveryCacheDir, httpCacheDir string, ttl time.Duration) (*CachedDiscoveryClient, error) {
if len(httpCacheDir) > 0 {
// update the given restconfig with a custom roundtripper that

View File

@@ -19,8 +19,6 @@ package memory
import (
"errors"
"fmt"
"net"
"net/url"
"sync"
"syscall"
@@ -64,19 +62,11 @@ var _ discovery.CachedDiscoveryInterface = &memCacheClient{}
// "Connection reset" error which usually means that apiserver is temporarily
// unavailable.
func isTransientConnectionError(err error) bool {
urlError, ok := err.(*url.Error)
if !ok {
return false
var errno syscall.Errno
if errors.As(err, &errno) {
return errno == syscall.ECONNREFUSED || errno == syscall.ECONNRESET
}
opError, ok := urlError.Err.(*net.OpError)
if !ok {
return false
}
errno, ok := opError.Err.(syscall.Errno)
if !ok {
return false
}
return errno == syscall.ECONNREFUSED || errno == syscall.ECONNRESET
return false
}
func isTransientError(err error) bool {

19
go.mod
View File

@@ -2,14 +2,14 @@
module k8s.io/client-go
go 1.13
go 1.15
require (
cloud.google.com/go v0.51.0 // indirect
github.com/Azure/go-autorest/autorest v0.9.6
github.com/Azure/go-autorest/autorest/adal v0.8.2
github.com/davecgh/go-spew v1.1.1
github.com/evanphx/json-patch v0.0.0-20190815234213-e83c0a1c26c8
github.com/evanphx/json-patch v4.9.0+incompatible
github.com/gogo/protobuf v1.3.1
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7
github.com/golang/protobuf v1.4.2
@@ -22,19 +22,18 @@ require (
github.com/peterbourgon/diskv v2.0.1+incompatible
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.4.0
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6
golang.org/x/time v0.0.0-20191024005414-555d28b269f0
k8s.io/api v0.0.0
k8s.io/apimachinery v0.0.0
k8s.io/api v0.19.6
k8s.io/apimachinery v0.19.6
k8s.io/klog/v2 v2.2.0
k8s.io/utils v0.0.0-20200619165400-6e3d28b6ed19
k8s.io/utils v0.0.0-20200729134348-d5654de09c73
sigs.k8s.io/yaml v1.2.0
)
replace (
k8s.io/api => ../api
k8s.io/apimachinery => ../apimachinery
k8s.io/client-go => ../client-go
k8s.io/api => k8s.io/api v0.19.6
k8s.io/apimachinery => k8s.io/apimachinery v0.19.6
)

35
go.sum
View File

@@ -56,8 +56,8 @@ github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkg
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v0.0.0-20190815234213-e83c0a1c26c8 h1:DM7gHzQfHwIj+St8zaPOI6iQEPAxOwIkskvw6s9rDaM=
github.com/evanphx/json-patch v0.0.0-20190815234213-e83c0a1c26c8/go.mod h1:pmLOTb3x90VhIKxsA9yeQG5yfOkkKnkk1h+Ql8NDYDw=
github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
@@ -127,8 +127,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
@@ -157,7 +157,6 @@ github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
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/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -180,8 +179,8 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo=
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -215,6 +214,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -239,8 +240,9 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8=
golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd h1:5CtCZbICpIOFdgO940moixOPjc0178IU44m4EjOO5IY=
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
@@ -332,18 +334,19 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
k8s.io/api v0.19.6/go.mod h1:Plxx44Nh4zVblkJrIgxVPgPre1mvng6tXf1Sj3bs0fU=
k8s.io/apimachinery v0.19.6/go.mod h1:6sRbGRAVY5DOCuZwB5XkqguBqpqLU6q/kOaOdk29z6Q=
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/klog/v2 v2.2.0 h1:XRvcwJozkgZ1UQJmfMGpvRthQHOvihEhYtDfAaxMz/A=
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
k8s.io/kube-openapi v0.0.0-20200427153329-656914f816f9 h1:5NC2ITmvg8RoxoH0wgmL4zn4VZqXGsKbxrikjaQx6s4=
k8s.io/kube-openapi v0.0.0-20200427153329-656914f816f9/go.mod h1:bfCVj+qXcEaE5SCvzBaqpOySr6tuCcpPKqF6HD8nyCw=
k8s.io/utils v0.0.0-20200619165400-6e3d28b6ed19 h1:7Nu2dTj82c6IaWvL7hImJzcXoTPz1MsSCH7r+0m6rfo=
k8s.io/utils v0.0.0-20200619165400-6e3d28b6ed19/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6 h1:+WnxoVtG8TMiudHBSEtrVL1egv36TkkJm+bA8AxicmQ=
k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o=
k8s.io/utils v0.0.0-20200729134348-d5654de09c73 h1:uJmqzgNWG7XyClnU/mLPBWwfKKF1K8Hf8whTseBgJcg=
k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
sigs.k8s.io/structured-merge-diff/v3 v3.0.1-0.20200706213357-43c19bbb7fba h1:AAbnc5KQuTWKuh2QSnyghKIOTFzB0Jayv7/OFDn3Cy4=
sigs.k8s.io/structured-merge-diff/v3 v3.0.1-0.20200706213357-43c19bbb7fba/go.mod h1:V06abazjHneE37ZdSY/UUwPVgcJMKI/jU5XGUjgIKoc=
sigs.k8s.io/structured-merge-diff/v4 v4.0.1 h1:YXTMot5Qz/X1iBRJhAt+vI+HVttY0WkSqqhKxQ0xVbA=
sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=

View File

@@ -185,7 +185,7 @@ func TestAzureTokenSource(t *testing.T) {
expiresOn = "foo"
)
cfg := map[string]string{
cfgConfigMode: string(configMode),
cfgConfigMode: strconv.Itoa(int(configMode)),
cfgApiserverID: serverID,
cfgClientID: clientID,
cfgTenantID: tenantID,
@@ -365,7 +365,7 @@ func TestAzureTokenSourceScenarios(t *testing.T) {
persister := newFakePersister()
cfg := map[string]string{
cfgConfigMode: string(configMode),
cfgConfigMode: strconv.Itoa(int(configMode)),
}
if tc.configToken != nil {
cfg = token2Cfg(tc.configToken)

164
rest/connection_test.go Normal file
View File

@@ -0,0 +1,164 @@
/*
Copyright 2019 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 rest
import (
"context"
"fmt"
"io"
"net"
"net/http"
"net/http/httptest"
"net/url"
"os"
"strconv"
"sync/atomic"
"testing"
"time"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
utilnet "k8s.io/apimachinery/pkg/util/net"
)
type tcpLB struct {
t *testing.T
ln net.Listener
serverURL string
dials int32
}
func (lb *tcpLB) handleConnection(in net.Conn, stopCh chan struct{}) {
out, err := net.Dial("tcp", lb.serverURL)
if err != nil {
lb.t.Log(err)
return
}
go io.Copy(out, in)
go io.Copy(in, out)
<-stopCh
if err := out.Close(); err != nil {
lb.t.Fatalf("failed to close connection: %v", err)
}
}
func (lb *tcpLB) serve(stopCh chan struct{}) {
conn, err := lb.ln.Accept()
if err != nil {
lb.t.Fatalf("failed to accept: %v", err)
}
atomic.AddInt32(&lb.dials, 1)
go lb.handleConnection(conn, stopCh)
}
func newLB(t *testing.T, serverURL string) *tcpLB {
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("failed to bind: %v", err)
}
lb := tcpLB{
serverURL: serverURL,
ln: ln,
t: t,
}
return &lb
}
func setEnv(key, value string) func() {
originalValue := os.Getenv(key)
os.Setenv(key, value)
return func() {
os.Setenv(key, originalValue)
}
}
const (
readIdleTimeout int = 1
pingTimeout int = 1
)
func TestReconnectBrokenTCP(t *testing.T) {
defer setEnv("HTTP2_READ_IDLE_TIMEOUT_SECONDS", strconv.Itoa(readIdleTimeout))()
defer setEnv("HTTP2_PING_TIMEOUT_SECONDS", strconv.Itoa(pingTimeout))()
defer setEnv("DISABLE_HTTP2", "")()
ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %s", r.Proto)
}))
ts.EnableHTTP2 = true
ts.StartTLS()
defer ts.Close()
u, err := url.Parse(ts.URL)
if err != nil {
t.Fatalf("failed to parse URL from %q: %v", ts.URL, err)
}
lb := newLB(t, u.Host)
defer lb.ln.Close()
stopCh := make(chan struct{})
go lb.serve(stopCh)
transport, ok := ts.Client().Transport.(*http.Transport)
if !ok {
t.Fatalf("failed to assert *http.Transport")
}
config := &Config{
Host: "https://" + lb.ln.Addr().String(),
Transport: utilnet.SetTransportDefaults(transport),
Timeout: 1 * time.Second,
// These fields are required to create a REST client.
ContentConfig: ContentConfig{
GroupVersion: &schema.GroupVersion{},
NegotiatedSerializer: &serializer.CodecFactory{},
},
}
client, err := RESTClientFor(config)
if err != nil {
t.Fatalf("failed to create REST client: %v", err)
}
data, err := client.Get().AbsPath("/").DoRaw(context.TODO())
if err != nil {
t.Fatalf("unexpected err: %s: %v", data, err)
}
if string(data) != "Hello, HTTP/2.0" {
t.Fatalf("unexpected response: %s", data)
}
// Deliberately let the LB stop proxying traffic for the current
// connection. This mimics a broken TCP connection that's not properly
// closed.
close(stopCh)
stopCh = make(chan struct{})
go lb.serve(stopCh)
// Sleep enough time for the HTTP/2 health check to detect and close
// the broken TCP connection.
time.Sleep(time.Duration(1+readIdleTimeout+pingTimeout) * time.Second)
// If the HTTP/2 health check were disabled, the broken connection
// would still be in the connection pool, the following request would
// then reuse the broken connection instead of creating a new one, and
// thus would fail.
data, err = client.Get().AbsPath("/").DoRaw(context.TODO())
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
if string(data) != "Hello, HTTP/2.0" {
t.Fatalf("unexpected response: %s", data)
}
dials := atomic.LoadInt32(&lb.dials)
if dials != 2 {
t.Fatalf("expected %d dials, got %d", 2, dials)
}
}

View File

@@ -60,7 +60,7 @@ func (f *fakeNamespacedScaleClient) Get(ctx context.Context, resource schema.Gro
func (f *fakeNamespacedScaleClient) Update(ctx context.Context, resource schema.GroupResource, scale *autoscalingapi.Scale, opts metav1.UpdateOptions) (*autoscalingapi.Scale, error) {
obj, err := f.fake.
Invokes(testing.NewUpdateSubresourceAction(resource.WithVersion(""), f.namespace, "scale", scale), &autoscalingapi.Scale{})
Invokes(testing.NewUpdateSubresourceAction(resource.WithVersion(""), "scale", f.namespace, scale), &autoscalingapi.Scale{})
if err != nil {
return nil, err

View File

@@ -144,11 +144,11 @@ func (c *controller) Run(stopCh <-chan struct{}) {
c.reflectorMutex.Unlock()
var wg wait.Group
defer wg.Wait()
wg.StartWithChannel(stopCh, r.Run)
wait.Until(c.processLoop, time.Second, stopCh)
wg.Wait()
}
// Returns true once this controller has completed an initial resource listing

View File

@@ -402,3 +402,49 @@ func TestUpdate(t *testing.T) {
testDoneWG.Wait()
close(stop)
}
func TestPanicPropagated(t *testing.T) {
// source simulates an apiserver object endpoint.
source := fcache.NewFakeControllerSource()
// Make a controller that just panic if the AddFunc is called.
_, controller := NewInformer(
source,
&v1.Pod{},
time.Millisecond*100,
ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
// Create a panic.
panic("Just panic.")
},
},
)
// Run the controller and run it until we close stop.
stop := make(chan struct{})
defer close(stop)
propagated := make(chan interface{})
go func() {
defer func() {
if r := recover(); r != nil {
propagated <- r
}
}()
controller.Run(stop)
}()
// Let's add a object to the source. It will trigger a panic.
source.Add(&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "test"}})
// Check if the panic propagated up.
select {
case p := <-propagated:
if p == "Just panic." {
t.Logf("Test Passed")
} else {
t.Errorf("unrecognized panic in controller run: %v", p)
}
case <-time.After(wait.ForeverTestTimeout):
t.Errorf("timeout: the panic failed to propagate from the controller run method!")
}
}

View File

@@ -570,5 +570,26 @@ func isExpiredError(err error) bool {
}
func isTooLargeResourceVersionError(err error) bool {
return apierrors.HasStatusCause(err, metav1.CauseTypeResourceVersionTooLarge)
if apierrors.HasStatusCause(err, metav1.CauseTypeResourceVersionTooLarge) {
return true
}
// In Kubernetes 1.17.0-1.18.5, the api server doesn't set the error status cause to
// metav1.CauseTypeResourceVersionTooLarge to indicate that the requested minimum resource
// version is larger than the largest currently available resource version. To ensure backward
// compatibility with these server versions we also need to detect the error based on the content
// of the error message field.
if !apierrors.IsTimeout(err) {
return false
}
apierr, ok := err.(apierrors.APIStatus)
if !ok || apierr == nil || apierr.Status().Details == nil {
return false
}
for _, cause := range apierr.Status().Details.Causes {
// Matches the message returned by api server 1.17.0-1.18.5 for this error condition
if cause.Message == "Too large resource version" {
return true
}
}
return false
}

View File

@@ -738,9 +738,14 @@ func TestReflectorFullListIfTooLarge(t *testing.T) {
err := apierrors.NewTimeoutError("too large resource version", 1)
err.ErrStatus.Details.Causes = []metav1.StatusCause{{Type: metav1.CauseTypeResourceVersionTooLarge}}
return nil, err
// relist after the initial list (covers the error format used in api server 1.17.0-1.18.5)
case "30":
err := apierrors.NewTimeoutError("too large resource version", 1)
err.ErrStatus.Details.Causes = []metav1.StatusCause{{Message: "Too large resource version"}}
return nil, err
// relist from etcd after "too large" error
case "":
return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "10"}}, nil
return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "30"}}, nil
default:
return nil, fmt.Errorf("unexpected List call: %s", options.ResourceVersion)
}
@@ -759,12 +764,15 @@ func TestReflectorFullListIfTooLarge(t *testing.T) {
// may be synced to a different version and they will never converge.
// TODO: We should use etcd progress-notify feature to avoid this behavior but until this is
// done we simply try to relist from now to avoid continuous errors on relists.
stopCh = make(chan struct{})
if err := r.ListAndWatch(stopCh); err != nil {
t.Fatal(err)
for i := 1; i <= 2; i++ {
// relist twice to cover the two variants of TooLargeResourceVersion api errors
stopCh = make(chan struct{})
if err := r.ListAndWatch(stopCh); err != nil {
t.Fatal(err)
}
}
expectedRVs := []string{"0", "20", ""}
expectedRVs := []string{"0", "20", "", "30", ""}
if !reflect.DeepEqual(listCallRVs, expectedRVs) {
t.Errorf("Expected series of list calls with resource version of %#v but got: %#v", expectedRVs, listCallRVs)
}

View File

@@ -290,8 +290,12 @@ func (le *LeaderElector) release() bool {
if !le.IsLeader() {
return true
}
now := metav1.Now()
leaderElectionRecord := rl.LeaderElectionRecord{
LeaderTransitions: le.observedRecord.LeaderTransitions,
LeaderTransitions: le.observedRecord.LeaderTransitions,
LeaseDurationSeconds: 1,
RenewTime: now,
AcquireTime: now,
}
if err := le.config.Lock.Update(context.TODO(), leaderElectionRecord); err != nil {
klog.Errorf("Failed to release lock: %v", err)

View File

@@ -917,3 +917,284 @@ func TestTryAcquireOrRenewEndpointsLeases(t *testing.T) {
func TestTryAcquireOrRenewConfigMapsLeases(t *testing.T) {
testTryAcquireOrRenewMultiLock(t, "configmapsleases")
}
func testReleaseLease(t *testing.T, objectType string) {
tests := []struct {
name string
observedRecord rl.LeaderElectionRecord
observedTime time.Time
reactors []Reactor
expectSuccess bool
transitionLeader bool
outHolder string
}{
{
name: "release acquired lock from no object",
reactors: []Reactor{
{
verb: "get",
objectType: objectType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, errors.NewNotFound(action.(fakeclient.GetAction).GetResource().GroupResource(), action.(fakeclient.GetAction).GetName())
},
},
{
verb: "create",
objectType: objectType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, action.(fakeclient.CreateAction).GetObject(), nil
},
},
{
verb: "update",
objectType: objectType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, action.(fakeclient.UpdateAction).GetObject(), nil
},
},
},
expectSuccess: true,
outHolder: "",
},
}
for i := range tests {
test := &tests[i]
t.Run(test.name, func(t *testing.T) {
// OnNewLeader is called async so we have to wait for it.
var wg sync.WaitGroup
wg.Add(1)
var reportedLeader string
var lock rl.Interface
objectMeta := metav1.ObjectMeta{Namespace: "foo", Name: "bar"}
resourceLockConfig := rl.ResourceLockConfig{
Identity: "baz",
EventRecorder: &record.FakeRecorder{},
}
c := &fake.Clientset{}
for _, reactor := range test.reactors {
c.AddReactor(reactor.verb, objectType, reactor.reaction)
}
c.AddReactor("*", "*", func(action fakeclient.Action) (bool, runtime.Object, error) {
t.Errorf("unreachable action. testclient called too many times: %+v", action)
return true, nil, fmt.Errorf("unreachable action")
})
switch objectType {
case "endpoints":
lock = &rl.EndpointsLock{
EndpointsMeta: objectMeta,
LockConfig: resourceLockConfig,
Client: c.CoreV1(),
}
case "configmaps":
lock = &rl.ConfigMapLock{
ConfigMapMeta: objectMeta,
LockConfig: resourceLockConfig,
Client: c.CoreV1(),
}
case "leases":
lock = &rl.LeaseLock{
LeaseMeta: objectMeta,
LockConfig: resourceLockConfig,
Client: c.CoordinationV1(),
}
}
lec := LeaderElectionConfig{
Lock: lock,
LeaseDuration: 10 * time.Second,
Callbacks: LeaderCallbacks{
OnNewLeader: func(l string) {
defer wg.Done()
reportedLeader = l
},
},
}
observedRawRecord := GetRawRecordOrDie(t, objectType, test.observedRecord)
le := &LeaderElector{
config: lec,
observedRecord: test.observedRecord,
observedRawRecord: observedRawRecord,
observedTime: test.observedTime,
clock: clock.RealClock{},
}
if !le.tryAcquireOrRenew(context.Background()) {
t.Errorf("unexpected result of tryAcquireOrRenew: [succeeded=%v]", true)
}
le.maybeReportTransition()
// Wait for a response to the leader transition, and add 1 so that we can track the final transition.
wg.Wait()
wg.Add(1)
if test.expectSuccess != le.release() {
t.Errorf("unexpected result of release: [succeeded=%v]", !test.expectSuccess)
}
le.observedRecord.AcquireTime = metav1.Time{}
le.observedRecord.RenewTime = metav1.Time{}
if le.observedRecord.HolderIdentity != test.outHolder {
t.Errorf("expected holder:\n\t%+v\ngot:\n\t%+v", test.outHolder, le.observedRecord.HolderIdentity)
}
if len(test.reactors) != len(c.Actions()) {
t.Errorf("wrong number of api interactions")
}
if test.transitionLeader && le.observedRecord.LeaderTransitions != 1 {
t.Errorf("leader should have transitioned but did not")
}
if !test.transitionLeader && le.observedRecord.LeaderTransitions != 0 {
t.Errorf("leader should not have transitioned but did")
}
le.maybeReportTransition()
wg.Wait()
if reportedLeader != test.outHolder {
t.Errorf("reported leader was not the new leader. expected %q, got %q", test.outHolder, reportedLeader)
}
})
}
}
// Will test leader election using endpoints as the resource
func TestReleaseLeaseEndpoints(t *testing.T) {
testReleaseLease(t, "endpoints")
}
// Will test leader election using endpoints as the resource
func TestReleaseLeaseConfigMaps(t *testing.T) {
testReleaseLease(t, "configmaps")
}
// Will test leader election using endpoints as the resource
func TestReleaseLeaseLeases(t *testing.T) {
testReleaseLease(t, "leases")
}
func TestReleaseOnCancellation_Endpoints(t *testing.T) {
testReleaseOnCancellation(t, "endpoints")
}
func TestReleaseOnCancellation_ConfigMaps(t *testing.T) {
testReleaseOnCancellation(t, "configmaps")
}
func TestReleaseOnCancellation_Leases(t *testing.T) {
testReleaseOnCancellation(t, "leases")
}
func testReleaseOnCancellation(t *testing.T, objectType string) {
var (
onNewLeader = make(chan struct{})
onRenewCalled = make(chan struct{})
onRenewResume = make(chan struct{})
onRelease = make(chan struct{})
lockObj runtime.Object
updates int
)
resourceLockConfig := rl.ResourceLockConfig{
Identity: "baz",
EventRecorder: &record.FakeRecorder{},
}
c := &fake.Clientset{}
c.AddReactor("get", objectType, func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
if lockObj != nil {
return true, lockObj, nil
}
return true, nil, errors.NewNotFound(action.(fakeclient.GetAction).GetResource().GroupResource(), action.(fakeclient.GetAction).GetName())
})
// create lock
c.AddReactor("create", objectType, func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
lockObj = action.(fakeclient.CreateAction).GetObject()
return true, lockObj, nil
})
c.AddReactor("update", objectType, func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
updates++
// Second update (first renew) should return our canceled error
// FakeClient doesn't do anything with the context so we're doing this ourselves
if updates == 2 {
close(onRenewCalled)
<-onRenewResume
return true, nil, context.Canceled
} else if updates == 3 {
close(onRelease)
}
lockObj = action.(fakeclient.UpdateAction).GetObject()
return true, lockObj, nil
})
c.AddReactor("*", "*", func(action fakeclient.Action) (bool, runtime.Object, error) {
t.Errorf("unreachable action. testclient called too many times: %+v", action)
return true, nil, fmt.Errorf("unreachable action")
})
lock, err := rl.New(objectType, "foo", "bar", c.CoreV1(), c.CoordinationV1(), resourceLockConfig)
if err != nil {
t.Fatal("resourcelock.New() = ", err)
}
lec := LeaderElectionConfig{
Lock: lock,
LeaseDuration: 15 * time.Second,
RenewDeadline: 2 * time.Second,
RetryPeriod: 1 * time.Second,
// This is what we're testing
ReleaseOnCancel: true,
Callbacks: LeaderCallbacks{
OnNewLeader: func(identity string) {},
OnStoppedLeading: func() {},
OnStartedLeading: func(context.Context) {
close(onNewLeader)
},
},
}
elector, err := NewLeaderElector(lec)
if err != nil {
t.Fatal("Failed to create leader elector: ", err)
}
ctx, cancel := context.WithCancel(context.Background())
go elector.Run(ctx)
// Wait for us to become the leader
select {
case <-onNewLeader:
case <-time.After(10 * time.Second):
t.Fatal("failed to become the leader")
}
// Wait for renew (update) to be invoked
select {
case <-onRenewCalled:
case <-time.After(10 * time.Second):
t.Fatal("the elector failed to renew the lock")
}
// Cancel the context - stopping the elector while
// it's running
cancel()
// Resume the update call to return the cancellation
// which should trigger the release flow
close(onRenewResume)
select {
case <-onRelease:
case <-time.After(10 * time.Second):
t.Fatal("the lock was not released")
}
}

View File

@@ -92,8 +92,12 @@ func (cml *ConfigMapLock) Update(ctx context.Context, ler LeaderElectionRecord)
cml.cm.Annotations = make(map[string]string)
}
cml.cm.Annotations[LeaderElectionRecordAnnotationKey] = string(recordBytes)
cml.cm, err = cml.Client.ConfigMaps(cml.ConfigMapMeta.Namespace).Update(ctx, cml.cm, metav1.UpdateOptions{})
return err
cm, err := cml.Client.ConfigMaps(cml.ConfigMapMeta.Namespace).Update(ctx, cml.cm, metav1.UpdateOptions{})
if err != nil {
return err
}
cml.cm = cm
return nil
}
// RecordEvent in leader election while adding meta-data

View File

@@ -87,8 +87,12 @@ func (el *EndpointsLock) Update(ctx context.Context, ler LeaderElectionRecord) e
el.e.Annotations = make(map[string]string)
}
el.e.Annotations[LeaderElectionRecordAnnotationKey] = string(recordBytes)
el.e, err = el.Client.Endpoints(el.EndpointsMeta.Namespace).Update(ctx, el.e, metav1.UpdateOptions{})
return err
e, err := el.Client.Endpoints(el.EndpointsMeta.Namespace).Update(ctx, el.e, metav1.UpdateOptions{})
if err != nil {
return err
}
el.e = e
return nil
}
// RecordEvent in leader election while adding meta-data

View File

@@ -71,9 +71,14 @@ func (ll *LeaseLock) Update(ctx context.Context, ler LeaderElectionRecord) error
return errors.New("lease not initialized, call get or create first")
}
ll.lease.Spec = LeaderElectionRecordToLeaseSpec(&ler)
var err error
ll.lease, err = ll.Client.Leases(ll.LeaseMeta.Namespace).Update(ctx, ll.lease, metav1.UpdateOptions{})
return err
lease, err := ll.Client.Leases(ll.LeaseMeta.Namespace).Update(ctx, ll.lease, metav1.UpdateOptions{})
if err != nil {
return err
}
ll.lease = lease
return nil
}
// RecordEvent in leader election while adding meta-data

View File

@@ -24,7 +24,7 @@ import (
"testing"
"time"
"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8sruntime "k8s.io/apimachinery/pkg/runtime"
@@ -509,7 +509,7 @@ func TestLotsOfEvents(t *testing.T) {
APIVersion: "version",
}
// we need to vary the reason to prevent aggregation
go recorder.Eventf(ref, v1.EventTypeNormal, "Reason-"+string(i), strconv.Itoa(i))
go recorder.Eventf(ref, v1.EventTypeNormal, "Reason-"+strconv.Itoa(i), strconv.Itoa(i))
}
// Make sure no events were dropped by either of the listeners.
for i := 0; i < maxQueuedEvents; i++ {

View File

@@ -153,7 +153,8 @@ func (f *EventSourceObjectSpamFilter) Filter(event *v1.Event) bool {
// localKey - key that makes this event in the local group
type EventAggregatorKeyFunc func(event *v1.Event) (aggregateKey string, localKey string)
// EventAggregatorByReasonFunc aggregates events by exact match on event.Source, event.InvolvedObject, event.Type and event.Reason
// EventAggregatorByReasonFunc aggregates events by exact match on event.Source, event.InvolvedObject, event.Type,
// event.Reason, event.ReportingController and event.ReportingInstance
func EventAggregatorByReasonFunc(event *v1.Event) (string, string) {
return strings.Join([]string{
event.Source.Component,
@@ -165,6 +166,8 @@ func EventAggregatorByReasonFunc(event *v1.Event) (string, string) {
event.InvolvedObject.APIVersion,
event.Type,
event.Reason,
event.ReportingController,
event.ReportingInstance,
},
""), event.Message
}

View File

@@ -18,6 +18,7 @@ package record
import (
"reflect"
"strconv"
"strings"
"testing"
"time"
@@ -69,10 +70,10 @@ func makeUniqueEvents(num int) []v1.Event {
events := []v1.Event{}
kind := "Pod"
for i := 0; i < num; i++ {
reason := strings.Join([]string{"reason", string(i)}, "-")
message := strings.Join([]string{"message", string(i)}, "-")
name := strings.Join([]string{"pod", string(i)}, "-")
namespace := strings.Join([]string{"ns", string(i)}, "-")
reason := strings.Join([]string{"reason", strconv.Itoa(i)}, "-")
message := strings.Join([]string{"message", strconv.Itoa(i)}, "-")
name := strings.Join([]string{"pod", strconv.Itoa(i)}, "-")
namespace := strings.Join([]string{"ns", strconv.Itoa(i)}, "-")
involvedObject := makeObjectReference(kind, name, namespace)
events = append(events, makeEvent(reason, message, involvedObject))
}
@@ -82,7 +83,7 @@ func makeUniqueEvents(num int) []v1.Event {
func makeSimilarEvents(num int, template v1.Event, messagePrefix string) []v1.Event {
events := makeEvents(num, template)
for i := range events {
events[i].Message = strings.Join([]string{messagePrefix, string(i), events[i].Message}, "-")
events[i].Message = strings.Join([]string{messagePrefix, strconv.Itoa(i), events[i].Message}, "-")
}
return events
}

View File

@@ -47,12 +47,9 @@ type tlsCacheKey struct {
keyData string
certFile string
keyFile string
getCert string
serverName string
nextProtos string
dial string
disableCompression bool
proxy string
}
func (t tlsCacheKey) String() string {
@@ -60,22 +57,24 @@ func (t tlsCacheKey) String() string {
if len(t.keyData) > 0 {
keyText = "<redacted>"
}
return fmt.Sprintf("insecure:%v, caData:%#v, certData:%#v, keyData:%s, getCert: %s, serverName:%s, dial:%s disableCompression:%t, proxy: %s", t.insecure, t.caData, t.certData, keyText, t.getCert, t.serverName, t.dial, t.disableCompression, t.proxy)
return fmt.Sprintf("insecure:%v, caData:%#v, certData:%#v, keyData:%s, serverName:%s, disableCompression:%t", t.insecure, t.caData, t.certData, keyText, t.serverName, t.disableCompression)
}
func (c *tlsTransportCache) get(config *Config) (http.RoundTripper, error) {
key, err := tlsConfigKey(config)
key, canCache, err := tlsConfigKey(config)
if err != nil {
return nil, err
}
// Ensure we only create a single transport for the given TLS options
c.mu.Lock()
defer c.mu.Unlock()
if canCache {
// Ensure we only create a single transport for the given TLS options
c.mu.Lock()
defer c.mu.Unlock()
// See if we already have a custom transport for this config
if t, ok := c.transports[key]; ok {
return t, nil
// See if we already have a custom transport for this config
if t, ok := c.transports[key]; ok {
return t, nil
}
}
// Get the TLS options for this client config
@@ -110,8 +109,7 @@ func (c *tlsTransportCache) get(config *Config) (http.RoundTripper, error) {
proxy = config.Proxy
}
// Cache a single transport for these options
c.transports[key] = utilnet.SetTransportDefaults(&http.Transport{
transport := utilnet.SetTransportDefaults(&http.Transport{
Proxy: proxy,
TLSHandshakeTimeout: 10 * time.Second,
TLSClientConfig: tlsConfig,
@@ -119,24 +117,33 @@ func (c *tlsTransportCache) get(config *Config) (http.RoundTripper, error) {
DialContext: dial,
DisableCompression: config.DisableCompression,
})
return c.transports[key], nil
if canCache {
// Cache a single transport for these options
c.transports[key] = transport
}
return transport, nil
}
// tlsConfigKey returns a unique key for tls.Config objects returned from TLSConfigFor
func tlsConfigKey(c *Config) (tlsCacheKey, error) {
func tlsConfigKey(c *Config) (tlsCacheKey, bool, error) {
// Make sure ca/key/cert content is loaded
if err := loadTLSFiles(c); err != nil {
return tlsCacheKey{}, err
return tlsCacheKey{}, false, err
}
if c.TLS.GetCert != nil || c.Dial != nil || c.Proxy != nil {
// cannot determine equality for functions
return tlsCacheKey{}, false, nil
}
k := tlsCacheKey{
insecure: c.TLS.Insecure,
caData: string(c.TLS.CAData),
getCert: fmt.Sprintf("%p", c.TLS.GetCert),
serverName: c.TLS.ServerName,
nextProtos: strings.Join(c.TLS.NextProtos, ","),
dial: fmt.Sprintf("%p", c.Dial),
disableCompression: c.DisableCompression,
proxy: fmt.Sprintf("%p", c.Proxy),
}
if c.TLS.ReloadTLSFiles {
@@ -147,5 +154,5 @@ func tlsConfigKey(c *Config) (tlsCacheKey, error) {
k.keyData = string(c.TLS.KeyData)
}
return k, nil
return k, true, nil
}

View File

@@ -21,7 +21,6 @@ import (
"crypto/tls"
"net"
"net/http"
"net/url"
"testing"
)
@@ -37,16 +36,24 @@ func TestTLSConfigKey(t *testing.T) {
}
for nameA, valueA := range identicalConfigurations {
for nameB, valueB := range identicalConfigurations {
keyA, err := tlsConfigKey(valueA)
keyA, canCache, err := tlsConfigKey(valueA)
if err != nil {
t.Errorf("Unexpected error for %q: %v", nameA, err)
continue
}
keyB, err := tlsConfigKey(valueB)
if !canCache {
t.Errorf("Unexpected canCache=false")
continue
}
keyB, canCache, err := tlsConfigKey(valueB)
if err != nil {
t.Errorf("Unexpected error for %q: %v", nameB, err)
continue
}
if !canCache {
t.Errorf("Unexpected canCache=false")
continue
}
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
@@ -132,12 +139,12 @@ func TestTLSConfigKey(t *testing.T) {
}
for nameA, valueA := range uniqueConfigurations {
for nameB, valueB := range uniqueConfigurations {
keyA, err := tlsConfigKey(valueA)
keyA, canCacheA, err := tlsConfigKey(valueA)
if err != nil {
t.Errorf("Unexpected error for %q: %v", nameA, err)
continue
}
keyB, err := tlsConfigKey(valueB)
keyB, canCacheB, err := tlsConfigKey(valueB)
if err != nil {
t.Errorf("Unexpected error for %q: %v", nameB, err)
continue
@@ -148,33 +155,18 @@ func TestTLSConfigKey(t *testing.T) {
if keyA != keyB {
t.Errorf("Expected identical cache keys for %q and %q, got:\n\t%s\n\t%s", nameA, nameB, keyA, keyB)
}
if canCacheA != canCacheB {
t.Errorf("Expected identical canCache %q and %q, got:\n\t%v\n\t%v", nameA, nameB, canCacheA, canCacheB)
}
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
if canCacheA && canCacheB {
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
}
}
}
}
}
func TestTLSConfigKeyFuncPtr(t *testing.T) {
keys := make(map[tlsCacheKey]struct{})
makeKey := func(p func(*http.Request) (*url.URL, error)) tlsCacheKey {
key, err := tlsConfigKey(&Config{Proxy: p})
if err != nil {
t.Fatalf("Unexpected error creating cache key: %v", err)
}
return key
}
keys[makeKey(http.ProxyFromEnvironment)] = struct{}{}
keys[makeKey(http.ProxyFromEnvironment)] = struct{}{}
keys[makeKey(http.ProxyURL(nil))] = struct{}{}
keys[makeKey(nil)] = struct{}{}
if got, want := len(keys), 3; got != want {
t.Fatalf("Unexpected number of keys: got=%d want=%d", got, want)
}
}

View File

@@ -340,6 +340,7 @@ func (r *requestInfo) toCurl() string {
headers := ""
for key, values := range r.RequestHeaders {
for _, value := range values {
value = maskValue(key, value)
headers += fmt.Sprintf(` -H %q`, fmt.Sprintf("%s: %s", key, value))
}
}

View File

@@ -103,13 +103,23 @@ func (j *JSONPath) FindResults(data interface{}) ([][]reflect.Value, error) {
if j.beginRange > 0 {
j.beginRange--
j.inRange++
for _, value := range results {
if len(results) > 0 {
for _, value := range results {
j.parser.Root.Nodes = nodes[i+1:]
nextResults, err := j.FindResults(value.Interface())
if err != nil {
return nil, err
}
fullResult = append(fullResult, nextResults...)
}
} else {
// If the range has no results, we still need to process the nodes within the range
// so the position will advance to the end node
j.parser.Root.Nodes = nodes[i+1:]
nextResults, err := j.FindResults(value.Interface())
_, err := j.FindResults(nil)
if err != nil {
return nil, err
}
fullResult = append(fullResult, nextResults...)
}
j.inRange--

View File

@@ -263,6 +263,8 @@ func TestStructInput(t *testing.T) {
{"allarray", "{.Book[*].Author}", storeData, "Nigel Rees Evelyn Waugh Herman Melville", false},
{"allfields", `{range .Bicycle[*]}{ "{" }{ @.* }{ "} " }{end}`, storeData, "{red 19.95 true} {green 20.01 false} ", false},
{"recurfields", "{..Price}", storeData, "8.95 12.99 8.99 19.95 20.01", false},
{"recurdotfields", "{...Price}", storeData, "8.95 12.99 8.99 19.95 20.01", false},
{"superrecurfields", "{............................................................Price}", storeData, "", true},
{"allstructsSlice", "{.Bicycle}", storeData,
`[{"Color":"red","Price":19.95,"IsNew":true},{"Color":"green","Price":20.01,"IsNew":false}]`, false},
{"allstructs", `{range .Bicycle[*]}{ @ }{ " " }{end}`, storeData,
@@ -391,6 +393,21 @@ func TestKubernetes(t *testing.T) {
testJSONPathSortOutput(randomPrintOrderTests, t)
}
func TestEmptyRange(t *testing.T) {
var input = []byte(`{"items":[]}`)
var emptyList interface{}
err := json.Unmarshal(input, &emptyList)
if err != nil {
t.Error(err)
}
tests := []jsonpathTest{
{"empty range", `{range .items[*]}{.metadata.name}{end}`, &emptyList, "", false},
{"empty nested range", `{range .items[*]}{.metadata.name}{":"}{range @.spec.containers[*]}{.name}{","}{end}{"+"}{end}`, &emptyList, "", false},
}
testJSONPath(tests, true, t)
}
func TestNestedRanges(t *testing.T) {
var input = []byte(`{
"items": [

View File

@@ -214,8 +214,11 @@ func (p *Parser) parseIdentifier(cur *ListNode) error {
return p.parseInsideAction(cur)
}
// parseRecursive scans the recursive desent operator ..
// parseRecursive scans the recursive descent operator ..
func (p *Parser) parseRecursive(cur *ListNode) error {
if lastIndex := len(cur.Nodes) - 1; lastIndex >= 0 && cur.Nodes[lastIndex].Type() == NodeRecursive {
return fmt.Errorf("invalid multiple recursive descent")
}
p.pos += len("..")
p.consumeText()
cur.append(newRecursive())

View File

@@ -141,6 +141,7 @@ func TestFailParser(t *testing.T) {
{"invalid number", "{+12.3.0}", "cannot parse number +12.3.0"},
{"unterminated array", "{[1}", "unterminated array"},
{"unterminated filter", "{[?(.price]}", "unterminated filter"},
{"invalid multiple recursive descent", "{........}", "invalid multiple recursive descent"},
}
for _, test := range failParserTests {
_, err := Parse(test.name, test.text)