Skip to content

Commit

Permalink
Add a validating webhook to EdgeDevice
Browse files Browse the repository at this point in the history
Prevent irrelevant or conflicting device specifications.

Signed-off-by: Roy Golan <[email protected]>
  • Loading branch information
rgolangh committed Mar 7, 2022
1 parent 311ec5d commit adeea60
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 4 deletions.
4 changes: 4 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ resources:
kind: EdgeDevice
path: github.com/project-flotta/flotta-operator/api/v1alpha1
version: v1alpha1
webhooks:
defaulting: true
validation: true
webhookVersion: v1
- api:
crdVersion: v1
namespaced: true
Expand Down
84 changes: 84 additions & 0 deletions api/v1alpha1/edgedevice_webhook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
Copyright 2021.
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 (
"fmt"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/webhook"
)

// log is for logging in this package.
var edgedevicelog = logf.Log.WithName("edgedevice-resource")

func (r *EdgeDevice) SetupWebhookWithManager(mgr ctrl.Manager) error {
return ctrl.NewWebhookManagedBy(mgr).
For(r).
Complete()
}

var _ webhook.Defaulter = &EdgeDevice{}

// Default implements webhook.Defaulter so a webhook will be registered for the type
func (d *EdgeDevice) Default() {
}

// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation.
//+kubebuilder:webhook:path=/validate-management-project-flotta-io-v1alpha1-edgedevice,mutating=false,failurePolicy=fail,sideEffects=None,groups=management.project-flotta.io,resources=edgedevices,verbs=create;update,versions=v1alpha1,name=vedgedevice.kb.io,admissionReviewVersions={v1,v1beta1}

var _ webhook.Validator = &EdgeDevice{}

// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
func (d *EdgeDevice) ValidateCreate() error {
edgedevicelog.Info("validate create", "name", d.Name)
err := d.validateCreateOrUpdate()
if err != nil {
return err
}
return nil
}

// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
func (d *EdgeDevice) ValidateUpdate(old runtime.Object) error {
edgedevicelog.Info("validate update", "name", d.Name)
err := d.validateCreateOrUpdate()
if err != nil {
return err
}
return nil
}

func (d *EdgeDevice) validateCreateOrUpdate() error {
if d.Spec.Storage != nil &&
d.Spec.Storage.S3 != nil &&
d.Spec.Storage.S3.CreateOBC &&
(d.Spec.Storage.S3.SecretName != "" || d.Spec.Storage.S3.ConfigMapName != "") {
return fmt.Errorf("%[1]s=true is invalid when %[2]s or %[3]s values are set.\n"+
"Either set %[1]s=false or remove the values from %[2]s and %[3]s",
"spec.storage.s3.createOBC",
"spec.storage.s3.secretName",
"spec.storage.s3.configMapName")
}
return nil
}

// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
func (_ *EdgeDevice) ValidateDelete() error {
return nil
}
49 changes: 49 additions & 0 deletions api/v1alpha1/edgedevice_webhook_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package v1alpha1

import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var _ = Describe("EdgeDevice Webhook", func() {
var (
device EdgeDevice
)
BeforeEach(func() {
device = EdgeDevice{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{},
Spec: EdgeDeviceSpec{
OsInformation: nil,
RequestTime: nil,
Heartbeat: nil,
Storage: &Storage{S3: &S3Storage{}},
Metrics: nil,
LogCollection: nil,
},
Status: EdgeDeviceStatus{},
}
})

Describe("EdgeDevice validating webhook", func() {
Context("conflicting s3.secretName s3.configMapName s3.createOBC fields", func() {
It("should fail to create", func() {
// given
device.Spec.Storage.S3.SecretName = "secret"
device.Spec.Storage.S3.ConfigMapName = "cm"
device.Spec.Storage.S3.CreateOBC = true
// then
Expect(device.ValidateCreate()).To(HaveOccurred())
})
It("should fail to update", func() {
// given
device.Spec.Storage.S3.SecretName = "secret"
device.Spec.Storage.S3.ConfigMapName = "cm"
device.Spec.Storage.S3.CreateOBC = true
// then
Expect(device.ValidateUpdate(nil)).To(HaveOccurred())
})
})
})
})
23 changes: 23 additions & 0 deletions config/default/manager_webhook_patch.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: controller-manager
namespace: system
spec:
template:
spec:
containers:
- name: manager
ports:
- containerPort: 9443
name: webhook-server
protocol: TCP
volumeMounts:
- mountPath: /tmp/k8s-webhook-server/serving-certs
name: cert
readOnly: true
volumes:
- name: cert
secret:
defaultMode: 420
secretName: webhook-server-cert
8 changes: 8 additions & 0 deletions config/default/webhookcainjection_patch.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# This patch add annotation to admission webhook config and
# the variables $(CERTIFICATE_NAMESPACE) and $(CERTIFICATE_NAME) will be substituted by kustomize.
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: validating-webhook-configuration
annotations:
cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
21 changes: 21 additions & 0 deletions config/webhook/manifests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,24 @@ webhooks:
resources:
- edgedeployments
sideEffects: None
- admissionReviewVersions:
- v1
- v1beta1
clientConfig:
service:
name: webhook-service
namespace: system
path: /validate-management-project-flotta-io-v1alpha1-edgedevice
failurePolicy: Fail
name: vedgedevice.kb.io
rules:
- apiGroups:
- management.project-flotta.io
apiVersions:
- v1alpha1
operations:
- CREATE
- UPDATE
resources:
- edgedevices
sideEffects: None
14 changes: 10 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import (

"github.com/kelseyhightower/envconfig"
routev1 "github.com/openshift/api/route/v1"
"go.uber.org/zap/zapcore"

"github.com/project-flotta/flotta-operator/internal/images"
"github.com/project-flotta/flotta-operator/internal/k8sclient"
"github.com/project-flotta/flotta-operator/internal/metrics"
Expand All @@ -41,21 +43,21 @@ import (
"github.com/project-flotta/flotta-operator/internal/yggdrasil"
"github.com/project-flotta/flotta-operator/restapi"
watchers "github.com/project-flotta/flotta-operator/watchers"
"go.uber.org/zap/zapcore"

// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
// to ensure that exec-entrypoint and run can make use of them.
_ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/client-go/util/flowcontrol"

obv1 "github.com/kube-object-storage/lib-bucket-provisioner/pkg/apis/objectbucket.io/v1alpha1"
"github.com/project-flotta/flotta-operator/api/v1alpha1"
managementv1alpha1 "github.com/project-flotta/flotta-operator/api/v1alpha1"
"github.com/project-flotta/flotta-operator/controllers"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/kubernetes"

"github.com/project-flotta/flotta-operator/api/v1alpha1"
managementv1alpha1 "github.com/project-flotta/flotta-operator/api/v1alpha1"
"github.com/project-flotta/flotta-operator/controllers"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
Expand Down Expand Up @@ -231,6 +233,10 @@ func main() {
}
}

if err = (&managementv1alpha1.EdgeDevice{}).SetupWebhookWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create webhook", "webhook", "EdgeDevice")
os.Exit(1)
}
//+kubebuilder:scaffold:builder

if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
Expand Down

0 comments on commit adeea60

Please sign in to comment.