mirror of
https://github.com/k8snetworkplumbingwg/multus-cni.git
synced 2025-08-21 01:33:28 +00:00
[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:
parent
535c0f5b8e
commit
cb02c95ed5
@ -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
|
||||||
|
}(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 != "" {
|
||||||
|
Loading…
Reference in New Issue
Block a user