├── .github
└── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── OWNERS
├── README.md
├── SECURITY_CONTACTS
├── artifacts
└── examples
│ ├── crd-status-subresource.yaml
│ ├── crd.yaml
│ └── example-foo.yaml
├── code-of-conduct.md
├── controller.go
├── controller_test.go
├── docs
├── controller-client-go.md
└── images
│ └── client-go-controller-interaction.jpeg
├── go.mod
├── go.sum
├── hack
├── boilerplate.go.txt
├── custom-boilerplate.go.txt
├── tools.go
├── update-codegen.sh
└── verify-codegen.sh
├── main.go
└── pkg
├── apis
└── samplecontroller
│ ├── register.go
│ └── v1alpha1
│ ├── doc.go
│ ├── register.go
│ ├── types.go
│ └── zz_generated.deepcopy.go
├── generated
├── clientset
│ └── versioned
│ │ ├── clientset.go
│ │ ├── fake
│ │ ├── clientset_generated.go
│ │ ├── doc.go
│ │ └── register.go
│ │ ├── scheme
│ │ ├── doc.go
│ │ └── register.go
│ │ └── typed
│ │ └── samplecontroller
│ │ └── v1alpha1
│ │ ├── doc.go
│ │ ├── fake
│ │ ├── doc.go
│ │ ├── fake_foo.go
│ │ └── fake_samplecontroller_client.go
│ │ ├── foo.go
│ │ ├── generated_expansion.go
│ │ └── samplecontroller_client.go
├── informers
│ └── externalversions
│ │ ├── factory.go
│ │ ├── generic.go
│ │ ├── internalinterfaces
│ │ └── factory_interfaces.go
│ │ └── samplecontroller
│ │ ├── interface.go
│ │ └── v1alpha1
│ │ ├── foo.go
│ │ └── interface.go
└── listers
│ └── samplecontroller
│ └── v1alpha1
│ ├── expansion_generated.go
│ └── foo.go
└── signals
├── signal.go
├── signal_posix.go
└── signal_windows.go
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | Sorry, we do not accept changes directly against this repository. Please see
2 | CONTRIBUTING.md for information on where and how to contribute instead.
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | sample-controller
2 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing guidelines
2 |
3 | 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/). 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.
4 |
5 | This repository is published from [kubernetes/kubernetes/staging/src/k8s.io/sample-controller](https://git.k8s.io/kubernetes/staging/src/k8s.io/sample-controller) by the [kubernetes publishing-bot](https://git.k8s.io/publishing-bot).
6 |
7 | Please see [Staging Directory and Publishing](https://git.k8s.io/community/contributors/devel/sig-architecture/staging.md) for more information
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/OWNERS:
--------------------------------------------------------------------------------
1 | # See the OWNERS docs at https://go.k8s.io/owners
2 |
3 | approvers:
4 | - deads2k
5 | - jpbetz
6 | - sttts
7 | - munnerz
8 | reviewers:
9 | - deads2k
10 | - sttts
11 | - munnerz
12 | - nikhita
13 | labels:
14 | - sig/api-machinery
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # sample-controller
2 |
3 | This repository implements a simple controller for watching Foo resources as
4 | defined with a CustomResourceDefinition (CRD).
5 |
6 | **Note:** go-get or vendor this package as `k8s.io/sample-controller`.
7 |
8 | This particular example demonstrates how to perform basic operations such as:
9 |
10 | * How to register a new custom resource (custom resource type) of type `Foo` using a CustomResourceDefinition.
11 | * How to create/get/list instances of your new resource type `Foo`.
12 | * How to setup a controller on resource handling create/update/delete events.
13 |
14 | It makes use of the generators in [k8s.io/code-generator](https://github.com/kubernetes/code-generator)
15 | to generate a typed client, informers, listers and deep-copy functions. You can
16 | do this yourself using the `./hack/update-codegen.sh` script.
17 |
18 | The `update-codegen` script will automatically generate the following files &
19 | directories:
20 |
21 | * `pkg/apis/samplecontroller/v1alpha1/zz_generated.deepcopy.go`
22 | * `pkg/generated/`
23 |
24 | Changes should not be made to these files manually, and when creating your own
25 | controller based off of this implementation you should not copy these files and
26 | instead run the `update-codegen` script to generate your own.
27 |
28 | ## Details
29 |
30 | The sample controller uses [client-go library](https://github.com/kubernetes/client-go/tree/master/tools/cache) extensively.
31 | The details of interaction points of the sample controller with various mechanisms from this library are
32 | explained [here](docs/controller-client-go.md).
33 |
34 | ## Fetch sample-controller and its dependencies
35 |
36 | Issue the following commands --- starting in whatever working directory you
37 | like.
38 |
39 | ```sh
40 | git clone https://github.com/kubernetes/sample-controller
41 | cd sample-controller
42 | ```
43 |
44 | Note, however, that if you intend to
45 | generate code then you will also need the
46 | code-generator repo to exist in an old-style location. One easy way
47 | to do this is to use the command `go mod vendor` to create and
48 | populate the `vendor` directory.
49 |
50 | ### A Note on kubernetes/kubernetes
51 |
52 | If you are developing Kubernetes according to
53 | https://github.com/kubernetes/community/blob/master/contributors/guide/github-workflow.md
54 | then you already have a copy of this demo in
55 | `kubernetes/staging/src/k8s.io/sample-controller` and its dependencies
56 | --- including the code generator --- are in usable locations
57 | (valid for all Go versions).
58 |
59 | ## Purpose
60 |
61 | This is an example of how to build a kube-like controller with a single type.
62 |
63 | ## Running
64 |
65 | **Prerequisite**: Since the sample-controller uses `apps/v1` deployments, the Kubernetes cluster version should be greater than 1.9.
66 |
67 | ```sh
68 | # assumes you have a working kubeconfig, not required if operating in-cluster
69 | go build -o sample-controller .
70 | ./sample-controller -kubeconfig=$HOME/.kube/config
71 |
72 | # create a CustomResourceDefinition
73 | kubectl create -f artifacts/examples/crd-status-subresource.yaml
74 |
75 | # create a custom resource of type Foo
76 | kubectl create -f artifacts/examples/example-foo.yaml
77 |
78 | # check deployments created through the custom resource
79 | kubectl get deployments
80 | ```
81 |
82 | ## Use Cases
83 |
84 | CustomResourceDefinitions can be used to implement custom resource types for your Kubernetes cluster.
85 | These act like most other Resources in Kubernetes, and may be `kubectl apply`'d, etc.
86 |
87 | Some example use cases:
88 |
89 | * Provisioning/Management of external datastores/databases (eg. CloudSQL/RDS instances)
90 | * Higher level abstractions around Kubernetes primitives (eg. a single Resource to define an etcd cluster, backed by a Service and a ReplicationController)
91 |
92 | ## Defining types
93 |
94 | Each instance of your custom resource has an attached Spec, which should be defined via a `struct{}` to provide data format validation.
95 | In practice, this Spec is arbitrary key-value data that specifies the configuration/behavior of your Resource.
96 |
97 | For example, if you were implementing a custom resource for a Database, you might provide a DatabaseSpec like the following:
98 |
99 | ``` go
100 | type DatabaseSpec struct {
101 | Databases []string `json:"databases"`
102 | Users []User `json:"users"`
103 | Version string `json:"version"`
104 | }
105 |
106 | type User struct {
107 | Name string `json:"name"`
108 | Password string `json:"password"`
109 | }
110 | ```
111 |
112 | Note, the JSON tag `json:` is required on all user facing fields within your type. Typically API types contain only user facing fields. When the JSON tag is omitted from the field, Kubernetes generators consider the field to be internal and will not expose the field in their generated external output. For example, this means that the field would not be included in a generated CRD schema.
113 |
114 | ## Validation
115 |
116 | To validate custom resources, use the [`CustomResourceValidation`](https://kubernetes.io/docs/tasks/access-kubernetes-api/extend-api-custom-resource-definitions/#validation) feature. Validation in the form of a [structured schema](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#specifying-a-structural-schema) is mandatory to be provided for `apiextensions.k8s.io/v1`.
117 |
118 | ### Example
119 |
120 | The schema in [`crd.yaml`](./artifacts/examples/crd.yaml) applies the following validation on the custom resource:
121 | `spec.replicas` must be an integer and must have a minimum value of 1 and a maximum value of 10.
122 |
123 | ## Subresources
124 |
125 | Custom Resources support `/status` and `/scale` [subresources](https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#subresources). The `CustomResourceSubresources` feature is in GA from v1.16.
126 |
127 | ### Example
128 |
129 | The CRD in [`crd-status-subresource.yaml`](./artifacts/examples/crd-status-subresource.yaml) enables the `/status` subresource for custom resources.
130 | This means that [`UpdateStatus`](./controller.go) can be used by the controller to update only the status part of the custom resource.
131 |
132 | To understand why only the status part of the custom resource should be updated, please refer to the [Kubernetes API conventions](https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status).
133 |
134 | In the above steps, use `crd-status-subresource.yaml` to create the CRD:
135 |
136 | ```sh
137 | # create a CustomResourceDefinition supporting the status subresource
138 | kubectl create -f artifacts/examples/crd-status-subresource.yaml
139 | ```
140 |
141 | ## A Note on the API version
142 | The [group](https://kubernetes.io/docs/reference/using-api/#api-groups) version of the custom resource in `crd.yaml` is `v1alpha`, this can be evolved to a stable API version, `v1`, using [CRD Versioning](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning/).
143 |
144 | ## Cleanup
145 |
146 | You can clean up the created CustomResourceDefinition with:
147 | ```sh
148 | kubectl delete crd foos.samplecontroller.k8s.io
149 | ```
150 |
151 | ## Compatibility
152 |
153 | HEAD of this repository will match HEAD of k8s.io/apimachinery and
154 | k8s.io/client-go.
155 |
156 | ## Where does it come from?
157 |
158 | `sample-controller` is synced from
159 | https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/sample-controller.
160 | Code changes are made in that location, merged into k8s.io/kubernetes and
161 | later synced here.
162 |
163 |
--------------------------------------------------------------------------------
/SECURITY_CONTACTS:
--------------------------------------------------------------------------------
1 | # Defined below are the security contacts for this repo.
2 | #
3 | # They are the contact point for the Product Security Committee to reach out
4 | # to for triaging and handling of incoming issues.
5 | #
6 | # The below names agree to abide by the
7 | # [Embargo Policy](https://git.k8s.io/security/private-distributors-list.md#embargo-policy)
8 | # and will be removed and replaced if they violate that agreement.
9 | #
10 | # DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE
11 | # INSTRUCTIONS AT https://kubernetes.io/security/
12 |
13 | cheftako
14 | deads2k
15 | lavalamp
16 | sttts
17 |
--------------------------------------------------------------------------------
/artifacts/examples/crd-status-subresource.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apiextensions.k8s.io/v1
2 | kind: CustomResourceDefinition
3 | metadata:
4 | name: foos.samplecontroller.k8s.io
5 | # for more information on the below annotation, please see
6 | # https://github.com/kubernetes/enhancements/blob/master/keps/sig-api-machinery/2337-k8s.io-group-protection/README.md
7 | annotations:
8 | "api-approved.kubernetes.io": "unapproved, experimental-only; please get an approval from Kubernetes API reviewers if you're trying to develop a CRD in the *.k8s.io or *.kubernetes.io groups"
9 | spec:
10 | group: samplecontroller.k8s.io
11 | versions:
12 | - name: v1alpha1
13 | served: true
14 | storage: true
15 | schema:
16 | # schema used for validation
17 | openAPIV3Schema:
18 | type: object
19 | properties:
20 | spec:
21 | type: object
22 | properties:
23 | deploymentName:
24 | type: string
25 | replicas:
26 | type: integer
27 | minimum: 1
28 | maximum: 10
29 | status:
30 | type: object
31 | properties:
32 | availableReplicas:
33 | type: integer
34 | # subresources for the custom resource
35 | subresources:
36 | # enables the status subresource
37 | status: {}
38 | names:
39 | kind: Foo
40 | plural: foos
41 | scope: Namespaced
42 |
--------------------------------------------------------------------------------
/artifacts/examples/crd.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apiextensions.k8s.io/v1
2 | kind: CustomResourceDefinition
3 | metadata:
4 | name: foos.samplecontroller.k8s.io
5 | # for more information on the below annotation, please see
6 | # https://github.com/kubernetes/enhancements/blob/master/keps/sig-api-machinery/2337-k8s.io-group-protection/README.md
7 | annotations:
8 | "api-approved.kubernetes.io": "unapproved, experimental-only; please get an approval from Kubernetes API reviewers if you're trying to develop a CRD in the *.k8s.io or *.kubernetes.io groups"
9 | spec:
10 | group: samplecontroller.k8s.io
11 | versions:
12 | - name: v1alpha1
13 | served: true
14 | storage: true
15 | schema:
16 | # schema used for validation
17 | openAPIV3Schema:
18 | type: object
19 | properties:
20 | spec:
21 | type: object
22 | properties:
23 | deploymentName:
24 | type: string
25 | replicas:
26 | type: integer
27 | minimum: 1
28 | maximum: 10
29 | status:
30 | type: object
31 | properties:
32 | availableReplicas:
33 | type: integer
34 | names:
35 | kind: Foo
36 | plural: foos
37 | scope: Namespaced
38 |
--------------------------------------------------------------------------------
/artifacts/examples/example-foo.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: samplecontroller.k8s.io/v1alpha1
2 | kind: Foo
3 | metadata:
4 | name: example-foo
5 | spec:
6 | deploymentName: example-foo
7 | replicas: 1
8 |
--------------------------------------------------------------------------------
/code-of-conduct.md:
--------------------------------------------------------------------------------
1 | # Kubernetes Community Code of Conduct
2 |
3 | Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md)
4 |
--------------------------------------------------------------------------------
/controller.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package main
18 |
19 | import (
20 | "context"
21 | "fmt"
22 | "time"
23 |
24 | "golang.org/x/time/rate"
25 |
26 | appsv1 "k8s.io/api/apps/v1"
27 | corev1 "k8s.io/api/core/v1"
28 | "k8s.io/apimachinery/pkg/api/errors"
29 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30 | utilruntime "k8s.io/apimachinery/pkg/util/runtime"
31 | "k8s.io/apimachinery/pkg/util/wait"
32 | appsinformers "k8s.io/client-go/informers/apps/v1"
33 | "k8s.io/client-go/kubernetes"
34 | "k8s.io/client-go/kubernetes/scheme"
35 | typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
36 | appslisters "k8s.io/client-go/listers/apps/v1"
37 | "k8s.io/client-go/tools/cache"
38 | "k8s.io/client-go/tools/record"
39 | "k8s.io/client-go/util/workqueue"
40 | "k8s.io/klog/v2"
41 |
42 | samplev1alpha1 "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1"
43 | clientset "k8s.io/sample-controller/pkg/generated/clientset/versioned"
44 | samplescheme "k8s.io/sample-controller/pkg/generated/clientset/versioned/scheme"
45 | informers "k8s.io/sample-controller/pkg/generated/informers/externalversions/samplecontroller/v1alpha1"
46 | listers "k8s.io/sample-controller/pkg/generated/listers/samplecontroller/v1alpha1"
47 | )
48 |
49 | const controllerAgentName = "sample-controller"
50 |
51 | const (
52 | // SuccessSynced is used as part of the Event 'reason' when a Foo is synced
53 | SuccessSynced = "Synced"
54 | // ErrResourceExists is used as part of the Event 'reason' when a Foo fails
55 | // to sync due to a Deployment of the same name already existing.
56 | ErrResourceExists = "ErrResourceExists"
57 |
58 | // MessageResourceExists is the message used for Events when a resource
59 | // fails to sync due to a Deployment already existing
60 | MessageResourceExists = "Resource %q already exists and is not managed by Foo"
61 | // MessageResourceSynced is the message used for an Event fired when a Foo
62 | // is synced successfully
63 | MessageResourceSynced = "Foo synced successfully"
64 | // FieldManager distinguishes this controller from other things writing to API objects
65 | FieldManager = controllerAgentName
66 | )
67 |
68 | // Controller is the controller implementation for Foo resources
69 | type Controller struct {
70 | // kubeclientset is a standard kubernetes clientset
71 | kubeclientset kubernetes.Interface
72 | // sampleclientset is a clientset for our own API group
73 | sampleclientset clientset.Interface
74 |
75 | deploymentsLister appslisters.DeploymentLister
76 | deploymentsSynced cache.InformerSynced
77 | foosLister listers.FooLister
78 | foosSynced cache.InformerSynced
79 |
80 | // workqueue is a rate limited work queue. This is used to queue work to be
81 | // processed instead of performing it as soon as a change happens. This
82 | // means we can ensure we only process a fixed amount of resources at a
83 | // time, and makes it easy to ensure we are never processing the same item
84 | // simultaneously in two different workers.
85 | workqueue workqueue.TypedRateLimitingInterface[cache.ObjectName]
86 | // recorder is an event recorder for recording Event resources to the
87 | // Kubernetes API.
88 | recorder record.EventRecorder
89 | }
90 |
91 | // NewController returns a new sample controller
92 | func NewController(
93 | ctx context.Context,
94 | kubeclientset kubernetes.Interface,
95 | sampleclientset clientset.Interface,
96 | deploymentInformer appsinformers.DeploymentInformer,
97 | fooInformer informers.FooInformer) *Controller {
98 | logger := klog.FromContext(ctx)
99 |
100 | // Create event broadcaster
101 | // Add sample-controller types to the default Kubernetes Scheme so Events can be
102 | // logged for sample-controller types.
103 | utilruntime.Must(samplescheme.AddToScheme(scheme.Scheme))
104 | logger.V(4).Info("Creating event broadcaster")
105 |
106 | eventBroadcaster := record.NewBroadcaster(record.WithContext(ctx))
107 | eventBroadcaster.StartStructuredLogging(0)
108 | eventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: kubeclientset.CoreV1().Events("")})
109 | recorder := eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: controllerAgentName})
110 | ratelimiter := workqueue.NewTypedMaxOfRateLimiter(
111 | workqueue.NewTypedItemExponentialFailureRateLimiter[cache.ObjectName](5*time.Millisecond, 1000*time.Second),
112 | &workqueue.TypedBucketRateLimiter[cache.ObjectName]{Limiter: rate.NewLimiter(rate.Limit(50), 300)},
113 | )
114 |
115 | controller := &Controller{
116 | kubeclientset: kubeclientset,
117 | sampleclientset: sampleclientset,
118 | deploymentsLister: deploymentInformer.Lister(),
119 | deploymentsSynced: deploymentInformer.Informer().HasSynced,
120 | foosLister: fooInformer.Lister(),
121 | foosSynced: fooInformer.Informer().HasSynced,
122 | workqueue: workqueue.NewTypedRateLimitingQueue(ratelimiter),
123 | recorder: recorder,
124 | }
125 |
126 | logger.Info("Setting up event handlers")
127 | // Set up an event handler for when Foo resources change
128 | fooInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
129 | AddFunc: controller.enqueueFoo,
130 | UpdateFunc: func(old, new interface{}) {
131 | controller.enqueueFoo(new)
132 | },
133 | })
134 | // Set up an event handler for when Deployment resources change. This
135 | // handler will lookup the owner of the given Deployment, and if it is
136 | // owned by a Foo resource then the handler will enqueue that Foo resource for
137 | // processing. This way, we don't need to implement custom logic for
138 | // handling Deployment resources. More info on this pattern:
139 | // https://github.com/kubernetes/community/blob/8cafef897a22026d42f5e5bb3f104febe7e29830/contributors/devel/controllers.md
140 | deploymentInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
141 | AddFunc: controller.handleObject,
142 | UpdateFunc: func(old, new interface{}) {
143 | newDepl := new.(*appsv1.Deployment)
144 | oldDepl := old.(*appsv1.Deployment)
145 | if newDepl.ResourceVersion == oldDepl.ResourceVersion {
146 | // Periodic resync will send update events for all known Deployments.
147 | // Two different versions of the same Deployment will always have different RVs.
148 | return
149 | }
150 | controller.handleObject(new)
151 | },
152 | DeleteFunc: controller.handleObject,
153 | })
154 |
155 | return controller
156 | }
157 |
158 | // Run will set up the event handlers for types we are interested in, as well
159 | // as syncing informer caches and starting workers. It will block until stopCh
160 | // is closed, at which point it will shutdown the workqueue and wait for
161 | // workers to finish processing their current work items.
162 | func (c *Controller) Run(ctx context.Context, workers int) error {
163 | defer utilruntime.HandleCrash()
164 | defer c.workqueue.ShutDown()
165 | logger := klog.FromContext(ctx)
166 |
167 | // Start the informer factories to begin populating the informer caches
168 | logger.Info("Starting Foo controller")
169 |
170 | // Wait for the caches to be synced before starting workers
171 | logger.Info("Waiting for informer caches to sync")
172 |
173 | if ok := cache.WaitForCacheSync(ctx.Done(), c.deploymentsSynced, c.foosSynced); !ok {
174 | return fmt.Errorf("failed to wait for caches to sync")
175 | }
176 |
177 | logger.Info("Starting workers", "count", workers)
178 | // Launch two workers to process Foo resources
179 | for i := 0; i < workers; i++ {
180 | go wait.UntilWithContext(ctx, c.runWorker, time.Second)
181 | }
182 |
183 | logger.Info("Started workers")
184 | <-ctx.Done()
185 | logger.Info("Shutting down workers")
186 |
187 | return nil
188 | }
189 |
190 | // runWorker is a long-running function that will continually call the
191 | // processNextWorkItem function in order to read and process a message on the
192 | // workqueue.
193 | func (c *Controller) runWorker(ctx context.Context) {
194 | for c.processNextWorkItem(ctx) {
195 | }
196 | }
197 |
198 | // processNextWorkItem will read a single work item off the workqueue and
199 | // attempt to process it, by calling the syncHandler.
200 | func (c *Controller) processNextWorkItem(ctx context.Context) bool {
201 | objRef, shutdown := c.workqueue.Get()
202 | logger := klog.FromContext(ctx)
203 |
204 | if shutdown {
205 | return false
206 | }
207 |
208 | // We call Done at the end of this func so the workqueue knows we have
209 | // finished processing this item. We also must remember to call Forget
210 | // if we do not want this work item being re-queued. For example, we do
211 | // not call Forget if a transient error occurs, instead the item is
212 | // put back on the workqueue and attempted again after a back-off
213 | // period.
214 | defer c.workqueue.Done(objRef)
215 |
216 | // Run the syncHandler, passing it the structured reference to the object to be synced.
217 | err := c.syncHandler(ctx, objRef)
218 | if err == nil {
219 | // If no error occurs then we Forget this item so it does not
220 | // get queued again until another change happens.
221 | c.workqueue.Forget(objRef)
222 | logger.Info("Successfully synced", "objectName", objRef)
223 | return true
224 | }
225 | // there was a failure so be sure to report it. This method allows for
226 | // pluggable error handling which can be used for things like
227 | // cluster-monitoring.
228 | utilruntime.HandleErrorWithContext(ctx, err, "Error syncing; requeuing for later retry", "objectReference", objRef)
229 | // since we failed, we should requeue the item to work on later. This
230 | // method will add a backoff to avoid hotlooping on particular items
231 | // (they're probably still not going to work right away) and overall
232 | // controller protection (everything I've done is broken, this controller
233 | // needs to calm down or it can starve other useful work) cases.
234 | c.workqueue.AddRateLimited(objRef)
235 | return true
236 | }
237 |
238 | // syncHandler compares the actual state with the desired, and attempts to
239 | // converge the two. It then updates the Status block of the Foo resource
240 | // with the current status of the resource.
241 | func (c *Controller) syncHandler(ctx context.Context, objectRef cache.ObjectName) error {
242 | logger := klog.LoggerWithValues(klog.FromContext(ctx), "objectRef", objectRef)
243 |
244 | // Get the Foo resource with this namespace/name
245 | foo, err := c.foosLister.Foos(objectRef.Namespace).Get(objectRef.Name)
246 | if err != nil {
247 | // The Foo resource may no longer exist, in which case we stop
248 | // processing.
249 | if errors.IsNotFound(err) {
250 | utilruntime.HandleErrorWithContext(ctx, err, "Foo referenced by item in work queue no longer exists", "objectReference", objectRef)
251 | return nil
252 | }
253 |
254 | return err
255 | }
256 |
257 | deploymentName := foo.Spec.DeploymentName
258 | if deploymentName == "" {
259 | // We choose to absorb the error here as the worker would requeue the
260 | // resource otherwise. Instead, the next time the resource is updated
261 | // the resource will be queued again.
262 | utilruntime.HandleErrorWithContext(ctx, nil, "Deployment name missing from object reference", "objectReference", objectRef)
263 | return nil
264 | }
265 |
266 | // Get the deployment with the name specified in Foo.spec
267 | deployment, err := c.deploymentsLister.Deployments(foo.Namespace).Get(deploymentName)
268 | // If the resource doesn't exist, we'll create it
269 | if errors.IsNotFound(err) {
270 | deployment, err = c.kubeclientset.AppsV1().Deployments(foo.Namespace).Create(ctx, newDeployment(foo), metav1.CreateOptions{FieldManager: FieldManager})
271 | }
272 |
273 | // If an error occurs during Get/Create, we'll requeue the item so we can
274 | // attempt processing again later. This could have been caused by a
275 | // temporary network failure, or any other transient reason.
276 | if err != nil {
277 | return err
278 | }
279 |
280 | // If the Deployment is not controlled by this Foo resource, we should log
281 | // a warning to the event recorder and return error msg.
282 | if !metav1.IsControlledBy(deployment, foo) {
283 | msg := fmt.Sprintf(MessageResourceExists, deployment.Name)
284 | c.recorder.Event(foo, corev1.EventTypeWarning, ErrResourceExists, msg)
285 | return fmt.Errorf("%s", msg)
286 | }
287 |
288 | // If this number of the replicas on the Foo resource is specified, and the
289 | // number does not equal the current desired replicas on the Deployment, we
290 | // should update the Deployment resource.
291 | if foo.Spec.Replicas != nil && *foo.Spec.Replicas != *deployment.Spec.Replicas {
292 | logger.V(4).Info("Update deployment resource", "currentReplicas", *deployment.Spec.Replicas, "desiredReplicas", *foo.Spec.Replicas)
293 | deployment, err = c.kubeclientset.AppsV1().Deployments(foo.Namespace).Update(ctx, newDeployment(foo), metav1.UpdateOptions{FieldManager: FieldManager})
294 | }
295 |
296 | // If an error occurs during Update, we'll requeue the item so we can
297 | // attempt processing again later. This could have been caused by a
298 | // temporary network failure, or any other transient reason.
299 | if err != nil {
300 | return err
301 | }
302 |
303 | // Finally, we update the status block of the Foo resource to reflect the
304 | // current state of the world
305 | err = c.updateFooStatus(ctx, foo, deployment)
306 | if err != nil {
307 | return err
308 | }
309 |
310 | c.recorder.Event(foo, corev1.EventTypeNormal, SuccessSynced, MessageResourceSynced)
311 | return nil
312 | }
313 |
314 | func (c *Controller) updateFooStatus(ctx context.Context, foo *samplev1alpha1.Foo, deployment *appsv1.Deployment) error {
315 | // NEVER modify objects from the store. It's a read-only, local cache.
316 | // You can use DeepCopy() to make a deep copy of original object and modify this copy
317 | // Or create a copy manually for better performance
318 | fooCopy := foo.DeepCopy()
319 | fooCopy.Status.AvailableReplicas = deployment.Status.AvailableReplicas
320 | // If the CustomResourceSubresources feature gate is not enabled,
321 | // we must use Update instead of UpdateStatus to update the Status block of the Foo resource.
322 | // UpdateStatus will not allow changes to the Spec of the resource,
323 | // which is ideal for ensuring nothing other than resource status has been updated.
324 | _, err := c.sampleclientset.SamplecontrollerV1alpha1().Foos(foo.Namespace).UpdateStatus(ctx, fooCopy, metav1.UpdateOptions{FieldManager: FieldManager})
325 | return err
326 | }
327 |
328 | // enqueueFoo takes a Foo resource and converts it into a namespace/name
329 | // string which is then put onto the work queue. This method should *not* be
330 | // passed resources of any type other than Foo.
331 | func (c *Controller) enqueueFoo(obj interface{}) {
332 | if objectRef, err := cache.ObjectToName(obj); err != nil {
333 | utilruntime.HandleError(err)
334 | return
335 | } else {
336 | c.workqueue.Add(objectRef)
337 | }
338 | }
339 |
340 | // handleObject will take any resource implementing metav1.Object and attempt
341 | // to find the Foo resource that 'owns' it. It does this by looking at the
342 | // objects metadata.ownerReferences field for an appropriate OwnerReference.
343 | // It then enqueues that Foo resource to be processed. If the object does not
344 | // have an appropriate OwnerReference, it will simply be skipped.
345 | func (c *Controller) handleObject(obj interface{}) {
346 | var object metav1.Object
347 | var ok bool
348 | logger := klog.FromContext(context.Background())
349 | if object, ok = obj.(metav1.Object); !ok {
350 | tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
351 | if !ok {
352 | // If the object value is not too big and does not contain sensitive information then
353 | // it may be useful to include it.
354 | utilruntime.HandleErrorWithContext(context.Background(), nil, "Error decoding object, invalid type", "type", fmt.Sprintf("%T", obj))
355 | return
356 | }
357 | object, ok = tombstone.Obj.(metav1.Object)
358 | if !ok {
359 | // If the object value is not too big and does not contain sensitive information then
360 | // it may be useful to include it.
361 | utilruntime.HandleErrorWithContext(context.Background(), nil, "Error decoding object tombstone, invalid type", "type", fmt.Sprintf("%T", tombstone.Obj))
362 | return
363 | }
364 | logger.V(4).Info("Recovered deleted object", "resourceName", object.GetName())
365 | }
366 | logger.V(4).Info("Processing object", "object", klog.KObj(object))
367 | if ownerRef := metav1.GetControllerOf(object); ownerRef != nil {
368 | // If this object is not owned by a Foo, we should not do anything more
369 | // with it.
370 | if ownerRef.Kind != "Foo" {
371 | return
372 | }
373 |
374 | foo, err := c.foosLister.Foos(object.GetNamespace()).Get(ownerRef.Name)
375 | if err != nil {
376 | logger.V(4).Info("Ignore orphaned object", "object", klog.KObj(object), "foo", ownerRef.Name)
377 | return
378 | }
379 |
380 | c.enqueueFoo(foo)
381 | return
382 | }
383 | }
384 |
385 | // newDeployment creates a new Deployment for a Foo resource. It also sets
386 | // the appropriate OwnerReferences on the resource so handleObject can discover
387 | // the Foo resource that 'owns' it.
388 | func newDeployment(foo *samplev1alpha1.Foo) *appsv1.Deployment {
389 | labels := map[string]string{
390 | "app": "nginx",
391 | "controller": foo.Name,
392 | }
393 | return &appsv1.Deployment{
394 | ObjectMeta: metav1.ObjectMeta{
395 | Name: foo.Spec.DeploymentName,
396 | Namespace: foo.Namespace,
397 | OwnerReferences: []metav1.OwnerReference{
398 | *metav1.NewControllerRef(foo, samplev1alpha1.SchemeGroupVersion.WithKind("Foo")),
399 | },
400 | },
401 | Spec: appsv1.DeploymentSpec{
402 | Replicas: foo.Spec.Replicas,
403 | Selector: &metav1.LabelSelector{
404 | MatchLabels: labels,
405 | },
406 | Template: corev1.PodTemplateSpec{
407 | ObjectMeta: metav1.ObjectMeta{
408 | Labels: labels,
409 | },
410 | Spec: corev1.PodSpec{
411 | Containers: []corev1.Container{
412 | {
413 | Name: "nginx",
414 | Image: "nginx:latest",
415 | },
416 | },
417 | },
418 | },
419 | },
420 | }
421 | }
422 |
--------------------------------------------------------------------------------
/controller_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package main
18 |
19 | import (
20 | "context"
21 | "fmt"
22 | "reflect"
23 | "testing"
24 | "time"
25 |
26 | apps "k8s.io/api/apps/v1"
27 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28 | "k8s.io/apimachinery/pkg/runtime"
29 | "k8s.io/apimachinery/pkg/runtime/schema"
30 | "k8s.io/apimachinery/pkg/util/diff"
31 | kubeinformers "k8s.io/client-go/informers"
32 | k8sfake "k8s.io/client-go/kubernetes/fake"
33 | core "k8s.io/client-go/testing"
34 | "k8s.io/client-go/tools/cache"
35 | "k8s.io/client-go/tools/record"
36 | "k8s.io/klog/v2/ktesting"
37 |
38 | samplecontroller "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1"
39 | "k8s.io/sample-controller/pkg/generated/clientset/versioned/fake"
40 | informers "k8s.io/sample-controller/pkg/generated/informers/externalversions"
41 | )
42 |
43 | var (
44 | alwaysReady = func() bool { return true }
45 | noResyncPeriodFunc = func() time.Duration { return 0 }
46 | )
47 |
48 | type fixture struct {
49 | t *testing.T
50 |
51 | client *fake.Clientset
52 | kubeclient *k8sfake.Clientset
53 | // Objects to put in the store.
54 | fooLister []*samplecontroller.Foo
55 | deploymentLister []*apps.Deployment
56 | // Actions expected to happen on the client.
57 | kubeactions []core.Action
58 | actions []core.Action
59 | // Objects from here preloaded into NewSimpleFake.
60 | kubeobjects []runtime.Object
61 | objects []runtime.Object
62 | }
63 |
64 | func newFixture(t *testing.T) *fixture {
65 | f := &fixture{}
66 | f.t = t
67 | f.objects = []runtime.Object{}
68 | f.kubeobjects = []runtime.Object{}
69 | return f
70 | }
71 |
72 | func newFoo(name string, replicas *int32) *samplecontroller.Foo {
73 | return &samplecontroller.Foo{
74 | TypeMeta: metav1.TypeMeta{APIVersion: samplecontroller.SchemeGroupVersion.String()},
75 | ObjectMeta: metav1.ObjectMeta{
76 | Name: name,
77 | Namespace: metav1.NamespaceDefault,
78 | },
79 | Spec: samplecontroller.FooSpec{
80 | DeploymentName: fmt.Sprintf("%s-deployment", name),
81 | Replicas: replicas,
82 | },
83 | }
84 | }
85 |
86 | func (f *fixture) newController(ctx context.Context) (*Controller, informers.SharedInformerFactory, kubeinformers.SharedInformerFactory) {
87 | f.client = fake.NewSimpleClientset(f.objects...)
88 | f.kubeclient = k8sfake.NewSimpleClientset(f.kubeobjects...)
89 |
90 | i := informers.NewSharedInformerFactory(f.client, noResyncPeriodFunc())
91 | k8sI := kubeinformers.NewSharedInformerFactory(f.kubeclient, noResyncPeriodFunc())
92 |
93 | c := NewController(ctx, f.kubeclient, f.client,
94 | k8sI.Apps().V1().Deployments(), i.Samplecontroller().V1alpha1().Foos())
95 |
96 | c.foosSynced = alwaysReady
97 | c.deploymentsSynced = alwaysReady
98 | c.recorder = &record.FakeRecorder{}
99 |
100 | for _, f := range f.fooLister {
101 | i.Samplecontroller().V1alpha1().Foos().Informer().GetIndexer().Add(f)
102 | }
103 |
104 | for _, d := range f.deploymentLister {
105 | k8sI.Apps().V1().Deployments().Informer().GetIndexer().Add(d)
106 | }
107 |
108 | return c, i, k8sI
109 | }
110 |
111 | func (f *fixture) run(ctx context.Context, fooRef cache.ObjectName) {
112 | f.runController(ctx, fooRef, true, false)
113 | }
114 |
115 | func (f *fixture) runExpectError(ctx context.Context, fooRef cache.ObjectName) {
116 | f.runController(ctx, fooRef, true, true)
117 | }
118 |
119 | func (f *fixture) runController(ctx context.Context, fooRef cache.ObjectName, startInformers bool, expectError bool) {
120 | c, i, k8sI := f.newController(ctx)
121 | if startInformers {
122 | i.Start(ctx.Done())
123 | k8sI.Start(ctx.Done())
124 | }
125 |
126 | err := c.syncHandler(ctx, fooRef)
127 | if !expectError && err != nil {
128 | f.t.Errorf("error syncing foo: %v", err)
129 | } else if expectError && err == nil {
130 | f.t.Error("expected error syncing foo, got nil")
131 | }
132 |
133 | actions := filterInformerActions(f.client.Actions())
134 | for i, action := range actions {
135 | if len(f.actions) < i+1 {
136 | f.t.Errorf("%d unexpected actions: %+v", len(actions)-len(f.actions), actions[i:])
137 | break
138 | }
139 |
140 | expectedAction := f.actions[i]
141 | checkAction(expectedAction, action, f.t)
142 | }
143 |
144 | if len(f.actions) > len(actions) {
145 | f.t.Errorf("%d additional expected actions:%+v", len(f.actions)-len(actions), f.actions[len(actions):])
146 | }
147 |
148 | k8sActions := filterInformerActions(f.kubeclient.Actions())
149 | for i, action := range k8sActions {
150 | if len(f.kubeactions) < i+1 {
151 | f.t.Errorf("%d unexpected actions: %+v", len(k8sActions)-len(f.kubeactions), k8sActions[i:])
152 | break
153 | }
154 |
155 | expectedAction := f.kubeactions[i]
156 | checkAction(expectedAction, action, f.t)
157 | }
158 |
159 | if len(f.kubeactions) > len(k8sActions) {
160 | f.t.Errorf("%d additional expected actions:%+v", len(f.kubeactions)-len(k8sActions), f.kubeactions[len(k8sActions):])
161 | }
162 | }
163 |
164 | // checkAction verifies that expected and actual actions are equal and both have
165 | // same attached resources
166 | func checkAction(expected, actual core.Action, t *testing.T) {
167 | if !(expected.Matches(actual.GetVerb(), actual.GetResource().Resource) && actual.GetSubresource() == expected.GetSubresource()) {
168 | t.Errorf("Expected\n\t%#v\ngot\n\t%#v", expected, actual)
169 | return
170 | }
171 |
172 | if reflect.TypeOf(actual) != reflect.TypeOf(expected) {
173 | t.Errorf("Action has wrong type. Expected: %t. Got: %t", expected, actual)
174 | return
175 | }
176 |
177 | switch a := actual.(type) {
178 | case core.CreateActionImpl:
179 | e, _ := expected.(core.CreateActionImpl)
180 | expObject := e.GetObject()
181 | object := a.GetObject()
182 |
183 | if !reflect.DeepEqual(expObject, object) {
184 | t.Errorf("Action %s %s has wrong object\nDiff:\n %s",
185 | a.GetVerb(), a.GetResource().Resource, diff.ObjectGoPrintSideBySide(expObject, object))
186 | }
187 | case core.UpdateActionImpl:
188 | e, _ := expected.(core.UpdateActionImpl)
189 | expObject := e.GetObject()
190 | object := a.GetObject()
191 |
192 | if !reflect.DeepEqual(expObject, object) {
193 | t.Errorf("Action %s %s has wrong object\nDiff:\n %s",
194 | a.GetVerb(), a.GetResource().Resource, diff.ObjectGoPrintSideBySide(expObject, object))
195 | }
196 | case core.PatchActionImpl:
197 | e, _ := expected.(core.PatchActionImpl)
198 | expPatch := e.GetPatch()
199 | patch := a.GetPatch()
200 |
201 | if !reflect.DeepEqual(expPatch, patch) {
202 | t.Errorf("Action %s %s has wrong patch\nDiff:\n %s",
203 | a.GetVerb(), a.GetResource().Resource, diff.ObjectGoPrintSideBySide(expPatch, patch))
204 | }
205 | default:
206 | t.Errorf("Uncaptured Action %s %s, you should explicitly add a case to capture it",
207 | actual.GetVerb(), actual.GetResource().Resource)
208 | }
209 | }
210 |
211 | // filterInformerActions filters list and watch actions for testing resources.
212 | // Since list and watch don't change resource state we can filter it to lower
213 | // nose level in our tests.
214 | func filterInformerActions(actions []core.Action) []core.Action {
215 | ret := []core.Action{}
216 | for _, action := range actions {
217 | if len(action.GetNamespace()) == 0 &&
218 | (action.Matches("list", "foos") ||
219 | action.Matches("watch", "foos") ||
220 | action.Matches("list", "deployments") ||
221 | action.Matches("watch", "deployments")) {
222 | continue
223 | }
224 | ret = append(ret, action)
225 | }
226 |
227 | return ret
228 | }
229 |
230 | func (f *fixture) expectCreateDeploymentAction(d *apps.Deployment) {
231 | f.kubeactions = append(f.kubeactions, core.NewCreateAction(schema.GroupVersionResource{Resource: "deployments"}, d.Namespace, d))
232 | }
233 |
234 | func (f *fixture) expectUpdateDeploymentAction(d *apps.Deployment) {
235 | f.kubeactions = append(f.kubeactions, core.NewUpdateAction(schema.GroupVersionResource{Resource: "deployments"}, d.Namespace, d))
236 | }
237 |
238 | func (f *fixture) expectUpdateFooStatusAction(foo *samplecontroller.Foo) {
239 | action := core.NewUpdateSubresourceAction(schema.GroupVersionResource{Resource: "foos"}, "status", foo.Namespace, foo)
240 | f.actions = append(f.actions, action)
241 | }
242 |
243 | func getRef(foo *samplecontroller.Foo, t *testing.T) cache.ObjectName {
244 | ref := cache.MetaObjectToName(foo)
245 | return ref
246 | }
247 |
248 | func TestCreatesDeployment(t *testing.T) {
249 | f := newFixture(t)
250 | foo := newFoo("test", int32Ptr(1))
251 | _, ctx := ktesting.NewTestContext(t)
252 |
253 | f.fooLister = append(f.fooLister, foo)
254 | f.objects = append(f.objects, foo)
255 |
256 | expDeployment := newDeployment(foo)
257 | f.expectCreateDeploymentAction(expDeployment)
258 | f.expectUpdateFooStatusAction(foo)
259 |
260 | f.run(ctx, getRef(foo, t))
261 | }
262 |
263 | func TestDoNothing(t *testing.T) {
264 | f := newFixture(t)
265 | foo := newFoo("test", int32Ptr(1))
266 | _, ctx := ktesting.NewTestContext(t)
267 |
268 | d := newDeployment(foo)
269 |
270 | f.fooLister = append(f.fooLister, foo)
271 | f.objects = append(f.objects, foo)
272 | f.deploymentLister = append(f.deploymentLister, d)
273 | f.kubeobjects = append(f.kubeobjects, d)
274 |
275 | f.expectUpdateFooStatusAction(foo)
276 | f.run(ctx, getRef(foo, t))
277 | }
278 |
279 | func TestUpdateDeployment(t *testing.T) {
280 | f := newFixture(t)
281 | foo := newFoo("test", int32Ptr(1))
282 | _, ctx := ktesting.NewTestContext(t)
283 |
284 | d := newDeployment(foo)
285 |
286 | // Update replicas
287 | foo.Spec.Replicas = int32Ptr(2)
288 | expDeployment := newDeployment(foo)
289 |
290 | f.fooLister = append(f.fooLister, foo)
291 | f.objects = append(f.objects, foo)
292 | f.deploymentLister = append(f.deploymentLister, d)
293 | f.kubeobjects = append(f.kubeobjects, d)
294 |
295 | f.expectUpdateFooStatusAction(foo)
296 | f.expectUpdateDeploymentAction(expDeployment)
297 | f.run(ctx, getRef(foo, t))
298 | }
299 |
300 | func TestNotControlledByUs(t *testing.T) {
301 | f := newFixture(t)
302 | foo := newFoo("test", int32Ptr(1))
303 | _, ctx := ktesting.NewTestContext(t)
304 |
305 | d := newDeployment(foo)
306 |
307 | d.ObjectMeta.OwnerReferences = []metav1.OwnerReference{}
308 |
309 | f.fooLister = append(f.fooLister, foo)
310 | f.objects = append(f.objects, foo)
311 | f.deploymentLister = append(f.deploymentLister, d)
312 | f.kubeobjects = append(f.kubeobjects, d)
313 |
314 | f.runExpectError(ctx, getRef(foo, t))
315 | }
316 |
317 | func int32Ptr(i int32) *int32 { return &i }
318 |
--------------------------------------------------------------------------------
/docs/controller-client-go.md:
--------------------------------------------------------------------------------
1 | # client-go under the hood
2 |
3 | The [client-go](https://github.com/kubernetes/client-go/) library contains various mechanisms that you can use when
4 | developing your custom controllers. These mechanisms are defined in the
5 | [tools/cache folder](https://github.com/kubernetes/client-go/tree/master/tools/cache) of the library.
6 |
7 | Here is a pictorial representation showing how the various components in
8 | the client-go library work and their interaction points with the custom
9 | controller code that you will write.
10 |
11 |
12 |
13 |
14 |
15 | ## client-go components
16 |
17 | * Reflector: A reflector, which is defined in [type *Reflector* inside package *cache*](https://github.com/kubernetes/client-go/blob/master/tools/cache/reflector.go),
18 | watches the Kubernetes API for the specified resource type (kind).
19 | The function in which this is done is *ListAndWatch*.
20 | The watch could be for an in-built resource or it could be for a custom resource.
21 | When the reflector receives notification about existence of new
22 | resource instance through the watch API, it gets the newly created object
23 | using the corresponding listing API and puts it in the Delta Fifo queue
24 | inside the *watchHandler* function.
25 |
26 |
27 | * Informer: An informer defined in the [base controller inside package *cache*](https://github.com/kubernetes/client-go/blob/master/tools/cache/controller.go) pops objects from the Delta Fifo queue.
28 | The function in which this is done is *processLoop*. The job of this base controller
29 | is to save the object for later retrieval, and to invoke our controller passing it the object.
30 |
31 | * Indexer: An indexer provides indexing functionality over objects.
32 | It is defined in [type *Indexer* inside package *cache*](https://github.com/kubernetes/client-go/blob/master/tools/cache/index.go). A typical indexing use-case is to create an index based on object labels. Indexer can
33 | maintain indexes based on several indexing functions.
34 | Indexer uses a thread-safe data store to store objects and their keys.
35 | There is a default function named *MetaNamespaceKeyFunc* defined in [type *Store* inside package *cache*](https://github.com/kubernetes/client-go/blob/master/tools/cache/store.go)
36 | that generates an object’s key as `/` combination for that object.
37 |
38 |
39 | ## Custom Controller components
40 |
41 | * Informer reference: This is the reference to the Informer instance that knows
42 | how to work with your custom resource objects. Your custom controller code needs
43 | to create the appropriate Informer.
44 |
45 | * Indexer reference: This is the reference to the Indexer instance that knows
46 | how to work with your custom resource objects. Your custom controller code needs
47 | to create this. You will be using this reference for retrieving objects for
48 | later processing.
49 |
50 | The base controller in client-go provides the *NewIndexerInformer* function to create Informer and Indexer.
51 | In your code you can either [directly invoke this function](https://github.com/kubernetes/client-go/blob/master/examples/workqueue/main.go#L174) or [use factory methods for creating an informer.](https://github.com/kubernetes/sample-controller/blob/master/main.go#L61)
52 |
53 | * Resource Event Handlers: These are the callback functions which will be called by
54 | the Informer when it wants to deliver an object to your controller. The typical
55 | pattern to write these functions is to obtain the dispatched object’s key
56 | and enqueue that key in a work queue for further processing.
57 |
58 | * Work queue: This is the queue that you create in your controller code to decouple
59 | delivery of an object from its processing. Resource event handler functions are written
60 | to extract the delivered object’s key and add that to the work queue.
61 |
62 | * Process Item: This is the function that you create in your code which processes items
63 | from the work queue. There can be one or more other functions that do the actual processing.
64 | These functions will typically use the [Indexer reference](https://github.com/kubernetes/client-go/blob/master/examples/workqueue/main.go#L73), or a Listing wrapper to retrieve the object corresponding to the key.
--------------------------------------------------------------------------------
/docs/images/client-go-controller-interaction.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kubernetes/sample-controller/099b2a3118ac16d7f9036befe1c0bf1e71a56c8f/docs/images/client-go-controller-interaction.jpeg
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | // This is a generated file. Do not edit directly.
2 |
3 | module k8s.io/sample-controller
4 |
5 | go 1.24.0
6 |
7 | godebug default=go1.24
8 |
9 | require (
10 | golang.org/x/time v0.9.0
11 | k8s.io/api v0.0.0-20250516033257-ffe08c772d5b
12 | k8s.io/apimachinery v0.0.0-20250516032956-da3bba90543c
13 | k8s.io/client-go v0.0.0-20250516033711-025e06660a23
14 | k8s.io/code-generator v0.0.0-20250516034928-3a6fa0a71475
15 | k8s.io/klog/v2 v2.130.1
16 | )
17 |
18 | require (
19 | github.com/davecgh/go-spew v1.1.1 // indirect
20 | github.com/emicklei/go-restful/v3 v3.11.0 // indirect
21 | github.com/fxamacker/cbor/v2 v2.8.0 // indirect
22 | github.com/go-logr/logr v1.4.2 // indirect
23 | github.com/go-openapi/jsonpointer v0.21.0 // indirect
24 | github.com/go-openapi/jsonreference v0.20.2 // indirect
25 | github.com/go-openapi/swag v0.23.0 // indirect
26 | github.com/gogo/protobuf v1.3.2 // indirect
27 | github.com/google/gnostic-models v0.6.9 // indirect
28 | github.com/google/go-cmp v0.7.0 // indirect
29 | github.com/google/uuid v1.6.0 // indirect
30 | github.com/josharian/intern v1.0.0 // indirect
31 | github.com/json-iterator/go v1.1.12 // indirect
32 | github.com/mailru/easyjson v0.7.7 // indirect
33 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
34 | github.com/modern-go/reflect2 v1.0.2 // indirect
35 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
36 | github.com/pkg/errors v0.9.1 // indirect
37 | github.com/spf13/pflag v1.0.6 // indirect
38 | github.com/x448/float16 v0.8.4 // indirect
39 | golang.org/x/mod v0.21.0 // indirect
40 | golang.org/x/net v0.38.0 // indirect
41 | golang.org/x/oauth2 v0.27.0 // indirect
42 | golang.org/x/sync v0.12.0 // indirect
43 | golang.org/x/sys v0.31.0 // indirect
44 | golang.org/x/term v0.30.0 // indirect
45 | golang.org/x/text v0.23.0 // indirect
46 | golang.org/x/tools v0.26.0 // indirect
47 | google.golang.org/protobuf v1.36.5 // indirect
48 | gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
49 | gopkg.in/inf.v0 v0.9.1 // indirect
50 | gopkg.in/yaml.v3 v3.0.1 // indirect
51 | k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7 // indirect
52 | k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
53 | k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 // indirect
54 | sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
55 | sigs.k8s.io/randfill v1.0.0 // indirect
56 | sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
57 | sigs.k8s.io/yaml v1.4.0 // indirect
58 | )
59 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
4 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5 | github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
6 | github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
7 | github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU=
8 | github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
9 | github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
10 | github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
11 | github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
12 | github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
13 | github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
14 | github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
15 | github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
16 | github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
17 | github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
18 | github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
19 | github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
20 | github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
21 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
22 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
23 | github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
24 | github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw=
25 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
26 | github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
27 | github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
28 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
29 | github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
30 | github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
31 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
32 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
33 | github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
34 | github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
35 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
36 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
37 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
38 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
39 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
40 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
41 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
42 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
43 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
44 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
45 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
46 | github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
47 | github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
48 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
49 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
50 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
51 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
52 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
53 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
54 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
55 | github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
56 | github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
57 | github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
58 | github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
59 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
60 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
61 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
62 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
63 | github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
64 | github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
65 | github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
66 | github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
67 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
68 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
69 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
70 | github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
71 | github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
72 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
73 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
74 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
75 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
76 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
77 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
78 | github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
79 | github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
80 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
81 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
82 | go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
83 | go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
84 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
85 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
86 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
87 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
88 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
89 | golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
90 | golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
91 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
92 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
93 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
94 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
95 | golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
96 | golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
97 | golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
98 | golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
99 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
100 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
101 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
102 | golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
103 | golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
104 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
105 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
106 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
107 | golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
108 | golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
109 | golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
110 | golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
111 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
112 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
113 | golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
114 | golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
115 | golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
116 | golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
117 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
118 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
119 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
120 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
121 | golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
122 | golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
123 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
124 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
125 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
126 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
127 | google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
128 | google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
129 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
130 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
131 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
132 | gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
133 | gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
134 | gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
135 | gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
136 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
137 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
138 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
139 | k8s.io/api v0.0.0-20250516033257-ffe08c772d5b h1:LwK7OunFjfg9xoa3X/I03H2D1JIlpSbNBIPCowQfo/g=
140 | k8s.io/api v0.0.0-20250516033257-ffe08c772d5b/go.mod h1:xqViZ9G2V/f3Ft2zh5qGrluqUiREXWND/qSDpxuAvUA=
141 | k8s.io/apimachinery v0.0.0-20250516032956-da3bba90543c h1:32RPTmIMyn/cz7/8xxQ4BhJTkvQE1nnzR0YR4ODcVRs=
142 | k8s.io/apimachinery v0.0.0-20250516032956-da3bba90543c/go.mod h1:pJRnLHx/rdGhRBHKhKq/NczIcMw4cPylIe+hff1zJaU=
143 | k8s.io/client-go v0.0.0-20250516033711-025e06660a23 h1:h8NujnSdqX3mcu0g7Tcls57Oy5AX1saqB8+mEX0vkbk=
144 | k8s.io/client-go v0.0.0-20250516033711-025e06660a23/go.mod h1:70YvuiC0JxRnkbXLUExjxqfqaPzpA0RvkM0mUmvQ2Fo=
145 | k8s.io/code-generator v0.0.0-20250516034928-3a6fa0a71475 h1:FAS4zfStDhEUeh9k3ZrTSQP7+ogg/QmQ5f+wtlD4CNQ=
146 | k8s.io/code-generator v0.0.0-20250516034928-3a6fa0a71475/go.mod h1:NQ3v9ly7Z0E0ZIlcYXZgT2TOewfR7LIo4dGKKbB7wXI=
147 | k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7 h1:2OX19X59HxDprNCVrWi6jb7LW1PoqTlYqEq5H2oetog=
148 | k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU=
149 | k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
150 | k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
151 | k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
152 | k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8=
153 | k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 h1:jgJW5IePPXLGB8e/1wvd0Ich9QE97RvvF3a8J3fP/Lg=
154 | k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
155 | sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
156 | sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
157 | sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
158 | sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
159 | sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
160 | sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI=
161 | sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
162 | sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
163 | sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
164 |
--------------------------------------------------------------------------------
/hack/boilerplate.go.txt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 |
--------------------------------------------------------------------------------
/hack/custom-boilerplate.go.txt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright YEAR The Kubernetes sample-controller Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 |
--------------------------------------------------------------------------------
/hack/tools.go:
--------------------------------------------------------------------------------
1 | //go:build tools
2 | // +build tools
3 |
4 | /*
5 | Copyright 2019 The Kubernetes Authors.
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | */
19 |
20 | // This package imports things required by build scripts, to force `go mod` to see them as dependencies
21 | package tools
22 |
23 | import _ "k8s.io/code-generator"
24 |
--------------------------------------------------------------------------------
/hack/update-codegen.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Copyright 2017 The Kubernetes Authors.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | set -o errexit
18 | set -o nounset
19 | set -o pipefail
20 |
21 | SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
22 | CODEGEN_PKG=${CODEGEN_PKG:-$(cd "${SCRIPT_ROOT}"; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../code-generator)}
23 |
24 | source "${CODEGEN_PKG}/kube_codegen.sh"
25 |
26 | THIS_PKG="k8s.io/sample-controller"
27 |
28 | kube::codegen::gen_helpers \
29 | --boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \
30 | "${SCRIPT_ROOT}/pkg/apis"
31 |
32 | kube::codegen::gen_client \
33 | --with-watch \
34 | --output-dir "${SCRIPT_ROOT}/pkg/generated" \
35 | --output-pkg "${THIS_PKG}/pkg/generated" \
36 | --boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \
37 | "${SCRIPT_ROOT}/pkg/apis"
38 |
--------------------------------------------------------------------------------
/hack/verify-codegen.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Copyright 2017 The Kubernetes Authors.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | set -o errexit
18 | set -o nounset
19 | set -o pipefail
20 |
21 | SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
22 | DIFFROOT="${SCRIPT_ROOT}/pkg"
23 | TMP_DIFFROOT="$(mktemp -d -t "$(basename "$0").XXXXXX")/pkg"
24 |
25 | cleanup() {
26 | rm -rf "${TMP_DIFFROOT}"
27 | }
28 | trap "cleanup" EXIT SIGINT
29 |
30 | cleanup
31 |
32 | mkdir -p "${TMP_DIFFROOT}"
33 | cp -a "${DIFFROOT}"/* "${TMP_DIFFROOT}"
34 |
35 | "${SCRIPT_ROOT}/hack/update-codegen.sh"
36 | echo "diffing ${DIFFROOT} against freshly generated codegen"
37 | ret=0
38 | diff -Naupr "${DIFFROOT}" "${TMP_DIFFROOT}" || ret=$?
39 | if [[ $ret -eq 0 ]]; then
40 | echo "${DIFFROOT} up to date."
41 | else
42 | echo "${DIFFROOT} is out of date. Please run hack/update-codegen.sh"
43 | fi
44 | exit $ret
45 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package main
18 |
19 | import (
20 | "flag"
21 | "time"
22 |
23 | kubeinformers "k8s.io/client-go/informers"
24 | "k8s.io/client-go/kubernetes"
25 | "k8s.io/client-go/tools/clientcmd"
26 | "k8s.io/klog/v2"
27 | "k8s.io/sample-controller/pkg/signals"
28 | // Uncomment the following line to load the gcp plugin (only required to authenticate against GKE clusters).
29 | // _ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
30 |
31 | clientset "k8s.io/sample-controller/pkg/generated/clientset/versioned"
32 | informers "k8s.io/sample-controller/pkg/generated/informers/externalversions"
33 | )
34 |
35 | var (
36 | masterURL string
37 | kubeconfig string
38 | )
39 |
40 | func main() {
41 | klog.InitFlags(nil)
42 | flag.Parse()
43 |
44 | // set up signals so we handle the shutdown signal gracefully
45 | ctx := signals.SetupSignalHandler()
46 | logger := klog.FromContext(ctx)
47 |
48 | cfg, err := clientcmd.BuildConfigFromFlags(masterURL, kubeconfig)
49 | if err != nil {
50 | logger.Error(err, "Error building kubeconfig")
51 | klog.FlushAndExit(klog.ExitFlushTimeout, 1)
52 | }
53 |
54 | kubeClient, err := kubernetes.NewForConfig(cfg)
55 | if err != nil {
56 | logger.Error(err, "Error building kubernetes clientset")
57 | klog.FlushAndExit(klog.ExitFlushTimeout, 1)
58 | }
59 |
60 | exampleClient, err := clientset.NewForConfig(cfg)
61 | if err != nil {
62 | logger.Error(err, "Error building kubernetes clientset")
63 | klog.FlushAndExit(klog.ExitFlushTimeout, 1)
64 | }
65 |
66 | kubeInformerFactory := kubeinformers.NewSharedInformerFactory(kubeClient, time.Second*30)
67 | exampleInformerFactory := informers.NewSharedInformerFactory(exampleClient, time.Second*30)
68 |
69 | controller := NewController(ctx, kubeClient, exampleClient,
70 | kubeInformerFactory.Apps().V1().Deployments(),
71 | exampleInformerFactory.Samplecontroller().V1alpha1().Foos())
72 |
73 | // notice that there is no need to run Start methods in a separate goroutine. (i.e. go kubeInformerFactory.Start(ctx.done())
74 | // Start method is non-blocking and runs all registered informers in a dedicated goroutine.
75 | kubeInformerFactory.Start(ctx.Done())
76 | exampleInformerFactory.Start(ctx.Done())
77 |
78 | if err = controller.Run(ctx, 2); err != nil {
79 | logger.Error(err, "Error running controller")
80 | klog.FlushAndExit(klog.ExitFlushTimeout, 1)
81 | }
82 | }
83 |
84 | func init() {
85 | flag.StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
86 | flag.StringVar(&masterURL, "master", "", "The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.")
87 | }
88 |
--------------------------------------------------------------------------------
/pkg/apis/samplecontroller/register.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package samplecontroller
18 |
19 | // GroupName is the group name used in this package
20 | const (
21 | GroupName = "samplecontroller.k8s.io"
22 | )
23 |
--------------------------------------------------------------------------------
/pkg/apis/samplecontroller/v1alpha1/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // +k8s:deepcopy-gen=package
18 | // +groupName=samplecontroller.k8s.io
19 |
20 | // Package v1alpha1 is the v1alpha1 version of the API.
21 | package v1alpha1
22 |
--------------------------------------------------------------------------------
/pkg/apis/samplecontroller/v1alpha1/register.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package v1alpha1
18 |
19 | import (
20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21 | "k8s.io/apimachinery/pkg/runtime"
22 | "k8s.io/apimachinery/pkg/runtime/schema"
23 |
24 | samplecontroller "k8s.io/sample-controller/pkg/apis/samplecontroller"
25 | )
26 |
27 | // SchemeGroupVersion is group version used to register these objects
28 | var SchemeGroupVersion = schema.GroupVersion{Group: samplecontroller.GroupName, Version: "v1alpha1"}
29 |
30 | // Kind takes an unqualified kind and returns back a Group qualified GroupKind
31 | func Kind(kind string) schema.GroupKind {
32 | return SchemeGroupVersion.WithKind(kind).GroupKind()
33 | }
34 |
35 | // Resource takes an unqualified resource and returns a Group qualified GroupResource
36 | func Resource(resource string) schema.GroupResource {
37 | return SchemeGroupVersion.WithResource(resource).GroupResource()
38 | }
39 |
40 | var (
41 | // SchemeBuilder initializes a scheme builder
42 | SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
43 | // AddToScheme is a global function that registers this API group & version to a scheme
44 | AddToScheme = SchemeBuilder.AddToScheme
45 | )
46 |
47 | // Adds the list of known types to Scheme.
48 | func addKnownTypes(scheme *runtime.Scheme) error {
49 | scheme.AddKnownTypes(SchemeGroupVersion,
50 | &Foo{},
51 | &FooList{},
52 | )
53 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
54 | return nil
55 | }
56 |
--------------------------------------------------------------------------------
/pkg/apis/samplecontroller/v1alpha1/types.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package v1alpha1
18 |
19 | import (
20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21 | )
22 |
23 | // +genclient
24 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
25 |
26 | // Foo is a specification for a Foo resource
27 | type Foo struct {
28 | metav1.TypeMeta `json:",inline"`
29 | metav1.ObjectMeta `json:"metadata,omitempty"`
30 |
31 | Spec FooSpec `json:"spec"`
32 | Status FooStatus `json:"status"`
33 | }
34 |
35 | // FooSpec is the spec for a Foo resource
36 | type FooSpec struct {
37 | DeploymentName string `json:"deploymentName"`
38 | Replicas *int32 `json:"replicas"`
39 | }
40 |
41 | // FooStatus is the status for a Foo resource
42 | type FooStatus struct {
43 | AvailableReplicas int32 `json:"availableReplicas"`
44 | }
45 |
46 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
47 |
48 | // FooList is a list of Foo resources
49 | type FooList struct {
50 | metav1.TypeMeta `json:",inline"`
51 | metav1.ListMeta `json:"metadata"`
52 |
53 | Items []Foo `json:"items"`
54 | }
55 |
--------------------------------------------------------------------------------
/pkg/apis/samplecontroller/v1alpha1/zz_generated.deepcopy.go:
--------------------------------------------------------------------------------
1 | //go:build !ignore_autogenerated
2 | // +build !ignore_autogenerated
3 |
4 | /*
5 | Copyright The Kubernetes Authors.
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | */
19 |
20 | // Code generated by deepcopy-gen. DO NOT EDIT.
21 |
22 | package v1alpha1
23 |
24 | import (
25 | runtime "k8s.io/apimachinery/pkg/runtime"
26 | )
27 |
28 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
29 | func (in *Foo) DeepCopyInto(out *Foo) {
30 | *out = *in
31 | out.TypeMeta = in.TypeMeta
32 | in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
33 | in.Spec.DeepCopyInto(&out.Spec)
34 | out.Status = in.Status
35 | return
36 | }
37 |
38 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Foo.
39 | func (in *Foo) DeepCopy() *Foo {
40 | if in == nil {
41 | return nil
42 | }
43 | out := new(Foo)
44 | in.DeepCopyInto(out)
45 | return out
46 | }
47 |
48 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
49 | func (in *Foo) DeepCopyObject() runtime.Object {
50 | if c := in.DeepCopy(); c != nil {
51 | return c
52 | }
53 | return nil
54 | }
55 |
56 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
57 | func (in *FooList) DeepCopyInto(out *FooList) {
58 | *out = *in
59 | out.TypeMeta = in.TypeMeta
60 | in.ListMeta.DeepCopyInto(&out.ListMeta)
61 | if in.Items != nil {
62 | in, out := &in.Items, &out.Items
63 | *out = make([]Foo, len(*in))
64 | for i := range *in {
65 | (*in)[i].DeepCopyInto(&(*out)[i])
66 | }
67 | }
68 | return
69 | }
70 |
71 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FooList.
72 | func (in *FooList) DeepCopy() *FooList {
73 | if in == nil {
74 | return nil
75 | }
76 | out := new(FooList)
77 | in.DeepCopyInto(out)
78 | return out
79 | }
80 |
81 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
82 | func (in *FooList) DeepCopyObject() runtime.Object {
83 | if c := in.DeepCopy(); c != nil {
84 | return c
85 | }
86 | return nil
87 | }
88 |
89 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
90 | func (in *FooSpec) DeepCopyInto(out *FooSpec) {
91 | *out = *in
92 | if in.Replicas != nil {
93 | in, out := &in.Replicas, &out.Replicas
94 | *out = new(int32)
95 | **out = **in
96 | }
97 | return
98 | }
99 |
100 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FooSpec.
101 | func (in *FooSpec) DeepCopy() *FooSpec {
102 | if in == nil {
103 | return nil
104 | }
105 | out := new(FooSpec)
106 | in.DeepCopyInto(out)
107 | return out
108 | }
109 |
110 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
111 | func (in *FooStatus) DeepCopyInto(out *FooStatus) {
112 | *out = *in
113 | return
114 | }
115 |
116 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FooStatus.
117 | func (in *FooStatus) DeepCopy() *FooStatus {
118 | if in == nil {
119 | return nil
120 | }
121 | out := new(FooStatus)
122 | in.DeepCopyInto(out)
123 | return out
124 | }
125 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/clientset.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package versioned
20 |
21 | import (
22 | fmt "fmt"
23 | http "net/http"
24 |
25 | discovery "k8s.io/client-go/discovery"
26 | rest "k8s.io/client-go/rest"
27 | flowcontrol "k8s.io/client-go/util/flowcontrol"
28 | samplecontrollerv1alpha1 "k8s.io/sample-controller/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1"
29 | )
30 |
31 | type Interface interface {
32 | Discovery() discovery.DiscoveryInterface
33 | SamplecontrollerV1alpha1() samplecontrollerv1alpha1.SamplecontrollerV1alpha1Interface
34 | }
35 |
36 | // Clientset contains the clients for groups.
37 | type Clientset struct {
38 | *discovery.DiscoveryClient
39 | samplecontrollerV1alpha1 *samplecontrollerv1alpha1.SamplecontrollerV1alpha1Client
40 | }
41 |
42 | // SamplecontrollerV1alpha1 retrieves the SamplecontrollerV1alpha1Client
43 | func (c *Clientset) SamplecontrollerV1alpha1() samplecontrollerv1alpha1.SamplecontrollerV1alpha1Interface {
44 | return c.samplecontrollerV1alpha1
45 | }
46 |
47 | // Discovery retrieves the DiscoveryClient
48 | func (c *Clientset) Discovery() discovery.DiscoveryInterface {
49 | if c == nil {
50 | return nil
51 | }
52 | return c.DiscoveryClient
53 | }
54 |
55 | // NewForConfig creates a new Clientset for the given config.
56 | // If config's RateLimiter is not set and QPS and Burst are acceptable,
57 | // NewForConfig will generate a rate-limiter in configShallowCopy.
58 | // NewForConfig is equivalent to NewForConfigAndClient(c, httpClient),
59 | // where httpClient was generated with rest.HTTPClientFor(c).
60 | func NewForConfig(c *rest.Config) (*Clientset, error) {
61 | configShallowCopy := *c
62 |
63 | if configShallowCopy.UserAgent == "" {
64 | configShallowCopy.UserAgent = rest.DefaultKubernetesUserAgent()
65 | }
66 |
67 | // share the transport between all clients
68 | httpClient, err := rest.HTTPClientFor(&configShallowCopy)
69 | if err != nil {
70 | return nil, err
71 | }
72 |
73 | return NewForConfigAndClient(&configShallowCopy, httpClient)
74 | }
75 |
76 | // NewForConfigAndClient creates a new Clientset for the given config and http client.
77 | // Note the http client provided takes precedence over the configured transport values.
78 | // If config's RateLimiter is not set and QPS and Burst are acceptable,
79 | // NewForConfigAndClient will generate a rate-limiter in configShallowCopy.
80 | func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) {
81 | configShallowCopy := *c
82 | if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 {
83 | if configShallowCopy.Burst <= 0 {
84 | return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0")
85 | }
86 | configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst)
87 | }
88 |
89 | var cs Clientset
90 | var err error
91 | cs.samplecontrollerV1alpha1, err = samplecontrollerv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient)
92 | if err != nil {
93 | return nil, err
94 | }
95 |
96 | cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient)
97 | if err != nil {
98 | return nil, err
99 | }
100 | return &cs, nil
101 | }
102 |
103 | // NewForConfigOrDie creates a new Clientset for the given config and
104 | // panics if there is an error in the config.
105 | func NewForConfigOrDie(c *rest.Config) *Clientset {
106 | cs, err := NewForConfig(c)
107 | if err != nil {
108 | panic(err)
109 | }
110 | return cs
111 | }
112 |
113 | // New creates a new Clientset for the given RESTClient.
114 | func New(c rest.Interface) *Clientset {
115 | var cs Clientset
116 | cs.samplecontrollerV1alpha1 = samplecontrollerv1alpha1.New(c)
117 |
118 | cs.DiscoveryClient = discovery.NewDiscoveryClient(c)
119 | return &cs
120 | }
121 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/fake/clientset_generated.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package fake
20 |
21 | import (
22 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23 | "k8s.io/apimachinery/pkg/runtime"
24 | "k8s.io/apimachinery/pkg/watch"
25 | "k8s.io/client-go/discovery"
26 | fakediscovery "k8s.io/client-go/discovery/fake"
27 | "k8s.io/client-go/testing"
28 | clientset "k8s.io/sample-controller/pkg/generated/clientset/versioned"
29 | samplecontrollerv1alpha1 "k8s.io/sample-controller/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1"
30 | fakesamplecontrollerv1alpha1 "k8s.io/sample-controller/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/fake"
31 | )
32 |
33 | // NewSimpleClientset returns a clientset that will respond with the provided objects.
34 | // It's backed by a very simple object tracker that processes creates, updates and deletions as-is,
35 | // without applying any field management, validations and/or defaults. It shouldn't be considered a replacement
36 | // for a real clientset and is mostly useful in simple unit tests.
37 | //
38 | // DEPRECATED: NewClientset replaces this with support for field management, which significantly improves
39 | // server side apply testing. NewClientset is only available when apply configurations are generated (e.g.
40 | // via --with-applyconfig).
41 | func NewSimpleClientset(objects ...runtime.Object) *Clientset {
42 | o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder())
43 | for _, obj := range objects {
44 | if err := o.Add(obj); err != nil {
45 | panic(err)
46 | }
47 | }
48 |
49 | cs := &Clientset{tracker: o}
50 | cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake}
51 | cs.AddReactor("*", "*", testing.ObjectReaction(o))
52 | cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) {
53 | var opts metav1.ListOptions
54 | if watchActcion, ok := action.(testing.WatchActionImpl); ok {
55 | opts = watchActcion.ListOptions
56 | }
57 | gvr := action.GetResource()
58 | ns := action.GetNamespace()
59 | watch, err := o.Watch(gvr, ns, opts)
60 | if err != nil {
61 | return false, nil, err
62 | }
63 | return true, watch, nil
64 | })
65 |
66 | return cs
67 | }
68 |
69 | // Clientset implements clientset.Interface. Meant to be embedded into a
70 | // struct to get a default implementation. This makes faking out just the method
71 | // you want to test easier.
72 | type Clientset struct {
73 | testing.Fake
74 | discovery *fakediscovery.FakeDiscovery
75 | tracker testing.ObjectTracker
76 | }
77 |
78 | func (c *Clientset) Discovery() discovery.DiscoveryInterface {
79 | return c.discovery
80 | }
81 |
82 | func (c *Clientset) Tracker() testing.ObjectTracker {
83 | return c.tracker
84 | }
85 |
86 | var (
87 | _ clientset.Interface = &Clientset{}
88 | _ testing.FakeClient = &Clientset{}
89 | )
90 |
91 | // SamplecontrollerV1alpha1 retrieves the SamplecontrollerV1alpha1Client
92 | func (c *Clientset) SamplecontrollerV1alpha1() samplecontrollerv1alpha1.SamplecontrollerV1alpha1Interface {
93 | return &fakesamplecontrollerv1alpha1.FakeSamplecontrollerV1alpha1{Fake: &c.Fake}
94 | }
95 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/fake/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | // This package has the automatically generated fake clientset.
20 | package fake
21 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/fake/register.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package fake
20 |
21 | import (
22 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23 | runtime "k8s.io/apimachinery/pkg/runtime"
24 | schema "k8s.io/apimachinery/pkg/runtime/schema"
25 | serializer "k8s.io/apimachinery/pkg/runtime/serializer"
26 | utilruntime "k8s.io/apimachinery/pkg/util/runtime"
27 | samplecontrollerv1alpha1 "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1"
28 | )
29 |
30 | var scheme = runtime.NewScheme()
31 | var codecs = serializer.NewCodecFactory(scheme)
32 |
33 | var localSchemeBuilder = runtime.SchemeBuilder{
34 | samplecontrollerv1alpha1.AddToScheme,
35 | }
36 |
37 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition
38 | // of clientsets, like in:
39 | //
40 | // import (
41 | // "k8s.io/client-go/kubernetes"
42 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme"
43 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
44 | // )
45 | //
46 | // kclientset, _ := kubernetes.NewForConfig(c)
47 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
48 | //
49 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
50 | // correctly.
51 | var AddToScheme = localSchemeBuilder.AddToScheme
52 |
53 | func init() {
54 | v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"})
55 | utilruntime.Must(AddToScheme(scheme))
56 | }
57 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/scheme/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | // This package contains the scheme of the automatically generated clientset.
20 | package scheme
21 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/scheme/register.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package scheme
20 |
21 | import (
22 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23 | runtime "k8s.io/apimachinery/pkg/runtime"
24 | schema "k8s.io/apimachinery/pkg/runtime/schema"
25 | serializer "k8s.io/apimachinery/pkg/runtime/serializer"
26 | utilruntime "k8s.io/apimachinery/pkg/util/runtime"
27 | samplecontrollerv1alpha1 "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1"
28 | )
29 |
30 | var Scheme = runtime.NewScheme()
31 | var Codecs = serializer.NewCodecFactory(Scheme)
32 | var ParameterCodec = runtime.NewParameterCodec(Scheme)
33 | var localSchemeBuilder = runtime.SchemeBuilder{
34 | samplecontrollerv1alpha1.AddToScheme,
35 | }
36 |
37 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition
38 | // of clientsets, like in:
39 | //
40 | // import (
41 | // "k8s.io/client-go/kubernetes"
42 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme"
43 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
44 | // )
45 | //
46 | // kclientset, _ := kubernetes.NewForConfig(c)
47 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
48 | //
49 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
50 | // correctly.
51 | var AddToScheme = localSchemeBuilder.AddToScheme
52 |
53 | func init() {
54 | v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
55 | utilruntime.Must(AddToScheme(Scheme))
56 | }
57 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | // This package has the automatically generated typed clients.
20 | package v1alpha1
21 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/fake/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | // Package fake has the automatically generated clients.
20 | package fake
21 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/fake/fake_foo.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package fake
20 |
21 | import (
22 | gentype "k8s.io/client-go/gentype"
23 | v1alpha1 "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1"
24 | samplecontrollerv1alpha1 "k8s.io/sample-controller/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1"
25 | )
26 |
27 | // fakeFoos implements FooInterface
28 | type fakeFoos struct {
29 | *gentype.FakeClientWithList[*v1alpha1.Foo, *v1alpha1.FooList]
30 | Fake *FakeSamplecontrollerV1alpha1
31 | }
32 |
33 | func newFakeFoos(fake *FakeSamplecontrollerV1alpha1, namespace string) samplecontrollerv1alpha1.FooInterface {
34 | return &fakeFoos{
35 | gentype.NewFakeClientWithList[*v1alpha1.Foo, *v1alpha1.FooList](
36 | fake.Fake,
37 | namespace,
38 | v1alpha1.SchemeGroupVersion.WithResource("foos"),
39 | v1alpha1.SchemeGroupVersion.WithKind("Foo"),
40 | func() *v1alpha1.Foo { return &v1alpha1.Foo{} },
41 | func() *v1alpha1.FooList { return &v1alpha1.FooList{} },
42 | func(dst, src *v1alpha1.FooList) { dst.ListMeta = src.ListMeta },
43 | func(list *v1alpha1.FooList) []*v1alpha1.Foo { return gentype.ToPointerSlice(list.Items) },
44 | func(list *v1alpha1.FooList, items []*v1alpha1.Foo) { list.Items = gentype.FromPointerSlice(items) },
45 | ),
46 | fake,
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/fake/fake_samplecontroller_client.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package fake
20 |
21 | import (
22 | rest "k8s.io/client-go/rest"
23 | testing "k8s.io/client-go/testing"
24 | v1alpha1 "k8s.io/sample-controller/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1"
25 | )
26 |
27 | type FakeSamplecontrollerV1alpha1 struct {
28 | *testing.Fake
29 | }
30 |
31 | func (c *FakeSamplecontrollerV1alpha1) Foos(namespace string) v1alpha1.FooInterface {
32 | return newFakeFoos(c, namespace)
33 | }
34 |
35 | // RESTClient returns a RESTClient that is used to communicate
36 | // with API server by this client implementation.
37 | func (c *FakeSamplecontrollerV1alpha1) RESTClient() rest.Interface {
38 | var ret *rest.RESTClient
39 | return ret
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/foo.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package v1alpha1
20 |
21 | import (
22 | context "context"
23 |
24 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25 | types "k8s.io/apimachinery/pkg/types"
26 | watch "k8s.io/apimachinery/pkg/watch"
27 | gentype "k8s.io/client-go/gentype"
28 | samplecontrollerv1alpha1 "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1"
29 | scheme "k8s.io/sample-controller/pkg/generated/clientset/versioned/scheme"
30 | )
31 |
32 | // FoosGetter has a method to return a FooInterface.
33 | // A group's client should implement this interface.
34 | type FoosGetter interface {
35 | Foos(namespace string) FooInterface
36 | }
37 |
38 | // FooInterface has methods to work with Foo resources.
39 | type FooInterface interface {
40 | Create(ctx context.Context, foo *samplecontrollerv1alpha1.Foo, opts v1.CreateOptions) (*samplecontrollerv1alpha1.Foo, error)
41 | Update(ctx context.Context, foo *samplecontrollerv1alpha1.Foo, opts v1.UpdateOptions) (*samplecontrollerv1alpha1.Foo, error)
42 | // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
43 | UpdateStatus(ctx context.Context, foo *samplecontrollerv1alpha1.Foo, opts v1.UpdateOptions) (*samplecontrollerv1alpha1.Foo, error)
44 | Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
45 | DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
46 | Get(ctx context.Context, name string, opts v1.GetOptions) (*samplecontrollerv1alpha1.Foo, error)
47 | List(ctx context.Context, opts v1.ListOptions) (*samplecontrollerv1alpha1.FooList, error)
48 | Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
49 | Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *samplecontrollerv1alpha1.Foo, err error)
50 | FooExpansion
51 | }
52 |
53 | // foos implements FooInterface
54 | type foos struct {
55 | *gentype.ClientWithList[*samplecontrollerv1alpha1.Foo, *samplecontrollerv1alpha1.FooList]
56 | }
57 |
58 | // newFoos returns a Foos
59 | func newFoos(c *SamplecontrollerV1alpha1Client, namespace string) *foos {
60 | return &foos{
61 | gentype.NewClientWithList[*samplecontrollerv1alpha1.Foo, *samplecontrollerv1alpha1.FooList](
62 | "foos",
63 | c.RESTClient(),
64 | scheme.ParameterCodec,
65 | namespace,
66 | func() *samplecontrollerv1alpha1.Foo { return &samplecontrollerv1alpha1.Foo{} },
67 | func() *samplecontrollerv1alpha1.FooList { return &samplecontrollerv1alpha1.FooList{} },
68 | ),
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/generated_expansion.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package v1alpha1
20 |
21 | type FooExpansion interface{}
22 |
--------------------------------------------------------------------------------
/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/samplecontroller_client.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package v1alpha1
20 |
21 | import (
22 | http "net/http"
23 |
24 | rest "k8s.io/client-go/rest"
25 | samplecontrollerv1alpha1 "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1"
26 | scheme "k8s.io/sample-controller/pkg/generated/clientset/versioned/scheme"
27 | )
28 |
29 | type SamplecontrollerV1alpha1Interface interface {
30 | RESTClient() rest.Interface
31 | FoosGetter
32 | }
33 |
34 | // SamplecontrollerV1alpha1Client is used to interact with features provided by the samplecontroller.k8s.io group.
35 | type SamplecontrollerV1alpha1Client struct {
36 | restClient rest.Interface
37 | }
38 |
39 | func (c *SamplecontrollerV1alpha1Client) Foos(namespace string) FooInterface {
40 | return newFoos(c, namespace)
41 | }
42 |
43 | // NewForConfig creates a new SamplecontrollerV1alpha1Client for the given config.
44 | // NewForConfig is equivalent to NewForConfigAndClient(c, httpClient),
45 | // where httpClient was generated with rest.HTTPClientFor(c).
46 | func NewForConfig(c *rest.Config) (*SamplecontrollerV1alpha1Client, error) {
47 | config := *c
48 | setConfigDefaults(&config)
49 | httpClient, err := rest.HTTPClientFor(&config)
50 | if err != nil {
51 | return nil, err
52 | }
53 | return NewForConfigAndClient(&config, httpClient)
54 | }
55 |
56 | // NewForConfigAndClient creates a new SamplecontrollerV1alpha1Client for the given config and http client.
57 | // Note the http client provided takes precedence over the configured transport values.
58 | func NewForConfigAndClient(c *rest.Config, h *http.Client) (*SamplecontrollerV1alpha1Client, error) {
59 | config := *c
60 | setConfigDefaults(&config)
61 | client, err := rest.RESTClientForConfigAndClient(&config, h)
62 | if err != nil {
63 | return nil, err
64 | }
65 | return &SamplecontrollerV1alpha1Client{client}, nil
66 | }
67 |
68 | // NewForConfigOrDie creates a new SamplecontrollerV1alpha1Client for the given config and
69 | // panics if there is an error in the config.
70 | func NewForConfigOrDie(c *rest.Config) *SamplecontrollerV1alpha1Client {
71 | client, err := NewForConfig(c)
72 | if err != nil {
73 | panic(err)
74 | }
75 | return client
76 | }
77 |
78 | // New creates a new SamplecontrollerV1alpha1Client for the given RESTClient.
79 | func New(c rest.Interface) *SamplecontrollerV1alpha1Client {
80 | return &SamplecontrollerV1alpha1Client{c}
81 | }
82 |
83 | func setConfigDefaults(config *rest.Config) {
84 | gv := samplecontrollerv1alpha1.SchemeGroupVersion
85 | config.GroupVersion = &gv
86 | config.APIPath = "/apis"
87 | config.NegotiatedSerializer = rest.CodecFactoryForGeneratedClient(scheme.Scheme, scheme.Codecs).WithoutConversion()
88 |
89 | if config.UserAgent == "" {
90 | config.UserAgent = rest.DefaultKubernetesUserAgent()
91 | }
92 | }
93 |
94 | // RESTClient returns a RESTClient that is used to communicate
95 | // with API server by this client implementation.
96 | func (c *SamplecontrollerV1alpha1Client) RESTClient() rest.Interface {
97 | if c == nil {
98 | return nil
99 | }
100 | return c.restClient
101 | }
102 |
--------------------------------------------------------------------------------
/pkg/generated/informers/externalversions/factory.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by informer-gen. DO NOT EDIT.
18 |
19 | package externalversions
20 |
21 | import (
22 | reflect "reflect"
23 | sync "sync"
24 | time "time"
25 |
26 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27 | runtime "k8s.io/apimachinery/pkg/runtime"
28 | schema "k8s.io/apimachinery/pkg/runtime/schema"
29 | cache "k8s.io/client-go/tools/cache"
30 | versioned "k8s.io/sample-controller/pkg/generated/clientset/versioned"
31 | internalinterfaces "k8s.io/sample-controller/pkg/generated/informers/externalversions/internalinterfaces"
32 | samplecontroller "k8s.io/sample-controller/pkg/generated/informers/externalversions/samplecontroller"
33 | )
34 |
35 | // SharedInformerOption defines the functional option type for SharedInformerFactory.
36 | type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory
37 |
38 | type sharedInformerFactory struct {
39 | client versioned.Interface
40 | namespace string
41 | tweakListOptions internalinterfaces.TweakListOptionsFunc
42 | lock sync.Mutex
43 | defaultResync time.Duration
44 | customResync map[reflect.Type]time.Duration
45 | transform cache.TransformFunc
46 |
47 | informers map[reflect.Type]cache.SharedIndexInformer
48 | // startedInformers is used for tracking which informers have been started.
49 | // This allows Start() to be called multiple times safely.
50 | startedInformers map[reflect.Type]bool
51 | // wg tracks how many goroutines were started.
52 | wg sync.WaitGroup
53 | // shuttingDown is true when Shutdown has been called. It may still be running
54 | // because it needs to wait for goroutines.
55 | shuttingDown bool
56 | }
57 |
58 | // WithCustomResyncConfig sets a custom resync period for the specified informer types.
59 | func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption {
60 | return func(factory *sharedInformerFactory) *sharedInformerFactory {
61 | for k, v := range resyncConfig {
62 | factory.customResync[reflect.TypeOf(k)] = v
63 | }
64 | return factory
65 | }
66 | }
67 |
68 | // WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory.
69 | func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption {
70 | return func(factory *sharedInformerFactory) *sharedInformerFactory {
71 | factory.tweakListOptions = tweakListOptions
72 | return factory
73 | }
74 | }
75 |
76 | // WithNamespace limits the SharedInformerFactory to the specified namespace.
77 | func WithNamespace(namespace string) SharedInformerOption {
78 | return func(factory *sharedInformerFactory) *sharedInformerFactory {
79 | factory.namespace = namespace
80 | return factory
81 | }
82 | }
83 |
84 | // WithTransform sets a transform on all informers.
85 | func WithTransform(transform cache.TransformFunc) SharedInformerOption {
86 | return func(factory *sharedInformerFactory) *sharedInformerFactory {
87 | factory.transform = transform
88 | return factory
89 | }
90 | }
91 |
92 | // NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces.
93 | func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory {
94 | return NewSharedInformerFactoryWithOptions(client, defaultResync)
95 | }
96 |
97 | // NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory.
98 | // Listers obtained via this SharedInformerFactory will be subject to the same filters
99 | // as specified here.
100 | // Deprecated: Please use NewSharedInformerFactoryWithOptions instead
101 | func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory {
102 | return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions))
103 | }
104 |
105 | // NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options.
106 | func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory {
107 | factory := &sharedInformerFactory{
108 | client: client,
109 | namespace: v1.NamespaceAll,
110 | defaultResync: defaultResync,
111 | informers: make(map[reflect.Type]cache.SharedIndexInformer),
112 | startedInformers: make(map[reflect.Type]bool),
113 | customResync: make(map[reflect.Type]time.Duration),
114 | }
115 |
116 | // Apply all options
117 | for _, opt := range options {
118 | factory = opt(factory)
119 | }
120 |
121 | return factory
122 | }
123 |
124 | func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) {
125 | f.lock.Lock()
126 | defer f.lock.Unlock()
127 |
128 | if f.shuttingDown {
129 | return
130 | }
131 |
132 | for informerType, informer := range f.informers {
133 | if !f.startedInformers[informerType] {
134 | f.wg.Add(1)
135 | // We need a new variable in each loop iteration,
136 | // otherwise the goroutine would use the loop variable
137 | // and that keeps changing.
138 | informer := informer
139 | go func() {
140 | defer f.wg.Done()
141 | informer.Run(stopCh)
142 | }()
143 | f.startedInformers[informerType] = true
144 | }
145 | }
146 | }
147 |
148 | func (f *sharedInformerFactory) Shutdown() {
149 | f.lock.Lock()
150 | f.shuttingDown = true
151 | f.lock.Unlock()
152 |
153 | // Will return immediately if there is nothing to wait for.
154 | f.wg.Wait()
155 | }
156 |
157 | func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool {
158 | informers := func() map[reflect.Type]cache.SharedIndexInformer {
159 | f.lock.Lock()
160 | defer f.lock.Unlock()
161 |
162 | informers := map[reflect.Type]cache.SharedIndexInformer{}
163 | for informerType, informer := range f.informers {
164 | if f.startedInformers[informerType] {
165 | informers[informerType] = informer
166 | }
167 | }
168 | return informers
169 | }()
170 |
171 | res := map[reflect.Type]bool{}
172 | for informType, informer := range informers {
173 | res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced)
174 | }
175 | return res
176 | }
177 |
178 | // InformerFor returns the SharedIndexInformer for obj using an internal
179 | // client.
180 | func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer {
181 | f.lock.Lock()
182 | defer f.lock.Unlock()
183 |
184 | informerType := reflect.TypeOf(obj)
185 | informer, exists := f.informers[informerType]
186 | if exists {
187 | return informer
188 | }
189 |
190 | resyncPeriod, exists := f.customResync[informerType]
191 | if !exists {
192 | resyncPeriod = f.defaultResync
193 | }
194 |
195 | informer = newFunc(f.client, resyncPeriod)
196 | informer.SetTransform(f.transform)
197 | f.informers[informerType] = informer
198 |
199 | return informer
200 | }
201 |
202 | // SharedInformerFactory provides shared informers for resources in all known
203 | // API group versions.
204 | //
205 | // It is typically used like this:
206 | //
207 | // ctx, cancel := context.Background()
208 | // defer cancel()
209 | // factory := NewSharedInformerFactory(client, resyncPeriod)
210 | // defer factory.WaitForStop() // Returns immediately if nothing was started.
211 | // genericInformer := factory.ForResource(resource)
212 | // typedInformer := factory.SomeAPIGroup().V1().SomeType()
213 | // factory.Start(ctx.Done()) // Start processing these informers.
214 | // synced := factory.WaitForCacheSync(ctx.Done())
215 | // for v, ok := range synced {
216 | // if !ok {
217 | // fmt.Fprintf(os.Stderr, "caches failed to sync: %v", v)
218 | // return
219 | // }
220 | // }
221 | //
222 | // // Creating informers can also be created after Start, but then
223 | // // Start must be called again:
224 | // anotherGenericInformer := factory.ForResource(resource)
225 | // factory.Start(ctx.Done())
226 | type SharedInformerFactory interface {
227 | internalinterfaces.SharedInformerFactory
228 |
229 | // Start initializes all requested informers. They are handled in goroutines
230 | // which run until the stop channel gets closed.
231 | // Warning: Start does not block. When run in a go-routine, it will race with a later WaitForCacheSync.
232 | Start(stopCh <-chan struct{})
233 |
234 | // Shutdown marks a factory as shutting down. At that point no new
235 | // informers can be started anymore and Start will return without
236 | // doing anything.
237 | //
238 | // In addition, Shutdown blocks until all goroutines have terminated. For that
239 | // to happen, the close channel(s) that they were started with must be closed,
240 | // either before Shutdown gets called or while it is waiting.
241 | //
242 | // Shutdown may be called multiple times, even concurrently. All such calls will
243 | // block until all goroutines have terminated.
244 | Shutdown()
245 |
246 | // WaitForCacheSync blocks until all started informers' caches were synced
247 | // or the stop channel gets closed.
248 | WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool
249 |
250 | // ForResource gives generic access to a shared informer of the matching type.
251 | ForResource(resource schema.GroupVersionResource) (GenericInformer, error)
252 |
253 | // InformerFor returns the SharedIndexInformer for obj using an internal
254 | // client.
255 | InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer
256 |
257 | Samplecontroller() samplecontroller.Interface
258 | }
259 |
260 | func (f *sharedInformerFactory) Samplecontroller() samplecontroller.Interface {
261 | return samplecontroller.New(f, f.namespace, f.tweakListOptions)
262 | }
263 |
--------------------------------------------------------------------------------
/pkg/generated/informers/externalversions/generic.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by informer-gen. DO NOT EDIT.
18 |
19 | package externalversions
20 |
21 | import (
22 | fmt "fmt"
23 |
24 | schema "k8s.io/apimachinery/pkg/runtime/schema"
25 | cache "k8s.io/client-go/tools/cache"
26 | v1alpha1 "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1"
27 | )
28 |
29 | // GenericInformer is type of SharedIndexInformer which will locate and delegate to other
30 | // sharedInformers based on type
31 | type GenericInformer interface {
32 | Informer() cache.SharedIndexInformer
33 | Lister() cache.GenericLister
34 | }
35 |
36 | type genericInformer struct {
37 | informer cache.SharedIndexInformer
38 | resource schema.GroupResource
39 | }
40 |
41 | // Informer returns the SharedIndexInformer.
42 | func (f *genericInformer) Informer() cache.SharedIndexInformer {
43 | return f.informer
44 | }
45 |
46 | // Lister returns the GenericLister.
47 | func (f *genericInformer) Lister() cache.GenericLister {
48 | return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource)
49 | }
50 |
51 | // ForResource gives generic access to a shared informer of the matching type
52 | // TODO extend this to unknown resources with a client pool
53 | func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) {
54 | switch resource {
55 | // Group=samplecontroller.k8s.io, Version=v1alpha1
56 | case v1alpha1.SchemeGroupVersion.WithResource("foos"):
57 | return &genericInformer{resource: resource.GroupResource(), informer: f.Samplecontroller().V1alpha1().Foos().Informer()}, nil
58 |
59 | }
60 |
61 | return nil, fmt.Errorf("no informer found for %v", resource)
62 | }
63 |
--------------------------------------------------------------------------------
/pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by informer-gen. DO NOT EDIT.
18 |
19 | package internalinterfaces
20 |
21 | import (
22 | time "time"
23 |
24 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25 | runtime "k8s.io/apimachinery/pkg/runtime"
26 | cache "k8s.io/client-go/tools/cache"
27 | versioned "k8s.io/sample-controller/pkg/generated/clientset/versioned"
28 | )
29 |
30 | // NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer.
31 | type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer
32 |
33 | // SharedInformerFactory a small interface to allow for adding an informer without an import cycle
34 | type SharedInformerFactory interface {
35 | Start(stopCh <-chan struct{})
36 | InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer
37 | }
38 |
39 | // TweakListOptionsFunc is a function that transforms a v1.ListOptions.
40 | type TweakListOptionsFunc func(*v1.ListOptions)
41 |
--------------------------------------------------------------------------------
/pkg/generated/informers/externalversions/samplecontroller/interface.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by informer-gen. DO NOT EDIT.
18 |
19 | package samplecontroller
20 |
21 | import (
22 | internalinterfaces "k8s.io/sample-controller/pkg/generated/informers/externalversions/internalinterfaces"
23 | v1alpha1 "k8s.io/sample-controller/pkg/generated/informers/externalversions/samplecontroller/v1alpha1"
24 | )
25 |
26 | // Interface provides access to each of this group's versions.
27 | type Interface interface {
28 | // V1alpha1 provides access to shared informers for resources in V1alpha1.
29 | V1alpha1() v1alpha1.Interface
30 | }
31 |
32 | type group struct {
33 | factory internalinterfaces.SharedInformerFactory
34 | namespace string
35 | tweakListOptions internalinterfaces.TweakListOptionsFunc
36 | }
37 |
38 | // New returns a new Interface.
39 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
40 | return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
41 | }
42 |
43 | // V1alpha1 returns a new v1alpha1.Interface.
44 | func (g *group) V1alpha1() v1alpha1.Interface {
45 | return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions)
46 | }
47 |
--------------------------------------------------------------------------------
/pkg/generated/informers/externalversions/samplecontroller/v1alpha1/foo.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by informer-gen. DO NOT EDIT.
18 |
19 | package v1alpha1
20 |
21 | import (
22 | context "context"
23 | time "time"
24 |
25 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26 | runtime "k8s.io/apimachinery/pkg/runtime"
27 | watch "k8s.io/apimachinery/pkg/watch"
28 | cache "k8s.io/client-go/tools/cache"
29 | apissamplecontrollerv1alpha1 "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1"
30 | versioned "k8s.io/sample-controller/pkg/generated/clientset/versioned"
31 | internalinterfaces "k8s.io/sample-controller/pkg/generated/informers/externalversions/internalinterfaces"
32 | samplecontrollerv1alpha1 "k8s.io/sample-controller/pkg/generated/listers/samplecontroller/v1alpha1"
33 | )
34 |
35 | // FooInformer provides access to a shared informer and lister for
36 | // Foos.
37 | type FooInformer interface {
38 | Informer() cache.SharedIndexInformer
39 | Lister() samplecontrollerv1alpha1.FooLister
40 | }
41 |
42 | type fooInformer struct {
43 | factory internalinterfaces.SharedInformerFactory
44 | tweakListOptions internalinterfaces.TweakListOptionsFunc
45 | namespace string
46 | }
47 |
48 | // NewFooInformer constructs a new informer for Foo type.
49 | // Always prefer using an informer factory to get a shared informer instead of getting an independent
50 | // one. This reduces memory footprint and number of connections to the server.
51 | func NewFooInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
52 | return NewFilteredFooInformer(client, namespace, resyncPeriod, indexers, nil)
53 | }
54 |
55 | // NewFilteredFooInformer constructs a new informer for Foo type.
56 | // Always prefer using an informer factory to get a shared informer instead of getting an independent
57 | // one. This reduces memory footprint and number of connections to the server.
58 | func NewFilteredFooInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
59 | return cache.NewSharedIndexInformer(
60 | &cache.ListWatch{
61 | ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
62 | if tweakListOptions != nil {
63 | tweakListOptions(&options)
64 | }
65 | return client.SamplecontrollerV1alpha1().Foos(namespace).List(context.Background(), options)
66 | },
67 | WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
68 | if tweakListOptions != nil {
69 | tweakListOptions(&options)
70 | }
71 | return client.SamplecontrollerV1alpha1().Foos(namespace).Watch(context.Background(), options)
72 | },
73 | ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) {
74 | if tweakListOptions != nil {
75 | tweakListOptions(&options)
76 | }
77 | return client.SamplecontrollerV1alpha1().Foos(namespace).List(ctx, options)
78 | },
79 | WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) {
80 | if tweakListOptions != nil {
81 | tweakListOptions(&options)
82 | }
83 | return client.SamplecontrollerV1alpha1().Foos(namespace).Watch(ctx, options)
84 | },
85 | },
86 | &apissamplecontrollerv1alpha1.Foo{},
87 | resyncPeriod,
88 | indexers,
89 | )
90 | }
91 |
92 | func (f *fooInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
93 | return NewFilteredFooInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
94 | }
95 |
96 | func (f *fooInformer) Informer() cache.SharedIndexInformer {
97 | return f.factory.InformerFor(&apissamplecontrollerv1alpha1.Foo{}, f.defaultInformer)
98 | }
99 |
100 | func (f *fooInformer) Lister() samplecontrollerv1alpha1.FooLister {
101 | return samplecontrollerv1alpha1.NewFooLister(f.Informer().GetIndexer())
102 | }
103 |
--------------------------------------------------------------------------------
/pkg/generated/informers/externalversions/samplecontroller/v1alpha1/interface.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by informer-gen. DO NOT EDIT.
18 |
19 | package v1alpha1
20 |
21 | import (
22 | internalinterfaces "k8s.io/sample-controller/pkg/generated/informers/externalversions/internalinterfaces"
23 | )
24 |
25 | // Interface provides access to all the informers in this group version.
26 | type Interface interface {
27 | // Foos returns a FooInformer.
28 | Foos() FooInformer
29 | }
30 |
31 | type version struct {
32 | factory internalinterfaces.SharedInformerFactory
33 | namespace string
34 | tweakListOptions internalinterfaces.TweakListOptionsFunc
35 | }
36 |
37 | // New returns a new Interface.
38 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
39 | return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
40 | }
41 |
42 | // Foos returns a FooInformer.
43 | func (v *version) Foos() FooInformer {
44 | return &fooInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
45 | }
46 |
--------------------------------------------------------------------------------
/pkg/generated/listers/samplecontroller/v1alpha1/expansion_generated.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by lister-gen. DO NOT EDIT.
18 |
19 | package v1alpha1
20 |
21 | // FooListerExpansion allows custom methods to be added to
22 | // FooLister.
23 | type FooListerExpansion interface{}
24 |
25 | // FooNamespaceListerExpansion allows custom methods to be added to
26 | // FooNamespaceLister.
27 | type FooNamespaceListerExpansion interface{}
28 |
--------------------------------------------------------------------------------
/pkg/generated/listers/samplecontroller/v1alpha1/foo.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by lister-gen. DO NOT EDIT.
18 |
19 | package v1alpha1
20 |
21 | import (
22 | labels "k8s.io/apimachinery/pkg/labels"
23 | listers "k8s.io/client-go/listers"
24 | cache "k8s.io/client-go/tools/cache"
25 | samplecontrollerv1alpha1 "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1"
26 | )
27 |
28 | // FooLister helps list Foos.
29 | // All objects returned here must be treated as read-only.
30 | type FooLister interface {
31 | // List lists all Foos in the indexer.
32 | // Objects returned here must be treated as read-only.
33 | List(selector labels.Selector) (ret []*samplecontrollerv1alpha1.Foo, err error)
34 | // Foos returns an object that can list and get Foos.
35 | Foos(namespace string) FooNamespaceLister
36 | FooListerExpansion
37 | }
38 |
39 | // fooLister implements the FooLister interface.
40 | type fooLister struct {
41 | listers.ResourceIndexer[*samplecontrollerv1alpha1.Foo]
42 | }
43 |
44 | // NewFooLister returns a new FooLister.
45 | func NewFooLister(indexer cache.Indexer) FooLister {
46 | return &fooLister{listers.New[*samplecontrollerv1alpha1.Foo](indexer, samplecontrollerv1alpha1.Resource("foo"))}
47 | }
48 |
49 | // Foos returns an object that can list and get Foos.
50 | func (s *fooLister) Foos(namespace string) FooNamespaceLister {
51 | return fooNamespaceLister{listers.NewNamespaced[*samplecontrollerv1alpha1.Foo](s.ResourceIndexer, namespace)}
52 | }
53 |
54 | // FooNamespaceLister helps list and get Foos.
55 | // All objects returned here must be treated as read-only.
56 | type FooNamespaceLister interface {
57 | // List lists all Foos in the indexer for a given namespace.
58 | // Objects returned here must be treated as read-only.
59 | List(selector labels.Selector) (ret []*samplecontrollerv1alpha1.Foo, err error)
60 | // Get retrieves the Foo from the indexer for a given namespace and name.
61 | // Objects returned here must be treated as read-only.
62 | Get(name string) (*samplecontrollerv1alpha1.Foo, error)
63 | FooNamespaceListerExpansion
64 | }
65 |
66 | // fooNamespaceLister implements the FooNamespaceLister
67 | // interface.
68 | type fooNamespaceLister struct {
69 | listers.ResourceIndexer[*samplecontrollerv1alpha1.Foo]
70 | }
71 |
--------------------------------------------------------------------------------
/pkg/signals/signal.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package signals
18 |
19 | import (
20 | "context"
21 | "os"
22 | "os/signal"
23 | )
24 |
25 | var onlyOneSignalHandler = make(chan struct{})
26 |
27 | // SetupSignalHandler registered for SIGTERM and SIGINT. A context is returned
28 | // which is cancelled on one of these signals. If a second signal is caught,
29 | // the program is terminated with exit code 1.
30 | func SetupSignalHandler() context.Context {
31 | close(onlyOneSignalHandler) // panics when called twice
32 |
33 | c := make(chan os.Signal, 2)
34 | ctx, cancel := context.WithCancel(context.Background())
35 | signal.Notify(c, shutdownSignals...)
36 | go func() {
37 | <-c
38 | cancel()
39 | <-c
40 | os.Exit(1) // second signal. Exit directly.
41 | }()
42 |
43 | return ctx
44 | }
45 |
--------------------------------------------------------------------------------
/pkg/signals/signal_posix.go:
--------------------------------------------------------------------------------
1 | //go:build !windows
2 | // +build !windows
3 |
4 | /*
5 | Copyright 2017 The Kubernetes Authors.
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | */
19 |
20 | package signals
21 |
22 | import (
23 | "os"
24 | "syscall"
25 | )
26 |
27 | var shutdownSignals = []os.Signal{os.Interrupt, syscall.SIGTERM}
28 |
--------------------------------------------------------------------------------
/pkg/signals/signal_windows.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package signals
18 |
19 | import (
20 | "os"
21 | )
22 |
23 | var shutdownSignals = []os.Signal{os.Interrupt}
24 |
--------------------------------------------------------------------------------