Skip to content

Commit

Permalink
feat: Add support for Admission Controller (Mellanox#593)
Browse files Browse the repository at this point in the history
This change implements validating admission controller for supported
CRDs NicClusterPolicy, HostDeviceNetwork, and MacvlanNetwork, and
IPoIBNetwork.
Currently, this commit covers:
 - Using operator-sdk to scaffold the webhook for the CRDS
 - Implementing validation rules for NicClusterPolicy.
   - IBKubernetes.PKeyGUIDPoolRangeStart
   - IBKubernetes.PKeyGUIDPoolRangeEnd
   - OFEDDriver.Version
   - RdmaSharedDevicePlugin.Config
     - Configuration is a valid JSON and check its schema
     - Resource name is valid for k8s.
     - At least one of the supported selectors exists. 
     - All selectors are strings.
   - SriovNetworkDevicePlugin.Config.
     - Configuration is a valid JSON and check its schema.
     - Resource name is valid for k8s.
     - At least one of the supported selectors exists.
     - All selectors are strings.
 - Implemented validation rules for HostDeviceNetwork.
   - ResourceName
  • Loading branch information
adrianchiris committed Oct 15, 2023
2 parents 45a8172 + 0210796 commit 0d2367d
Show file tree
Hide file tree
Showing 34 changed files with 2,258 additions and 7 deletions.
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ COPY --from=builder /workspace/manager .
COPY --from=builder /workspace/kubectl /usr/local/bin
COPY --from=builder /workspace/crds /crds

COPY /webhook-schemas /webhook-schemas
COPY manifests/ manifests/
USER 65532:65532

Expand Down
6 changes: 6 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ resources:
kind: NicClusterPolicy
path: github.com/Mellanox/network-operator/api/v1alpha1
version: v1alpha1
webhooks:
validation: true
webhookVersion: v1
- api:
crdVersion: v1
controller: true
Expand All @@ -31,4 +34,7 @@ resources:
kind: HostDeviceNetwork
path: github.com/Mellanox/network-operator/api/v1alpha1
version: v1alpha1
webhooks:
validation: true
webhookVersion: v1
version: "3"
91 changes: 91 additions & 0 deletions api/v1alpha1/hostdevicenetwork_webhook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
2023 NVIDIA CORPORATION & AFFILIATES
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 (
"regexp"

apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation/field"
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 hostDeviceNetworkLog = logf.Log.WithName("hostdevicenetwork-resource")

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

//nolint:lll
//+kubebuilder:webhook:path=/validate-mellanox-com-v1alpha1-hostdevicenetwork,mutating=false,failurePolicy=fail,sideEffects=None,groups=mellanox.com,resources=hostdevicenetworks,verbs=create;update,versions=v1alpha1,name=vhostdevicenetwork.kb.io,admissionReviewVersions=v1

var _ webhook.Validator = &HostDeviceNetwork{}

// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
func (w *HostDeviceNetwork) ValidateCreate() error {
hostDeviceNetworkLog.Info("validate create", "name", w.Name)

return w.validateHostDeviceNetwork()
}

// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
func (w *HostDeviceNetwork) ValidateUpdate(_ runtime.Object) error {
hostDeviceNetworkLog.Info("validate update", "name", w.Name)

return w.validateHostDeviceNetwork()
}

// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
func (w *HostDeviceNetwork) ValidateDelete() error {
hostDeviceNetworkLog.Info("validate delete", "name", w.Name)

// Validation for delete call is not required
return nil
}

/*
We are validating here HostDeviceNetwork:
- ResourceName must be valid for k8s
*/

func (w *HostDeviceNetwork) validateHostDeviceNetwork() error {
resourceName := w.Spec.ResourceName
if !isValidHostDeviceNetworkResourceName(resourceName) {
var allErrs field.ErrorList
allErrs = append(allErrs, field.Invalid(field.NewPath("Spec"), resourceName,
"Invalid Resource name, it must consist of alphanumeric characters, '-', '_' or '.', "+
"and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', "+
"regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')"))
return apierrors.NewInvalid(
schema.GroupKind{Group: "mellanox.com", Kind: "HostDeviceNetwork"},
w.Name, allErrs)
}
return nil
}

func isValidHostDeviceNetworkResourceName(resourceName string) bool {
resourceNamePattern := `^([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$`
resourceNameRegex := regexp.MustCompile(resourceNamePattern)
return resourceNameRegex.MatchString(resourceName)
}
46 changes: 46 additions & 0 deletions api/v1alpha1/hostdevicenetwork_webhook_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
2023 NVIDIA CORPORATION & AFFILIATES
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 //nolint:dupl

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

//nolint:dupl
var _ = Describe("Validate", func() {
Context("HostDeviceNetwork tests", func() {
It("Valid ResourceName", func() {
hostDeviceNetwork := HostDeviceNetwork{
ObjectMeta: metav1.ObjectMeta{Name: "test"},
Spec: HostDeviceNetworkSpec{
ResourceName: "hostdev",
},
}
Expect(hostDeviceNetwork.ValidateCreate()).NotTo(HaveOccurred())
})
It("Invalid ResourceName", func() {
hostDeviceNetwork := HostDeviceNetwork{
ObjectMeta: metav1.ObjectMeta{Name: "test"},
Spec: HostDeviceNetworkSpec{
ResourceName: "hostdev!!",
},
}
Expect(hostDeviceNetwork.ValidateCreate().Error()).To(ContainSubstring("Invalid Resource name"))
})
})
})
Loading

0 comments on commit 0d2367d

Please sign in to comment.