Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package csiconfigobservercontroller

import (
"strings"

"k8s.io/client-go/tools/cache"

configinformers "github.com/openshift/client-go/config/informers/externalversions"
configlistersv1 "github.com/openshift/client-go/config/listers/config/v1"

"github.com/openshift/library-go/pkg/controller/factory"
"github.com/openshift/library-go/pkg/operator/configobserver"
"github.com/openshift/library-go/pkg/operator/configobserver/proxy"
"github.com/openshift/library-go/pkg/operator/events"
"github.com/openshift/library-go/pkg/operator/resourcesynccontroller"
"github.com/openshift/library-go/pkg/operator/v1helpers"
)

// ProxyConfigPath returns the path for the observed proxy config. This is a
// function to avoid exposing a slice that could potentially be appended.
func ProxyConfigPath() []string {
return []string{"targetcsiconfig", "proxy"}
}

// Listers implement the configobserver.Listers interface.
type Listers struct {
ProxyLister_ configlistersv1.ProxyLister

ResourceSync resourcesynccontroller.ResourceSyncer
PreRunCachesSynced []cache.InformerSynced
}

func (l Listers) ProxyLister() configlistersv1.ProxyLister {
return l.ProxyLister_
}

func (l Listers) ResourceSyncer() resourcesynccontroller.ResourceSyncer {
return l.ResourceSync
}

func (l Listers) PreRunHasSynced() []cache.InformerSynced {
return l.PreRunCachesSynced
}

// CISConfigObserverController watches information that's relevant to CSI driver operators.
// For now it only observes proxy information, (through the proxy.config.openshift.io/cluster
// object), but more will be added.
type CSIConfigObserverController struct {
factory.Controller
}

// NewCSIConfigObserverController returns a new CSIConfigObserverController.
func NewCSIConfigObserverController(
name string,
operatorClient v1helpers.OperatorClient,
configinformers configinformers.SharedInformerFactory,
eventRecorder events.Recorder,
) *CSIConfigObserverController {
informers := []factory.Informer{
operatorClient.Informer(),
configinformers.Config().V1().Proxies().Informer(),
}

c := &CSIConfigObserverController{
Controller: configobserver.NewConfigObserver(
operatorClient,
eventRecorder.WithComponentSuffix("csi-config-observer-controller-"+strings.ToLower(name)),
Listers{
ProxyLister_: configinformers.Config().V1().Proxies().Lister(),
PreRunCachesSynced: append([]cache.InformerSynced{},
operatorClient.Informer().HasSynced,
configinformers.Config().V1().Proxies().Informer().HasSynced,
),
},
informers,
proxy.NewProxyObserveFunc(ProxyConfigPath()),
),
}

return c
}
43 changes: 37 additions & 6 deletions pkg/operator/csi/csicontrollerset/csi_controller_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,26 @@ package csicontrollerset

import (
"context"
"fmt"

utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"

configinformers "github.com/openshift/client-go/config/informers/externalversions"
"github.com/openshift/library-go/pkg/controller/factory"
"github.com/openshift/library-go/pkg/operator/csi/credentialsrequestcontroller"
"github.com/openshift/library-go/pkg/operator/csi/csiconfigobservercontroller"
"github.com/openshift/library-go/pkg/operator/csi/csidrivercontrollerservicecontroller"
"github.com/openshift/library-go/pkg/operator/csi/csidrivernodeservicecontroller"
"github.com/openshift/library-go/pkg/operator/events"
"github.com/openshift/library-go/pkg/operator/loglevel"
"github.com/openshift/library-go/pkg/operator/management"
"github.com/openshift/library-go/pkg/operator/resource/resourceapply"
"github.com/openshift/library-go/pkg/operator/staticresourcecontroller"
"github.com/openshift/library-go/pkg/operator/v1helpers"

"github.com/openshift/library-go/pkg/operator/csi/credentialsrequestcontroller"
"github.com/openshift/library-go/pkg/operator/csi/csidrivercontrollerservicecontroller"
"github.com/openshift/library-go/pkg/operator/csi/csidrivernodeservicecontroller"
)

// CSIControllerSet contains a set of controllers that are usually used to deploy CSI Drivers.
Expand All @@ -28,20 +30,27 @@ type CSIControllerSet struct {
managementStateController factory.Controller
staticResourcesController factory.Controller
credentialsRequestController factory.Controller
csiConfigObserverController factory.Controller
csiDriverControllerServiceController factory.Controller
csiDriverNodeServiceController factory.Controller

operatorClient v1helpers.OperatorClient
eventRecorder events.Recorder
preRunCachesSynced []cache.InformerSynced
operatorClient v1helpers.OperatorClient
eventRecorder events.Recorder
}

// Run starts all controllers initialized in the set.
func (c *CSIControllerSet) Run(ctx context.Context, workers int) {
if !cache.WaitForCacheSync(ctx.Done(), c.preRunCachesSynced...) {
utilruntime.HandleError(fmt.Errorf("caches did not sync"))
return
}
for _, ctrl := range []factory.Controller{
c.logLevelController,
c.managementStateController,
c.staticResourcesController,
c.credentialsRequestController,
c.csiConfigObserverController,
c.csiDriverControllerServiceController,
c.csiDriverNodeServiceController,
} {
Expand Down Expand Up @@ -109,6 +118,19 @@ func (c *CSIControllerSet) WithCredentialsRequestController(
return c
}

func (c *CSIControllerSet) WithCSIConfigObserverController(
name string,
configinformers configinformers.SharedInformerFactory,
) *CSIControllerSet {
c.csiConfigObserverController = csiconfigobservercontroller.NewCSIConfigObserverController(
name,
c.operatorClient,
configinformers,
c.eventRecorder,
)
return c
}

func (c *CSIControllerSet) WithCSIDriverControllerService(
name string,
assetFunc func(string) []byte,
Expand Down Expand Up @@ -153,6 +175,15 @@ func (c *CSIControllerSet) WithCSIDriverNodeService(
return c
}

// WithExtraInformers adds informers that individual controllers don't wait for. These are typically
// informers used by hook functions in csidrivercontrollerservicecontroller and csidrivernodeservicecontroller.
func (c *CSIControllerSet) WithExtraInformers(informers ...cache.SharedIndexInformer) *CSIControllerSet {
for i := range informers {
c.preRunCachesSynced = append(c.preRunCachesSynced, informers[i].HasSynced)
}
return c
}

// New returns a basic *ControllerSet without any controller.
func NewCSIControllerSet(operatorClient v1helpers.OperatorClient, eventRecorder events.Recorder) *CSIControllerSet {
return &CSIControllerSet{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,21 @@ import (
"strings"
"time"

appsv1 "k8s.io/api/apps/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
appsinformersv1 "k8s.io/client-go/informers/apps/v1"
"k8s.io/client-go/kubernetes"

opv1 "github.com/openshift/api/operator/v1"
configinformers "github.com/openshift/client-go/config/informers/externalversions"

"github.com/openshift/library-go/pkg/controller/factory"
"github.com/openshift/library-go/pkg/operator/events"
"github.com/openshift/library-go/pkg/operator/loglevel"
"github.com/openshift/library-go/pkg/operator/resource/resourceapply"
"github.com/openshift/library-go/pkg/operator/resource/resourcemerge"
"github.com/openshift/library-go/pkg/operator/resource/resourceread"
"github.com/openshift/library-go/pkg/operator/v1helpers"
appsv1 "k8s.io/api/apps/v1"
appsinformersv1 "k8s.io/client-go/informers/apps/v1"
"k8s.io/client-go/kubernetes"
)

const (
Expand All @@ -36,7 +37,7 @@ const (
)

// DeploymentHookFunc is a hook function to modify the Deployment.
type DeploymentHookFunc func(*appsv1.Deployment) error
type DeploymentHookFunc func(*opv1.OperatorSpec, *appsv1.Deployment) error

// CSIDriverControllerServiceController is a controller that deploys a CSI Controller Service to a given namespace.
//
Expand Down Expand Up @@ -162,7 +163,7 @@ func (c *CSIDriverControllerServiceController) sync(ctx context.Context, syncCon
required := resourceread.ReadDeploymentV1OrDie(manifest)

for i := range c.optionalDeploymentHooks {
err := c.optionalDeploymentHooks[i](required)
err := c.optionalDeploymentHooks[i](opSpec, required)
if err != nil {
return fmt.Errorf("error running hook function (index=%d): %w", i, err)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ func addGenerationReactor(client *fakecore.Clientset) {
})
}

func deploymentAnnotationHook(instance *appsv1.Deployment) error {
func deploymentAnnotationHook(opSpec *opv1.OperatorSpec, instance *appsv1.Deployment) error {
if instance.Annotations == nil {
instance.Annotations = map[string]string{}
}
Expand Down
65 changes: 65 additions & 0 deletions pkg/operator/csi/csidrivercontrollerservicecontroller/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package csidrivercontrollerservicecontroller

import (
"crypto/sha256"
"fmt"
"strings"

appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/client-go/informers/core/v1"

opv1 "github.com/openshift/api/operator/v1"

"github.com/openshift/library-go/pkg/operator/csi/csiconfigobservercontroller"
"github.com/openshift/library-go/pkg/operator/resource/resourcehash"
"github.com/openshift/library-go/pkg/operator/v1helpers"
)

// WithObservedProxyDeploymentHook creates a deployment hook that injects into the deployment's containers the observed proxy config.
func WithObservedProxyDeploymentHook() DeploymentHookFunc {
return func(opSpec *opv1.OperatorSpec, deployment *appsv1.Deployment) error {
containerNamesString := deployment.Annotations["config.openshift.io/inject-proxy"]
err := v1helpers.InjectObservedProxyIntoContainers(
&deployment.Spec.Template.Spec,
strings.Split(containerNamesString, ","),
opSpec.ObservedConfig.Raw,
csiconfigobservercontroller.ProxyConfigPath()...,
)
return err
}
}

// With SecretHashAnnotationHook creates a deployment hook that annotates a Deployment with a secret's hash.
func WithSecretHashAnnotationHook(
namespace string,
secretName string,
secretInformer corev1.SecretInformer,
) DeploymentHookFunc {
return func(opSpec *opv1.OperatorSpec, deployment *appsv1.Deployment) error {
inputHashes, err := resourcehash.MultipleObjectHashStringMapForObjectReferenceFromLister(
nil,
secretInformer.Lister(),
resourcehash.NewObjectRef().ForSecret().InNamespace(namespace).Named(secretName),
)
if err != nil {
return fmt.Errorf("invalid dependency reference: %w", err)
}
if deployment.Annotations == nil {
deployment.Annotations = map[string]string{}
}
if deployment.Spec.Template.Annotations == nil {
deployment.Spec.Template.Annotations = map[string]string{}
}
for k, v := range inputHashes {
annotationKey := fmt.Sprintf("operator.openshift.io/dep-%s", k)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets move this into a var/constant

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to leave this on as is. I prefer to leave format strings inline, plus I couldn't re-use the const for the annotation below (%x != %s)

if len(annotationKey) > 63 {
hash := sha256.Sum256([]byte(k))
annotationKey = fmt.Sprintf("operator.openshift.io/dep-%x", hash)
annotationKey = annotationKey[:63]
}
deployment.Annotations[annotationKey] = v
deployment.Spec.Template.Annotations[annotationKey] = v
}
return nil
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const (
)

// DaemonSetHookFunc is a hook function to modify the DaemonSet.
type DaemonSetHookFunc func(*appsv1.DaemonSet) error
type DaemonSetHookFunc func(*opv1.OperatorSpec, *appsv1.DaemonSet) error

// CSIDriverNodeServiceController is a controller that deploys a CSI Node Service to a given namespace.
//
Expand Down Expand Up @@ -128,7 +128,7 @@ func (c *CSIDriverNodeServiceController) sync(ctx context.Context, syncContext f
required := resourceread.ReadDaemonSetV1OrDie(manifest)

for i := range c.optionalDaemonSetHooks {
err := c.optionalDaemonSetHooks[i](required)
err := c.optionalDaemonSetHooks[i](opSpec, required)
if err != nil {
return fmt.Errorf("error running hook function (index=%d): %w", i, err)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ func addGenerationReactor(client *fakecore.Clientset) {
})
}

func daemonSetAnnotationHook(instance *appsv1.DaemonSet) error {
func daemonSetAnnotationHook(opSpec *opv1.OperatorSpec, instance *appsv1.DaemonSet) error {
if instance.Annotations == nil {
instance.Annotations = map[string]string{}
}
Expand Down
25 changes: 25 additions & 0 deletions pkg/operator/csi/csidrivernodeservicecontroller/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package csidrivernodeservicecontroller

import (
"strings"

opv1 "github.com/openshift/api/operator/v1"
appsv1 "k8s.io/api/apps/v1"

"github.com/openshift/library-go/pkg/operator/csi/csiconfigobservercontroller"
"github.com/openshift/library-go/pkg/operator/v1helpers"
)

// WithObservedProxyDaemonSetHook creates a hook that injects into the daemonSet's containers the observed proxy config.
func WithObservedProxyDaemonSetHook() DaemonSetHookFunc {
return func(opSpec *opv1.OperatorSpec, daemonSet *appsv1.DaemonSet) error {
containerNamesString := daemonSet.Annotations["config.openshift.io/inject-proxy"]
err := v1helpers.InjectObservedProxyIntoContainers(
&daemonSet.Spec.Template.Spec,
strings.Split(containerNamesString, ","),
opSpec.ObservedConfig.Raw,
csiconfigobservercontroller.ProxyConfigPath()...,
)
return err
}
}
Loading