Skip to content

Commit 97baa6e

Browse files
hdp617everpeace
authored andcommitted
feat: Add ClusterProfiles provider
Signed-off-by: Shingo Omura <everpeace@gmail.com>
1 parent 08707d8 commit 97baa6e

File tree

9 files changed

+1429
-71
lines changed

9 files changed

+1429
-71
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"providers": [
3+
{
4+
"name": "google",
5+
"execConfig": {
6+
"apiVersion": "client.authentication.k8s.io/v1beta1",
7+
"args": null,
8+
"command": "gke-gcloud-auth-plugin",
9+
"env": null,
10+
"provideClusterInfo": true
11+
}
12+
}
13+
]
14+
}

examples/clusterprofile/go.mod

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
module sigs.k8s.io/multicluster-runtime/examples/clusterprofile
2+
3+
go 1.24.0
4+
5+
replace (
6+
sigs.k8s.io/multicluster-runtime => ../..
7+
sigs.k8s.io/multicluster-runtime/providers/clusterprofile => ../../providers/clusterprofile
8+
)
9+
10+
require (
11+
k8s.io/api v0.33.3
12+
k8s.io/apimachinery v0.33.3
13+
k8s.io/kubectl v0.33.3
14+
sigs.k8s.io/cluster-inventory-api v0.0.0-20250702132726-0f613c6275a5
15+
sigs.k8s.io/controller-runtime v0.21.0
16+
sigs.k8s.io/multicluster-runtime v0.0.0-00010101000000-000000000000
17+
)
18+
19+
require (
20+
github.com/beorn7/perks v1.0.1 // indirect
21+
github.com/cespare/xxhash/v2 v2.3.0 // indirect
22+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
23+
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
24+
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
25+
github.com/fsnotify/fsnotify v1.8.0 // indirect
26+
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
27+
github.com/go-logr/logr v1.4.3 // indirect
28+
github.com/go-logr/zapr v1.3.0 // indirect
29+
github.com/go-openapi/jsonpointer v0.21.1 // indirect
30+
github.com/go-openapi/jsonreference v0.21.0 // indirect
31+
github.com/go-openapi/swag v0.23.1 // indirect
32+
github.com/gogo/protobuf v1.3.2 // indirect
33+
github.com/google/btree v1.1.3 // indirect
34+
github.com/google/gnostic-models v0.6.9 // indirect
35+
github.com/google/go-cmp v0.7.0 // indirect
36+
github.com/google/uuid v1.6.0 // indirect
37+
github.com/josharian/intern v1.0.0 // indirect
38+
github.com/json-iterator/go v1.1.12 // indirect
39+
github.com/mailru/easyjson v0.9.0 // indirect
40+
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
41+
github.com/modern-go/reflect2 v1.0.2 // indirect
42+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
43+
github.com/pkg/errors v0.9.1 // indirect
44+
github.com/prometheus/client_golang v1.22.0 // indirect
45+
github.com/prometheus/client_model v0.6.1 // indirect
46+
github.com/prometheus/common v0.62.0 // indirect
47+
github.com/prometheus/procfs v0.15.1 // indirect
48+
github.com/spf13/pflag v1.0.6 // indirect
49+
github.com/x448/float16 v0.8.4 // indirect
50+
go.uber.org/multierr v1.11.0 // indirect
51+
go.uber.org/zap v1.27.0 // indirect
52+
golang.org/x/net v0.39.0 // indirect
53+
golang.org/x/oauth2 v0.29.0 // indirect
54+
golang.org/x/sync v0.15.0 // indirect
55+
golang.org/x/sys v0.32.0 // indirect
56+
golang.org/x/term v0.31.0 // indirect
57+
golang.org/x/text v0.24.0 // indirect
58+
golang.org/x/time v0.11.0 // indirect
59+
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
60+
google.golang.org/protobuf v1.36.6 // indirect
61+
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
62+
gopkg.in/inf.v0 v0.9.1 // indirect
63+
gopkg.in/yaml.v3 v3.0.1 // indirect
64+
k8s.io/apiextensions-apiserver v0.33.0 // indirect
65+
k8s.io/client-go v0.33.3 // indirect
66+
k8s.io/klog/v2 v2.130.1 // indirect
67+
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
68+
k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
69+
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
70+
sigs.k8s.io/randfill v1.0.0 // indirect
71+
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
72+
sigs.k8s.io/yaml v1.4.0 // indirect
73+
)

examples/clusterprofile/go.sum

Lines changed: 196 additions & 0 deletions
Large diffs are not rendered by default.

examples/clusterprofile/main.go

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
/*
2+
Copyright 2025 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+
// This example demonstrates how to use the ClusterProfiles provider to create
18+
// a multi-cluster operator that can watch and reconcile resources across
19+
// multiple Kubernetes clusters using ClusterProfile resources.
20+
//
21+
// The operator watches for ClusterProfile resources in a specified namespace
22+
// and automatically creates connections to the clusters they reference using
23+
// configured credential providers.
24+
//
25+
// Usage:
26+
//
27+
// go run main.go --namespace cluster-inventory --credential-providers-file clusterprofile-provider-file.json
28+
//
29+
// This will:
30+
// 1. Set up the ClusterProfiles provider with credential providers
31+
// 2. Watch for ClusterProfile resources in the specified namespace
32+
// 3. Create a multi-cluster controller that watches ConfigMaps across all connected clusters
33+
// 4. Log information about discovered ConfigMaps
34+
package main
35+
36+
import (
37+
"context"
38+
"errors"
39+
"flag"
40+
"log"
41+
"os"
42+
43+
"k8s.io/apimachinery/pkg/util/runtime"
44+
"k8s.io/client-go/kubernetes/scheme"
45+
"sigs.k8s.io/cluster-inventory-api/pkg/credentials"
46+
"sigs.k8s.io/controller-runtime/pkg/log/zap"
47+
"sigs.k8s.io/controller-runtime/pkg/manager"
48+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
49+
50+
corev1 "k8s.io/api/core/v1"
51+
apierrors "k8s.io/apimachinery/pkg/api/errors"
52+
clusterinventory "sigs.k8s.io/cluster-inventory-api/apis/v1alpha1"
53+
ctrl "sigs.k8s.io/controller-runtime"
54+
ctrllog "sigs.k8s.io/controller-runtime/pkg/log"
55+
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
56+
mcbuilder "sigs.k8s.io/multicluster-runtime/pkg/builder"
57+
mcmanager "sigs.k8s.io/multicluster-runtime/pkg/manager"
58+
mcreconcile "sigs.k8s.io/multicluster-runtime/pkg/reconcile"
59+
clusterprofileprovider "sigs.k8s.io/multicluster-runtime/providers/clusterprofile"
60+
)
61+
62+
func init() {
63+
runtime.Must(clusterinventory.AddToScheme(scheme.Scheme))
64+
}
65+
66+
func main() {
67+
// Set up command line flags for credential providers configuration
68+
credentialsProviders := credentials.SetupProviderFileFlag()
69+
flag.Parse()
70+
71+
// Define the namespace where ClusterProfile resources will be watched
72+
var clusterInventoryNamespace string
73+
flag.StringVar(&clusterInventoryNamespace, "namespace", "", "Cluster inventory namespace")
74+
75+
// Set up logging options
76+
opts := zap.Options{
77+
Development: true,
78+
}
79+
opts.BindFlags(flag.CommandLine)
80+
flag.Parse()
81+
82+
// Initialize logger and signal handler
83+
ctrllog.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
84+
entryLog := ctrllog.Log.WithName("entrypoint")
85+
ctx := ctrl.SetupSignalHandler()
86+
87+
entryLog.Info("Starting ClusterProfiles provider example", "namespace", clusterInventoryNamespace)
88+
89+
// Load credential providers from configuration file
90+
cpCreds, err := credentials.NewFromFile(*credentialsProviders)
91+
if err != nil {
92+
log.Fatalf("Got error reading credentials providers: %v", err)
93+
}
94+
95+
// Create the clusterprofiles provider with options
96+
providerOpts := clusterprofileprovider.Options{
97+
Namespace: clusterInventoryNamespace,
98+
CredentialsProvider: cpCreds,
99+
Scheme: scheme.Scheme,
100+
}
101+
102+
// Create the provider instance
103+
provider := clusterprofileprovider.New(providerOpts)
104+
105+
// Setup a cluster-aware Manager with the provider to lookup clusters
106+
managerOpts := manager.Options{
107+
Metrics: metricsserver.Options{
108+
BindAddress: "0", // Disable metrics server
109+
},
110+
}
111+
112+
// Create multicluster manager that will coordinate across all discovered clusters
113+
entryLog.Info("Creating multicluster manager")
114+
mgr, err := mcmanager.New(ctrl.GetConfigOrDie(), provider, managerOpts)
115+
if err != nil {
116+
entryLog.Error(err, "Unable to create manager")
117+
os.Exit(1)
118+
}
119+
120+
// Setup provider controller with the manager to start watching ClusterProfile resources
121+
err = provider.SetupWithManager(ctx, mgr)
122+
if err != nil {
123+
entryLog.Error(err, "Unable to setup provider with manager")
124+
os.Exit(1)
125+
}
126+
127+
// Create a multi-cluster controller that watches ConfigMaps across all connected clusters
128+
// This demonstrates how to build controllers that operate across multiple clusters
129+
err = mcbuilder.ControllerManagedBy(mgr).
130+
Named("multicluster-configmaps").
131+
For(&corev1.ConfigMap{}).
132+
Complete(mcreconcile.Func(
133+
func(ctx context.Context, req mcreconcile.Request) (ctrl.Result, error) {
134+
log := ctrllog.FromContext(ctx).WithValues("cluster", req.ClusterName)
135+
log.Info("Reconciling ConfigMap")
136+
137+
// Get the cluster client for the specific cluster where this resource lives
138+
cl, err := mgr.GetCluster(ctx, req.ClusterName)
139+
if err != nil {
140+
return reconcile.Result{}, err
141+
}
142+
143+
// Retrieve the ConfigMap from the specific cluster
144+
cm := &corev1.ConfigMap{}
145+
if err := cl.GetClient().Get(ctx, req.Request.NamespacedName, cm); err != nil {
146+
if apierrors.IsNotFound(err) {
147+
return reconcile.Result{}, nil
148+
}
149+
return reconcile.Result{}, err
150+
}
151+
152+
log.Info("ConfigMap found", "namespace", cm.Namespace, "name", cm.Name, "cluster", req.ClusterName)
153+
154+
// Here you would add your multi-cluster reconciliation logic
155+
// For example:
156+
// - Sync resources across clusters
157+
// - Aggregate data from multiple clusters
158+
// - Implement cross-cluster policies
159+
160+
return ctrl.Result{}, nil
161+
},
162+
))
163+
if err != nil {
164+
entryLog.Error(err, "unable to create controller")
165+
os.Exit(1)
166+
}
167+
168+
// Start the manager - this will begin watching ClusterProfile resources
169+
// and automatically connect to discovered clusters
170+
entryLog.Info("Starting manager")
171+
err = mgr.Start(ctx)
172+
if err != nil && !errors.Is(err, context.Canceled) {
173+
entryLog.Error(err, "unable to start")
174+
os.Exit(1)
175+
}
176+
}

go.mod

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,18 @@ require (
66
github.com/go-logr/logr v1.4.2
77
github.com/onsi/ginkgo/v2 v2.22.0
88
github.com/onsi/gomega v1.36.1
9-
github.com/spf13/pflag v1.0.5
9+
github.com/spf13/pflag v1.0.6
1010
go.uber.org/zap v1.27.0
11-
golang.org/x/mod v0.21.0
12-
golang.org/x/sync v0.12.0
13-
golang.org/x/sys v0.31.0
11+
golang.org/x/mod v0.24.0
12+
golang.org/x/sync v0.13.0
13+
golang.org/x/sys v0.32.0
1414
k8s.io/api v0.33.0
1515
k8s.io/apiextensions-apiserver v0.33.0
1616
k8s.io/apimachinery v0.33.0
1717
k8s.io/client-go v0.33.0
1818
k8s.io/klog/v2 v2.130.1
19-
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738
19+
k8s.io/utils v0.0.0-20241210054802-24370beab758
20+
sigs.k8s.io/cluster-inventory-api v0.0.0-20250702132726-0f613c6275a5
2021
sigs.k8s.io/controller-runtime v0.21.0
2122
sigs.k8s.io/yaml v1.4.0
2223
)
@@ -25,15 +26,15 @@ require (
2526
github.com/beorn7/perks v1.0.1 // indirect
2627
github.com/blang/semver/v4 v4.0.0 // indirect
2728
github.com/cespare/xxhash/v2 v2.3.0 // indirect
28-
github.com/davecgh/go-spew v1.1.1 // indirect
29-
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
29+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
30+
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
3031
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
31-
github.com/fsnotify/fsnotify v1.7.0 // indirect
32+
github.com/fsnotify/fsnotify v1.8.0 // indirect
3233
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
3334
github.com/go-logr/zapr v1.3.0 // indirect
34-
github.com/go-openapi/jsonpointer v0.21.0 // indirect
35-
github.com/go-openapi/jsonreference v0.20.2 // indirect
36-
github.com/go-openapi/swag v0.23.0 // indirect
35+
github.com/go-openapi/jsonpointer v0.21.1 // indirect
36+
github.com/go-openapi/jsonreference v0.21.0 // indirect
37+
github.com/go-openapi/swag v0.23.1 // indirect
3738
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
3839
github.com/gogo/protobuf v1.3.2 // indirect
3940
github.com/google/btree v1.1.3 // indirect
@@ -43,7 +44,7 @@ require (
4344
github.com/google/uuid v1.6.0 // indirect
4445
github.com/josharian/intern v1.0.0 // indirect
4546
github.com/json-iterator/go v1.1.12 // indirect
46-
github.com/mailru/easyjson v0.7.7 // indirect
47+
github.com/mailru/easyjson v0.9.0 // indirect
4748
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
4849
github.com/modern-go/reflect2 v1.0.2 // indirect
4950
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
@@ -54,19 +55,19 @@ require (
5455
github.com/prometheus/procfs v0.15.1 // indirect
5556
github.com/x448/float16 v0.8.4 // indirect
5657
go.uber.org/multierr v1.11.0 // indirect
57-
golang.org/x/net v0.38.0 // indirect
58-
golang.org/x/oauth2 v0.27.0 // indirect
59-
golang.org/x/term v0.30.0 // indirect
60-
golang.org/x/text v0.23.0 // indirect
61-
golang.org/x/time v0.9.0 // indirect
62-
golang.org/x/tools v0.26.0 // indirect
58+
golang.org/x/net v0.39.0 // indirect
59+
golang.org/x/oauth2 v0.29.0 // indirect
60+
golang.org/x/term v0.31.0 // indirect
61+
golang.org/x/text v0.24.0 // indirect
62+
golang.org/x/time v0.11.0 // indirect
63+
golang.org/x/tools v0.30.0 // indirect
6364
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
64-
google.golang.org/protobuf v1.36.5 // indirect
65+
google.golang.org/protobuf v1.36.6 // indirect
6566
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
6667
gopkg.in/inf.v0 v0.9.1 // indirect
6768
gopkg.in/yaml.v3 v3.0.1 // indirect
6869
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
69-
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
70+
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
7071
sigs.k8s.io/randfill v1.0.0 // indirect
7172
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
7273
)

0 commit comments

Comments
 (0)