From a0a3eb8bf2c5e423378e97eabc06c52d4fb22103 Mon Sep 17 00:00:00 2001 From: Tamal Saha Date: Tue, 11 Jun 2024 14:14:01 -0700 Subject: [PATCH] Create and sync ace-info configmap Signed-off-by: Tamal Saha --- pkg/apiserver/apiserver.go | 28 +++++- pkg/b3/client.go | 11 ++- pkg/cmds/run.go | 1 + pkg/cmds/server/start.go | 3 +- .../clustermetadata/cm_controller.go | 94 +++++++++++++++++++ 5 files changed, 127 insertions(+), 10 deletions(-) create mode 100644 pkg/controllers/clustermetadata/cm_controller.go diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index e0b97f613..2acbc462b 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -33,6 +33,7 @@ import ( policyinstall "kubeops.dev/ui-server/apis/policy/install" policyapi "kubeops.dev/ui-server/apis/policy/v1alpha1" "kubeops.dev/ui-server/pkg/b3" + clustermetacontroller "kubeops.dev/ui-server/pkg/controllers/clustermetadata" projectquotacontroller "kubeops.dev/ui-server/pkg/controllers/projectquota" "kubeops.dev/ui-server/pkg/graph" "kubeops.dev/ui-server/pkg/metricshandler" @@ -90,6 +91,7 @@ import ( "k8s.io/klog/v2" "k8s.io/klog/v2/klogr" "kmodules.xyz/authorizer" + kmapi "kmodules.xyz/client-go/api/v1" cu "kmodules.xyz/client-go/client" clustermeta "kmodules.xyz/client-go/cluster" "kmodules.xyz/client-go/meta" @@ -255,6 +257,11 @@ func (c completedConfig) New(ctx context.Context) (*UIServer, error) { return nil, err } + bc, err := b3.NewClient(c.ExtraConfig.BaseURL, c.ExtraConfig.Token, c.ExtraConfig.CACert, cid) + if err != nil { + return nil, errors.Wrap(err, "failed to create b3 api client") + } + pqr, err := projectquotacontroller.NewReconciler(mgr.GetClient(), kc).SetupWithManager(mgr) if err != nil { klog.Error(err, "unable to create controller", "controller", "ProjectQuota") @@ -271,6 +278,22 @@ func (c completedConfig) New(ctx context.Context) (*UIServer, error) { os.Exit(1) } + if err := mgr.Add(manager.RunnableFunc(func(ctx context.Context) error { + md, err := bc.Identify(cid) + if err != nil { + return err + } + return clustermeta.UpsertClusterMetadata(mgr.GetClient(), md) + })); err != nil { + setupLog.Error(err, fmt.Sprintf("unable to upsert cluster metadata into configmap %s/%s", metav1.NamespacePublic, kmapi.AceInfoConfigMapName)) + os.Exit(1) + } + err = clustermetacontroller.NewReconciler(mgr.GetClient(), bc).SetupWithManager(mgr) + if err != nil { + klog.Error(err, "unable to create controller", "controller", "ConfigMap") + os.Exit(1) + } + s := &UIServer{ GenericAPIServer: genericServer, Manager: mgr, @@ -332,11 +355,6 @@ func (c completedConfig) New(ctx context.Context) (*UIServer, error) { } } { - bc, err := b3.NewClient(c.ExtraConfig.BaseURL, c.ExtraConfig.Token, c.ExtraConfig.CACert, cid) - if err != nil { - return nil, errors.Wrap(err, "failed to create b3 api client") - } - apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(identityapi.GroupName, Scheme, metav1.ParameterCodec, Codecs) v1alpha1storage := map[string]rest.Storage{} diff --git a/pkg/b3/client.go b/pkg/b3/client.go index 3fde29782..bde977d40 100644 --- a/pkg/b3/client.go +++ b/pkg/b3/client.go @@ -69,6 +69,7 @@ func (c *Client) Identify(clusterUID string) (*kmapi.ClusterMetadata, error) { if err != nil { return nil, err // TODO } + apiEndpoint := u.String() u.Path = path.Join(u.Path, "api/v1/clustersv2/identity", clusterUID) req, err := http.NewRequest(http.MethodGet, u.String(), nil) @@ -107,6 +108,10 @@ func (c *Client) Identify(clusterUID string) (*kmapi.ClusterMetadata, error) { if err != nil { return nil, err } + + md.APIEndpoint = apiEndpoint + md.CABundle = string(c.caCert) + return &md, nil } @@ -155,8 +160,8 @@ var ( func (c *Client) GetIdentity() (*identityapi.ClusterIdentity, error) { once.Do(func() error { - var status *kmapi.ClusterMetadata - status, idError = c.Identify(c.clusterUID) + var md *kmapi.ClusterMetadata + md, idError = c.Identify(c.clusterUID) if idError != nil { return idError } @@ -167,7 +172,7 @@ func (c *Client) GetIdentity() (*identityapi.ClusterIdentity, error) { CreationTimestamp: creationTimestamp, Generation: 1, }, - Status: *status, + Status: *md, } idError = nil return idError diff --git a/pkg/cmds/run.go b/pkg/cmds/run.go index bb6734de8..d753e0093 100644 --- a/pkg/cmds/run.go +++ b/pkg/cmds/run.go @@ -51,6 +51,7 @@ func NewCmdRun(ctx context.Context, out, errOut io.Writer) *cobra.Command { return nil }, } + flags := cmd.Flags() o.AddFlags(flags) utilfeature.DefaultMutableFeatureGate.AddFlag(flags) diff --git a/pkg/cmds/server/start.go b/pkg/cmds/server/start.go index 433d82ff0..53aa146cb 100644 --- a/pkg/cmds/server/start.go +++ b/pkg/cmds/server/start.go @@ -196,7 +196,6 @@ func (o *UIServerOptions) Config() (*apiserver.Config, error) { ClientConfig: serverConfig.ClientConfig, PromConfig: *o.PrometheusOptions, } - if err := o.ExtraOptions.ApplyTo(&extraConfig); err != nil { return nil, err } @@ -205,7 +204,6 @@ func (o *UIServerOptions) Config() (*apiserver.Config, error) { GenericConfig: serverConfig, ExtraConfig: extraConfig, } - return config, nil } @@ -215,6 +213,7 @@ func (o UIServerOptions) RunUIServer(ctx context.Context) error { if err != nil { return err } + { metricshandler.RegisterSelfMetrics() telemetryMux := buildTelemetryServer(legacyregistry.DefaultGatherer) diff --git a/pkg/controllers/clustermetadata/cm_controller.go b/pkg/controllers/clustermetadata/cm_controller.go new file mode 100644 index 000000000..4dddc9021 --- /dev/null +++ b/pkg/controllers/clustermetadata/cm_controller.go @@ -0,0 +1,94 @@ +/* +Copyright AppsCode Inc. and Contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package clustermetadata + +import ( + "context" + + "kubeops.dev/ui-server/pkg/b3" + + core "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + kmapi "kmodules.xyz/client-go/api/v1" + clustermeta "kmodules.xyz/client-go/cluster" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/predicate" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +// ClusterMetadataReconciler reconciles a ClusterMetadata object +type ClusterMetadataReconciler struct { + kc client.Client + bc *b3.Client + clusterID string +} + +var _ reconcile.Reconciler = &ClusterMetadataReconciler{} + +func NewReconciler(kc client.Client, bc *b3.Client) *ClusterMetadataReconciler { + return &ClusterMetadataReconciler{ + kc: kc, + bc: bc, + } +} + +func (r *ClusterMetadataReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + md, err := r.bc.Identify(r.clusterID) + if err != nil { + return ctrl.Result{}, err + } + + err = clustermeta.UpsertClusterMetadata(r.kc, md) + return ctrl.Result{}, err +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ClusterMetadataReconciler) SetupWithManager(mgr ctrl.Manager) error { + filter := func(object client.Object) bool { + return object.GetName() == kmapi.AceInfoConfigMapName && + object.GetNamespace() == metav1.NamespacePublic + } + + return ctrl.NewControllerManagedBy(mgr). + For(&core.ConfigMap{}, builder.WithPredicates(predicate.Funcs{ + CreateFunc: func(e event.CreateEvent) bool { + return filter(e.Object) + }, + UpdateFunc: func(e event.UpdateEvent) bool { + if e.ObjectOld == nil { + return false + } + if e.ObjectNew == nil { + return false + } + if e.ObjectNew.GetResourceVersion() == e.ObjectOld.GetResourceVersion() { + return false + } + return filter(e.ObjectNew) + }, + DeleteFunc: func(e event.DeleteEvent) bool { + return filter(e.Object) + }, + GenericFunc: func(e event.GenericEvent) bool { + return filter(e.Object) + }, + })). + Complete(r) +}