Skip to content

Commit

Permalink
Merge pull request GoogleCloudPlatform#1910 from yuwenma/register-dir…
Browse files Browse the repository at this point in the history
…ect-controller

Register direct controller from crd annotation
  • Loading branch information
google-oss-prow[bot] authored Jun 3, 2024
2 parents 140d7c5 + 9a749a4 commit ea7ee5c
Show file tree
Hide file tree
Showing 13 changed files with 176 additions and 151 deletions.
2 changes: 2 additions & 0 deletions cmd/manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ import (
klog "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/manager/signals"

_ "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/register"
)

var logger = klog.Log.WithName("setup")
Expand Down
25 changes: 9 additions & 16 deletions pkg/controller/direct/alloydb/cluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,30 +28,23 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/manager"

krm "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/clients/generated/apis/alloydb/v1beta1"
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller"
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/directbase"
)

// AddClusterController creates a new controller and adds it to the Manager.
// The Manager will set fields on the Controller and start it when the Manager is started.
func AddClusterController(mgr manager.Manager, config *controller.Config, opts directbase.Deps) error {
gvk := krm.AlloyDBClusterGVK
func init() {
directbase.ControllerBuilder.RegisterModel(krm.AlloyDBClusterGVK, NewModel)
}

// TODO: Share gcp client (any value in doing so)?
ctx := context.TODO()
gcpClient, err := newGCPClient(ctx, config)
if err != nil {
return err
}
m := &clusterModel{gcpClient: gcpClient}
return directbase.Add(mgr, gvk, m, opts)
func NewModel(config *controller.Config) directbase.Model {
return &clusterModel{config: config}
}

type clusterModel struct {
*gcpClient
// *gcpClient
config *controller.Config
}

// model implements the Model interface.
Expand All @@ -73,11 +66,11 @@ var _ directbase.Adapter = &clusterAdapter{}
// AdapterForObject implements the Model interface.
func (m *clusterModel) AdapterForObject(ctx context.Context, reader client.Reader, u *unstructured.Unstructured) (directbase.Adapter, error) {
klog.FromContext(ctx).V(0).Info("creating adapter", "u", u)
client, err := m.newAlloyDBAdminClient(ctx)
gcpClient, err := newGCPClient(ctx, m.config)
if err != nil {
return nil, err
}

client, err := gcpClient.newAlloyDBAdminClient(ctx)
obj := &krm.AlloyDBCluster{}
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &obj); err != nil {
return nil, fmt.Errorf("error converting to %T: %w", obj, err)
Expand Down
11 changes: 5 additions & 6 deletions pkg/controller/direct/apikeys/apikeyskey_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/manager"

krm "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/clients/generated/apis/apikeys/v1alpha1"
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller"
Expand All @@ -36,12 +35,12 @@ import (
. "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/mappings" //nolint:revive
)

// AddKeyReconciler creates a new controller and adds it to the Manager.
// The Manager will set fields on the Controller and start it when the Manager is started.
func AddKeyReconciler(mgr manager.Manager, config *controller.Config, opts directbase.Deps) error {
gvk := krm.APIKeysKeyGVK
func init() {
directbase.ControllerBuilder.RegisterModel(krm.APIKeysKeyGVK, NewModel)
}

return directbase.Add(mgr, gvk, &model{config: *config}, opts)
func NewModel(config *controller.Config) directbase.Model {
return &model{config: *config}
}

type model struct {
Expand Down
73 changes: 67 additions & 6 deletions pkg/controller/direct/directbase/directbase_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (

"github.com/GoogleCloudPlatform/k8s-config-connector/operator/pkg/apis/core/v1beta1"
"github.com/GoogleCloudPlatform/k8s-config-connector/operator/pkg/kccstate"
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller"
kcciamclient "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/iam/iamclient"
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/jitter"
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/lifecyclehandler"
Expand All @@ -34,6 +35,7 @@ import (
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/execution"
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/k8s"
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/util"
apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"

"golang.org/x/sync/semaphore"
apierrors "k8s.io/apimachinery/pkg/api/errors"
Expand All @@ -53,22 +55,81 @@ import (
"sigs.k8s.io/controller-runtime/pkg/source"
)

// Add creates a new controller for reconciling objects of the specified GVK, delegating actual resource reconciliation to the provided Model.
func Add(mgr manager.Manager, gvk schema.GroupVersionKind, model Model, opts Deps) error {
var ControllerBuilder directControllerBuilder

func init() {
ControllerBuilder = directControllerBuilder{}
}

type directControllerBuilder struct {
modelMapper map[schema.GroupVersionKind]func(*controller.Config) Model
}

func (c *directControllerBuilder) RegisterModel(gvk schema.GroupVersionKind, modelFn func(*controller.Config) Model) {
if c.modelMapper == nil {
c.modelMapper = map[schema.GroupVersionKind]func(*controller.Config) Model{}
}
c.modelMapper[gvk] = modelFn
}

func (c *directControllerBuilder) AddController(mgr manager.Manager, config *controller.Config, gvk schema.GroupVersionKind, deps Deps) error {
immediateReconcileRequests := make(chan event.GenericEvent, k8s.ImmediateReconcileRequestsBufferSize)
resourceWatcherRoutines := semaphore.NewWeighted(k8s.MaxNumResourceWatcherRoutines)
reconciler, err := NewReconciler(mgr, immediateReconcileRequests, resourceWatcherRoutines, gvk, model, opts.JitterGenerator)

reconciler, err := c.NewReconciler(mgr, config, immediateReconcileRequests, resourceWatcherRoutines, gvk, deps.JitterGenerator)
if err != nil {
return err
}
return add(mgr, reconciler)
}

// NewReconciler returns a new reconcile.Reconciler.
func NewReconciler(mgr manager.Manager, immediateReconcileRequests chan event.GenericEvent, resourceWatcherRoutines *semaphore.Weighted,
gvk schema.GroupVersionKind, model Model, jg jitter.Generator) (*DirectReconciler, error) {
func (c *directControllerBuilder) IsDirectByCRD(crd *apiextensions.CustomResourceDefinition) bool {
for gvk, _ := range c.modelMapper {
if gvk.Group == crd.Spec.Group && gvk.Kind == crd.Spec.Names.Kind {
for _, version := range crd.Spec.Versions {
if gvk.Version == version.Name {
return true
}
}

}
}
return false
}

func (c *directControllerBuilder) IsDirectByGK(gk schema.GroupKind) bool {
if c.modelMapper == nil {
return false
}
for gvk, _ := range c.modelMapper {
if gvk.Group == gk.Group && gvk.Kind == gk.Kind {
return true
}
}
return false
}

func (c *directControllerBuilder) IsDirectByGVK(gvk schema.GroupVersionKind) bool {
if c.modelMapper == nil {
return false
}
_, ok := c.modelMapper[gvk]
if ok {
return true
}
return false
}

// NewReconciler returns a new reconcile.Reconciler.
func (c *directControllerBuilder) NewReconciler(mgr manager.Manager, config *controller.Config, immediateReconcileRequests chan event.GenericEvent, resourceWatcherRoutines *semaphore.Weighted,
gvk schema.GroupVersionKind, jg jitter.Generator) (*DirectReconciler, error) {
controllerName := strings.ToLower(gvk.Kind) + "-controller"
modelFn, ok := c.modelMapper[gvk]
if !ok {
return nil, fmt.Errorf("no direct controller is registered for GroupVersionKind %s", gvk)
}
model := modelFn(config)

if jg == nil {
return nil, fmt.Errorf("jitter generator is not initialized")
}
Expand Down
25 changes: 12 additions & 13 deletions pkg/controller/direct/gkehub/featuremembership_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/manager"

krm "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/clients/generated/apis/gkehub/v1beta1"
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller"
Expand All @@ -34,21 +33,16 @@ import (

const ctrlName = "gkehubfeaturemembership-controller"

// AddGkeHubController creates a new controller and adds it to the Manager.
// The Manager will set fields on the Controller and start it when the Manager is started.
func AddGkeHubController(mgr manager.Manager, config *controller.Config, opts directbase.Deps) error {
gvk := krm.GKEHubFeatureMembershipGVK
func init() {
directbase.ControllerBuilder.RegisterModel(krm.GKEHubFeatureMembershipGVK, GetModel)
}

gcpClient, err := newGCPClient(config)
if err != nil {
return err
}
m := &gkeHubModel{gcpClient: gcpClient}
return directbase.Add(mgr, gvk, m, opts)
func GetModel(config *controller.Config) directbase.Model {
return &gkeHubModel{config: config}
}

type gkeHubModel struct {
gcpClient *gcpClient
config *controller.Config
}

// model implements the Model interface.
Expand All @@ -70,7 +64,12 @@ var _ directbase.Adapter = &gkeHubAdapter{}

// AdapterForObject implements the Model interface.
func (m *gkeHubModel) AdapterForObject(ctx context.Context, reader client.Reader, u *unstructured.Unstructured) (directbase.Adapter, error) {
projectsLocationsFeaturesService, err := m.gcpClient.newProjectsLocationsFeaturesService(ctx)
gcpClient, err := newGCPClient(m.config)
if err != nil {
return nil, err
}

projectsLocationsFeaturesService, err := gcpClient.newProjectsLocationsFeaturesService(ctx)
if err != nil {
return nil, err
}
Expand Down
33 changes: 11 additions & 22 deletions pkg/controller/direct/logging/logmetric_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/manager"

krm "github.com/GoogleCloudPlatform/k8s-config-connector/apis/resources/logging/v1beta1"
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/apis/k8s/v1alpha1"
Expand All @@ -36,31 +35,16 @@ import (

const ctrlName = "logmetric-controller"

// AddLogMetricController creates a new controller and adds it to the Manager.
// The Manager will set fields on the Controller and start it when the Manager is started.
func AddLogMetricController(mgr manager.Manager, config *controller.Config, opts directbase.Deps) error {
gvk := krm.LoggingLogMetricGVK

// todo(acpana): plumb context throughout direct
ctx := context.TODO()
gcpClient, err := newGCPClient(ctx, config)
if err != nil {
return err
}
m := &logMetricModel{gcpClient: gcpClient}
return directbase.Add(mgr, gvk, m, opts)
func init() {
directbase.ControllerBuilder.RegisterModel(krm.LoggingLogMetricGVK, GetModel)
}

func GetModel(ctx context.Context, config *controller.Config) (directbase.Model, error) {
gcpClient, err := newGCPClient(ctx, config)
if err != nil {
return nil, err
}
return &logMetricModel{gcpClient: gcpClient}, nil
func GetModel(config *controller.Config) directbase.Model {
return &logMetricModel{config: config}
}

type logMetricModel struct {
*gcpClient
config *controller.Config
}

// model implements the Model interface.
Expand All @@ -79,7 +63,12 @@ var _ directbase.Adapter = &logMetricAdapter{}

// AdapterForObject implements the Model interface.
func (m *logMetricModel) AdapterForObject(ctx context.Context, reader client.Reader, u *unstructured.Unstructured) (directbase.Adapter, error) {
projectMetricsService, err := m.newProjectMetricsService(ctx)
gcpClient, err := newGCPClient(ctx, m.config)
if err != nil {
return nil, err
}

projectMetricsService, err := gcpClient.newProjectMetricsService(ctx)
if err != nil {
return nil, err
}
Expand Down
23 changes: 23 additions & 0 deletions pkg/controller/direct/register/register.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2024 Google LLC
//
// 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 register

import (
_ "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/alloydb"
_ "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/apikeys"
_ "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/gkehub"
_ "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/logging"
_ "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/resourcemanager"
)
5 changes: 1 addition & 4 deletions pkg/controller/direct/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,7 @@ func Export(ctx context.Context, url string, config *controller.Config) (*unstru
if strings.HasPrefix(url, "//logging.googleapis.com/") {
tokens := strings.Split(strings.TrimPrefix(url, "//logging.googleapis.com/"), "/")
if len(tokens) == 4 && tokens[0] == "projects" && tokens[2] == "metrics" {
m, err := logging.GetModel(ctx, config)
if err != nil {
return nil, err
}
m := logging.GetModel(config)
in := &unstructured.Unstructured{}
in.SetName(tokens[3])
if err := unstructured.SetNestedField(in.Object, tokens[1], "spec", "projectRef", "external"); err != nil {
Expand Down
29 changes: 13 additions & 16 deletions pkg/controller/direct/resourcemanager/tagkey_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,30 +28,22 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/manager"

krm "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/clients/generated/apis/tags/v1beta1"
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller"
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/directbase"
)

// AddTagKeyController creates a new controller and adds it to the Manager.
// The Manager will set fields on the Controller and start it when the Manager is started.
func AddTagKeyController(mgr manager.Manager, config *controller.Config, opts directbase.Deps) error {
gvk := krm.TagsTagKeyGVK
func init() {
directbase.ControllerBuilder.RegisterModel(krm.TagsTagKeyGVK, GetModel)
}

// TODO: Share gcp client (any value in doing so)?
ctx := context.TODO()
gcpClient, err := newGCPClient(ctx, config)
if err != nil {
return err
}
m := &tagKeyModel{gcpClient: gcpClient}
return directbase.Add(mgr, gvk, m, opts)
func GetModel(config *controller.Config) directbase.Model {
return &tagKeyModel{config: config}
}

type tagKeyModel struct {
*gcpClient
config *controller.Config
}

// model implements the Model interface.
Expand All @@ -72,7 +64,12 @@ var _ directbase.Adapter = &tagKeyAdapter{}

// AdapterForObject implements the Model interface.
func (m *tagKeyModel) AdapterForObject(ctx context.Context, reader client.Reader, u *unstructured.Unstructured) (directbase.Adapter, error) {
tagKeysClient, err := m.newTagKeysClient(ctx)
gcpClient, err := newGCPClient(ctx, m.config)
if err != nil {
return nil, err
}

tagKeysClient, err := gcpClient.newTagKeysClient(ctx)
if err != nil {
return nil, err
}
Expand All @@ -91,7 +88,7 @@ func (m *tagKeyModel) AdapterForObject(ctx context.Context, reader client.Reader
return &tagKeyAdapter{
resourceID: resourceID,
desired: obj,
gcpClient: m.gcpClient,
gcpClient: gcpClient,
tagKeysClient: tagKeysClient,
}, nil
}
Expand Down
Loading

0 comments on commit ea7ee5c

Please sign in to comment.