Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
SQUASH: cleanup of example
Signed-off-by: Dr. Stefan Schimanski <[email protected]>
  • Loading branch information
sttts committed Apr 23, 2024
commit 8616d540410d3d3c9b4b77109cf23ed1ede4b7ec
43 changes: 20 additions & 23 deletions examples/kcp/config/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ limitations under the License.
package main

import (
"os"

kcpclienthelper "github.com/kcp-dev/apimachinery/v2/pkg/client"
apisv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1"
"github.com/kcp-dev/kcp/sdk/apis/core"
corev1alpha1 "github.com/kcp-dev/kcp/sdk/apis/core/v1alpha1"
tenancyv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/tenancy/v1alpha1"
"github.com/kcp-dev/logicalcluster/v3"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
Expand All @@ -34,8 +35,8 @@ import (

"github.com/kcp-dev/controller-runtime/examples/kcp/config/consumers"
"github.com/kcp-dev/controller-runtime/examples/kcp/config/widgets"
"github.com/kcp-dev/controller-runtime/examples/kcp/config/widgets/resources"
"sigs.k8s.io/controller-runtime/pkg/log"
widgetresources "github.com/kcp-dev/controller-runtime/examples/kcp/config/widgets/resources"
ctrllog "sigs.k8s.io/controller-runtime/pkg/log"
)

// config is bootstrap set of assets for the controller-runtime examples.
Expand All @@ -49,16 +50,11 @@ import (
// done by the platform operator to enable service providers to deploy their
// controllers.

var (
scheme = runtime.NewScheme()
)

func init() {
utilruntime.Must(tenancyv1alpha1.AddToScheme(scheme))
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(corev1alpha1.AddToScheme(scheme))
utilruntime.Must(apisv1alpha1.AddToScheme(scheme))

utilruntime.Must(tenancyv1alpha1.AddToScheme(clientgoscheme.Scheme))
utilruntime.Must(clientgoscheme.AddToScheme(clientgoscheme.Scheme))
utilruntime.Must(corev1alpha1.AddToScheme(clientgoscheme.Scheme))
utilruntime.Must(apisv1alpha1.AddToScheme(clientgoscheme.Scheme))
}

var (
Expand All @@ -73,44 +69,45 @@ func main() {
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))

ctx := ctrl.SetupSignalHandler()
log := log.FromContext(ctx)
log := ctrllog.FromContext(ctx)

restConfig, err := config.GetConfigWithContext("base")
if err != nil {
log.Error(err, "unable to get config")
os.Exit(1)
}

restCopy := rest.CopyConfig(restConfig)
restRoot := rest.AddUserAgent(kcpclienthelper.SetCluster(restCopy, core.RootCluster.Path()), "bootstrap-root")
clientRoot, err := client.New(restRoot, client.Options{
Scheme: scheme,
})
rootClient, err := client.New(restRoot, client.Options{})
if err != nil {
log.Error(err, "unable to create client")
os.Exit(1)
}

restCopy = rest.CopyConfig(restConfig)
restWidgets := rest.AddUserAgent(kcpclienthelper.SetCluster(restCopy, clusterName), "bootstrap-widgets")
clientWidgets, err := client.New(restWidgets, client.Options{
Scheme: scheme,
})
widgetsClient, err := client.New(restWidgets, client.Options{})
if err != nil {
log.Error(err, "unable to create client")
os.Exit(1)
}

err = widgets.Bootstrap(ctx, clientRoot)
err = widgets.Bootstrap(ctx, rootClient)
if err != nil {
log.Error(err, "failed to bootstrap widgets")
os.Exit(1)
}

err = resources.Bootstrap(ctx, clientWidgets)
err = widgetresources.Bootstrap(ctx, widgetsClient)
if err != nil {
log.Error(err, "failed to bootstrap resources")
os.Exit(1)
}

err = consumers.Bootstrap(ctx, clientRoot)
err = consumers.Bootstrap(ctx, rootClient)
if err != nil {
log.Error(err, "failed to bootstrap consumers")
os.Exit(1)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package controllers
package configmap

import (
"context"
"fmt"
"time"

corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/kcp"

ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand All @@ -33,68 +33,63 @@ import (
"sigs.k8s.io/controller-runtime/pkg/log"
)

type ConfigMapReconciler struct {
client.Client
type Reconciler struct {
Client client.Client
}

func (r *ConfigMapReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
log := log.FromContext(ctx).WithValues("cluster", req.ClusterName)

// Test get
var configMap corev1.ConfigMap
if err := r.Client.Get(ctx, req.NamespacedName, &configMap); err != nil {
var cm corev1.ConfigMap
if err := r.Client.Get(ctx, req.NamespacedName, &cm); err != nil {
log.Error(err, "unable to get configmap")
return ctrl.Result{}, nil
}

log.Info("Get: retrieved configMap")
labels := configMap.Labels
if cm.Labels["name"] != "" {
response := fmt.Sprintf("hello-%s", cm.Labels["name"])

if labels["name"] != "" {
response := fmt.Sprintf("hello-%s", labels["name"])

if labels["response"] != response {
labels["response"] = response
if cm.Labels["response"] != response {
cm.Labels["response"] = response

// Test Update
if err := r.Client.Update(ctx, &configMap); err != nil {
if err := r.Client.Update(ctx, &cm); err != nil {
return ctrl.Result{}, err
}

log.Info("Update: updated configMap")
return ctrl.Result{}, nil
}
}

// Test list
var configMapList corev1.ConfigMapList
if err := r.Client.List(ctx, &configMapList); err != nil {
var cms corev1.ConfigMapList
if err := r.Client.List(ctx, &cms); err != nil {
log.Error(err, "unable to list configmaps")
return ctrl.Result{}, nil
}
log.Info("List: got", "itemCount", len(configMapList.Items))
log.Info("List: got", "itemCount", len(cms.Items))
found := false
for _, cm := range configMapList.Items {
for _, other := range cms.Items {
cluster, ok := kontext.ClusterFrom(ctx)
if !ok {
log.Info("List: got", "clusterName", cluster.String(), "namespace", cm.Namespace, "name", cm.Name)
} else {
if cm.Name == configMap.Name && cm.Namespace == configMap.Namespace {
if found {
return ctrl.Result{}, fmt.Errorf("there should be listed only one configmap with the given name '%s' for the given namespace '%s' when the clusterName is not available", cm.Name, cm.Namespace)
}
found = true
log.Info("Found in listed configmaps", "namespace", cm.Namespace, "name", cm.Name)
log.Info("List: got", "clusterName", cluster.String(), "namespace", other.Namespace, "name", other.Name)
} else if other.Name == cm.Name && other.Namespace == cm.Namespace {
if found {
return ctrl.Result{}, fmt.Errorf("there should be listed only one configmap with the given name '%s' for the given namespace '%s' when the clusterName is not available", cm.Name, cm.Namespace)
}
found = true
log.Info("Found in listed configmaps", "namespace", cm.Namespace, "name", cm.Name)
}
}

// If the configmap has a namespace field, create the corresponding namespace
nsName, exists := configMap.Data["namespace"]
nsName, exists := cm.Data["namespace"]
if exists {
var namespace corev1.Namespace
nsKey := types.NamespacedName{Name: nsName}

if err := r.Client.Get(ctx, nsKey, &namespace); err != nil {
if err := r.Client.Get(ctx, types.NamespacedName{Name: nsName}, &namespace); err != nil {
if !apierrors.IsNotFound(err) {
log.Error(err, "unable to get namespace")
return ctrl.Result{}, err
Expand All @@ -107,29 +102,28 @@ func (r *ConfigMapReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, err
}
log.Info("Create: created ", "namespace", nsName)
return ctrl.Result{RequeueAfter: time.Second * 5}, nil
return ctrl.Result{Requeue: true}, nil
}
log.Info("Exists", "namespace", nsName)
}

// If the configmap has a secretData field, create a secret in the same namespace
// If the secret already exists but is out of sync, it will be non-destructively patched
secretData, exists := configMap.Data["secretData"]
secretData, exists := cm.Data["secretData"]
if exists {
var secret corev1.Secret

secret.SetName(configMap.GetName())
secret.SetNamespace(configMap.GetNamespace())
secret.SetOwnerReferences([]metav1.OwnerReference{metav1.OwnerReference{
Name: configMap.GetName(),
UID: configMap.GetUID(),
secret.SetName(cm.GetName())
secret.SetNamespace(cm.GetNamespace())
secret.SetOwnerReferences([]metav1.OwnerReference{{
Name: cm.GetName(),
UID: cm.GetUID(),
APIVersion: "v1",
Kind: "ConfigMap",
Controller: func() *bool { x := true; return &x }(),
}})
secret.Data = map[string][]byte{"dataFromCM": []byte(secretData)}

operationResult, err := controllerutil.CreateOrPatch(ctx, r, &secret, func() error {
operationResult, err := controllerutil.CreateOrPatch(ctx, r.Client, &secret, func() error {
secret.Data["dataFromCM"] = []byte(secretData)
return nil
})
Expand All @@ -143,9 +137,9 @@ func (r *ConfigMapReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, nil
}

func (r *ConfigMapReconciler) SetupWithManager(mgr ctrl.Manager) error {
func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&corev1.ConfigMap{}).
Owns(&corev1.Secret{}).
Complete(WithClusterInContext(r))
Complete(kcp.WithClusterInContext(r))
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,81 +14,70 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package controllers
package widget

import (
"context"

"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/kcp"
"sigs.k8s.io/controller-runtime/pkg/log"

datav1alpha1 "github.com/kcp-dev/controller-runtime/examples/kcp/apis/v1alpha1"
)

// WidgetReconciler reconciles a Widget object
type WidgetReconciler struct {
client.Client
Scheme *runtime.Scheme
// Reconciler reconciles a Widget object
type Reconciler struct {
Client client.Client
}

// Reconcile TODO
func (r *WidgetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
logger := log.FromContext(ctx)
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
log := log.FromContext(ctx)

// Include the clusterName from req.ObjectKey in the logger, similar to the namespace and name keys that are already
// there.
logger = logger.WithValues("clusterName", req.ClusterName)
log = log.WithValues("clusterName", req.ClusterName)

// You probably wouldn't need to do this, but if you wanted to list all instances across all logical clusters:
var allWidgets datav1alpha1.WidgetList
if err := r.Client.List(ctx, &allWidgets); err != nil {
return ctrl.Result{}, err
}

logger.Info("Listed all widgets across all workspaces", "count", len(allWidgets.Items))
log.Info("Listed all widgets across all workspaces", "count", len(allWidgets.Items))

logger.Info("Getting widget")
log.Info("Getting widget")
var w datav1alpha1.Widget
if err := r.Client.Get(ctx, req.NamespacedName, &w); err != nil {
if errors.IsNotFound(err) {
// Normal - was deleted
return ctrl.Result{}, nil
}

return ctrl.Result{}, err
}

logger.Info("Listing all widgets in the current logical cluster")
log.Info("Listing all widgets in the current logical cluster")
var list datav1alpha1.WidgetList
if err := r.Client.List(ctx, &list); err != nil {
return ctrl.Result{}, err
}

numWidgets := len(list.Items)
if numWidgets == w.Status.Total {
logger.Info("No need to patch because the widget status is already correct")
return ctrl.Result{}, nil
}

logger.Info("Patching widget status to store total widget count in the current logical cluster")
original := w.DeepCopy()
patch := client.MergeFrom(original)

w.Status.Total = numWidgets

if err := r.Client.Status().Patch(ctx, &w, patch); err != nil {
log.Info("Patching widget status to store total widget count in the current logical cluster")
orig := w.DeepCopy()
w.Status.Total = len(list.Items)
if err := r.Client.Status().Patch(ctx, &w, client.MergeFromWithOptions(orig, client.MergeFromWithOptimisticLock{})); err != nil {
return ctrl.Result{}, err
}

return ctrl.Result{}, nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *WidgetReconciler) SetupWithManager(mgr ctrl.Manager) error {
func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&datav1alpha1.Widget{}).
Complete(WithClusterInContext(r))
Complete(kcp.WithClusterInContext(r))
}
Loading