Skip to content

Commit 8099c6c

Browse files
committedOct 17, 2020
adding ComponentConfig type and Options parsing
Signed-off-by: Chris Hein <me@chrishein.com>
1 parent c000ea8 commit 8099c6c

26 files changed

+1340
-21
lines changed
 

‎.golangci.yml

-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ linters:
2828
- unparam
2929
- ineffassign
3030
- nakedret
31-
- interfacer
3231
- gocyclo
3332
- lll
3433
- dupl

‎Makefile

+8
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ TOOLS_DIR := hack/tools
3939
TOOLS_BIN_DIR := $(TOOLS_DIR)/bin
4040
GOLANGCI_LINT := $(abspath $(TOOLS_BIN_DIR)/golangci-lint)
4141
GO_APIDIFF := $(TOOLS_BIN_DIR)/go-apidiff
42+
CONTROLLER_GEN := $(TOOLS_BIN_DIR)/controller-gen
4243

4344
# The help will print out all targets with their descriptions organized bellow their categories. The categories are represented by `##@` and the target descriptions by `##`.
4445
# The awk commands is responsible to read the entire set of makefiles included in this invocation, looking for lines of the file as xyz: ## something, and then pretty-format the target and help. Then, if there's a line with ##@ something, that gets pretty-printed as a category.
@@ -66,6 +67,9 @@ $(GOLANGCI_LINT): $(TOOLS_DIR)/go.mod # Build golangci-lint from tools folder.
6667
$(GO_APIDIFF): $(TOOLS_DIR)/go.mod # Build go-apidiff from tools folder.
6768
cd $(TOOLS_DIR) && go build -tags=tools -o bin/go-apidiff github.com/joelanford/go-apidiff
6869

70+
$(CONTROLLER_GEN): $(TOOLS_DIR)/go.mod # Build controller-gen from tools folder.
71+
cd $(TOOLS_DIR) && go build -tags=tools -o bin/controller-gen sigs.k8s.io/controller-tools/cmd/controller-gen
72+
6973
## --------------------------------------
7074
## Linting
7175
## --------------------------------------
@@ -83,6 +87,10 @@ modules: ## Runs go mod to ensure modules are up to date.
8387
go mod tidy
8488
cd $(TOOLS_DIR); go mod tidy
8589

90+
.PHONY: generate
91+
generate: $(CONTROLLER_GEN) ## Runs controller-gen for internal types for config file
92+
$(CONTROLLER_GEN) object paths="./pkg/config/v1alpha1/...;./examples/configfile/custom/v1alpha1/..."
93+
8694
## --------------------------------------
8795
## Cleanup / Verification
8896
## --------------------------------------

‎designs/component-config.md

+20-20
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ This change is important because:
5353

5454
- Provide an interface for pulling configuration data out of exposed `ComponentConfig` types (see below for implementation)
5555
- Provide a new `ctrl.NewFromComponentConfig()` function for initializing a manager
56-
- Provide an embeddable `ControllerConfiguration` type for easily authoring `ComponentConfig` types
56+
- Provide an embeddable `ControllerManagerConfiguration` type for easily authoring `ComponentConfig` types
5757
- Provide an `DefaultControllerConfig` to make the switching easier for clients
5858

5959
### Non-Goals/Future Work
@@ -137,8 +137,8 @@ import (
137137
configv1alpha1 "k8s.io/component-base/config/v1alpha1"
138138
)
139139

140-
// ControllerConfiguration defines the embedded RuntimeConfiguration for controller-runtime clients.
141-
type ControllerConfiguration struct {
140+
// ControllerManagerConfiguration defines the embedded RuntimeConfiguration for controller-runtime clients.
141+
type ControllerManagerConfiguration struct {
142142
Namespace string `json:"namespace,omitempty"`
143143

144144
SyncPeriod *time.Duration `json:"syncPeriod,omitempty"`
@@ -147,16 +147,16 @@ type ControllerConfiguration struct {
147147

148148
MetricsBindAddress string `json:"metricsBindAddress,omitempty"`
149149

150-
Health ControllerConfigurationHealth `json:"health,omitempty"`
150+
Health ControllerManagerConfigurationHealth `json:"health,omitempty"`
151151

152152
Port *int `json:"port,omitempty"`
153153
Host string `json:"host,omitempty"`
154154

155155
CertDir string `json:"certDir,omitempty"`
156156
}
157157

158-
// ControllerConfigurationHealth defines the health configs
159-
type ControllerConfigurationHealth struct {
158+
// ControllerManagerConfigurationHealth defines the health configs
159+
type ControllerManagerConfigurationHealth struct {
160160
HealthProbeBindAddress string `json:"healthProbeBindAddress,omitempty"`
161161

162162
ReadinessEndpointName string `json:"readinessEndpointName,omitempty"`
@@ -181,11 +181,11 @@ import (
181181
configv1alpha1 "sigs.k8s.io/controller-runtime/pkg/apis/config/v1alpha1"
182182
)
183183

184-
// DefaultControllerConfiguration is the Schema for the DefaultControllerConfigurations API
185-
type DefaultControllerConfiguration struct {
184+
// DefaultControllerManagerConfiguration is the Schema for the DefaultControllerManagerConfigurations API
185+
type DefaultControllerManagerConfiguration struct {
186186
metav1.TypeMeta `json:",inline"`
187187

188-
Spec configv1alpha1.ControllerConfiguration `json:"spec,omitempty"`
188+
Spec configv1alpha1.ControllerManagerConfiguration `json:"spec,omitempty"`
189189
}
190190
```
191191

@@ -194,19 +194,19 @@ This would allow a controller author to use this struct with any config that sup
194194
```yaml
195195
# config.yaml
196196
apiVersion: config.somedomain.io/v1alpha1
197-
kind: FoobarControllerConfiguration
197+
kind: FoobarControllerManagerConfiguration
198198
spec:
199199
port: 9443
200200
metricsBindAddress: ":8080"
201201
leaderElection:
202202
leaderElect: false
203203
```
204204
205-
Given the following config and `DefaultControllerConfiguration` we'd be able to initialize the controller using the following.
205+
Given the following config and `DefaultControllerManagerConfiguration` we'd be able to initialize the controller using the following.
206206

207207

208208
```golang
209-
mgr, err := ctrl.NewManagerFromComponentConfig(ctrl.GetConfigOrDie(), scheme, configname, &defaultv1alpha1.DefaultControllerConfiguration{})
209+
mgr, err := ctrl.NewManagerFromComponentConfig(ctrl.GetConfigOrDie(), scheme, configname, &defaultv1alpha1.DefaultControllerManagerConfiguration{})
210210
if err != nil {
211211
// ...
212212
}
@@ -222,8 +222,8 @@ Since this design still requires setting up the initial `ComponentConfig` type a
222222
```golang
223223
leaderElect := true
224224
225-
config := &defaultv1alpha1.DefaultControllerConfiguration{
226-
Spec: configv1alpha1.ControllerConfiguration{
225+
config := &defaultv1alpha1.DefaultControllerManagerConfiguration{
226+
Spec: configv1alpha1.ControllerManagerConfiguration{
227227
LeaderElection: configv1alpha1.LeaderElectionConfiguration{
228228
LeaderElect: &leaderElect,
229229
},
@@ -250,7 +250,7 @@ import (
250250
)
251251
252252
type ControllerNameConfigurationSpec struct {
253-
configv1alpha1.ControllerConfiguration `json:",inline"`
253+
configv1alpha1.ControllerManagerConfiguration `json:",inline"`
254254
}
255255

256256
type ControllerNameConfiguration struct {
@@ -260,20 +260,20 @@ type ControllerNameConfiguration struct {
260260
}
261261
```
262262

263-
Usage of this custom `ComponentConfig` type would require then changing the `ctrl.NewFromComponentConfig()` to use the new struct vs the `DefaultControllerConfiguration`.
263+
Usage of this custom `ComponentConfig` type would require then changing the `ctrl.NewFromComponentConfig()` to use the new struct vs the `DefaultControllerManagerConfiguration`.
264264

265265
## User Stories
266266

267267
### Controller Author with `controller-runtime` and default type
268268

269269
- Mount `ConfigMap`
270-
- Initialize `ctrl.Manager` with `NewFromComponentConfig` with config name and `DefaultControllerConfiguration` type
270+
- Initialize `ctrl.Manager` with `NewFromComponentConfig` with config name and `DefaultControllerManagerConfiguration` type
271271
- Build custom controller as usual
272272

273273
### Controller Author with `controller-runtime` and custom type
274274

275275
- Implement `ComponentConfig` type
276-
- Embed `ControllerConfiguration` type
276+
- Embed `ControllerManagerConfiguration` type
277277
- Mount `ConfigMap`
278278
- Initialize `ctrl.Manager` with `NewFromComponentConfig` with config name and `ComponentConfig` type
279279
- Build custom controller as usual
@@ -311,9 +311,9 @@ _Provided that the controller provides manifests_
311311

312312
- [x] 02/19/2020: Proposed idea in an issue or [community meeting]
313313
- [x] 02/24/2020: Proposal submitted to `controller-runtime`
314-
- [x] 03/02/2020: Updated with default `DefaultControllerConfiguration`
314+
- [x] 03/02/2020: Updated with default `DefaultControllerManagerConfiguration`
315315
- [x] 03/04/2020: Updated with embeddable `RuntimeConfig`
316-
- [x] 03/10/2020: Updated embeddable name to `ControllerConfiguration`
316+
- [x] 03/10/2020: Updated embeddable name to `ControllerManagerConfiguration`
317317

318318

319319
<!-- Links -->
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
apiVersion: controller-runtime.sigs.k8s.io/v1alpha1
2+
kind: ControllerManagerConfiguration
3+
cacheNamespace: default
4+
metrics:
5+
bindAddress: :9091
6+
leaderElection:
7+
leaderElect: false
+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
Copyright 2018 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+
23+
appsv1 "k8s.io/api/apps/v1"
24+
"k8s.io/apimachinery/pkg/api/errors"
25+
"sigs.k8s.io/controller-runtime/pkg/client"
26+
"sigs.k8s.io/controller-runtime/pkg/log"
27+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
28+
)
29+
30+
// reconcileReplicaSet reconciles ReplicaSets
31+
type reconcileReplicaSet struct {
32+
// client can be used to retrieve objects from the APIServer.
33+
client client.Client
34+
}
35+
36+
// Implement reconcile.Reconciler so the controller can reconcile objects
37+
var _ reconcile.Reconciler = &reconcileReplicaSet{}
38+
39+
func (r *reconcileReplicaSet) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
40+
// set up a convenient log object so we don't have to type request over and over again
41+
log := log.FromContext(ctx)
42+
43+
// Fetch the ReplicaSet from the cache
44+
rs := &appsv1.ReplicaSet{}
45+
err := r.client.Get(context.TODO(), request.NamespacedName, rs)
46+
if errors.IsNotFound(err) {
47+
log.Error(nil, "Could not find ReplicaSet")
48+
return reconcile.Result{}, nil
49+
}
50+
51+
if err != nil {
52+
return reconcile.Result{}, fmt.Errorf("could not fetch ReplicaSet: %+v", err)
53+
}
54+
55+
// Print the ReplicaSet
56+
log.Info("Reconciling ReplicaSet", "container name", rs.Spec.Template.Spec.Containers[0].Name)
57+
58+
// Set the label if it is missing
59+
if rs.Labels == nil {
60+
rs.Labels = map[string]string{}
61+
}
62+
if rs.Labels["hello"] == "world" {
63+
return reconcile.Result{}, nil
64+
}
65+
66+
// Update the ReplicaSet
67+
rs.Labels["hello"] = "world"
68+
err = r.client.Update(context.TODO(), rs)
69+
if err != nil {
70+
return reconcile.Result{}, fmt.Errorf("could not write ReplicaSet: %+v", err)
71+
}
72+
73+
return reconcile.Result{}, nil
74+
}

‎examples/configfile/builtin/main.go

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
Copyright 2020 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+
"os"
21+
22+
appsv1 "k8s.io/api/apps/v1"
23+
corev1 "k8s.io/api/core/v1"
24+
"k8s.io/apimachinery/pkg/runtime"
25+
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
26+
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
27+
ctrl "sigs.k8s.io/controller-runtime"
28+
"sigs.k8s.io/controller-runtime/pkg/client/config"
29+
cfg "sigs.k8s.io/controller-runtime/pkg/config"
30+
"sigs.k8s.io/controller-runtime/pkg/log"
31+
"sigs.k8s.io/controller-runtime/pkg/log/zap"
32+
"sigs.k8s.io/controller-runtime/pkg/manager/signals"
33+
)
34+
35+
var scheme = runtime.NewScheme()
36+
37+
func init() {
38+
log.SetLogger(zap.New())
39+
clientgoscheme.AddToScheme(scheme)
40+
}
41+
42+
func main() {
43+
entryLog := log.Log.WithName("entrypoint")
44+
45+
// Setup a Manager
46+
entryLog.Info("setting up manager")
47+
mgr, err := ctrl.NewManager(config.GetConfigOrDie(), ctrl.Options{
48+
Scheme: scheme,
49+
}.AndFromOrDie(cfg.File()))
50+
if err != nil {
51+
entryLog.Error(err, "unable to set up overall controller manager")
52+
os.Exit(1)
53+
}
54+
55+
// Setup a new controller to reconcile ReplicaSets
56+
err = ctrl.NewControllerManagedBy(mgr).
57+
For(&appsv1.ReplicaSet{}).
58+
Owns(&corev1.Pod{}).
59+
Complete(&reconcileReplicaSet{
60+
client: mgr.GetClient(),
61+
})
62+
if err != nil {
63+
entryLog.Error(err, "unable to create controller")
64+
os.Exit(1)
65+
}
66+
67+
entryLog.Info("starting manager")
68+
if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
69+
entryLog.Error(err, "unable to run manager")
70+
os.Exit(1)
71+
}
72+
}
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
apiVersion: examples.x-k8s.io/v1alpha1
2+
kind: CustomControllerManagerConfiguration
3+
clusterName: example-test
4+
cacheNamespace: default
5+
metrics:
6+
bindAddress: :8081
7+
leaderElection:
8+
leaderElect: false

0 commit comments

Comments
 (0)
Please sign in to comment.