Compare commits

..

27 Commits

Author SHA1 Message Date
Kubernetes Publisher
23c0fac11e Fix Godeps.json to point to kubernetes-1.13.8 tags 2019-07-08 17:52:19 +00:00
Kubernetes Publisher
5633e3a616 Merge pull request #79501 from nikhita/remove-bitbucket-01
[1.13] Replace bitbucket with github to fix godep error

Kubernetes-commit: bd6da4fe2b07f7681802f28de264ee7eda5cef5d
2019-06-29 00:41:23 +00:00
Nikhita Raghunath
2705570f5e Replace bitbucket with github
This commit has the following changes:

- Replace `bitbucket.org/ww/goautoneg` with `github.com/munnerz/goautoneg`.
- Replace `bitbucket.org/bertimus9/systemstat` with `github.com/nikhita/systemstat`.
- Bump kube-openapi to remove so that it's dependency on `bitbucket.org/ww/goautoneg`
moves to `github.com/munnerz/goautoneg`.
- Generate `swagger.json` generated from the above change.
- Update `BUILD` files.

Bitbucket is replaced with GitHub because:

Atlassian finally pulled the plug on their 1.0 api and forces everyone
to use 2.0 now: https://developer.atlassian.com/cloud/bitbucket/deprecation-notice-v1-apis/

This leads to an error like:

```
godep: error downloading dep (bitbucket.org/ww/goautoneg): https://api.bitbucket.org/1.0/repositories/ww/goautoneg: 410 Gone
```

This was fixed in upstream go in golang/tools@13ba8ad.

To fix this in k/k:

1) We'll need to either bump our vendored version
https://github.com/kubernetes/kubernetes/blob/release-1.13/vendor/golang.org/x/tools/go/vcs/vcs.go#L676.
However, this bump brings in _lots_ of changes.

2) We can entirely remove our dependency on bitbucket.

The second point is better because:

1) godep itself vendors in an older version: https://github.com/tools/godep/blob/master/vendor/golang.org/x/tools/go/vcs/vcs.go#L667.
This means that anyone who installs godep directly, without forking it,
will not be able to use it with Kubernetes if we stick to bitbucket.

2) Bumping `golang/x/tools` requires running `godep restore`, which doesn't
work because that uses the 1.0 api...leading to a catch-22 like situation.

Kubernetes-commit: 409df0aa2e5a555454909eab3c4f492461c21f3b
2019-06-28 15:43:19 +05:30
Kubernetes Publisher
1777665291 Merge pull request #78028 from yuchengwu/automated-cherry-pick-of-#77874-github-release-1.13
Automated cherry pick of #77874: fix CVE-2019-11244: `kubectl --http-cache=<world-accessible

Kubernetes-commit: 211b1ada57ae0b85dd08c4c353c90305fa1f14c9
2019-05-21 19:07:02 +00:00
Kubernetes Publisher
1b0f6441b0 Merge pull request #77899 from mikedanese/automated-cherry-pick-of-#77613-upstream-release-1.13
Automated cherry pick of #77613 upstream release 1.13

Kubernetes-commit: bb630af86712366105b76959acca5bd71798bfb1
2019-05-21 10:20:25 -07:00
Jordan Liggitt
f2f74ab51a honor overridden tokenfile, add InClusterConfig override tests
Kubernetes-commit: d31e2f5f11440cdf1ada47f6ba99b01a410fb7c6
2019-05-15 08:15:02 -04:00
Mike Danese
f0d5882143 BoundServiceAccountTokenVolume: fix InClusterConfig
Kubernetes-commit: c748ddf904ad2878e43c5c564ef7d4650c43cb48
2019-05-14 09:29:16 -07:00
Yucheng Wu
7c7fe05819 fix CVE-2019-11244: kubectl --http-cache=<world-accessible dir> creates world-writeable cached schema files
Kubernetes-commit: 8bebb336d0dfa07c70f92ca81fd88986d2a3192b
2019-05-14 14:49:38 +08:00
Kubernetes Publisher
65905f29c1 Merge pull request #76200 from mvladev/automated-cherry-pick-of-#75072-upstream-release-1.13
Automated cherry pick of #75072: Check for required name parameter in dynamic client

Kubernetes-commit: 405aa2e8b674b86f55c298d750e67bea1fdfa4bb
2019-05-06 18:47:56 -07:00
Levi Blackstone
52d188ef6c Check for required name parameter in dynamic client
The Create, Delete, Get, Patch, Update and UpdateStatus
methods in the dynamic client all expect the name
parameter to be non-empty, but did not validate this
requirement, which could lead to a panic. Add explicit
checks to these methods.

Kubernetes-commit: 55cdbb43c001baa578523413201b35976e561ea6
2019-03-06 16:21:33 -07:00
Kubernetes Publisher
b9d8bc3e50 Merge pull request #75532 from andyzhangx/automated-cherry-pick-of-#72143-upstream-release-1.13
Automated cherry pick of #72143: Fix aad support in kubectl for sovereign cloud

Kubernetes-commit: 73d746b3f37cde4d0919700c1fb4d9f926fb01d9
2019-04-03 20:44:49 -07:00
Dong Liu
cba5305359 Fix aad support in kubectl for sovereign cloud
Kubernetes-commit: d951fc7970cd417bd855f2946702bfb6e5efc998
2018-12-18 13:50:56 +08:00
Kubernetes Publisher
7621a5ebb8 Merge pull request #74672 from logicalhan/automated-cherry-pick-of-#74636-upstream-release-1.13
Automated cherry pick of #74636: Remove reflector metrics as they currently cause a memory

Kubernetes-commit: b5f55a8fc542efd87871b02991e3d930692c64a2
2019-03-07 16:13:46 +00:00
Han Kang
adcd4a6e94 Remove reflector metrics as they currently cause a memory leak
Kubernetes-commit: 48cfdd8c5b14643d93042b9eeb38772386cc86e8
2019-02-26 16:22:24 -08:00
Kubernetes Publisher
f8e521c159 Merge pull request #74102 from caesarxuchao/automated-cherry-pick-of-#73443-#73713-#73805-#74000-upstream-release-1.13
Automated cherry pick of #73443: update json-patch to pick up bug fixes

Kubernetes-commit: de4225fa13bfb50581f80e6af63b326a3c1028b1
2019-02-21 21:43:11 +00:00
Chao Xu
99c0ce7cfe Importing latest json-patch.
Kubernetes-commit: f80a5504d88b9029a4323a7c6bd31e034badc315
2019-02-04 09:47:54 -08:00
Chao Xu
21a91e3c21 update json-patch to pick up bug fixes
Kubernetes-commit: f0a495cff09087e38f39ac2dd4864b38e14da7be
2019-01-28 17:42:01 -08:00
Kubernetes Publisher
86dbf26d38 Merge pull request #72837 from liggitt/automated-cherry-pick-of-#72825-upstream-release-1.13
Automated cherry pick of #72825: Find current resourceVersion for waiting for

Kubernetes-commit: f5d6de398b219e9c85081582f42e0755587ef9fa
2019-01-15 09:52:54 -08:00
Jordan Liggitt
2c40298487 Find current resourceVersion for waiting for deletion/conditions
Kubernetes-commit: a0fa584f3edda46b9ccf9916051ca0b9d8d1fe0a
2019-01-11 10:38:18 -05:00
Kubernetes Publisher
73dad31f02 Merge pull request #72672 from liggitt/automated-cherry-pick-of-#72437-upstream-release-1.13
Automated cherry pick of #72437: Shorten re-read period for token files to work with

Kubernetes-commit: abc71e373ff5a5a701c5e48e2cd07b28f18b3b48
2019-01-10 19:35:54 +00:00
Jordan Liggitt
db82653708 Shorten re-read period for token files to work with ProjectedTokenVolumeSource
Kubernetes-commit: cf878b9332c8875ed0fcb8ce07cccd99547ce099
2018-12-29 22:18:28 -05:00
Kubernetes Publisher
abf3a7067f Merge pull request #71723 from liggitt/automated-cherry-pick-of-#71713-upstream-release-1.13
Automated cherry pick of #71713, #71857: Plumb token and token file through rest.Config

Kubernetes-commit: 5bdc2077e8ca7c4ccf493eb76b396055802362d4
2018-12-12 03:08:43 +00:00
Jordan Liggitt
1a246d9074 Plumb token and token file through rest.Config
Kubernetes-commit: 863a63d863f002eb16843f6e3785702a6c27e76d
2018-12-04 11:24:29 -05:00
Kubernetes Prow Robot
49478befba Merge pull request #515 from nikhita/changelog-release-10-branch
Cherry-pick of changelog updates to release-10.0 branch
2018-12-04 04:18:38 -08:00
Nikhita Raghunath
cde316a81d Remove custom godep step in travis 2018-12-04 16:19:23 +05:30
Nikhita Raghunath
7f18b87519 Update README to reflect 10.0.0 release
(cherry picked from commit cdcff04a6c)
2018-12-03 15:39:51 +05:30
Nikhita Raghunath
d71b6c1c6d Add client-go 10.0.0 changelog
(cherry picked from commit bc06bb2a21)
2018-12-03 15:39:33 +05:30
22 changed files with 456 additions and 180 deletions

View File

@@ -3,8 +3,7 @@ language: go
go_import_path: k8s.io/client-go
go:
- 1.11.1
- 1.11.2
script:
- if [ "$TRAVIS_BRANCH" != "master" ]; then godep restore; fi
- go build ./...
- go build ./...

View File

@@ -5,6 +5,114 @@ https://github.com/kubernetes/test-infra/issues/5843.
Changes in `k8s.io/api` and `k8s.io/apimachinery` are mentioned here
because `k8s.io/client-go` depends on them.
# v10.0.0
**Breaking Changes:**
* Action required: client-go will no longer have bootstrap
(`k8s.io/client-go/tools/bootstrap`) related code. Any reference to it will
break. Please redirect all references to `k8s.io/bootstrap` instead.
([#67356](https://github.com/kubernetes/kubernetes/pull/67356))
* The methods `NewSelfSignedCACert` and `NewSignedCert` now use `crypto.Signer`
interface instead of `rsa.PrivateKey` for certificate creation. This is done
to allow different kind of private keys (for example: ecdsa).
([#69329](https://github.com/kubernetes/kubernetes/pull/69329))
* `GetScale` and `UpdateScale` methods have been added for `apps/v1` clients
and with this, no-verb scale clients have been removed.
([#70437](https://github.com/kubernetes/kubernetes/pull/70437))
* `k8s.io/client-go/util/cert/triple` package has been removed.
([#70966](https://github.com/kubernetes/kubernetes/pull/70966))
**New Features:**
* `unfinished_work_microseconds` is added to the workqueue metrics.
It can be used to detect stuck worker threads (kube-controller-manager runs many workqueues.).
([#70884](https://github.com/kubernetes/kubernetes/pull/70884))
* A method `GetPorts` is added to expose the ports that were forwarded.
This can be used to retrieve the locally-bound port in cases where the input was port 0.
([#67513](https://github.com/kubernetes/kubernetes/pull/67513))
* Dynamic listers and informers, that work with `runtime.Unstructured` objects,
are added. These are useful for writing generic, non-generated controllers.
([68748](https://github.com/kubernetes/kubernetes/pull/68748))
* The dynamic fake client now supports JSONPatch.
([#69330](https://github.com/kubernetes/kubernetes/pull/69330))
* The `GetBinding` method is added for pods in the fake client.
([#69412](https://github.com/kubernetes/kubernetes/pull/69412))
**Bug fixes and Improvements:**
* The `apiVersion` and action name values for fake evictions are now set.
([#69035](https://github.com/kubernetes/kubernetes/pull/69035))
* PEM files containing both TLS certificate and key can now be parsed in
arbitrary order. Previously key was always required to be first.
([#69536](https://github.com/kubernetes/kubernetes/pull/69536))
* Go clients created from a kubeconfig that specifies a `TokenFile` now
periodically reload the token from the specified file.
([#70606](https://github.com/kubernetes/kubernetes/pull/70606))
* It is now ensured that oversized data frames are not written to
spdystreams in `remotecommand.NewSPDYExecutor`.
([#70999](https://github.com/kubernetes/kubernetes/pull/70999))
* A panic occuring on calling `scheme.Convert` is fixed by populating the fake
dynamic client scheme. ([#69125](https://github.com/kubernetes/kubernetes/pull/69125))
* Add step to correctly setup permissions for the in-cluster-client-configuration example.
([#69232](https://github.com/kubernetes/kubernetes/pull/69232))
* The function `Parallelize` is deprecated. Use `ParallelizeUntil` instead.
([#68403](https://github.com/kubernetes/kubernetes/pull/68403))
* [k8s.io/apimachinery] Restrict redirect following from the apiserver to
same-host redirects, and ignore redirects in some cases.
([#66516](https://github.com/kubernetes/kubernetes/pull/66516))
## API changes
**New Features:**
* GlusterFS PersistentVolumes sources can now reference endpoints in any
namespace using the `spec.glusterfs.endpointsNamespace` field.
Ensure all kubelets are upgraded to 1.13+ before using this capability.
([#60195](https://github.com/kubernetes/kubernetes/pull/60195))
* The [dynamic audit configuration](https://github.com/kubernetes/community/blob/master/keps/sig-auth/0014-dynamic-audit-configuration.md)
API is added. ([#67547](https://github.com/kubernetes/kubernetes/pull/67547))
* A new field `EnableServiceLinks` is added to the `PodSpec` to indicate whether
information about services should be injected into pod's environment variables.
([#68754](https://github.com/kubernetes/kubernetes/pull/68754))
* `CSIPersistentVolume` feature, i.e. `PersistentVolumes` with
`CSIPersistentVolumeSource`, is GA. `CSIPersistentVolume` feature gate is now
deprecated and will be removed according to deprecation policy.
([#69929](https://github.com/kubernetes/kubernetes/pull/69929))
* Raw block volume support is promoted to beta, and enabled by default.
This is accessible via the `volumeDevices` container field in pod specs,
and the `volumeMode` field in persistent volume and persistent volume claims definitions.
([#71167](https://github.com/kubernetes/kubernetes/pull/71167))
**Bug fixes and Improvements:**
* The default value of extensions/v1beta1 Deployment's `RevisionHistoryLimit`
is set to `MaxInt32`. ([#66605](https://github.com/kubernetes/kubernetes/pull/66605))
* `procMount` field is no longer incorrectly marked as required in openapi schema.
([#69694](https://github.com/kubernetes/kubernetes/pull/69694))
* The caBundle and service fields in admission webhook API objects now correctly
indicate they are optional. ([#70138](https://github.com/kubernetes/kubernetes/pull/70138))
# v9.0.0
**Breaking Changes:**

172
Godeps/Godeps.json generated
View File

@@ -56,7 +56,7 @@
},
{
"ImportPath": "github.com/evanphx/json-patch",
"Rev": "36442dbdb585210f8d5a1b45e67aa323c197d5c4"
"Rev": "5858425f75500d40c52783dce87d085a483ce135"
},
{
"ImportPath": "github.com/gogo/protobuf/proto",
@@ -272,339 +272,339 @@
},
{
"ImportPath": "k8s.io/api/admissionregistration/v1alpha1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/admissionregistration/v1beta1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/apps/v1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/apps/v1beta1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/apps/v1beta2",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/auditregistration/v1alpha1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/authentication/v1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/authentication/v1beta1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/authorization/v1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/authorization/v1beta1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/autoscaling/v1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/autoscaling/v2beta1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/autoscaling/v2beta2",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/batch/v1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/batch/v1beta1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/batch/v2alpha1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/certificates/v1beta1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/coordination/v1beta1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/core/v1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/events/v1beta1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/extensions/v1beta1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/imagepolicy/v1alpha1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/networking/v1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/policy/v1beta1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/rbac/v1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/rbac/v1alpha1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/rbac/v1beta1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/scheduling/v1alpha1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/scheduling/v1beta1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/settings/v1alpha1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/storage/v1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/storage/v1alpha1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/api/storage/v1beta1",
"Rev": "89a74a8d264df0e993299876a8cde88379b940ee"
"Rev": "9a6558301daeb24d8ac1cc79ea0ccd1a23f1410d"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/apitesting",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/apitesting/fuzzer",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/apitesting/roundtrip",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/equality",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/errors",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/meta",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/resource",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/fuzzer",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/internalversion",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1beta1",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/conversion",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/conversion/queryparams",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/fields",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/labels",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/schema",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/json",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/protobuf",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/recognizer",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/streaming",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/versioning",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/selection",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/types",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/cache",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/clock",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/diff",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/errors",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/framer",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/httpstream",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/httpstream/spdy",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/intstr",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/json",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/mergepatch",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/naming",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/net",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/remotecommand",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/runtime",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/sets",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/strategicpatch",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/validation",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/validation/field",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/wait",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/yaml",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/version",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/watch",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/json",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/netutil",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/reflect",
"Rev": "2b1284ed4c93a43499e781493253e2ac5959c4fd"
"Rev": "e20a3a656cff908c57d43ba1c2ccec3b269e8ad7"
},
{
"ImportPath": "k8s.io/klog",
@@ -612,7 +612,7 @@
},
{
"ImportPath": "k8s.io/kube-openapi/pkg/util/proto",
"Rev": "c59034cc13d587f5ef4e85ca0ade0c1866ae8e1d"
"Rev": "fd52d7a69c206aae478f9aff43cb10eaf25e5c2a"
},
{
"ImportPath": "sigs.k8s.io/yaml",

View File

@@ -2,7 +2,7 @@
Go clients for talking to a [kubernetes](http://kubernetes.io/) cluster.
We currently recommend using the v9.0.0 tag. See [INSTALL.md](/INSTALL.md) for
We currently recommend using the v10.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.
@@ -91,16 +91,16 @@ We will backport bugfixes--but not new features--into older versions of
#### Compatibility matrix
| | Kubernetes 1.6 | Kubernetes 1.7 | Kubernetes 1.8 | Kubernetes 1.9 | Kubernetes 1.10 | Kubernetes 1.11 | Kubernetes 1.12 |
|---------------------|----------------|----------------|----------------|----------------|-----------------|-----------------|-----------------|
| client-go 3.0 | ✓ | - | +- | +- | +- | +- | +- |
| client-go 4.0 | +- | ✓ | +- | +- | +- | +- | +- |
| client-go 5.0 | +- | +- | ✓ | +- | +- | +- | +- |
| client-go 6.0 | +- | +- | +- | ✓ | +- | +- | +- |
| client-go 7.0 | +- | +- | +- | +- | ✓ | +- | +- |
| client-go 8.0 | +- | +- | +- | +- | +- | ✓ | +- |
| client-go 9.0 | +- | +- | +- | +- | +- | +- | ✓ |
| client-go HEAD | +- | +- | +- | +- | +- | +- | +- |
| | Kubernetes 1.7 | Kubernetes 1.8 | Kubernetes 1.9 | Kubernetes 1.10 | Kubernetes 1.11 | Kubernetes 1.12 | Kubernetes 1.13 |
|---------------------|----------------|----------------|----------------|-----------------|-----------------|-----------------|-----------------|
| client-go 4.0 | ✓ | +- | +- | +- | +- | +- | +- |
| client-go 5.0 | +- | ✓ | +- | +- | +- | +- | +- |
| client-go 6.0 | +- | +- | ✓ | +- | +- | +- | +- |
| client-go 7.0 | +- | +- | +- | ✓ | +- | +- | +- |
| client-go 8.0 | +- | +- | +- | +- | ✓ | +- | +- |
| client-go 9.0 | +- | +- | +- | +- | +- | ✓ | +- |
| client-go 10.0 | +- | +- | +- | +- | +- | +- | ✓ |
| client-go HEAD | +- | +- | +- | +- | +- | +- | +- |
Key:
@@ -128,9 +128,10 @@ between client-go versions.
| client-go 4.0 | Kubernetes main repo, 1.7 branch | = - |
| client-go 5.0 | Kubernetes main repo, 1.8 branch | = - |
| client-go 6.0 | Kubernetes main repo, 1.9 branch | = - |
| client-go 7.0 | Kubernetes main repo, 1.10 branch | |
| client-go 7.0 | Kubernetes main repo, 1.10 branch | = - |
| client-go 8.0 | Kubernetes main repo, 1.11 branch | ✓ |
| client-go 9.0 | Kubernetes main repo, 1.12 branch | ✓ |
| client-go 10.0 | Kubernetes main repo, 1.13 branch | ✓ |
| client-go HEAD | Kubernetes main repo, master branch | ✓ |
Key:

View File

@@ -164,7 +164,7 @@ func (d *CachedDiscoveryClient) getCachedFile(filename string) ([]byte, error) {
}
func (d *CachedDiscoveryClient) writeCachedFile(filename string, obj runtime.Object) error {
if err := os.MkdirAll(filepath.Dir(filename), 0755); err != nil {
if err := os.MkdirAll(filepath.Dir(filename), 0750); err != nil {
return err
}
@@ -183,7 +183,7 @@ func (d *CachedDiscoveryClient) writeCachedFile(filename string, obj runtime.Obj
return err
}
err = os.Chmod(f.Name(), 0755)
err = os.Chmod(f.Name(), 0660)
if err != nil {
return err
}

View File

@@ -19,6 +19,7 @@ package discovery
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"time"
@@ -95,6 +96,32 @@ func TestNewCachedDiscoveryClient_TTL(t *testing.T) {
assert.Equal(c.groupCalls, 2)
}
func TestNewCachedDiscoveryClient_PathPerm(t *testing.T) {
assert := assert.New(t)
d, err := ioutil.TempDir("", "")
assert.NoError(err)
os.RemoveAll(d)
defer os.RemoveAll(d)
c := fakeDiscoveryClient{}
cdc := newCachedDiscoveryClient(&c, d, 1*time.Nanosecond)
cdc.ServerGroups()
err = filepath.Walk(d, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
assert.Equal(os.FileMode(0750), info.Mode().Perm())
} else {
assert.Equal(os.FileMode(0660), info.Mode().Perm())
}
return nil
})
assert.NoError(err)
}
type fakeDiscoveryClient struct {
groupCalls int
resourceCalls int

View File

@@ -18,6 +18,7 @@ package discovery
import (
"net/http"
"os"
"path/filepath"
"github.com/gregjones/httpcache"
@@ -35,6 +36,8 @@ type cacheRoundTripper struct {
// corresponding requests.
func newCacheRoundTripper(cacheDir string, rt http.RoundTripper) http.RoundTripper {
d := diskv.New(diskv.Options{
PathPerm: os.FileMode(0750),
FilePerm: os.FileMode(0660),
BasePath: cacheDir,
TempDir: filepath.Join(cacheDir, ".diskv-temp"),
})

View File

@@ -22,7 +22,10 @@ import (
"net/http"
"net/url"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
)
// copied from k8s.io/client-go/transport/round_trippers_test.go
@@ -93,3 +96,52 @@ func TestCacheRoundTripper(t *testing.T) {
t.Errorf("Invalid content read from cache %q", string(content))
}
}
func TestCacheRoundTripperPathPerm(t *testing.T) {
assert := assert.New(t)
rt := &testRoundTripper{}
cacheDir, err := ioutil.TempDir("", "cache-rt")
os.RemoveAll(cacheDir)
defer os.RemoveAll(cacheDir)
if err != nil {
t.Fatal(err)
}
cache := newCacheRoundTripper(cacheDir, rt)
// First call, caches the response
req := &http.Request{
Method: http.MethodGet,
URL: &url.URL{Host: "localhost"},
}
rt.Response = &http.Response{
Header: http.Header{"ETag": []string{`"123456"`}},
Body: ioutil.NopCloser(bytes.NewReader([]byte("Content"))),
StatusCode: http.StatusOK,
}
resp, err := cache.RoundTrip(req)
if err != nil {
t.Fatal(err)
}
content, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatal(err)
}
if string(content) != "Content" {
t.Errorf(`Expected Body to be "Content", got %q`, string(content))
}
err = filepath.Walk(cacheDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
assert.Equal(os.FileMode(0750), info.Mode().Perm())
} else {
assert.Equal(os.FileMode(0660), info.Mode().Perm())
}
return nil
})
assert.NoError(err)
}

View File

@@ -303,6 +303,7 @@ func (c *dynamicResourceClient) List(opts metav1.ListOptions) (*unstructured.Uns
}
list := &unstructured.UnstructuredList{}
list.SetResourceVersion(entireList.GetResourceVersion())
for i := range entireList.Items {
item := &entireList.Items[i]
metadata, err := meta.Accessor(item)

View File

@@ -17,6 +17,7 @@ limitations under the License.
package dynamic
import (
"fmt"
"io"
"k8s.io/apimachinery/pkg/api/meta"
@@ -94,6 +95,9 @@ func (c *dynamicResourceClient) Create(obj *unstructured.Unstructured, opts meta
return nil, err
}
name = accessor.GetName()
if len(name) == 0 {
return nil, fmt.Errorf("name is required")
}
}
result := c.client.client.
@@ -122,6 +126,10 @@ func (c *dynamicResourceClient) Update(obj *unstructured.Unstructured, opts meta
if err != nil {
return nil, err
}
name := accessor.GetName()
if len(name) == 0 {
return nil, fmt.Errorf("name is required")
}
outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
if err != nil {
return nil, err
@@ -129,7 +137,7 @@ func (c *dynamicResourceClient) Update(obj *unstructured.Unstructured, opts meta
result := c.client.client.
Put().
AbsPath(append(c.makeURLSegments(accessor.GetName()), subresources...)...).
AbsPath(append(c.makeURLSegments(name), subresources...)...).
Body(outBytes).
SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
Do()
@@ -153,6 +161,10 @@ func (c *dynamicResourceClient) UpdateStatus(obj *unstructured.Unstructured, opt
if err != nil {
return nil, err
}
name := accessor.GetName()
if len(name) == 0 {
return nil, fmt.Errorf("name is required")
}
outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
if err != nil {
@@ -161,7 +173,7 @@ func (c *dynamicResourceClient) UpdateStatus(obj *unstructured.Unstructured, opt
result := c.client.client.
Put().
AbsPath(append(c.makeURLSegments(accessor.GetName()), "status")...).
AbsPath(append(c.makeURLSegments(name), "status")...).
Body(outBytes).
SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
Do()
@@ -181,6 +193,9 @@ func (c *dynamicResourceClient) UpdateStatus(obj *unstructured.Unstructured, opt
}
func (c *dynamicResourceClient) Delete(name string, opts *metav1.DeleteOptions, subresources ...string) error {
if len(name) == 0 {
return fmt.Errorf("name is required")
}
if opts == nil {
opts = &metav1.DeleteOptions{}
}
@@ -216,6 +231,9 @@ func (c *dynamicResourceClient) DeleteCollection(opts *metav1.DeleteOptions, lis
}
func (c *dynamicResourceClient) Get(name string, opts metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error) {
if len(name) == 0 {
return nil, fmt.Errorf("name is required")
}
result := c.client.client.Get().AbsPath(append(c.makeURLSegments(name), subresources...)...).SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).Do()
if err := result.Error(); err != nil {
return nil, err
@@ -284,6 +302,9 @@ func (c *dynamicResourceClient) Watch(opts metav1.ListOptions) (watch.Interface,
}
func (c *dynamicResourceClient) Patch(name string, pt types.PatchType, data []byte, opts metav1.UpdateOptions, subresources ...string) (*unstructured.Unstructured, error) {
if len(name) == 0 {
return nil, fmt.Errorf("name is required")
}
result := c.client.client.
Patch(pt).
AbsPath(append(c.makeURLSegments(name), subresources...)...).

View File

@@ -145,6 +145,7 @@ func (r *azureRoundTripper) WrappedRoundTripper() http.RoundTripper { return r.r
type azureToken struct {
token adal.Token
environment string
clientID string
tenantID string
apiserverID string
@@ -219,6 +220,10 @@ func (ts *azureTokenSource) retrieveTokenFromCfg() (*azureToken, error) {
if refreshToken == "" {
return nil, fmt.Errorf("no refresh token in cfg: %s", cfgRefreshToken)
}
environment := ts.cfg[cfgEnvironment]
if environment == "" {
return nil, fmt.Errorf("no environment in cfg: %s", cfgEnvironment)
}
clientID := ts.cfg[cfgClientID]
if clientID == "" {
return nil, fmt.Errorf("no client ID in cfg: %s", cfgClientID)
@@ -250,6 +255,7 @@ func (ts *azureTokenSource) retrieveTokenFromCfg() (*azureToken, error) {
Resource: fmt.Sprintf("spn:%s", apiserverID),
Type: tokenType,
},
environment: environment,
clientID: clientID,
tenantID: tenantID,
apiserverID: apiserverID,
@@ -260,6 +266,7 @@ func (ts *azureTokenSource) storeTokenInCfg(token *azureToken) error {
newCfg := make(map[string]string)
newCfg[cfgAccessToken] = token.token.AccessToken
newCfg[cfgRefreshToken] = token.token.RefreshToken
newCfg[cfgEnvironment] = token.environment
newCfg[cfgClientID] = token.clientID
newCfg[cfgTenantID] = token.tenantID
newCfg[cfgApiserverID] = token.apiserverID
@@ -275,7 +282,12 @@ func (ts *azureTokenSource) storeTokenInCfg(token *azureToken) error {
}
func (ts *azureTokenSource) refreshToken(token *azureToken) (*azureToken, error) {
oauthConfig, err := adal.NewOAuthConfig(azure.PublicCloud.ActiveDirectoryEndpoint, token.tenantID)
env, err := azure.EnvironmentFromName(token.environment)
if err != nil {
return nil, err
}
oauthConfig, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, token.tenantID)
if err != nil {
return nil, fmt.Errorf("building the OAuth configuration for token refresh: %v", err)
}
@@ -299,6 +311,7 @@ func (ts *azureTokenSource) refreshToken(token *azureToken) (*azureToken, error)
return &azureToken{
token: spt.Token(),
environment: token.environment,
clientID: token.clientID,
tenantID: token.tenantID,
apiserverID: token.apiserverID,
@@ -353,6 +366,7 @@ func (ts *azureTokenSourceDeviceCode) Token() (*azureToken, error) {
return &azureToken{
token: *token,
environment: ts.environment.Name,
clientID: ts.clientID,
tenantID: ts.tenantID,
apiserverID: ts.apiserverID,

View File

@@ -53,6 +53,13 @@ func TestAzureTokenSource(t *testing.T) {
wantCfg := token2Cfg(token)
persistedCfg := persiter.Cache()
wantCfgLen := len(wantCfg)
persistedCfgLen := len(persistedCfg)
if wantCfgLen != persistedCfgLen {
t.Errorf("wantCfgLen and persistedCfgLen do not match, wantCfgLen=%v, persistedCfgLen=%v", wantCfgLen, persistedCfgLen)
}
for k, v := range persistedCfg {
if strings.Compare(v, wantCfg[k]) != 0 {
t.Errorf("Token() persisted cfg %s: got %v, want %v", k, v, wantCfg[k])
@@ -103,6 +110,7 @@ type fakeTokenSource struct {
func (ts *fakeTokenSource) Token() (*azureToken, error) {
return &azureToken{
token: newFackeAzureToken(ts.accessToken, ts.expiresOn),
environment: "testenv",
clientID: "fake",
tenantID: "fake",
apiserverID: "fake",
@@ -113,6 +121,7 @@ func token2Cfg(token *azureToken) map[string]string {
cfg := make(map[string]string)
cfg[cfgAccessToken] = token.token.AccessToken
cfg[cfgRefreshToken] = token.token.RefreshToken
cfg[cfgEnvironment] = token.environment
cfg[cfgClientID] = token.clientID
cfg[cfgTenantID] = token.tenantID
cfg[cfgApiserverID] = token.apiserverID

View File

@@ -70,6 +70,11 @@ type Config struct {
// TODO: demonstrate an OAuth2 compatible client.
BearerToken string
// Path to a file containing a BearerToken.
// If set, the contents are periodically read.
// The last successfully read value takes precedence over BearerToken.
BearerTokenFile string
// Impersonate is the configuration that RESTClient will use for impersonation.
Impersonate ImpersonationConfig
@@ -322,9 +327,8 @@ func InClusterConfig() (*Config, error) {
return nil, ErrNotInCluster
}
ts := NewCachedFileTokenSource(tokenFile)
if _, err := ts.Token(); err != nil {
token, err := ioutil.ReadFile(tokenFile)
if err != nil {
return nil, err
}
@@ -340,7 +344,8 @@ func InClusterConfig() (*Config, error) {
// TODO: switch to using cluster DNS.
Host: "https://" + net.JoinHostPort(host, port),
TLSClientConfig: tlsClientConfig,
WrapTransport: TokenSourceWrapTransport(ts),
BearerToken: string(token),
BearerTokenFile: tokenFile,
}, nil
}
@@ -430,12 +435,13 @@ func AnonymousClientConfig(config *Config) *Config {
// CopyConfig returns a copy of the given config
func CopyConfig(config *Config) *Config {
return &Config{
Host: config.Host,
APIPath: config.APIPath,
ContentConfig: config.ContentConfig,
Username: config.Username,
Password: config.Password,
BearerToken: config.BearerToken,
Host: config.Host,
APIPath: config.APIPath,
ContentConfig: config.ContentConfig,
Username: config.Username,
Password: config.Password,
BearerToken: config.BearerToken,
BearerTokenFile: config.BearerTokenFile,
Impersonate: ImpersonationConfig{
Groups: config.Impersonate.Groups,
Extra: config.Impersonate.Extra,

View File

@@ -264,6 +264,7 @@ func TestAnonymousConfig(t *testing.T) {
// is added to Config, update AnonymousClientConfig to preserve the field otherwise.
expected.Impersonate = ImpersonationConfig{}
expected.BearerToken = ""
expected.BearerTokenFile = ""
expected.Username = ""
expected.Password = ""
expected.AuthProvider = nil

View File

@@ -74,9 +74,10 @@ func (c *Config) TransportConfig() (*transport.Config, error) {
KeyFile: c.KeyFile,
KeyData: c.KeyData,
},
Username: c.Username,
Password: c.Password,
BearerToken: c.BearerToken,
Username: c.Username,
Password: c.Password,
BearerToken: c.BearerToken,
BearerTokenFile: c.BearerTokenFile,
Impersonate: transport.ImpersonationConfig{
UserName: c.Impersonate.UserName,
Groups: c.Impersonate.Groups,

View File

@@ -24,10 +24,8 @@ import (
"net"
"net/url"
"reflect"
"strconv"
"strings"
"sync"
"sync/atomic"
"syscall"
"time"
@@ -95,17 +93,10 @@ func NewReflector(lw ListerWatcher, expectedType interface{}, store Store, resyn
return NewNamedReflector(naming.GetNameFromCallsite(internalPackages...), lw, expectedType, store, resyncPeriod)
}
// reflectorDisambiguator is used to disambiguate started reflectors.
// initialized to an unstable value to ensure meaning isn't attributed to the suffix.
var reflectorDisambiguator = int64(time.Now().UnixNano() % 12345)
// NewNamedReflector same as NewReflector, but with a specified name for logging
func NewNamedReflector(name string, lw ListerWatcher, expectedType interface{}, store Store, resyncPeriod time.Duration) *Reflector {
reflectorSuffix := atomic.AddInt64(&reflectorDisambiguator, 1)
r := &Reflector{
name: name,
// we need this to be unique per process (some names are still the same) but obvious who it belongs to
metrics: newReflectorMetrics(makeValidPrometheusMetricLabel(fmt.Sprintf("reflector_"+name+"_%d", reflectorSuffix))),
name: name,
listerWatcher: lw,
store: store,
expectedType: reflect.TypeOf(expectedType),
@@ -173,13 +164,10 @@ func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error {
// to be served from cache and potentially be delayed relative to
// etcd contents. Reflector framework will catch up via Watch() eventually.
options := metav1.ListOptions{ResourceVersion: "0"}
r.metrics.numberOfLists.Inc()
start := r.clock.Now()
list, err := r.listerWatcher.List(options)
if err != nil {
return fmt.Errorf("%s: Failed to list %v: %v", r.name, r.expectedType, err)
}
r.metrics.listDuration.Observe(time.Since(start).Seconds())
listMetaInterface, err := meta.ListAccessor(list)
if err != nil {
return fmt.Errorf("%s: Unable to understand list result %#v: %v", r.name, list, err)
@@ -189,7 +177,6 @@ func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error {
if err != nil {
return fmt.Errorf("%s: Unable to understand list result %#v (%v)", r.name, list, err)
}
r.metrics.numberOfItemsInList.Observe(float64(len(items)))
if err := r.syncWith(items, resourceVersion); err != nil {
return fmt.Errorf("%s: Unable to sync list result: %v", r.name, err)
}
@@ -239,7 +226,6 @@ func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error {
TimeoutSeconds: &timeoutSeconds,
}
r.metrics.numberOfWatches.Inc()
w, err := r.listerWatcher.Watch(options)
if err != nil {
switch err {
@@ -291,11 +277,6 @@ func (r *Reflector) watchHandler(w watch.Interface, resourceVersion *string, err
// Stopping the watcher should be idempotent and if we return from this function there's no way
// we're coming back in with the same watch interface.
defer w.Stop()
// update metrics
defer func() {
r.metrics.numberOfItemsInWatch.Observe(float64(eventCount))
r.metrics.watchDuration.Observe(time.Since(start).Seconds())
}()
loop:
for {
@@ -351,7 +332,6 @@ loop:
watchDuration := r.clock.Now().Sub(start)
if watchDuration < 1*time.Second && eventCount == 0 {
r.metrics.numberOfShortWatches.Inc()
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)
@@ -370,9 +350,4 @@ func (r *Reflector) setLastSyncResourceVersion(v string) {
r.lastSyncResourceVersionMutex.Lock()
defer r.lastSyncResourceVersionMutex.Unlock()
r.lastSyncResourceVersion = v
rv, err := strconv.Atoi(v)
if err == nil {
r.metrics.lastResourceVersion.Set(float64(rv))
}
}

View File

@@ -228,12 +228,14 @@ func (config *DirectClientConfig) getUserIdentificationPartialConfig(configAuthI
// blindly overwrite existing values based on precedence
if len(configAuthInfo.Token) > 0 {
mergedConfig.BearerToken = configAuthInfo.Token
mergedConfig.BearerTokenFile = configAuthInfo.TokenFile
} else if len(configAuthInfo.TokenFile) > 0 {
ts := restclient.NewCachedFileTokenSource(configAuthInfo.TokenFile)
if _, err := ts.Token(); err != nil {
tokenBytes, err := ioutil.ReadFile(configAuthInfo.TokenFile)
if err != nil {
return nil, err
}
mergedConfig.WrapTransport = restclient.TokenSourceWrapTransport(ts)
mergedConfig.BearerToken = string(tokenBytes)
mergedConfig.BearerTokenFile = configAuthInfo.TokenFile
}
if len(configAuthInfo.Impersonate) > 0 {
mergedConfig.Impersonate = restclient.ImpersonationConfig{
@@ -498,8 +500,9 @@ func (config *inClusterClientConfig) ClientConfig() (*restclient.Config, error)
if server := config.overrides.ClusterInfo.Server; len(server) > 0 {
icc.Host = server
}
if token := config.overrides.AuthInfo.Token; len(token) > 0 {
icc.BearerToken = token
if len(config.overrides.AuthInfo.Token) > 0 || len(config.overrides.AuthInfo.TokenFile) > 0 {
icc.BearerToken = config.overrides.AuthInfo.Token
icc.BearerTokenFile = config.overrides.AuthInfo.TokenFile
}
if certificateAuthorityFile := config.overrides.ClusterInfo.CertificateAuthority; len(certificateAuthorityFile) > 0 {
icc.TLSClientConfig.CAFile = certificateAuthorityFile

View File

@@ -18,7 +18,6 @@ package clientcmd
import (
"io/ioutil"
"net/http"
"os"
"reflect"
"strings"
@@ -334,19 +333,7 @@ func TestBasicTokenFile(t *testing.T) {
t.Fatalf("Unexpected error: %v", err)
}
var out *http.Request
clientConfig.WrapTransport(fakeTransport(func(req *http.Request) (*http.Response, error) {
out = req
return &http.Response{}, nil
})).RoundTrip(&http.Request{})
matchStringArg(token, strings.TrimPrefix(out.Header.Get("Authorization"), "Bearer "), t)
}
type fakeTransport func(*http.Request) (*http.Response, error)
func (ft fakeTransport) RoundTrip(req *http.Request) (*http.Response, error) {
return ft(req)
matchStringArg(token, clientConfig.BearerToken, t)
}
func TestPrecedenceTokenFile(t *testing.T) {
@@ -561,6 +548,30 @@ func TestInClusterClientConfigPrecedence(t *testing.T) {
},
},
},
{
overrides: &ConfigOverrides{
ClusterInfo: clientcmdapi.Cluster{
Server: "https://host-from-overrides.com",
CertificateAuthority: "/path/to/ca-from-overrides.crt",
},
AuthInfo: clientcmdapi.AuthInfo{
Token: "token-from-override",
TokenFile: "tokenfile-from-override",
},
},
},
{
overrides: &ConfigOverrides{
ClusterInfo: clientcmdapi.Cluster{
Server: "https://host-from-overrides.com",
CertificateAuthority: "/path/to/ca-from-overrides.crt",
},
AuthInfo: clientcmdapi.AuthInfo{
Token: "",
TokenFile: "tokenfile-from-override",
},
},
},
{
overrides: &ConfigOverrides{},
},
@@ -569,13 +580,15 @@ func TestInClusterClientConfigPrecedence(t *testing.T) {
for _, tc := range tt {
expectedServer := "https://host-from-cluster.com"
expectedToken := "token-from-cluster"
expectedTokenFile := "tokenfile-from-cluster"
expectedCAFile := "/path/to/ca-from-cluster.crt"
icc := &inClusterClientConfig{
inClusterConfigProvider: func() (*restclient.Config, error) {
return &restclient.Config{
Host: expectedServer,
BearerToken: expectedToken,
Host: expectedServer,
BearerToken: expectedToken,
BearerTokenFile: expectedTokenFile,
TLSClientConfig: restclient.TLSClientConfig{
CAFile: expectedCAFile,
},
@@ -592,8 +605,9 @@ func TestInClusterClientConfigPrecedence(t *testing.T) {
if overridenServer := tc.overrides.ClusterInfo.Server; len(overridenServer) > 0 {
expectedServer = overridenServer
}
if overridenToken := tc.overrides.AuthInfo.Token; len(overridenToken) > 0 {
expectedToken = overridenToken
if len(tc.overrides.AuthInfo.Token) > 0 || len(tc.overrides.AuthInfo.TokenFile) > 0 {
expectedToken = tc.overrides.AuthInfo.Token
expectedTokenFile = tc.overrides.AuthInfo.TokenFile
}
if overridenCAFile := tc.overrides.ClusterInfo.CertificateAuthority; len(overridenCAFile) > 0 {
expectedCAFile = overridenCAFile
@@ -605,6 +619,9 @@ func TestInClusterClientConfigPrecedence(t *testing.T) {
if clientConfig.BearerToken != expectedToken {
t.Errorf("Expected token %v, got %v", expectedToken, clientConfig.BearerToken)
}
if clientConfig.BearerTokenFile != expectedTokenFile {
t.Errorf("Expected tokenfile %v, got %v", expectedTokenFile, clientConfig.BearerTokenFile)
}
if clientConfig.TLSClientConfig.CAFile != expectedCAFile {
t.Errorf("Expected Certificate Authority %v, got %v", expectedCAFile, clientConfig.TLSClientConfig.CAFile)
}

View File

@@ -39,6 +39,11 @@ type Config struct {
// Bearer token for authentication
BearerToken string
// Path to a file containing a BearerToken.
// If set, the contents are periodically read.
// The last successfully read value takes precedence over BearerToken.
BearerTokenFile string
// Impersonate is the config that this Config will impersonate using
Impersonate ImpersonationConfig
@@ -80,7 +85,7 @@ func (c *Config) HasBasicAuth() bool {
// HasTokenAuth returns whether the configuration has token authentication or not.
func (c *Config) HasTokenAuth() bool {
return len(c.BearerToken) != 0
return len(c.BearerToken) != 0 || len(c.BearerTokenFile) != 0
}
// HasCertAuth returns whether the configuration has certificate authentication or not.

View File

@@ -22,6 +22,7 @@ import (
"strings"
"time"
"golang.org/x/oauth2"
"k8s.io/klog"
utilnet "k8s.io/apimachinery/pkg/util/net"
@@ -44,7 +45,11 @@ func HTTPWrappersForConfig(config *Config, rt http.RoundTripper) (http.RoundTrip
case config.HasBasicAuth() && config.HasTokenAuth():
return nil, fmt.Errorf("username/password or bearer token may be set, but not both")
case config.HasTokenAuth():
rt = NewBearerAuthRoundTripper(config.BearerToken, rt)
var err error
rt, err = NewBearerAuthWithRefreshRoundTripper(config.BearerToken, config.BearerTokenFile, rt)
if err != nil {
return nil, err
}
case config.HasBasicAuth():
rt = NewBasicAuthRoundTripper(config.Username, config.Password, rt)
}
@@ -265,13 +270,35 @@ func (rt *impersonatingRoundTripper) WrappedRoundTripper() http.RoundTripper { r
type bearerAuthRoundTripper struct {
bearer string
source oauth2.TokenSource
rt http.RoundTripper
}
// NewBearerAuthRoundTripper adds the provided bearer token to a request
// unless the authorization header has already been set.
func NewBearerAuthRoundTripper(bearer string, rt http.RoundTripper) http.RoundTripper {
return &bearerAuthRoundTripper{bearer, rt}
return &bearerAuthRoundTripper{bearer, nil, rt}
}
// NewBearerAuthRoundTripper adds the provided bearer token to a request
// unless the authorization header has already been set.
// If tokenFile is non-empty, it is periodically read,
// and the last successfully read content is used as the bearer token.
// If tokenFile is non-empty and bearer is empty, the tokenFile is read
// immediately to populate the initial bearer token.
func NewBearerAuthWithRefreshRoundTripper(bearer string, tokenFile string, rt http.RoundTripper) (http.RoundTripper, error) {
if len(tokenFile) == 0 {
return &bearerAuthRoundTripper{bearer, nil, rt}, nil
}
source := NewCachedFileTokenSource(tokenFile)
if len(bearer) == 0 {
token, err := source.Token()
if err != nil {
return nil, err
}
bearer = token.AccessToken
}
return &bearerAuthRoundTripper{bearer, source, rt}, nil
}
func (rt *bearerAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
@@ -280,7 +307,13 @@ func (rt *bearerAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response,
}
req = utilnet.CloneRequest(req)
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", rt.bearer))
token := rt.bearer
if rt.source != nil {
if refreshedToken, err := rt.source.Token(); err == nil {
token = refreshedToken.AccessToken
}
}
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
return rt.rt.RoundTrip(req)
}

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package rest
package transport
import (
"fmt"
@@ -47,14 +47,14 @@ func TokenSourceWrapTransport(ts oauth2.TokenSource) func(http.RoundTripper) htt
func NewCachedFileTokenSource(path string) oauth2.TokenSource {
return &cachingTokenSource{
now: time.Now,
leeway: 1 * time.Minute,
leeway: 10 * time.Second,
base: &fileTokenSource{
path: path,
// This period was picked because it is half of the minimum validity
// duration for a token provisioned by they TokenRequest API. This is
// unsophisticated and should induce rotation at a frequency that should
// work with the token volume source.
period: 5 * time.Minute,
// This period was picked because it is half of the duration between when the kubelet
// refreshes a projected service account token and when the original token expires.
// Default token lifetime is 10 minutes, and the kubelet starts refreshing at 80% of lifetime.
// This should induce re-reading at a frequency that works with the token volume source.
period: time.Minute,
},
}
}

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package rest
package transport
import (
"fmt"