[increment] has a couple updates and a code marker for pkg/server/server.go where I think status annotation might go

This commit is contained in:
dougbtv 2025-04-04 13:28:42 -04:00
parent 535c0f5b8e
commit cb02c95ed5
2 changed files with 37 additions and 97 deletions

View File

@ -1,19 +1,3 @@
/*
Copyright 2025 The Kubernetes Authors.
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 main package main
import ( import (
@ -22,7 +6,6 @@ import (
"io" "io"
"net/http" "net/http"
"os" "os"
"strings"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
@ -35,7 +18,6 @@ import (
"k8s.io/klog/v2" "k8s.io/klog/v2"
"gopkg.in/k8snetworkplumbingwg/multus-cni.v4/pkg/flags" "gopkg.in/k8snetworkplumbingwg/multus-cni.v4/pkg/flags"
configapi "sigs.k8s.io/dra-example-driver/api/example.com/resource/gpu/v1alpha1"
) )
const ( const (
@ -142,7 +124,7 @@ func newMux() *http.ServeMux {
} }
func serveResourceClaim(w http.ResponseWriter, r *http.Request) { func serveResourceClaim(w http.ResponseWriter, r *http.Request) {
serve(w, r, admitResourceClaimParameters) serve(w, r, admitOrMutatePod)
} }
// serve handles the http portion of a request prior to handing to an admit // serve handles the http portion of a request prior to handing to an admit
@ -214,94 +196,51 @@ func readAdmissionReview(data []byte) (*admissionv1.AdmissionReview, error) {
return requestedAdmissionReview, nil return requestedAdmissionReview, nil
} }
// admitResourceClaimParameters accepts both ResourceClaims and ResourceClaimTemplates and validates their func admitOrMutatePod(ar admissionv1.AdmissionReview) *admissionv1.AdmissionResponse {
// opaque device configuration parameters for this driver. if ar.Request.Kind.Kind != "Pod" {
func admitResourceClaimParameters(ar admissionv1.AdmissionReview) *admissionv1.AdmissionResponse { return &admissionv1.AdmissionResponse{Allowed: true}
klog.V(2).Info("admitting resource claim parameters") }
var deviceConfigs []resourceapi.DeviceClaimConfiguration var pod corev1.Pod
var specPath string if err := json.Unmarshal(ar.Request.Object.Raw, &pod); err != nil {
raw := ar.Request.Object.Raw
deserializer := codecs.UniversalDeserializer()
switch ar.Request.Resource {
case resourceClaimResource:
claim := resourceapi.ResourceClaim{}
if _, _, err := deserializer.Decode(raw, nil, &claim); err != nil {
klog.Error(err) klog.Error(err)
return &admissionv1.AdmissionResponse{ return toAdmissionError(err)
Result: &metav1.Status{
Message: err.Error(),
Reason: metav1.StatusReasonBadRequest,
},
} }
}
deviceConfigs = claim.Spec.Devices.Config // Bail early if pod has DRA-style claims (skip mutation)
specPath = "spec" for _, claim := range pod.Spec.ResourceClaims {
case resourceClaimTemplateResource: if claim.Source.ResourceClaimTemplateName != nil {
claimTemplate := resourceapi.ResourceClaimTemplate{} klog.Infof("Pod %s/%s uses DRA, skipping", pod.Namespace, pod.Name)
if _, _, err := deserializer.Decode(raw, nil, &claimTemplate); err != nil { return &admissionv1.AdmissionResponse{Allowed: true}
klog.Error(err)
return &admissionv1.AdmissionResponse{
Result: &metav1.Status{
Message: err.Error(),
Reason: metav1.StatusReasonBadRequest,
},
}
}
deviceConfigs = claimTemplate.Spec.Spec.Devices.Config
specPath = "spec.spec"
default:
msg := fmt.Sprintf("expected resource to be %s or %s, got %s", resourceClaimResource, resourceClaimTemplateResource, ar.Request.Resource)
klog.Error(msg)
return &admissionv1.AdmissionResponse{
Result: &metav1.Status{
Message: msg,
Reason: metav1.StatusReasonBadRequest,
},
} }
} }
var errs []error // Parse NADs from annotations
for configIndex, config := range deviceConfigs { nadSelector := pod.Annotations["k8s.v1.cni.cncf.io/networks"]
if config.Opaque == nil || config.Opaque.Driver != DriverName { if nadSelector == "" {
continue klog.Infof("No NAD annotation found for pod %s/%s", pod.Namespace, pod.Name)
return &admissionv1.AdmissionResponse{Allowed: true}
} }
fieldPath := fmt.Sprintf("%s.devices.config[%d].opaque.parameters", specPath, configIndex) // TODO: resolve NADs into delegate configs (e.g. using your existing logic)
decodedConfig, err := runtime.Decode(configapi.Decoder, config.DeviceConfiguration.Opaque.Parameters.Raw) // TODO: generate network-status JSON
if err != nil {
errs = append(errs, fmt.Errorf("error decoding object at %s: %w", fieldPath, err))
continue
}
gpuConfig, ok := decodedConfig.(*configapi.GpuConfig)
if !ok {
errs = append(errs, fmt.Errorf("expected v1alpha1.GpuConfig at %s but got: %T", fieldPath, decodedConfig))
continue
}
err = gpuConfig.Validate()
if err != nil {
errs = append(errs, fmt.Errorf("object at %s is invalid: %w", fieldPath, err))
}
}
if len(errs) > 0 { // Create a patch to mutate the pod
var errMsgs []string patch := []map[string]interface{}{
for _, err := range errs { {
errMsgs = append(errMsgs, err.Error()) "op": "add",
} "path": "/metadata/annotations/k8s.v1.cni.cncf.io~1network-status",
msg := fmt.Sprintf("%d configs failed to validate: %s", len(errs), strings.Join(errMsgs, "; ")) "value": `<computed-network-status-json>`,
klog.Error(msg)
return &admissionv1.AdmissionResponse{
Result: &metav1.Status{
Message: msg,
Reason: metav1.StatusReason(metav1.StatusReasonInvalid),
}, },
} }
}
patchBytes, _ := json.Marshal(patch)
return &admissionv1.AdmissionResponse{ return &admissionv1.AdmissionResponse{
Allowed: true, Allowed: true,
Patch: patchBytes,
PatchType: func() *admissionv1.PatchType {
pt := admissionv1.PatchTypeJSONPatch
return &pt
}(),
} }
} }

View File

@ -177,6 +177,7 @@ func newNetDefInformer(netdefClient netdefclient.Interface) (netdefinformer.Shar
return informerFactory, netdefInformer return informerFactory, netdefInformer
} }
// !bang
func newPodInformer(kubeClient kubernetes.Interface, nodeName string) (internalinterfaces.SharedInformerFactory, cache.SharedIndexInformer) { func newPodInformer(kubeClient kubernetes.Interface, nodeName string) (internalinterfaces.SharedInformerFactory, cache.SharedIndexInformer) {
var tweakFunc internalinterfaces.TweakListOptionsFunc var tweakFunc internalinterfaces.TweakListOptionsFunc
if nodeName != "" { if nodeName != "" {