Skip to content

Commit 42ff5ed

Browse files
committed
clean deps and add readme
1 parent 3e983ef commit 42ff5ed

File tree

7 files changed

+155
-57
lines changed

7 files changed

+155
-57
lines changed

examples/kcp/Makefile

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ CONTROLLER_GEN := $(LOCALBIN)/$(CONTROLLER_GEN_BIN)-$(CONTROLLER_GEN_VER)
1515
export CONTROLLER_GEN # so hack scripts can use it
1616

1717
KCP ?= $(LOCALBIN)/kcp
18+
KUBECTL_KCP ?= $(LOCALBIN)/kubectl-kcp
1819

1920
KCP_VERSION ?= 0.23.0
2021

@@ -32,7 +33,17 @@ $(KCP_APIGEN_GEN):
3233
$(CONTROLLER_GEN):
3334
GOBIN=$(LOCALBIN) $(GO_INSTALL) sigs.k8s.io/controller-tools/cmd/controller-gen $(CONTROLLER_GEN_BIN) $(CONTROLLER_GEN_VER)
3435

35-
build: $(KCP) $(KCP_APIGEN_GEN) $(CONTROLLER_GEN) build-controller
36+
$(KUBECTL_KCP): ## Download kcp kubectl plugins locally if necessary.
37+
curl -L -s -o - https://github.com/kcp-dev/kcp/releases/download/v$(KCP_VERSION)/kubectl-kcp-plugin_$(KCP_VERSION)_$(OS)_$(ARCH).tar.gz | tar --directory $(LOCALBIN)/../ -xvzf - bin
38+
touch $(KUBECTL_KCP) # we download an "old" file, so make will re-download to refresh it unless we make it newer than the owning dir
39+
40+
build: $(KCP) $(KCP_APIGEN_GEN) $(CONTROLLER_GEN) $(KUBECTL_KCP) build-controller
41+
42+
ifeq (,$(shell go env GOBIN))
43+
GOBIN=$(shell go env GOPATH)/bin
44+
else
45+
GOBIN=$(shell go env GOBIN)
46+
endif
3647

3748
.PHONY:
3849
build-controller: ## Build the controller binary.
@@ -46,7 +57,16 @@ kcp-server: $(KCP) $(ARTIFACT_DIR)/kcp ## Run the kcp server.
4657
@while true; do if [[ ! -s $(ARTIFACT_DIR)/kcp.kubeconfig ]]; then sleep 0.2; else break; fi; done
4758
@echo "Waiting for kcp server to be ready..."
4859
@while true; do if ! kubectl --kubeconfig $(ARTIFACT_DIR)/kcp.kubeconfig get --raw /readyz >$(ARTIFACT_DIR)/kcp.probe.log 2>&1; then sleep 0.2; else break; fi; done
49-
@echo "kcp server is ready."
60+
@echo "kcp server is ready and running in the background. To stop run 'make test-cleanup'"
61+
62+
.PHONY: kcp-bootstrap
63+
kcp-bootstrap:
64+
@go run ./config/main.go
65+
66+
.PHONY: kcp-controller
67+
kcp-controller: build kcp-bootstrap
68+
@echo "Starting kcp-controller in the background. To stop run 'make test-cleanup'"
69+
@if [[ ! -s $(ARTIFACT_DIR)/controller.log ]]; then ( ./bin/kcp-controller >$(ARTIFACT_DIR)/controller.log 2>&1 & ); fi
5070

5171
.PHONY: test-e2e-cleanup
5272
test-cleanup: ## Clean up processes and directories from an end-to-end test run.
@@ -61,19 +81,9 @@ $(ARTIFACT_DIR)/kcp: ## Create a directory for the kcp server data.
6181
generate: build
6282
./hack/update-codegen-crds.sh
6383

64-
bootstrap:
65-
export KUBECONFIG=./.test/kcp.kubeconfig
66-
@go run ./config/main.go
67-
68-
run-controller-background: build bootstrap
69-
export KUBECONFIG=./.test/kcp.kubeconfig
70-
kubectl ws use widgets
71-
@if [[ ! -s $(ARTIFACT_DIR)/controller.log ]]; then ( ./bin/kcp-controller >$(ARTIFACT_DIR)/controller.log 2>&1 & ); fi
72-
73-
run: build-controller bootstrap
74-
export KUBECONFIG=./.test/kcp.kubeconfig
75-
kubectl ws use widgets
84+
run-local: build-controller kcp-bootstrap
7685
./bin/kcp-controller
7786

87+
.PHONY: test
7888
test:
7989
go test ./... --workspace=root --kubeconfig=$(CURDIR)/$(ARTIFACT_DIR)/kcp.kubeconfig

examples/kcp/README.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# controller-runtime-example
2+
An example project that is multi-cluster aware and works with [kcp](https://github.com/kcp-dev/kcp)
3+
4+
## Description
5+
6+
In this example, we intentionally not using advanced kubebuilder patterns to keep the example simple and easy to understand.
7+
In the future, we will add more advanced examples. Example covers 3 parts:
8+
1. KCP bootstrapping - creating APIExport & consumer workspaces
9+
1. Creating WorkspaceType for particular exports
10+
2. Running controller with APIExport aware configuration and reconciling multiple consumer workspaces
11+
12+
13+
This example contains an example project that works with APIExports and multiple kcp workspaces. It demonstrates
14+
two reconcilers:
15+
16+
1. ConfigMap
17+
1. Get a ConfigMap for the key from the queue, from the correct logical cluster
18+
2. If the ConfigMap has labels["name"], set labels["response"] = "hello-$name" and save the changes
19+
3. List all ConfigMaps in the logical cluster and log each one's namespace and name
20+
4. If the ConfigMap from step 1 has data["namespace"] set, create a namespace whose name is the data value.
21+
5. If the ConfigMap from step 1 has data["secretData"] set, create a secret in the same namespace as the ConfigMap,
22+
with an owner reference to the ConfigMap, and data["dataFromCM"] set to the data value.
23+
24+
2. Widget
25+
1. Show how to list all Widget instances across all logical clusters
26+
2. Get a Widget for the key from the queue, from the correct logical cluster
27+
3. List all Widgets in the same logical cluster
28+
4. Count the number of Widgets (list length)
29+
5. Make sure `.status.total` matches the current count (via a `patch`)
30+
31+
## Getting Started
32+
33+
### Running on kcp
34+
35+
1. Run KCP with the following command:
36+
37+
```sh
38+
make kcp-server
39+
```
40+
41+
From this point onwards you can inspect kcp configuration using kubeconfig:
42+
43+
```sh
44+
export KUBECONFIG=.test/kcp.kubeconfig
45+
```
46+
47+
1. Bootstrap the KCP server with the following command:
48+
49+
```sh
50+
export KUBECONFIG=./.test/kcp.kubeconfig
51+
make kcp-bootstrap
52+
```
53+
54+
1. Run controller:
55+
56+
```sh
57+
export KUBECONFIG=./.test/kcp.kubeconfig
58+
make run-local
59+
```
60+
61+
1. In separate shell you can run tests to exercise the controller:
62+
63+
```sh
64+
export KUBECONFIG=./.test/kcp.kubeconfig
65+
make test
66+
```
67+
68+
### Uninstall resources
69+
To delete the resources from kcp:
70+
71+
```sh
72+
make test-clean
73+
```
74+
75+
76+
77+
### How it works
78+
This project aims to follow the Kubernetes [Operator pattern](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/)
79+
80+
It uses [Controllers](https://kubernetes.io/docs/concepts/architecture/controller/)
81+
which provides a reconcile function responsible for synchronizing resources until the desired state is reached.
82+
83+
84+
85+

examples/kcp/config/main.go

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,21 @@ limitations under the License.
1717
package main
1818

1919
import (
20-
"net/url"
21-
20+
"github.com/davecgh/go-spew/spew"
21+
kcpclienthelper "github.com/kcp-dev/apimachinery/v2/pkg/client"
2222
apisv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1"
23+
"github.com/kcp-dev/kcp/sdk/apis/core"
2324
corev1alpha1 "github.com/kcp-dev/kcp/sdk/apis/core/v1alpha1"
2425
tenancyv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/tenancy/v1alpha1"
26+
"github.com/kcp-dev/logicalcluster/v3"
2527
"k8s.io/apimachinery/pkg/runtime"
2628
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
2729
"k8s.io/apimachinery/pkg/util/sets"
2830
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
2931
"k8s.io/client-go/rest"
3032
ctrl "sigs.k8s.io/controller-runtime"
3133
"sigs.k8s.io/controller-runtime/pkg/client"
34+
"sigs.k8s.io/controller-runtime/pkg/client/config"
3235
"sigs.k8s.io/controller-runtime/pkg/log/zap"
3336

3437
"github.com/kcp-dev/controller-runtime/examples/kcp/config/consumers"
@@ -62,7 +65,7 @@ func init() {
6265

6366
var (
6467
// clusterName is the workspace to host common APIs.
65-
clusterName = "widgets"
68+
clusterName = logicalcluster.NewPath("root:widgets")
6669
)
6770

6871
func main() {
@@ -72,33 +75,32 @@ func main() {
7275
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
7376

7477
ctx := ctrl.SetupSignalHandler()
75-
restConfig := ctrl.GetConfigOrDie()
76-
7778
log := log.FromContext(ctx)
79+
fakeBatteries := sets.New("")
7880

79-
// Client for root cluster for workspace widget and consumers to bootstrap.
80-
clientRoot, err := client.New(restConfig, client.Options{
81-
Scheme: scheme,
82-
})
81+
restConfig, err := config.GetConfigWithContext("base")
8382
if err != nil {
84-
log.Error(err, "unable to create client")
83+
log.Error(err, "unable to get config")
8584
}
8685

87-
// Hack to set the clusterName in the restConfig.Host
88-
restWidgetsConfig := rest.CopyConfig(restConfig)
89-
restConfig.Host = restWidgetsConfig.Host + ":" + url.PathEscape(clusterName)
86+
restCopy := rest.CopyConfig(restConfig)
87+
restRoot := rest.AddUserAgent(kcpclienthelper.SetCluster(restCopy, core.RootCluster.Path()), "bootstrap-root")
88+
clientRoot, err := client.New(restRoot, client.Options{
89+
Scheme: scheme,
90+
})
9091
if err != nil {
91-
log.Error(err, "unable to set clusterName")
92+
log.Error(err, "unable to create client")
9293
}
9394

94-
clientWidgets, err := client.New(restConfig, client.Options{
95+
restCopy = rest.CopyConfig(restConfig)
96+
restWidgets := rest.AddUserAgent(kcpclienthelper.SetCluster(restCopy, clusterName), "bootstrap-widgets")
97+
clientWidgets, err := client.New(restWidgets, client.Options{
9598
Scheme: scheme,
9699
})
97100
if err != nil {
98101
log.Error(err, "unable to create client")
99102
}
100-
101-
fakeBatteries := sets.New("")
103+
spew.Dump(restWidgets)
102104

103105
err = widgets.Bootstrap(ctx, clientRoot, fakeBatteries)
104106
if err != nil {

examples/kcp/go.mod

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@ module github.com/kcp-dev/controller-runtime/examples/kcp
22

33
go 1.22.2
44

5+
// IMPORTANT: This is only an example replace directive. This is so examples can be run with the latest version of controller-runtime.
6+
// In your own projects, you should not use replace directives like this. Instead, you should use the latest version of controller-runtime.
57
replace sigs.k8s.io/controller-runtime => ../../
68

79
require (
810
github.com/davecgh/go-spew v1.1.1
911
github.com/google/go-cmp v0.6.0
10-
github.com/kcp-dev/apimachinery v0.0.0-20221102195355-d65878bc16be
11-
github.com/kcp-dev/controller-runtime-example v0.0.0-20230210212348-32255ed28d4b
12-
github.com/kcp-dev/kcp/pkg/apis v0.11.0
12+
github.com/kcp-dev/apimachinery/v2 v2.0.0-alpha.0.0.20230926071920-57d168bcbe34
1313
github.com/kcp-dev/kcp/sdk v0.23.0
14-
github.com/kcp-dev/logicalcluster/v2 v2.0.0-alpha.4
14+
github.com/kcp-dev/logicalcluster/v3 v3.0.5
1515
k8s.io/api v0.30.0-beta.0
1616
k8s.io/apiextensions-apiserver v0.30.0-beta.0
1717
k8s.io/apimachinery v0.30.0-beta.0
@@ -54,8 +54,6 @@ require (
5454
github.com/inconshreveable/mousetrap v1.1.0 // indirect
5555
github.com/josharian/intern v1.0.0 // indirect
5656
github.com/json-iterator/go v1.1.12 // indirect
57-
github.com/kcp-dev/apimachinery/v2 v2.0.0-alpha.0.0.20230926071920-57d168bcbe34 // indirect
58-
github.com/kcp-dev/logicalcluster/v3 v3.0.5 // indirect
5957
github.com/mailru/easyjson v0.7.7 // indirect
6058
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
6159
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect

examples/kcp/go.sum

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -888,18 +888,10 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8
888888
github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
889889
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
890890
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
891-
github.com/kcp-dev/apimachinery v0.0.0-20221102195355-d65878bc16be h1:2uDzJ896+ojtzgr9HJL8+tZEoqhq8blwymGinWFrQ6E=
892-
github.com/kcp-dev/apimachinery v0.0.0-20221102195355-d65878bc16be/go.mod h1:qnvUHkdxOrNzX17yX+z8r81CZEBuFdveNzWqFlwZ55w=
893891
github.com/kcp-dev/apimachinery/v2 v2.0.0-alpha.0.0.20230926071920-57d168bcbe34 h1:tom0JX5OmAeOOmkGv8LaYHDtA1xAKDiQL5U0vhYYgdM=
894892
github.com/kcp-dev/apimachinery/v2 v2.0.0-alpha.0.0.20230926071920-57d168bcbe34/go.mod h1:cWoaYGHl1nlzdEM2xvMzIASkEZJZLSf5nhe17M7wDhw=
895-
github.com/kcp-dev/controller-runtime-example v0.0.0-20230210212348-32255ed28d4b h1:PskZ90lSlD9vuUgjQVzyS9VK/P+SdSu92qvibmbQymg=
896-
github.com/kcp-dev/controller-runtime-example v0.0.0-20230210212348-32255ed28d4b/go.mod h1:ZV8H7jO7nkxq17tb+yZQnVOZqWbYqWOQBzta6Pd9aGQ=
897-
github.com/kcp-dev/kcp/pkg/apis v0.11.0 h1:K6p+tNHNcvfACCPLcHgY0EMLeaIwR1jS491FyLfXMII=
898-
github.com/kcp-dev/kcp/pkg/apis v0.11.0/go.mod h1:8cUAmfMJcksauz53UtsLYG8Phhx62rvuCnd/5t/Zihk=
899893
github.com/kcp-dev/kcp/sdk v0.23.0 h1:druOnL0DyLUZM5rwsQdf5G9WGyjluZBkaUKRjfvDUio=
900894
github.com/kcp-dev/kcp/sdk v0.23.0/go.mod h1:Pd2xxw/qhgfF2xgHolVwheq9VOJwPtNrBmxgBlYmjfk=
901-
github.com/kcp-dev/logicalcluster/v2 v2.0.0-alpha.4 h1:lHolbAfXXJDdcOO0bgQHtu0r4gq5Lt3/ueF0YGliIBc=
902-
github.com/kcp-dev/logicalcluster/v2 v2.0.0-alpha.4/go.mod h1:lfWJL764jKFJxZWOGuFuT3PCCLPo6lV5Cl8P7u9T05g=
903895
github.com/kcp-dev/logicalcluster/v3 v3.0.5 h1:JbYakokb+5Uinz09oTXomSUJVQsqfxEvU4RyHUYxHOU=
904896
github.com/kcp-dev/logicalcluster/v3 v3.0.5/go.mod h1:EWBUBxdr49fUB1cLMO4nOdBWmYifLbP1LfoL20KkXYY=
905897
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
@@ -939,7 +931,6 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
939931
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
940932
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
941933
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
942-
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
943934
github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
944935
github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
945936
github.com/onsi/gomega v1.31.0 h1:54UJxxj6cPInHS3a35wm6BK/F9nHYueZ1NVujHDrnXE=

examples/kcp/main.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"fmt"
2323
"os"
2424

25+
kcpclienthelper "github.com/kcp-dev/apimachinery/v2/pkg/client"
2526
"k8s.io/apimachinery/pkg/runtime"
2627
"k8s.io/apimachinery/pkg/types"
2728
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
@@ -30,6 +31,7 @@ import (
3031
"k8s.io/client-go/rest"
3132
"k8s.io/klog/v2"
3233
"sigs.k8s.io/controller-runtime/pkg/client"
34+
"sigs.k8s.io/controller-runtime/pkg/client/config"
3335

3436
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
3537
// to ensure that exec-entrypoint and run can make use of them.
@@ -41,6 +43,7 @@ import (
4143

4244
datav1alpha1 "github.com/kcp-dev/controller-runtime/examples/kcp/apis/v1alpha1"
4345
"github.com/kcp-dev/controller-runtime/examples/kcp/controllers"
46+
"github.com/kcp-dev/logicalcluster/v3"
4447

4548
apisv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1"
4649
)
@@ -89,12 +92,21 @@ func runController(ctx context.Context) error {
8992

9093
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
9194

92-
restConfig := ctrl.GetConfigOrDie()
95+
// Important: We use non-controller-runtime client loader so we can always
96+
// be sure we have correct kubeconfig file. This ease the development and maintenance
97+
// of the example. In production, you should use the controller-runtime client loader
98+
// to load the kubeconfig file dedicated to workspace where APIExport is located.
99+
//restConfig := ctrl.GetConfigOrDie()
100+
widgetsCluster := logicalcluster.NewPath("root:widgets")
101+
restConfig, err := config.GetConfigWithContext("base")
102+
if err != nil {
103+
return fmt.Errorf("unable to get config: %w", err)
104+
}
105+
restConfig = rest.AddUserAgent(kcpclienthelper.SetCluster(restConfig, widgetsCluster), "kcp-controller-runtime-example")
93106

94107
setupLog = setupLog.WithValues("api-export-name", apiExportName)
95108

96109
var mgr ctrl.Manager
97-
var err error
98110
options := ctrl.Options{
99111
Scheme: scheme,
100112
HealthProbeBindAddress: probeAddr,

0 commit comments

Comments
 (0)