-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmanagedcrl_webhook.go
More file actions
147 lines (123 loc) · 6.12 KB
/
managedcrl_webhook.go
File metadata and controls
147 lines (123 loc) · 6.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
Copyright 2025 Scality.
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 v1alpha1
import (
"context"
"fmt"
cmv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/webhook"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
"github.com/go-logr/logr"
crloperatorv1alpha1 "github.com/scality/crl-operator/api/v1alpha1"
)
// nolint:unused
// log is for logging in this package.
var managedcrllog = logf.Log.WithName("managedcrl-resource")
// SetupManagedCRLWebhookWithManager registers the webhook for ManagedCRL in the manager.
func SetupManagedCRLWebhookWithManager(mgr ctrl.Manager) error {
return ctrl.NewWebhookManagedBy(mgr).For(&crloperatorv1alpha1.ManagedCRL{}).
WithValidator(&ManagedCRLCustomValidator{
client: mgr.GetClient(),
}).
Complete()
}
// TODO(user): EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation.
// NOTE: The 'path' attribute must follow a specific pattern and should not be modified directly here.
// Modifying the path for an invalid path can cause API server errors; failing to locate the webhook.
// +kubebuilder:webhook:path=/validate-crl-operator-scality-com-v1alpha1-managedcrl,mutating=false,failurePolicy=fail,sideEffects=None,groups=crl-operator.scality.com,resources=managedcrls,verbs=create;update,versions=v1alpha1,name=vmanagedcrl-v1alpha1.kb.io,admissionReviewVersions=v1
// ManagedCRLCustomValidator struct is responsible for validating the ManagedCRL resource
// when it is created, updated, or deleted.
//
// NOTE: The +kubebuilder:object:generate=false marker prevents controller-gen from generating DeepCopy methods,
// as this struct is used only for temporary operations and does not need to be deeply copied.
type ManagedCRLCustomValidator struct {
client client.Client
}
var _ webhook.CustomValidator = &ManagedCRLCustomValidator{}
// ValidateCreate implements webhook.CustomValidator so a webhook will be registered for the type ManagedCRL.
func (v *ManagedCRLCustomValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
managedcrl, ok := obj.(*crloperatorv1alpha1.ManagedCRL)
if !ok {
return nil, fmt.Errorf("expected a ManagedCRL object but got %T", obj)
}
logger := managedcrllog.WithValues("name", managedcrl.GetName()).WithValues("namespace", managedcrl.GetNamespace())
logger.Info("Validation for ManagedCRL upon creation")
return nil, validationManagedCRL(logger, ctx, v.client, managedcrl)
}
// ValidateUpdate implements webhook.CustomValidator so a webhook will be registered for the type ManagedCRL.
func (v *ManagedCRLCustomValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) {
managedcrl, ok := newObj.(*crloperatorv1alpha1.ManagedCRL)
if !ok {
return nil, fmt.Errorf("expected a ManagedCRL object for the newObj but got %T", newObj)
}
logger := managedcrllog.WithValues("name", managedcrl.GetName()).WithValues("namespace", managedcrl.GetNamespace())
logger.Info("Validation for ManagedCRL upon update")
return nil, validationManagedCRL(logger, ctx, v.client, managedcrl)
}
// ValidateDelete implements webhook.CustomValidator so a webhook will be registered for the type ManagedCRL.
func (v *ManagedCRLCustomValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) {
managedcrl, ok := obj.(*crloperatorv1alpha1.ManagedCRL)
if !ok {
return nil, fmt.Errorf("expected a ManagedCRL object but got %T", obj)
}
managedcrllog.Info("Validation for ManagedCRL upon deletion", "name", managedcrl.GetName())
// TODO(user): fill in your validation logic upon object deletion.
return nil, nil
}
// validationManagedCRL validates the ManagedCRL fields.
func validationManagedCRL(logger logr.Logger, ctx context.Context, c client.Client, managedcrl *crloperatorv1alpha1.ManagedCRL) error {
if err := managedcrl.Validate(); err != nil {
logger.Error(err, "Validation failed")
return err
}
// Ensure the specified Issuer or ClusterIssuer exists
issuerLogger := logger.WithValues("issuer_name", managedcrl.Spec.IssuerRef.Name, "issuer_kind", managedcrl.Spec.IssuerRef.Kind)
issuerRef := managedcrl.Spec.IssuerRef
switch issuerRef.Kind {
case "Issuer":
var issuer cmv1.Issuer
err := c.Get(ctx, client.ObjectKey{Namespace: managedcrl.Namespace, Name: issuerRef.Name}, &issuer)
if err != nil {
issuerLogger.Error(err, "Issuer not found")
return fmt.Errorf("issuer %s not found in namespace %s", issuerRef.Name, managedcrl.Namespace)
}
if issuer.Spec.CA == nil || issuer.Spec.CA.SecretName == "" {
err := fmt.Errorf("issuer %s in namespace %s is not a CA issuer", issuerRef.Name, managedcrl.Namespace)
issuerLogger.Error(err, "Issuer is not a CA issuer")
return err
}
case "ClusterIssuer":
var issuer cmv1.ClusterIssuer
err := c.Get(ctx, client.ObjectKey{Name: issuerRef.Name}, &issuer)
if err != nil {
issuerLogger.Error(err, "ClusterIssuer not found")
return fmt.Errorf("clusterissuer %s not found", issuerRef.Name)
}
if issuer.Spec.CA == nil || issuer.Spec.CA.SecretName == "" {
err := fmt.Errorf("clusterissuer %s is not a CA issuer", issuerRef.Name)
issuerLogger.Error(err, "Issuer is not a CA issuer")
return err
}
default:
err := fmt.Errorf("invalid IssuerRef kind: %s", issuerRef.Kind)
issuerLogger.Error(err, "IssuerRef kind must be either 'Issuer' or 'ClusterIssuer'")
return err
}
logger.Info("Validation successful")
return nil
}