mirror of
https://github.com/kubernetes/client-go.git
synced 2026-06-27 12:15:25 +00:00
Compare commits
82 Commits
kubernetes
...
kubernetes
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
161ce6706f | ||
|
|
a32a6f7a30 | ||
|
|
f1dfb4fe82 | ||
|
|
16bcffe0e4 | ||
|
|
d528d16a5d | ||
|
|
d4e85bc08a | ||
|
|
a1d3d648d0 | ||
|
|
ba02bb8cc0 | ||
|
|
1132e72f6c | ||
|
|
b9197b961a | ||
|
|
3922ef2909 | ||
|
|
238f979bb4 | ||
|
|
98b61416aa | ||
|
|
7624422635 | ||
|
|
bc9b51d240 | ||
|
|
e9644b2e3e | ||
|
|
41735bf478 | ||
|
|
318a83db09 | ||
|
|
f8772cd39b | ||
|
|
8c19b9f4a6 | ||
|
|
6894652660 | ||
|
|
0e1c000cb7 | ||
|
|
8d0e6f1b7b | ||
|
|
c4788cee6e | ||
|
|
775f4ddf38 | ||
|
|
571c0ef670 | ||
|
|
7c85ddb6ae | ||
|
|
a2a1463427 | ||
|
|
145c0413a4 | ||
|
|
0a8a1d7b7f | ||
|
|
debe729c79 | ||
|
|
050872ffe7 | ||
|
|
6f03b71b98 | ||
|
|
af446e4f13 | ||
|
|
a4893d5271 | ||
|
|
d7b4c23325 | ||
|
|
1924198484 | ||
|
|
1f4f5fa64a | ||
|
|
74d7a2e0eb | ||
|
|
5971a24b40 | ||
|
|
d3ab799453 | ||
|
|
f5d68cde58 | ||
|
|
dac3b9c76a | ||
|
|
a56922bade | ||
|
|
9bbcc2938d | ||
|
|
ab63be7642 | ||
|
|
52589237eb | ||
|
|
7a5b91a7ca | ||
|
|
4bda71482c | ||
|
|
881cd219a8 | ||
|
|
370c449f1e | ||
|
|
c02e303b36 | ||
|
|
0dd469e42b | ||
|
|
4b146a95cd | ||
|
|
3c0d1af94b | ||
|
|
f8f007fd45 | ||
|
|
e55a71a3e0 | ||
|
|
656c97889d | ||
|
|
a537b3b527 | ||
|
|
6f1579c35d | ||
|
|
d4d115c905 | ||
|
|
a57d0056db | ||
|
|
d7ea50d263 | ||
|
|
d063930b33 | ||
|
|
d3a5e5f798 | ||
|
|
52092c3c67 | ||
|
|
a7c4a955b2 | ||
|
|
d46fe40533 | ||
|
|
93a8bb4af0 | ||
|
|
890ae18798 | ||
|
|
e9766ae820 | ||
|
|
940f075619 | ||
|
|
ecaa2792f4 | ||
|
|
7bd7ed8621 | ||
|
|
808ced1183 | ||
|
|
cd92d91e0f | ||
|
|
69cd73bcf4 | ||
|
|
5c806db031 | ||
|
|
a3f022a93c | ||
|
|
54033229aa | ||
|
|
5aa4fef661 | ||
|
|
7d13a606b3 |
@@ -1,8 +1,6 @@
|
||||
# Contributing guidelines
|
||||
|
||||
Do not open pull requests directly against this repository. They will be ignored. Instead, please open pull requests against [kubernetes/kubernetes](https://git.k8s.io/kubernetes/).
|
||||
The exception is changes to the `README.md` itself.
|
||||
Please follow the same [contributing guide](https://git.k8s.io/kubernetes/CONTRIBUTING.md) you would follow for any other pull request made to kubernetes/kubernetes.
|
||||
Do not open pull requests directly against kubernetes/client-go repository (except for README.md); they will be ignored. Instead, please open pull requests and issues against [kubernetes/kubernetes](https://git.k8s.io/kubernetes/). Please follow the same [contributing guide](https://git.k8s.io/kubernetes/CONTRIBUTING.md) you would follow for any other pull request made to kubernetes/kubernetes.
|
||||
|
||||
This repository is published from [kubernetes/kubernetes/staging/src/k8s.io/client-go](https://git.k8s.io/kubernetes/staging/src/k8s.io/client-go) by the [kubernetes publishing-bot](https://git.k8s.io/publishing-bot).
|
||||
|
||||
|
||||
40
Godeps/Godeps.json
generated
40
Godeps/Godeps.json
generated
@@ -164,7 +164,7 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gregjones/httpcache",
|
||||
"Rev": "787624de3eb7"
|
||||
"Rev": "9cad4c3443a7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/golang-lru",
|
||||
@@ -180,7 +180,7 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/json-iterator/go",
|
||||
"Rev": "v1.1.7"
|
||||
"Rev": "v1.1.8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jstemmer/go-junit-report",
|
||||
@@ -248,7 +248,7 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/spf13/pflag",
|
||||
"Rev": "v1.0.3"
|
||||
"Rev": "v1.0.5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/stretchr/objx",
|
||||
@@ -256,7 +256,7 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/stretchr/testify",
|
||||
"Rev": "v1.3.0"
|
||||
"Rev": "v1.4.0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "go.opencensus.io",
|
||||
@@ -264,7 +264,7 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto",
|
||||
"Rev": "e84da0312774"
|
||||
"Rev": "60c769a6c586"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/exp",
|
||||
@@ -272,35 +272,39 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/lint",
|
||||
"Rev": "8f45f776aaf1"
|
||||
"Rev": "5614ed5bae6f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net",
|
||||
"Rev": "cdfb69ac37fc"
|
||||
"Rev": "13f9640d40b9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/oauth2",
|
||||
"Rev": "9f3314589c9a"
|
||||
"Rev": "0f29369cfe45"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/sync",
|
||||
"Rev": "42b317875d0f"
|
||||
"Rev": "112230192c58"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/sys",
|
||||
"Rev": "3b5209105503"
|
||||
"Rev": "fde4db37ae7a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text",
|
||||
"Rev": "e6919f6577db"
|
||||
"Rev": "v0.3.2"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/time",
|
||||
"Rev": "f51c12702a4d"
|
||||
"Rev": "9d24e82272b4"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/tools",
|
||||
"Rev": "e65039ee4138"
|
||||
"Rev": "65e3620a7ae7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/xerrors",
|
||||
"Rev": "a985d3407aa7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "google.golang.org/api",
|
||||
@@ -328,7 +332,7 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/inf.v0",
|
||||
"Rev": "v0.9.0"
|
||||
"Rev": "v0.9.1"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/tomb.v1",
|
||||
@@ -344,11 +348,11 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/api",
|
||||
"Rev": "5524a3672fbb"
|
||||
"Rev": "v0.18.0-alpha.1"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/apimachinery",
|
||||
"Rev": "af6325b3a843"
|
||||
"Rev": "v0.18.0-alpha.1"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/gengo",
|
||||
@@ -360,11 +364,11 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi",
|
||||
"Rev": "743ec37842bf"
|
||||
"Rev": "30be4d16710a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/utils",
|
||||
"Rev": "8d271d903fe4"
|
||||
"Rev": "e782cd3c129f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "sigs.k8s.io/structured-merge-diff",
|
||||
|
||||
22
INSTALL.md
22
INSTALL.md
@@ -52,14 +52,30 @@ go mod init
|
||||
|
||||
### Add client-go as a dependency
|
||||
|
||||
Indicate which version of `client-go` your project requires (replace `kubernetes-1.15.0` with the desired version):
|
||||
Indicate which version of `client-go` your project requires:
|
||||
|
||||
- If you are using Kubernetes versions >= `v1.17.0`, use a corresponding
|
||||
`v0.x.y` tag. For example, `k8s.io/client-go@v0.17.0` corresponds to Kubernetes `v1.17.0`:
|
||||
|
||||
```sh
|
||||
go get k8s.io/client-go@kubernetes-1.15.0
|
||||
go get k8s.io/client-go@v0.17.0
|
||||
```
|
||||
|
||||
You can also use a non-semver `kubernetes-1.x.y` tag to refer to a version
|
||||
of `client-go` corresponding to a given Kubernetes release. Prior to Kubernetes
|
||||
`v1.17.0` these were the only tags available for use with go modules.
|
||||
For example, `kubernetes-1.16.3` corresponds to Kubernetes `v1.16.3`.
|
||||
However, it is recommended to use semver-like `v0.x.y` tags over non-semver
|
||||
`kubernetes-1.x.y` tags to have a seamless experience with go modules.
|
||||
|
||||
- If you are using Kubernetes versions < `v1.17.0` (replace `kubernetes-1.16.3` with the desired version):
|
||||
|
||||
```sh
|
||||
go get k8s.io/client-go@kubernetes-1.16.3
|
||||
```
|
||||
|
||||
You can now import and use the `k8s.io/client-go` APIs in your project.
|
||||
The next time you `go build`, `go test`, or `go run` your project,
|
||||
`k8s.io/client-go` and its dependencies will be downloaded (if needed),
|
||||
and detailed dependency version info will be added to your `go.mod` file
|
||||
(or you can also run `go mod tidy` to do this directly).
|
||||
(or you can also run `go mod tidy` to do this directly).
|
||||
|
||||
105
README.md
105
README.md
@@ -2,7 +2,8 @@
|
||||
|
||||
Go clients for talking to a [kubernetes](http://kubernetes.io/) cluster.
|
||||
|
||||
We recommend using the `kubernetes-1.x.y` tag matching the current Kubernetes release (`kubernetes-1.15.3` at the time this was written).
|
||||
We recommend using the `v0.x.y` tags for Kubernetes releases >= `v1.17.0` and
|
||||
`kubernetes-1.x.y` tags for Kubernetes releases < `v1.17.0`.
|
||||
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.
|
||||
|
||||
@@ -44,42 +45,31 @@ See [INSTALL.md](/INSTALL.md) for detailed installation instructions.
|
||||
|
||||
### Versioning
|
||||
|
||||
`client-go` follows [semver](http://semver.org/). We will not make
|
||||
backwards-incompatible changes without incrementing the major version number. A
|
||||
change is backwards-incompatible either if it *i)* changes the public interfaces
|
||||
of `client-go`, or *ii)* makes `client-go` incompatible with otherwise supported
|
||||
versions of Kubernetes clusters.
|
||||
- For each `v1.x.y` Kubernetes release, the major version (first digit)
|
||||
would remain `0`.
|
||||
|
||||
Changes that add features in a backwards-compatible way will result in bumping
|
||||
the minor version (second digit) number.
|
||||
|
||||
Bugfixes will result in the patch version (third digit) changing. PRs that are
|
||||
- Bugfixes will result in the patch version (third digit) changing. PRs that are
|
||||
cherry-picked into an older Kubernetes release branch will result in an update
|
||||
to the corresponding branch in `client-go`, with a corresponding new tag
|
||||
changing the patch version.
|
||||
|
||||
A consequence of this is that `client-go` version numbers will be unrelated to
|
||||
Kubernetes version numbers.
|
||||
|
||||
#### Branches and tags.
|
||||
|
||||
We will create a new branch and tag for each increment in the major version number or
|
||||
minor version number. We will create only a new tag for each increment in the patch
|
||||
We will create a new branch and tag for each increment in the minor version
|
||||
number. We will create only a new tag for each increment in the patch
|
||||
version number. See [semver](http://semver.org/) for definitions of major,
|
||||
minor, and patch.
|
||||
|
||||
The master branch will track HEAD in the main Kubernetes repo and
|
||||
accumulate changes. Consider HEAD to have the version `x.(y+1).0-alpha` or
|
||||
`(x+1).0.0-alpha` (depending on whether it has accumulated a breaking change or
|
||||
not), where `x` and `y` are the current major and minor versions.
|
||||
The HEAD of the master branch in client-go will track the HEAD of the master
|
||||
branch in the main Kubernetes repo.
|
||||
|
||||
#### Compatibility: your code <-> client-go
|
||||
|
||||
`client-go` follows [semver](http://semver.org/), so until the major version of
|
||||
client-go gets increased, your code will compile and will continue to work with
|
||||
explicitly supported versions of Kubernetes clusters. You must use a dependency
|
||||
management system and pin a specific major version of `client-go` to get this
|
||||
benefit, as HEAD follows the upstream Kubernetes repo.
|
||||
The `v0.x.y` tags indicate that go APIs may change in incompatible ways in
|
||||
different versions.
|
||||
|
||||
See [INSTALL.md](INSTALL.md) for guidelines on requiring a specific
|
||||
version of client-go.
|
||||
|
||||
#### Compatibility: client-go <-> Kubernetes clusters
|
||||
|
||||
@@ -92,16 +82,12 @@ We will backport bugfixes--but not new features--into older versions of
|
||||
|
||||
#### Compatibility matrix
|
||||
|
||||
| | Kubernetes 1.9 | Kubernetes 1.10 | Kubernetes 1.11 | Kubernetes 1.12 | Kubernetes 1.13 | Kubernetes 1.14 | Kubernetes 1.15 |
|
||||
|---------------------|----------------|-----------------|-----------------|-----------------|-----------------|-----------------|-----------------|
|
||||
| client-go 6.0 | ✓ | +- | +- | +- | +- | +- | +- |
|
||||
| client-go 7.0 | +- | ✓ | +- | +- | +- | +- | +- |
|
||||
| client-go 8.0 | +- | +- | ✓ | +- | +- | +- | +- |
|
||||
| client-go 9.0 | +- | +- | +- | ✓ | +- | +- | +- |
|
||||
| client-go 10.0 | +- | +- | +- | +- | ✓ | +- | +- |
|
||||
| client-go 11.0 | +- | +- | +- | +- | +- | ✓ | +- |
|
||||
| client-go 12.0 | +- | +- | +- | +- | +- | +- | ✓ |
|
||||
| client-go HEAD | +- | +- | +- | +- | +- | +- | +- |
|
||||
| | Kubernetes 1.15 | Kubernetes 1.16 | Kubernetes 1.17 |
|
||||
|-------------------------------|-----------------|-----------------|-----------------|
|
||||
| `kubernetes-1.15.0` | ✓ | +- | +- |
|
||||
| `kubernetes-1.16.0` | +- | ✓ | +- |
|
||||
| `kubernetes-1.17.0`/`v0.17.0` | +- | +- | ✓ |
|
||||
| `HEAD` | +- | +- | +- |
|
||||
|
||||
Key:
|
||||
|
||||
@@ -122,19 +108,21 @@ between client-go versions.
|
||||
|
||||
| Branch | Canonical source code location | Maintenance status |
|
||||
|----------------|--------------------------------------|-------------------------------|
|
||||
| client-go 1.4 | Kubernetes main repo, 1.4 branch | = - |
|
||||
| client-go 1.5 | Kubernetes main repo, 1.5 branch | = - |
|
||||
| client-go 2.0 | Kubernetes main repo, 1.5 branch | = - |
|
||||
| client-go 3.0 | Kubernetes main repo, 1.6 branch | = - |
|
||||
| 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 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 11.0 | Kubernetes main repo, 1.14 branch | ✓ |
|
||||
| client-go 12.0 | Kubernetes main repo, 1.15 branch | ✓ |
|
||||
| `release-1.4` | Kubernetes main repo, 1.4 branch | = - |
|
||||
| `release-1.5` | Kubernetes main repo, 1.5 branch | = - |
|
||||
| `release-2.0` | Kubernetes main repo, 1.5 branch | = - |
|
||||
| `release-3.0` | Kubernetes main repo, 1.6 branch | = - |
|
||||
| `release-4.0` | Kubernetes main repo, 1.7 branch | = - |
|
||||
| `release-5.0` | Kubernetes main repo, 1.8 branch | = - |
|
||||
| `release-6.0` | Kubernetes main repo, 1.9 branch | = - |
|
||||
| `release-7.0` | Kubernetes main repo, 1.10 branch | = - |
|
||||
| `release-8.0` | Kubernetes main repo, 1.11 branch | =- |
|
||||
| `release-9.0` | Kubernetes main repo, 1.12 branch | =- |
|
||||
| `release-10.0` | Kubernetes main repo, 1.13 branch | =- |
|
||||
| `release-11.0` | Kubernetes main repo, 1.14 branch | ✓ |
|
||||
| `release-12.0` | Kubernetes main repo, 1.15 branch | ✓ |
|
||||
| `release-13.0` | Kubernetes main repo, 1.16 branch | ✓ |
|
||||
| `release-14.0` | Kubernetes main repo, 1.17 branch | ✓ |
|
||||
| client-go HEAD | Kubernetes main repo, master branch | ✓ |
|
||||
|
||||
Key:
|
||||
@@ -161,14 +149,19 @@ existing users won't be broken.
|
||||
|
||||
This repository is still a mirror of
|
||||
[k8s.io/kubernetes/staging/src/client-go](https://github.com/kubernetes/kubernetes/tree/master/staging/src/k8s.io/client-go),
|
||||
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-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),
|
||||
the code development is still done in the staging area.
|
||||
|
||||
Since Kubernetes `v1.8.0`, when syncing the code from the staging area,
|
||||
we also sync the Kubernetes version tags to client-go, prefixed with
|
||||
`kubernetes-`. From Kubernetes `v1.17.0`, we also create matching semver
|
||||
`v0.x.y` tags for each `v1.x.y` Kubernetes release.
|
||||
|
||||
For example, if you check out the `kubernetes-1.17.0` or the `v0.17.0` tag in
|
||||
client-go, the code you get is exactly the same as if you check out the `v1.17.0`
|
||||
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),
|
||||
[apiextension-apiserver](https://github.com/kubernetes/apiextensions-apiserver),
|
||||
etc. The Kubernetes version tag does NOT claim any backwards compatibility
|
||||
guarantees for client-go. Please check the [semantic versions](#versioning) if
|
||||
@@ -179,7 +172,7 @@ you care about backwards compatibility.
|
||||
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
|
||||
go get k8s.io/client-go@v0.17.0
|
||||
```
|
||||
|
||||
See [INSTALL.md](/INSTALL.md) for detailed instructions.
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 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 dynamic provides a client interface to arbitrary Kubernetes
|
||||
// APIs that exposes common high level operations and exposes common
|
||||
// metadata.
|
||||
package deprecated_dynamic
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
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/types"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/dynamic"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// Interface is a Kubernetes client that allows you to access metadata
|
||||
// and manipulate metadata of a Kubernetes API group.
|
||||
type Interface interface {
|
||||
// Resource returns an API interface to the specified resource for this client's
|
||||
// group and version. If resource is not a namespaced resource, then namespace
|
||||
// is ignored. The ResourceInterface inherits the parameter codec of this client.
|
||||
Resource(resource *metav1.APIResource, namespace string) ResourceInterface
|
||||
}
|
||||
|
||||
// ResourceInterface is an API interface to a specific resource under a
|
||||
// dynamic client.
|
||||
type ResourceInterface interface {
|
||||
// List returns a list of objects for this resource.
|
||||
List(opts metav1.ListOptions) (runtime.Object, error)
|
||||
// Get gets the resource with the specified name.
|
||||
Get(name string, opts metav1.GetOptions) (*unstructured.Unstructured, error)
|
||||
// Delete deletes the resource with the specified name.
|
||||
Delete(name string, opts *metav1.DeleteOptions) error
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
DeleteCollection(deleteOptions *metav1.DeleteOptions, listOptions metav1.ListOptions) error
|
||||
// Create creates the provided resource.
|
||||
Create(obj *unstructured.Unstructured) (*unstructured.Unstructured, error)
|
||||
// Update updates the provided resource.
|
||||
Update(obj *unstructured.Unstructured) (*unstructured.Unstructured, error)
|
||||
// Watch returns a watch.Interface that watches the resource.
|
||||
Watch(opts metav1.ListOptions) (watch.Interface, error)
|
||||
// Patch patches the provided resource.
|
||||
Patch(name string, pt types.PatchType, data []byte) (*unstructured.Unstructured, error)
|
||||
}
|
||||
|
||||
// Client is a Kubernetes client that allows you to access metadata
|
||||
// and manipulate metadata of a Kubernetes API group, and implements Interface.
|
||||
type Client struct {
|
||||
version schema.GroupVersion
|
||||
delegate dynamic.Interface
|
||||
}
|
||||
|
||||
// NewClient returns a new client based on the passed in config. The
|
||||
// codec is ignored, as the dynamic client uses it's own codec.
|
||||
func NewClient(conf *restclient.Config, version schema.GroupVersion) (*Client, error) {
|
||||
delegate, err := dynamic.NewForConfig(conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Client{version: version, delegate: delegate}, nil
|
||||
}
|
||||
|
||||
// Resource returns an API interface to the specified resource for this client's
|
||||
// group and version. If resource is not a namespaced resource, then namespace
|
||||
// is ignored. The ResourceInterface inherits the parameter codec of c.
|
||||
func (c *Client) Resource(resource *metav1.APIResource, namespace string) ResourceInterface {
|
||||
resourceTokens := strings.SplitN(resource.Name, "/", 2)
|
||||
subresources := []string{}
|
||||
if len(resourceTokens) > 1 {
|
||||
subresources = strings.Split(resourceTokens[1], "/")
|
||||
}
|
||||
|
||||
if len(namespace) == 0 {
|
||||
return oldResourceShim(c.delegate.Resource(c.version.WithResource(resourceTokens[0])), subresources)
|
||||
}
|
||||
return oldResourceShim(c.delegate.Resource(c.version.WithResource(resourceTokens[0])).Namespace(namespace), subresources)
|
||||
}
|
||||
|
||||
// the old interfaces used the wrong type for lists. this fixes that
|
||||
func oldResourceShim(in dynamic.ResourceInterface, subresources []string) ResourceInterface {
|
||||
return oldResourceShimType{ResourceInterface: in, subresources: subresources}
|
||||
}
|
||||
|
||||
type oldResourceShimType struct {
|
||||
dynamic.ResourceInterface
|
||||
subresources []string
|
||||
}
|
||||
|
||||
func (s oldResourceShimType) Create(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
|
||||
return s.ResourceInterface.Create(obj, metav1.CreateOptions{}, s.subresources...)
|
||||
}
|
||||
|
||||
func (s oldResourceShimType) Update(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
|
||||
return s.ResourceInterface.Update(obj, metav1.UpdateOptions{}, s.subresources...)
|
||||
}
|
||||
|
||||
func (s oldResourceShimType) Delete(name string, opts *metav1.DeleteOptions) error {
|
||||
return s.ResourceInterface.Delete(name, opts, s.subresources...)
|
||||
}
|
||||
|
||||
func (s oldResourceShimType) Get(name string, opts metav1.GetOptions) (*unstructured.Unstructured, error) {
|
||||
return s.ResourceInterface.Get(name, opts, s.subresources...)
|
||||
}
|
||||
|
||||
func (s oldResourceShimType) List(opts metav1.ListOptions) (runtime.Object, error) {
|
||||
return s.ResourceInterface.List(opts)
|
||||
}
|
||||
|
||||
func (s oldResourceShimType) Patch(name string, pt types.PatchType, data []byte) (*unstructured.Unstructured, error) {
|
||||
return s.ResourceInterface.Patch(name, pt, data, metav1.PatchOptions{}, s.subresources...)
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 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 deprecated_dynamic
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// ClientPool manages a pool of dynamic clients.
|
||||
type ClientPool interface {
|
||||
// ClientForGroupVersionResource returns a client configured for the specified groupVersionResource.
|
||||
// Resource may be empty.
|
||||
ClientForGroupVersionResource(resource schema.GroupVersionResource) (Interface, error)
|
||||
// ClientForGroupVersionKind returns a client configured for the specified groupVersionKind.
|
||||
// Kind may be empty.
|
||||
ClientForGroupVersionKind(kind schema.GroupVersionKind) (Interface, error)
|
||||
}
|
||||
|
||||
// APIPathResolverFunc knows how to convert a groupVersion to its API path. The Kind field is
|
||||
// optional.
|
||||
type APIPathResolverFunc func(kind schema.GroupVersionKind) string
|
||||
|
||||
// LegacyAPIPathResolverFunc can resolve paths properly with the legacy API.
|
||||
func LegacyAPIPathResolverFunc(kind schema.GroupVersionKind) string {
|
||||
if len(kind.Group) == 0 {
|
||||
return "/api"
|
||||
}
|
||||
return "/apis"
|
||||
}
|
||||
|
||||
// clientPoolImpl implements ClientPool and caches clients for the resource group versions
|
||||
// is asked to retrieve. This type is thread safe.
|
||||
type clientPoolImpl struct {
|
||||
lock sync.RWMutex
|
||||
config *restclient.Config
|
||||
clients map[schema.GroupVersion]*Client
|
||||
apiPathResolverFunc APIPathResolverFunc
|
||||
mapper meta.RESTMapper
|
||||
}
|
||||
|
||||
// NewClientPool returns a ClientPool from the specified config. It reuses clients for the same
|
||||
// group version. It is expected this type may be wrapped by specific logic that special cases certain
|
||||
// resources or groups.
|
||||
func NewClientPool(config *restclient.Config, mapper meta.RESTMapper, apiPathResolverFunc APIPathResolverFunc) ClientPool {
|
||||
confCopy := *config
|
||||
|
||||
return &clientPoolImpl{
|
||||
config: &confCopy,
|
||||
clients: map[schema.GroupVersion]*Client{},
|
||||
apiPathResolverFunc: apiPathResolverFunc,
|
||||
mapper: mapper,
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiates a new dynamic client pool with the given config.
|
||||
func NewDynamicClientPool(cfg *restclient.Config) ClientPool {
|
||||
// restMapper is not needed when using LegacyAPIPathResolverFunc
|
||||
emptyMapper := meta.MultiRESTMapper{}
|
||||
return NewClientPool(cfg, emptyMapper, LegacyAPIPathResolverFunc)
|
||||
}
|
||||
|
||||
// ClientForGroupVersionResource uses the provided RESTMapper to identify the appropriate resource. Resource may
|
||||
// be empty. If no matching kind is found the underlying client for that group is still returned.
|
||||
func (c *clientPoolImpl) ClientForGroupVersionResource(resource schema.GroupVersionResource) (Interface, error) {
|
||||
kinds, err := c.mapper.KindsFor(resource)
|
||||
if err != nil {
|
||||
if meta.IsNoMatchError(err) {
|
||||
return c.ClientForGroupVersionKind(schema.GroupVersionKind{Group: resource.Group, Version: resource.Version})
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return c.ClientForGroupVersionKind(kinds[0])
|
||||
}
|
||||
|
||||
// ClientForGroupVersion returns a client for the specified groupVersion, creates one if none exists. Kind
|
||||
// in the GroupVersionKind may be empty.
|
||||
func (c *clientPoolImpl) ClientForGroupVersionKind(kind schema.GroupVersionKind) (Interface, error) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
gv := kind.GroupVersion()
|
||||
|
||||
// do we have a client already configured?
|
||||
if existingClient, found := c.clients[gv]; found {
|
||||
return existingClient, nil
|
||||
}
|
||||
|
||||
// avoid changing the original config
|
||||
confCopy := *c.config
|
||||
conf := &confCopy
|
||||
|
||||
// we need to set the api path based on group version, if no group, default to legacy path
|
||||
conf.APIPath = c.apiPathResolverFunc(kind)
|
||||
|
||||
// we need to make a client
|
||||
conf.GroupVersion = &gv
|
||||
|
||||
dynamicClient, err := NewClient(conf, gv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.clients[gv] = dynamicClient
|
||||
return dynamicClient, nil
|
||||
}
|
||||
@@ -1,624 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 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 deprecated_dynamic
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
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/runtime/serializer/streaming"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
restclientwatch "k8s.io/client-go/rest/watch"
|
||||
)
|
||||
|
||||
func getJSON(version, kind, name string) []byte {
|
||||
return []byte(fmt.Sprintf(`{"apiVersion": %q, "kind": %q, "metadata": {"name": %q}}`, version, kind, name))
|
||||
}
|
||||
|
||||
func getListJSON(version, kind string, items ...[]byte) []byte {
|
||||
json := fmt.Sprintf(`{"apiVersion": %q, "kind": %q, "items": [%s]}`,
|
||||
version, kind, bytes.Join(items, []byte(",")))
|
||||
return []byte(json)
|
||||
}
|
||||
|
||||
func getObject(version, kind, name string) *unstructured.Unstructured {
|
||||
return &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": version,
|
||||
"kind": kind,
|
||||
"metadata": map[string]interface{}{
|
||||
"name": name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getClientServer(gv *schema.GroupVersion, h func(http.ResponseWriter, *http.Request)) (Interface, *httptest.Server, error) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(h))
|
||||
cl, err := NewClient(&restclient.Config{
|
||||
Host: srv.URL,
|
||||
ContentConfig: restclient.ContentConfig{GroupVersion: gv},
|
||||
}, *gv)
|
||||
if err != nil {
|
||||
srv.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
return cl, srv, nil
|
||||
}
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
namespace string
|
||||
path string
|
||||
resp []byte
|
||||
want *unstructured.UnstructuredList
|
||||
}{
|
||||
{
|
||||
name: "normal_list",
|
||||
path: "/apis/gtest/vtest/rtest",
|
||||
resp: getListJSON("vTest", "rTestList",
|
||||
getJSON("vTest", "rTest", "item1"),
|
||||
getJSON("vTest", "rTest", "item2")),
|
||||
want: &unstructured.UnstructuredList{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "vTest",
|
||||
"kind": "rTestList",
|
||||
},
|
||||
Items: []unstructured.Unstructured{
|
||||
*getObject("vTest", "rTest", "item1"),
|
||||
*getObject("vTest", "rTest", "item2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "namespaced_list",
|
||||
namespace: "nstest",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest",
|
||||
resp: getListJSON("vTest", "rTestList",
|
||||
getJSON("vTest", "rTest", "item1"),
|
||||
getJSON("vTest", "rTest", "item2")),
|
||||
want: &unstructured.UnstructuredList{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "vTest",
|
||||
"kind": "rTestList",
|
||||
},
|
||||
Items: []unstructured.Unstructured{
|
||||
*getObject("vTest", "rTest", "item1"),
|
||||
*getObject("vTest", "rTest", "item2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
t.Errorf("List(%q) got HTTP method %s. wanted GET", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("List(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", runtime.ContentTypeJSON)
|
||||
w.Write(tc.resp)
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
got, err := cl.Resource(resource, tc.namespace).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when listing %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tc.want) {
|
||||
t.Errorf("List(%q) want: %v\ngot: %v", tc.name, tc.want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
tcs := []struct {
|
||||
resource string
|
||||
namespace string
|
||||
name string
|
||||
path string
|
||||
resp []byte
|
||||
want *unstructured.Unstructured
|
||||
}{
|
||||
{
|
||||
resource: "rtest",
|
||||
name: "normal_get",
|
||||
path: "/apis/gtest/vtest/rtest/normal_get",
|
||||
resp: getJSON("vTest", "rTest", "normal_get"),
|
||||
want: getObject("vTest", "rTest", "normal_get"),
|
||||
},
|
||||
{
|
||||
resource: "rtest",
|
||||
namespace: "nstest",
|
||||
name: "namespaced_get",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_get",
|
||||
resp: getJSON("vTest", "rTest", "namespaced_get"),
|
||||
want: getObject("vTest", "rTest", "namespaced_get"),
|
||||
},
|
||||
{
|
||||
resource: "rtest/srtest",
|
||||
name: "normal_subresource_get",
|
||||
path: "/apis/gtest/vtest/rtest/normal_subresource_get/srtest",
|
||||
resp: getJSON("vTest", "srTest", "normal_subresource_get"),
|
||||
want: getObject("vTest", "srTest", "normal_subresource_get"),
|
||||
},
|
||||
{
|
||||
resource: "rtest/srtest",
|
||||
namespace: "nstest",
|
||||
name: "namespaced_subresource_get",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_subresource_get/srtest",
|
||||
resp: getJSON("vTest", "srTest", "namespaced_subresource_get"),
|
||||
want: getObject("vTest", "srTest", "namespaced_subresource_get"),
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: tc.resource, Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
t.Errorf("Get(%q) got HTTP method %s. wanted GET", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("Get(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", runtime.ContentTypeJSON)
|
||||
w.Write(tc.resp)
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
got, err := cl.Resource(resource, tc.namespace).Get(tc.name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when getting %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tc.want) {
|
||||
t.Errorf("Get(%q) want: %v\ngot: %v", tc.name, tc.want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
background := metav1.DeletePropagationBackground
|
||||
uid := types.UID("uid")
|
||||
|
||||
statusOK := &metav1.Status{
|
||||
TypeMeta: metav1.TypeMeta{Kind: "Status"},
|
||||
Status: metav1.StatusSuccess,
|
||||
}
|
||||
tcs := []struct {
|
||||
namespace string
|
||||
name string
|
||||
path string
|
||||
deleteOptions *metav1.DeleteOptions
|
||||
}{
|
||||
{
|
||||
name: "normal_delete",
|
||||
path: "/apis/gtest/vtest/rtest/normal_delete",
|
||||
},
|
||||
{
|
||||
namespace: "nstest",
|
||||
name: "namespaced_delete",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_delete",
|
||||
},
|
||||
{
|
||||
namespace: "nstest",
|
||||
name: "namespaced_delete_with_options",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_delete_with_options",
|
||||
deleteOptions: &metav1.DeleteOptions{Preconditions: &metav1.Preconditions{UID: &uid}, PropagationPolicy: &background},
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "DELETE" {
|
||||
t.Errorf("Delete(%q) got HTTP method %s. wanted DELETE", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("Delete(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", runtime.ContentTypeJSON)
|
||||
unstructured.UnstructuredJSONScheme.Encode(statusOK, w)
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
err = cl.Resource(resource, tc.namespace).Delete(tc.name, tc.deleteOptions)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when deleting %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteCollection(t *testing.T) {
|
||||
statusOK := &metav1.Status{
|
||||
TypeMeta: metav1.TypeMeta{Kind: "Status"},
|
||||
Status: metav1.StatusSuccess,
|
||||
}
|
||||
tcs := []struct {
|
||||
namespace string
|
||||
name string
|
||||
path string
|
||||
}{
|
||||
{
|
||||
name: "normal_delete_collection",
|
||||
path: "/apis/gtest/vtest/rtest",
|
||||
},
|
||||
{
|
||||
namespace: "nstest",
|
||||
name: "namespaced_delete_collection",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest",
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "DELETE" {
|
||||
t.Errorf("DeleteCollection(%q) got HTTP method %s. wanted DELETE", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("DeleteCollection(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", runtime.ContentTypeJSON)
|
||||
unstructured.UnstructuredJSONScheme.Encode(statusOK, w)
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
err = cl.Resource(resource, tc.namespace).DeleteCollection(nil, metav1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when deleting collection %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
tcs := []struct {
|
||||
resource string
|
||||
name string
|
||||
namespace string
|
||||
obj *unstructured.Unstructured
|
||||
path string
|
||||
}{
|
||||
{
|
||||
resource: "rtest",
|
||||
name: "normal_create",
|
||||
path: "/apis/gtest/vtest/rtest",
|
||||
obj: getObject("gtest/vTest", "rTest", "normal_create"),
|
||||
},
|
||||
{
|
||||
resource: "rtest",
|
||||
name: "namespaced_create",
|
||||
namespace: "nstest",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest",
|
||||
obj: getObject("gtest/vTest", "rTest", "namespaced_create"),
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: tc.resource, Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
t.Errorf("Create(%q) got HTTP method %s. wanted POST", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("Create(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", runtime.ContentTypeJSON)
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Errorf("Create(%q) unexpected error reading body: %v", tc.name, err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(data)
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
got, err := cl.Resource(resource, tc.namespace).Create(tc.obj)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tc.obj) {
|
||||
t.Errorf("Create(%q) want: %v\ngot: %v", tc.name, tc.obj, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
tcs := []struct {
|
||||
resource string
|
||||
name string
|
||||
namespace string
|
||||
obj *unstructured.Unstructured
|
||||
path string
|
||||
}{
|
||||
{
|
||||
resource: "rtest",
|
||||
name: "normal_update",
|
||||
path: "/apis/gtest/vtest/rtest/normal_update",
|
||||
obj: getObject("gtest/vTest", "rTest", "normal_update"),
|
||||
},
|
||||
{
|
||||
resource: "rtest",
|
||||
name: "namespaced_update",
|
||||
namespace: "nstest",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_update",
|
||||
obj: getObject("gtest/vTest", "rTest", "namespaced_update"),
|
||||
},
|
||||
{
|
||||
resource: "rtest/srtest",
|
||||
name: "normal_subresource_update",
|
||||
path: "/apis/gtest/vtest/rtest/normal_update/srtest",
|
||||
obj: getObject("gtest/vTest", "srTest", "normal_update"),
|
||||
},
|
||||
{
|
||||
resource: "rtest/srtest",
|
||||
name: "namespaced_subresource_update",
|
||||
namespace: "nstest",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_update/srtest",
|
||||
obj: getObject("gtest/vTest", "srTest", "namespaced_update"),
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: tc.resource, Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "PUT" {
|
||||
t.Errorf("Update(%q) got HTTP method %s. wanted PUT", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("Update(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", runtime.ContentTypeJSON)
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Errorf("Update(%q) unexpected error reading body: %v", tc.name, err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(data)
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
got, err := cl.Resource(resource, tc.namespace).Update(tc.obj)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when updating %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tc.obj) {
|
||||
t.Errorf("Update(%q) want: %v\ngot: %v", tc.name, tc.obj, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWatch(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
namespace string
|
||||
events []watch.Event
|
||||
path string
|
||||
query string
|
||||
}{
|
||||
{
|
||||
name: "normal_watch",
|
||||
path: "/apis/gtest/vtest/rtest",
|
||||
query: "watch=true",
|
||||
events: []watch.Event{
|
||||
{Type: watch.Added, Object: getObject("gtest/vTest", "rTest", "normal_watch")},
|
||||
{Type: watch.Modified, Object: getObject("gtest/vTest", "rTest", "normal_watch")},
|
||||
{Type: watch.Deleted, Object: getObject("gtest/vTest", "rTest", "normal_watch")},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "namespaced_watch",
|
||||
namespace: "nstest",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest",
|
||||
query: "watch=true",
|
||||
events: []watch.Event{
|
||||
{Type: watch.Added, Object: getObject("gtest/vTest", "rTest", "namespaced_watch")},
|
||||
{Type: watch.Modified, Object: getObject("gtest/vTest", "rTest", "namespaced_watch")},
|
||||
{Type: watch.Deleted, Object: getObject("gtest/vTest", "rTest", "namespaced_watch")},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
t.Errorf("Watch(%q) got HTTP method %s. wanted GET", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("Watch(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
if r.URL.RawQuery != tc.query {
|
||||
t.Errorf("Watch(%q) got query %s. wanted %s", tc.name, r.URL.RawQuery, tc.query)
|
||||
}
|
||||
|
||||
codec := unstructured.UnstructuredJSONScheme
|
||||
enc := restclientwatch.NewEncoder(streaming.NewEncoder(w, codec), codec)
|
||||
for _, e := range tc.events {
|
||||
enc.Encode(&e)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
watcher, err := cl.Resource(resource, tc.namespace).Watch(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when watching %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, want := range tc.events {
|
||||
got := <-watcher.ResultChan()
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("Watch(%q) want: %v\ngot: %v", tc.name, want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPatch(t *testing.T) {
|
||||
tcs := []struct {
|
||||
resource string
|
||||
name string
|
||||
namespace string
|
||||
patch []byte
|
||||
want *unstructured.Unstructured
|
||||
path string
|
||||
}{
|
||||
{
|
||||
resource: "rtest",
|
||||
name: "normal_patch",
|
||||
path: "/apis/gtest/vtest/rtest/normal_patch",
|
||||
patch: getJSON("gtest/vTest", "rTest", "normal_patch"),
|
||||
want: getObject("gtest/vTest", "rTest", "normal_patch"),
|
||||
},
|
||||
{
|
||||
resource: "rtest",
|
||||
name: "namespaced_patch",
|
||||
namespace: "nstest",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_patch",
|
||||
patch: getJSON("gtest/vTest", "rTest", "namespaced_patch"),
|
||||
want: getObject("gtest/vTest", "rTest", "namespaced_patch"),
|
||||
},
|
||||
{
|
||||
resource: "rtest/srtest",
|
||||
name: "normal_subresource_patch",
|
||||
path: "/apis/gtest/vtest/rtest/normal_subresource_patch/srtest",
|
||||
patch: getJSON("gtest/vTest", "srTest", "normal_subresource_patch"),
|
||||
want: getObject("gtest/vTest", "srTest", "normal_subresource_patch"),
|
||||
},
|
||||
{
|
||||
resource: "rtest/srtest",
|
||||
name: "namespaced_subresource_patch",
|
||||
namespace: "nstest",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_subresource_patch/srtest",
|
||||
patch: getJSON("gtest/vTest", "srTest", "namespaced_subresource_patch"),
|
||||
want: getObject("gtest/vTest", "srTest", "namespaced_subresource_patch"),
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: tc.resource, Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "PATCH" {
|
||||
t.Errorf("Patch(%q) got HTTP method %s. wanted PATCH", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("Patch(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
content := r.Header.Get("Content-Type")
|
||||
if content != string(types.StrategicMergePatchType) {
|
||||
t.Errorf("Patch(%q) got Content-Type %s. wanted %s", tc.name, content, types.StrategicMergePatchType)
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Errorf("Patch(%q) unexpected error reading body: %v", tc.name, err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(data)
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
got, err := cl.Resource(resource, tc.namespace).Patch(tc.name, types.StrategicMergePatchType, tc.patch)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when patching %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tc.want) {
|
||||
t.Errorf("Patch(%q) want: %v\ngot: %v", tc.name, tc.want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -463,6 +463,13 @@ func setDiscoveryDefaults(config *restclient.Config) error {
|
||||
if config.Timeout == 0 {
|
||||
config.Timeout = defaultTimeout
|
||||
}
|
||||
if config.Burst == 0 && config.QPS < 100 {
|
||||
// discovery is expected to be bursty, increase the default burst
|
||||
// to accommodate looking up resource info for many API groups.
|
||||
// matches burst set by ConfigFlags#ToDiscoveryClient().
|
||||
// see https://issue.k8s.io/86149
|
||||
config.Burst = 100
|
||||
}
|
||||
codec := runtime.NoopEncoder{Decoder: scheme.Codecs.UniversalDecoder()}
|
||||
config.NegotiatedSerializer = serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{Serializer: codec})
|
||||
if len(config.UserAgent) == 0 {
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/googleapis/gnostic/OpenAPIv2"
|
||||
@@ -198,6 +199,26 @@ func TestGetServerResources(t *testing.T) {
|
||||
{Name: "jobs", Namespaced: true, Kind: "Job"},
|
||||
},
|
||||
}
|
||||
extensionsbeta3 := metav1.APIResourceList{GroupVersion: "extensions/v1beta3", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}}
|
||||
extensionsbeta4 := metav1.APIResourceList{GroupVersion: "extensions/v1beta4", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}}
|
||||
extensionsbeta5 := metav1.APIResourceList{GroupVersion: "extensions/v1beta5", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}}
|
||||
extensionsbeta6 := metav1.APIResourceList{GroupVersion: "extensions/v1beta6", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}}
|
||||
extensionsbeta7 := metav1.APIResourceList{GroupVersion: "extensions/v1beta7", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}}
|
||||
extensionsbeta8 := metav1.APIResourceList{GroupVersion: "extensions/v1beta8", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}}
|
||||
extensionsbeta9 := metav1.APIResourceList{GroupVersion: "extensions/v1beta9", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}}
|
||||
extensionsbeta10 := metav1.APIResourceList{GroupVersion: "extensions/v1beta10", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}}
|
||||
|
||||
appsbeta1 := metav1.APIResourceList{GroupVersion: "apps/v1beta1", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}}
|
||||
appsbeta2 := metav1.APIResourceList{GroupVersion: "apps/v1beta2", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}}
|
||||
appsbeta3 := metav1.APIResourceList{GroupVersion: "apps/v1beta3", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}}
|
||||
appsbeta4 := metav1.APIResourceList{GroupVersion: "apps/v1beta4", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}}
|
||||
appsbeta5 := metav1.APIResourceList{GroupVersion: "apps/v1beta5", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}}
|
||||
appsbeta6 := metav1.APIResourceList{GroupVersion: "apps/v1beta6", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}}
|
||||
appsbeta7 := metav1.APIResourceList{GroupVersion: "apps/v1beta7", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}}
|
||||
appsbeta8 := metav1.APIResourceList{GroupVersion: "apps/v1beta8", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}}
|
||||
appsbeta9 := metav1.APIResourceList{GroupVersion: "apps/v1beta9", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}}
|
||||
appsbeta10 := metav1.APIResourceList{GroupVersion: "apps/v1beta10", APIResources: []metav1.APIResource{{Name: "deployments", Namespaced: true, Kind: "Deployment"}}}
|
||||
|
||||
tests := []struct {
|
||||
resourcesList *metav1.APIResourceList
|
||||
path string
|
||||
@@ -232,6 +253,42 @@ func TestGetServerResources(t *testing.T) {
|
||||
list = &beta
|
||||
case "/apis/extensions/v1beta2":
|
||||
list = &beta2
|
||||
case "/apis/extensions/v1beta3":
|
||||
list = &extensionsbeta3
|
||||
case "/apis/extensions/v1beta4":
|
||||
list = &extensionsbeta4
|
||||
case "/apis/extensions/v1beta5":
|
||||
list = &extensionsbeta5
|
||||
case "/apis/extensions/v1beta6":
|
||||
list = &extensionsbeta6
|
||||
case "/apis/extensions/v1beta7":
|
||||
list = &extensionsbeta7
|
||||
case "/apis/extensions/v1beta8":
|
||||
list = &extensionsbeta8
|
||||
case "/apis/extensions/v1beta9":
|
||||
list = &extensionsbeta9
|
||||
case "/apis/extensions/v1beta10":
|
||||
list = &extensionsbeta10
|
||||
case "/apis/apps/v1beta1":
|
||||
list = &appsbeta1
|
||||
case "/apis/apps/v1beta2":
|
||||
list = &appsbeta2
|
||||
case "/apis/apps/v1beta3":
|
||||
list = &appsbeta3
|
||||
case "/apis/apps/v1beta4":
|
||||
list = &appsbeta4
|
||||
case "/apis/apps/v1beta5":
|
||||
list = &appsbeta5
|
||||
case "/apis/apps/v1beta6":
|
||||
list = &appsbeta6
|
||||
case "/apis/apps/v1beta7":
|
||||
list = &appsbeta7
|
||||
case "/apis/apps/v1beta8":
|
||||
list = &appsbeta8
|
||||
case "/apis/apps/v1beta9":
|
||||
list = &appsbeta9
|
||||
case "/apis/apps/v1beta10":
|
||||
list = &appsbeta10
|
||||
case "/api":
|
||||
list = &metav1.APIVersions{
|
||||
Versions: []string{
|
||||
@@ -241,11 +298,34 @@ func TestGetServerResources(t *testing.T) {
|
||||
case "/apis":
|
||||
list = &metav1.APIGroupList{
|
||||
Groups: []metav1.APIGroup{
|
||||
{
|
||||
Name: "apps",
|
||||
Versions: []metav1.GroupVersionForDiscovery{
|
||||
{GroupVersion: "apps/v1beta1", Version: "v1beta1"},
|
||||
{GroupVersion: "apps/v1beta2", Version: "v1beta2"},
|
||||
{GroupVersion: "apps/v1beta3", Version: "v1beta3"},
|
||||
{GroupVersion: "apps/v1beta4", Version: "v1beta4"},
|
||||
{GroupVersion: "apps/v1beta5", Version: "v1beta5"},
|
||||
{GroupVersion: "apps/v1beta6", Version: "v1beta6"},
|
||||
{GroupVersion: "apps/v1beta7", Version: "v1beta7"},
|
||||
{GroupVersion: "apps/v1beta8", Version: "v1beta8"},
|
||||
{GroupVersion: "apps/v1beta9", Version: "v1beta9"},
|
||||
{GroupVersion: "apps/v1beta10", Version: "v1beta10"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "extensions",
|
||||
Versions: []metav1.GroupVersionForDiscovery{
|
||||
{GroupVersion: "extensions/v1beta1", Version: "v1beta1"},
|
||||
{GroupVersion: "extensions/v1beta2", Version: "v1beta2"},
|
||||
{GroupVersion: "extensions/v1beta3", Version: "v1beta3"},
|
||||
{GroupVersion: "extensions/v1beta4", Version: "v1beta4"},
|
||||
{GroupVersion: "extensions/v1beta5", Version: "v1beta5"},
|
||||
{GroupVersion: "extensions/v1beta6", Version: "v1beta6"},
|
||||
{GroupVersion: "extensions/v1beta7", Version: "v1beta7"},
|
||||
{GroupVersion: "extensions/v1beta8", Version: "v1beta8"},
|
||||
{GroupVersion: "extensions/v1beta9", Version: "v1beta9"},
|
||||
{GroupVersion: "extensions/v1beta10", Version: "v1beta10"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -265,8 +345,8 @@ func TestGetServerResources(t *testing.T) {
|
||||
w.Write(output)
|
||||
}))
|
||||
defer server.Close()
|
||||
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
|
||||
for _, test := range tests {
|
||||
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
|
||||
got, err := client.ServerResourcesForGroupVersion(test.request)
|
||||
if test.expectErr {
|
||||
if err == nil {
|
||||
@@ -283,12 +363,40 @@ func TestGetServerResources(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
|
||||
start := time.Now()
|
||||
serverResources, err := client.ServerResources()
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
end := time.Now()
|
||||
if d := end.Sub(start); d > time.Second {
|
||||
t.Errorf("took too long to perform discovery: %s", d)
|
||||
}
|
||||
serverGroupVersions := groupVersions(serverResources)
|
||||
expectedGroupVersions := []string{"v1", "extensions/v1beta1", "extensions/v1beta2"}
|
||||
expectedGroupVersions := []string{
|
||||
"v1",
|
||||
"apps/v1beta1",
|
||||
"apps/v1beta2",
|
||||
"apps/v1beta3",
|
||||
"apps/v1beta4",
|
||||
"apps/v1beta5",
|
||||
"apps/v1beta6",
|
||||
"apps/v1beta7",
|
||||
"apps/v1beta8",
|
||||
"apps/v1beta9",
|
||||
"apps/v1beta10",
|
||||
"extensions/v1beta1",
|
||||
"extensions/v1beta2",
|
||||
"extensions/v1beta3",
|
||||
"extensions/v1beta4",
|
||||
"extensions/v1beta5",
|
||||
"extensions/v1beta6",
|
||||
"extensions/v1beta7",
|
||||
"extensions/v1beta8",
|
||||
"extensions/v1beta9",
|
||||
"extensions/v1beta10",
|
||||
}
|
||||
if !reflect.DeepEqual(expectedGroupVersions, serverGroupVersions) {
|
||||
t.Errorf("unexpected group versions: %v", diff.ObjectReflectDiff(expectedGroupVersions, serverGroupVersions))
|
||||
}
|
||||
|
||||
@@ -537,6 +537,8 @@ func TestWatch(t *testing.T) {
|
||||
t.Errorf("Watch(%q) got query %s. wanted %s", tc.name, r.URL.RawQuery, tc.query)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
enc := restclientwatch.NewEncoder(streaming.NewEncoder(w, unstructured.UnstructuredJSONScheme), unstructured.UnstructuredJSONScheme)
|
||||
for _, e := range tc.events {
|
||||
enc.Encode(&e)
|
||||
|
||||
@@ -18,11 +18,11 @@ package dynamic
|
||||
|
||||
import (
|
||||
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/runtime/serializer"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/versioning"
|
||||
)
|
||||
|
||||
var watchScheme = runtime.NewScheme()
|
||||
@@ -41,37 +41,6 @@ func init() {
|
||||
metav1.AddToGroupVersion(deleteScheme, versionV1)
|
||||
}
|
||||
|
||||
var watchJsonSerializerInfo = runtime.SerializerInfo{
|
||||
MediaType: "application/json",
|
||||
MediaTypeType: "application",
|
||||
MediaTypeSubType: "json",
|
||||
EncodesAsText: true,
|
||||
Serializer: json.NewSerializer(json.DefaultMetaFactory, watchScheme, watchScheme, false),
|
||||
PrettySerializer: json.NewSerializer(json.DefaultMetaFactory, watchScheme, watchScheme, true),
|
||||
StreamSerializer: &runtime.StreamSerializerInfo{
|
||||
EncodesAsText: true,
|
||||
Serializer: json.NewSerializer(json.DefaultMetaFactory, watchScheme, watchScheme, false),
|
||||
Framer: json.Framer,
|
||||
},
|
||||
}
|
||||
|
||||
// watchNegotiatedSerializer is used to read the wrapper of the watch stream
|
||||
type watchNegotiatedSerializer struct{}
|
||||
|
||||
var watchNegotiatedSerializerInstance = watchNegotiatedSerializer{}
|
||||
|
||||
func (s watchNegotiatedSerializer) SupportedMediaTypes() []runtime.SerializerInfo {
|
||||
return []runtime.SerializerInfo{watchJsonSerializerInfo}
|
||||
}
|
||||
|
||||
func (s watchNegotiatedSerializer) EncoderForVersion(encoder runtime.Encoder, gv runtime.GroupVersioner) runtime.Encoder {
|
||||
return versioning.NewDefaultingCodecForScheme(watchScheme, encoder, nil, gv, nil)
|
||||
}
|
||||
|
||||
func (s watchNegotiatedSerializer) DecoderToVersion(decoder runtime.Decoder, gv runtime.GroupVersioner) runtime.Decoder {
|
||||
return versioning.NewDefaultingCodecForScheme(watchScheme, nil, decoder, nil, gv)
|
||||
}
|
||||
|
||||
// basicNegotiatedSerializer is used to handle discovery and error handling serialization
|
||||
type basicNegotiatedSerializer struct{}
|
||||
|
||||
@@ -82,8 +51,8 @@ func (s basicNegotiatedSerializer) SupportedMediaTypes() []runtime.SerializerInf
|
||||
MediaTypeType: "application",
|
||||
MediaTypeSubType: "json",
|
||||
EncodesAsText: true,
|
||||
Serializer: json.NewSerializer(json.DefaultMetaFactory, basicScheme, basicScheme, false),
|
||||
PrettySerializer: json.NewSerializer(json.DefaultMetaFactory, basicScheme, basicScheme, true),
|
||||
Serializer: json.NewSerializer(json.DefaultMetaFactory, unstructuredCreater{basicScheme}, unstructuredTyper{basicScheme}, false),
|
||||
PrettySerializer: json.NewSerializer(json.DefaultMetaFactory, unstructuredCreater{basicScheme}, unstructuredTyper{basicScheme}, true),
|
||||
StreamSerializer: &runtime.StreamSerializerInfo{
|
||||
EncodesAsText: true,
|
||||
Serializer: json.NewSerializer(json.DefaultMetaFactory, basicScheme, basicScheme, false),
|
||||
@@ -94,9 +63,46 @@ func (s basicNegotiatedSerializer) SupportedMediaTypes() []runtime.SerializerInf
|
||||
}
|
||||
|
||||
func (s basicNegotiatedSerializer) EncoderForVersion(encoder runtime.Encoder, gv runtime.GroupVersioner) runtime.Encoder {
|
||||
return versioning.NewDefaultingCodecForScheme(watchScheme, encoder, nil, gv, nil)
|
||||
return runtime.WithVersionEncoder{
|
||||
Version: gv,
|
||||
Encoder: encoder,
|
||||
ObjectTyper: unstructuredTyper{basicScheme},
|
||||
}
|
||||
}
|
||||
|
||||
func (s basicNegotiatedSerializer) DecoderToVersion(decoder runtime.Decoder, gv runtime.GroupVersioner) runtime.Decoder {
|
||||
return versioning.NewDefaultingCodecForScheme(watchScheme, nil, decoder, nil, gv)
|
||||
return decoder
|
||||
}
|
||||
|
||||
type unstructuredCreater struct {
|
||||
nested runtime.ObjectCreater
|
||||
}
|
||||
|
||||
func (c unstructuredCreater) New(kind schema.GroupVersionKind) (runtime.Object, error) {
|
||||
out, err := c.nested.New(kind)
|
||||
if err == nil {
|
||||
return out, nil
|
||||
}
|
||||
out = &unstructured.Unstructured{}
|
||||
out.GetObjectKind().SetGroupVersionKind(kind)
|
||||
return out, nil
|
||||
}
|
||||
|
||||
type unstructuredTyper struct {
|
||||
nested runtime.ObjectTyper
|
||||
}
|
||||
|
||||
func (t unstructuredTyper) ObjectKinds(obj runtime.Object) ([]schema.GroupVersionKind, bool, error) {
|
||||
kinds, unversioned, err := t.nested.ObjectKinds(obj)
|
||||
if err == nil {
|
||||
return kinds, unversioned, nil
|
||||
}
|
||||
if _, ok := obj.(runtime.Unstructured); ok && !obj.GetObjectKind().GroupVersionKind().Empty() {
|
||||
return []schema.GroupVersionKind{obj.GetObjectKind().GroupVersionKind()}, false, nil
|
||||
}
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
func (t unstructuredTyper) Recognizes(gvk schema.GroupVersionKind) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -18,14 +18,12 @@ package dynamic
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"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/runtime/serializer/streaming"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/rest"
|
||||
@@ -282,31 +280,10 @@ func (c *dynamicResourceClient) List(opts metav1.ListOptions) (*unstructured.Uns
|
||||
}
|
||||
|
||||
func (c *dynamicResourceClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
|
||||
internalGV := schema.GroupVersions{
|
||||
{Group: c.resource.Group, Version: runtime.APIVersionInternal},
|
||||
// always include the legacy group as a decoding target to handle non-error `Status` return types
|
||||
{Group: "", Version: runtime.APIVersionInternal},
|
||||
}
|
||||
s := &rest.Serializers{
|
||||
Encoder: watchNegotiatedSerializerInstance.EncoderForVersion(watchJsonSerializerInfo.Serializer, c.resource.GroupVersion()),
|
||||
Decoder: watchNegotiatedSerializerInstance.DecoderToVersion(watchJsonSerializerInfo.Serializer, internalGV),
|
||||
|
||||
RenegotiatedDecoder: func(contentType string, params map[string]string) (runtime.Decoder, error) {
|
||||
return watchNegotiatedSerializerInstance.DecoderToVersion(watchJsonSerializerInfo.Serializer, internalGV), nil
|
||||
},
|
||||
StreamingSerializer: watchJsonSerializerInfo.StreamSerializer.Serializer,
|
||||
Framer: watchJsonSerializerInfo.StreamSerializer.Framer,
|
||||
}
|
||||
|
||||
wrappedDecoderFn := func(body io.ReadCloser) streaming.Decoder {
|
||||
framer := s.Framer.NewFrameReader(body)
|
||||
return streaming.NewDecoder(framer, s.StreamingSerializer)
|
||||
}
|
||||
|
||||
opts.Watch = true
|
||||
return c.client.client.Get().AbsPath(c.makeURLSegments("")...).
|
||||
SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
|
||||
WatchWithSpecificDecoders(wrappedDecoderFn, unstructured.UnstructuredJSONScheme)
|
||||
Watch()
|
||||
}
|
||||
|
||||
func (c *dynamicResourceClient) Patch(name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (*unstructured.Unstructured, error) {
|
||||
|
||||
34
go.mod
34
go.mod
@@ -2,7 +2,7 @@
|
||||
|
||||
module k8s.io/client-go
|
||||
|
||||
go 1.12
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.38.0 // indirect
|
||||
@@ -18,32 +18,26 @@ require (
|
||||
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-20170728041850-787624de3eb7
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7
|
||||
github.com/imdario/mergo v0.3.5
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible
|
||||
github.com/spf13/pflag v1.0.3
|
||||
github.com/stretchr/testify v1.3.0
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.4.0
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586
|
||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4
|
||||
google.golang.org/appengine v1.5.0 // indirect
|
||||
k8s.io/api v0.0.0-20191025225708-5524a3672fbb
|
||||
k8s.io/apimachinery v0.0.0-20191025225532-af6325b3a843
|
||||
k8s.io/api v0.18.0-alpha.1
|
||||
k8s.io/apimachinery v0.18.0-alpha.1
|
||||
k8s.io/klog v1.0.0
|
||||
k8s.io/utils v0.0.0-20191010214722-8d271d903fe4
|
||||
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f
|
||||
sigs.k8s.io/yaml v1.1.0
|
||||
)
|
||||
|
||||
replace (
|
||||
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/net => golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc
|
||||
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-20191025225708-5524a3672fbb
|
||||
k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20191025225532-af6325b3a843
|
||||
golang.org/x/sys => golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a // pinned to release-branch.go1.13
|
||||
golang.org/x/tools => golang.org/x/tools v0.0.0-20190821162956-65e3620a7ae7 // pinned to release-branch.go1.13
|
||||
k8s.io/api => k8s.io/api v0.18.0-alpha.1
|
||||
k8s.io/apimachinery => k8s.io/apimachinery v0.18.0-alpha.1
|
||||
)
|
||||
|
||||
89
go.sum
89
go.sum
@@ -72,8 +72,8 @@ github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1
|
||||
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-20170728041850-787624de3eb7 h1:6TSoaYExHper8PYsJu23GWVNOyYRCSnIFyxKgLSZ54w=
|
||||
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
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/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=
|
||||
@@ -83,8 +83,8 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
|
||||
github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q=
|
||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok=
|
||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
@@ -118,35 +118,54 @@ 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.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||
github.com/spf13/pflag v1.0.3/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/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=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
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/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/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
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/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=
|
||||
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/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=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
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-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=
|
||||
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=
|
||||
@@ -162,8 +181,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.0 h1:3zYtXIO92bvsdS3ggAdA8Gb4Azj0YU+TVY1uGYNFA8o=
|
||||
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/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=
|
||||
@@ -174,17 +193,17 @@ 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.0.0-20191025225708-5524a3672fbb/go.mod h1:NMIXwlJTrA+pXie6lv562GUPkluJ4oRGzQfqWBLaceY=
|
||||
k8s.io/apimachinery v0.0.0-20191025225532-af6325b3a843/go.mod h1:gA1T9z4LIup7PIegBwxkF2UYXUNVKhOAPvQWWnAc34k=
|
||||
k8s.io/api v0.18.0-alpha.1/go.mod h1:X82bXHlVEfxpVA9rO5PMaSOdQ+VdlSjT9A2Tl/CWL4A=
|
||||
k8s.io/apimachinery v0.18.0-alpha.1/go.mod h1:Ng1IY8TS7sC44KJxT/WUR6qFRfWwahYYYpNXyYRKOCY=
|
||||
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=
|
||||
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-20191010214722-8d271d903fe4 h1:Gi+/O1saihwDqnlmC8Vhv1M5Sp4+rbOmK9TbsLn8ZEA=
|
||||
k8s.io/utils v0.0.0-20191010214722-8d271d903fe4/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU=
|
||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
|
||||
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo=
|
||||
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/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=
|
||||
|
||||
@@ -20,6 +20,7 @@ package discovery
|
||||
|
||||
import (
|
||||
v1alpha1 "k8s.io/client-go/informers/discovery/v1alpha1"
|
||||
v1beta1 "k8s.io/client-go/informers/discovery/v1beta1"
|
||||
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
|
||||
)
|
||||
|
||||
@@ -27,6 +28,8 @@ import (
|
||||
type Interface interface {
|
||||
// V1alpha1 provides access to shared informers for resources in V1alpha1.
|
||||
V1alpha1() v1alpha1.Interface
|
||||
// V1beta1 provides access to shared informers for resources in V1beta1.
|
||||
V1beta1() v1beta1.Interface
|
||||
}
|
||||
|
||||
type group struct {
|
||||
@@ -44,3 +47,8 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList
|
||||
func (g *group) V1alpha1() v1alpha1.Interface {
|
||||
return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions)
|
||||
}
|
||||
|
||||
// V1beta1 returns a new v1beta1.Interface.
|
||||
func (g *group) V1beta1() v1beta1.Interface {
|
||||
return v1beta1.New(g.factory, g.namespace, g.tweakListOptions)
|
||||
}
|
||||
|
||||
89
informers/discovery/v1beta1/endpointslice.go
Normal file
89
informers/discovery/v1beta1/endpointslice.go
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
time "time"
|
||||
|
||||
discoveryv1beta1 "k8s.io/api/discovery/v1beta1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
|
||||
kubernetes "k8s.io/client-go/kubernetes"
|
||||
v1beta1 "k8s.io/client-go/listers/discovery/v1beta1"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// EndpointSliceInformer provides access to a shared informer and lister for
|
||||
// EndpointSlices.
|
||||
type EndpointSliceInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() v1beta1.EndpointSliceLister
|
||||
}
|
||||
|
||||
type endpointSliceInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
namespace string
|
||||
}
|
||||
|
||||
// NewEndpointSliceInformer constructs a new informer for EndpointSlice type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewEndpointSliceInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return NewFilteredEndpointSliceInformer(client, namespace, resyncPeriod, indexers, nil)
|
||||
}
|
||||
|
||||
// NewFilteredEndpointSliceInformer constructs a new informer for EndpointSlice type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewFilteredEndpointSliceInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
|
||||
return cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.DiscoveryV1beta1().EndpointSlices(namespace).List(options)
|
||||
},
|
||||
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.DiscoveryV1beta1().EndpointSlices(namespace).Watch(options)
|
||||
},
|
||||
},
|
||||
&discoveryv1beta1.EndpointSlice{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *endpointSliceInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewFilteredEndpointSliceInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *endpointSliceInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&discoveryv1beta1.EndpointSlice{}, f.defaultInformer)
|
||||
}
|
||||
|
||||
func (f *endpointSliceInformer) Lister() v1beta1.EndpointSliceLister {
|
||||
return v1beta1.NewEndpointSliceLister(f.Informer().GetIndexer())
|
||||
}
|
||||
45
informers/discovery/v1beta1/interface.go
Normal file
45
informers/discovery/v1beta1/interface.go
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
|
||||
)
|
||||
|
||||
// Interface provides access to all the informers in this group version.
|
||||
type Interface interface {
|
||||
// EndpointSlices returns a EndpointSliceInformer.
|
||||
EndpointSlices() EndpointSliceInformer
|
||||
}
|
||||
|
||||
type version struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
namespace string
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
}
|
||||
|
||||
// New returns a new Interface.
|
||||
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
|
||||
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
|
||||
}
|
||||
|
||||
// EndpointSlices returns a EndpointSliceInformer.
|
||||
func (v *version) EndpointSlices() EndpointSliceInformer {
|
||||
return &endpointSliceInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
}
|
||||
@@ -37,6 +37,7 @@ import (
|
||||
discovery "k8s.io/client-go/informers/discovery"
|
||||
events "k8s.io/client-go/informers/events"
|
||||
extensions "k8s.io/client-go/informers/extensions"
|
||||
flowcontrol "k8s.io/client-go/informers/flowcontrol"
|
||||
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
|
||||
networking "k8s.io/client-go/informers/networking"
|
||||
node "k8s.io/client-go/informers/node"
|
||||
@@ -200,6 +201,7 @@ type SharedInformerFactory interface {
|
||||
Discovery() discovery.Interface
|
||||
Events() events.Interface
|
||||
Extensions() extensions.Interface
|
||||
Flowcontrol() flowcontrol.Interface
|
||||
Networking() networking.Interface
|
||||
Node() node.Interface
|
||||
Policy() policy.Interface
|
||||
@@ -253,6 +255,10 @@ func (f *sharedInformerFactory) Extensions() extensions.Interface {
|
||||
return extensions.New(f, f.namespace, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *sharedInformerFactory) Flowcontrol() flowcontrol.Interface {
|
||||
return flowcontrol.New(f, f.namespace, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *sharedInformerFactory) Networking() networking.Interface {
|
||||
return networking.New(f, f.namespace, f.tweakListOptions)
|
||||
}
|
||||
|
||||
46
informers/flowcontrol/interface.go
Normal file
46
informers/flowcontrol/interface.go
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package flowcontrol
|
||||
|
||||
import (
|
||||
v1alpha1 "k8s.io/client-go/informers/flowcontrol/v1alpha1"
|
||||
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
|
||||
)
|
||||
|
||||
// Interface provides access to each of this group's versions.
|
||||
type Interface interface {
|
||||
// V1alpha1 provides access to shared informers for resources in V1alpha1.
|
||||
V1alpha1() v1alpha1.Interface
|
||||
}
|
||||
|
||||
type group struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
namespace string
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
}
|
||||
|
||||
// New returns a new Interface.
|
||||
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
|
||||
return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
|
||||
}
|
||||
|
||||
// V1alpha1 returns a new v1alpha1.Interface.
|
||||
func (g *group) V1alpha1() v1alpha1.Interface {
|
||||
return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions)
|
||||
}
|
||||
88
informers/flowcontrol/v1alpha1/flowschema.go
Normal file
88
informers/flowcontrol/v1alpha1/flowschema.go
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
time "time"
|
||||
|
||||
flowcontrolv1alpha1 "k8s.io/api/flowcontrol/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
|
||||
kubernetes "k8s.io/client-go/kubernetes"
|
||||
v1alpha1 "k8s.io/client-go/listers/flowcontrol/v1alpha1"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// FlowSchemaInformer provides access to a shared informer and lister for
|
||||
// FlowSchemas.
|
||||
type FlowSchemaInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() v1alpha1.FlowSchemaLister
|
||||
}
|
||||
|
||||
type flowSchemaInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
}
|
||||
|
||||
// NewFlowSchemaInformer constructs a new informer for FlowSchema type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewFlowSchemaInformer(client kubernetes.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return NewFilteredFlowSchemaInformer(client, resyncPeriod, indexers, nil)
|
||||
}
|
||||
|
||||
// NewFilteredFlowSchemaInformer constructs a new informer for FlowSchema type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewFilteredFlowSchemaInformer(client kubernetes.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
|
||||
return cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.FlowcontrolV1alpha1().FlowSchemas().List(options)
|
||||
},
|
||||
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.FlowcontrolV1alpha1().FlowSchemas().Watch(options)
|
||||
},
|
||||
},
|
||||
&flowcontrolv1alpha1.FlowSchema{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *flowSchemaInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewFilteredFlowSchemaInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *flowSchemaInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&flowcontrolv1alpha1.FlowSchema{}, f.defaultInformer)
|
||||
}
|
||||
|
||||
func (f *flowSchemaInformer) Lister() v1alpha1.FlowSchemaLister {
|
||||
return v1alpha1.NewFlowSchemaLister(f.Informer().GetIndexer())
|
||||
}
|
||||
52
informers/flowcontrol/v1alpha1/interface.go
Normal file
52
informers/flowcontrol/v1alpha1/interface.go
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
|
||||
)
|
||||
|
||||
// Interface provides access to all the informers in this group version.
|
||||
type Interface interface {
|
||||
// FlowSchemas returns a FlowSchemaInformer.
|
||||
FlowSchemas() FlowSchemaInformer
|
||||
// PriorityLevelConfigurations returns a PriorityLevelConfigurationInformer.
|
||||
PriorityLevelConfigurations() PriorityLevelConfigurationInformer
|
||||
}
|
||||
|
||||
type version struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
namespace string
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
}
|
||||
|
||||
// New returns a new Interface.
|
||||
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
|
||||
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
|
||||
}
|
||||
|
||||
// FlowSchemas returns a FlowSchemaInformer.
|
||||
func (v *version) FlowSchemas() FlowSchemaInformer {
|
||||
return &flowSchemaInformer{factory: v.factory, tweakListOptions: v.tweakListOptions}
|
||||
}
|
||||
|
||||
// PriorityLevelConfigurations returns a PriorityLevelConfigurationInformer.
|
||||
func (v *version) PriorityLevelConfigurations() PriorityLevelConfigurationInformer {
|
||||
return &priorityLevelConfigurationInformer{factory: v.factory, tweakListOptions: v.tweakListOptions}
|
||||
}
|
||||
88
informers/flowcontrol/v1alpha1/prioritylevelconfiguration.go
Normal file
88
informers/flowcontrol/v1alpha1/prioritylevelconfiguration.go
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
time "time"
|
||||
|
||||
flowcontrolv1alpha1 "k8s.io/api/flowcontrol/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
|
||||
kubernetes "k8s.io/client-go/kubernetes"
|
||||
v1alpha1 "k8s.io/client-go/listers/flowcontrol/v1alpha1"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// PriorityLevelConfigurationInformer provides access to a shared informer and lister for
|
||||
// PriorityLevelConfigurations.
|
||||
type PriorityLevelConfigurationInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() v1alpha1.PriorityLevelConfigurationLister
|
||||
}
|
||||
|
||||
type priorityLevelConfigurationInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
}
|
||||
|
||||
// NewPriorityLevelConfigurationInformer constructs a new informer for PriorityLevelConfiguration type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewPriorityLevelConfigurationInformer(client kubernetes.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return NewFilteredPriorityLevelConfigurationInformer(client, resyncPeriod, indexers, nil)
|
||||
}
|
||||
|
||||
// NewFilteredPriorityLevelConfigurationInformer constructs a new informer for PriorityLevelConfiguration type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewFilteredPriorityLevelConfigurationInformer(client kubernetes.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
|
||||
return cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.FlowcontrolV1alpha1().PriorityLevelConfigurations().List(options)
|
||||
},
|
||||
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.FlowcontrolV1alpha1().PriorityLevelConfigurations().Watch(options)
|
||||
},
|
||||
},
|
||||
&flowcontrolv1alpha1.PriorityLevelConfiguration{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *priorityLevelConfigurationInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewFilteredPriorityLevelConfigurationInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *priorityLevelConfigurationInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&flowcontrolv1alpha1.PriorityLevelConfiguration{}, f.defaultInformer)
|
||||
}
|
||||
|
||||
func (f *priorityLevelConfigurationInformer) Lister() v1alpha1.PriorityLevelConfigurationLister {
|
||||
return v1alpha1.NewPriorityLevelConfigurationLister(f.Informer().GetIndexer())
|
||||
}
|
||||
@@ -38,8 +38,10 @@ import (
|
||||
coordinationv1beta1 "k8s.io/api/coordination/v1beta1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
discoveryv1alpha1 "k8s.io/api/discovery/v1alpha1"
|
||||
discoveryv1beta1 "k8s.io/api/discovery/v1beta1"
|
||||
eventsv1beta1 "k8s.io/api/events/v1beta1"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
flowcontrolv1alpha1 "k8s.io/api/flowcontrol/v1alpha1"
|
||||
networkingv1 "k8s.io/api/networking/v1"
|
||||
networkingv1beta1 "k8s.io/api/networking/v1beta1"
|
||||
nodev1alpha1 "k8s.io/api/node/v1alpha1"
|
||||
@@ -207,6 +209,10 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
|
||||
case discoveryv1alpha1.SchemeGroupVersion.WithResource("endpointslices"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Discovery().V1alpha1().EndpointSlices().Informer()}, nil
|
||||
|
||||
// Group=discovery.k8s.io, Version=v1beta1
|
||||
case discoveryv1beta1.SchemeGroupVersion.WithResource("endpointslices"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Discovery().V1beta1().EndpointSlices().Informer()}, nil
|
||||
|
||||
// Group=events.k8s.io, Version=v1beta1
|
||||
case eventsv1beta1.SchemeGroupVersion.WithResource("events"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Events().V1beta1().Events().Informer()}, nil
|
||||
@@ -225,6 +231,12 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
|
||||
case extensionsv1beta1.SchemeGroupVersion.WithResource("replicasets"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Extensions().V1beta1().ReplicaSets().Informer()}, nil
|
||||
|
||||
// Group=flowcontrol.apiserver.k8s.io, Version=v1alpha1
|
||||
case flowcontrolv1alpha1.SchemeGroupVersion.WithResource("flowschemas"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Flowcontrol().V1alpha1().FlowSchemas().Informer()}, nil
|
||||
case flowcontrolv1alpha1.SchemeGroupVersion.WithResource("prioritylevelconfigurations"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Flowcontrol().V1alpha1().PriorityLevelConfigurations().Informer()}, nil
|
||||
|
||||
// Group=networking.k8s.io, Version=v1
|
||||
case networkingv1.SchemeGroupVersion.WithResource("networkpolicies"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Networking().V1().NetworkPolicies().Informer()}, nil
|
||||
@@ -294,6 +306,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Settings().V1alpha1().PodPresets().Informer()}, nil
|
||||
|
||||
// Group=storage.k8s.io, Version=v1
|
||||
case storagev1.SchemeGroupVersion.WithResource("csinodes"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Storage().V1().CSINodes().Informer()}, nil
|
||||
case storagev1.SchemeGroupVersion.WithResource("storageclasses"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Storage().V1().StorageClasses().Informer()}, nil
|
||||
case storagev1.SchemeGroupVersion.WithResource("volumeattachments"):
|
||||
|
||||
88
informers/storage/v1/csinode.go
Normal file
88
informers/storage/v1/csinode.go
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
time "time"
|
||||
|
||||
storagev1 "k8s.io/api/storage/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
|
||||
kubernetes "k8s.io/client-go/kubernetes"
|
||||
v1 "k8s.io/client-go/listers/storage/v1"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// CSINodeInformer provides access to a shared informer and lister for
|
||||
// CSINodes.
|
||||
type CSINodeInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() v1.CSINodeLister
|
||||
}
|
||||
|
||||
type cSINodeInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
}
|
||||
|
||||
// NewCSINodeInformer constructs a new informer for CSINode type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewCSINodeInformer(client kubernetes.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return NewFilteredCSINodeInformer(client, resyncPeriod, indexers, nil)
|
||||
}
|
||||
|
||||
// NewFilteredCSINodeInformer constructs a new informer for CSINode type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewFilteredCSINodeInformer(client kubernetes.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
|
||||
return cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.StorageV1().CSINodes().List(options)
|
||||
},
|
||||
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.StorageV1().CSINodes().Watch(options)
|
||||
},
|
||||
},
|
||||
&storagev1.CSINode{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *cSINodeInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewFilteredCSINodeInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *cSINodeInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&storagev1.CSINode{}, f.defaultInformer)
|
||||
}
|
||||
|
||||
func (f *cSINodeInformer) Lister() v1.CSINodeLister {
|
||||
return v1.NewCSINodeLister(f.Informer().GetIndexer())
|
||||
}
|
||||
@@ -24,6 +24,8 @@ import (
|
||||
|
||||
// Interface provides access to all the informers in this group version.
|
||||
type Interface interface {
|
||||
// CSINodes returns a CSINodeInformer.
|
||||
CSINodes() CSINodeInformer
|
||||
// StorageClasses returns a StorageClassInformer.
|
||||
StorageClasses() StorageClassInformer
|
||||
// VolumeAttachments returns a VolumeAttachmentInformer.
|
||||
@@ -41,6 +43,11 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList
|
||||
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
|
||||
}
|
||||
|
||||
// CSINodes returns a CSINodeInformer.
|
||||
func (v *version) CSINodes() CSINodeInformer {
|
||||
return &cSINodeInformer{factory: v.factory, tweakListOptions: v.tweakListOptions}
|
||||
}
|
||||
|
||||
// StorageClasses returns a StorageClassInformer.
|
||||
func (v *version) StorageClasses() StorageClassInformer {
|
||||
return &storageClassInformer{factory: v.factory, tweakListOptions: v.tweakListOptions}
|
||||
|
||||
@@ -43,8 +43,10 @@ import (
|
||||
coordinationv1beta1 "k8s.io/client-go/kubernetes/typed/coordination/v1beta1"
|
||||
corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
discoveryv1alpha1 "k8s.io/client-go/kubernetes/typed/discovery/v1alpha1"
|
||||
discoveryv1beta1 "k8s.io/client-go/kubernetes/typed/discovery/v1beta1"
|
||||
eventsv1beta1 "k8s.io/client-go/kubernetes/typed/events/v1beta1"
|
||||
extensionsv1beta1 "k8s.io/client-go/kubernetes/typed/extensions/v1beta1"
|
||||
flowcontrolv1alpha1 "k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1"
|
||||
networkingv1 "k8s.io/client-go/kubernetes/typed/networking/v1"
|
||||
networkingv1beta1 "k8s.io/client-go/kubernetes/typed/networking/v1beta1"
|
||||
nodev1alpha1 "k8s.io/client-go/kubernetes/typed/node/v1alpha1"
|
||||
@@ -87,8 +89,10 @@ type Interface interface {
|
||||
CoordinationV1() coordinationv1.CoordinationV1Interface
|
||||
CoreV1() corev1.CoreV1Interface
|
||||
DiscoveryV1alpha1() discoveryv1alpha1.DiscoveryV1alpha1Interface
|
||||
DiscoveryV1beta1() discoveryv1beta1.DiscoveryV1beta1Interface
|
||||
EventsV1beta1() eventsv1beta1.EventsV1beta1Interface
|
||||
ExtensionsV1beta1() extensionsv1beta1.ExtensionsV1beta1Interface
|
||||
FlowcontrolV1alpha1() flowcontrolv1alpha1.FlowcontrolV1alpha1Interface
|
||||
NetworkingV1() networkingv1.NetworkingV1Interface
|
||||
NetworkingV1beta1() networkingv1beta1.NetworkingV1beta1Interface
|
||||
NodeV1alpha1() nodev1alpha1.NodeV1alpha1Interface
|
||||
@@ -131,8 +135,10 @@ type Clientset struct {
|
||||
coordinationV1 *coordinationv1.CoordinationV1Client
|
||||
coreV1 *corev1.CoreV1Client
|
||||
discoveryV1alpha1 *discoveryv1alpha1.DiscoveryV1alpha1Client
|
||||
discoveryV1beta1 *discoveryv1beta1.DiscoveryV1beta1Client
|
||||
eventsV1beta1 *eventsv1beta1.EventsV1beta1Client
|
||||
extensionsV1beta1 *extensionsv1beta1.ExtensionsV1beta1Client
|
||||
flowcontrolV1alpha1 *flowcontrolv1alpha1.FlowcontrolV1alpha1Client
|
||||
networkingV1 *networkingv1.NetworkingV1Client
|
||||
networkingV1beta1 *networkingv1beta1.NetworkingV1beta1Client
|
||||
nodeV1alpha1 *nodev1alpha1.NodeV1alpha1Client
|
||||
@@ -255,6 +261,11 @@ func (c *Clientset) DiscoveryV1alpha1() discoveryv1alpha1.DiscoveryV1alpha1Inter
|
||||
return c.discoveryV1alpha1
|
||||
}
|
||||
|
||||
// DiscoveryV1beta1 retrieves the DiscoveryV1beta1Client
|
||||
func (c *Clientset) DiscoveryV1beta1() discoveryv1beta1.DiscoveryV1beta1Interface {
|
||||
return c.discoveryV1beta1
|
||||
}
|
||||
|
||||
// EventsV1beta1 retrieves the EventsV1beta1Client
|
||||
func (c *Clientset) EventsV1beta1() eventsv1beta1.EventsV1beta1Interface {
|
||||
return c.eventsV1beta1
|
||||
@@ -265,6 +276,11 @@ func (c *Clientset) ExtensionsV1beta1() extensionsv1beta1.ExtensionsV1beta1Inter
|
||||
return c.extensionsV1beta1
|
||||
}
|
||||
|
||||
// FlowcontrolV1alpha1 retrieves the FlowcontrolV1alpha1Client
|
||||
func (c *Clientset) FlowcontrolV1alpha1() flowcontrolv1alpha1.FlowcontrolV1alpha1Interface {
|
||||
return c.flowcontrolV1alpha1
|
||||
}
|
||||
|
||||
// NetworkingV1 retrieves the NetworkingV1Client
|
||||
func (c *Clientset) NetworkingV1() networkingv1.NetworkingV1Interface {
|
||||
return c.networkingV1
|
||||
@@ -445,6 +461,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cs.discoveryV1beta1, err = discoveryv1beta1.NewForConfig(&configShallowCopy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cs.eventsV1beta1, err = eventsv1beta1.NewForConfig(&configShallowCopy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -453,6 +473,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cs.flowcontrolV1alpha1, err = flowcontrolv1alpha1.NewForConfig(&configShallowCopy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cs.networkingV1, err = networkingv1.NewForConfig(&configShallowCopy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -546,8 +570,10 @@ func NewForConfigOrDie(c *rest.Config) *Clientset {
|
||||
cs.coordinationV1 = coordinationv1.NewForConfigOrDie(c)
|
||||
cs.coreV1 = corev1.NewForConfigOrDie(c)
|
||||
cs.discoveryV1alpha1 = discoveryv1alpha1.NewForConfigOrDie(c)
|
||||
cs.discoveryV1beta1 = discoveryv1beta1.NewForConfigOrDie(c)
|
||||
cs.eventsV1beta1 = eventsv1beta1.NewForConfigOrDie(c)
|
||||
cs.extensionsV1beta1 = extensionsv1beta1.NewForConfigOrDie(c)
|
||||
cs.flowcontrolV1alpha1 = flowcontrolv1alpha1.NewForConfigOrDie(c)
|
||||
cs.networkingV1 = networkingv1.NewForConfigOrDie(c)
|
||||
cs.networkingV1beta1 = networkingv1beta1.NewForConfigOrDie(c)
|
||||
cs.nodeV1alpha1 = nodev1alpha1.NewForConfigOrDie(c)
|
||||
@@ -592,8 +618,10 @@ func New(c rest.Interface) *Clientset {
|
||||
cs.coordinationV1 = coordinationv1.New(c)
|
||||
cs.coreV1 = corev1.New(c)
|
||||
cs.discoveryV1alpha1 = discoveryv1alpha1.New(c)
|
||||
cs.discoveryV1beta1 = discoveryv1beta1.New(c)
|
||||
cs.eventsV1beta1 = eventsv1beta1.New(c)
|
||||
cs.extensionsV1beta1 = extensionsv1beta1.New(c)
|
||||
cs.flowcontrolV1alpha1 = flowcontrolv1alpha1.New(c)
|
||||
cs.networkingV1 = networkingv1.New(c)
|
||||
cs.networkingV1beta1 = networkingv1beta1.New(c)
|
||||
cs.nodeV1alpha1 = nodev1alpha1.New(c)
|
||||
|
||||
@@ -66,10 +66,14 @@ import (
|
||||
fakecorev1 "k8s.io/client-go/kubernetes/typed/core/v1/fake"
|
||||
discoveryv1alpha1 "k8s.io/client-go/kubernetes/typed/discovery/v1alpha1"
|
||||
fakediscoveryv1alpha1 "k8s.io/client-go/kubernetes/typed/discovery/v1alpha1/fake"
|
||||
discoveryv1beta1 "k8s.io/client-go/kubernetes/typed/discovery/v1beta1"
|
||||
fakediscoveryv1beta1 "k8s.io/client-go/kubernetes/typed/discovery/v1beta1/fake"
|
||||
eventsv1beta1 "k8s.io/client-go/kubernetes/typed/events/v1beta1"
|
||||
fakeeventsv1beta1 "k8s.io/client-go/kubernetes/typed/events/v1beta1/fake"
|
||||
extensionsv1beta1 "k8s.io/client-go/kubernetes/typed/extensions/v1beta1"
|
||||
fakeextensionsv1beta1 "k8s.io/client-go/kubernetes/typed/extensions/v1beta1/fake"
|
||||
flowcontrolv1alpha1 "k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1"
|
||||
fakeflowcontrolv1alpha1 "k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1/fake"
|
||||
networkingv1 "k8s.io/client-go/kubernetes/typed/networking/v1"
|
||||
fakenetworkingv1 "k8s.io/client-go/kubernetes/typed/networking/v1/fake"
|
||||
networkingv1beta1 "k8s.io/client-go/kubernetes/typed/networking/v1beta1"
|
||||
@@ -255,6 +259,11 @@ func (c *Clientset) DiscoveryV1alpha1() discoveryv1alpha1.DiscoveryV1alpha1Inter
|
||||
return &fakediscoveryv1alpha1.FakeDiscoveryV1alpha1{Fake: &c.Fake}
|
||||
}
|
||||
|
||||
// DiscoveryV1beta1 retrieves the DiscoveryV1beta1Client
|
||||
func (c *Clientset) DiscoveryV1beta1() discoveryv1beta1.DiscoveryV1beta1Interface {
|
||||
return &fakediscoveryv1beta1.FakeDiscoveryV1beta1{Fake: &c.Fake}
|
||||
}
|
||||
|
||||
// EventsV1beta1 retrieves the EventsV1beta1Client
|
||||
func (c *Clientset) EventsV1beta1() eventsv1beta1.EventsV1beta1Interface {
|
||||
return &fakeeventsv1beta1.FakeEventsV1beta1{Fake: &c.Fake}
|
||||
@@ -265,6 +274,11 @@ func (c *Clientset) ExtensionsV1beta1() extensionsv1beta1.ExtensionsV1beta1Inter
|
||||
return &fakeextensionsv1beta1.FakeExtensionsV1beta1{Fake: &c.Fake}
|
||||
}
|
||||
|
||||
// FlowcontrolV1alpha1 retrieves the FlowcontrolV1alpha1Client
|
||||
func (c *Clientset) FlowcontrolV1alpha1() flowcontrolv1alpha1.FlowcontrolV1alpha1Interface {
|
||||
return &fakeflowcontrolv1alpha1.FakeFlowcontrolV1alpha1{Fake: &c.Fake}
|
||||
}
|
||||
|
||||
// NetworkingV1 retrieves the NetworkingV1Client
|
||||
func (c *Clientset) NetworkingV1() networkingv1.NetworkingV1Interface {
|
||||
return &fakenetworkingv1.FakeNetworkingV1{Fake: &c.Fake}
|
||||
|
||||
@@ -40,8 +40,10 @@ import (
|
||||
coordinationv1beta1 "k8s.io/api/coordination/v1beta1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
discoveryv1alpha1 "k8s.io/api/discovery/v1alpha1"
|
||||
discoveryv1beta1 "k8s.io/api/discovery/v1beta1"
|
||||
eventsv1beta1 "k8s.io/api/events/v1beta1"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
flowcontrolv1alpha1 "k8s.io/api/flowcontrol/v1alpha1"
|
||||
networkingv1 "k8s.io/api/networking/v1"
|
||||
networkingv1beta1 "k8s.io/api/networking/v1beta1"
|
||||
nodev1alpha1 "k8s.io/api/node/v1alpha1"
|
||||
@@ -89,8 +91,10 @@ var localSchemeBuilder = runtime.SchemeBuilder{
|
||||
coordinationv1.AddToScheme,
|
||||
corev1.AddToScheme,
|
||||
discoveryv1alpha1.AddToScheme,
|
||||
discoveryv1beta1.AddToScheme,
|
||||
eventsv1beta1.AddToScheme,
|
||||
extensionsv1beta1.AddToScheme,
|
||||
flowcontrolv1alpha1.AddToScheme,
|
||||
networkingv1.AddToScheme,
|
||||
networkingv1beta1.AddToScheme,
|
||||
nodev1alpha1.AddToScheme,
|
||||
|
||||
@@ -40,8 +40,10 @@ import (
|
||||
coordinationv1beta1 "k8s.io/api/coordination/v1beta1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
discoveryv1alpha1 "k8s.io/api/discovery/v1alpha1"
|
||||
discoveryv1beta1 "k8s.io/api/discovery/v1beta1"
|
||||
eventsv1beta1 "k8s.io/api/events/v1beta1"
|
||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
flowcontrolv1alpha1 "k8s.io/api/flowcontrol/v1alpha1"
|
||||
networkingv1 "k8s.io/api/networking/v1"
|
||||
networkingv1beta1 "k8s.io/api/networking/v1beta1"
|
||||
nodev1alpha1 "k8s.io/api/node/v1alpha1"
|
||||
@@ -89,8 +91,10 @@ var localSchemeBuilder = runtime.SchemeBuilder{
|
||||
coordinationv1.AddToScheme,
|
||||
corev1.AddToScheme,
|
||||
discoveryv1alpha1.AddToScheme,
|
||||
discoveryv1beta1.AddToScheme,
|
||||
eventsv1beta1.AddToScheme,
|
||||
extensionsv1beta1.AddToScheme,
|
||||
flowcontrolv1alpha1.AddToScheme,
|
||||
networkingv1.AddToScheme,
|
||||
networkingv1beta1.AddToScheme,
|
||||
nodev1alpha1.AddToScheme,
|
||||
|
||||
89
kubernetes/typed/discovery/v1beta1/discovery_client.go
Normal file
89
kubernetes/typed/discovery/v1beta1/discovery_client.go
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
v1beta1 "k8s.io/api/discovery/v1beta1"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type DiscoveryV1beta1Interface interface {
|
||||
RESTClient() rest.Interface
|
||||
EndpointSlicesGetter
|
||||
}
|
||||
|
||||
// DiscoveryV1beta1Client is used to interact with features provided by the discovery.k8s.io group.
|
||||
type DiscoveryV1beta1Client struct {
|
||||
restClient rest.Interface
|
||||
}
|
||||
|
||||
func (c *DiscoveryV1beta1Client) EndpointSlices(namespace string) EndpointSliceInterface {
|
||||
return newEndpointSlices(c, namespace)
|
||||
}
|
||||
|
||||
// NewForConfig creates a new DiscoveryV1beta1Client for the given config.
|
||||
func NewForConfig(c *rest.Config) (*DiscoveryV1beta1Client, error) {
|
||||
config := *c
|
||||
if err := setConfigDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := rest.RESTClientFor(&config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &DiscoveryV1beta1Client{client}, nil
|
||||
}
|
||||
|
||||
// NewForConfigOrDie creates a new DiscoveryV1beta1Client for the given config and
|
||||
// panics if there is an error in the config.
|
||||
func NewForConfigOrDie(c *rest.Config) *DiscoveryV1beta1Client {
|
||||
client, err := NewForConfig(c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
// New creates a new DiscoveryV1beta1Client for the given RESTClient.
|
||||
func New(c rest.Interface) *DiscoveryV1beta1Client {
|
||||
return &DiscoveryV1beta1Client{c}
|
||||
}
|
||||
|
||||
func setConfigDefaults(config *rest.Config) error {
|
||||
gv := v1beta1.SchemeGroupVersion
|
||||
config.GroupVersion = &gv
|
||||
config.APIPath = "/apis"
|
||||
config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
|
||||
|
||||
if config.UserAgent == "" {
|
||||
config.UserAgent = rest.DefaultKubernetesUserAgent()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RESTClient returns a RESTClient that is used to communicate
|
||||
// with API server by this client implementation.
|
||||
func (c *DiscoveryV1beta1Client) RESTClient() rest.Interface {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return c.restClient
|
||||
}
|
||||
20
kubernetes/typed/discovery/v1beta1/doc.go
Normal file
20
kubernetes/typed/discovery/v1beta1/doc.go
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// This package has the automatically generated typed clients.
|
||||
package v1beta1
|
||||
174
kubernetes/typed/discovery/v1beta1/endpointslice.go
Normal file
174
kubernetes/typed/discovery/v1beta1/endpointslice.go
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
v1beta1 "k8s.io/api/discovery/v1beta1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
scheme "k8s.io/client-go/kubernetes/scheme"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// EndpointSlicesGetter has a method to return a EndpointSliceInterface.
|
||||
// A group's client should implement this interface.
|
||||
type EndpointSlicesGetter interface {
|
||||
EndpointSlices(namespace string) EndpointSliceInterface
|
||||
}
|
||||
|
||||
// EndpointSliceInterface has methods to work with EndpointSlice resources.
|
||||
type EndpointSliceInterface interface {
|
||||
Create(*v1beta1.EndpointSlice) (*v1beta1.EndpointSlice, error)
|
||||
Update(*v1beta1.EndpointSlice) (*v1beta1.EndpointSlice, error)
|
||||
Delete(name string, options *v1.DeleteOptions) error
|
||||
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
|
||||
Get(name string, options v1.GetOptions) (*v1beta1.EndpointSlice, error)
|
||||
List(opts v1.ListOptions) (*v1beta1.EndpointSliceList, error)
|
||||
Watch(opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.EndpointSlice, err error)
|
||||
EndpointSliceExpansion
|
||||
}
|
||||
|
||||
// endpointSlices implements EndpointSliceInterface
|
||||
type endpointSlices struct {
|
||||
client rest.Interface
|
||||
ns string
|
||||
}
|
||||
|
||||
// newEndpointSlices returns a EndpointSlices
|
||||
func newEndpointSlices(c *DiscoveryV1beta1Client, namespace string) *endpointSlices {
|
||||
return &endpointSlices{
|
||||
client: c.RESTClient(),
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the endpointSlice, and returns the corresponding endpointSlice object, and an error if there is any.
|
||||
func (c *endpointSlices) Get(name string, options v1.GetOptions) (result *v1beta1.EndpointSlice, err error) {
|
||||
result = &v1beta1.EndpointSlice{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("endpointslices").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of EndpointSlices that match those selectors.
|
||||
func (c *endpointSlices) List(opts v1.ListOptions) (result *v1beta1.EndpointSliceList, err error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
result = &v1beta1.EndpointSliceList{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("endpointslices").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested endpointSlices.
|
||||
func (c *endpointSlices) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("endpointslices").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// Create takes the representation of a endpointSlice and creates it. Returns the server's representation of the endpointSlice, and an error, if there is any.
|
||||
func (c *endpointSlices) Create(endpointSlice *v1beta1.EndpointSlice) (result *v1beta1.EndpointSlice, err error) {
|
||||
result = &v1beta1.EndpointSlice{}
|
||||
err = c.client.Post().
|
||||
Namespace(c.ns).
|
||||
Resource("endpointslices").
|
||||
Body(endpointSlice).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a endpointSlice and updates it. Returns the server's representation of the endpointSlice, and an error, if there is any.
|
||||
func (c *endpointSlices) Update(endpointSlice *v1beta1.EndpointSlice) (result *v1beta1.EndpointSlice, err error) {
|
||||
result = &v1beta1.EndpointSlice{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("endpointslices").
|
||||
Name(endpointSlice.Name).
|
||||
Body(endpointSlice).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the endpointSlice and deletes it. Returns an error if one occurs.
|
||||
func (c *endpointSlices) Delete(name string, options *v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("endpointslices").
|
||||
Name(name).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *endpointSlices) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
var timeout time.Duration
|
||||
if listOptions.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second
|
||||
}
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("endpointslices").
|
||||
VersionedParams(&listOptions, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched endpointSlice.
|
||||
func (c *endpointSlices) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.EndpointSlice, err error) {
|
||||
result = &v1beta1.EndpointSlice{}
|
||||
err = c.client.Patch(pt).
|
||||
Namespace(c.ns).
|
||||
Resource("endpointslices").
|
||||
SubResource(subresources...).
|
||||
Name(name).
|
||||
Body(data).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
20
kubernetes/typed/discovery/v1beta1/fake/doc.go
Normal file
20
kubernetes/typed/discovery/v1beta1/fake/doc.go
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// Package fake has the automatically generated clients.
|
||||
package fake
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1beta1 "k8s.io/client-go/kubernetes/typed/discovery/v1beta1"
|
||||
rest "k8s.io/client-go/rest"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
type FakeDiscoveryV1beta1 struct {
|
||||
*testing.Fake
|
||||
}
|
||||
|
||||
func (c *FakeDiscoveryV1beta1) EndpointSlices(namespace string) v1beta1.EndpointSliceInterface {
|
||||
return &FakeEndpointSlices{c, namespace}
|
||||
}
|
||||
|
||||
// RESTClient returns a RESTClient that is used to communicate
|
||||
// with API server by this client implementation.
|
||||
func (c *FakeDiscoveryV1beta1) RESTClient() rest.Interface {
|
||||
var ret *rest.RESTClient
|
||||
return ret
|
||||
}
|
||||
128
kubernetes/typed/discovery/v1beta1/fake/fake_endpointslice.go
Normal file
128
kubernetes/typed/discovery/v1beta1/fake/fake_endpointslice.go
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1beta1 "k8s.io/api/discovery/v1beta1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
// FakeEndpointSlices implements EndpointSliceInterface
|
||||
type FakeEndpointSlices struct {
|
||||
Fake *FakeDiscoveryV1beta1
|
||||
ns string
|
||||
}
|
||||
|
||||
var endpointslicesResource = schema.GroupVersionResource{Group: "discovery.k8s.io", Version: "v1beta1", Resource: "endpointslices"}
|
||||
|
||||
var endpointslicesKind = schema.GroupVersionKind{Group: "discovery.k8s.io", Version: "v1beta1", Kind: "EndpointSlice"}
|
||||
|
||||
// Get takes name of the endpointSlice, and returns the corresponding endpointSlice object, and an error if there is any.
|
||||
func (c *FakeEndpointSlices) Get(name string, options v1.GetOptions) (result *v1beta1.EndpointSlice, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewGetAction(endpointslicesResource, c.ns, name), &v1beta1.EndpointSlice{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.EndpointSlice), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of EndpointSlices that match those selectors.
|
||||
func (c *FakeEndpointSlices) List(opts v1.ListOptions) (result *v1beta1.EndpointSliceList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewListAction(endpointslicesResource, endpointslicesKind, c.ns, opts), &v1beta1.EndpointSliceList{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &v1beta1.EndpointSliceList{ListMeta: obj.(*v1beta1.EndpointSliceList).ListMeta}
|
||||
for _, item := range obj.(*v1beta1.EndpointSliceList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested endpointSlices.
|
||||
func (c *FakeEndpointSlices) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewWatchAction(endpointslicesResource, c.ns, opts))
|
||||
|
||||
}
|
||||
|
||||
// Create takes the representation of a endpointSlice and creates it. Returns the server's representation of the endpointSlice, and an error, if there is any.
|
||||
func (c *FakeEndpointSlices) Create(endpointSlice *v1beta1.EndpointSlice) (result *v1beta1.EndpointSlice, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewCreateAction(endpointslicesResource, c.ns, endpointSlice), &v1beta1.EndpointSlice{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.EndpointSlice), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a endpointSlice and updates it. Returns the server's representation of the endpointSlice, and an error, if there is any.
|
||||
func (c *FakeEndpointSlices) Update(endpointSlice *v1beta1.EndpointSlice) (result *v1beta1.EndpointSlice, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateAction(endpointslicesResource, c.ns, endpointSlice), &v1beta1.EndpointSlice{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.EndpointSlice), err
|
||||
}
|
||||
|
||||
// Delete takes name of the endpointSlice and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeEndpointSlices) Delete(name string, options *v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewDeleteAction(endpointslicesResource, c.ns, name), &v1beta1.EndpointSlice{})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeEndpointSlices) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
action := testing.NewDeleteCollectionAction(endpointslicesResource, c.ns, listOptions)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &v1beta1.EndpointSliceList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched endpointSlice.
|
||||
func (c *FakeEndpointSlices) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.EndpointSlice, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewPatchSubresourceAction(endpointslicesResource, c.ns, name, pt, data, subresources...), &v1beta1.EndpointSlice{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.EndpointSlice), err
|
||||
}
|
||||
21
kubernetes/typed/discovery/v1beta1/generated_expansion.go
Normal file
21
kubernetes/typed/discovery/v1beta1/generated_expansion.go
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
type EndpointSliceExpansion interface{}
|
||||
20
kubernetes/typed/flowcontrol/v1alpha1/doc.go
Normal file
20
kubernetes/typed/flowcontrol/v1alpha1/doc.go
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// This package has the automatically generated typed clients.
|
||||
package v1alpha1
|
||||
20
kubernetes/typed/flowcontrol/v1alpha1/fake/doc.go
Normal file
20
kubernetes/typed/flowcontrol/v1alpha1/fake/doc.go
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// Package fake has the automatically generated clients.
|
||||
package fake
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1alpha1 "k8s.io/client-go/kubernetes/typed/flowcontrol/v1alpha1"
|
||||
rest "k8s.io/client-go/rest"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
type FakeFlowcontrolV1alpha1 struct {
|
||||
*testing.Fake
|
||||
}
|
||||
|
||||
func (c *FakeFlowcontrolV1alpha1) FlowSchemas() v1alpha1.FlowSchemaInterface {
|
||||
return &FakeFlowSchemas{c}
|
||||
}
|
||||
|
||||
func (c *FakeFlowcontrolV1alpha1) PriorityLevelConfigurations() v1alpha1.PriorityLevelConfigurationInterface {
|
||||
return &FakePriorityLevelConfigurations{c}
|
||||
}
|
||||
|
||||
// RESTClient returns a RESTClient that is used to communicate
|
||||
// with API server by this client implementation.
|
||||
func (c *FakeFlowcontrolV1alpha1) RESTClient() rest.Interface {
|
||||
var ret *rest.RESTClient
|
||||
return ret
|
||||
}
|
||||
131
kubernetes/typed/flowcontrol/v1alpha1/fake/fake_flowschema.go
Normal file
131
kubernetes/typed/flowcontrol/v1alpha1/fake/fake_flowschema.go
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1alpha1 "k8s.io/api/flowcontrol/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
// FakeFlowSchemas implements FlowSchemaInterface
|
||||
type FakeFlowSchemas struct {
|
||||
Fake *FakeFlowcontrolV1alpha1
|
||||
}
|
||||
|
||||
var flowschemasResource = schema.GroupVersionResource{Group: "flowcontrol.apiserver.k8s.io", Version: "v1alpha1", Resource: "flowschemas"}
|
||||
|
||||
var flowschemasKind = schema.GroupVersionKind{Group: "flowcontrol.apiserver.k8s.io", Version: "v1alpha1", Kind: "FlowSchema"}
|
||||
|
||||
// Get takes name of the flowSchema, and returns the corresponding flowSchema object, and an error if there is any.
|
||||
func (c *FakeFlowSchemas) Get(name string, options v1.GetOptions) (result *v1alpha1.FlowSchema, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootGetAction(flowschemasResource, name), &v1alpha1.FlowSchema{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.FlowSchema), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of FlowSchemas that match those selectors.
|
||||
func (c *FakeFlowSchemas) List(opts v1.ListOptions) (result *v1alpha1.FlowSchemaList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootListAction(flowschemasResource, flowschemasKind, opts), &v1alpha1.FlowSchemaList{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &v1alpha1.FlowSchemaList{ListMeta: obj.(*v1alpha1.FlowSchemaList).ListMeta}
|
||||
for _, item := range obj.(*v1alpha1.FlowSchemaList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested flowSchemas.
|
||||
func (c *FakeFlowSchemas) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewRootWatchAction(flowschemasResource, opts))
|
||||
}
|
||||
|
||||
// Create takes the representation of a flowSchema and creates it. Returns the server's representation of the flowSchema, and an error, if there is any.
|
||||
func (c *FakeFlowSchemas) Create(flowSchema *v1alpha1.FlowSchema) (result *v1alpha1.FlowSchema, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootCreateAction(flowschemasResource, flowSchema), &v1alpha1.FlowSchema{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.FlowSchema), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a flowSchema and updates it. Returns the server's representation of the flowSchema, and an error, if there is any.
|
||||
func (c *FakeFlowSchemas) Update(flowSchema *v1alpha1.FlowSchema) (result *v1alpha1.FlowSchema, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootUpdateAction(flowschemasResource, flowSchema), &v1alpha1.FlowSchema{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.FlowSchema), err
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *FakeFlowSchemas) UpdateStatus(flowSchema *v1alpha1.FlowSchema) (*v1alpha1.FlowSchema, error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootUpdateSubresourceAction(flowschemasResource, "status", flowSchema), &v1alpha1.FlowSchema{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.FlowSchema), err
|
||||
}
|
||||
|
||||
// Delete takes name of the flowSchema and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeFlowSchemas) Delete(name string, options *v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewRootDeleteAction(flowschemasResource, name), &v1alpha1.FlowSchema{})
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeFlowSchemas) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
action := testing.NewRootDeleteCollectionAction(flowschemasResource, listOptions)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &v1alpha1.FlowSchemaList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched flowSchema.
|
||||
func (c *FakeFlowSchemas) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.FlowSchema, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootPatchSubresourceAction(flowschemasResource, name, pt, data, subresources...), &v1alpha1.FlowSchema{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.FlowSchema), err
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1alpha1 "k8s.io/api/flowcontrol/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
// FakePriorityLevelConfigurations implements PriorityLevelConfigurationInterface
|
||||
type FakePriorityLevelConfigurations struct {
|
||||
Fake *FakeFlowcontrolV1alpha1
|
||||
}
|
||||
|
||||
var prioritylevelconfigurationsResource = schema.GroupVersionResource{Group: "flowcontrol.apiserver.k8s.io", Version: "v1alpha1", Resource: "prioritylevelconfigurations"}
|
||||
|
||||
var prioritylevelconfigurationsKind = schema.GroupVersionKind{Group: "flowcontrol.apiserver.k8s.io", Version: "v1alpha1", Kind: "PriorityLevelConfiguration"}
|
||||
|
||||
// Get takes name of the priorityLevelConfiguration, and returns the corresponding priorityLevelConfiguration object, and an error if there is any.
|
||||
func (c *FakePriorityLevelConfigurations) Get(name string, options v1.GetOptions) (result *v1alpha1.PriorityLevelConfiguration, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootGetAction(prioritylevelconfigurationsResource, name), &v1alpha1.PriorityLevelConfiguration{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.PriorityLevelConfiguration), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of PriorityLevelConfigurations that match those selectors.
|
||||
func (c *FakePriorityLevelConfigurations) List(opts v1.ListOptions) (result *v1alpha1.PriorityLevelConfigurationList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootListAction(prioritylevelconfigurationsResource, prioritylevelconfigurationsKind, opts), &v1alpha1.PriorityLevelConfigurationList{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &v1alpha1.PriorityLevelConfigurationList{ListMeta: obj.(*v1alpha1.PriorityLevelConfigurationList).ListMeta}
|
||||
for _, item := range obj.(*v1alpha1.PriorityLevelConfigurationList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested priorityLevelConfigurations.
|
||||
func (c *FakePriorityLevelConfigurations) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewRootWatchAction(prioritylevelconfigurationsResource, opts))
|
||||
}
|
||||
|
||||
// Create takes the representation of a priorityLevelConfiguration and creates it. Returns the server's representation of the priorityLevelConfiguration, and an error, if there is any.
|
||||
func (c *FakePriorityLevelConfigurations) Create(priorityLevelConfiguration *v1alpha1.PriorityLevelConfiguration) (result *v1alpha1.PriorityLevelConfiguration, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootCreateAction(prioritylevelconfigurationsResource, priorityLevelConfiguration), &v1alpha1.PriorityLevelConfiguration{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.PriorityLevelConfiguration), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a priorityLevelConfiguration and updates it. Returns the server's representation of the priorityLevelConfiguration, and an error, if there is any.
|
||||
func (c *FakePriorityLevelConfigurations) Update(priorityLevelConfiguration *v1alpha1.PriorityLevelConfiguration) (result *v1alpha1.PriorityLevelConfiguration, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootUpdateAction(prioritylevelconfigurationsResource, priorityLevelConfiguration), &v1alpha1.PriorityLevelConfiguration{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.PriorityLevelConfiguration), err
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *FakePriorityLevelConfigurations) UpdateStatus(priorityLevelConfiguration *v1alpha1.PriorityLevelConfiguration) (*v1alpha1.PriorityLevelConfiguration, error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootUpdateSubresourceAction(prioritylevelconfigurationsResource, "status", priorityLevelConfiguration), &v1alpha1.PriorityLevelConfiguration{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.PriorityLevelConfiguration), err
|
||||
}
|
||||
|
||||
// Delete takes name of the priorityLevelConfiguration and deletes it. Returns an error if one occurs.
|
||||
func (c *FakePriorityLevelConfigurations) Delete(name string, options *v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewRootDeleteAction(prioritylevelconfigurationsResource, name), &v1alpha1.PriorityLevelConfiguration{})
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakePriorityLevelConfigurations) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
action := testing.NewRootDeleteCollectionAction(prioritylevelconfigurationsResource, listOptions)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &v1alpha1.PriorityLevelConfigurationList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched priorityLevelConfiguration.
|
||||
func (c *FakePriorityLevelConfigurations) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.PriorityLevelConfiguration, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootPatchSubresourceAction(prioritylevelconfigurationsResource, name, pt, data, subresources...), &v1alpha1.PriorityLevelConfiguration{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1alpha1.PriorityLevelConfiguration), err
|
||||
}
|
||||
94
kubernetes/typed/flowcontrol/v1alpha1/flowcontrol_client.go
Normal file
94
kubernetes/typed/flowcontrol/v1alpha1/flowcontrol_client.go
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
v1alpha1 "k8s.io/api/flowcontrol/v1alpha1"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type FlowcontrolV1alpha1Interface interface {
|
||||
RESTClient() rest.Interface
|
||||
FlowSchemasGetter
|
||||
PriorityLevelConfigurationsGetter
|
||||
}
|
||||
|
||||
// FlowcontrolV1alpha1Client is used to interact with features provided by the flowcontrol.apiserver.k8s.io group.
|
||||
type FlowcontrolV1alpha1Client struct {
|
||||
restClient rest.Interface
|
||||
}
|
||||
|
||||
func (c *FlowcontrolV1alpha1Client) FlowSchemas() FlowSchemaInterface {
|
||||
return newFlowSchemas(c)
|
||||
}
|
||||
|
||||
func (c *FlowcontrolV1alpha1Client) PriorityLevelConfigurations() PriorityLevelConfigurationInterface {
|
||||
return newPriorityLevelConfigurations(c)
|
||||
}
|
||||
|
||||
// NewForConfig creates a new FlowcontrolV1alpha1Client for the given config.
|
||||
func NewForConfig(c *rest.Config) (*FlowcontrolV1alpha1Client, error) {
|
||||
config := *c
|
||||
if err := setConfigDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := rest.RESTClientFor(&config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &FlowcontrolV1alpha1Client{client}, nil
|
||||
}
|
||||
|
||||
// NewForConfigOrDie creates a new FlowcontrolV1alpha1Client for the given config and
|
||||
// panics if there is an error in the config.
|
||||
func NewForConfigOrDie(c *rest.Config) *FlowcontrolV1alpha1Client {
|
||||
client, err := NewForConfig(c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
// New creates a new FlowcontrolV1alpha1Client for the given RESTClient.
|
||||
func New(c rest.Interface) *FlowcontrolV1alpha1Client {
|
||||
return &FlowcontrolV1alpha1Client{c}
|
||||
}
|
||||
|
||||
func setConfigDefaults(config *rest.Config) error {
|
||||
gv := v1alpha1.SchemeGroupVersion
|
||||
config.GroupVersion = &gv
|
||||
config.APIPath = "/apis"
|
||||
config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
|
||||
|
||||
if config.UserAgent == "" {
|
||||
config.UserAgent = rest.DefaultKubernetesUserAgent()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RESTClient returns a RESTClient that is used to communicate
|
||||
// with API server by this client implementation.
|
||||
func (c *FlowcontrolV1alpha1Client) RESTClient() rest.Interface {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return c.restClient
|
||||
}
|
||||
180
kubernetes/typed/flowcontrol/v1alpha1/flowschema.go
Normal file
180
kubernetes/typed/flowcontrol/v1alpha1/flowschema.go
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
v1alpha1 "k8s.io/api/flowcontrol/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
scheme "k8s.io/client-go/kubernetes/scheme"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// FlowSchemasGetter has a method to return a FlowSchemaInterface.
|
||||
// A group's client should implement this interface.
|
||||
type FlowSchemasGetter interface {
|
||||
FlowSchemas() FlowSchemaInterface
|
||||
}
|
||||
|
||||
// FlowSchemaInterface has methods to work with FlowSchema resources.
|
||||
type FlowSchemaInterface interface {
|
||||
Create(*v1alpha1.FlowSchema) (*v1alpha1.FlowSchema, error)
|
||||
Update(*v1alpha1.FlowSchema) (*v1alpha1.FlowSchema, error)
|
||||
UpdateStatus(*v1alpha1.FlowSchema) (*v1alpha1.FlowSchema, error)
|
||||
Delete(name string, options *v1.DeleteOptions) error
|
||||
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
|
||||
Get(name string, options v1.GetOptions) (*v1alpha1.FlowSchema, error)
|
||||
List(opts v1.ListOptions) (*v1alpha1.FlowSchemaList, error)
|
||||
Watch(opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.FlowSchema, err error)
|
||||
FlowSchemaExpansion
|
||||
}
|
||||
|
||||
// flowSchemas implements FlowSchemaInterface
|
||||
type flowSchemas struct {
|
||||
client rest.Interface
|
||||
}
|
||||
|
||||
// newFlowSchemas returns a FlowSchemas
|
||||
func newFlowSchemas(c *FlowcontrolV1alpha1Client) *flowSchemas {
|
||||
return &flowSchemas{
|
||||
client: c.RESTClient(),
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the flowSchema, and returns the corresponding flowSchema object, and an error if there is any.
|
||||
func (c *flowSchemas) Get(name string, options v1.GetOptions) (result *v1alpha1.FlowSchema, err error) {
|
||||
result = &v1alpha1.FlowSchema{}
|
||||
err = c.client.Get().
|
||||
Resource("flowschemas").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of FlowSchemas that match those selectors.
|
||||
func (c *flowSchemas) List(opts v1.ListOptions) (result *v1alpha1.FlowSchemaList, err error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
result = &v1alpha1.FlowSchemaList{}
|
||||
err = c.client.Get().
|
||||
Resource("flowschemas").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested flowSchemas.
|
||||
func (c *flowSchemas) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Resource("flowschemas").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// Create takes the representation of a flowSchema and creates it. Returns the server's representation of the flowSchema, and an error, if there is any.
|
||||
func (c *flowSchemas) Create(flowSchema *v1alpha1.FlowSchema) (result *v1alpha1.FlowSchema, err error) {
|
||||
result = &v1alpha1.FlowSchema{}
|
||||
err = c.client.Post().
|
||||
Resource("flowschemas").
|
||||
Body(flowSchema).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a flowSchema and updates it. Returns the server's representation of the flowSchema, and an error, if there is any.
|
||||
func (c *flowSchemas) Update(flowSchema *v1alpha1.FlowSchema) (result *v1alpha1.FlowSchema, err error) {
|
||||
result = &v1alpha1.FlowSchema{}
|
||||
err = c.client.Put().
|
||||
Resource("flowschemas").
|
||||
Name(flowSchema.Name).
|
||||
Body(flowSchema).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
|
||||
func (c *flowSchemas) UpdateStatus(flowSchema *v1alpha1.FlowSchema) (result *v1alpha1.FlowSchema, err error) {
|
||||
result = &v1alpha1.FlowSchema{}
|
||||
err = c.client.Put().
|
||||
Resource("flowschemas").
|
||||
Name(flowSchema.Name).
|
||||
SubResource("status").
|
||||
Body(flowSchema).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the flowSchema and deletes it. Returns an error if one occurs.
|
||||
func (c *flowSchemas) Delete(name string, options *v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Resource("flowschemas").
|
||||
Name(name).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *flowSchemas) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
var timeout time.Duration
|
||||
if listOptions.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second
|
||||
}
|
||||
return c.client.Delete().
|
||||
Resource("flowschemas").
|
||||
VersionedParams(&listOptions, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched flowSchema.
|
||||
func (c *flowSchemas) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.FlowSchema, err error) {
|
||||
result = &v1alpha1.FlowSchema{}
|
||||
err = c.client.Patch(pt).
|
||||
Resource("flowschemas").
|
||||
SubResource(subresources...).
|
||||
Name(name).
|
||||
Body(data).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
23
kubernetes/typed/flowcontrol/v1alpha1/generated_expansion.go
Normal file
23
kubernetes/typed/flowcontrol/v1alpha1/generated_expansion.go
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
type FlowSchemaExpansion interface{}
|
||||
|
||||
type PriorityLevelConfigurationExpansion interface{}
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
v1alpha1 "k8s.io/api/flowcontrol/v1alpha1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
scheme "k8s.io/client-go/kubernetes/scheme"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// PriorityLevelConfigurationsGetter has a method to return a PriorityLevelConfigurationInterface.
|
||||
// A group's client should implement this interface.
|
||||
type PriorityLevelConfigurationsGetter interface {
|
||||
PriorityLevelConfigurations() PriorityLevelConfigurationInterface
|
||||
}
|
||||
|
||||
// PriorityLevelConfigurationInterface has methods to work with PriorityLevelConfiguration resources.
|
||||
type PriorityLevelConfigurationInterface interface {
|
||||
Create(*v1alpha1.PriorityLevelConfiguration) (*v1alpha1.PriorityLevelConfiguration, error)
|
||||
Update(*v1alpha1.PriorityLevelConfiguration) (*v1alpha1.PriorityLevelConfiguration, error)
|
||||
UpdateStatus(*v1alpha1.PriorityLevelConfiguration) (*v1alpha1.PriorityLevelConfiguration, error)
|
||||
Delete(name string, options *v1.DeleteOptions) error
|
||||
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
|
||||
Get(name string, options v1.GetOptions) (*v1alpha1.PriorityLevelConfiguration, error)
|
||||
List(opts v1.ListOptions) (*v1alpha1.PriorityLevelConfigurationList, error)
|
||||
Watch(opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.PriorityLevelConfiguration, err error)
|
||||
PriorityLevelConfigurationExpansion
|
||||
}
|
||||
|
||||
// priorityLevelConfigurations implements PriorityLevelConfigurationInterface
|
||||
type priorityLevelConfigurations struct {
|
||||
client rest.Interface
|
||||
}
|
||||
|
||||
// newPriorityLevelConfigurations returns a PriorityLevelConfigurations
|
||||
func newPriorityLevelConfigurations(c *FlowcontrolV1alpha1Client) *priorityLevelConfigurations {
|
||||
return &priorityLevelConfigurations{
|
||||
client: c.RESTClient(),
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the priorityLevelConfiguration, and returns the corresponding priorityLevelConfiguration object, and an error if there is any.
|
||||
func (c *priorityLevelConfigurations) Get(name string, options v1.GetOptions) (result *v1alpha1.PriorityLevelConfiguration, err error) {
|
||||
result = &v1alpha1.PriorityLevelConfiguration{}
|
||||
err = c.client.Get().
|
||||
Resource("prioritylevelconfigurations").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of PriorityLevelConfigurations that match those selectors.
|
||||
func (c *priorityLevelConfigurations) List(opts v1.ListOptions) (result *v1alpha1.PriorityLevelConfigurationList, err error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
result = &v1alpha1.PriorityLevelConfigurationList{}
|
||||
err = c.client.Get().
|
||||
Resource("prioritylevelconfigurations").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested priorityLevelConfigurations.
|
||||
func (c *priorityLevelConfigurations) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Resource("prioritylevelconfigurations").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// Create takes the representation of a priorityLevelConfiguration and creates it. Returns the server's representation of the priorityLevelConfiguration, and an error, if there is any.
|
||||
func (c *priorityLevelConfigurations) Create(priorityLevelConfiguration *v1alpha1.PriorityLevelConfiguration) (result *v1alpha1.PriorityLevelConfiguration, err error) {
|
||||
result = &v1alpha1.PriorityLevelConfiguration{}
|
||||
err = c.client.Post().
|
||||
Resource("prioritylevelconfigurations").
|
||||
Body(priorityLevelConfiguration).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a priorityLevelConfiguration and updates it. Returns the server's representation of the priorityLevelConfiguration, and an error, if there is any.
|
||||
func (c *priorityLevelConfigurations) Update(priorityLevelConfiguration *v1alpha1.PriorityLevelConfiguration) (result *v1alpha1.PriorityLevelConfiguration, err error) {
|
||||
result = &v1alpha1.PriorityLevelConfiguration{}
|
||||
err = c.client.Put().
|
||||
Resource("prioritylevelconfigurations").
|
||||
Name(priorityLevelConfiguration.Name).
|
||||
Body(priorityLevelConfiguration).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
|
||||
func (c *priorityLevelConfigurations) UpdateStatus(priorityLevelConfiguration *v1alpha1.PriorityLevelConfiguration) (result *v1alpha1.PriorityLevelConfiguration, err error) {
|
||||
result = &v1alpha1.PriorityLevelConfiguration{}
|
||||
err = c.client.Put().
|
||||
Resource("prioritylevelconfigurations").
|
||||
Name(priorityLevelConfiguration.Name).
|
||||
SubResource("status").
|
||||
Body(priorityLevelConfiguration).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the priorityLevelConfiguration and deletes it. Returns an error if one occurs.
|
||||
func (c *priorityLevelConfigurations) Delete(name string, options *v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Resource("prioritylevelconfigurations").
|
||||
Name(name).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *priorityLevelConfigurations) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
var timeout time.Duration
|
||||
if listOptions.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second
|
||||
}
|
||||
return c.client.Delete().
|
||||
Resource("prioritylevelconfigurations").
|
||||
VersionedParams(&listOptions, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched priorityLevelConfiguration.
|
||||
func (c *priorityLevelConfigurations) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.PriorityLevelConfiguration, err error) {
|
||||
result = &v1alpha1.PriorityLevelConfiguration{}
|
||||
err = c.client.Patch(pt).
|
||||
Resource("prioritylevelconfigurations").
|
||||
SubResource(subresources...).
|
||||
Name(name).
|
||||
Body(data).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
164
kubernetes/typed/storage/v1/csinode.go
Normal file
164
kubernetes/typed/storage/v1/csinode.go
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
v1 "k8s.io/api/storage/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
scheme "k8s.io/client-go/kubernetes/scheme"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// CSINodesGetter has a method to return a CSINodeInterface.
|
||||
// A group's client should implement this interface.
|
||||
type CSINodesGetter interface {
|
||||
CSINodes() CSINodeInterface
|
||||
}
|
||||
|
||||
// CSINodeInterface has methods to work with CSINode resources.
|
||||
type CSINodeInterface interface {
|
||||
Create(*v1.CSINode) (*v1.CSINode, error)
|
||||
Update(*v1.CSINode) (*v1.CSINode, error)
|
||||
Delete(name string, options *metav1.DeleteOptions) error
|
||||
DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error
|
||||
Get(name string, options metav1.GetOptions) (*v1.CSINode, error)
|
||||
List(opts metav1.ListOptions) (*v1.CSINodeList, error)
|
||||
Watch(opts metav1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.CSINode, err error)
|
||||
CSINodeExpansion
|
||||
}
|
||||
|
||||
// cSINodes implements CSINodeInterface
|
||||
type cSINodes struct {
|
||||
client rest.Interface
|
||||
}
|
||||
|
||||
// newCSINodes returns a CSINodes
|
||||
func newCSINodes(c *StorageV1Client) *cSINodes {
|
||||
return &cSINodes{
|
||||
client: c.RESTClient(),
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the cSINode, and returns the corresponding cSINode object, and an error if there is any.
|
||||
func (c *cSINodes) Get(name string, options metav1.GetOptions) (result *v1.CSINode, err error) {
|
||||
result = &v1.CSINode{}
|
||||
err = c.client.Get().
|
||||
Resource("csinodes").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of CSINodes that match those selectors.
|
||||
func (c *cSINodes) List(opts metav1.ListOptions) (result *v1.CSINodeList, err error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
result = &v1.CSINodeList{}
|
||||
err = c.client.Get().
|
||||
Resource("csinodes").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested cSINodes.
|
||||
func (c *cSINodes) Watch(opts metav1.ListOptions) (watch.Interface, error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Resource("csinodes").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// Create takes the representation of a cSINode and creates it. Returns the server's representation of the cSINode, and an error, if there is any.
|
||||
func (c *cSINodes) Create(cSINode *v1.CSINode) (result *v1.CSINode, err error) {
|
||||
result = &v1.CSINode{}
|
||||
err = c.client.Post().
|
||||
Resource("csinodes").
|
||||
Body(cSINode).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a cSINode and updates it. Returns the server's representation of the cSINode, and an error, if there is any.
|
||||
func (c *cSINodes) Update(cSINode *v1.CSINode) (result *v1.CSINode, err error) {
|
||||
result = &v1.CSINode{}
|
||||
err = c.client.Put().
|
||||
Resource("csinodes").
|
||||
Name(cSINode.Name).
|
||||
Body(cSINode).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the cSINode and deletes it. Returns an error if one occurs.
|
||||
func (c *cSINodes) Delete(name string, options *metav1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Resource("csinodes").
|
||||
Name(name).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *cSINodes) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error {
|
||||
var timeout time.Duration
|
||||
if listOptions.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second
|
||||
}
|
||||
return c.client.Delete().
|
||||
Resource("csinodes").
|
||||
VersionedParams(&listOptions, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched cSINode.
|
||||
func (c *cSINodes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.CSINode, err error) {
|
||||
result = &v1.CSINode{}
|
||||
err = c.client.Patch(pt).
|
||||
Resource("csinodes").
|
||||
SubResource(subresources...).
|
||||
Name(name).
|
||||
Body(data).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
120
kubernetes/typed/storage/v1/fake/fake_csinode.go
Normal file
120
kubernetes/typed/storage/v1/fake/fake_csinode.go
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
storagev1 "k8s.io/api/storage/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
// FakeCSINodes implements CSINodeInterface
|
||||
type FakeCSINodes struct {
|
||||
Fake *FakeStorageV1
|
||||
}
|
||||
|
||||
var csinodesResource = schema.GroupVersionResource{Group: "storage.k8s.io", Version: "v1", Resource: "csinodes"}
|
||||
|
||||
var csinodesKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1", Kind: "CSINode"}
|
||||
|
||||
// Get takes name of the cSINode, and returns the corresponding cSINode object, and an error if there is any.
|
||||
func (c *FakeCSINodes) Get(name string, options v1.GetOptions) (result *storagev1.CSINode, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootGetAction(csinodesResource, name), &storagev1.CSINode{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*storagev1.CSINode), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of CSINodes that match those selectors.
|
||||
func (c *FakeCSINodes) List(opts v1.ListOptions) (result *storagev1.CSINodeList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootListAction(csinodesResource, csinodesKind, opts), &storagev1.CSINodeList{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &storagev1.CSINodeList{ListMeta: obj.(*storagev1.CSINodeList).ListMeta}
|
||||
for _, item := range obj.(*storagev1.CSINodeList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested cSINodes.
|
||||
func (c *FakeCSINodes) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewRootWatchAction(csinodesResource, opts))
|
||||
}
|
||||
|
||||
// Create takes the representation of a cSINode and creates it. Returns the server's representation of the cSINode, and an error, if there is any.
|
||||
func (c *FakeCSINodes) Create(cSINode *storagev1.CSINode) (result *storagev1.CSINode, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootCreateAction(csinodesResource, cSINode), &storagev1.CSINode{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*storagev1.CSINode), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a cSINode and updates it. Returns the server's representation of the cSINode, and an error, if there is any.
|
||||
func (c *FakeCSINodes) Update(cSINode *storagev1.CSINode) (result *storagev1.CSINode, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootUpdateAction(csinodesResource, cSINode), &storagev1.CSINode{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*storagev1.CSINode), err
|
||||
}
|
||||
|
||||
// Delete takes name of the cSINode and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeCSINodes) Delete(name string, options *v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewRootDeleteAction(csinodesResource, name), &storagev1.CSINode{})
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeCSINodes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
action := testing.NewRootDeleteCollectionAction(csinodesResource, listOptions)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &storagev1.CSINodeList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched cSINode.
|
||||
func (c *FakeCSINodes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *storagev1.CSINode, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootPatchSubresourceAction(csinodesResource, name, pt, data, subresources...), &storagev1.CSINode{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*storagev1.CSINode), err
|
||||
}
|
||||
@@ -28,6 +28,10 @@ type FakeStorageV1 struct {
|
||||
*testing.Fake
|
||||
}
|
||||
|
||||
func (c *FakeStorageV1) CSINodes() v1.CSINodeInterface {
|
||||
return &FakeCSINodes{c}
|
||||
}
|
||||
|
||||
func (c *FakeStorageV1) StorageClasses() v1.StorageClassInterface {
|
||||
return &FakeStorageClasses{c}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ limitations under the License.
|
||||
|
||||
package v1
|
||||
|
||||
type CSINodeExpansion interface{}
|
||||
|
||||
type StorageClassExpansion interface{}
|
||||
|
||||
type VolumeAttachmentExpansion interface{}
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
|
||||
type StorageV1Interface interface {
|
||||
RESTClient() rest.Interface
|
||||
CSINodesGetter
|
||||
StorageClassesGetter
|
||||
VolumeAttachmentsGetter
|
||||
}
|
||||
@@ -35,6 +36,10 @@ type StorageV1Client struct {
|
||||
restClient rest.Interface
|
||||
}
|
||||
|
||||
func (c *StorageV1Client) CSINodes() CSINodeInterface {
|
||||
return newCSINodes(c)
|
||||
}
|
||||
|
||||
func (c *StorageV1Client) StorageClasses() StorageClassInterface {
|
||||
return newStorageClasses(c)
|
||||
}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 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 v1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
apps "k8s.io/api/apps/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
// DeploymentListerExpansion allows custom methods to be added to
|
||||
// DeploymentLister.
|
||||
type DeploymentListerExpansion interface {
|
||||
GetDeploymentsForReplicaSet(rs *apps.ReplicaSet) ([]*apps.Deployment, error)
|
||||
}
|
||||
|
||||
// DeploymentNamespaceListerExpansion allows custom methods to be added to
|
||||
// DeploymentNamespaceLister.
|
||||
type DeploymentNamespaceListerExpansion interface{}
|
||||
|
||||
// GetDeploymentsForReplicaSet returns a list of Deployments that potentially
|
||||
// match a ReplicaSet. Only the one specified in the ReplicaSet's ControllerRef
|
||||
// will actually manage it.
|
||||
// Returns an error only if no matching Deployments are found.
|
||||
func (s *deploymentLister) GetDeploymentsForReplicaSet(rs *apps.ReplicaSet) ([]*apps.Deployment, error) {
|
||||
if len(rs.Labels) == 0 {
|
||||
return nil, fmt.Errorf("no deployments found for ReplicaSet %v because it has no labels", rs.Name)
|
||||
}
|
||||
|
||||
// TODO: MODIFY THIS METHOD so that it checks for the podTemplateSpecHash label
|
||||
dList, err := s.Deployments(rs.Namespace).List(labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var deployments []*apps.Deployment
|
||||
for _, d := range dList {
|
||||
selector, err := metav1.LabelSelectorAsSelector(d.Spec.Selector)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid label selector: %v", err)
|
||||
}
|
||||
// If a deployment with a nil or empty selector creeps in, it should match nothing, not everything.
|
||||
if selector.Empty() || !selector.Matches(labels.Set(rs.Labels)) {
|
||||
continue
|
||||
}
|
||||
deployments = append(deployments, d)
|
||||
}
|
||||
|
||||
if len(deployments) == 0 {
|
||||
return nil, fmt.Errorf("could not find deployments set for ReplicaSet %s in namespace %s with labels: %v", rs.Name, rs.Namespace, rs.Labels)
|
||||
}
|
||||
|
||||
return deployments, nil
|
||||
}
|
||||
@@ -25,3 +25,11 @@ type ControllerRevisionListerExpansion interface{}
|
||||
// ControllerRevisionNamespaceListerExpansion allows custom methods to be added to
|
||||
// ControllerRevisionNamespaceLister.
|
||||
type ControllerRevisionNamespaceListerExpansion interface{}
|
||||
|
||||
// DeploymentListerExpansion allows custom methods to be added to
|
||||
// DeploymentLister.
|
||||
type DeploymentListerExpansion interface{}
|
||||
|
||||
// DeploymentNamespaceListerExpansion allows custom methods to be added to
|
||||
// DeploymentNamespaceLister.
|
||||
type DeploymentNamespaceListerExpansion interface{}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 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 v1beta2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
apps "k8s.io/api/apps/v1beta2"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
// DeploymentListerExpansion allows custom methods to be added to
|
||||
// DeploymentLister.
|
||||
type DeploymentListerExpansion interface {
|
||||
GetDeploymentsForReplicaSet(rs *apps.ReplicaSet) ([]*apps.Deployment, error)
|
||||
}
|
||||
|
||||
// DeploymentNamespaceListerExpansion allows custom methods to be added to
|
||||
// DeploymentNamespaceLister.
|
||||
type DeploymentNamespaceListerExpansion interface{}
|
||||
|
||||
// GetDeploymentsForReplicaSet returns a list of Deployments that potentially
|
||||
// match a ReplicaSet. Only the one specified in the ReplicaSet's ControllerRef
|
||||
// will actually manage it.
|
||||
// Returns an error only if no matching Deployments are found.
|
||||
func (s *deploymentLister) GetDeploymentsForReplicaSet(rs *apps.ReplicaSet) ([]*apps.Deployment, error) {
|
||||
if len(rs.Labels) == 0 {
|
||||
return nil, fmt.Errorf("no deployments found for ReplicaSet %v because it has no labels", rs.Name)
|
||||
}
|
||||
|
||||
// TODO: MODIFY THIS METHOD so that it checks for the podTemplateSpecHash label
|
||||
dList, err := s.Deployments(rs.Namespace).List(labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var deployments []*apps.Deployment
|
||||
for _, d := range dList {
|
||||
selector, err := metav1.LabelSelectorAsSelector(d.Spec.Selector)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid label selector: %v", err)
|
||||
}
|
||||
// If a deployment with a nil or empty selector creeps in, it should match nothing, not everything.
|
||||
if selector.Empty() || !selector.Matches(labels.Set(rs.Labels)) {
|
||||
continue
|
||||
}
|
||||
deployments = append(deployments, d)
|
||||
}
|
||||
|
||||
if len(deployments) == 0 {
|
||||
return nil, fmt.Errorf("could not find deployments set for ReplicaSet %s in namespace %s with labels: %v", rs.Name, rs.Namespace, rs.Labels)
|
||||
}
|
||||
|
||||
return deployments, nil
|
||||
}
|
||||
@@ -25,3 +25,11 @@ type ControllerRevisionListerExpansion interface{}
|
||||
// ControllerRevisionNamespaceListerExpansion allows custom methods to be added to
|
||||
// ControllerRevisionNamespaceLister.
|
||||
type ControllerRevisionNamespaceListerExpansion interface{}
|
||||
|
||||
// DeploymentListerExpansion allows custom methods to be added to
|
||||
// DeploymentLister.
|
||||
type DeploymentListerExpansion interface{}
|
||||
|
||||
// DeploymentNamespaceListerExpansion allows custom methods to be added to
|
||||
// DeploymentNamespaceLister.
|
||||
type DeploymentNamespaceListerExpansion interface{}
|
||||
|
||||
@@ -58,6 +58,10 @@ type LimitRangeNamespaceListerExpansion interface{}
|
||||
// NamespaceLister.
|
||||
type NamespaceListerExpansion interface{}
|
||||
|
||||
// NodeListerExpansion allows custom methods to be added to
|
||||
// NodeLister.
|
||||
type NodeListerExpansion interface{}
|
||||
|
||||
// PersistentVolumeListerExpansion allows custom methods to be added to
|
||||
// PersistentVolumeLister.
|
||||
type PersistentVolumeListerExpansion interface{}
|
||||
@@ -102,6 +106,14 @@ type SecretListerExpansion interface{}
|
||||
// SecretNamespaceLister.
|
||||
type SecretNamespaceListerExpansion interface{}
|
||||
|
||||
// ServiceListerExpansion allows custom methods to be added to
|
||||
// ServiceLister.
|
||||
type ServiceListerExpansion interface{}
|
||||
|
||||
// ServiceNamespaceListerExpansion allows custom methods to be added to
|
||||
// ServiceNamespaceLister.
|
||||
type ServiceNamespaceListerExpansion interface{}
|
||||
|
||||
// ServiceAccountListerExpansion allows custom methods to be added to
|
||||
// ServiceAccountLister.
|
||||
type ServiceAccountListerExpansion interface{}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 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 v1
|
||||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
// NodeConditionPredicate is a function that indicates whether the given node's conditions meet
|
||||
// some set of criteria defined by the function.
|
||||
type NodeConditionPredicate func(node *v1.Node) bool
|
||||
|
||||
// NodeListerExpansion allows custom methods to be added to
|
||||
// NodeLister.
|
||||
type NodeListerExpansion interface {
|
||||
ListWithPredicate(predicate NodeConditionPredicate) ([]*v1.Node, error)
|
||||
}
|
||||
|
||||
func (l *nodeLister) ListWithPredicate(predicate NodeConditionPredicate) ([]*v1.Node, error) {
|
||||
nodes, err := l.List(labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var filtered []*v1.Node
|
||||
for i := range nodes {
|
||||
if predicate(nodes[i]) {
|
||||
filtered = append(filtered, nodes[i])
|
||||
}
|
||||
}
|
||||
|
||||
return filtered, nil
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 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 v1
|
||||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
// ServiceListerExpansion allows custom methods to be added to
|
||||
// ServiceLister.
|
||||
type ServiceListerExpansion interface {
|
||||
GetPodServices(pod *v1.Pod) ([]*v1.Service, error)
|
||||
}
|
||||
|
||||
// ServiceNamespaceListerExpansion allows custom methods to be added to
|
||||
// ServiceNamespaceLister.
|
||||
type ServiceNamespaceListerExpansion interface{}
|
||||
|
||||
// TODO: Move this back to scheduler as a helper function that takes a Store,
|
||||
// rather than a method of ServiceLister.
|
||||
func (s *serviceLister) GetPodServices(pod *v1.Pod) ([]*v1.Service, error) {
|
||||
allServices, err := s.Services(pod.Namespace).List(labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var services []*v1.Service
|
||||
for i := range allServices {
|
||||
service := allServices[i]
|
||||
if service.Spec.Selector == nil {
|
||||
// services with nil selectors match nothing, not everything.
|
||||
continue
|
||||
}
|
||||
selector := labels.Set(service.Spec.Selector).AsSelectorPreValidated()
|
||||
if selector.Matches(labels.Set(pod.Labels)) {
|
||||
services = append(services, service)
|
||||
}
|
||||
}
|
||||
|
||||
return services, nil
|
||||
}
|
||||
94
listers/discovery/v1beta1/endpointslice.go
Normal file
94
listers/discovery/v1beta1/endpointslice.go
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
v1beta1 "k8s.io/api/discovery/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// EndpointSliceLister helps list EndpointSlices.
|
||||
type EndpointSliceLister interface {
|
||||
// List lists all EndpointSlices in the indexer.
|
||||
List(selector labels.Selector) (ret []*v1beta1.EndpointSlice, err error)
|
||||
// EndpointSlices returns an object that can list and get EndpointSlices.
|
||||
EndpointSlices(namespace string) EndpointSliceNamespaceLister
|
||||
EndpointSliceListerExpansion
|
||||
}
|
||||
|
||||
// endpointSliceLister implements the EndpointSliceLister interface.
|
||||
type endpointSliceLister struct {
|
||||
indexer cache.Indexer
|
||||
}
|
||||
|
||||
// NewEndpointSliceLister returns a new EndpointSliceLister.
|
||||
func NewEndpointSliceLister(indexer cache.Indexer) EndpointSliceLister {
|
||||
return &endpointSliceLister{indexer: indexer}
|
||||
}
|
||||
|
||||
// List lists all EndpointSlices in the indexer.
|
||||
func (s *endpointSliceLister) List(selector labels.Selector) (ret []*v1beta1.EndpointSlice, err error) {
|
||||
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1beta1.EndpointSlice))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// EndpointSlices returns an object that can list and get EndpointSlices.
|
||||
func (s *endpointSliceLister) EndpointSlices(namespace string) EndpointSliceNamespaceLister {
|
||||
return endpointSliceNamespaceLister{indexer: s.indexer, namespace: namespace}
|
||||
}
|
||||
|
||||
// EndpointSliceNamespaceLister helps list and get EndpointSlices.
|
||||
type EndpointSliceNamespaceLister interface {
|
||||
// List lists all EndpointSlices in the indexer for a given namespace.
|
||||
List(selector labels.Selector) (ret []*v1beta1.EndpointSlice, err error)
|
||||
// Get retrieves the EndpointSlice from the indexer for a given namespace and name.
|
||||
Get(name string) (*v1beta1.EndpointSlice, error)
|
||||
EndpointSliceNamespaceListerExpansion
|
||||
}
|
||||
|
||||
// endpointSliceNamespaceLister implements the EndpointSliceNamespaceLister
|
||||
// interface.
|
||||
type endpointSliceNamespaceLister struct {
|
||||
indexer cache.Indexer
|
||||
namespace string
|
||||
}
|
||||
|
||||
// List lists all EndpointSlices in the indexer for a given namespace.
|
||||
func (s endpointSliceNamespaceLister) List(selector labels.Selector) (ret []*v1beta1.EndpointSlice, err error) {
|
||||
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1beta1.EndpointSlice))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves the EndpointSlice from the indexer for a given namespace and name.
|
||||
func (s endpointSliceNamespaceLister) Get(name string) (*v1beta1.EndpointSlice, error) {
|
||||
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.NewNotFound(v1beta1.Resource("endpointslice"), name)
|
||||
}
|
||||
return obj.(*v1beta1.EndpointSlice), nil
|
||||
}
|
||||
27
listers/discovery/v1beta1/expansion_generated.go
Normal file
27
listers/discovery/v1beta1/expansion_generated.go
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
// EndpointSliceListerExpansion allows custom methods to be added to
|
||||
// EndpointSliceLister.
|
||||
type EndpointSliceListerExpansion interface{}
|
||||
|
||||
// EndpointSliceNamespaceListerExpansion allows custom methods to be added to
|
||||
// EndpointSliceNamespaceLister.
|
||||
type EndpointSliceNamespaceListerExpansion interface{}
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 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 v1beta1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
// DeploymentListerExpansion allows custom methods to be added to
|
||||
// DeploymentLister.
|
||||
type DeploymentListerExpansion interface {
|
||||
GetDeploymentsForReplicaSet(rs *extensions.ReplicaSet) ([]*extensions.Deployment, error)
|
||||
}
|
||||
|
||||
// DeploymentNamespaceListerExpansion allows custom methods to be added to
|
||||
// DeploymentNamespaceLister.
|
||||
type DeploymentNamespaceListerExpansion interface{}
|
||||
|
||||
// GetDeploymentsForReplicaSet returns a list of Deployments that potentially
|
||||
// match a ReplicaSet. Only the one specified in the ReplicaSet's ControllerRef
|
||||
// will actually manage it.
|
||||
// Returns an error only if no matching Deployments are found.
|
||||
func (s *deploymentLister) GetDeploymentsForReplicaSet(rs *extensions.ReplicaSet) ([]*extensions.Deployment, error) {
|
||||
if len(rs.Labels) == 0 {
|
||||
return nil, fmt.Errorf("no deployments found for ReplicaSet %v because it has no labels", rs.Name)
|
||||
}
|
||||
|
||||
// TODO: MODIFY THIS METHOD so that it checks for the podTemplateSpecHash label
|
||||
dList, err := s.Deployments(rs.Namespace).List(labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var deployments []*extensions.Deployment
|
||||
for _, d := range dList {
|
||||
selector, err := metav1.LabelSelectorAsSelector(d.Spec.Selector)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid label selector: %v", err)
|
||||
}
|
||||
// If a deployment with a nil or empty selector creeps in, it should match nothing, not everything.
|
||||
if selector.Empty() || !selector.Matches(labels.Set(rs.Labels)) {
|
||||
continue
|
||||
}
|
||||
deployments = append(deployments, d)
|
||||
}
|
||||
|
||||
if len(deployments) == 0 {
|
||||
return nil, fmt.Errorf("could not find deployments set for ReplicaSet %s in namespace %s with labels: %v", rs.Name, rs.Namespace, rs.Labels)
|
||||
}
|
||||
|
||||
return deployments, nil
|
||||
}
|
||||
@@ -18,6 +18,14 @@ limitations under the License.
|
||||
|
||||
package v1beta1
|
||||
|
||||
// DeploymentListerExpansion allows custom methods to be added to
|
||||
// DeploymentLister.
|
||||
type DeploymentListerExpansion interface{}
|
||||
|
||||
// DeploymentNamespaceListerExpansion allows custom methods to be added to
|
||||
// DeploymentNamespaceLister.
|
||||
type DeploymentNamespaceListerExpansion interface{}
|
||||
|
||||
// IngressListerExpansion allows custom methods to be added to
|
||||
// IngressLister.
|
||||
type IngressListerExpansion interface{}
|
||||
|
||||
27
listers/flowcontrol/v1alpha1/expansion_generated.go
Normal file
27
listers/flowcontrol/v1alpha1/expansion_generated.go
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
// FlowSchemaListerExpansion allows custom methods to be added to
|
||||
// FlowSchemaLister.
|
||||
type FlowSchemaListerExpansion interface{}
|
||||
|
||||
// PriorityLevelConfigurationListerExpansion allows custom methods to be added to
|
||||
// PriorityLevelConfigurationLister.
|
||||
type PriorityLevelConfigurationListerExpansion interface{}
|
||||
65
listers/flowcontrol/v1alpha1/flowschema.go
Normal file
65
listers/flowcontrol/v1alpha1/flowschema.go
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
v1alpha1 "k8s.io/api/flowcontrol/v1alpha1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// FlowSchemaLister helps list FlowSchemas.
|
||||
type FlowSchemaLister interface {
|
||||
// List lists all FlowSchemas in the indexer.
|
||||
List(selector labels.Selector) (ret []*v1alpha1.FlowSchema, err error)
|
||||
// Get retrieves the FlowSchema from the index for a given name.
|
||||
Get(name string) (*v1alpha1.FlowSchema, error)
|
||||
FlowSchemaListerExpansion
|
||||
}
|
||||
|
||||
// flowSchemaLister implements the FlowSchemaLister interface.
|
||||
type flowSchemaLister struct {
|
||||
indexer cache.Indexer
|
||||
}
|
||||
|
||||
// NewFlowSchemaLister returns a new FlowSchemaLister.
|
||||
func NewFlowSchemaLister(indexer cache.Indexer) FlowSchemaLister {
|
||||
return &flowSchemaLister{indexer: indexer}
|
||||
}
|
||||
|
||||
// List lists all FlowSchemas in the indexer.
|
||||
func (s *flowSchemaLister) List(selector labels.Selector) (ret []*v1alpha1.FlowSchema, err error) {
|
||||
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha1.FlowSchema))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves the FlowSchema from the index for a given name.
|
||||
func (s *flowSchemaLister) Get(name string) (*v1alpha1.FlowSchema, error) {
|
||||
obj, exists, err := s.indexer.GetByKey(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.NewNotFound(v1alpha1.Resource("flowschema"), name)
|
||||
}
|
||||
return obj.(*v1alpha1.FlowSchema), nil
|
||||
}
|
||||
65
listers/flowcontrol/v1alpha1/prioritylevelconfiguration.go
Normal file
65
listers/flowcontrol/v1alpha1/prioritylevelconfiguration.go
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
v1alpha1 "k8s.io/api/flowcontrol/v1alpha1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// PriorityLevelConfigurationLister helps list PriorityLevelConfigurations.
|
||||
type PriorityLevelConfigurationLister interface {
|
||||
// List lists all PriorityLevelConfigurations in the indexer.
|
||||
List(selector labels.Selector) (ret []*v1alpha1.PriorityLevelConfiguration, err error)
|
||||
// Get retrieves the PriorityLevelConfiguration from the index for a given name.
|
||||
Get(name string) (*v1alpha1.PriorityLevelConfiguration, error)
|
||||
PriorityLevelConfigurationListerExpansion
|
||||
}
|
||||
|
||||
// priorityLevelConfigurationLister implements the PriorityLevelConfigurationLister interface.
|
||||
type priorityLevelConfigurationLister struct {
|
||||
indexer cache.Indexer
|
||||
}
|
||||
|
||||
// NewPriorityLevelConfigurationLister returns a new PriorityLevelConfigurationLister.
|
||||
func NewPriorityLevelConfigurationLister(indexer cache.Indexer) PriorityLevelConfigurationLister {
|
||||
return &priorityLevelConfigurationLister{indexer: indexer}
|
||||
}
|
||||
|
||||
// List lists all PriorityLevelConfigurations in the indexer.
|
||||
func (s *priorityLevelConfigurationLister) List(selector labels.Selector) (ret []*v1alpha1.PriorityLevelConfiguration, err error) {
|
||||
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1alpha1.PriorityLevelConfiguration))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves the PriorityLevelConfiguration from the index for a given name.
|
||||
func (s *priorityLevelConfigurationLister) Get(name string) (*v1alpha1.PriorityLevelConfiguration, error) {
|
||||
obj, exists, err := s.indexer.GetByKey(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.NewNotFound(v1alpha1.Resource("prioritylevelconfiguration"), name)
|
||||
}
|
||||
return obj.(*v1alpha1.PriorityLevelConfiguration), nil
|
||||
}
|
||||
65
listers/storage/v1/csinode.go
Normal file
65
listers/storage/v1/csinode.go
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
v1 "k8s.io/api/storage/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// CSINodeLister helps list CSINodes.
|
||||
type CSINodeLister interface {
|
||||
// List lists all CSINodes in the indexer.
|
||||
List(selector labels.Selector) (ret []*v1.CSINode, err error)
|
||||
// Get retrieves the CSINode from the index for a given name.
|
||||
Get(name string) (*v1.CSINode, error)
|
||||
CSINodeListerExpansion
|
||||
}
|
||||
|
||||
// cSINodeLister implements the CSINodeLister interface.
|
||||
type cSINodeLister struct {
|
||||
indexer cache.Indexer
|
||||
}
|
||||
|
||||
// NewCSINodeLister returns a new CSINodeLister.
|
||||
func NewCSINodeLister(indexer cache.Indexer) CSINodeLister {
|
||||
return &cSINodeLister{indexer: indexer}
|
||||
}
|
||||
|
||||
// List lists all CSINodes in the indexer.
|
||||
func (s *cSINodeLister) List(selector labels.Selector) (ret []*v1.CSINode, err error) {
|
||||
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
|
||||
ret = append(ret, m.(*v1.CSINode))
|
||||
})
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieves the CSINode from the index for a given name.
|
||||
func (s *cSINodeLister) Get(name string) (*v1.CSINode, error) {
|
||||
obj, exists, err := s.indexer.GetByKey(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.NewNotFound(v1.Resource("csinode"), name)
|
||||
}
|
||||
return obj.(*v1.CSINode), nil
|
||||
}
|
||||
@@ -18,6 +18,10 @@ limitations under the License.
|
||||
|
||||
package v1
|
||||
|
||||
// CSINodeListerExpansion allows custom methods to be added to
|
||||
// CSINodeLister.
|
||||
type CSINodeListerExpansion interface{}
|
||||
|
||||
// StorageClassListerExpansion allows custom methods to be added to
|
||||
// StorageClassLister.
|
||||
type StorageClassListerExpansion interface{}
|
||||
|
||||
@@ -317,7 +317,6 @@ func (c *metadataResourceClient) List(opts metav1.ListOptions) (*metav1.PartialO
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("incoming object is incorrect type %T", obj)
|
||||
}
|
||||
fmt.Printf("DEBUG: %#v\n", inputList)
|
||||
|
||||
list := &metav1.PartialObjectMetadataList{
|
||||
ListMeta: inputList.ListMeta,
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -42,12 +43,14 @@ import (
|
||||
"k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1"
|
||||
"k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
|
||||
"k8s.io/client-go/tools/clientcmd/api"
|
||||
"k8s.io/client-go/tools/metrics"
|
||||
"k8s.io/client-go/transport"
|
||||
"k8s.io/client-go/util/connrotation"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
const execInfoEnv = "KUBERNETES_EXEC_INFO"
|
||||
const onRotateListWarningLength = 1000
|
||||
|
||||
var scheme = runtime.NewScheme()
|
||||
var codecs = serializer.NewCodecFactory(scheme)
|
||||
@@ -164,7 +167,7 @@ type Authenticator struct {
|
||||
cachedCreds *credentials
|
||||
exp time.Time
|
||||
|
||||
onRotate func()
|
||||
onRotateList []func()
|
||||
}
|
||||
|
||||
type credentials struct {
|
||||
@@ -191,7 +194,15 @@ func (a *Authenticator) UpdateTransportConfig(c *transport.Config) error {
|
||||
dial = (&net.Dialer{Timeout: 30 * time.Second, KeepAlive: 30 * time.Second}).DialContext
|
||||
}
|
||||
d := connrotation.NewDialer(dial)
|
||||
a.onRotate = d.CloseAll
|
||||
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
a.onRotateList = append(a.onRotateList, d.CloseAll)
|
||||
onRotateListLength := len(a.onRotateList)
|
||||
if onRotateListLength > onRotateListWarningLength {
|
||||
klog.Warningf("constructing many client instances from the same exec auth config can cause performance problems during cert rotation and can exhaust available network connections; %d clients constructed calling %q", onRotateListLength, a.cmd)
|
||||
}
|
||||
|
||||
c.Dial = d.DialContext
|
||||
|
||||
return nil
|
||||
@@ -251,6 +262,7 @@ func (a *Authenticator) cert() (*tls.Certificate, error) {
|
||||
func (a *Authenticator) getCreds() (*credentials, error) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
|
||||
if a.cachedCreds != nil && !a.credsExpired() {
|
||||
return a.cachedCreds, nil
|
||||
}
|
||||
@@ -258,6 +270,7 @@ func (a *Authenticator) getCreds() (*credentials, error) {
|
||||
if err := a.refreshCredsLocked(nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return a.cachedCreds, nil
|
||||
}
|
||||
|
||||
@@ -346,6 +359,17 @@ func (a *Authenticator) refreshCredsLocked(r *clientauthentication.Response) err
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed parsing client key/certificate: %v", err)
|
||||
}
|
||||
|
||||
// Leaf is initialized to be nil:
|
||||
// https://golang.org/pkg/crypto/tls/#X509KeyPair
|
||||
// Leaf certificate is the first certificate:
|
||||
// https://golang.org/pkg/crypto/tls/#Certificate
|
||||
// Populating leaf is useful for quickly accessing the underlying x509
|
||||
// certificate values.
|
||||
cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed parsing client leaf certificate: %v", err)
|
||||
}
|
||||
newCreds.cert = &cert
|
||||
}
|
||||
|
||||
@@ -353,8 +377,20 @@ func (a *Authenticator) refreshCredsLocked(r *clientauthentication.Response) err
|
||||
a.cachedCreds = newCreds
|
||||
// Only close all connections when TLS cert rotates. Token rotation doesn't
|
||||
// need the extra noise.
|
||||
if a.onRotate != nil && oldCreds != nil && !reflect.DeepEqual(oldCreds.cert, a.cachedCreds.cert) {
|
||||
a.onRotate()
|
||||
if oldCreds != nil && !reflect.DeepEqual(oldCreds.cert, a.cachedCreds.cert) {
|
||||
// Can be nil if the exec auth plugin only returned token auth.
|
||||
if oldCreds.cert != nil && oldCreds.cert.Leaf != nil {
|
||||
metrics.ClientCertRotationAge.Observe(time.Now().Sub(oldCreds.cert.Leaf.NotBefore))
|
||||
}
|
||||
for _, onRotate := range a.onRotateList {
|
||||
onRotate()
|
||||
}
|
||||
}
|
||||
|
||||
expiry := time.Time{}
|
||||
if a.cachedCreds.cert != nil && a.cachedCreds.cert.Leaf != nil {
|
||||
expiry = a.cachedCreds.cert.Leaf.NotAfter
|
||||
}
|
||||
expirationMetrics.set(a, expiry)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -97,6 +97,10 @@ func init() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
validCert = &cert
|
||||
}
|
||||
|
||||
@@ -713,8 +717,54 @@ func TestTLSCredentials(t *testing.T) {
|
||||
get(t, "valid TLS cert again", false)
|
||||
}
|
||||
|
||||
func TestConcurrentUpdateTransportConfig(t *testing.T) {
|
||||
n := time.Now()
|
||||
now := func() time.Time { return n }
|
||||
|
||||
env := []string{""}
|
||||
environ := func() []string {
|
||||
s := make([]string, len(env))
|
||||
copy(s, env)
|
||||
return s
|
||||
}
|
||||
|
||||
c := api.ExecConfig{
|
||||
Command: "./testdata/test-plugin.sh",
|
||||
APIVersion: "client.authentication.k8s.io/v1alpha1",
|
||||
}
|
||||
a, err := newAuthenticator(newCache(), &c)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
a.environ = environ
|
||||
a.now = now
|
||||
a.stderr = ioutil.Discard
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
defer close(stopCh)
|
||||
|
||||
numConcurrent := 2
|
||||
|
||||
for i := 0; i < numConcurrent; i++ {
|
||||
go func() {
|
||||
for {
|
||||
tc := &transport.Config{}
|
||||
a.UpdateTransportConfig(tc)
|
||||
|
||||
select {
|
||||
case <-stopCh:
|
||||
return
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
|
||||
// genClientCert generates an x509 certificate for testing. Certificate and key
|
||||
// are returned in PEM encoding.
|
||||
// are returned in PEM encoding. The generated cert expires in 24 hours.
|
||||
func genClientCert(t *testing.T) ([]byte, []byte) {
|
||||
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
|
||||
60
plugin/pkg/client/auth/exec/metrics.go
Normal file
60
plugin/pkg/client/auth/exec/metrics.go
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
Copyright 2018 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 exec
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"k8s.io/client-go/tools/metrics"
|
||||
)
|
||||
|
||||
type certificateExpirationTracker struct {
|
||||
mu sync.RWMutex
|
||||
m map[*Authenticator]time.Time
|
||||
metricSet func(*time.Time)
|
||||
}
|
||||
|
||||
var expirationMetrics = &certificateExpirationTracker{
|
||||
m: map[*Authenticator]time.Time{},
|
||||
metricSet: func(e *time.Time) {
|
||||
metrics.ClientCertExpiry.Set(e)
|
||||
},
|
||||
}
|
||||
|
||||
// set stores the given expiration time and updates the updates the certificate
|
||||
// expiry metric to the earliest expiration time.
|
||||
func (c *certificateExpirationTracker) set(a *Authenticator, t time.Time) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
c.m[a] = t
|
||||
|
||||
earliest := time.Time{}
|
||||
for _, t := range c.m {
|
||||
if t.IsZero() {
|
||||
continue
|
||||
}
|
||||
if earliest.IsZero() || earliest.After(t) {
|
||||
earliest = t
|
||||
}
|
||||
}
|
||||
if earliest.IsZero() {
|
||||
c.metricSet(nil)
|
||||
} else {
|
||||
c.metricSet(&earliest)
|
||||
}
|
||||
}
|
||||
96
plugin/pkg/client/auth/exec/metrics_test.go
Normal file
96
plugin/pkg/client/auth/exec/metrics_test.go
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
Copyright 2018 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 exec
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type mockExpiryGauge struct {
|
||||
v *time.Time
|
||||
}
|
||||
|
||||
func (m *mockExpiryGauge) Set(t *time.Time) {
|
||||
m.v = t
|
||||
}
|
||||
|
||||
func ptr(t time.Time) *time.Time {
|
||||
return &t
|
||||
}
|
||||
|
||||
func TestCertificateExpirationTracker(t *testing.T) {
|
||||
now := time.Now()
|
||||
mockMetric := &mockExpiryGauge{}
|
||||
|
||||
tracker := &certificateExpirationTracker{
|
||||
m: map[*Authenticator]time.Time{},
|
||||
metricSet: mockMetric.Set,
|
||||
}
|
||||
|
||||
firstAuthenticator := &Authenticator{}
|
||||
secondAuthenticator := &Authenticator{}
|
||||
for _, tc := range []struct {
|
||||
desc string
|
||||
auth *Authenticator
|
||||
time time.Time
|
||||
want *time.Time
|
||||
}{
|
||||
{
|
||||
desc: "ttl for one authenticator",
|
||||
auth: firstAuthenticator,
|
||||
time: now.Add(time.Minute * 10),
|
||||
want: ptr(now.Add(time.Minute * 10)),
|
||||
},
|
||||
{
|
||||
desc: "second authenticator shorter ttl",
|
||||
auth: secondAuthenticator,
|
||||
time: now.Add(time.Minute * 5),
|
||||
want: ptr(now.Add(time.Minute * 5)),
|
||||
},
|
||||
{
|
||||
desc: "update shorter to be longer",
|
||||
auth: secondAuthenticator,
|
||||
time: now.Add(time.Minute * 15),
|
||||
want: ptr(now.Add(time.Minute * 10)),
|
||||
},
|
||||
{
|
||||
desc: "update shorter to be zero time",
|
||||
auth: firstAuthenticator,
|
||||
time: time.Time{},
|
||||
want: ptr(now.Add(time.Minute * 15)),
|
||||
},
|
||||
{
|
||||
desc: "update last to be zero time records nil",
|
||||
auth: secondAuthenticator,
|
||||
time: time.Time{},
|
||||
want: nil,
|
||||
},
|
||||
} {
|
||||
// Must run in series as the tests build off each other.
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
tracker.set(tc.auth, tc.time)
|
||||
if mockMetric.v != nil && tc.want != nil {
|
||||
if !mockMetric.v.Equal(*tc.want) {
|
||||
t.Errorf("got: %s; want: %s", mockMetric.v, tc.want)
|
||||
}
|
||||
} else if mockMetric.v != tc.want {
|
||||
t.Errorf("got: %s; want: %s", mockMetric.v, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -476,25 +476,25 @@ func Test_cmdTokenSource_roundTrip(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
"Unauthorized",
|
||||
http.Response{StatusCode: 401},
|
||||
http.Response{StatusCode: http.StatusUnauthorized},
|
||||
make(map[string]string),
|
||||
make(map[string]string),
|
||||
},
|
||||
{
|
||||
"Unauthorized, nonempty defaultCache",
|
||||
http.Response{StatusCode: 401},
|
||||
http.Response{StatusCode: http.StatusUnauthorized},
|
||||
cmdCache,
|
||||
cmdCache,
|
||||
},
|
||||
{
|
||||
"Authorized",
|
||||
http.Response{StatusCode: 200},
|
||||
http.Response{StatusCode: http.StatusOK},
|
||||
make(map[string]string),
|
||||
simpleCacheUpdated,
|
||||
},
|
||||
{
|
||||
"Authorized, nonempty defaultCache",
|
||||
http.Response{StatusCode: 200},
|
||||
http.Response{StatusCode: http.StatusOK},
|
||||
cmdCache,
|
||||
cmdCacheUpdated,
|
||||
},
|
||||
|
||||
@@ -76,24 +76,25 @@ func newClientCache() *clientCache {
|
||||
}
|
||||
|
||||
type cacheKey struct {
|
||||
clusterAddress string
|
||||
// Canonical issuer URL string of the provider.
|
||||
issuerURL string
|
||||
clientID string
|
||||
}
|
||||
|
||||
func (c *clientCache) getClient(issuer, clientID string) (*oidcAuthProvider, bool) {
|
||||
func (c *clientCache) getClient(clusterAddress, issuer, clientID string) (*oidcAuthProvider, bool) {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
client, ok := c.cache[cacheKey{issuer, clientID}]
|
||||
client, ok := c.cache[cacheKey{clusterAddress: clusterAddress, issuerURL: issuer, clientID: clientID}]
|
||||
return client, ok
|
||||
}
|
||||
|
||||
// setClient attempts to put the client in the cache but may return any clients
|
||||
// with the same keys set before. This is so there's only ever one client for a provider.
|
||||
func (c *clientCache) setClient(issuer, clientID string, client *oidcAuthProvider) *oidcAuthProvider {
|
||||
func (c *clientCache) setClient(clusterAddress, issuer, clientID string, client *oidcAuthProvider) *oidcAuthProvider {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
key := cacheKey{issuer, clientID}
|
||||
key := cacheKey{clusterAddress: clusterAddress, issuerURL: issuer, clientID: clientID}
|
||||
|
||||
// If another client has already initialized a client for the given provider we want
|
||||
// to use that client instead of the one we're trying to set. This is so all transports
|
||||
@@ -107,7 +108,7 @@ func (c *clientCache) setClient(issuer, clientID string, client *oidcAuthProvide
|
||||
return client
|
||||
}
|
||||
|
||||
func newOIDCAuthProvider(_ string, cfg map[string]string, persister restclient.AuthProviderConfigPersister) (restclient.AuthProvider, error) {
|
||||
func newOIDCAuthProvider(clusterAddress string, cfg map[string]string, persister restclient.AuthProviderConfigPersister) (restclient.AuthProvider, error) {
|
||||
issuer := cfg[cfgIssuerUrl]
|
||||
if issuer == "" {
|
||||
return nil, fmt.Errorf("Must provide %s", cfgIssuerUrl)
|
||||
@@ -119,7 +120,7 @@ func newOIDCAuthProvider(_ string, cfg map[string]string, persister restclient.A
|
||||
}
|
||||
|
||||
// Check cache for existing provider.
|
||||
if provider, ok := cache.getClient(issuer, clientID); ok {
|
||||
if provider, ok := cache.getClient(clusterAddress, issuer, clientID); ok {
|
||||
return provider, nil
|
||||
}
|
||||
|
||||
@@ -157,7 +158,7 @@ func newOIDCAuthProvider(_ string, cfg map[string]string, persister restclient.A
|
||||
persister: persister,
|
||||
}
|
||||
|
||||
return cache.setClient(issuer, clientID, provider), nil
|
||||
return cache.setClient(clusterAddress, issuer, clientID, provider), nil
|
||||
}
|
||||
|
||||
type oidcAuthProvider struct {
|
||||
|
||||
@@ -119,20 +119,40 @@ func TestExpired(t *testing.T) {
|
||||
func TestClientCache(t *testing.T) {
|
||||
cache := newClientCache()
|
||||
|
||||
if _, ok := cache.getClient("issuer1", "id1"); ok {
|
||||
if _, ok := cache.getClient("cluster1", "issuer1", "id1"); ok {
|
||||
t.Fatalf("got client before putting one in the cache")
|
||||
}
|
||||
assertCacheLen(t, cache, 0)
|
||||
|
||||
cli1 := new(oidcAuthProvider)
|
||||
cli2 := new(oidcAuthProvider)
|
||||
cli3 := new(oidcAuthProvider)
|
||||
|
||||
gotcli := cache.setClient("issuer1", "id1", cli1)
|
||||
gotcli := cache.setClient("cluster1", "issuer1", "id1", cli1)
|
||||
if cli1 != gotcli {
|
||||
t.Fatalf("set first client and got a different one")
|
||||
}
|
||||
assertCacheLen(t, cache, 1)
|
||||
|
||||
gotcli = cache.setClient("issuer1", "id1", cli2)
|
||||
gotcli = cache.setClient("cluster1", "issuer1", "id1", cli2)
|
||||
if cli1 != gotcli {
|
||||
t.Fatalf("set a second client and didn't get the first")
|
||||
}
|
||||
assertCacheLen(t, cache, 1)
|
||||
|
||||
gotcli = cache.setClient("cluster2", "issuer1", "id1", cli3)
|
||||
if cli1 == gotcli {
|
||||
t.Fatalf("set a third client and got the first")
|
||||
}
|
||||
if cli3 != gotcli {
|
||||
t.Fatalf("set third client and got a different one")
|
||||
}
|
||||
assertCacheLen(t, cache, 2)
|
||||
}
|
||||
|
||||
func assertCacheLen(t *testing.T, cache *clientCache, length int) {
|
||||
t.Helper()
|
||||
if len(cache.cache) != length {
|
||||
t.Errorf("expected cache length %d got %d", length, len(cache.cache))
|
||||
}
|
||||
}
|
||||
|
||||
141
rest/client.go
141
rest/client.go
@@ -17,8 +17,6 @@ limitations under the License.
|
||||
package rest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -51,6 +49,28 @@ type Interface interface {
|
||||
APIVersion() schema.GroupVersion
|
||||
}
|
||||
|
||||
// ClientContentConfig controls how RESTClient communicates with the server.
|
||||
//
|
||||
// TODO: ContentConfig will be updated to accept a Negotiator instead of a
|
||||
// NegotiatedSerializer and NegotiatedSerializer will be removed.
|
||||
type ClientContentConfig struct {
|
||||
// AcceptContentTypes specifies the types the client will accept and is optional.
|
||||
// If not set, ContentType will be used to define the Accept header
|
||||
AcceptContentTypes string
|
||||
// ContentType specifies the wire format used to communicate with the server.
|
||||
// This value will be set as the Accept header on requests made to the server if
|
||||
// AcceptContentTypes is not set, and as the default content type on any object
|
||||
// sent to the server. If not set, "application/json" is used.
|
||||
ContentType string
|
||||
// GroupVersion is the API version to talk to. Must be provided when initializing
|
||||
// a RESTClient directly. When initializing a Client, will be set with the default
|
||||
// code version. This is used as the default group version for VersionedParams.
|
||||
GroupVersion schema.GroupVersion
|
||||
// Negotiator is used for obtaining encoders and decoders for multiple
|
||||
// supported media types.
|
||||
Negotiator runtime.ClientNegotiator
|
||||
}
|
||||
|
||||
// RESTClient imposes common Kubernetes API conventions on a set of resource paths.
|
||||
// The baseURL is expected to point to an HTTP or HTTPS path that is the parent
|
||||
// of one or more resources. The server should return a decodable API resource
|
||||
@@ -64,34 +84,27 @@ type RESTClient struct {
|
||||
// versionedAPIPath is a path segment connecting the base URL to the resource root
|
||||
versionedAPIPath string
|
||||
|
||||
// contentConfig is the information used to communicate with the server.
|
||||
contentConfig ContentConfig
|
||||
|
||||
// serializers contain all serializers for underlying content type.
|
||||
serializers Serializers
|
||||
// content describes how a RESTClient encodes and decodes responses.
|
||||
content ClientContentConfig
|
||||
|
||||
// creates BackoffManager that is passed to requests.
|
||||
createBackoffMgr func() BackoffManager
|
||||
|
||||
// TODO extract this into a wrapper interface via the RESTClient interface in kubectl.
|
||||
Throttle flowcontrol.RateLimiter
|
||||
// rateLimiter is shared among all requests created by this client unless specifically
|
||||
// overridden.
|
||||
rateLimiter flowcontrol.RateLimiter
|
||||
|
||||
// Set specific behavior of the client. If not set http.DefaultClient will be used.
|
||||
Client *http.Client
|
||||
}
|
||||
|
||||
type Serializers struct {
|
||||
Encoder runtime.Encoder
|
||||
Decoder runtime.Decoder
|
||||
StreamingSerializer runtime.Serializer
|
||||
Framer runtime.Framer
|
||||
RenegotiatedDecoder func(contentType string, params map[string]string) (runtime.Decoder, error)
|
||||
}
|
||||
|
||||
// NewRESTClient creates a new RESTClient. This client performs generic REST functions
|
||||
// such as Get, Put, Post, and Delete on specified paths. Codec controls encoding and
|
||||
// decoding of responses from the server.
|
||||
func NewRESTClient(baseURL *url.URL, versionedAPIPath string, config ContentConfig, maxQPS float32, maxBurst int, rateLimiter flowcontrol.RateLimiter, client *http.Client) (*RESTClient, error) {
|
||||
// such as Get, Put, Post, and Delete on specified paths.
|
||||
func NewRESTClient(baseURL *url.URL, versionedAPIPath string, config ClientContentConfig, rateLimiter flowcontrol.RateLimiter, client *http.Client) (*RESTClient, error) {
|
||||
if len(config.ContentType) == 0 {
|
||||
config.ContentType = "application/json"
|
||||
}
|
||||
|
||||
base := *baseURL
|
||||
if !strings.HasSuffix(base.Path, "/") {
|
||||
base.Path += "/"
|
||||
@@ -99,31 +112,14 @@ func NewRESTClient(baseURL *url.URL, versionedAPIPath string, config ContentConf
|
||||
base.RawQuery = ""
|
||||
base.Fragment = ""
|
||||
|
||||
if config.GroupVersion == nil {
|
||||
config.GroupVersion = &schema.GroupVersion{}
|
||||
}
|
||||
if len(config.ContentType) == 0 {
|
||||
config.ContentType = "application/json"
|
||||
}
|
||||
serializers, err := createSerializers(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var throttle flowcontrol.RateLimiter
|
||||
if maxQPS > 0 && rateLimiter == nil {
|
||||
throttle = flowcontrol.NewTokenBucketRateLimiter(maxQPS, maxBurst)
|
||||
} else if rateLimiter != nil {
|
||||
throttle = rateLimiter
|
||||
}
|
||||
return &RESTClient{
|
||||
base: &base,
|
||||
versionedAPIPath: versionedAPIPath,
|
||||
contentConfig: config,
|
||||
serializers: *serializers,
|
||||
content: config,
|
||||
createBackoffMgr: readExpBackoffConfig,
|
||||
Throttle: throttle,
|
||||
Client: client,
|
||||
rateLimiter: rateLimiter,
|
||||
|
||||
Client: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -132,7 +128,7 @@ func (c *RESTClient) GetRateLimiter() flowcontrol.RateLimiter {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return c.Throttle
|
||||
return c.rateLimiter
|
||||
}
|
||||
|
||||
// readExpBackoffConfig handles the internal logic of determining what the
|
||||
@@ -153,58 +149,6 @@ func readExpBackoffConfig() BackoffManager {
|
||||
time.Duration(backoffDurationInt)*time.Second)}
|
||||
}
|
||||
|
||||
// createSerializers creates all necessary serializers for given contentType.
|
||||
// TODO: the negotiated serializer passed to this method should probably return
|
||||
// serializers that control decoding and versioning without this package
|
||||
// being aware of the types. Depends on whether RESTClient must deal with
|
||||
// generic infrastructure.
|
||||
func createSerializers(config ContentConfig) (*Serializers, error) {
|
||||
mediaTypes := config.NegotiatedSerializer.SupportedMediaTypes()
|
||||
contentType := config.ContentType
|
||||
mediaType, _, err := mime.ParseMediaType(contentType)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("the content type specified in the client configuration is not recognized: %v", err)
|
||||
}
|
||||
info, ok := runtime.SerializerInfoForMediaType(mediaTypes, mediaType)
|
||||
if !ok {
|
||||
if len(contentType) != 0 || len(mediaTypes) == 0 {
|
||||
return nil, fmt.Errorf("no serializers registered for %s", contentType)
|
||||
}
|
||||
info = mediaTypes[0]
|
||||
}
|
||||
|
||||
internalGV := schema.GroupVersions{
|
||||
{
|
||||
Group: config.GroupVersion.Group,
|
||||
Version: runtime.APIVersionInternal,
|
||||
},
|
||||
// always include the legacy group as a decoding target to handle non-error `Status` return types
|
||||
{
|
||||
Group: "",
|
||||
Version: runtime.APIVersionInternal,
|
||||
},
|
||||
}
|
||||
|
||||
s := &Serializers{
|
||||
Encoder: config.NegotiatedSerializer.EncoderForVersion(info.Serializer, *config.GroupVersion),
|
||||
Decoder: config.NegotiatedSerializer.DecoderToVersion(info.Serializer, internalGV),
|
||||
|
||||
RenegotiatedDecoder: func(contentType string, params map[string]string) (runtime.Decoder, error) {
|
||||
info, ok := runtime.SerializerInfoForMediaType(mediaTypes, contentType)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("serializer for %s not registered", contentType)
|
||||
}
|
||||
return config.NegotiatedSerializer.DecoderToVersion(info.Serializer, internalGV), nil
|
||||
},
|
||||
}
|
||||
if info.StreamSerializer != nil {
|
||||
s.StreamingSerializer = info.StreamSerializer.Serializer
|
||||
s.Framer = info.StreamSerializer.Framer
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Verb begins a request with a verb (GET, POST, PUT, DELETE).
|
||||
//
|
||||
// Example usage of RESTClient's request building interface:
|
||||
@@ -219,12 +163,7 @@ func createSerializers(config ContentConfig) (*Serializers, error) {
|
||||
// list, ok := resp.(*api.PodList)
|
||||
//
|
||||
func (c *RESTClient) Verb(verb string) *Request {
|
||||
backoff := c.createBackoffMgr()
|
||||
|
||||
if c.Client == nil {
|
||||
return NewRequest(nil, verb, c.base, c.versionedAPIPath, c.contentConfig, c.serializers, backoff, c.Throttle, 0)
|
||||
}
|
||||
return NewRequest(c.Client, verb, c.base, c.versionedAPIPath, c.contentConfig, c.serializers, backoff, c.Throttle, c.Client.Timeout)
|
||||
return NewRequest(c).Verb(verb)
|
||||
}
|
||||
|
||||
// Post begins a POST request. Short for c.Verb("POST").
|
||||
@@ -254,5 +193,5 @@ func (c *RESTClient) Delete() *Request {
|
||||
|
||||
// APIVersion returns the APIVersion this RESTClient is expected to use.
|
||||
func (c *RESTClient) APIVersion() schema.GroupVersion {
|
||||
return *c.contentConfig.GroupVersion
|
||||
return c.content.GroupVersion
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ import (
|
||||
|
||||
"fmt"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
v1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -57,12 +57,14 @@ func TestSerializer(t *testing.T) {
|
||||
NegotiatedSerializer: scheme.Codecs.WithoutConversion(),
|
||||
}
|
||||
|
||||
serializer, err := createSerializers(contentConfig)
|
||||
n := runtime.NewClientNegotiator(contentConfig.NegotiatedSerializer, gv)
|
||||
d, err := n.Decoder("application/json", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// bytes based on actual return from API server when encoding an "unversioned" object
|
||||
obj, err := runtime.Decode(serializer.Decoder, []byte(`{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Success"}`))
|
||||
obj, err := runtime.Decode(d, []byte(`{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Success"}`))
|
||||
t.Log(obj)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -269,6 +269,9 @@ type ContentConfig struct {
|
||||
GroupVersion *schema.GroupVersion
|
||||
// NegotiatedSerializer is used for obtaining encoders and decoders for multiple
|
||||
// supported media types.
|
||||
//
|
||||
// TODO: NegotiatedSerializer will be phased out as internal clients are removed
|
||||
// from Kubernetes.
|
||||
NegotiatedSerializer runtime.NegotiatedSerializer
|
||||
}
|
||||
|
||||
@@ -283,14 +286,6 @@ func RESTClientFor(config *Config) (*RESTClient, error) {
|
||||
if config.NegotiatedSerializer == nil {
|
||||
return nil, fmt.Errorf("NegotiatedSerializer is required when initializing a RESTClient")
|
||||
}
|
||||
qps := config.QPS
|
||||
if config.QPS == 0.0 {
|
||||
qps = DefaultQPS
|
||||
}
|
||||
burst := config.Burst
|
||||
if config.Burst == 0 {
|
||||
burst = DefaultBurst
|
||||
}
|
||||
|
||||
baseURL, versionedAPIPath, err := defaultServerUrlFor(config)
|
||||
if err != nil {
|
||||
@@ -310,7 +305,33 @@ func RESTClientFor(config *Config) (*RESTClient, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return NewRESTClient(baseURL, versionedAPIPath, config.ContentConfig, qps, burst, config.RateLimiter, httpClient)
|
||||
rateLimiter := config.RateLimiter
|
||||
if rateLimiter == nil {
|
||||
qps := config.QPS
|
||||
if config.QPS == 0.0 {
|
||||
qps = DefaultQPS
|
||||
}
|
||||
burst := config.Burst
|
||||
if config.Burst == 0 {
|
||||
burst = DefaultBurst
|
||||
}
|
||||
if qps > 0 {
|
||||
rateLimiter = flowcontrol.NewTokenBucketRateLimiter(qps, burst)
|
||||
}
|
||||
}
|
||||
|
||||
var gv schema.GroupVersion
|
||||
if config.GroupVersion != nil {
|
||||
gv = *config.GroupVersion
|
||||
}
|
||||
clientContent := ClientContentConfig{
|
||||
AcceptContentTypes: config.AcceptContentTypes,
|
||||
ContentType: config.ContentType,
|
||||
GroupVersion: gv,
|
||||
Negotiator: runtime.NewClientNegotiator(config.NegotiatedSerializer, gv),
|
||||
}
|
||||
|
||||
return NewRESTClient(baseURL, versionedAPIPath, clientContent, rateLimiter, httpClient)
|
||||
}
|
||||
|
||||
// UnversionedRESTClientFor is the same as RESTClientFor, except that it allows
|
||||
@@ -338,13 +359,33 @@ func UnversionedRESTClientFor(config *Config) (*RESTClient, error) {
|
||||
}
|
||||
}
|
||||
|
||||
versionConfig := config.ContentConfig
|
||||
if versionConfig.GroupVersion == nil {
|
||||
v := metav1.SchemeGroupVersion
|
||||
versionConfig.GroupVersion = &v
|
||||
rateLimiter := config.RateLimiter
|
||||
if rateLimiter == nil {
|
||||
qps := config.QPS
|
||||
if config.QPS == 0.0 {
|
||||
qps = DefaultQPS
|
||||
}
|
||||
burst := config.Burst
|
||||
if config.Burst == 0 {
|
||||
burst = DefaultBurst
|
||||
}
|
||||
if qps > 0 {
|
||||
rateLimiter = flowcontrol.NewTokenBucketRateLimiter(qps, burst)
|
||||
}
|
||||
}
|
||||
|
||||
return NewRESTClient(baseURL, versionedAPIPath, versionConfig, config.QPS, config.Burst, config.RateLimiter, httpClient)
|
||||
gv := metav1.SchemeGroupVersion
|
||||
if config.GroupVersion != nil {
|
||||
gv = *config.GroupVersion
|
||||
}
|
||||
clientContent := ClientContentConfig{
|
||||
AcceptContentTypes: config.AcceptContentTypes,
|
||||
ContentType: config.ContentType,
|
||||
GroupVersion: gv,
|
||||
Negotiator: runtime.NewClientNegotiator(config.NegotiatedSerializer, gv),
|
||||
}
|
||||
|
||||
return NewRESTClient(baseURL, versionedAPIPath, clientContent, rateLimiter, httpClient)
|
||||
}
|
||||
|
||||
// SetKubernetesDefaults sets default values on the provided client config for accessing the
|
||||
|
||||
@@ -155,6 +155,59 @@ func TestRESTClientRequires(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRESTClientLimiter(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Name string
|
||||
Config Config
|
||||
Limiter flowcontrol.RateLimiter
|
||||
}{
|
||||
{
|
||||
Config: Config{},
|
||||
Limiter: flowcontrol.NewTokenBucketRateLimiter(5, 10),
|
||||
},
|
||||
{
|
||||
Config: Config{QPS: 10},
|
||||
Limiter: flowcontrol.NewTokenBucketRateLimiter(10, 10),
|
||||
},
|
||||
{
|
||||
Config: Config{QPS: -1},
|
||||
Limiter: nil,
|
||||
},
|
||||
{
|
||||
Config: Config{
|
||||
RateLimiter: flowcontrol.NewTokenBucketRateLimiter(11, 12),
|
||||
},
|
||||
Limiter: flowcontrol.NewTokenBucketRateLimiter(11, 12),
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
t.Run("Versioned_"+testCase.Name, func(t *testing.T) {
|
||||
config := testCase.Config
|
||||
config.Host = "127.0.0.1"
|
||||
config.ContentConfig = ContentConfig{GroupVersion: &v1.SchemeGroupVersion, NegotiatedSerializer: scheme.Codecs}
|
||||
client, err := RESTClientFor(&config)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(testCase.Limiter, client.rateLimiter) {
|
||||
t.Fatalf("unexpected rate limiter: %#v", client.rateLimiter)
|
||||
}
|
||||
})
|
||||
t.Run("Unversioned_"+testCase.Name, func(t *testing.T) {
|
||||
config := testCase.Config
|
||||
config.Host = "127.0.0.1"
|
||||
config.ContentConfig = ContentConfig{GroupVersion: &v1.SchemeGroupVersion, NegotiatedSerializer: scheme.Codecs}
|
||||
client, err := UnversionedRESTClientFor(&config)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(testCase.Limiter, client.rateLimiter) {
|
||||
t.Fatalf("unexpected rate limiter: %#v", client.rateLimiter)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type fakeLimiter struct {
|
||||
FakeSaturation float64
|
||||
FakeQPS float32
|
||||
|
||||
@@ -29,6 +29,8 @@ import (
|
||||
"k8s.io/client-go/util/flowcontrol"
|
||||
)
|
||||
|
||||
// CreateHTTPClient creates an http.Client that will invoke the provided roundTripper func
|
||||
// when a request is made.
|
||||
func CreateHTTPClient(roundTripper func(*http.Request) (*http.Response, error)) *http.Client {
|
||||
return &http.Client{
|
||||
Transport: roundTripperFunc(roundTripper),
|
||||
@@ -41,40 +43,49 @@ func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
return f(req)
|
||||
}
|
||||
|
||||
// RESTClient provides a fake RESTClient interface.
|
||||
// RESTClient provides a fake RESTClient interface. It is used to mock network
|
||||
// interactions via a rest.Request, or to make them via the provided Client to
|
||||
// a specific server.
|
||||
type RESTClient struct {
|
||||
Client *http.Client
|
||||
NegotiatedSerializer runtime.NegotiatedSerializer
|
||||
GroupVersion schema.GroupVersion
|
||||
VersionedAPIPath string
|
||||
|
||||
Req *http.Request
|
||||
// Err is returned when any request would be made to the server. If Err is set,
|
||||
// Req will not be recorded, Resp will not be returned, and Client will not be
|
||||
// invoked.
|
||||
Err error
|
||||
// Req is set to the last request that was executed (had the methods Do/DoRaw) invoked.
|
||||
Req *http.Request
|
||||
// If Client is specified, the client will be invoked instead of returning Resp if
|
||||
// Err is not set.
|
||||
Client *http.Client
|
||||
// Resp is returned to the caller after Req is recorded, unless Err or Client are set.
|
||||
Resp *http.Response
|
||||
Err error
|
||||
}
|
||||
|
||||
func (c *RESTClient) Get() *restclient.Request {
|
||||
return c.request("GET")
|
||||
return c.Verb("GET")
|
||||
}
|
||||
|
||||
func (c *RESTClient) Put() *restclient.Request {
|
||||
return c.request("PUT")
|
||||
return c.Verb("PUT")
|
||||
}
|
||||
|
||||
func (c *RESTClient) Patch(pt types.PatchType) *restclient.Request {
|
||||
return c.request("PATCH").SetHeader("Content-Type", string(pt))
|
||||
return c.Verb("PATCH").SetHeader("Content-Type", string(pt))
|
||||
}
|
||||
|
||||
func (c *RESTClient) Post() *restclient.Request {
|
||||
return c.request("POST")
|
||||
return c.Verb("POST")
|
||||
}
|
||||
|
||||
func (c *RESTClient) Delete() *restclient.Request {
|
||||
return c.request("DELETE")
|
||||
return c.Verb("DELETE")
|
||||
}
|
||||
|
||||
func (c *RESTClient) Verb(verb string) *restclient.Request {
|
||||
return c.request(verb)
|
||||
return c.Request().Verb(verb)
|
||||
}
|
||||
|
||||
func (c *RESTClient) APIVersion() schema.GroupVersion {
|
||||
@@ -85,28 +96,17 @@ func (c *RESTClient) GetRateLimiter() flowcontrol.RateLimiter {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *RESTClient) request(verb string) *restclient.Request {
|
||||
config := restclient.ContentConfig{
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
GroupVersion: &c.GroupVersion,
|
||||
NegotiatedSerializer: c.NegotiatedSerializer,
|
||||
func (c *RESTClient) Request() *restclient.Request {
|
||||
config := restclient.ClientContentConfig{
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
GroupVersion: c.GroupVersion,
|
||||
Negotiator: runtime.NewClientNegotiator(c.NegotiatedSerializer, c.GroupVersion),
|
||||
}
|
||||
|
||||
ns := c.NegotiatedSerializer
|
||||
info, _ := runtime.SerializerInfoForMediaType(ns.SupportedMediaTypes(), runtime.ContentTypeJSON)
|
||||
serializers := restclient.Serializers{
|
||||
// TODO this was hardcoded before, but it doesn't look right
|
||||
Encoder: ns.EncoderForVersion(info.Serializer, c.GroupVersion),
|
||||
Decoder: ns.DecoderToVersion(info.Serializer, c.GroupVersion),
|
||||
}
|
||||
if info.StreamSerializer != nil {
|
||||
serializers.StreamingSerializer = info.StreamSerializer.Serializer
|
||||
serializers.Framer = info.StreamSerializer.Framer
|
||||
}
|
||||
return restclient.NewRequest(c, verb, &url.URL{Host: "localhost"}, c.VersionedAPIPath, config, serializers, nil, nil, 0)
|
||||
return restclient.NewRequestWithClient(&url.URL{Scheme: "https", Host: "localhost"}, c.VersionedAPIPath, config, CreateHTTPClient(c.do))
|
||||
}
|
||||
|
||||
func (c *RESTClient) Do(req *http.Request) (*http.Response, error) {
|
||||
// do is invoked when a Request() created by this client is executed.
|
||||
func (c *RESTClient) do(req *http.Request) (*http.Response, error) {
|
||||
if c.Err != nil {
|
||||
return nil, c.Err
|
||||
}
|
||||
|
||||
221
rest/request.go
221
rest/request.go
@@ -48,7 +48,8 @@ import (
|
||||
|
||||
var (
|
||||
// longThrottleLatency defines threshold for logging requests. All requests being
|
||||
// throttle for more than longThrottleLatency will be logged.
|
||||
// throttled (via the provided rateLimiter) for more than longThrottleLatency will
|
||||
// be logged.
|
||||
longThrottleLatency = 50 * time.Millisecond
|
||||
)
|
||||
|
||||
@@ -74,19 +75,20 @@ func (r *RequestConstructionError) Error() string {
|
||||
return fmt.Sprintf("request construction error: '%v'", r.Err)
|
||||
}
|
||||
|
||||
var noBackoff = &NoBackoff{}
|
||||
|
||||
// Request allows for building up a request to a server in a chained fashion.
|
||||
// Any errors are stored until the end of your call, so you only have to
|
||||
// check once.
|
||||
type Request struct {
|
||||
// required
|
||||
client HTTPClient
|
||||
verb string
|
||||
c *RESTClient
|
||||
|
||||
baseURL *url.URL
|
||||
content ContentConfig
|
||||
serializers Serializers
|
||||
rateLimiter flowcontrol.RateLimiter
|
||||
backoff BackoffManager
|
||||
timeout time.Duration
|
||||
|
||||
// generic components accessible via method setters
|
||||
verb string
|
||||
pathPrefix string
|
||||
subpath string
|
||||
params url.Values
|
||||
@@ -98,7 +100,6 @@ type Request struct {
|
||||
resource string
|
||||
resourceName string
|
||||
subresource string
|
||||
timeout time.Duration
|
||||
|
||||
// output
|
||||
err error
|
||||
@@ -106,42 +107,63 @@ type Request struct {
|
||||
|
||||
// This is only used for per-request timeouts, deadlines, and cancellations.
|
||||
ctx context.Context
|
||||
|
||||
backoffMgr BackoffManager
|
||||
throttle flowcontrol.RateLimiter
|
||||
}
|
||||
|
||||
// NewRequest creates a new request helper object for accessing runtime.Objects on a server.
|
||||
func NewRequest(client HTTPClient, verb string, baseURL *url.URL, versionedAPIPath string, content ContentConfig, serializers Serializers, backoff BackoffManager, throttle flowcontrol.RateLimiter, timeout time.Duration) *Request {
|
||||
func NewRequest(c *RESTClient) *Request {
|
||||
var backoff BackoffManager
|
||||
if c.createBackoffMgr != nil {
|
||||
backoff = c.createBackoffMgr()
|
||||
}
|
||||
if backoff == nil {
|
||||
klog.V(2).Infof("Not implementing request backoff strategy.")
|
||||
backoff = &NoBackoff{}
|
||||
backoff = noBackoff
|
||||
}
|
||||
|
||||
pathPrefix := "/"
|
||||
if baseURL != nil {
|
||||
pathPrefix = path.Join(pathPrefix, baseURL.Path)
|
||||
var pathPrefix string
|
||||
if c.base != nil {
|
||||
pathPrefix = path.Join("/", c.base.Path, c.versionedAPIPath)
|
||||
} else {
|
||||
pathPrefix = path.Join("/", c.versionedAPIPath)
|
||||
}
|
||||
|
||||
var timeout time.Duration
|
||||
if c.Client != nil {
|
||||
timeout = c.Client.Timeout
|
||||
}
|
||||
|
||||
r := &Request{
|
||||
client: client,
|
||||
verb: verb,
|
||||
baseURL: baseURL,
|
||||
pathPrefix: path.Join(pathPrefix, versionedAPIPath),
|
||||
content: content,
|
||||
serializers: serializers,
|
||||
backoffMgr: backoff,
|
||||
throttle: throttle,
|
||||
c: c,
|
||||
rateLimiter: c.rateLimiter,
|
||||
backoff: backoff,
|
||||
timeout: timeout,
|
||||
pathPrefix: pathPrefix,
|
||||
}
|
||||
|
||||
switch {
|
||||
case len(content.AcceptContentTypes) > 0:
|
||||
r.SetHeader("Accept", content.AcceptContentTypes)
|
||||
case len(content.ContentType) > 0:
|
||||
r.SetHeader("Accept", content.ContentType+", */*")
|
||||
case len(c.content.AcceptContentTypes) > 0:
|
||||
r.SetHeader("Accept", c.content.AcceptContentTypes)
|
||||
case len(c.content.ContentType) > 0:
|
||||
r.SetHeader("Accept", c.content.ContentType+", */*")
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// NewRequestWithClient creates a Request with an embedded RESTClient for use in test scenarios.
|
||||
func NewRequestWithClient(base *url.URL, versionedAPIPath string, content ClientContentConfig, client *http.Client) *Request {
|
||||
return NewRequest(&RESTClient{
|
||||
base: base,
|
||||
versionedAPIPath: versionedAPIPath,
|
||||
content: content,
|
||||
Client: client,
|
||||
})
|
||||
}
|
||||
|
||||
// Verb sets the verb this request will use.
|
||||
func (r *Request) Verb(verb string) *Request {
|
||||
r.verb = verb
|
||||
return r
|
||||
}
|
||||
|
||||
// Prefix adds segments to the relative beginning to the request path. These
|
||||
// items will be placed before the optional Namespace, Resource, or Name sections.
|
||||
// Setting AbsPath will clear any previously set Prefix segments
|
||||
@@ -184,17 +206,17 @@ func (r *Request) Resource(resource string) *Request {
|
||||
// or defaults to the stub implementation if nil is provided
|
||||
func (r *Request) BackOff(manager BackoffManager) *Request {
|
||||
if manager == nil {
|
||||
r.backoffMgr = &NoBackoff{}
|
||||
r.backoff = &NoBackoff{}
|
||||
return r
|
||||
}
|
||||
|
||||
r.backoffMgr = manager
|
||||
r.backoff = manager
|
||||
return r
|
||||
}
|
||||
|
||||
// Throttle receives a rate-limiter and sets or replaces an existing request limiter
|
||||
func (r *Request) Throttle(limiter flowcontrol.RateLimiter) *Request {
|
||||
r.throttle = limiter
|
||||
r.rateLimiter = limiter
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -272,8 +294,8 @@ func (r *Request) AbsPath(segments ...string) *Request {
|
||||
if r.err != nil {
|
||||
return r
|
||||
}
|
||||
r.pathPrefix = path.Join(r.baseURL.Path, path.Join(segments...))
|
||||
if len(segments) == 1 && (len(r.baseURL.Path) > 1 || len(segments[0]) > 1) && strings.HasSuffix(segments[0], "/") {
|
||||
r.pathPrefix = path.Join(r.c.base.Path, path.Join(segments...))
|
||||
if len(segments) == 1 && (len(r.c.base.Path) > 1 || len(segments[0]) > 1) && strings.HasSuffix(segments[0], "/") {
|
||||
// preserve any trailing slashes for legacy behavior
|
||||
r.pathPrefix += "/"
|
||||
}
|
||||
@@ -317,7 +339,7 @@ func (r *Request) Param(paramName, s string) *Request {
|
||||
// VersionedParams will not write query parameters that have omitempty set and are empty. If a
|
||||
// parameter has already been set it is appended to (Params and VersionedParams are additive).
|
||||
func (r *Request) VersionedParams(obj runtime.Object, codec runtime.ParameterCodec) *Request {
|
||||
return r.SpecificallyVersionedParams(obj, codec, *r.content.GroupVersion)
|
||||
return r.SpecificallyVersionedParams(obj, codec, r.c.content.GroupVersion)
|
||||
}
|
||||
|
||||
func (r *Request) SpecificallyVersionedParams(obj runtime.Object, codec runtime.ParameterCodec, version schema.GroupVersion) *Request {
|
||||
@@ -397,14 +419,19 @@ func (r *Request) Body(obj interface{}) *Request {
|
||||
if reflect.ValueOf(t).IsNil() {
|
||||
return r
|
||||
}
|
||||
data, err := runtime.Encode(r.serializers.Encoder, t)
|
||||
encoder, err := r.c.content.Negotiator.Encoder(r.c.content.ContentType, nil)
|
||||
if err != nil {
|
||||
r.err = err
|
||||
return r
|
||||
}
|
||||
data, err := runtime.Encode(encoder, t)
|
||||
if err != nil {
|
||||
r.err = err
|
||||
return r
|
||||
}
|
||||
glogBody("Request Body", data)
|
||||
r.body = bytes.NewReader(data)
|
||||
r.SetHeader("Content-Type", r.content.ContentType)
|
||||
r.SetHeader("Content-Type", r.c.content.ContentType)
|
||||
default:
|
||||
r.err = fmt.Errorf("unknown type used for body: %+v", obj)
|
||||
}
|
||||
@@ -433,8 +460,8 @@ func (r *Request) URL() *url.URL {
|
||||
}
|
||||
|
||||
finalURL := &url.URL{}
|
||||
if r.baseURL != nil {
|
||||
*finalURL = *r.baseURL
|
||||
if r.c.base != nil {
|
||||
*finalURL = *r.c.base
|
||||
}
|
||||
finalURL.Path = p
|
||||
|
||||
@@ -468,8 +495,8 @@ func (r Request) finalURLTemplate() url.URL {
|
||||
segments := strings.Split(r.URL().Path, "/")
|
||||
groupIndex := 0
|
||||
index := 0
|
||||
if r.URL() != nil && r.baseURL != nil && strings.Contains(r.URL().Path, r.baseURL.Path) {
|
||||
groupIndex += len(strings.Split(r.baseURL.Path, "/"))
|
||||
if r.URL() != nil && r.c.base != nil && strings.Contains(r.URL().Path, r.c.base.Path) {
|
||||
groupIndex += len(strings.Split(r.c.base.Path, "/"))
|
||||
}
|
||||
if groupIndex >= len(segments) {
|
||||
return *url
|
||||
@@ -522,20 +549,20 @@ func (r Request) finalURLTemplate() url.URL {
|
||||
}
|
||||
|
||||
func (r *Request) tryThrottle() error {
|
||||
if r.throttle == nil {
|
||||
if r.rateLimiter == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
var err error
|
||||
if r.ctx != nil {
|
||||
err = r.throttle.Wait(r.ctx)
|
||||
err = r.rateLimiter.Wait(r.ctx)
|
||||
} else {
|
||||
r.throttle.Accept()
|
||||
r.rateLimiter.Accept()
|
||||
}
|
||||
|
||||
if latency := time.Since(now); latency > longThrottleLatency {
|
||||
klog.V(4).Infof("Throttling request took %v, request: %s:%s", latency, r.verb, r.URL().String())
|
||||
klog.V(3).Infof("Throttling request took %v, request: %s:%s", latency, r.verb, r.URL().String())
|
||||
}
|
||||
|
||||
return err
|
||||
@@ -544,27 +571,11 @@ func (r *Request) tryThrottle() error {
|
||||
// Watch attempts to begin watching the requested location.
|
||||
// Returns a watch.Interface, or an error.
|
||||
func (r *Request) Watch() (watch.Interface, error) {
|
||||
return r.WatchWithSpecificDecoders(
|
||||
func(body io.ReadCloser) streaming.Decoder {
|
||||
framer := r.serializers.Framer.NewFrameReader(body)
|
||||
return streaming.NewDecoder(framer, r.serializers.StreamingSerializer)
|
||||
},
|
||||
r.serializers.Decoder,
|
||||
)
|
||||
}
|
||||
|
||||
// WatchWithSpecificDecoders attempts to begin watching the requested location with a *different* decoder.
|
||||
// Turns out that you want one "standard" decoder for the watch event and one "personal" decoder for the content
|
||||
// Returns a watch.Interface, or an error.
|
||||
func (r *Request) WatchWithSpecificDecoders(wrapperDecoderFn func(io.ReadCloser) streaming.Decoder, embeddedDecoder runtime.Decoder) (watch.Interface, error) {
|
||||
// We specifically don't want to rate limit watches, so we
|
||||
// don't use r.throttle here.
|
||||
// don't use r.rateLimiter here.
|
||||
if r.err != nil {
|
||||
return nil, r.err
|
||||
}
|
||||
if r.serializers.Framer == nil {
|
||||
return nil, fmt.Errorf("watching resources is not possible with this client (content-type: %s)", r.content.ContentType)
|
||||
}
|
||||
|
||||
url := r.URL().String()
|
||||
req, err := http.NewRequest(r.verb, url, r.body)
|
||||
@@ -575,18 +586,18 @@ func (r *Request) WatchWithSpecificDecoders(wrapperDecoderFn func(io.ReadCloser)
|
||||
req = req.WithContext(r.ctx)
|
||||
}
|
||||
req.Header = r.headers
|
||||
client := r.client
|
||||
client := r.c.Client
|
||||
if client == nil {
|
||||
client = http.DefaultClient
|
||||
}
|
||||
r.backoffMgr.Sleep(r.backoffMgr.CalculateBackoff(r.URL()))
|
||||
r.backoff.Sleep(r.backoff.CalculateBackoff(r.URL()))
|
||||
resp, err := client.Do(req)
|
||||
updateURLMetrics(r, resp, err)
|
||||
if r.baseURL != nil {
|
||||
if r.c.base != nil {
|
||||
if err != nil {
|
||||
r.backoffMgr.UpdateBackoff(r.baseURL, err, 0)
|
||||
r.backoff.UpdateBackoff(r.c.base, err, 0)
|
||||
} else {
|
||||
r.backoffMgr.UpdateBackoff(r.baseURL, err, resp.StatusCode)
|
||||
r.backoff.UpdateBackoff(r.c.base, err, resp.StatusCode)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
@@ -604,9 +615,22 @@ func (r *Request) WatchWithSpecificDecoders(wrapperDecoderFn func(io.ReadCloser)
|
||||
}
|
||||
return nil, fmt.Errorf("for request %s, got status: %v", url, resp.StatusCode)
|
||||
}
|
||||
wrapperDecoder := wrapperDecoderFn(resp.Body)
|
||||
|
||||
contentType := resp.Header.Get("Content-Type")
|
||||
mediaType, params, err := mime.ParseMediaType(contentType)
|
||||
if err != nil {
|
||||
klog.V(4).Infof("Unexpected content type from the server: %q: %v", contentType, err)
|
||||
}
|
||||
objectDecoder, streamingSerializer, framer, err := r.c.content.Negotiator.StreamDecoder(mediaType, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
frameReader := framer.NewFrameReader(resp.Body)
|
||||
watchEventDecoder := streaming.NewDecoder(frameReader, streamingSerializer)
|
||||
|
||||
return watch.NewStreamWatcher(
|
||||
restclientwatch.NewDecoder(wrapperDecoder, embeddedDecoder),
|
||||
restclientwatch.NewDecoder(watchEventDecoder, objectDecoder),
|
||||
// use 500 to indicate that the cause of the error is unknown - other error codes
|
||||
// are more specific to HTTP interactions, and set a reason
|
||||
errors.NewClientErrorReporter(http.StatusInternalServerError, r.verb, "ClientWatchDecoding"),
|
||||
@@ -617,8 +641,8 @@ func (r *Request) WatchWithSpecificDecoders(wrapperDecoderFn func(io.ReadCloser)
|
||||
// It also handles corner cases for incomplete/invalid request data.
|
||||
func updateURLMetrics(req *Request, resp *http.Response, err error) {
|
||||
url := "none"
|
||||
if req.baseURL != nil {
|
||||
url = req.baseURL.Host
|
||||
if req.c.base != nil {
|
||||
url = req.c.base.Host
|
||||
}
|
||||
|
||||
// Errors can be arbitrary strings. Unbound label cardinality is not suitable for a metric
|
||||
@@ -656,18 +680,18 @@ func (r *Request) Stream() (io.ReadCloser, error) {
|
||||
req = req.WithContext(r.ctx)
|
||||
}
|
||||
req.Header = r.headers
|
||||
client := r.client
|
||||
client := r.c.Client
|
||||
if client == nil {
|
||||
client = http.DefaultClient
|
||||
}
|
||||
r.backoffMgr.Sleep(r.backoffMgr.CalculateBackoff(r.URL()))
|
||||
r.backoff.Sleep(r.backoff.CalculateBackoff(r.URL()))
|
||||
resp, err := client.Do(req)
|
||||
updateURLMetrics(r, resp, err)
|
||||
if r.baseURL != nil {
|
||||
if r.c.base != nil {
|
||||
if err != nil {
|
||||
r.backoffMgr.UpdateBackoff(r.URL(), err, 0)
|
||||
r.backoff.UpdateBackoff(r.URL(), err, 0)
|
||||
} else {
|
||||
r.backoffMgr.UpdateBackoff(r.URL(), err, resp.StatusCode)
|
||||
r.backoff.UpdateBackoff(r.URL(), err, resp.StatusCode)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
@@ -738,7 +762,7 @@ func (r *Request) request(fn func(*http.Request, *http.Response)) error {
|
||||
return err
|
||||
}
|
||||
|
||||
client := r.client
|
||||
client := r.c.Client
|
||||
if client == nil {
|
||||
client = http.DefaultClient
|
||||
}
|
||||
@@ -765,11 +789,11 @@ func (r *Request) request(fn func(*http.Request, *http.Response)) error {
|
||||
}
|
||||
req.Header = r.headers
|
||||
|
||||
r.backoffMgr.Sleep(r.backoffMgr.CalculateBackoff(r.URL()))
|
||||
r.backoff.Sleep(r.backoff.CalculateBackoff(r.URL()))
|
||||
if retries > 0 {
|
||||
// We are retrying the request that we already send to apiserver
|
||||
// at least once before.
|
||||
// This request should also be throttled with the client-internal throttler.
|
||||
// This request should also be throttled with the client-internal rate limiter.
|
||||
if err := r.tryThrottle(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -777,24 +801,29 @@ func (r *Request) request(fn func(*http.Request, *http.Response)) error {
|
||||
resp, err := client.Do(req)
|
||||
updateURLMetrics(r, resp, err)
|
||||
if err != nil {
|
||||
r.backoffMgr.UpdateBackoff(r.URL(), err, 0)
|
||||
r.backoff.UpdateBackoff(r.URL(), err, 0)
|
||||
} else {
|
||||
r.backoffMgr.UpdateBackoff(r.URL(), err, resp.StatusCode)
|
||||
r.backoff.UpdateBackoff(r.URL(), err, resp.StatusCode)
|
||||
}
|
||||
if err != nil {
|
||||
// "Connection reset by peer" is usually a transient error.
|
||||
// "Connection reset by peer", "Connection refused" or "apiserver is shutting down" are usually a transient errors.
|
||||
// Thus in case of "GET" operations, we simply retry it.
|
||||
// We are not automatically retrying "write" operations, as
|
||||
// they are not idempotent.
|
||||
if !net.IsConnectionReset(err) || r.verb != "GET" {
|
||||
if r.verb != "GET" {
|
||||
return err
|
||||
}
|
||||
// For the purpose of retry, we set the artificial "retry-after" response.
|
||||
// TODO: Should we clean the original response if it exists?
|
||||
resp = &http.Response{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
Header: http.Header{"Retry-After": []string{"1"}},
|
||||
Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
|
||||
// For connection errors and apiserver shutdown errors retry.
|
||||
if net.IsConnectionReset(err) || net.IsConnectionRefused(err) {
|
||||
// For the purpose of retry, we set the artificial "retry-after" response.
|
||||
// TODO: Should we clean the original response if it exists?
|
||||
resp = &http.Response{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
Header: http.Header{"Retry-After": []string{"1"}},
|
||||
Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -822,7 +851,7 @@ func (r *Request) request(fn func(*http.Request, *http.Response)) error {
|
||||
}
|
||||
|
||||
klog.V(4).Infof("Got a Retry-After %ds response for attempt %d to %v", seconds, retries, url)
|
||||
r.backoffMgr.Sleep(time.Duration(seconds) * time.Second)
|
||||
r.backoff.Sleep(time.Duration(seconds) * time.Second)
|
||||
return false
|
||||
}
|
||||
fn(req, resp)
|
||||
@@ -908,14 +937,18 @@ func (r *Request) transformResponse(resp *http.Response, req *http.Request) Resu
|
||||
glogBody("Response Body", body)
|
||||
|
||||
// verify the content type is accurate
|
||||
var decoder runtime.Decoder
|
||||
contentType := resp.Header.Get("Content-Type")
|
||||
decoder := r.serializers.Decoder
|
||||
if len(contentType) > 0 && (decoder == nil || (len(r.content.ContentType) > 0 && contentType != r.content.ContentType)) {
|
||||
if len(contentType) == 0 {
|
||||
contentType = r.c.content.ContentType
|
||||
}
|
||||
if len(contentType) > 0 {
|
||||
var err error
|
||||
mediaType, params, err := mime.ParseMediaType(contentType)
|
||||
if err != nil {
|
||||
return Result{err: errors.NewInternalError(err)}
|
||||
}
|
||||
decoder, err = r.serializers.RenegotiatedDecoder(mediaType, params)
|
||||
decoder, err = r.c.content.Negotiator.Decoder(mediaType, params)
|
||||
if err != nil {
|
||||
// if we fail to negotiate a decoder, treat this as an unstructured error
|
||||
switch {
|
||||
@@ -1035,7 +1068,7 @@ func (r *Request) newUnstructuredResponseError(body []byte, isTextResponse bool,
|
||||
}
|
||||
var groupResource schema.GroupResource
|
||||
if len(r.resource) > 0 {
|
||||
groupResource.Group = r.content.GroupVersion.Group
|
||||
groupResource.Group = r.c.content.GroupVersion.Group
|
||||
groupResource.Resource = r.resource
|
||||
}
|
||||
return errors.NewGenericServerResponse(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -180,7 +180,7 @@ func fakeScaleClient(t *testing.T) (ScalesGetter, []schema.GroupResource) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeaders(), Body: bytesBody(res)}, nil
|
||||
return &http.Response{StatusCode: http.StatusOK, Header: defaultHeaders(), Body: bytesBody(res)}, nil
|
||||
case "PUT":
|
||||
decoder := codecs.UniversalDeserializer()
|
||||
body, err := ioutil.ReadAll(req.Body)
|
||||
@@ -198,7 +198,7 @@ func fakeScaleClient(t *testing.T) (ScalesGetter, []schema.GroupResource) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeaders(), Body: bytesBody(res)}, nil
|
||||
return &http.Response{StatusCode: http.StatusOK, Header: defaultHeaders(), Body: bytesBody(res)}, nil
|
||||
case "PATCH":
|
||||
body, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
@@ -229,7 +229,7 @@ func fakeScaleClient(t *testing.T) (ScalesGetter, []schema.GroupResource) {
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid patch type")
|
||||
}
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeaders(), Body: bytesBody(res)}, nil
|
||||
return &http.Response{StatusCode: http.StatusOK, Header: defaultHeaders(), Body: bytesBody(res)}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected request for URL %q with method %q", req.URL.String(), req.Method)
|
||||
}
|
||||
|
||||
2
tools/cache/index.go
vendored
2
tools/cache/index.go
vendored
@@ -56,7 +56,7 @@ type Indexer interface {
|
||||
type IndexFunc func(obj interface{}) ([]string, error)
|
||||
|
||||
// IndexFuncToKeyFuncAdapter adapts an indexFunc to a keyFunc. This is only useful if your index function returns
|
||||
// unique values for every object. This is conversion can create errors when more than one key is found. You
|
||||
// unique values for every object. This conversion can create errors when more than one key is found. You
|
||||
// should prefer to make proper key and index functions.
|
||||
func IndexFuncToKeyFuncAdapter(indexFunc IndexFunc) KeyFunc {
|
||||
return func(obj interface{}) (string, error) {
|
||||
|
||||
20
tools/cache/mutation_detector.go
vendored
20
tools/cache/mutation_detector.go
vendored
@@ -48,7 +48,7 @@ func NewCacheMutationDetector(name string) MutationDetector {
|
||||
return dummyMutationDetector{}
|
||||
}
|
||||
klog.Warningln("Mutation detector is enabled, this will result in memory leakage.")
|
||||
return &defaultCacheMutationDetector{name: name, period: 1 * time.Second}
|
||||
return &defaultCacheMutationDetector{name: name, period: 1 * time.Second, retainDuration: 2 * time.Minute}
|
||||
}
|
||||
|
||||
type dummyMutationDetector struct{}
|
||||
@@ -68,6 +68,10 @@ type defaultCacheMutationDetector struct {
|
||||
lock sync.Mutex
|
||||
cachedObjs []cacheObj
|
||||
|
||||
retainDuration time.Duration
|
||||
lastRotated time.Time
|
||||
retainedCachedObjs []cacheObj
|
||||
|
||||
// failureFunc is injectable for unit testing. If you don't have it, the process will panic.
|
||||
// This panic is intentional, since turning on this detection indicates you want a strong
|
||||
// failure signal. This failure is effectively a p0 bug and you can't trust process results
|
||||
@@ -84,6 +88,14 @@ type cacheObj struct {
|
||||
func (d *defaultCacheMutationDetector) Run(stopCh <-chan struct{}) {
|
||||
// we DON'T want protection from panics. If we're running this code, we want to die
|
||||
for {
|
||||
if d.lastRotated.IsZero() {
|
||||
d.lastRotated = time.Now()
|
||||
} else if time.Now().Sub(d.lastRotated) > d.retainDuration {
|
||||
d.retainedCachedObjs = d.cachedObjs
|
||||
d.cachedObjs = nil
|
||||
d.lastRotated = time.Now()
|
||||
}
|
||||
|
||||
d.CompareObjects()
|
||||
|
||||
select {
|
||||
@@ -120,6 +132,12 @@ func (d *defaultCacheMutationDetector) CompareObjects() {
|
||||
altered = true
|
||||
}
|
||||
}
|
||||
for i, obj := range d.retainedCachedObjs {
|
||||
if !reflect.DeepEqual(obj.cached, obj.copied) {
|
||||
fmt.Printf("CACHE %s[%d] ALTERED!\n%v\n", d.name, i, diff.ObjectGoPrintSideBySide(obj.cached, obj.copied))
|
||||
altered = true
|
||||
}
|
||||
}
|
||||
|
||||
if altered {
|
||||
msg := fmt.Sprintf("cache %s modified", d.name)
|
||||
|
||||
71
tools/cache/reflector.go
vendored
71
tools/cache/reflector.go
vendored
@@ -74,6 +74,9 @@ type Reflector struct {
|
||||
// observed when doing a sync with the underlying store
|
||||
// it is thread safe, but not synchronized with the underlying store
|
||||
lastSyncResourceVersion string
|
||||
// isLastSyncResourceVersionGone is true if the previous list or watch request with lastSyncResourceVersion
|
||||
// failed with an HTTP 410 (Gone) status code.
|
||||
isLastSyncResourceVersionGone bool
|
||||
// lastSyncResourceVersionMutex guards read/write access to lastSyncResourceVersion
|
||||
lastSyncResourceVersionMutex sync.RWMutex
|
||||
// WatchListPageSize is the requested chunk size of initial and resync watch lists.
|
||||
@@ -185,10 +188,7 @@ func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error {
|
||||
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()
|
||||
// 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"}
|
||||
options := metav1.ListOptions{ResourceVersion: r.relistResourceVersion()}
|
||||
|
||||
if err := func() error {
|
||||
initTrace := trace.New("Reflector ListAndWatch", trace.Field{"name", r.name})
|
||||
@@ -211,8 +211,17 @@ func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error {
|
||||
if r.WatchListPageSize != 0 {
|
||||
pager.PageSize = r.WatchListPageSize
|
||||
}
|
||||
// Pager falls back to full list if paginated list calls fail due to an "Expired" error.
|
||||
|
||||
list, err = pager.List(context.Background(), options)
|
||||
if isExpiredError(err) {
|
||||
r.setIsLastSyncResourceVersionExpired(true)
|
||||
// Retry immediately if the resource version used to list is expired.
|
||||
// The pager already falls back to full list if paginated list calls fail due to an "Expired" error on
|
||||
// continuation pages, but the pager might not be enabled, or the full list might fail because the
|
||||
// resource version it is listing at is expired, so we need to fallback to resourceVersion="" in all
|
||||
// to recover and ensure the reflector makes forward progress.
|
||||
list, err = pager.List(context.Background(), metav1.ListOptions{ResourceVersion: r.relistResourceVersion()})
|
||||
}
|
||||
close(listCh)
|
||||
}()
|
||||
select {
|
||||
@@ -225,6 +234,7 @@ func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: Failed to list %v: %v", r.name, r.expectedTypeName, err)
|
||||
}
|
||||
r.setIsLastSyncResourceVersionExpired(false) // list was successful
|
||||
initTrace.Step("Objects listed")
|
||||
listMetaInterface, err := meta.ListAccessor(list)
|
||||
if err != nil {
|
||||
@@ -298,10 +308,13 @@ func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error {
|
||||
|
||||
w, err := r.listerWatcher.Watch(options)
|
||||
if err != nil {
|
||||
switch err {
|
||||
case io.EOF:
|
||||
switch {
|
||||
case isExpiredError(err):
|
||||
r.setIsLastSyncResourceVersionExpired(true)
|
||||
klog.V(4).Infof("%s: watch of %v closed with: %v", r.name, r.expectedTypeName, err)
|
||||
case err == io.EOF:
|
||||
// watch closed normally
|
||||
case io.ErrUnexpectedEOF:
|
||||
case err == io.ErrUnexpectedEOF:
|
||||
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.expectedTypeName, err))
|
||||
@@ -320,7 +333,8 @@ func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error {
|
||||
if err := r.watchHandler(w, &resourceVersion, resyncerrc, stopCh); err != nil {
|
||||
if err != errorStopRequested {
|
||||
switch {
|
||||
case apierrs.IsResourceExpired(err):
|
||||
case isExpiredError(err):
|
||||
r.setIsLastSyncResourceVersionExpired(true)
|
||||
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.expectedTypeName, err)
|
||||
@@ -432,3 +446,42 @@ func (r *Reflector) setLastSyncResourceVersion(v string) {
|
||||
defer r.lastSyncResourceVersionMutex.Unlock()
|
||||
r.lastSyncResourceVersion = v
|
||||
}
|
||||
|
||||
// relistResourceVersion determines the resource version the reflector should list or relist from.
|
||||
// Returns either the lastSyncResourceVersion so that this reflector will relist with a resource
|
||||
// versions no older than has already been observed in relist results or watch events, or, if the last relist resulted
|
||||
// in an HTTP 410 (Gone) status code, returns "" so that the relist will use the latest resource version available in
|
||||
// etcd via a quorum read.
|
||||
func (r *Reflector) relistResourceVersion() string {
|
||||
r.lastSyncResourceVersionMutex.RLock()
|
||||
defer r.lastSyncResourceVersionMutex.RUnlock()
|
||||
|
||||
if r.isLastSyncResourceVersionGone {
|
||||
// Since this reflector makes paginated list requests, and all paginated list requests skip the watch cache
|
||||
// if the lastSyncResourceVersion is expired, we set ResourceVersion="" and list again to re-establish reflector
|
||||
// to the latest available ResourceVersion, using a consistent read from etcd.
|
||||
return ""
|
||||
}
|
||||
if r.lastSyncResourceVersion == "" {
|
||||
// For performance reasons, initial list performed by reflector uses "0" as resource version to allow it to
|
||||
// be served from the watch cache if it is enabled.
|
||||
return "0"
|
||||
}
|
||||
return r.lastSyncResourceVersion
|
||||
}
|
||||
|
||||
// setIsLastSyncResourceVersionExpired sets if the last list or watch request with lastSyncResourceVersion returned a
|
||||
// expired error: HTTP 410 (Gone) Status Code.
|
||||
func (r *Reflector) setIsLastSyncResourceVersionExpired(isExpired bool) {
|
||||
r.lastSyncResourceVersionMutex.Lock()
|
||||
defer r.lastSyncResourceVersionMutex.Unlock()
|
||||
r.isLastSyncResourceVersionGone = isExpired
|
||||
}
|
||||
|
||||
func isExpiredError(err error) bool {
|
||||
// In Kubernetes 1.17 and earlier, the api server returns both apierrs.StatusReasonExpired and
|
||||
// apierrs.StatusReasonGone for HTTP 410 (Gone) status code responses. In 1.18 the kube server is more consistent
|
||||
// and always returns apierrs.StatusReasonExpired. For backward compatibility we can only remove the apierrs.IsGone
|
||||
// check when we fully drop support for Kubernetes 1.17 servers from reflectors.
|
||||
return apierrs.IsResourceExpired(err) || apierrs.IsGone(err)
|
||||
}
|
||||
|
||||
192
tools/cache/reflector_test.go
vendored
192
tools/cache/reflector_test.go
vendored
@@ -26,6 +26,7 @@ import (
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@@ -434,6 +435,197 @@ func TestReflectorWatchListPageSize(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestReflectorResyncWithResourceVersion ensures that a reflector keeps track of the ResourceVersion and sends
|
||||
// it in relist requests to prevent the reflector from traveling back in time if the relist is to a api-server or
|
||||
// etcd that is partitioned and serving older data than the reflector has already processed.
|
||||
func TestReflectorResyncWithResourceVersion(t *testing.T) {
|
||||
stopCh := make(chan struct{})
|
||||
s := NewStore(MetaNamespaceKeyFunc)
|
||||
listCallRVs := []string{}
|
||||
|
||||
lw := &testLW{
|
||||
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
|
||||
// Stop once the reflector begins watching since we're only interested in the list.
|
||||
close(stopCh)
|
||||
fw := watch.NewFake()
|
||||
return fw, nil
|
||||
},
|
||||
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
|
||||
listCallRVs = append(listCallRVs, options.ResourceVersion)
|
||||
pods := make([]v1.Pod, 8)
|
||||
for i := 0; i < 8; i++ {
|
||||
pods[i] = v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("pod-%d", i), ResourceVersion: fmt.Sprintf("%d", i)}}
|
||||
}
|
||||
switch options.ResourceVersion {
|
||||
case "0":
|
||||
return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "10"}, Items: pods[0:4]}, nil
|
||||
case "10":
|
||||
return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "11"}, Items: pods[0:8]}, nil
|
||||
default:
|
||||
t.Fatalf("Unrecognized ResourceVersion: %s", options.ResourceVersion)
|
||||
}
|
||||
return nil, nil
|
||||
},
|
||||
}
|
||||
r := NewReflector(lw, &v1.Pod{}, s, 0)
|
||||
|
||||
// Initial list should use RV=0
|
||||
r.ListAndWatch(stopCh)
|
||||
|
||||
results := s.List()
|
||||
if len(results) != 4 {
|
||||
t.Errorf("Expected 4 results, got %d", len(results))
|
||||
}
|
||||
|
||||
// relist should use lastSyncResourceVersions (RV=10)
|
||||
stopCh = make(chan struct{})
|
||||
r.ListAndWatch(stopCh)
|
||||
|
||||
results = s.List()
|
||||
if len(results) != 8 {
|
||||
t.Errorf("Expected 8 results, got %d", len(results))
|
||||
}
|
||||
|
||||
expectedRVs := []string{"0", "10"}
|
||||
if !reflect.DeepEqual(listCallRVs, expectedRVs) {
|
||||
t.Errorf("Expected series of list calls with resource versiosn of %v but got: %v", expectedRVs, listCallRVs)
|
||||
}
|
||||
}
|
||||
|
||||
// TestReflectorExpiredExactResourceVersion tests that a reflector handles the behavior of kubernetes 1.16 an earlier
|
||||
// where if the exact ResourceVersion requested is not available for a List request for a non-zero ResourceVersion,
|
||||
// an "Expired" error is returned if the ResourceVersion has expired (etcd has compacted it).
|
||||
// (In kubernetes 1.17, or when the watch cache is enabled, the List will instead return the list that is no older than
|
||||
// the requested ResourceVersion).
|
||||
func TestReflectorExpiredExactResourceVersion(t *testing.T) {
|
||||
stopCh := make(chan struct{})
|
||||
s := NewStore(MetaNamespaceKeyFunc)
|
||||
listCallRVs := []string{}
|
||||
|
||||
lw := &testLW{
|
||||
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
|
||||
// Stop once the reflector begins watching since we're only interested in the list.
|
||||
close(stopCh)
|
||||
fw := watch.NewFake()
|
||||
return fw, nil
|
||||
},
|
||||
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
|
||||
listCallRVs = append(listCallRVs, options.ResourceVersion)
|
||||
pods := make([]v1.Pod, 8)
|
||||
for i := 0; i < 8; i++ {
|
||||
pods[i] = v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("pod-%d", i), ResourceVersion: fmt.Sprintf("%d", i)}}
|
||||
}
|
||||
switch options.ResourceVersion {
|
||||
case "0":
|
||||
return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "10"}, Items: pods[0:4]}, nil
|
||||
case "10":
|
||||
// When watch cache is disabled, if the exact ResourceVersion requested is not available, a "Expired" error is returned.
|
||||
return nil, apierrs.NewResourceExpired("The resourceVersion for the provided watch is too old.")
|
||||
case "":
|
||||
return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "11"}, Items: pods[0:8]}, nil
|
||||
default:
|
||||
t.Fatalf("Unrecognized ResourceVersion: %s", options.ResourceVersion)
|
||||
}
|
||||
return nil, nil
|
||||
},
|
||||
}
|
||||
r := NewReflector(lw, &v1.Pod{}, s, 0)
|
||||
|
||||
// Initial list should use RV=0
|
||||
r.ListAndWatch(stopCh)
|
||||
|
||||
results := s.List()
|
||||
if len(results) != 4 {
|
||||
t.Errorf("Expected 4 results, got %d", len(results))
|
||||
}
|
||||
|
||||
// relist should use lastSyncResourceVersions (RV=10) and since RV=10 is expired, it should retry with RV="".
|
||||
stopCh = make(chan struct{})
|
||||
r.ListAndWatch(stopCh)
|
||||
|
||||
results = s.List()
|
||||
if len(results) != 8 {
|
||||
t.Errorf("Expected 8 results, got %d", len(results))
|
||||
}
|
||||
|
||||
expectedRVs := []string{"0", "10", ""}
|
||||
if !reflect.DeepEqual(listCallRVs, expectedRVs) {
|
||||
t.Errorf("Expected series of list calls with resource versiosn of %v but got: %v", expectedRVs, listCallRVs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReflectorFullListIfExpired(t *testing.T) {
|
||||
stopCh := make(chan struct{})
|
||||
s := NewStore(MetaNamespaceKeyFunc)
|
||||
listCallRVs := []string{}
|
||||
|
||||
lw := &testLW{
|
||||
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
|
||||
// Stop once the reflector begins watching since we're only interested in the list.
|
||||
close(stopCh)
|
||||
fw := watch.NewFake()
|
||||
return fw, nil
|
||||
},
|
||||
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
|
||||
listCallRVs = append(listCallRVs, options.ResourceVersion)
|
||||
pods := make([]v1.Pod, 8)
|
||||
for i := 0; i < 8; i++ {
|
||||
pods[i] = v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("pod-%d", i), ResourceVersion: fmt.Sprintf("%d", i)}}
|
||||
}
|
||||
rvContinueLimit := func(rv, c string, l int64) metav1.ListOptions {
|
||||
return metav1.ListOptions{ResourceVersion: rv, Continue: c, Limit: l}
|
||||
}
|
||||
switch rvContinueLimit(options.ResourceVersion, options.Continue, options.Limit) {
|
||||
// initial limited list
|
||||
case rvContinueLimit("0", "", 4):
|
||||
return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "10"}, Items: pods[0:4]}, nil
|
||||
// first page of the rv=10 list
|
||||
case rvContinueLimit("10", "", 4):
|
||||
return &v1.PodList{ListMeta: metav1.ListMeta{Continue: "C1", ResourceVersion: "11"}, Items: pods[0:4]}, nil
|
||||
// second page of the above list
|
||||
case rvContinueLimit("", "C1", 4):
|
||||
return nil, apierrs.NewResourceExpired("The resourceVersion for the provided watch is too old.")
|
||||
// rv=10 unlimited list
|
||||
case rvContinueLimit("10", "", 0):
|
||||
return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "11"}, Items: pods[0:8]}, nil
|
||||
default:
|
||||
err := fmt.Errorf("unexpected list options: %#v", options)
|
||||
t.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
return nil, nil
|
||||
},
|
||||
}
|
||||
r := NewReflector(lw, &v1.Pod{}, s, 0)
|
||||
r.WatchListPageSize = 4
|
||||
|
||||
// Initial list should use RV=0
|
||||
if err := r.ListAndWatch(stopCh); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
results := s.List()
|
||||
if len(results) != 4 {
|
||||
t.Errorf("Expected 4 results, got %d", len(results))
|
||||
}
|
||||
|
||||
// relist should use lastSyncResourceVersions (RV=10) and since second page of that expired, it should full list with RV=10
|
||||
stopCh = make(chan struct{})
|
||||
if err := r.ListAndWatch(stopCh); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
results = s.List()
|
||||
if len(results) != 8 {
|
||||
t.Errorf("Expected 8 results, got %d", len(results))
|
||||
}
|
||||
|
||||
expectedRVs := []string{"0", "10", "", "10"}
|
||||
if !reflect.DeepEqual(listCallRVs, expectedRVs) {
|
||||
t.Errorf("Expected series of list calls with resource versiosn of %#v but got: %#v", expectedRVs, listCallRVs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReflectorSetExpectedType(t *testing.T) {
|
||||
obj := &unstructured.Unstructured{}
|
||||
gvk := schema.GroupVersionKind{
|
||||
|
||||
7
tools/cache/thread_safe_store.go
vendored
7
tools/cache/thread_safe_store.go
vendored
@@ -292,6 +292,13 @@ func (c *threadSafeMap) deleteFromIndices(obj interface{}, key string) {
|
||||
set := index[indexValue]
|
||||
if set != nil {
|
||||
set.Delete(key)
|
||||
|
||||
// If we don't delete the set when zero, indices with high cardinality
|
||||
// short lived resources can cause memory to increase over time from
|
||||
// unused empty sets. See `kubernetes/kubernetes/issues/84959`.
|
||||
if len(set) == 0 {
|
||||
delete(index, indexValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
92
tools/cache/thread_safe_store_test.go
vendored
Normal file
92
tools/cache/thread_safe_store_test.go
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
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 cache
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestThreadSafeStoreDeleteRemovesEmptySetsFromIndex(t *testing.T) {
|
||||
testIndexer := "testIndexer"
|
||||
|
||||
indexers := Indexers{
|
||||
testIndexer: func(obj interface{}) (strings []string, e error) {
|
||||
indexes := []string{obj.(string)}
|
||||
return indexes, nil
|
||||
},
|
||||
}
|
||||
|
||||
indices := Indices{}
|
||||
store := NewThreadSafeStore(indexers, indices).(*threadSafeMap)
|
||||
|
||||
testKey := "testKey"
|
||||
|
||||
store.Add(testKey, testKey)
|
||||
|
||||
// Assumption check, there should be a set for the `testKey` with one element in the added index
|
||||
set := store.indices[testIndexer][testKey]
|
||||
|
||||
if len(set) != 1 {
|
||||
t.Errorf("Initial assumption of index backing string set having 1 element failed. Actual elements: %d", len(set))
|
||||
return
|
||||
}
|
||||
|
||||
store.Delete(testKey)
|
||||
set, present := store.indices[testIndexer][testKey]
|
||||
|
||||
if present {
|
||||
t.Errorf("Index backing string set not deleted from index. Set length: %d", len(set))
|
||||
}
|
||||
}
|
||||
|
||||
func TestThreadSafeStoreAddKeepsNonEmptySetPostDeleteFromIndex(t *testing.T) {
|
||||
testIndexer := "testIndexer"
|
||||
testIndex := "testIndex"
|
||||
|
||||
indexers := Indexers{
|
||||
testIndexer: func(obj interface{}) (strings []string, e error) {
|
||||
indexes := []string{testIndex}
|
||||
return indexes, nil
|
||||
},
|
||||
}
|
||||
|
||||
indices := Indices{}
|
||||
store := NewThreadSafeStore(indexers, indices).(*threadSafeMap)
|
||||
|
||||
store.Add("retain", "retain")
|
||||
store.Add("delete", "delete")
|
||||
|
||||
// Assumption check, there should be a set for the `testIndex` with two elements
|
||||
set := store.indices[testIndexer][testIndex]
|
||||
|
||||
if len(set) != 2 {
|
||||
t.Errorf("Initial assumption of index backing string set having 2 elements failed. Actual elements: %d", len(set))
|
||||
return
|
||||
}
|
||||
|
||||
store.Delete("delete")
|
||||
set, present := store.indices[testIndexer][testIndex]
|
||||
|
||||
if !present {
|
||||
t.Errorf("Index backing string set erroneously deleted from index.")
|
||||
return
|
||||
}
|
||||
|
||||
if len(set) != 1 {
|
||||
t.Errorf("Index backing string set has incorrect length, expect 1. Set length: %d", len(set))
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package clientcmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@@ -29,6 +30,7 @@ import (
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
clientcmdlatest "k8s.io/client-go/tools/clientcmd/api/latest"
|
||||
)
|
||||
@@ -175,6 +177,56 @@ func TestConflictingCurrentContext(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeYAML(t *testing.T) {
|
||||
config := clientcmdapi.Config{
|
||||
CurrentContext: "any-context-value",
|
||||
Contexts: map[string]*clientcmdapi.Context{
|
||||
"433e40": {
|
||||
Cluster: "433e40",
|
||||
},
|
||||
},
|
||||
Clusters: map[string]*clientcmdapi.Cluster{
|
||||
"0": {
|
||||
Server: "https://localhost:1234",
|
||||
},
|
||||
"1": {
|
||||
Server: "https://localhost:1234",
|
||||
},
|
||||
"433e40": {
|
||||
Server: "https://localhost:1234",
|
||||
},
|
||||
},
|
||||
}
|
||||
data, err := Write(config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expected := []byte(`apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
server: https://localhost:1234
|
||||
name: "0"
|
||||
- cluster:
|
||||
server: https://localhost:1234
|
||||
name: "1"
|
||||
- cluster:
|
||||
server: https://localhost:1234
|
||||
name: "433e40"
|
||||
contexts:
|
||||
- context:
|
||||
cluster: "433e40"
|
||||
user: ""
|
||||
name: "433e40"
|
||||
current-context: any-context-value
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users: null
|
||||
`)
|
||||
if !bytes.Equal(expected, data) {
|
||||
t.Error(diff.ObjectReflectDiff(string(expected), string(data)))
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadingEmptyMaps(t *testing.T) {
|
||||
configFile, _ := ioutil.TempFile("", "")
|
||||
defer os.Remove(configFile.Name())
|
||||
|
||||
19
tools/events/doc.go
Normal file
19
tools/events/doc.go
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
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 events has all client logic for recording and reporting
|
||||
// "k8s.io/api/events/v1beta1".Event events.
|
||||
package events // import "k8s.io/client-go/tools/events"
|
||||
@@ -37,26 +37,27 @@ import (
|
||||
"k8s.io/client-go/tools/record"
|
||||
)
|
||||
|
||||
func createLockObject(t *testing.T, 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,
|
||||
}
|
||||
if record != nil {
|
||||
recordBytes, _ := json.Marshal(record)
|
||||
objectMeta.Annotations = map[string]string{
|
||||
rl.LeaderElectionRecordAnnotationKey: string(recordBytes),
|
||||
}
|
||||
}
|
||||
switch objectType {
|
||||
case "endpoints":
|
||||
recordBytes, _ := json.Marshal(record)
|
||||
objectMeta.Annotations = map[string]string{
|
||||
rl.LeaderElectionRecordAnnotationKey: string(recordBytes),
|
||||
}
|
||||
obj = &corev1.Endpoints{ObjectMeta: objectMeta}
|
||||
case "configmaps":
|
||||
recordBytes, _ := json.Marshal(record)
|
||||
objectMeta.Annotations = map[string]string{
|
||||
rl.LeaderElectionRecordAnnotationKey: string(recordBytes),
|
||||
}
|
||||
obj = &corev1.ConfigMap{ObjectMeta: objectMeta}
|
||||
case "leases":
|
||||
spec := rl.LeaderElectionRecordToLeaseSpec(&record)
|
||||
var spec coordinationv1.LeaseSpec
|
||||
if record != nil {
|
||||
spec = rl.LeaderElectionRecordToLeaseSpec(record)
|
||||
}
|
||||
obj = &coordinationv1.Lease{ObjectMeta: objectMeta, Spec: spec}
|
||||
default:
|
||||
t.Fatal("unexpected objType:" + objectType)
|
||||
@@ -108,13 +109,33 @@ func testTryAcquireOrRenew(t *testing.T, objectType string) {
|
||||
expectSuccess: true,
|
||||
outHolder: "baz",
|
||||
},
|
||||
{
|
||||
name: "acquire from object without annotations",
|
||||
reactors: []Reactor{
|
||||
{
|
||||
verb: "get",
|
||||
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
|
||||
return true, createLockObject(t, objectType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), nil), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
verb: "update",
|
||||
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 object",
|
||||
reactors: []Reactor{
|
||||
{
|
||||
verb: "get",
|
||||
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
|
||||
return true, createLockObject(t, objectType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), rl.LeaderElectionRecord{}), nil
|
||||
return true, createLockObject(t, objectType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{}), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -135,7 +156,7 @@ func testTryAcquireOrRenew(t *testing.T, objectType string) {
|
||||
{
|
||||
verb: "get",
|
||||
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
|
||||
return true, createLockObject(t, 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
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -158,7 +179,7 @@ func testTryAcquireOrRenew(t *testing.T, objectType string) {
|
||||
{
|
||||
verb: "get",
|
||||
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
|
||||
return true, createLockObject(t, 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
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -180,7 +201,7 @@ func testTryAcquireOrRenew(t *testing.T, objectType string) {
|
||||
{
|
||||
verb: "get",
|
||||
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
|
||||
return true, createLockObject(t, 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
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -195,7 +216,7 @@ func testTryAcquireOrRenew(t *testing.T, objectType string) {
|
||||
{
|
||||
verb: "get",
|
||||
reaction: func(action fakeclient.Action) (handled bool, ret runtime.Object, err error) {
|
||||
return true, createLockObject(t, 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
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -421,7 +442,7 @@ func testTryAcquireOrRenewMultiLock(t *testing.T, objectType string) {
|
||||
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
|
||||
return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{}), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -464,14 +485,14 @@ func testTryAcquireOrRenewMultiLock(t *testing.T, objectType string) {
|
||||
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
|
||||
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
|
||||
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{}), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -485,7 +506,7 @@ func testTryAcquireOrRenewMultiLock(t *testing.T, objectType string) {
|
||||
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
|
||||
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{}), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -507,7 +528,7 @@ func testTryAcquireOrRenewMultiLock(t *testing.T, objectType string) {
|
||||
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
|
||||
return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -528,7 +549,7 @@ func testTryAcquireOrRenewMultiLock(t *testing.T, objectType string) {
|
||||
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
|
||||
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -554,14 +575,14 @@ func testTryAcquireOrRenewMultiLock(t *testing.T, objectType string) {
|
||||
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
|
||||
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
|
||||
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -575,7 +596,7 @@ func testTryAcquireOrRenewMultiLock(t *testing.T, objectType string) {
|
||||
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
|
||||
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -601,14 +622,14 @@ func testTryAcquireOrRenewMultiLock(t *testing.T, objectType string) {
|
||||
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
|
||||
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
|
||||
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "baz"}), nil
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -626,14 +647,14 @@ func testTryAcquireOrRenewMultiLock(t *testing.T, objectType string) {
|
||||
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
|
||||
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
|
||||
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: rl.UnknownLeader}), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -647,7 +668,7 @@ func testTryAcquireOrRenewMultiLock(t *testing.T, objectType string) {
|
||||
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
|
||||
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: rl.UnknownLeader}), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -673,7 +694,7 @@ func testTryAcquireOrRenewMultiLock(t *testing.T, objectType string) {
|
||||
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
|
||||
return true, createLockObject(t, primaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -698,14 +719,14 @@ func testTryAcquireOrRenewMultiLock(t *testing.T, objectType string) {
|
||||
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
|
||||
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
|
||||
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -723,14 +744,14 @@ func testTryAcquireOrRenewMultiLock(t *testing.T, objectType string) {
|
||||
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
|
||||
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
|
||||
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "bing"}), nil
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -748,14 +769,14 @@ func testTryAcquireOrRenewMultiLock(t *testing.T, objectType string) {
|
||||
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
|
||||
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
|
||||
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "baz"}), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -769,7 +790,7 @@ func testTryAcquireOrRenewMultiLock(t *testing.T, objectType string) {
|
||||
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
|
||||
return true, createLockObject(t, secondaryType, action.GetNamespace(), action.(fakeclient.GetAction).GetName(), &rl.LeaderElectionRecord{HolderIdentity: "baz"}), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -82,6 +82,9 @@ func (el *EndpointsLock) Update(ler LeaderElectionRecord) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if el.e.Annotations == nil {
|
||||
el.e.Annotations = make(map[string]string)
|
||||
}
|
||||
el.e.Annotations[LeaderElectionRecordAnnotationKey] = string(recordBytes)
|
||||
el.e, err = el.Client.Endpoints(el.EndpointsMeta.Namespace).Update(el.e)
|
||||
return err
|
||||
|
||||
@@ -96,25 +96,24 @@ func (ll *LeaseLock) Identity() string {
|
||||
}
|
||||
|
||||
func LeaseSpecToLeaderElectionRecord(spec *coordinationv1.LeaseSpec) *LeaderElectionRecord {
|
||||
holderIdentity := ""
|
||||
var r LeaderElectionRecord
|
||||
if spec.HolderIdentity != nil {
|
||||
holderIdentity = *spec.HolderIdentity
|
||||
r.HolderIdentity = *spec.HolderIdentity
|
||||
}
|
||||
leaseDurationSeconds := 0
|
||||
if spec.LeaseDurationSeconds != nil {
|
||||
leaseDurationSeconds = int(*spec.LeaseDurationSeconds)
|
||||
r.LeaseDurationSeconds = int(*spec.LeaseDurationSeconds)
|
||||
}
|
||||
leaseTransitions := 0
|
||||
if spec.LeaseTransitions != nil {
|
||||
leaseTransitions = int(*spec.LeaseTransitions)
|
||||
r.LeaderTransitions = int(*spec.LeaseTransitions)
|
||||
}
|
||||
return &LeaderElectionRecord{
|
||||
HolderIdentity: holderIdentity,
|
||||
LeaseDurationSeconds: leaseDurationSeconds,
|
||||
AcquireTime: metav1.Time{spec.AcquireTime.Time},
|
||||
RenewTime: metav1.Time{spec.RenewTime.Time},
|
||||
LeaderTransitions: leaseTransitions,
|
||||
if spec.AcquireTime != nil {
|
||||
r.AcquireTime = metav1.Time{spec.AcquireTime.Time}
|
||||
}
|
||||
if spec.RenewTime != nil {
|
||||
r.RenewTime = metav1.Time{spec.RenewTime.Time}
|
||||
}
|
||||
return &r
|
||||
|
||||
}
|
||||
|
||||
func LeaderElectionRecordToLeaseSpec(ler *LeaderElectionRecord) coordinationv1.LeaseSpec {
|
||||
|
||||
@@ -26,6 +26,16 @@ import (
|
||||
|
||||
var registerMetrics sync.Once
|
||||
|
||||
// DurationMetric is a measurement of some amount of time.
|
||||
type DurationMetric interface {
|
||||
Observe(duration time.Duration)
|
||||
}
|
||||
|
||||
// ExpiryMetric sets some time of expiry. If nil, assume not relevant.
|
||||
type ExpiryMetric interface {
|
||||
Set(expiry *time.Time)
|
||||
}
|
||||
|
||||
// LatencyMetric observes client latency partitioned by verb and url.
|
||||
type LatencyMetric interface {
|
||||
Observe(verb string, u url.URL, latency time.Duration)
|
||||
@@ -37,21 +47,51 @@ type ResultMetric interface {
|
||||
}
|
||||
|
||||
var (
|
||||
// ClientCertExpiry is the expiry time of a client certificate
|
||||
ClientCertExpiry ExpiryMetric = noopExpiry{}
|
||||
// ClientCertRotationAge is the age of a certificate that has just been rotated.
|
||||
ClientCertRotationAge DurationMetric = noopDuration{}
|
||||
// RequestLatency is the latency metric that rest clients will update.
|
||||
RequestLatency LatencyMetric = noopLatency{}
|
||||
// RequestResult is the result metric that rest clients will update.
|
||||
RequestResult ResultMetric = noopResult{}
|
||||
)
|
||||
|
||||
// RegisterOpts contains all the metrics to register. Metrics may be nil.
|
||||
type RegisterOpts struct {
|
||||
ClientCertExpiry ExpiryMetric
|
||||
ClientCertRotationAge DurationMetric
|
||||
RequestLatency LatencyMetric
|
||||
RequestResult ResultMetric
|
||||
}
|
||||
|
||||
// Register registers metrics for the rest client to use. This can
|
||||
// only be called once.
|
||||
func Register(lm LatencyMetric, rm ResultMetric) {
|
||||
func Register(opts RegisterOpts) {
|
||||
registerMetrics.Do(func() {
|
||||
RequestLatency = lm
|
||||
RequestResult = rm
|
||||
if opts.ClientCertExpiry != nil {
|
||||
ClientCertExpiry = opts.ClientCertExpiry
|
||||
}
|
||||
if opts.ClientCertRotationAge != nil {
|
||||
ClientCertRotationAge = opts.ClientCertRotationAge
|
||||
}
|
||||
if opts.RequestLatency != nil {
|
||||
RequestLatency = opts.RequestLatency
|
||||
}
|
||||
if opts.RequestResult != nil {
|
||||
RequestResult = opts.RequestResult
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type noopDuration struct{}
|
||||
|
||||
func (noopDuration) Observe(time.Duration) {}
|
||||
|
||||
type noopExpiry struct{}
|
||||
|
||||
func (noopExpiry) Set(*time.Time) {}
|
||||
|
||||
type noopLatency struct{}
|
||||
|
||||
func (noopLatency) Observe(string, url.URL, time.Duration) {}
|
||||
|
||||
@@ -77,6 +77,7 @@ func (p *ListPager) List(ctx context.Context, options metav1.ListOptions) (runti
|
||||
if options.Limit == 0 {
|
||||
options.Limit = p.PageSize
|
||||
}
|
||||
requestedResourceVersion := options.ResourceVersion
|
||||
var list *metainternalversion.List
|
||||
for {
|
||||
select {
|
||||
@@ -87,12 +88,18 @@ func (p *ListPager) List(ctx context.Context, options metav1.ListOptions) (runti
|
||||
|
||||
obj, err := p.PageFn(ctx, options)
|
||||
if err != nil {
|
||||
if !errors.IsResourceExpired(err) || !p.FullListIfExpired {
|
||||
// Only fallback to full list if an "Expired" errors is returned, FullListIfExpired is true, and
|
||||
// the "Expired" error occurred in page 2 or later (since full list is intended to prevent a pager.List from
|
||||
// failing when the resource versions is established by the first page request falls out of the compaction
|
||||
// during the subsequent list requests).
|
||||
if !errors.IsResourceExpired(err) || !p.FullListIfExpired || options.Continue == "" {
|
||||
return nil, err
|
||||
}
|
||||
// the list expired while we were processing, fall back to a full list
|
||||
// the list expired while we were processing, fall back to a full list at
|
||||
// the requested ResourceVersion.
|
||||
options.Limit = 0
|
||||
options.Continue = ""
|
||||
options.ResourceVersion = requestedResourceVersion
|
||||
return p.PageFn(ctx, options)
|
||||
}
|
||||
m, err := meta.ListAccessor(obj)
|
||||
@@ -125,6 +132,10 @@ func (p *ListPager) List(ctx context.Context, options metav1.ListOptions) (runti
|
||||
|
||||
// set the next loop up
|
||||
options.Continue = m.GetContinue()
|
||||
// Clear the ResourceVersion on the subsequent List calls to avoid the
|
||||
// `specifying resource version is not allowed when using continue` error.
|
||||
// See https://github.com/kubernetes/kubernetes/issues/85221#issuecomment-553748143.
|
||||
options.ResourceVersion = ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,10 @@ func (p *testPager) PagedList(ctx context.Context, options metav1.ListOptions) (
|
||||
p.t.Errorf("invariant violated, expected limit %d and continue %s, got %#v", p.expectPage, expectedContinue, options)
|
||||
return nil, fmt.Errorf("invariant violated")
|
||||
}
|
||||
if options.Continue != "" && options.ResourceVersion != "" {
|
||||
p.t.Errorf("invariant violated, specifying resource version (%s) is not allowed when using continue (%s).", options.ResourceVersion, options.Continue)
|
||||
return nil, fmt.Errorf("invariant violated")
|
||||
}
|
||||
var list metainternalversion.List
|
||||
total := options.Limit
|
||||
if total == 0 {
|
||||
@@ -181,6 +185,12 @@ func TestListPager_List(t *testing.T) {
|
||||
args: args{},
|
||||
want: list(21, "rv:20"),
|
||||
},
|
||||
{
|
||||
name: "two pages with resourceVersion",
|
||||
fields: fields{PageSize: 10, PageFn: (&testPager{t: t, expectPage: 10, remaining: 11, rv: "rv:20"}).PagedList},
|
||||
args: args{options: metav1.ListOptions{ResourceVersion: "rv:10"}},
|
||||
want: list(11, "rv:20"),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -14,5 +14,6 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package record has all client logic for recording and reporting events.
|
||||
// Package record has all client logic for recording and reporting
|
||||
// "k8s.io/api/core/v1".Event events.
|
||||
package record // import "k8s.io/client-go/tools/record"
|
||||
|
||||
@@ -132,14 +132,14 @@ type EventBroadcaster interface {
|
||||
Shutdown()
|
||||
}
|
||||
|
||||
// EventRecorderAdapter is a wrapper around EventRecorder implementing the
|
||||
// new EventRecorder interface.
|
||||
// EventRecorderAdapter is a wrapper around a "k8s.io/client-go/tools/record".EventRecorder
|
||||
// implementing the new "k8s.io/client-go/tools/events".EventRecorder interface.
|
||||
type EventRecorderAdapter struct {
|
||||
recorder EventRecorder
|
||||
}
|
||||
|
||||
// NewEventRecorderAdapter returns an adapter implementing new EventRecorder
|
||||
// interface.
|
||||
// NewEventRecorderAdapter returns an adapter implementing the new
|
||||
// "k8s.io/client-go/tools/events".EventRecorder interface.
|
||||
func NewEventRecorderAdapter(recorder EventRecorder) *EventRecorderAdapter {
|
||||
return &EventRecorderAdapter{
|
||||
recorder: recorder,
|
||||
|
||||
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package cert
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
@@ -59,3 +60,14 @@ func ParseCertsPEM(pemCerts []byte) ([]*x509.Certificate, error) {
|
||||
}
|
||||
return certs, nil
|
||||
}
|
||||
|
||||
// EncodeCertificates returns the PEM-encoded byte array that represents by the specified certs.
|
||||
func EncodeCertificates(certs ...*x509.Certificate) ([]byte, error) {
|
||||
b := bytes.Buffer{}
|
||||
for _, cert := range certs {
|
||||
if err := pem.Encode(&b, &pem.Block{Type: CertificateBlockType, Bytes: cert.Raw}); err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
}
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
102
util/cert/server_inspection.go
Normal file
102
util/cert/server_inspection.go
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
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 cert
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GetClientCANames gets the CA names for client certs that a server accepts. This is useful when inspecting the
|
||||
// state of particular servers. apiHost is "host:port"
|
||||
func GetClientCANames(apiHost string) ([]string, error) {
|
||||
// when we run this the second time, we know which one we are expecting
|
||||
acceptableCAs := []string{}
|
||||
tlsConfig := &tls.Config{
|
||||
InsecureSkipVerify: true, // this is insecure to always get to the GetClientCertificate
|
||||
GetClientCertificate: func(hello *tls.CertificateRequestInfo) (*tls.Certificate, error) {
|
||||
acceptableCAs = []string{}
|
||||
for _, curr := range hello.AcceptableCAs {
|
||||
acceptableCAs = append(acceptableCAs, string(curr))
|
||||
}
|
||||
return &tls.Certificate{}, nil
|
||||
},
|
||||
}
|
||||
|
||||
conn, err := tls.Dial("tcp", apiHost, tlsConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := conn.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return acceptableCAs, nil
|
||||
}
|
||||
|
||||
// GetClientCANamesForURL is GetClientCANames against a URL string like we use in kubeconfigs
|
||||
func GetClientCANamesForURL(kubeConfigURL string) ([]string, error) {
|
||||
apiserverURL, err := url.Parse(kubeConfigURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return GetClientCANames(apiserverURL.Host)
|
||||
}
|
||||
|
||||
// GetServingCertificates returns the x509 certs used by a server as certificates and pem encoded bytes.
|
||||
// The serverName is optional for specifying a different name to get SNI certificates. apiHost is "host:port"
|
||||
func GetServingCertificates(apiHost, serverName string) ([]*x509.Certificate, [][]byte, error) {
|
||||
tlsConfig := &tls.Config{
|
||||
InsecureSkipVerify: true, // this is insecure so that we always get connected
|
||||
}
|
||||
// if a name is specified for SNI, set it.
|
||||
if len(serverName) > 0 {
|
||||
tlsConfig.ServerName = serverName
|
||||
}
|
||||
|
||||
conn, err := tls.Dial("tcp", apiHost, tlsConfig)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err = conn.Close(); err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to close connection : %v", err)
|
||||
}
|
||||
|
||||
peerCerts := conn.ConnectionState().PeerCertificates
|
||||
peerCertBytes := [][]byte{}
|
||||
for _, a := range peerCerts {
|
||||
actualCert, err := EncodeCertificates(a)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
peerCertBytes = append(peerCertBytes, []byte(strings.TrimSpace(string(actualCert))))
|
||||
}
|
||||
|
||||
return peerCerts, peerCertBytes, err
|
||||
}
|
||||
|
||||
// GetServingCertificatesForURL is GetServingCertificates against a URL string like we use in kubeconfigs
|
||||
func GetServingCertificatesForURL(kubeConfigURL, serverName string) ([]*x509.Certificate, [][]byte, error) {
|
||||
apiserverURL, err := url.Parse(kubeConfigURL)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return GetServingCertificates(apiserverURL.Host, serverName)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user