Skip to content

Commit

Permalink
Merge pull request red-hat-storage#115 from leelavg/5496-webhook
Browse files Browse the repository at this point in the history
implement webhook for validating ocs-client-operator subscription channel
  • Loading branch information
openshift-merge-bot[bot] authored Mar 25, 2024
2 parents c3db819 + 9dd4342 commit 300e2b6
Show file tree
Hide file tree
Showing 12 changed files with 308 additions and 22 deletions.
1 change: 1 addition & 0 deletions config/manager/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
resources:
- manager.yaml
- webhook_service.yaml

generatorOptions:
disableNameSuffixHash: true
Expand Down
8 changes: 8 additions & 0 deletions config/manager/manager.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,20 @@ metadata:
namespace: system
labels:
control-plane: controller-manager
app: ocs-client-operator
spec:
selector:
matchLabels:
control-plane: controller-manager
app: ocs-client-operator
replicas: 1
template:
metadata:
annotations:
kubectl.kubernetes.io/default-container: manager
labels:
control-plane: controller-manager
app: ocs-client-operator
spec:
securityContext:
runAsNonRoot: true
Expand All @@ -36,6 +39,8 @@ spec:
volumeMounts:
- name: csi-images
mountPath: /opt/config
- mountPath: /etc/tls/private
name: webhook-cert-secret
env:
- name: OPERATOR_NAMESPACE
valueFrom:
Expand Down Expand Up @@ -74,5 +79,8 @@ spec:
- name: csi-images
configMap:
name: csi-images
- name: webhook-cert-secret
secret:
secretName: webhook-cert-secret
serviceAccountName: controller-manager
terminationGracePeriodSeconds: 10
16 changes: 16 additions & 0 deletions config/manager/webhook_service.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
apiVersion: v1
kind: Service
metadata:
annotations:
service.beta.openshift.io/serving-cert-secret-name: webhook-cert-secret
name: webhook-server
namespace: system
spec:
ports:
- name: https
port: 443
protocol: TCP
targetPort: 7443
selector:
app: ocs-client-operator
type: ClusterIP
18 changes: 18 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ rules:
verbs:
- get
- list
- apiGroups:
- admissionregistration.k8s.io
resources:
- validatingwebhookconfigurations
verbs:
- create
- get
- list
- update
- watch
- apiGroups:
- apps
Expand Down Expand Up @@ -204,6 +213,15 @@ rules:
- get
- list
- watch
- apiGroups:
- operators.coreos.com
resources:
- subscriptions
verbs:
- get
- list
- update
- watch
- apiGroups:
- security.openshift.io
resources:
Expand Down
1 change: 1 addition & 0 deletions config/rbac/status-reporter-clusterrole.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ rules:
verbs:
- get
- list
- patch
- apiGroups:
- ""
resources:
Expand Down
119 changes: 116 additions & 3 deletions controllers/clusterversion_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,14 @@ import (
"github.com/red-hat-storage/ocs-client-operator/pkg/console"
"github.com/red-hat-storage/ocs-client-operator/pkg/csi"
"github.com/red-hat-storage/ocs-client-operator/pkg/templates"
"github.com/red-hat-storage/ocs-client-operator/pkg/utils"

"github.com/go-logr/logr"
configv1 "github.com/openshift/api/config/v1"
secv1 "github.com/openshift/api/security/v1"
opv1a1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
admrv1 "k8s.io/api/admissionregistration/v1"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
extv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
Expand All @@ -57,9 +60,10 @@ const (
operatorConfigMapName = "ocs-client-operator-config"
// ClusterVersionName is the name of the ClusterVersion object in the
// openshift cluster.
clusterVersionName = "version"

deployCSIKey = "DEPLOY_CSI"
clusterVersionName = "version"
deployCSIKey = "DEPLOY_CSI"
subscriptionLabelKey = "managed-by"
subscriptionLabelValue = "webhook.subscription.ocs.openshift.io"
)

// ClusterVersionReconciler reconciles a ClusterVersion object
Expand Down Expand Up @@ -106,10 +110,29 @@ func (c *ClusterVersionReconciler) SetupWithManager(mgr ctrl.Manager) error {
},
)

subscriptionPredicates := builder.WithPredicates(
predicate.NewPredicateFuncs(
func(client client.Object) bool {
return client.GetNamespace() == c.OperatorNamespace
},
),
predicate.LabelChangedPredicate{},
)

webhookPredicates := builder.WithPredicates(
predicate.NewPredicateFuncs(
func(client client.Object) bool {
return client.GetName() == templates.SubscriptionWebhookName
},
),
)

return ctrl.NewControllerManagedBy(mgr).
For(&configv1.ClusterVersion{}, clusterVersionPredicates).
Watches(&corev1.ConfigMap{}, enqueueClusterVersionRequest, configMapPredicates).
Watches(&extv1.CustomResourceDefinition{}, enqueueClusterVersionRequest, builder.OnlyMetadata).
Watches(&opv1a1.Subscription{}, enqueueClusterVersionRequest, subscriptionPredicates).
Watches(&admrv1.ValidatingWebhookConfiguration{}, enqueueClusterVersionRequest, webhookPredicates).
Complete(c)
}

Expand All @@ -127,6 +150,8 @@ func (c *ClusterVersionReconciler) SetupWithManager(mgr ctrl.Manager) error {
//+kubebuilder:rbac:groups=monitoring.coreos.com,resources=prometheusrules,verbs=get;list;watch;create;update
//+kubebuilder:rbac:groups="",resources=services,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=console.openshift.io,resources=consoleplugins,verbs=*
//+kubebuilder:rbac:groups=operators.coreos.com,resources=subscriptions,verbs=get;list;watch;update
//+kubebuilder:rbac:groups=admissionregistration.k8s.io,resources=validatingwebhookconfigurations,verbs=get;list;update;create;watch

// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/[email protected]/pkg/reconcile
Expand All @@ -135,6 +160,16 @@ func (c *ClusterVersionReconciler) Reconcile(ctx context.Context, req ctrl.Reque
c.log = log.FromContext(ctx, "ClusterVersion", req)
c.log.Info("Reconciling ClusterVersion")

if err := c.reconcileSubscriptionValidatingWebhook(); err != nil {
c.log.Error(err, "unable to register subscription validating webhook")
return ctrl.Result{}, err
}

if err := labelClientOperatorSubscription(c); err != nil {
c.log.Error(err, "unable to label ocs client operator subscription")
return ctrl.Result{}, err
}

if err := c.ensureConsolePlugin(); err != nil {
c.log.Error(err, "unable to deploy client console")
return ctrl.Result{}, err
Expand Down Expand Up @@ -494,3 +529,81 @@ func (c *ClusterVersionReconciler) getDeployCSIConfig() (bool, error) {
func (c *ClusterVersionReconciler) get(obj client.Object, opts ...client.GetOption) error {
return c.Get(c.ctx, client.ObjectKeyFromObject(obj), obj, opts...)
}

func (c *ClusterVersionReconciler) reconcileSubscriptionValidatingWebhook() error {
whConfig := &admrv1.ValidatingWebhookConfiguration{}
whConfig.Name = templates.SubscriptionWebhookName

// TODO (lgangava): after change to configmap controller, need to remove webhook during deletion
err := c.createOrUpdate(whConfig, func() error {

// openshift fills in the ca on finding this annotation
whConfig.Annotations = map[string]string{
"service.beta.openshift.io/inject-cabundle": "true",
}

var caBundle []byte
if len(whConfig.Webhooks) == 0 {
whConfig.Webhooks = make([]admrv1.ValidatingWebhook, 1)
} else {
// do not mutate CA bundle that was injected by openshift
caBundle = whConfig.Webhooks[0].ClientConfig.CABundle
}

// webhook desired state
var wh *admrv1.ValidatingWebhook = &whConfig.Webhooks[0]
templates.SubscriptionValidatingWebhook.DeepCopyInto(wh)

wh.Name = whConfig.Name
// only send requests received from own namespace
wh.NamespaceSelector = &metav1.LabelSelector{
MatchLabels: map[string]string{
"kubernetes.io/metadata.name": c.OperatorNamespace,
},
}
// only send resources matching the label
wh.ObjectSelector = &metav1.LabelSelector{
MatchLabels: map[string]string{
subscriptionLabelKey: subscriptionLabelValue,
},
}
// preserve the existing (injected) CA bundle if any
wh.ClientConfig.CABundle = caBundle
// send request to the service running in own namespace
wh.ClientConfig.Service.Namespace = c.OperatorNamespace

return nil
})

if err != nil {
return err
}

c.log.Info("successfully registered validating webhook")
return nil
}

func labelClientOperatorSubscription(c *ClusterVersionReconciler) error {
subscriptionList := &opv1a1.SubscriptionList{}
err := c.List(c.ctx, subscriptionList, client.InNamespace(c.OperatorNamespace))
if err != nil {
return fmt.Errorf("failed to list subscriptions")
}

sub := utils.Find(subscriptionList.Items, func(sub *opv1a1.Subscription) bool {
return sub.Spec.Package == "ocs-client-operator"
})

if sub == nil {
return fmt.Errorf("failed to find subscription with ocs-client-operator package")
}

if utils.AddLabel(sub, subscriptionLabelKey, subscriptionLabelValue) {
if err := c.Update(c.ctx, sub); err != nil {
return err
}
}

c.log.Info("successfully labelled ocs-client-operator subscription")
return nil
}
15 changes: 2 additions & 13 deletions controllers/storageclient_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/klog/v2"
Expand Down Expand Up @@ -440,16 +439,6 @@ func getStatusReporterName(namespace, name string) string {
return fmt.Sprintf("storageclient-%s-status-reporter", hex.EncodeToString(reporterName[:8]))
}

// addLabel add a label to a resource metadata
func addLabel(obj metav1.Object, key string, value string) {
labels := obj.GetLabels()
if labels == nil {
labels = map[string]string{}
obj.SetLabels(labels)
}
labels[key] = value
}

func (s *StorageClientReconciler) delete(obj client.Object) error {
if err := s.Client.Delete(s.ctx, obj); err != nil && !errors.IsNotFound(err) {
return err
Expand All @@ -462,8 +451,8 @@ func (s *StorageClientReconciler) reconcileClientStatusReporterJob(instance *v1a
cronJob := &batchv1.CronJob{}
cronJob.Name = getStatusReporterName(instance.Namespace, instance.Name)
cronJob.Namespace = s.OperatorNamespace
addLabel(cronJob, storageClientNameLabel, instance.Name)
addLabel(cronJob, storageClientNamespaceLabel, instance.Namespace)
utils.AddLabel(cronJob, storageClientNameLabel, instance.Name)
utils.AddLabel(cronJob, storageClientNamespaceLabel, instance.Namespace)
var podDeadLineSeconds int64 = 120
jobDeadLineSeconds := podDeadLineSeconds + 35
var keepJobResourceSeconds int32 = 600
Expand Down
Loading

0 comments on commit 300e2b6

Please sign in to comment.