Compare commits

..

101 Commits

Author SHA1 Message Date
Kubernetes Publisher
347e4def6c Fix dependencies to point to kubernetes-1.17.0-alpha.2 tag 2019-10-15 14:59:58 +00:00
Kubernetes Publisher
bd505ee787 Merge pull request #83785 from yastij/bump-utils-rangesize
bump k8s.io/utils to pickup bug fix for rangesize func

Kubernetes-commit: 677903edc6cfe1fb045a55b0734ee05ce8c3d03c
2019-10-14 07:06:54 +00:00
Yassine TIJANI
5462db5944 bump k8s.io/utils to pickup bug fix for rangesize
Signed-off-by: Yassine TIJANI <ytijani@vmware.com>

Kubernetes-commit: 5d49cbd3cae68d7aafdeac7f2ca08208118f09ad
2019-10-11 16:45:21 +02:00
Mengjiang Bao
c51c673cf8 chore(*): update election example (#82821)
* feat(*): simplify leader election example

* chore(*): fix with comment

* chore(*): add os.exit

* chore(*): fix typo

Kubernetes-commit: 1185012da65edf802f22aff24141c0466a2a3ac8
2019-10-14 07:06:53 +00:00
Kubernetes Publisher
172b42569c Merge pull request #82652 from ricardomaraschini/request-construction-error
Clean up dynamic client pre-flight check

Kubernetes-commit: 5ae180cb53c0c63bdba72cb94f8356357f94c28c
2019-10-10 20:00:49 +00:00
Kubernetes Publisher
e318746e79 Merge pull request #83615 from yutedz/evt-receiver-name
Use consistent short name for receivers

Kubernetes-commit: 9b200ae4c3a4585edd43a2111a45e57024083ed9
2019-10-09 23:58:30 +00:00
Ted Yu
9be50f2e07 Use consistent short name for receivers
Kubernetes-commit: 21b11c2b6434f949299f85a12c535bfd169c2cf3
2019-10-08 09:08:52 -07:00
Kubernetes Publisher
1210218b4a Merge pull request #83489 from yutedz/brocaster-shutdown
Expose Shutdown func for EventBroadcaster

Kubernetes-commit: 0a9ef994eb40ac0c9bb51ee87b0d494f0bc5393a
2019-10-08 11:58:22 +00:00
Ted Yu
c4ea3eed4f Expose Shutdown func for EventBroadcaster
Kubernetes-commit: 57d43e4946f352f075b219b0a2f35942b06cfeb9
2019-10-07 08:58:38 -07:00
Kubernetes Publisher
911ef75fbc Merge pull request #83106 from jfbai/cleanup-v1-event-expansion
refactor: v1 event expansion.

Kubernetes-commit: 2dc5add8b15bbad5de1d721a1967328a7ad5c369
2019-10-07 15:58:14 +00:00
Kubernetes Publisher
c918cd02a1 Merge pull request #83547 from liggitt/override-ca-file
Overriding CA file should override skip TLS and CA data

Kubernetes-commit: 70d453d32df254ef0c3420804c6487a2ba55a5e0
2019-10-06 23:58:18 +00:00
Jordan Liggitt
24302e441b Overriding CA file should override skip TLS and CA data
Kubernetes-commit: 857572168e79430af2dbf05e9d4705dfb3f0d99b
2019-10-06 13:40:21 -04:00
Jianfei Bai
95b72f7306 cleanup v1 event expansion.
Kubernetes-commit: 89b7c63b5d19001c1ea0541ece0d22407aaeb304
2019-10-06 10:10:57 +08:00
Kubernetes Publisher
b1fd789501 Merge pull request #82176 from pohly/ginkgo-stack-fix
Ginkgo update + stack fix

Kubernetes-commit: b140b431073ae4d84ce9ef5e01a1f27058178ead
2019-10-05 11:58:21 +00:00
Kubernetes Publisher
ec28f1ce46 Merge pull request #82371 from deads2k/cert-reload-delegated
add ability to authenticators for dynamic update of certs for delegated authn

Kubernetes-commit: 7ac65858bb9fdf41bb0cf3b257a4943ea8457ed6
2019-10-04 15:58:30 +00:00
Kubernetes Publisher
a746c2f219 Merge pull request #83261 from liggitt/yaml-limits
limit yaml/json decode size

Kubernetes-commit: 4afcba42bed2bb7c36e5209a90d87343f32a0efa
2019-10-03 03:58:59 +00:00
Jordan Liggitt
9c30dbec4d bump gopkg.in/yaml.v2 v2.2.4
Kubernetes-commit: 8aeffa8716dcf986544df74444264ef639d61a7a
2019-10-02 14:46:08 -04:00
Kubernetes Publisher
0ebb3d5f49 Merge pull request #81914 from wojtek-t/cache_serializations_across_watchers
Cache serializations across watchers

Kubernetes-commit: 7878160a9747c0c2d4f2cc16a7401407253d578b
2019-10-01 19:58:19 +00:00
Patrick Ohly
1289614f84 vendor: update gomega to v1.7.0
Updated to keep both Ginkgo and Gomega at the latest releases.

Kubernetes-commit: 27b9a9c2381fab195f2db1bc709e46d0b83fc729
2019-10-01 20:25:05 +02:00
Kubernetes Publisher
ad4f099992 Merge pull request #83071 from chendotjs/bytes-equal
replace bytes.Compare() with bytes.Equal()

Kubernetes-commit: cd95e57c71a194a80064b00a44e42a222003dac8
2019-09-27 20:00:09 +00:00
chenyaqi01
3eb165927d replace bytes.Compare() with bytes.Equal()
Kubernetes-commit: 66be69bb0e7fd147be650385d272ae14ee2857c8
2019-09-27 10:06:50 +08:00
Kubernetes Publisher
95884bf844 Merge pull request #82764 from yaron2/authimportfix
fix auth import statement in client-go

Kubernetes-commit: 5c57ce3058b184dca0fb0379f698bd835336d674
2019-09-26 23:57:51 +00:00
Kubernetes Publisher
1db9859ae8 Merge pull request #81030 from ricky1993/leader_election_migrate
migrate leader election to lease API

Kubernetes-commit: d14943b0fbc311250cd56e7227bc443fb364540d
2019-09-26 15:57:47 +00:00
Kubernetes Publisher
07054768d9 Merge pull request #83113 from yastij/bump-utils
bump k8s.io/utils to pickup ipallocator changes

Kubernetes-commit: 28bcf55accc52dfd4fde5f603a5784c40c485528
2019-09-25 23:57:46 +00:00
Kubernetes Publisher
6ff1103255 Merge pull request #82932 from ashish-billore/mybranch2
Corrected the pod reporting and messages

Kubernetes-commit: 08f46e425baa9e479f0d940b1901ace5a7f5a90a
2019-09-25 19:57:56 +00:00
Kubernetes Publisher
61aeaa97a2 Merge pull request #82388 from marun/unstructured-reflector
Add support for type checking Unstructured event objects via GVK to client-go's reflector

Kubernetes-commit: 0676af36c5658af0319163fe2ed2fecccb43ae02
2019-09-25 19:57:53 +00:00
Kubernetes Publisher
0e97bf0202 Merge pull request #83064 from liggitt/propagate-context
Propagate context to remote authorize/authenticate webhook calls

Kubernetes-commit: 327f53ba57aeaa4b7e7c20b1ef98c42b26b7ea7f
2019-09-25 19:57:52 +00:00
Yassine TIJANI
bec79dc075 bump k8s.io/utils to pickup ipallocator changes
Signed-off-by: Yassine TIJANI <ytijani@vmware.com>

Kubernetes-commit: 16fe4d76271f6330c2837462a40edf95dde95942
2019-09-25 16:15:30 +02:00
Kubernetes Publisher
0df3af31cd Merge pull request #83018 from jfbai/fix-remove-duplicated-field-in-eventKey
fix: remove reportingInstance field in eventKey.

Kubernetes-commit: 0541d0bb79537431421774465721f33fd3b053bc
2019-09-24 15:57:51 +00:00
Jordan Liggitt
18d8747a77 Add context-propagating CreateContext methods to *Review clients
Kubernetes-commit: 4ffa91a388c6dbfd1d3c9f4c8a37b067b9b6a427
2019-09-24 11:02:25 -04:00
Maru Newby
d147ce7d6e Run hack/update-bazel.sh
Kubernetes-commit: 2a836d1710b5a1c1330ff58dad369d6afd2a1185
2019-09-24 01:21:54 +00:00
Maru Newby
ab4e4fccf4 Add support for type checking Unstructured via GVK in reflector
It was previously possible to instantiate `Reflector` with
`*unstructured.Unstructured` as the expected type but this did not
support checking that event objects were of the correct API
type (e.g. if event object was `v1.Pod` in `Unstructured` form but
`v1.Service` was expected). This commit adds support for providing a
GVK via an `Unstructured` expected type to compare with the GVK of
event objects. The GVK will also be used in reflector log output.

Kubernetes-commit: 237dbfd8ad322dfcad4bd4d5345368480c22d82f
2019-09-24 01:20:40 +00:00
Kubernetes Publisher
2bd34d193b Merge pull request #83014 from danielqsj/bump-klog
Bump k8s.io/klog to v1.0.0

Kubernetes-commit: b7003211d5454982401c19705f73bf2820ede855
2019-09-23 15:57:54 +00:00
Jianfei Bai
bc70a20c12 fix: remove reportingInstance field in eventKey.
Kubernetes-commit: 6b17e5e2a48d00946bdf443d9bfaf8a295b344ec
2019-09-23 20:00:16 +08:00
danielqsj
bfc25e7605 Bump k8s.io/klog to v1.0.0
Kubernetes-commit: c2a4906152e67a45308f988aa2cb8b76b4503855
2019-09-23 16:51:43 +08:00
Kubernetes Publisher
bcb3724b2b Merge pull request #82941 from jfbai/docs-add-comments-for-action-arg
docs: add comments for action.

Kubernetes-commit: dda0553dd7849a1b0ed0def6c58b02fc3a695063
2019-09-20 15:57:38 +00:00
Jianfei Bai
a537b01432 docs: add comments for action.
Kubernetes-commit: 993fe6f4bda183e1583cf0f879fbf9a076e99e8a
2019-09-20 21:32:44 +08:00
ashish-billore
6078bde84c Corrected the pod reporting and messages
It is inconsistent and confusing to report pod count from all
namespaces but report message for only default namespace.
Added the namespace (default) reporting to clarify this.
Updated comments for usage clarity.

Kubernetes-commit: 31e427b54c500f2e532ebeb1990eb7580bf86729
2019-09-20 19:18:17 +09:00
Kubernetes Publisher
297c8350f5 Merge pull request #82096 from logicalhan/version-deletion
remove pkg/version and some of redundant copies of it

Kubernetes-commit: 67d928acdc351d3d4f9e20a92cee4452a26ed0c4
2019-09-18 03:58:23 +00:00
Kubernetes Publisher
ecd4f6fb8c Merge pull request #82325 from RainbowMango/pr_cleanupup_staticcheck_for_client_cache
Cleanup staticcheck for package cache

Kubernetes-commit: 41b3e60f0e4032eec2caf38348d82641395f7af6
2019-09-17 07:58:24 +00:00
yaron2
67a52dfbe2 fix auth import statement
Kubernetes-commit: 6b9ec1c59e1965f4253ecb1e8b600bc582780df9
2019-09-16 11:00:36 -07:00
Kubernetes Publisher
6f3bc4ba92 Merge pull request #82585 from wojtek-t/fix_meta_internalversion_codecs
Ensure conversions are registered for metainternalversion codecs

Kubernetes-commit: 4dd1e3fa43e06f1c2fb9c4bd0bce8c821fd8a979
2019-09-13 08:08:25 +00:00
Kubernetes Publisher
26b1e9b529 Merge pull request #82446 from ibuildthecloud/master
Check cache is synced first before sleeping

Kubernetes-commit: ae3b1099ee5d07b1cc4541bedec1ae63e52debf8
2019-09-13 08:08:22 +00:00
Kubernetes Publisher
86c133ba28 Merge pull request #82284 from danwinship/retry-on-conflict-docs
Clarify retry.RetryOnConflict docs

Kubernetes-commit: 8d247629c38228ac18513612024c527f58ed9c57
2019-09-13 08:08:21 +00:00
Ricardo Maraschini
e6a1dc4b13 Creating function for preflight check.
Migrated code that checks for common programmer errors to a separated
function and added test coverage for it. Wrong comment stating that a
typed error is returned was also removed.

Kubernetes-commit: ad5fafd6ade2838098890a4e7727c8e347686867
2019-09-12 19:22:46 +02:00
wojtekt
aebe267284 Ensure conversions are registered for metainternalversion codecs
Kubernetes-commit: 54163527a69a8c868b87d301876559495220d1b0
2019-09-11 16:30:08 +02:00
Han Kang
e0bb139390 remove pkg/version and some of redundant copies of it
Change-Id: Ia58367c1b1274bfb49c8a4784051463abaf795de

Kubernetes-commit: 866ea74326fba45241cbccd3ca4624b68ba7022f
2019-09-10 14:42:55 -07:00
Darren Shepherd
6d3b14b468 Check cache is synced first before sleeping
If a cache was already synced, cache.WaitForCacheSync would
always take 100ms to complete because the PollUntil method will
sleep first before checking the condition.  Switching to
PollImmediateUntil will ensure already synced caches will return
immediately.  For code that has, for example, 20 informers, the time
to check the cache was in sync would take at least 2 seconds, but with
this change it can be as fast as you can actually load the data.

Signed-off-by: Darren Shepherd <darren@rancher.com>

Kubernetes-commit: 8a58f332dd62b68ae22c67585002defe6aeb4b04
2019-09-06 16:30:04 -07:00
Kubernetes Publisher
67a413f31a Merge pull request #82425 from liggitt/client-go-readme
Update dev setup and client-go install instructions

Kubernetes-commit: 38752f7f99869ed65fb44378360a517649dc2f83
2019-09-06 19:52:28 +00:00
Jordan Liggitt
4fe1937613 Update client-go install instructions
Kubernetes-commit: df3d143d157c0558ba6b0f642b16697a774ecb94
2019-09-06 11:00:01 -04:00
Kubernetes Prow Robot
9bcaef49c8 Merge pull request #671 from liggitt/go-get-readme
Update README go get commands
2019-09-06 11:10:16 -07:00
Jordan Liggitt
fc74d0f6b3 Update README go get commands 2019-09-06 13:48:41 -04:00
David Eads
a7d8568b02 add ability to authenticators for dynamic update of certs
Kubernetes-commit: 51195dd86012c4c4b17a1707ef50a46fa046f74f
2019-09-05 09:59:59 -04:00
RainbowMango
e990876d88 Cleanup staticcheck from staging/src/k8s.io/client-go/tools/cache.
Kubernetes-commit: 19e5c8565d444cbb81d554a69960d7144996b05a
2019-09-04 18:32:06 +08:00
Dan Winship
9781541482 Clarify retry.RetryOnConflict docs
Kubernetes-commit: 23b391e1dd56e84708ac8c95bf6293fe86879c1c
2019-09-03 12:26:17 -04:00
Dan Winship
0e80a77286 Restore retry.RetryOnConflict docs, fix up retry.OnError docs/naming
Kubernetes-commit: b098e013242be8b480340d30063388b0020ae32e
2019-09-06 06:33:34 -04:00
Kubernetes Publisher
3fe2abece8 Merge pull request #77354 from jennybuckley/crd-apply
Use CRD validation field in server-side apply

Kubernetes-commit: ab162cd28c332d0ecfb4f918d5f91e9e57acdb61
2019-08-31 07:49:46 +00:00
Patrick Ohly
7f988d725c e2e log: Ginkgo 1.10.1 fixes stack skip
Now Ginkgo properly skips the initial stack entry.

Kubernetes-commit: ecd7ae55bc3ceda761f4405764815f70d38e3b2c
2019-08-30 17:58:48 +02:00
Kubernetes Publisher
d4d906eb58 Merge pull request #82090 from liggitt/webhook-http2
Use http/1.1 for apiserver->webhook clients

Kubernetes-commit: f442b6ef320140730f544527597a140e535f1e1d
2019-08-30 15:49:49 +00:00
Kubernetes Publisher
326ca7a019 Merge pull request #81770 from Hyzhou/fix_link
Fix broken link to api-conventions doc.

Kubernetes-commit: a9f0db16614ae62563ead2018f1692407bd93d8f
2019-08-30 03:49:49 +00:00
jennybuckley
cb7b787fa1 Update generated
Kubernetes-commit: badd5b9a26026138e4fc44a643ec1c6b65a7891b
2019-08-29 19:10:28 -07:00
Kubernetes Publisher
065c7aba1f Merge pull request #81947 from RainbowMango/pr_cleanup_staticcheck_for_client_p1
Cleanup client-go static analysis issues-phase 1

Kubernetes-commit: b131b4b4caa8f47df867174ac1eff251c5ad8328
2019-08-29 15:52:11 +00:00
misakazhou
325de63e79 Fix broken link to api-conventions doc.
Signed-off-by: misakazhou <misakazhou@tencent.com>

Kubernetes-commit: f0323a2030c7adae0e0965a7d3b455dd416472a0
2019-08-29 08:35:16 +08:00
Kubernetes Publisher
8248d0a0e6 Merge pull request #80766 from robscott/discovery-api
Adding Discovery API for EndpointSlice

Kubernetes-commit: 6c9f26ca3ab8656673f0f0b05097bdf7e8fbd911
2019-08-28 23:51:40 +00:00
Jordan Liggitt
696c159e45 Plumb NextProtos to TLS client config, honor http/2 client preference
Kubernetes-commit: aef05c8dca2c1a9967ebd9a2f67a0bf7fb16f079
2019-08-28 09:55:37 -04:00
Kubernetes Publisher
b4d94f0160 Merge pull request #81871 from prameshj/vendor-update
Update vendor k8s-cloud-provider and google API

Kubernetes-commit: 91bec13163b18238a8ed3d9b872cd27b1193077d
2019-08-28 11:49:57 +00:00
Patrick Ohly
33ba610635 e2e log: fix full stacktrace with Ginkgo 1.10.0
Ginkgo 1.10.0 includes the relevant fix for dumping the full stack
(https://github.com/onsi/ginkgo/pull/590), so when using that release
we can simplify the logging unit test.

By changing the skipping, we can avoid the rather volatile util.go
entries. However, that gomega is part of the stack trace still needs
to be fixed in Gingko.

Kubernetes-commit: 02ce619078b1a75e9fa258e101f81af899719e8e
2019-08-27 14:22:46 +02:00
RainbowMango
532b6f676e Cleanup staticcheck issues for package in client-go.
Kubernetes-commit: c8c055b3163dd2661b3f9dd1b0ffb718a61aba24
2019-08-26 20:55:32 +08:00
Pavithra Ramesh
51b2905727 Update vendor k8s-cloud-provider and google API
Ran commands:
hack/pin-dependency.sh github.com/GoogleCloudPlatform/k8s-cloud-provider 27a4ced34534a6c32b63159b100ac0efaa1d37b3
hack/update-vendor.sh

hack/pin-dependency.sh google.golang.org/api 5213b809086156e6e2b262a41394993fcff97439
hack/update-vendor.sh

hack/verify-vendor.sh

merge conflicts

Kubernetes-commit: ce3b145e7369da6c1179346a4e6f4f9992d235b7
2019-08-23 15:51:45 -07:00
Kubernetes Publisher
15739c3f80 Merge pull request #81527 from yastij/move-controller-util
move WaitForCacheSync to the sharedInformer package

Kubernetes-commit: 927f45191ef34012c890a17a4e77fdbe0f12de94
2019-08-27 11:49:28 +00:00
Kubernetes Publisher
6ddd067b15 Merge pull request #81889 from tedyu/ctrl-rm-refl-mutex
Utilize reflectorMutex in LastSyncResourceVersion

Kubernetes-commit: 9a5dc8f082cc7163e93f773d433e4719282837bb
2019-08-26 23:49:19 +00:00
Ted Yu
541253da74 Utilize reflectorMutex in LastSyncResourceVersion
Kubernetes-commit: 4f54538ae8ff7a4e6829bea1479194af87b7833c
2019-08-26 07:46:26 -07:00
Kubernetes Publisher
cc5a7c7149 Merge pull request #81507 from eloyekunle/fix/scale-client
update scale client to support non-namespaced resources

Kubernetes-commit: a118e59912ebf3fc6bd79e580048ae6fac7a7431
2019-08-26 11:53:23 +00:00
Kubernetes Publisher
597bab4578 Merge pull request #81780 from yastij/fix-nil-panic
check that the recorded event is not nil on refreshExistingEventSeries

Kubernetes-commit: ab7c4a7c3767447cfdee10dc59996836858f764f
2019-08-26 11:53:22 +00:00
Kubernetes Publisher
9fc8bb16d6 Merge pull request #81768 from wojtek-t/cleanup_serializers
Remove dead code

Kubernetes-commit: 2cbe49e84925b44803c451d3ab48dabf9d5e7973
2019-08-26 11:53:21 +00:00
Elijah Oyekunle
5c0e283ed8 update scale client to support non-namespaced resources
Kubernetes-commit: fcd44b44cadef56e9782dcc875f5572cbc43b018
2019-08-23 10:50:45 +01:00
Kubernetes Publisher
cdbd92c111 Merge pull request #81634 from likakuli/fix_errno
fixes a bug that connection refused error cannot be recognized correctly

Kubernetes-commit: 22a8bcf30af52d87a0289bb705ff5c41aaf6f72a
2019-08-23 01:28:14 +00:00
Yassine TIJANI
72094bc6d5 check that the recorded event is not nil on refreshExistingEventSeries
Signed-off-by: Yassine TIJANI <ytijani@vmware.com>

Kubernetes-commit: 000c2c557f862270ec83341c1af3fcd7c6f7d4a2
2019-08-22 11:56:35 +01:00
wojtekt
bac0f5a6c7 Remove dead code
Kubernetes-commit: b1675717168826c3314bf5b7e28c282f9643eadf
2019-08-22 08:58:45 +02:00
Kubernetes Publisher
f4e58ce609 Merge pull request #71757 from mikedanese/fixcancel
implement request cancellation in token transport

Kubernetes-commit: bc1d8c6d61078269540f807248a455cba09e672c
2019-08-22 05:39:41 +00:00
Kubernetes Publisher
c8dc69f8a8 Merge pull request #81189 from tallclair/staticcheck-verify
Add verify-staticcheck script

Kubernetes-commit: 39c10d1550d63a4a5c585600507ffd6a0f157267
2019-08-20 10:14:07 +00:00
likakuli
6a1fb71239 fixes a bug that connection refused error cannot be recognized correctly
Kubernetes-commit: 3cec9098020ecc168573c7ee658282954dac2a2e
2019-08-20 12:18:46 +08:00
Yassine TIJANI
7ee6383729 move WaitForCacheSync to the sharedInformer package
Signed-off-by: Yassine TIJANI <ytijani@vmware.com>

Kubernetes-commit: 7e4c3096fe71afc6a23c273b3309ed5db7289d8c
2019-08-16 21:15:53 +02:00
wojtekt
33fd3701cd Implement Encoder.Identifier() method
Kubernetes-commit: cd4215ad8b95773a793f69fc2e8bf93c7ede97aa
2019-08-14 16:23:03 +02:00
Tim Allclair
8355a02ca7 Bump golang.org/x/tools version for staticcheck compat
Kubernetes-commit: 9a02ef7fe5eb166a53131c52b59844179c4158e9
2019-08-08 11:04:56 -07:00
Kubernetes Publisher
6de8fdd410 Merge pull request #79574 from justaugustus/azure-sdk-bump
Azure SDK updates (6/30/19)

Kubernetes-commit: 1ff4525a29f1736fca19e10b49e42664b29010c2
2019-08-16 10:13:43 +00:00
Stephen Augustus
cca417f1ca Update Azure/azure-sdk-for-go and Azure/go-autorest modules
Signed-off-by: Stephen Augustus <saugustus@vmware.com>

Kubernetes-commit: db855f9ba0ced2303fbb3b9776dd2a0d78b31897
2019-08-15 17:57:49 -04:00
Kubernetes Publisher
e290f153d1 Merge pull request #81394 from cblecker/golang-deps
Update golang/x/net dependency

Kubernetes-commit: 1f6cb3cb9def97320a5412dcbea1661edd95c29e
2019-08-14 10:16:25 +00:00
Kubernetes Publisher
92cf7d1eaf Merge pull request #81331 from tariq1890/tst_typo
[k8s.io/client-go]fix typo in eventseries_test.go method

Kubernetes-commit: a520302fb4673e595fcb70d2a4db26598371be92
2019-08-14 06:10:25 +00:00
Kubernetes Publisher
1ca6f0db2b Merge pull request #81330 from tedyu/hide-auth-hdr
Hide bearer token in logs

Kubernetes-commit: 4441f1d9c3e94d9a3d93b4f184a591cab02a5245
2019-08-14 06:10:24 +00:00
Christoph Blecker
d522c037ae Update vendor
Kubernetes-commit: 5f971d6d8862de319edbd24a729a704292c560dc
2019-08-13 17:51:45 -07:00
Christoph Blecker
17815e944e Pin golang.org/x/net to cdfb69a
Kubernetes-commit: ebadc53f50219112c3d80039de7b13779f9d4f63
2019-08-13 17:45:53 -07:00
Kubernetes Publisher
7eecfc25a0 Merge pull request #81305 from tedyu/evt-patch-err
Error code incorrectly hidden in recordEvent

Kubernetes-commit: f22b67dd8f9f4c1ce7434a6432e4f952ef36ea32
2019-08-13 22:10:22 +00:00
Kubernetes Publisher
48bc0598fd Merge pull request #81164 from dims/update-to-latest-klog-0.4.0
Update to latest klog 0.4.0

Kubernetes-commit: 461b2d8b9ae818b4b08a6c74d2ec6048fe7a52b6
2019-08-13 22:10:21 +00:00
Ted Yu
689d090711 Hide bearer token in logs
Kubernetes-commit: 010d8382642119c73cb2405286b347c08d704287
2019-08-13 09:36:13 -07:00
Tariq Ibrahim
31cdc04542 Address review comments
Kubernetes-commit: 805640382339f646a175f04f9e4846d5bf2ef61f
2019-08-13 09:07:39 -07:00
tariqibrahim
8ade4cae05 [k8s.io/client-go]fix typo in eventseries_test.go method
Kubernetes-commit: 06e1b38768ba243d29dcc6a3fe51381d2624a62f
2019-08-12 21:16:23 -07:00
Ted Yu
cde59a28d7 Error code incorrectly hidden in recordEvent
Kubernetes-commit: 31f374f42a2c816c8fb928c5db46474f5fc24b31
2019-08-12 12:11:37 -07:00
chenyixiang
ba49d2a180 migrate leader election to lease API
Change-Id: I21fd5cdc1af59e456628cf15fc84b2d79db2eda0

Kubernetes-commit: 447295aff2bd8cdc92a2376553d83546a4d6eb41
2019-08-07 01:48:32 +08:00
Rob Scott
1ff77877ed Adding discovery/v1alpha1 API for EndpointSlices
Kubernetes-commit: f80cee928040ad458fbced70392063e0a5d160e5
2019-07-30 12:48:34 -07:00
Mike Danese
cdbf1c4b62 implement request cancellation in token transport
Kubernetes-commit: a42e029e6905bee5b9d5489610c4fbe5988eeac6
2018-12-05 12:36:48 -08:00
56 changed files with 1380 additions and 374 deletions

38
Godeps/Godeps.json generated
View File

@@ -164,7 +164,7 @@
},
{
"ImportPath": "github.com/gregjones/httpcache",
"Rev": "9cad4c3443a7"
"Rev": "787624de3eb7"
},
{
"ImportPath": "github.com/hashicorp/golang-lru",
@@ -228,11 +228,11 @@
},
{
"ImportPath": "github.com/onsi/ginkgo",
"Rev": "v1.8.0"
"Rev": "v1.10.1"
},
{
"ImportPath": "github.com/onsi/gomega",
"Rev": "v1.5.0"
"Rev": "v1.7.0"
},
{
"ImportPath": "github.com/peterbourgon/diskv",
@@ -248,7 +248,7 @@
},
{
"ImportPath": "github.com/spf13/pflag",
"Rev": "v1.0.5"
"Rev": "v1.0.3"
},
{
"ImportPath": "github.com/stretchr/objx",
@@ -264,7 +264,7 @@
},
{
"ImportPath": "golang.org/x/crypto",
"Rev": "60c769a6c586"
"Rev": "e84da0312774"
},
{
"ImportPath": "golang.org/x/exp",
@@ -272,39 +272,35 @@
},
{
"ImportPath": "golang.org/x/lint",
"Rev": "5614ed5bae6f"
"Rev": "8f45f776aaf1"
},
{
"ImportPath": "golang.org/x/net",
"Rev": "13f9640d40b9"
"Rev": "cdfb69ac37fc"
},
{
"ImportPath": "golang.org/x/oauth2",
"Rev": "0f29369cfe45"
"Rev": "9f3314589c9a"
},
{
"ImportPath": "golang.org/x/sync",
"Rev": "112230192c58"
"Rev": "42b317875d0f"
},
{
"ImportPath": "golang.org/x/sys",
"Rev": "fde4db37ae7a"
"Rev": "3b5209105503"
},
{
"ImportPath": "golang.org/x/text",
"Rev": "v0.3.2"
"Rev": "e6919f6577db"
},
{
"ImportPath": "golang.org/x/time",
"Rev": "9d24e82272b4"
"Rev": "f51c12702a4d"
},
{
"ImportPath": "golang.org/x/tools",
"Rev": "65e3620a7ae7"
},
{
"ImportPath": "golang.org/x/xerrors",
"Rev": "a985d3407aa7"
"Rev": "e65039ee4138"
},
{
"ImportPath": "google.golang.org/api",
@@ -332,7 +328,7 @@
},
{
"ImportPath": "gopkg.in/inf.v0",
"Rev": "v0.9.1"
"Rev": "v0.9.0"
},
{
"ImportPath": "gopkg.in/tomb.v1",
@@ -348,11 +344,11 @@
},
{
"ImportPath": "k8s.io/api",
"Rev": "v0.16.7-beta.0"
"Rev": "35675025e55c"
},
{
"ImportPath": "k8s.io/apimachinery",
"Rev": "v0.16.7-beta.0"
"Rev": "fb3eea214746"
},
{
"ImportPath": "k8s.io/gengo",
@@ -368,7 +364,7 @@
},
{
"ImportPath": "k8s.io/utils",
"Rev": "581e00157fb1"
"Rev": "8d271d903fe4"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff",

View File

@@ -2,9 +2,9 @@
Go clients for talking to a [kubernetes](http://kubernetes.io/) cluster.
We currently recommend using the v12.0.0 tag. See [INSTALL.md](/INSTALL.md) for
detailed installation instructions. `go get k8s.io/client-go/...` works, but
will build `master`, which doesn't handle the dependencies well.
We recommend using the `kubernetes-1.x.y` tag matching the current Kubernetes release (`kubernetes-1.15.3` at the time this was written).
See [INSTALL.md](/INSTALL.md) for detailed installation instructions.
`go get k8s.io/client-go@master` works, but will fetch `master`, which may be less stable than a tagged release.
[![BuildStatus Widget]][BuildStatus Result]
[![GoReport Widget]][GoReport Status]
@@ -164,8 +164,8 @@ This repository is still a mirror of
the code development is still done in the staging area. Since Kubernetes 1.8
release, when syncing the code from the staging area, we also sync the Kubernetes
version tags to client-go, prefixed with "kubernetes-". For example, if you check
out the `kubernetes-v1.8.0` tag in client-go, the code you get is exactly the
same as if you check out the `v1.8.0` tag in kubernetes, and change directory to
out the `kubernetes-1.15.3` tag in client-go, the code you get is exactly the
same as if you check out the `v1.15.3` tag in Kubernetes, and change directory to
`staging/src/k8s.io/client-go`. The purpose is to let users quickly find matching
commits among published repos, like
[sample-apiserver](https://github.com/kubernetes/sample-apiserver),
@@ -176,10 +176,13 @@ you care about backwards compatibility.
### How to get it
You can use `go get k8s.io/client-go/...` to get client-go, but **you will get
the unstable master branch** and `client-go`'s vendored dependencies will not be
added to your `$GOPATH`. So we think most users will want to use a dependency
management system. See [INSTALL.md](/INSTALL.md) for detailed instructions.
Use go1.11+ and fetch the desired version using the `go get` command. For example:
```
go get k8s.io/client-go@kubernetes-1.15.3
```
See [INSTALL.md](/INSTALL.md) for detailed instructions.
### How to use it

View File

@@ -33,7 +33,7 @@ import (
"k8s.io/client-go/util/retry"
//
// Uncomment to load all auth plugins
// _ "k8s.io/client-go/plugin/pkg/client/auth
// _ "k8s.io/client-go/plugin/pkg/client/auth"
//
// Or uncomment to load specific auth plugins
// _ "k8s.io/client-go/plugin/pkg/client/auth/azure"

View File

@@ -34,7 +34,7 @@ import (
"k8s.io/client-go/util/retry"
//
// Uncomment to load all auth plugins
// _ "k8s.io/client-go/plugin/pkg/client/auth
// _ "k8s.io/client-go/plugin/pkg/client/auth"
//
// Or uncomment to load specific auth plugins
// _ "k8s.io/client-go/plugin/pkg/client/auth/azure"

View File

@@ -27,7 +27,7 @@ import (
"k8s.io/client-go/rest"
//
// Uncomment to load all auth plugins
// _ "k8s.io/client-go/plugin/pkg/client/auth
// _ "k8s.io/client-go/plugin/pkg/client/auth"
//
// Or uncomment to load specific auth plugins
// _ "k8s.io/client-go/plugin/pkg/client/auth/azure"
@@ -48,6 +48,8 @@ func main() {
panic(err.Error())
}
for {
// get pods in all the namespaces by omitting namespace
// Or specify namespace to get pods in particular namespace
pods, err := clientset.CoreV1().Pods("").List(metav1.ListOptions{})
if err != nil {
panic(err.Error())
@@ -55,17 +57,17 @@ func main() {
fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))
// Examples for error handling:
// - Use helper functions like e.g. errors.IsNotFound()
// - Use helper functions e.g. errors.IsNotFound()
// - And/or cast to StatusError and use its properties like e.g. ErrStatus.Message
_, err = clientset.CoreV1().Pods("default").Get("example-xxxxx", metav1.GetOptions{})
if errors.IsNotFound(err) {
fmt.Printf("Pod not found\n")
fmt.Printf("Pod example-xxxxx not found in default namespace\n")
} else if statusError, isStatus := err.(*errors.StatusError); isStatus {
fmt.Printf("Error getting pod %v\n", statusError.ErrStatus.Message)
} else if err != nil {
panic(err.Error())
} else {
fmt.Printf("Found pod\n")
fmt.Printf("Found example-xxxxx pod in default namespace\n")
}
time.Sleep(10 * time.Second)

View File

@@ -7,15 +7,16 @@ This example demonstrates how to use the leader election package.
Run the following three commands in separate terminals. Each terminal needs a unique `id`.
```bash
# first terminal
go run *.go -kubeconfig=/my/config -logtostderr=true -id=1
# first terminal
go run main.go -kubeconfig=/path/to/kubeconfig -logtostderr=true -lease-lock-name=example -lease-lock-namespace=default -id=1
# second terminal
go run *.go -kubeconfig=/my/config -logtostderr=true -id=2
# second terminal
go run main.go -kubeconfig=/path/to/kubeconfig -logtostderr=true -lease-lock-name=example -lease-lock-namespace=default -id=2
# third terminal
go run *.go -kubeconfig=/my/config -logtostderr=true -id=3
go run main.go -kubeconfig=/path/to/kubeconfig -logtostderr=true -lease-lock-name=example -lease-lock-namespace=default -id=3
```
> You can ignore the `-kubeconfig` flag if you are running these commands in the Kubernetes cluster.
Now kill the existing leader. You will see from the terminal outputs that one of the remaining two processes will be elected as the new leader.

View File

@@ -19,21 +19,18 @@ package main
import (
"context"
"flag"
"fmt"
"log"
"os"
"os/signal"
"strings"
"syscall"
"time"
"github.com/google/uuid"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clientset "k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/leaderelection"
"k8s.io/client-go/tools/leaderelection/resourcelock"
"k8s.io/client-go/transport"
"k8s.io/klog"
)
@@ -62,13 +59,16 @@ func main() {
var id string
flag.StringVar(&kubeconfig, "kubeconfig", "", "absolute path to the kubeconfig file")
flag.StringVar(&id, "id", "", "the holder identity name")
flag.StringVar(&leaseLockName, "lease-lock-name", "example", "the lease lock resource name")
flag.StringVar(&leaseLockNamespace, "lease-lock-namespace", "default", "the lease lock resource namespace")
flag.StringVar(&id, "id", uuid.New().String(), "the holder identity name")
flag.StringVar(&leaseLockName, "lease-lock-name", "", "the lease lock resource name")
flag.StringVar(&leaseLockNamespace, "lease-lock-namespace", "", "the lease lock resource namespace")
flag.Parse()
if id == "" {
klog.Fatal("unable to get id (missing id flag).")
if leaseLockName == "" {
klog.Fatal("unable to get lease lock resource name (missing lease-lock-name flag).")
}
if leaseLockNamespace == "" {
klog.Fatal("unable to get lease lock resource namespace (missing lease-lock-namespace flag).")
}
// leader election uses the Kubernetes API by writing to a
@@ -82,6 +82,29 @@ func main() {
}
client := clientset.NewForConfigOrDie(config)
run := func(ctx context.Context) {
// complete your controller loop here
klog.Info("Controller loop...")
select {}
}
// use a Go context so we can tell the leaderelection code when we
// want to step down
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// listen for interrupts or the Linux SIGTERM signal and cancel
// our context, which the leader election code will observe and
// step down
ch := make(chan os.Signal, 1)
signal.Notify(ch, os.Interrupt, syscall.SIGTERM)
go func() {
<-ch
klog.Info("Received termination, signaling shutdown")
cancel()
}()
// we use the Lease lock type since edits to Leases are less common
// and fewer objects in the cluster watch "all Leases".
lock := &resourcelock.LeaseLock{
@@ -95,25 +118,6 @@ func main() {
},
}
// use a Go context so we can tell the leaderelection code when we
// want to step down
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// use a client that will stop allowing new requests once the context ends
config.Wrap(transport.ContextCanceller(ctx, fmt.Errorf("the leader is shutting down")))
// listen for interrupts or the Linux SIGTERM signal and cancel
// our context, which the leader election code will observe and
// step down
ch := make(chan os.Signal, 1)
signal.Notify(ch, os.Interrupt, syscall.SIGTERM)
go func() {
<-ch
log.Printf("Received termination, signaling shutdown")
cancel()
}()
// start the leader election code loop
leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{
Lock: lock,
@@ -131,12 +135,12 @@ func main() {
OnStartedLeading: func(ctx context.Context) {
// we're notified when we start - this is where you would
// usually put your code
klog.Infof("%s: leading", id)
run(ctx)
},
OnStoppedLeading: func() {
// we can do cleanup here, or after the RunOrDie method
// returns
klog.Infof("%s: lost", id)
// we can do cleanup here
klog.Infof("leader lost: %s", id)
os.Exit(0)
},
OnNewLeader: func(identity string) {
// we're notified when new leader elected
@@ -144,18 +148,8 @@ func main() {
// I just got the lock
return
}
klog.Infof("new leader elected: %v", identity)
klog.Infof("new leader elected: %s", identity)
},
},
})
// because the context is closed, the client should report errors
_, err = client.CoordinationV1().Leases(leaseLockNamespace).Get(leaseLockName, metav1.GetOptions{})
if err == nil || !strings.Contains(err.Error(), "the leader is shutting down") {
log.Fatalf("%s: expected to get an error when trying to make a client call: %v", id, err)
}
// we no longer hold the lease, so perform any cleanup and then
// exit
log.Printf("%s: done", id)
}

29
go.mod
View File

@@ -14,27 +14,34 @@ require (
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903
github.com/golang/protobuf v1.3.1
github.com/google/gofuzz v1.0.0
github.com/google/uuid v1.1.1
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d
github.com/gophercloud/gophercloud v0.1.0
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7
github.com/imdario/mergo v0.3.5
github.com/peterbourgon/diskv v2.0.1+incompatible
github.com/spf13/pflag v1.0.5
github.com/spf13/pflag v1.0.3
github.com/stretchr/testify v1.3.0
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8
golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c
google.golang.org/appengine v1.5.0 // indirect
k8s.io/api v0.16.7-beta.0
k8s.io/apimachinery v0.16.7-beta.0
k8s.io/api v0.0.0-20191015145727-35675025e55c
k8s.io/apimachinery v0.0.0-20191014065749-fb3eea214746
k8s.io/klog v1.0.0
k8s.io/utils v0.0.0-20190801114015-581e00157fb1
k8s.io/utils v0.0.0-20191010214722-8d271d903fe4
sigs.k8s.io/yaml v1.1.0
)
replace (
golang.org/x/tools => golang.org/x/tools v0.0.0-20190821162956-65e3620a7ae7
k8s.io/api => k8s.io/api v0.16.7-beta.0
k8s.io/apimachinery => k8s.io/apimachinery v0.16.7-beta.0
golang.org/x/crypto => golang.org/x/crypto v0.0.0-20181025213731-e84da0312774
golang.org/x/lint => golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1
golang.org/x/oauth2 => golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a
golang.org/x/sync => golang.org/x/sync v0.0.0-20181108010431-42b317875d0f
golang.org/x/sys => golang.org/x/sys v0.0.0-20190209173611-3b5209105503
golang.org/x/text => golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db
golang.org/x/time => golang.org/x/time v0.0.0-20161028155119-f51c12702a4d
k8s.io/api => k8s.io/api v0.0.0-20191015145727-35675025e55c
k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20191014065749-fb3eea214746
)

84
go.sum
View File

@@ -64,14 +64,15 @@ github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/gophercloud/gophercloud v0.1.0 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o=
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7 h1:6TSoaYExHper8PYsJu23GWVNOyYRCSnIFyxKgLSZ54w=
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
@@ -104,11 +105,11 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
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/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -116,21 +117,17 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 h1:7KByu05hhLed2MO29w7p1XfZvZ13m8mub3shuVftRs0=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774 h1:a4tQYYYuK9QdeO/+kEvNYyuR21S+7ve5EANok6hABhI=
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -138,37 +135,24 @@ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
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 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc h1:gkKoSkUmnU6bpS/VhkuO27bzQeSA51uaEfbOW5dNb68=
golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA=
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190209173611-3b5209105503 h1:5SvYFrOM3W8Mexn9/oA44Ji7vhXAZQ9hiP+1Q/DMrWg=
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
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=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20190821162956-65e3620a7ae7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db h1:6/JqlYfC1CCaLnGceQTI+sDGhC9UBSPAsBqI0Gun6kU=
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20161028155119-f51c12702a4d h1:TnM+PKb3ylGmZvyPXmo9m/wktg7Jn/a/fNmr33HSj8g=
golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -184,8 +168,8 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/inf.v0 v0.9.0 h1:3zYtXIO92bvsdS3ggAdA8Gb4Azj0YU+TVY1uGYNFA8o=
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
@@ -196,8 +180,8 @@ gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.16.7-beta.0/go.mod h1:1ounEZgA7a1bg3T+IedYGcKQ++xHw2QzjR9Ngo5XhHU=
k8s.io/apimachinery v0.16.7-beta.0/go.mod h1:mhhO3hoLkWO+2eCvqjPtH2Ly92l9nJDwsswzWKpkN2w=
k8s.io/api v0.0.0-20191015145727-35675025e55c/go.mod h1:QkEbiSvETjiF869vsgCmJAUDD1VVz6Ut0ULyQP6ivY4=
k8s.io/apimachinery v0.0.0-20191014065749-fb3eea214746/go.mod h1:92mWDd8Ji2sw2157KIgino5wCxffA8KSvhW2oY4ypdw=
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
@@ -205,8 +189,8 @@ k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf h1:EYm5AW/UUDbnmnI+gK0TJDVK9qPLhM+sRHYanNKw0EQ=
k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
k8s.io/utils v0.0.0-20190801114015-581e00157fb1 h1:+ySTxfHnfzZb9ys375PXNlLhkJPLKgHajBU0N62BDvE=
k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
k8s.io/utils v0.0.0-20191010214722-8d271d903fe4 h1:Gi+/O1saihwDqnlmC8Vhv1M5Sp4+rbOmK9TbsLn8ZEA=
k8s.io/utils v0.0.0-20191010214722-8d271d903fe4/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=

View File

@@ -17,11 +17,17 @@ limitations under the License.
package fake
import (
"context"
authenticationapi "k8s.io/api/authentication/v1"
core "k8s.io/client-go/testing"
)
func (c *FakeTokenReviews) Create(tokenReview *authenticationapi.TokenReview) (result *authenticationapi.TokenReview, err error) {
return c.CreateContext(context.Background(), tokenReview)
}
func (c *FakeTokenReviews) CreateContext(ctx context.Context, tokenReview *authenticationapi.TokenReview) (result *authenticationapi.TokenReview, err error) {
obj, err := c.Fake.Invokes(core.NewRootCreateAction(authenticationapi.SchemeGroupVersion.WithResource("tokenreviews"), tokenReview), &authenticationapi.TokenReview{})
return obj.(*authenticationapi.TokenReview), err
}

View File

@@ -17,16 +17,24 @@ limitations under the License.
package v1
import (
"context"
authenticationapi "k8s.io/api/authentication/v1"
)
type TokenReviewExpansion interface {
Create(tokenReview *authenticationapi.TokenReview) (result *authenticationapi.TokenReview, err error)
CreateContext(ctx context.Context, tokenReview *authenticationapi.TokenReview) (result *authenticationapi.TokenReview, err error)
}
func (c *tokenReviews) Create(tokenReview *authenticationapi.TokenReview) (result *authenticationapi.TokenReview, err error) {
return c.CreateContext(context.Background(), tokenReview)
}
func (c *tokenReviews) CreateContext(ctx context.Context, tokenReview *authenticationapi.TokenReview) (result *authenticationapi.TokenReview, err error) {
result = &authenticationapi.TokenReview{}
err = c.client.Post().
Context(ctx).
Resource("tokenreviews").
Body(tokenReview).
Do().

View File

@@ -17,11 +17,17 @@ limitations under the License.
package fake
import (
"context"
authenticationapi "k8s.io/api/authentication/v1beta1"
core "k8s.io/client-go/testing"
)
func (c *FakeTokenReviews) Create(tokenReview *authenticationapi.TokenReview) (result *authenticationapi.TokenReview, err error) {
return c.CreateContext(context.Background(), tokenReview)
}
func (c *FakeTokenReviews) CreateContext(ctx context.Context, tokenReview *authenticationapi.TokenReview) (result *authenticationapi.TokenReview, err error) {
obj, err := c.Fake.Invokes(core.NewRootCreateAction(authenticationapi.SchemeGroupVersion.WithResource("tokenreviews"), tokenReview), &authenticationapi.TokenReview{})
return obj.(*authenticationapi.TokenReview), err
}

View File

@@ -17,16 +17,24 @@ limitations under the License.
package v1beta1
import (
"context"
authenticationapi "k8s.io/api/authentication/v1beta1"
)
type TokenReviewExpansion interface {
Create(tokenReview *authenticationapi.TokenReview) (result *authenticationapi.TokenReview, err error)
CreateContext(ctx context.Context, tokenReview *authenticationapi.TokenReview) (result *authenticationapi.TokenReview, err error)
}
func (c *tokenReviews) Create(tokenReview *authenticationapi.TokenReview) (result *authenticationapi.TokenReview, err error) {
return c.CreateContext(context.Background(), tokenReview)
}
func (c *tokenReviews) CreateContext(ctx context.Context, tokenReview *authenticationapi.TokenReview) (result *authenticationapi.TokenReview, err error) {
result = &authenticationapi.TokenReview{}
err = c.client.Post().
Context(ctx).
Resource("tokenreviews").
Body(tokenReview).
Do().

View File

@@ -17,11 +17,17 @@ limitations under the License.
package fake
import (
"context"
authorizationapi "k8s.io/api/authorization/v1"
core "k8s.io/client-go/testing"
)
func (c *FakeLocalSubjectAccessReviews) Create(sar *authorizationapi.LocalSubjectAccessReview) (result *authorizationapi.LocalSubjectAccessReview, err error) {
return c.CreateContext(context.Background(), sar)
}
func (c *FakeLocalSubjectAccessReviews) CreateContext(ctx context.Context, sar *authorizationapi.LocalSubjectAccessReview) (result *authorizationapi.LocalSubjectAccessReview, err error) {
obj, err := c.Fake.Invokes(core.NewCreateAction(authorizationapi.SchemeGroupVersion.WithResource("localsubjectaccessreviews"), c.ns, sar), &authorizationapi.SubjectAccessReview{})
return obj.(*authorizationapi.LocalSubjectAccessReview), err
}

View File

@@ -17,11 +17,17 @@ limitations under the License.
package fake
import (
"context"
authorizationapi "k8s.io/api/authorization/v1"
core "k8s.io/client-go/testing"
)
func (c *FakeSelfSubjectAccessReviews) Create(sar *authorizationapi.SelfSubjectAccessReview) (result *authorizationapi.SelfSubjectAccessReview, err error) {
return c.CreateContext(context.Background(), sar)
}
func (c *FakeSelfSubjectAccessReviews) CreateContext(ctx context.Context, sar *authorizationapi.SelfSubjectAccessReview) (result *authorizationapi.SelfSubjectAccessReview, err error) {
obj, err := c.Fake.Invokes(core.NewRootCreateAction(authorizationapi.SchemeGroupVersion.WithResource("selfsubjectaccessreviews"), sar), &authorizationapi.SelfSubjectAccessReview{})
return obj.(*authorizationapi.SelfSubjectAccessReview), err
}

View File

@@ -17,11 +17,17 @@ limitations under the License.
package fake
import (
"context"
authorizationapi "k8s.io/api/authorization/v1"
core "k8s.io/client-go/testing"
)
func (c *FakeSelfSubjectRulesReviews) Create(srr *authorizationapi.SelfSubjectRulesReview) (result *authorizationapi.SelfSubjectRulesReview, err error) {
return c.CreateContext(context.Background(), srr)
}
func (c *FakeSelfSubjectRulesReviews) CreateContext(ctx context.Context, srr *authorizationapi.SelfSubjectRulesReview) (result *authorizationapi.SelfSubjectRulesReview, err error) {
obj, err := c.Fake.Invokes(core.NewRootCreateAction(authorizationapi.SchemeGroupVersion.WithResource("selfsubjectrulesreviews"), srr), &authorizationapi.SelfSubjectRulesReview{})
return obj.(*authorizationapi.SelfSubjectRulesReview), err
}

View File

@@ -17,11 +17,17 @@ limitations under the License.
package fake
import (
"context"
authorizationapi "k8s.io/api/authorization/v1"
core "k8s.io/client-go/testing"
)
func (c *FakeSubjectAccessReviews) Create(sar *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReview, err error) {
return c.CreateContext(context.Background(), sar)
}
func (c *FakeSubjectAccessReviews) CreateContext(ctx context.Context, sar *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReview, err error) {
obj, err := c.Fake.Invokes(core.NewRootCreateAction(authorizationapi.SchemeGroupVersion.WithResource("subjectaccessreviews"), sar), &authorizationapi.SubjectAccessReview{})
if obj == nil {
return nil, err

View File

@@ -17,16 +17,24 @@ limitations under the License.
package v1
import (
"context"
authorizationapi "k8s.io/api/authorization/v1"
)
type LocalSubjectAccessReviewExpansion interface {
Create(sar *authorizationapi.LocalSubjectAccessReview) (result *authorizationapi.LocalSubjectAccessReview, err error)
CreateContext(ctx context.Context, sar *authorizationapi.LocalSubjectAccessReview) (result *authorizationapi.LocalSubjectAccessReview, err error)
}
func (c *localSubjectAccessReviews) Create(sar *authorizationapi.LocalSubjectAccessReview) (result *authorizationapi.LocalSubjectAccessReview, err error) {
return c.CreateContext(context.Background(), sar)
}
func (c *localSubjectAccessReviews) CreateContext(ctx context.Context, sar *authorizationapi.LocalSubjectAccessReview) (result *authorizationapi.LocalSubjectAccessReview, err error) {
result = &authorizationapi.LocalSubjectAccessReview{}
err = c.client.Post().
Context(ctx).
Namespace(c.ns).
Resource("localsubjectaccessreviews").
Body(sar).

View File

@@ -17,16 +17,24 @@ limitations under the License.
package v1
import (
"context"
authorizationapi "k8s.io/api/authorization/v1"
)
type SelfSubjectAccessReviewExpansion interface {
Create(sar *authorizationapi.SelfSubjectAccessReview) (result *authorizationapi.SelfSubjectAccessReview, err error)
CreateContext(ctx context.Context, sar *authorizationapi.SelfSubjectAccessReview) (result *authorizationapi.SelfSubjectAccessReview, err error)
}
func (c *selfSubjectAccessReviews) Create(sar *authorizationapi.SelfSubjectAccessReview) (result *authorizationapi.SelfSubjectAccessReview, err error) {
return c.CreateContext(context.Background(), sar)
}
func (c *selfSubjectAccessReviews) CreateContext(ctx context.Context, sar *authorizationapi.SelfSubjectAccessReview) (result *authorizationapi.SelfSubjectAccessReview, err error) {
result = &authorizationapi.SelfSubjectAccessReview{}
err = c.client.Post().
Context(ctx).
Resource("selfsubjectaccessreviews").
Body(sar).
Do().

View File

@@ -17,16 +17,24 @@ limitations under the License.
package v1
import (
"context"
authorizationapi "k8s.io/api/authorization/v1"
)
type SelfSubjectRulesReviewExpansion interface {
Create(srr *authorizationapi.SelfSubjectRulesReview) (result *authorizationapi.SelfSubjectRulesReview, err error)
CreateContext(ctx context.Context, srr *authorizationapi.SelfSubjectRulesReview) (result *authorizationapi.SelfSubjectRulesReview, err error)
}
func (c *selfSubjectRulesReviews) Create(srr *authorizationapi.SelfSubjectRulesReview) (result *authorizationapi.SelfSubjectRulesReview, err error) {
return c.CreateContext(context.Background(), srr)
}
func (c *selfSubjectRulesReviews) CreateContext(ctx context.Context, srr *authorizationapi.SelfSubjectRulesReview) (result *authorizationapi.SelfSubjectRulesReview, err error) {
result = &authorizationapi.SelfSubjectRulesReview{}
err = c.client.Post().
Context(ctx).
Resource("selfsubjectrulesreviews").
Body(srr).
Do().

View File

@@ -17,17 +17,25 @@ limitations under the License.
package v1
import (
"context"
authorizationapi "k8s.io/api/authorization/v1"
)
// The SubjectAccessReviewExpansion interface allows manually adding extra methods to the AuthorizationInterface.
type SubjectAccessReviewExpansion interface {
Create(sar *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReview, err error)
CreateContext(ctx context.Context, sar *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReview, err error)
}
func (c *subjectAccessReviews) Create(sar *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReview, err error) {
return c.CreateContext(context.Background(), sar)
}
func (c *subjectAccessReviews) CreateContext(ctx context.Context, sar *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReview, err error) {
result = &authorizationapi.SubjectAccessReview{}
err = c.client.Post().
Context(ctx).
Resource("subjectaccessreviews").
Body(sar).
Do().

View File

@@ -17,11 +17,17 @@ limitations under the License.
package fake
import (
"context"
authorizationapi "k8s.io/api/authorization/v1beta1"
core "k8s.io/client-go/testing"
)
func (c *FakeLocalSubjectAccessReviews) Create(sar *authorizationapi.LocalSubjectAccessReview) (result *authorizationapi.LocalSubjectAccessReview, err error) {
return c.CreateContext(context.Background(), sar)
}
func (c *FakeLocalSubjectAccessReviews) CreateContext(ctx context.Context, sar *authorizationapi.LocalSubjectAccessReview) (result *authorizationapi.LocalSubjectAccessReview, err error) {
obj, err := c.Fake.Invokes(core.NewCreateAction(authorizationapi.SchemeGroupVersion.WithResource("localsubjectaccessreviews"), c.ns, sar), &authorizationapi.SubjectAccessReview{})
return obj.(*authorizationapi.LocalSubjectAccessReview), err
}

View File

@@ -17,11 +17,17 @@ limitations under the License.
package fake
import (
"context"
authorizationapi "k8s.io/api/authorization/v1beta1"
core "k8s.io/client-go/testing"
)
func (c *FakeSelfSubjectAccessReviews) Create(sar *authorizationapi.SelfSubjectAccessReview) (result *authorizationapi.SelfSubjectAccessReview, err error) {
return c.CreateContext(context.Background(), sar)
}
func (c *FakeSelfSubjectAccessReviews) CreateContext(ctx context.Context, sar *authorizationapi.SelfSubjectAccessReview) (result *authorizationapi.SelfSubjectAccessReview, err error) {
obj, err := c.Fake.Invokes(core.NewRootCreateAction(authorizationapi.SchemeGroupVersion.WithResource("selfsubjectaccessreviews"), sar), &authorizationapi.SelfSubjectAccessReview{})
return obj.(*authorizationapi.SelfSubjectAccessReview), err
}

View File

@@ -17,11 +17,17 @@ limitations under the License.
package fake
import (
"context"
authorizationapi "k8s.io/api/authorization/v1beta1"
core "k8s.io/client-go/testing"
)
func (c *FakeSelfSubjectRulesReviews) Create(srr *authorizationapi.SelfSubjectRulesReview) (result *authorizationapi.SelfSubjectRulesReview, err error) {
return c.CreateContext(context.Background(), srr)
}
func (c *FakeSelfSubjectRulesReviews) CreateContext(ctx context.Context, srr *authorizationapi.SelfSubjectRulesReview) (result *authorizationapi.SelfSubjectRulesReview, err error) {
obj, err := c.Fake.Invokes(core.NewRootCreateAction(authorizationapi.SchemeGroupVersion.WithResource("selfsubjectrulesreviews"), srr), &authorizationapi.SelfSubjectRulesReview{})
return obj.(*authorizationapi.SelfSubjectRulesReview), err
}

View File

@@ -17,11 +17,17 @@ limitations under the License.
package fake
import (
"context"
authorizationapi "k8s.io/api/authorization/v1beta1"
core "k8s.io/client-go/testing"
)
func (c *FakeSubjectAccessReviews) Create(sar *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReview, err error) {
return c.CreateContext(context.Background(), sar)
}
func (c *FakeSubjectAccessReviews) CreateContext(ctx context.Context, sar *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReview, err error) {
obj, err := c.Fake.Invokes(core.NewRootCreateAction(authorizationapi.SchemeGroupVersion.WithResource("subjectaccessreviews"), sar), &authorizationapi.SubjectAccessReview{})
return obj.(*authorizationapi.SubjectAccessReview), err
}

View File

@@ -17,16 +17,24 @@ limitations under the License.
package v1beta1
import (
"context"
authorizationapi "k8s.io/api/authorization/v1beta1"
)
type LocalSubjectAccessReviewExpansion interface {
Create(sar *authorizationapi.LocalSubjectAccessReview) (result *authorizationapi.LocalSubjectAccessReview, err error)
CreateContext(ctx context.Context, sar *authorizationapi.LocalSubjectAccessReview) (result *authorizationapi.LocalSubjectAccessReview, err error)
}
func (c *localSubjectAccessReviews) Create(sar *authorizationapi.LocalSubjectAccessReview) (result *authorizationapi.LocalSubjectAccessReview, err error) {
return c.CreateContext(context.Background(), sar)
}
func (c *localSubjectAccessReviews) CreateContext(ctx context.Context, sar *authorizationapi.LocalSubjectAccessReview) (result *authorizationapi.LocalSubjectAccessReview, err error) {
result = &authorizationapi.LocalSubjectAccessReview{}
err = c.client.Post().
Context(ctx).
Namespace(c.ns).
Resource("localsubjectaccessreviews").
Body(sar).

View File

@@ -17,16 +17,24 @@ limitations under the License.
package v1beta1
import (
"context"
authorizationapi "k8s.io/api/authorization/v1beta1"
)
type SelfSubjectAccessReviewExpansion interface {
Create(sar *authorizationapi.SelfSubjectAccessReview) (result *authorizationapi.SelfSubjectAccessReview, err error)
CreateContext(ctx context.Context, sar *authorizationapi.SelfSubjectAccessReview) (result *authorizationapi.SelfSubjectAccessReview, err error)
}
func (c *selfSubjectAccessReviews) Create(sar *authorizationapi.SelfSubjectAccessReview) (result *authorizationapi.SelfSubjectAccessReview, err error) {
return c.CreateContext(context.Background(), sar)
}
func (c *selfSubjectAccessReviews) CreateContext(ctx context.Context, sar *authorizationapi.SelfSubjectAccessReview) (result *authorizationapi.SelfSubjectAccessReview, err error) {
result = &authorizationapi.SelfSubjectAccessReview{}
err = c.client.Post().
Context(ctx).
Resource("selfsubjectaccessreviews").
Body(sar).
Do().

View File

@@ -17,16 +17,24 @@ limitations under the License.
package v1beta1
import (
"context"
authorizationapi "k8s.io/api/authorization/v1beta1"
)
type SelfSubjectRulesReviewExpansion interface {
Create(srr *authorizationapi.SelfSubjectRulesReview) (result *authorizationapi.SelfSubjectRulesReview, err error)
CreateContext(ctx context.Context, srr *authorizationapi.SelfSubjectRulesReview) (result *authorizationapi.SelfSubjectRulesReview, err error)
}
func (c *selfSubjectRulesReviews) Create(srr *authorizationapi.SelfSubjectRulesReview) (result *authorizationapi.SelfSubjectRulesReview, err error) {
return c.CreateContext(context.Background(), srr)
}
func (c *selfSubjectRulesReviews) CreateContext(ctx context.Context, srr *authorizationapi.SelfSubjectRulesReview) (result *authorizationapi.SelfSubjectRulesReview, err error) {
result = &authorizationapi.SelfSubjectRulesReview{}
err = c.client.Post().
Context(ctx).
Resource("selfsubjectrulesreviews").
Body(srr).
Do().

View File

@@ -17,17 +17,25 @@ limitations under the License.
package v1beta1
import (
"context"
authorizationapi "k8s.io/api/authorization/v1beta1"
)
// The SubjectAccessReviewExpansion interface allows manually adding extra methods to the AuthorizationInterface.
type SubjectAccessReviewExpansion interface {
Create(sar *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReview, err error)
CreateContext(ctx context.Context, sar *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReview, err error)
}
func (c *subjectAccessReviews) Create(sar *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReview, err error) {
return c.CreateContext(context.Background(), sar)
}
func (c *subjectAccessReviews) CreateContext(ctx context.Context, sar *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReview, err error) {
result = &authorizationapi.SubjectAccessReview{}
err = c.client.Post().
Context(ctx).
Resource("subjectaccessreviews").
Body(sar).
Do().

View File

@@ -104,17 +104,17 @@ func (e *events) Search(scheme *runtime.Scheme, objOrRef runtime.Object) (*v1.Ev
if err != nil {
return nil, err
}
if e.ns != "" && ref.Namespace != e.ns {
if len(e.ns) > 0 && ref.Namespace != e.ns {
return nil, fmt.Errorf("won't be able to find any events of namespace '%v' in namespace '%v'", ref.Namespace, e.ns)
}
stringRefKind := string(ref.Kind)
var refKind *string
if stringRefKind != "" {
if len(stringRefKind) > 0 {
refKind = &stringRefKind
}
stringRefUID := string(ref.UID)
var refUID *string
if stringRefUID != "" {
if len(stringRefUID) > 0 {
refUID = &stringRefUID
}
fieldSelector := e.GetFieldSelector(&ref.Name, &ref.Namespace, refKind, refUID)
@@ -124,10 +124,9 @@ func (e *events) Search(scheme *runtime.Scheme, objOrRef runtime.Object) (*v1.Ev
// Returns the appropriate field selector based on the API version being used to communicate with the server.
// The returned field selector can be used with List and Watch to filter desired events.
func (e *events) GetFieldSelector(involvedObjectName, involvedObjectNamespace, involvedObjectKind, involvedObjectUID *string) fields.Selector {
apiVersion := e.client.APIVersion().String()
field := fields.Set{}
if involvedObjectName != nil {
field[GetInvolvedObjectNameFieldLabel(apiVersion)] = *involvedObjectName
field["involvedObject.name"] = *involvedObjectName
}
if involvedObjectNamespace != nil {
field["involvedObject.namespace"] = *involvedObjectNamespace
@@ -142,6 +141,7 @@ func (e *events) GetFieldSelector(involvedObjectName, involvedObjectNamespace, i
}
// Returns the appropriate field label to use for name of the involved object as per the given API version.
// DEPRECATED: please use "involvedObject.name" inline.
func GetInvolvedObjectNameFieldLabel(version string) string {
return "involvedObject.name"
}

View File

@@ -23,7 +23,7 @@ import (
"k8s.io/klog"
metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
metainternalversionscheme "k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
@@ -63,7 +63,7 @@ func ConfigFor(inConfig *rest.Config) *rest.Config {
config := rest.CopyConfig(inConfig)
config.AcceptContentTypes = "application/vnd.kubernetes.protobuf,application/json"
config.ContentType = "application/vnd.kubernetes.protobuf"
config.NegotiatedSerializer = metainternalversion.Codecs.WithoutConversion()
config.NegotiatedSerializer = metainternalversionscheme.Codecs.WithoutConversion()
if config.UserAgent == "" {
config.UserAgent = rest.DefaultKubernetesUserAgent()
}

View File

@@ -16,7 +16,7 @@
def version_x_defs():
# This should match the list of packages in kube::version::ldflag
stamp_pkgs = [
"k8s.io/kubernetes/pkg/version",
"k8s.io/component-base/version",
# In hack/lib/version.sh, this has a vendor/ prefix. That isn't needed here?
"k8s.io/client-go/pkg/version",
]

View File

@@ -287,7 +287,7 @@ func (ts *azureTokenSource) refreshToken(token *azureToken) (*azureToken, error)
return nil, err
}
oauthConfig, err := adal.NewOAuthConfigWithAPIVersion(env.ActiveDirectoryEndpoint, token.tenantID, nil)
oauthConfig, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, token.tenantID)
if err != nil {
return nil, fmt.Errorf("building the OAuth configuration for token refresh: %v", err)
}
@@ -344,7 +344,7 @@ func newAzureTokenSourceDeviceCode(environment azure.Environment, clientID strin
}
func (ts *azureTokenSourceDeviceCode) Token() (*azureToken, error) {
oauthConfig, err := adal.NewOAuthConfigWithAPIVersion(ts.environment.ActiveDirectoryEndpoint, ts.tenantID, nil)
oauthConfig, err := adal.NewOAuthConfig(ts.environment.ActiveDirectoryEndpoint, ts.tenantID)
if err != nil {
return nil, fmt.Errorf("building the OAuth configuration for device code authentication: %v", err)
}

View File

@@ -190,6 +190,10 @@ func (c *fakeCodec) Encode(obj runtime.Object, stream io.Writer) error {
return nil
}
func (c *fakeCodec) Identifier() runtime.Identifier {
return runtime.Identifier("fake")
}
type fakeRoundTripper struct{}
func (r *fakeRoundTripper) RoundTrip(*http.Request) (*http.Response, error) {

View File

@@ -691,6 +691,33 @@ func (r *Request) Stream() (io.ReadCloser, error) {
}
}
// requestPreflightCheck looks for common programmer errors on Request.
//
// We tackle here two programmer mistakes. The first one is to try to create
// something(POST) using an empty string as namespace with namespaceSet as
// true. If namespaceSet is true then namespace should also be defined. The
// second mistake is, when under the same circumstances, the programmer tries
// to GET, PUT or DELETE a named resource(resourceName != ""), again, if
// namespaceSet is true then namespace must not be empty.
func (r *Request) requestPreflightCheck() error {
if !r.namespaceSet {
return nil
}
if len(r.namespace) > 0 {
return nil
}
switch r.verb {
case "POST":
return fmt.Errorf("an empty namespace may not be set during creation")
case "GET", "PUT", "DELETE":
if len(r.resourceName) > 0 {
return fmt.Errorf("an empty namespace may not be set when a resource name is provided")
}
}
return nil
}
// request connects to the server and invokes the provided function when a server response is
// received. It handles retry behavior and up front validation of requests. It will invoke
// fn at most once. It will return an error if a problem occurred prior to connecting to the
@@ -707,12 +734,8 @@ func (r *Request) request(fn func(*http.Request, *http.Response)) error {
return r.err
}
// TODO: added to catch programmer errors (invoking operations with an object with an empty namespace)
if (r.verb == "GET" || r.verb == "PUT" || r.verb == "DELETE") && r.namespaceSet && len(r.resourceName) > 0 && len(r.namespace) == 0 {
return fmt.Errorf("an empty namespace may not be set when a resource name is provided")
}
if (r.verb == "POST") && r.namespaceSet && len(r.namespace) == 0 {
return fmt.Errorf("an empty namespace may not be set during creation")
if err := r.requestPreflightCheck(); err != nil {
return err
}
client := r.client
@@ -815,8 +838,6 @@ func (r *Request) request(fn func(*http.Request, *http.Response)) error {
// processing.
//
// Error type:
// * If the request can't be constructed, or an error happened earlier while building its
// arguments: *RequestConstructionError
// * If the server responds with a status: *errors.StatusError or *errors.UnexpectedObjectError
// * http.Client.Do errors are returned directly.
func (r *Request) Do() Result {

View File

@@ -1994,3 +1994,66 @@ func defaultResourcePathWithPrefix(prefix, resource, namespace, name string) str
}
return path
}
func TestRequestPreflightCheck(t *testing.T) {
for _, tt := range []struct {
name string
verbs []string
namespace string
resourceName string
namespaceSet bool
expectsErr bool
}{
{
name: "no namespace set",
verbs: []string{"GET", "PUT", "DELETE", "POST"},
namespaceSet: false,
expectsErr: false,
},
{
name: "empty resource name and namespace",
verbs: []string{"GET", "PUT", "DELETE"},
namespaceSet: true,
expectsErr: false,
},
{
name: "resource name with empty namespace",
verbs: []string{"GET", "PUT", "DELETE"},
namespaceSet: true,
resourceName: "ResourceName",
expectsErr: true,
},
{
name: "post empty resource name and namespace",
verbs: []string{"POST"},
namespaceSet: true,
expectsErr: true,
},
{
name: "working requests",
verbs: []string{"GET", "PUT", "DELETE", "POST"},
namespaceSet: true,
resourceName: "ResourceName",
namespace: "Namespace",
expectsErr: false,
},
} {
t.Run(tt.name, func(t *testing.T) {
for _, verb := range tt.verbs {
r := &Request{
verb: verb,
namespace: tt.namespace,
resourceName: tt.resourceName,
namespaceSet: tt.namespaceSet,
}
err := r.requestPreflightCheck()
hasErr := err != nil
if hasErr == tt.expectsErr {
return
}
t.Errorf("%s: expects error: %v, has error: %v", verb, tt.expectsErr, hasErr)
}
})
}
}

View File

@@ -295,6 +295,13 @@ func isDeletionDup(a, b *Delta) *Delta {
return b
}
// willObjectBeDeletedLocked returns true only if the last delta for the
// given object is Delete. Caller must lock first.
func (f *DeltaFIFO) willObjectBeDeletedLocked(id string) bool {
deltas := f.items[id]
return len(deltas) > 0 && deltas[len(deltas)-1].Type == Deleted
}
// queueActionLocked appends to the delta list for the object.
// Caller must lock first.
func (f *DeltaFIFO) queueActionLocked(actionType DeltaType, obj interface{}) error {
@@ -303,6 +310,13 @@ func (f *DeltaFIFO) queueActionLocked(actionType DeltaType, obj interface{}) err
return KeyError{obj, err}
}
// If object is supposed to be deleted (last event is Deleted),
// then we should ignore Sync events, because it would result in
// recreation of this object.
if actionType == Sync && f.willObjectBeDeletedLocked(id) {
return nil
}
newDeltas := append(f.items[id], Delta{actionType, obj})
newDeltas = dedupDeltas(newDeltas)
@@ -525,13 +539,6 @@ func (f *DeltaFIFO) Resync() error {
return nil
}
func (f *DeltaFIFO) syncKey(key string) error {
f.lock.Lock()
defer f.lock.Unlock()
return f.syncKeyLocked(key)
}
func (f *DeltaFIFO) syncKeyLocked(key string) error {
obj, exists, err := f.knownObjects.GetByKey(key)
if err != nil {

View File

@@ -85,33 +85,6 @@ func TestDeltaFIFO_basic(t *testing.T) {
}
}
// TestDeltaFIFO_replaceWithDeleteDeltaIn tests that a `Sync` delta for an
// object `O` with ID `X` is added when .Replace is called and `O` is among the
// replacement objects even if the DeltaFIFO already stores in terminal position
// a delta of type `Delete` for ID `X`. Not adding the `Sync` delta causes
// SharedIndexInformers to miss `O`'s create notification, see https://github.com/kubernetes/kubernetes/issues/83810
// for more details.
func TestDeltaFIFO_replaceWithDeleteDeltaIn(t *testing.T) {
oldObj := mkFifoObj("foo", 1)
newObj := mkFifoObj("foo", 2)
f := NewDeltaFIFO(testFifoObjectKeyFunc, keyLookupFunc(func() []testFifoObject {
return []testFifoObject{oldObj}
}))
f.Delete(oldObj)
f.Replace([]interface{}{newObj}, "")
actualDeltas := Pop(f)
expectedDeltas := Deltas{
Delta{Type: Deleted, Object: oldObj},
Delta{Type: Sync, Object: newObj},
}
if !reflect.DeepEqual(expectedDeltas, actualDeltas) {
t.Errorf("expected %#v, got %#v", expectedDeltas, actualDeltas)
}
}
func TestDeltaFIFO_requeueOnPop(t *testing.T) {
f := NewDeltaFIFO(testFifoObjectKeyFunc, nil)

View File

@@ -29,7 +29,9 @@ import (
apierrs "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/clock"
"k8s.io/apimachinery/pkg/util/naming"
utilnet "k8s.io/apimachinery/pkg/util/net"
@@ -41,15 +43,22 @@ import (
"k8s.io/utils/trace"
)
const defaultExpectedTypeName = "<unspecified>"
// Reflector watches a specified resource and causes all changes to be reflected in the given store.
type Reflector struct {
// name identifies this reflector. By default it will be a file:line if possible.
name string
// metrics tracks basic metric information about the reflector
metrics *reflectorMetrics
// The name of the type we expect to place in the store. The name
// will be the stringification of expectedGVK if provided, and the
// stringification of expectedType otherwise. It is for display
// only, and should not be used for parsing or comparison.
expectedTypeName string
// The type of object we expect to place in the store.
expectedType reflect.Type
// The GVK of the object we expect to place in the store if unstructured.
expectedGVK *schema.GroupVersionKind
// The destination to sync up with the watch source
store Store
// listerWatcher is used to perform lists and watches.
@@ -102,14 +111,35 @@ func NewNamedReflector(name string, lw ListerWatcher, expectedType interface{},
name: name,
listerWatcher: lw,
store: store,
expectedType: reflect.TypeOf(expectedType),
period: time.Second,
resyncPeriod: resyncPeriod,
clock: &clock.RealClock{},
}
r.setExpectedType(expectedType)
return r
}
func (r *Reflector) setExpectedType(expectedType interface{}) {
r.expectedType = reflect.TypeOf(expectedType)
if r.expectedType == nil {
r.expectedTypeName = defaultExpectedTypeName
return
}
r.expectedTypeName = r.expectedType.String()
if obj, ok := expectedType.(*unstructured.Unstructured); ok {
// Use gvk to check that watch event objects are of the desired type.
gvk := obj.GroupVersionKind()
if gvk.Empty() {
klog.V(4).Infof("Reflector from %s configured with expectedType of *unstructured.Unstructured with empty GroupVersionKind.", r.name)
return
}
r.expectedGVK = &gvk
r.expectedTypeName = gvk.String()
}
}
// internalPackages are packages that ignored when creating a default reflector name. These packages are in the common
// call chains to NewReflector, so they'd be low entropy names for reflectors
var internalPackages = []string{"client-go/tools/cache/"}
@@ -117,7 +147,7 @@ var internalPackages = []string{"client-go/tools/cache/"}
// Run starts a watch and handles watch events. Will restart the watch if it is closed.
// Run will exit when stopCh is closed.
func (r *Reflector) Run(stopCh <-chan struct{}) {
klog.V(3).Infof("Starting reflector %v (%s) from %s", r.expectedType, r.resyncPeriod, r.name)
klog.V(3).Infof("Starting reflector %v (%s) from %s", r.expectedTypeName, r.resyncPeriod, r.name)
wait.Until(func() {
if err := r.ListAndWatch(stopCh); err != nil {
utilruntime.HandleError(err)
@@ -129,9 +159,6 @@ var (
// nothing will ever be sent down this channel
neverExitWatch <-chan time.Time = make(chan time.Time)
// Used to indicate that watching stopped so that a resync could happen.
errorResyncRequested = errors.New("resync channel fired")
// Used to indicate that watching stopped because of a signal from the stop
// channel passed in from a client of the reflector.
errorStopRequested = errors.New("Stop requested")
@@ -155,7 +182,7 @@ func (r *Reflector) resyncChan() (<-chan time.Time, func() bool) {
// and then use the resource version to watch.
// It returns error if ListAndWatch didn't even try to initialize watch.
func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error {
klog.V(3).Infof("Listing and watching %v from %s", r.expectedType, r.name)
klog.V(3).Infof("Listing and watching %v from %s", r.expectedTypeName, r.name)
var resourceVersion string
// Explicitly set "0" as resource version - it's fine for the List()
@@ -196,7 +223,7 @@ func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error {
case <-listCh:
}
if err != nil {
return fmt.Errorf("%s: Failed to list %v: %v", r.name, r.expectedType, err)
return fmt.Errorf("%s: Failed to list %v: %v", r.name, r.expectedTypeName, err)
}
initTrace.Step("Objects listed")
listMetaInterface, err := meta.ListAccessor(list)
@@ -275,9 +302,9 @@ func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error {
case io.EOF:
// watch closed normally
case io.ErrUnexpectedEOF:
klog.V(1).Infof("%s: Watch for %v closed with unexpected EOF: %v", r.name, r.expectedType, err)
klog.V(1).Infof("%s: Watch for %v closed with unexpected EOF: %v", r.name, r.expectedTypeName, err)
default:
utilruntime.HandleError(fmt.Errorf("%s: Failed to watch %v: %v", r.name, r.expectedType, err))
utilruntime.HandleError(fmt.Errorf("%s: Failed to watch %v: %v", r.name, r.expectedTypeName, err))
}
// If this is "connection refused" error, it means that most likely apiserver is not responsive.
// It doesn't make sense to re-list all objects because most likely we will be able to restart
@@ -294,9 +321,9 @@ func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error {
if err != errorStopRequested {
switch {
case apierrs.IsResourceExpired(err):
klog.V(4).Infof("%s: watch of %v ended with: %v", r.name, r.expectedType, err)
klog.V(4).Infof("%s: watch of %v ended with: %v", r.name, r.expectedTypeName, err)
default:
klog.Warningf("%s: watch of %v ended with: %v", r.name, r.expectedType, err)
klog.Warningf("%s: watch of %v ended with: %v", r.name, r.expectedTypeName, err)
}
}
return nil
@@ -336,9 +363,17 @@ loop:
if event.Type == watch.Error {
return apierrs.FromObject(event.Object)
}
if e, a := r.expectedType, reflect.TypeOf(event.Object); e != nil && e != a {
utilruntime.HandleError(fmt.Errorf("%s: expected type %v, but watch event object had type %v", r.name, e, a))
continue
if r.expectedType != nil {
if e, a := r.expectedType, reflect.TypeOf(event.Object); e != a {
utilruntime.HandleError(fmt.Errorf("%s: expected type %v, but watch event object had type %v", r.name, e, a))
continue
}
}
if r.expectedGVK != nil {
if e, a := *r.expectedGVK, event.Object.GetObjectKind().GroupVersionKind(); e != a {
utilruntime.HandleError(fmt.Errorf("%s: expected gvk %v, but watch event object had gvk %v", r.name, e, a))
continue
}
}
meta, err := meta.Accessor(event.Object)
if err != nil {
@@ -380,7 +415,7 @@ loop:
if watchDuration < 1*time.Second && eventCount == 0 {
return fmt.Errorf("very short watch: %s: Unexpected watch close - watch lasted less than a second and no items received", r.name)
}
klog.V(4).Infof("%s: Watch close - %v total %v items received", r.name, r.expectedType, eventCount)
klog.V(4).Infof("%s: Watch close - %v total %v items received", r.name, r.expectedTypeName, eventCount)
return nil
}

View File

@@ -47,19 +47,6 @@ func (noopMetric) Dec() {}
func (noopMetric) Observe(float64) {}
func (noopMetric) Set(float64) {}
type reflectorMetrics struct {
numberOfLists CounterMetric
listDuration SummaryMetric
numberOfItemsInList SummaryMetric
numberOfWatches CounterMetric
numberOfShortWatches CounterMetric
watchDuration SummaryMetric
numberOfItemsInWatch SummaryMetric
lastResourceVersion GaugeMetric
}
// MetricsProvider generates various metrics used by the reflector.
type MetricsProvider interface {
NewListsMetric(name string) CounterMetric

View File

@@ -20,13 +20,16 @@ import (
"errors"
"fmt"
"math/rand"
"reflect"
"strconv"
"testing"
"time"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apimachinery/pkg/watch"
)
@@ -430,3 +433,58 @@ func TestReflectorWatchListPageSize(t *testing.T) {
t.Errorf("Expected 10 results, got %d", len(results))
}
}
func TestReflectorSetExpectedType(t *testing.T) {
obj := &unstructured.Unstructured{}
gvk := schema.GroupVersionKind{
Group: "mygroup",
Version: "v1",
Kind: "MyKind",
}
obj.SetGroupVersionKind(gvk)
testCases := map[string]struct {
inputType interface{}
expectedTypeName string
expectedType reflect.Type
expectedGVK *schema.GroupVersionKind
}{
"Nil type": {
expectedTypeName: defaultExpectedTypeName,
},
"Normal type": {
inputType: &v1.Pod{},
expectedTypeName: "*v1.Pod",
expectedType: reflect.TypeOf(&v1.Pod{}),
},
"Unstructured type without GVK": {
inputType: &unstructured.Unstructured{},
expectedTypeName: "*unstructured.Unstructured",
expectedType: reflect.TypeOf(&unstructured.Unstructured{}),
},
"Unstructured type with GVK": {
inputType: obj,
expectedTypeName: gvk.String(),
expectedType: reflect.TypeOf(&unstructured.Unstructured{}),
expectedGVK: &gvk,
},
}
for testName, tc := range testCases {
t.Run(testName, func(t *testing.T) {
r := &Reflector{}
r.setExpectedType(tc.inputType)
if tc.expectedType != r.expectedType {
t.Fatalf("Expected expectedType %v, got %v", tc.expectedType, r.expectedType)
}
if tc.expectedTypeName != r.expectedTypeName {
t.Fatalf("Expected expectedTypeName %v, got %v", tc.expectedTypeName, r.expectedTypeName)
}
gvkNotEqual := (tc.expectedGVK == nil) != (r.expectedGVK == nil)
if tc.expectedGVK != nil && r.expectedGVK != nil {
gvkNotEqual = *tc.expectedGVK != *r.expectedGVK
}
if gvkNotEqual {
t.Fatalf("Expected expectedGVK %v, got %v", tc.expectedGVK, r.expectedGVK)
}
})
}
}

View File

@@ -449,13 +449,15 @@ func (config *DirectClientConfig) getCluster() (clientcmdapi.Cluster, error) {
return clientcmdapi.Cluster{}, fmt.Errorf("cluster %q does not exist", clusterInfoName)
}
mergo.MergeWithOverwrite(mergedClusterInfo, config.overrides.ClusterInfo)
// An override of --insecure-skip-tls-verify=true and no accompanying CA/CA data should clear already-set CA/CA data
// otherwise, a kubeconfig containing a CA reference would return an error that "CA and insecure-skip-tls-verify couldn't both be set"
// * An override of --insecure-skip-tls-verify=true and no accompanying CA/CA data should clear already-set CA/CA data
// otherwise, a kubeconfig containing a CA reference would return an error that "CA and insecure-skip-tls-verify couldn't both be set".
// * An override of --certificate-authority should also override TLS skip settings and CA data, otherwise existing CA data will take precedence.
caLen := len(config.overrides.ClusterInfo.CertificateAuthority)
caDataLen := len(config.overrides.ClusterInfo.CertificateAuthorityData)
if config.overrides.ClusterInfo.InsecureSkipTLSVerify && caLen == 0 && caDataLen == 0 {
mergedClusterInfo.CertificateAuthority = ""
mergedClusterInfo.CertificateAuthorityData = nil
if config.overrides.ClusterInfo.InsecureSkipTLSVerify || caLen > 0 || caDataLen > 0 {
mergedClusterInfo.InsecureSkipTLSVerify = config.overrides.ClusterInfo.InsecureSkipTLSVerify
mergedClusterInfo.CertificateAuthority = config.overrides.ClusterInfo.CertificateAuthority
mergedClusterInfo.CertificateAuthorityData = config.overrides.ClusterInfo.CertificateAuthorityData
}
return *mergedClusterInfo, nil

View File

@@ -148,7 +148,7 @@ func TestInsecureOverridesCA(t *testing.T) {
actualCfg, err := clientBuilder.ClientConfig()
if err != nil {
t.Errorf("Unexpected error: %v", err)
t.Fatalf("Unexpected error: %v", err)
}
matchBoolArg(true, actualCfg.Insecure, t)
@@ -156,6 +156,30 @@ func TestInsecureOverridesCA(t *testing.T) {
matchByteArg(nil, actualCfg.TLSClientConfig.CAData, t)
}
func TestCAOverridesCAData(t *testing.T) {
file, err := ioutil.TempFile("", "my.ca")
if err != nil {
t.Fatalf("could not create tempfile: %v", err)
}
defer os.Remove(file.Name())
config := createCAValidTestConfig()
clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{
ClusterInfo: clientcmdapi.Cluster{
CertificateAuthority: file.Name(),
},
}, nil)
actualCfg, err := clientBuilder.ClientConfig()
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
matchBoolArg(false, actualCfg.Insecure, t)
matchStringArg(file.Name(), actualCfg.TLSClientConfig.CAFile, t)
matchByteArg(nil, actualCfg.TLSClientConfig.CAData, t)
}
func TestMergeContext(t *testing.T) {
const namespace = "overridden-namespace"

View File

@@ -53,7 +53,6 @@ type eventKey struct {
action string
reason string
reportingController string
reportingInstance string
regarding corev1.ObjectReference
related corev1.ObjectReference
}
@@ -103,6 +102,10 @@ func newBroadcaster(sink EventSink, sleepDuration time.Duration, eventCache map[
}
}
func (e *eventBroadcasterImpl) Shutdown() {
e.Broadcaster.Shutdown()
}
// refreshExistingEventSeries refresh events TTL
func (e *eventBroadcasterImpl) refreshExistingEventSeries() {
// TODO: Investigate whether lock contention won't be a problem
@@ -264,7 +267,6 @@ func getKey(event *v1beta1.Event) eventKey {
action: event.Action,
reason: event.Reason,
reportingController: event.ReportingController,
reportingInstance: event.ReportingInstance,
regarding: event.Regarding,
}
if event.Related != nil {

View File

@@ -33,6 +33,9 @@ type EventRecorder interface {
// should be in UpperCamelCase format (starting with a capital letter). "reason" will be used
// to automate handling of events, so imagine people writing switch statements to handle them.
// You want to make that easy.
// 'action' explains what happened with regarding/what action did the ReportingController
// (ReportingController is a type of a Controller reporting an Event, e.g. k8s.io/node-controller, k8s.io/kubelet.)
// take in regarding's name; it should be in UpperCamelCase format (starting with a capital letter).
// 'note' is intended to be human readable.
Eventf(regarding runtime.Object, related runtime.Object, eventtype, reason, action, note string, args ...interface{})
}
@@ -51,6 +54,9 @@ type EventBroadcaster interface {
// NOTE: events received on your eventHandler should be copied before being used.
// TODO: figure out if this can be removed.
StartEventWatcher(eventHandler func(event runtime.Object)) func()
// Shutdown shuts down the broadcaster
Shutdown()
}
// EventSink knows how to store events (client-go implements it.)

View File

@@ -21,9 +21,10 @@ import (
"testing"
"time"
"net/http"
"k8s.io/apimachinery/pkg/util/clock"
rl "k8s.io/client-go/tools/leaderelection/resourcelock"
"net/http"
)
type fakeLock struct {
@@ -31,8 +32,8 @@ type fakeLock struct {
}
// 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
func (fl *fakeLock) Get() (ler *rl.LeaderElectionRecord, rawRecord []byte, err error) {
return nil, nil, nil
}
// Create is a dummy to allow us to have a fakeLock for testing.

View File

@@ -53,9 +53,9 @@ limitations under the License.
package leaderelection
import (
"bytes"
"context"
"fmt"
"reflect"
"time"
"k8s.io/apimachinery/pkg/api/errors"
@@ -176,8 +176,9 @@ type LeaderCallbacks struct {
type LeaderElector struct {
config LeaderElectionConfig
// internal bookkeeping
observedRecord rl.LeaderElectionRecord
observedTime time.Time
observedRecord rl.LeaderElectionRecord
observedRawRecord []byte
observedTime time.Time
// used to implement OnNewLeader(), may lag slightly from the
// value observedRecord.HolderIdentity if the transition has
// not yet been reported.
@@ -324,7 +325,7 @@ func (le *LeaderElector) tryAcquireOrRenew() bool {
}
// 1. obtain or create the ElectionRecord
oldLeaderElectionRecord, err := le.config.Lock.Get()
oldLeaderElectionRecord, oldLeaderElectionRawRecord, err := le.config.Lock.Get()
if err != nil {
if !errors.IsNotFound(err) {
klog.Errorf("error retrieving resource lock %v: %v", le.config.Lock.Describe(), err)
@@ -340,8 +341,9 @@ func (le *LeaderElector) tryAcquireOrRenew() bool {
}
// 2. Record obtained, check the Identity & Time
if !reflect.DeepEqual(le.observedRecord, *oldLeaderElectionRecord) {
if !bytes.Equal(le.observedRawRecord, oldLeaderElectionRawRecord) {
le.observedRecord = *oldLeaderElectionRecord
le.observedRawRecord = oldLeaderElectionRawRecord
le.observedTime = le.clock.Now()
}
if len(oldLeaderElectionRecord.HolderIdentity) > 0 &&
@@ -365,6 +367,7 @@ func (le *LeaderElector) tryAcquireOrRenew() bool {
klog.Errorf("Failed to update lock: %v", err)
return false
}
le.observedRecord = leaderElectionRecord
le.observedTime = le.clock.Now()
return true

View File

@@ -37,7 +37,7 @@ import (
"k8s.io/client-go/tools/record"
)
func createLockObject(objectType, namespace, name string, record rl.LeaderElectionRecord) (obj runtime.Object) {
func createLockObject(t *testing.T, objectType, namespace, name string, record rl.LeaderElectionRecord) (obj runtime.Object) {
objectMeta := metav1.ObjectMeta{
Namespace: namespace,
Name: name,
@@ -59,7 +59,7 @@ func createLockObject(objectType, namespace, name string, record rl.LeaderElecti
spec := rl.LeaderElectionRecordToLeaseSpec(&record)
obj = &coordinationv1.Lease{ObjectMeta: objectMeta, Spec: spec}
default:
panic("unexpected objType:" + objectType)
t.Fatal("unexpected objType:" + objectType)
}
return
}
@@ -69,6 +69,12 @@ func TestTryAcquireOrRenewEndpoints(t *testing.T) {
testTryAcquireOrRenew(t, "endpoints")
}
type Reactor struct {
verb string
objectType string
reaction fakeclient.ReactionFunc
}
func testTryAcquireOrRenew(t *testing.T, objectType string) {
future := time.Now().Add(1000 * time.Hour)
past := time.Now().Add(-1000 * time.Hour)
@@ -77,10 +83,7 @@ func testTryAcquireOrRenew(t *testing.T, objectType string) {
name string
observedRecord rl.LeaderElectionRecord
observedTime time.Time
reactors []struct {
verb string
reaction fakeclient.ReactionFunc
}
reactors []Reactor
expectSuccess bool
transitionLeader bool
@@ -88,10 +91,7 @@ func testTryAcquireOrRenew(t *testing.T, objectType string) {
}{
{
name: "acquire from no object",
reactors: []struct {
verb string
reaction fakeclient.ReactionFunc
}{
reactors: []Reactor{
{
verb: "get",
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
@@ -110,14 +110,11 @@ func testTryAcquireOrRenew(t *testing.T, objectType string) {
},
{
name: "acquire from unled object",
reactors: []struct {
verb string
reaction fakeclient.ReactionFunc
}{
reactors: []Reactor{
{
verb: "get",
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(objectType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{}), nil
return true, createLockObject(t, objectType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{}), nil
},
},
{
@@ -134,14 +131,11 @@ func testTryAcquireOrRenew(t *testing.T, objectType string) {
},
{
name: "acquire from led, unacked object",
reactors: []struct {
verb string
reaction fakeclient.ReactionFunc
}{
reactors: []Reactor{
{
verb: "get",
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(objectType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil
return true, createLockObject(t, objectType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil
},
},
{
@@ -160,14 +154,11 @@ func testTryAcquireOrRenew(t *testing.T, objectType string) {
},
{
name: "acquire from empty led, acked object",
reactors: []struct {
verb string
reaction fakeclient.ReactionFunc
}{
reactors: []Reactor{
{
verb: "get",
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(objectType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: ""}), nil
return true, createLockObject(t, objectType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: ""}), nil
},
},
{
@@ -185,14 +176,11 @@ func testTryAcquireOrRenew(t *testing.T, objectType string) {
},
{
name: "don't acquire from led, acked object",
reactors: []struct {
verb string
reaction fakeclient.ReactionFunc
}{
reactors: []Reactor{
{
verb: "get",
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(objectType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil
return true, createLockObject(t, objectType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil
},
},
},
@@ -203,14 +191,11 @@ func testTryAcquireOrRenew(t *testing.T, objectType string) {
},
{
name: "renew already acquired object",
reactors: []struct {
verb string
reaction fakeclient.ReactionFunc
}{
reactors: []Reactor{
{
verb: "get",
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(objectType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: "baz"}), nil
return true, createLockObject(t, objectType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: "baz"}), nil
},
},
{
@@ -282,13 +267,14 @@ func testTryAcquireOrRenew(t *testing.T, objectType string) {
},
},
}
observedRawRecord := GetRawRecordOrDie(t, objectType, test.observedRecord)
le := &LeaderElector{
config: lec,
observedRecord: test.observedRecord,
observedTime: test.observedTime,
clock: clock.RealClock{},
config: lec,
observedRecord: test.observedRecord,
observedRawRecord: observedRawRecord,
observedTime: test.observedTime,
clock: clock.RealClock{},
}
if test.expectSuccess != le.tryAcquireOrRenew() {
t.Errorf("unexpected result of tryAcquireOrRenew: [succeeded=%v]", !test.expectSuccess)
}
@@ -352,3 +338,560 @@ func TestLeaseSpecToLeaderElectionRecordRoundTrip(t *testing.T) {
t.Errorf("diff: %v", diff.ObjectReflectDiff(oldRecord, newRecord))
}
}
func multiLockType(t *testing.T, objectType string) (primaryType, secondaryType string) {
switch objectType {
case rl.EndpointsLeasesResourceLock:
return rl.EndpointsResourceLock, rl.LeasesResourceLock
case rl.ConfigMapsLeasesResourceLock:
return rl.ConfigMapsResourceLock, rl.LeasesResourceLock
default:
t.Fatal("unexpected objType:" + objectType)
}
return
}
func GetRawRecordOrDie(t *testing.T, objectType string, ler rl.LeaderElectionRecord) (ret []byte) {
var err error
switch objectType {
case "endpoints", "configmaps", "leases":
ret, err = json.Marshal(ler)
if err != nil {
t.Fatalf("lock %s get raw record %v failed: %v", objectType, ler, err)
}
case "endpointsleases", "configmapsleases":
recordBytes, err := json.Marshal(ler)
if err != nil {
t.Fatalf("lock %s get raw record %v failed: %v", objectType, ler, err)
}
ret = rl.ConcatRawRecord(recordBytes, recordBytes)
default:
t.Fatal("unexpected objType:" + objectType)
}
return
}
func testTryAcquireOrRenewMultiLock(t *testing.T, objectType string) {
future := time.Now().Add(1000 * time.Hour)
past := time.Now().Add(-1000 * time.Hour)
primaryType, secondaryType := multiLockType(t, objectType)
tests := []struct {
name string
observedRecord rl.LeaderElectionRecord
observedRawRecord []byte
observedTime time.Time
reactors []Reactor
expectSuccess bool
transitionLeader bool
outHolder string
}{
{
name: "acquire from no object",
reactors: []Reactor{
{
verb: "get",
objectType: primaryType,
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: primaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, action.(fakeclient.CreateAction).GetObject(), nil
},
},
{
verb: "create",
objectType: secondaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, action.(fakeclient.CreateAction).GetObject(), nil
},
},
},
expectSuccess: true,
outHolder: "baz",
},
{
name: "acquire from unled old object",
reactors: []Reactor{
{
verb: "get",
objectType: primaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{}), nil
},
},
{
verb: "get",
objectType: secondaryType,
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: "update",
objectType: primaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, action.(fakeclient.UpdateAction).GetObject(), nil
},
},
{
verb: "get",
objectType: secondaryType,
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: secondaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, action.(fakeclient.CreateAction).GetObject(), nil
},
},
},
expectSuccess: true,
transitionLeader: true,
outHolder: "baz",
},
{
name: "acquire from unled transition object",
reactors: []Reactor{
{
verb: "get",
objectType: primaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{}), nil
},
},
{
verb: "get",
objectType: secondaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{}), nil
},
},
{
verb: "update",
objectType: primaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, action.(fakeclient.UpdateAction).GetObject(), nil
},
},
{
verb: "get",
objectType: secondaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{}), nil
},
},
{
verb: "update",
objectType: secondaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, action.(fakeclient.UpdateAction).GetObject(), nil
},
},
},
expectSuccess: true,
transitionLeader: true,
outHolder: "baz",
},
{
name: "acquire from led, unack old object",
reactors: []Reactor{
{
verb: "get",
objectType: primaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil
},
},
{
verb: "get",
objectType: secondaryType,
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: "update",
objectType: primaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, action.(fakeclient.UpdateAction).GetObject(), nil
},
},
{
verb: "get",
objectType: secondaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil
},
},
{
verb: "create",
objectType: secondaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, action.(fakeclient.CreateAction).GetObject(), nil
},
},
},
observedRecord: rl.LeaderElectionRecord{HolderIdentity: "bing"},
observedRawRecord: GetRawRecordOrDie(t, primaryType, rl.LeaderElectionRecord{HolderIdentity: "bing"}),
observedTime: past,
expectSuccess: true,
transitionLeader: true,
outHolder: "baz",
},
{
name: "acquire from led, unack transition object",
reactors: []Reactor{
{
verb: "get",
objectType: primaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil
},
},
{
verb: "get",
objectType: secondaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil
},
},
{
verb: "update",
objectType: primaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, action.(fakeclient.UpdateAction).GetObject(), nil
},
},
{
verb: "get",
objectType: secondaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil
},
},
{
verb: "update",
objectType: secondaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, action.(fakeclient.UpdateAction).GetObject(), nil
},
},
},
observedRecord: rl.LeaderElectionRecord{HolderIdentity: "bing"},
observedRawRecord: GetRawRecordOrDie(t, objectType, rl.LeaderElectionRecord{HolderIdentity: "bing"}),
observedTime: past,
expectSuccess: true,
transitionLeader: true,
outHolder: "baz",
},
{
name: "acquire from conflict led, ack transition object",
reactors: []Reactor{
{
verb: "get",
objectType: primaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil
},
},
{
verb: "get",
objectType: secondaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: "baz"}), nil
},
},
},
observedRecord: rl.LeaderElectionRecord{HolderIdentity: "bing"},
observedRawRecord: GetRawRecordOrDie(t, objectType, rl.LeaderElectionRecord{HolderIdentity: "bing"}),
observedTime: future,
expectSuccess: false,
outHolder: rl.UnknownLeader,
},
{
name: "acquire from led, unack unknown object",
reactors: []Reactor{
{
verb: "get",
objectType: primaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: rl.UnknownLeader}), nil
},
},
{
verb: "get",
objectType: secondaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: rl.UnknownLeader}), nil
},
},
{
verb: "update",
objectType: primaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, action.(fakeclient.UpdateAction).GetObject(), nil
},
},
{
verb: "get",
objectType: secondaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: rl.UnknownLeader}), nil
},
},
{
verb: "update",
objectType: secondaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, action.(fakeclient.UpdateAction).GetObject(), nil
},
},
},
observedRecord: rl.LeaderElectionRecord{HolderIdentity: rl.UnknownLeader},
observedRawRecord: GetRawRecordOrDie(t, objectType, rl.LeaderElectionRecord{HolderIdentity: rl.UnknownLeader}),
observedTime: past,
expectSuccess: true,
transitionLeader: true,
outHolder: "baz",
},
{
name: "don't acquire from led, ack old object",
reactors: []Reactor{
{
verb: "get",
objectType: primaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil
},
},
{
verb: "get",
objectType: secondaryType,
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())
},
},
},
observedRecord: rl.LeaderElectionRecord{HolderIdentity: "bing"},
observedRawRecord: GetRawRecordOrDie(t, primaryType, rl.LeaderElectionRecord{HolderIdentity: "bing"}),
observedTime: future,
expectSuccess: false,
outHolder: "bing",
},
{
name: "don't acquire from led, acked new object, observe new record",
reactors: []Reactor{
{
verb: "get",
objectType: primaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: "baz"}), nil
},
},
{
verb: "get",
objectType: secondaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil
},
},
},
observedRecord: rl.LeaderElectionRecord{HolderIdentity: "bing"},
observedRawRecord: GetRawRecordOrDie(t, secondaryType, rl.LeaderElectionRecord{HolderIdentity: "bing"}),
observedTime: future,
expectSuccess: false,
outHolder: rl.UnknownLeader,
},
{
name: "don't acquire from led, acked new object, observe transition record",
reactors: []Reactor{
{
verb: "get",
objectType: primaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil
},
},
{
verb: "get",
objectType: secondaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil
},
},
},
observedRecord: rl.LeaderElectionRecord{HolderIdentity: "bing"},
observedRawRecord: GetRawRecordOrDie(t, objectType, rl.LeaderElectionRecord{HolderIdentity: "bing"}),
observedTime: future,
expectSuccess: false,
outHolder: "bing",
},
{
name: "renew already required object",
reactors: []Reactor{
{
verb: "get",
objectType: primaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: "baz"}), nil
},
},
{
verb: "get",
objectType: secondaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: "baz"}), nil
},
},
{
verb: "update",
objectType: primaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, action.(fakeclient.UpdateAction).GetObject(), nil
},
},
{
verb: "get",
objectType: secondaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{HolderIdentity: "baz"}), nil
},
},
{
verb: "update",
objectType: secondaryType,
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
return true, action.(fakeclient.UpdateAction).GetObject(), nil
},
},
},
observedRecord: rl.LeaderElectionRecord{HolderIdentity: "baz"},
observedRawRecord: GetRawRecordOrDie(t, objectType, rl.LeaderElectionRecord{HolderIdentity: "baz"}),
observedTime: future,
expectSuccess: true,
outHolder: "baz",
},
}
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, reactor.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 rl.EndpointsLeasesResourceLock:
lock = &rl.MultiLock{
Primary: &rl.EndpointsLock{
EndpointsMeta: objectMeta,
LockConfig: resourceLockConfig,
Client: c.CoreV1(),
},
Secondary: &rl.LeaseLock{
LeaseMeta: objectMeta,
LockConfig: resourceLockConfig,
Client: c.CoordinationV1(),
},
}
case rl.ConfigMapsLeasesResourceLock:
lock = &rl.MultiLock{
Primary: &rl.ConfigMapLock{
ConfigMapMeta: objectMeta,
LockConfig: resourceLockConfig,
Client: c.CoreV1(),
},
Secondary: &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
},
},
}
le := &LeaderElector{
config: lec,
observedRecord: test.observedRecord,
observedRawRecord: test.observedRawRecord,
observedTime: test.observedTime,
clock: clock.RealClock{},
}
if test.expectSuccess != le.tryAcquireOrRenew() {
t.Errorf("unexpected result of tryAcquireOrRenew: [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 endpointsleases as the resource
func TestTryAcquireOrRenewEndpointsLeases(t *testing.T) {
testTryAcquireOrRenewMultiLock(t, "endpointsleases")
}
// Will test leader election using configmapsleases as the resource
func TestTryAcquireOrRenewConfigMapsLeases(t *testing.T) {
testTryAcquireOrRenewMultiLock(t, "configmapsleases")
}

View File

@@ -41,22 +41,23 @@ type ConfigMapLock struct {
}
// Get returns the election record from a ConfigMap Annotation
func (cml *ConfigMapLock) Get() (*LeaderElectionRecord, error) {
func (cml *ConfigMapLock) Get() (*LeaderElectionRecord, []byte, error) {
var record LeaderElectionRecord
var err error
cml.cm, err = cml.Client.ConfigMaps(cml.ConfigMapMeta.Namespace).Get(cml.ConfigMapMeta.Name, metav1.GetOptions{})
if err != nil {
return nil, err
return nil, nil, err
}
if cml.cm.Annotations == nil {
cml.cm.Annotations = make(map[string]string)
}
if recordBytes, found := cml.cm.Annotations[LeaderElectionRecordAnnotationKey]; found {
recordBytes, found := cml.cm.Annotations[LeaderElectionRecordAnnotationKey]
if found {
if err := json.Unmarshal([]byte(recordBytes), &record); err != nil {
return nil, err
return nil, nil, err
}
}
return &record, nil
return &record, []byte(recordBytes), nil
}
// Create attempts to create a LeaderElectionRecord annotation
@@ -106,7 +107,7 @@ func (cml *ConfigMapLock) Describe() string {
return fmt.Sprintf("%v/%v", cml.ConfigMapMeta.Namespace, cml.ConfigMapMeta.Name)
}
// returns the Identity of the lock
// Identity returns the Identity of the lock
func (cml *ConfigMapLock) Identity() string {
return cml.LockConfig.Identity
}

View File

@@ -36,22 +36,23 @@ type EndpointsLock struct {
}
// Get returns the election record from a Endpoints Annotation
func (el *EndpointsLock) Get() (*LeaderElectionRecord, error) {
func (el *EndpointsLock) Get() (*LeaderElectionRecord, []byte, error) {
var record LeaderElectionRecord
var err error
el.e, err = el.Client.Endpoints(el.EndpointsMeta.Namespace).Get(el.EndpointsMeta.Name, metav1.GetOptions{})
if err != nil {
return nil, err
return nil, nil, err
}
if el.e.Annotations == nil {
el.e.Annotations = make(map[string]string)
}
if recordBytes, found := el.e.Annotations[LeaderElectionRecordAnnotationKey]; found {
recordBytes, found := el.e.Annotations[LeaderElectionRecordAnnotationKey]
if found {
if err := json.Unmarshal([]byte(recordBytes), &record); err != nil {
return nil, err
return nil, nil, err
}
}
return &record, nil
return &record, []byte(recordBytes), nil
}
// Create attempts to create a LeaderElectionRecord annotation
@@ -101,7 +102,7 @@ func (el *EndpointsLock) Describe() string {
return fmt.Sprintf("%v/%v", el.EndpointsMeta.Namespace, el.EndpointsMeta.Name)
}
// returns the Identity of the lock
// Identity returns the Identity of the lock
func (el *EndpointsLock) Identity() string {
return el.LockConfig.Identity
}

View File

@@ -30,6 +30,8 @@ const (
EndpointsResourceLock = "endpoints"
ConfigMapsResourceLock = "configmaps"
LeasesResourceLock = "leases"
EndpointsLeasesResourceLock = "endpointsleases"
ConfigMapsLeasesResourceLock = "configmapsleases"
)
// LeaderElectionRecord is the record that is stored in the leader election annotation.
@@ -71,7 +73,7 @@ type ResourceLockConfig struct {
// by the leaderelection code.
type Interface interface {
// Get returns the LeaderElectionRecord
Get() (*LeaderElectionRecord, error)
Get() (*LeaderElectionRecord, []byte, error)
// Create attempts to create a LeaderElectionRecord
Create(ler LeaderElectionRecord) error
@@ -92,33 +94,46 @@ type Interface interface {
// Manufacture will create a lock of a given type according to the input parameters
func New(lockType string, ns string, name string, coreClient corev1.CoreV1Interface, coordinationClient coordinationv1.CoordinationV1Interface, rlc ResourceLockConfig) (Interface, error) {
endpointsLock := &EndpointsLock{
EndpointsMeta: metav1.ObjectMeta{
Namespace: ns,
Name: name,
},
Client: coreClient,
LockConfig: rlc,
}
configmapLock := &ConfigMapLock{
ConfigMapMeta: metav1.ObjectMeta{
Namespace: ns,
Name: name,
},
Client: coreClient,
LockConfig: rlc,
}
leaseLock := &LeaseLock{
LeaseMeta: metav1.ObjectMeta{
Namespace: ns,
Name: name,
},
Client: coordinationClient,
LockConfig: rlc,
}
switch lockType {
case EndpointsResourceLock:
return &EndpointsLock{
EndpointsMeta: metav1.ObjectMeta{
Namespace: ns,
Name: name,
},
Client: coreClient,
LockConfig: rlc,
}, nil
return endpointsLock, nil
case ConfigMapsResourceLock:
return &ConfigMapLock{
ConfigMapMeta: metav1.ObjectMeta{
Namespace: ns,
Name: name,
},
Client: coreClient,
LockConfig: rlc,
}, nil
return configmapLock, nil
case LeasesResourceLock:
return &LeaseLock{
LeaseMeta: metav1.ObjectMeta{
Namespace: ns,
Name: name,
},
Client: coordinationClient,
LockConfig: rlc,
return leaseLock, nil
case EndpointsLeasesResourceLock:
return &MultiLock{
Primary: endpointsLock,
Secondary: leaseLock,
}, nil
case ConfigMapsLeasesResourceLock:
return &MultiLock{
Primary: configmapLock,
Secondary: leaseLock,
}, nil
default:
return nil, fmt.Errorf("Invalid lock-type %s", lockType)

View File

@@ -17,6 +17,7 @@ limitations under the License.
package resourcelock
import (
"encoding/json"
"errors"
"fmt"
@@ -36,13 +37,18 @@ type LeaseLock struct {
}
// Get returns the election record from a Lease spec
func (ll *LeaseLock) Get() (*LeaderElectionRecord, error) {
func (ll *LeaseLock) Get() (*LeaderElectionRecord, []byte, error) {
var err error
ll.lease, err = ll.Client.Leases(ll.LeaseMeta.Namespace).Get(ll.LeaseMeta.Name, metav1.GetOptions{})
if err != nil {
return nil, err
return nil, nil, err
}
return LeaseSpecToLeaderElectionRecord(&ll.lease.Spec), nil
record := LeaseSpecToLeaderElectionRecord(&ll.lease.Spec)
recordByte, err := json.Marshal(*record)
if err != nil {
return nil, nil, err
}
return record, recordByte, nil
}
// Create attempts to create a Lease
@@ -84,7 +90,7 @@ func (ll *LeaseLock) Describe() string {
return fmt.Sprintf("%v/%v", ll.LeaseMeta.Namespace, ll.LeaseMeta.Name)
}
// returns the Identity of the lock
// Identity returns the Identity of the lock
func (ll *LeaseLock) Identity() string {
return ll.LockConfig.Identity
}

View File

@@ -0,0 +1,103 @@
/*
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 resourcelock
import (
"bytes"
"encoding/json"
apierrors "k8s.io/apimachinery/pkg/api/errors"
)
const (
UnknownLeader = "leaderelection.k8s.io/unknown"
)
// MultiLock is used for lock's migration
type MultiLock struct {
Primary Interface
Secondary Interface
}
// Get returns the older election record of the lock
func (ml *MultiLock) Get() (*LeaderElectionRecord, []byte, error) {
primary, primaryRaw, err := ml.Primary.Get()
if err != nil {
return nil, nil, err
}
secondary, secondaryRaw, err := ml.Secondary.Get()
if err != nil {
// Lock is held by old client
if apierrors.IsNotFound(err) && primary.HolderIdentity != ml.Identity() {
return primary, primaryRaw, nil
}
return nil, nil, err
}
if primary.HolderIdentity != secondary.HolderIdentity {
primary.HolderIdentity = UnknownLeader
primaryRaw, err = json.Marshal(primary)
if err != nil {
return nil, nil, err
}
}
return primary, ConcatRawRecord(primaryRaw, secondaryRaw), nil
}
// Create attempts to create both primary lock and secondary lock
func (ml *MultiLock) Create(ler LeaderElectionRecord) error {
err := ml.Primary.Create(ler)
if err != nil && !apierrors.IsAlreadyExists(err) {
return err
}
return ml.Secondary.Create(ler)
}
// Update will update and existing annotation on both two resources.
func (ml *MultiLock) Update(ler LeaderElectionRecord) error {
err := ml.Primary.Update(ler)
if err != nil {
return err
}
_, _, err = ml.Secondary.Get()
if err != nil && apierrors.IsNotFound(err) {
return ml.Secondary.Create(ler)
}
return ml.Secondary.Update(ler)
}
// RecordEvent in leader election while adding meta-data
func (ml *MultiLock) RecordEvent(s string) {
ml.Primary.RecordEvent(s)
ml.Secondary.RecordEvent(s)
}
// Describe is used to convert details on current resource lock
// into a string
func (ml *MultiLock) Describe() string {
return ml.Primary.Describe()
}
// Identity returns the Identity of the lock
func (ml *MultiLock) Identity() string {
return ml.Primary.Identity()
}
func ConcatRawRecord(primaryRaw, secondaryRaw []byte) []byte {
return bytes.Join([][]byte{primaryRaw, secondaryRaw}, []byte(","))
}

View File

@@ -127,25 +127,9 @@ type EventBroadcaster interface {
// NewRecorder returns an EventRecorder that can be used to send events to this EventBroadcaster
// with the event source set to the given event source.
NewRecorder(scheme *runtime.Scheme, source v1.EventSource) EventRecorder
}
// EventRecorderAdapter is a wrapper around EventRecorder implementing the
// new EventRecorder interface.
type EventRecorderAdapter struct {
recorder EventRecorder
}
// NewEventRecorderAdapter returns an adapter implementing new EventRecorder
// interface.
func NewEventRecorderAdapter(recorder EventRecorder) *EventRecorderAdapter {
return &EventRecorderAdapter{
recorder: recorder,
}
}
// Eventf is a wrapper around v1 Eventf
func (a *EventRecorderAdapter) Eventf(regarding, _ runtime.Object, eventtype, reason, action, note string, args ...interface{}) {
a.recorder.Eventf(regarding, eventtype, reason, note, args...)
// Shutdown shuts down the broadcaster
Shutdown()
}
// Creates a new event broadcaster.
@@ -180,14 +164,18 @@ type eventBroadcasterImpl struct {
// StartRecordingToSink starts sending events received from the specified eventBroadcaster to the given sink.
// The return value can be ignored or used to stop recording, if desired.
// TODO: make me an object with parameterizable queue length and retry interval
func (eventBroadcaster *eventBroadcasterImpl) StartRecordingToSink(sink EventSink) watch.Interface {
eventCorrelator := NewEventCorrelatorWithOptions(eventBroadcaster.options)
return eventBroadcaster.StartEventWatcher(
func (e *eventBroadcasterImpl) StartRecordingToSink(sink EventSink) watch.Interface {
eventCorrelator := NewEventCorrelatorWithOptions(e.options)
return e.StartEventWatcher(
func(event *v1.Event) {
recordToSink(sink, event, eventCorrelator, eventBroadcaster.sleepDuration)
recordToSink(sink, event, eventCorrelator, e.sleepDuration)
})
}
func (e *eventBroadcasterImpl) Shutdown() {
e.Broadcaster.Shutdown()
}
func recordToSink(sink EventSink, event *v1.Event, eventCorrelator *EventCorrelator, sleepDuration time.Duration) {
// Make a copy before modification, because there could be multiple listeners.
// Events are safe to copy like this.
@@ -268,8 +256,8 @@ func recordEvent(sink EventSink, event *v1.Event, patch []byte, updateExistingEv
// StartLogging starts sending events received from this EventBroadcaster to the given logging function.
// The return value can be ignored or used to stop recording, if desired.
func (eventBroadcaster *eventBroadcasterImpl) StartLogging(logf func(format string, args ...interface{})) watch.Interface {
return eventBroadcaster.StartEventWatcher(
func (e *eventBroadcasterImpl) StartLogging(logf func(format string, args ...interface{})) watch.Interface {
return e.StartEventWatcher(
func(e *v1.Event) {
logf("Event(%#v): type: '%v' reason: '%v' %v", e.InvolvedObject, e.Type, e.Reason, e.Message)
})
@@ -277,8 +265,8 @@ func (eventBroadcaster *eventBroadcasterImpl) StartLogging(logf func(format stri
// StartEventWatcher starts sending events received from this EventBroadcaster to the given event handler function.
// The return value can be ignored or used to stop recording, if desired.
func (eventBroadcaster *eventBroadcasterImpl) StartEventWatcher(eventHandler func(*v1.Event)) watch.Interface {
watcher := eventBroadcaster.Watch()
func (e *eventBroadcasterImpl) StartEventWatcher(eventHandler func(*v1.Event)) watch.Interface {
watcher := e.Watch()
go func() {
defer utilruntime.HandleCrash()
for watchEvent := range watcher.ResultChan() {
@@ -295,8 +283,8 @@ func (eventBroadcaster *eventBroadcasterImpl) StartEventWatcher(eventHandler fun
}
// NewRecorder returns an EventRecorder that records events with the given event source.
func (eventBroadcaster *eventBroadcasterImpl) NewRecorder(scheme *runtime.Scheme, source v1.EventSource) EventRecorder {
return &recorderImpl{scheme, source, eventBroadcaster.Broadcaster, clock.RealClock{}}
func (e *eventBroadcasterImpl) NewRecorder(scheme *runtime.Scheme, source v1.EventSource) EventRecorder {
return &recorderImpl{scheme, source, e.Broadcaster, clock.RealClock{}}
}
type recorderImpl struct {

View File

@@ -72,7 +72,22 @@ func WriteCert(certPath string, data []byte) error {
// NewPool returns an x509.CertPool containing the certificates in the given PEM-encoded file.
// Returns an error if the file could not be read, a certificate could not be parsed, or if the file does not contain any certificates
func NewPool(filename string) (*x509.CertPool, error) {
certs, err := CertsFromFile(filename)
pemBlock, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
pool, err := NewPoolFromBytes(pemBlock)
if err != nil {
return nil, fmt.Errorf("error creating pool from %s: %s", filename, err)
}
return pool, nil
}
// NewPoolFromBytes returns an x509.CertPool containing the certificates in the given PEM-encoded bytes.
// Returns an error if the file could not be read, a certificate could not be parsed, or if the file does not contain any certificates
func NewPoolFromBytes(pemBlock []byte) (*x509.CertPool, error) {
certs, err := ParseCertsPEM(pemBlock)
if err != nil {
return nil, err
}

View File

@@ -42,43 +42,64 @@ var DefaultBackoff = wait.Backoff{
Jitter: 0.1,
}
// OnError executes the provided function repeatedly, retrying if the server returns a specified
// error. Callers should preserve previous executions if they wish to retry changes. It performs an
// exponential backoff.
//
// var pod *api.Pod
// err := retry.OnError(DefaultBackoff, errors.IsConflict, func() (err error) {
// pod, err = c.Pods("mynamespace").UpdateStatus(podStatus)
// return
// })
// if err != nil {
// // may be conflict if max retries were hit
// return err
// }
// ...
//
// TODO: Make Backoff an interface?
func OnError(backoff wait.Backoff, errorFunc func(error) bool, fn func() error) error {
var lastConflictErr error
// OnError allows the caller to retry fn in case the error returned by fn is retriable
// according to the provided function. backoff defines the maximum retries and the wait
// interval between two retries.
func OnError(backoff wait.Backoff, retriable func(error) bool, fn func() error) error {
var lastErr error
err := wait.ExponentialBackoff(backoff, func() (bool, error) {
err := fn()
switch {
case err == nil:
return true, nil
case errorFunc(err):
lastConflictErr = err
case retriable(err):
lastErr = err
return false, nil
default:
return false, err
}
})
if err == wait.ErrWaitTimeout {
err = lastConflictErr
err = lastErr
}
return err
}
// RetryOnConflict executes the function function repeatedly, retrying if the server returns a conflicting
// RetryOnConflict is used to make an update to a resource when you have to worry about
// conflicts caused by other code making unrelated updates to the resource at the same
// time. fn should fetch the resource to be modified, make appropriate changes to it, try
// to update it, and return (unmodified) the error from the update function. On a
// successful update, RetryOnConflict will return nil. If the update function returns a
// "Conflict" error, RetryOnConflict will wait some amount of time as described by
// backoff, and then try again. On a non-"Conflict" error, or if it retries too many times
// and gives up, RetryOnConflict will return an error to the caller.
//
// err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
// // Fetch the resource here; you need to refetch it on every try, since
// // if you got a conflict on the last update attempt then you need to get
// // the current version before making your own changes.
// pod, err := c.Pods("mynamespace").Get(name, metav1.GetOptions{})
// if err ! nil {
// return err
// }
//
// // Make whatever updates to the resource are needed
// pod.Status.Phase = v1.PodFailed
//
// // Try to update
// _, err = c.Pods("mynamespace").UpdateStatus(pod)
// // You have to return err itself here (not wrapped inside another error)
// // so that RetryOnConflict can identify it correctly.
// return err
// })
// if err != nil {
// // May be conflict if max retries were hit, or may be something unrelated
// // like permissions or a network error
// return err
// }
// ...
//
// TODO: Make Backoff an interface?
func RetryOnConflict(backoff wait.Backoff, fn func() error) error {
return OnError(backoff, errors.IsConflict, fn)
}