...

Source file src/edge-infra.dev/pkg/sds/devices/agent/events/events.go

Documentation: edge-infra.dev/pkg/sds/devices/agent/events

     1  package events
     2  
     3  import (
     4  	"context"
     5  	"path/filepath"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/containerd/containerd/containers"
    10  
    11  	"edge-infra.dev/pkg/lib/kernel/devices"
    12  	"edge-infra.dev/pkg/lib/kernel/udev"
    13  	cc "edge-infra.dev/pkg/sds/devices/agent/common"
    14  	"edge-infra.dev/pkg/sds/devices/class"
    15  	dsv1 "edge-infra.dev/pkg/sds/devices/k8s/apis/v1"
    16  	"edge-infra.dev/pkg/sds/devices/logger"
    17  )
    18  
    19  type DeviceEvent interface {
    20  	Containers() map[string]*containers.Container
    21  	PosthookFunc() func(context.Context)
    22  	Timestamp() time.Time
    23  }
    24  
    25  // Base class for a device event
    26  type event struct {
    27  	// list of new container ids
    28  	containers map[string]*containers.Container
    29  	// postHookFn is the posthook function to call
    30  	postHookFn func(context.Context)
    31  	// timestamp of device event
    32  	timestamp time.Time
    33  }
    34  
    35  type udevEvent struct{ *event }
    36  type containerEvent struct{ *event }
    37  type classEvent struct{ *event }
    38  type kubeletEvent struct{ *event }
    39  
    40  var (
    41  	requested             = "requested"
    42  	deviceExistsInClassFn = deviceExistsInClass
    43  )
    44  
    45  // NewKubeletEvent returns an empty device event. This is to trigger
    46  // an update to the device plugins to ensure they are running and up-to-date.
    47  func NewKubeletEvent() DeviceEvent {
    48  	return &kubeletEvent{
    49  		event: &event{
    50  			containers: map[string]*containers.Container{},
    51  			postHookFn: func(context.Context) {},
    52  			timestamp:  time.Now(),
    53  		},
    54  	}
    55  }
    56  
    57  func (e *event) Containers() map[string]*containers.Container {
    58  	return e.containers
    59  }
    60  
    61  func (e *event) PosthookFunc() func(context.Context) {
    62  	return e.postHookFn
    63  }
    64  
    65  func (e *event) Timestamp() time.Time {
    66  	return e.timestamp
    67  }
    68  
    69  // ueventMatchesContainer checks to see if a uevent should be applied to a container given its list of device classes.
    70  // The function returns any matching device rules that apply to the container
    71  func ueventMatchesContainer(ctx context.Context, udevEvent *udev.UEvent, ctr *containers.Container, deviceClasses map[string]*dsv1.DeviceClass) bool {
    72  	log := logger.FromContext(ctx)
    73  	for classLabel := range ctr.Labels {
    74  		if !class.IsDeviceClass(classLabel) {
    75  			continue
    76  		}
    77  
    78  		deviceClass, ok := deviceClasses[classLabel]
    79  		if !ok || deviceClass == nil {
    80  			continue
    81  		}
    82  
    83  		devicePath := prefixSysPath(udevEvent.SysPath)
    84  		existsInClass := deviceExistsInClassFn(deviceClass, devicePath)
    85  		log.Log(ctx, logger.LevelTrace, "evaluating uevent matches device class", "class", classLabel, "container", ctr.Labels[cc.AnnContainerName], "event", udevEvent.SysPath, "matches class", existsInClass)
    86  		if existsInClass {
    87  			return true
    88  		}
    89  	}
    90  	return false
    91  }
    92  
    93  func deviceExistsInClass(deviceClass *dsv1.DeviceClass, devicePath string) bool {
    94  	return deviceClass.DeviceExistsInClass(devicePath)
    95  }
    96  
    97  func prefixSysPath(path string) string {
    98  	if strings.HasPrefix(path, devices.SysPath) {
    99  		return path
   100  	}
   101  	return filepath.Join(devices.SysPath, path)
   102  }
   103  

View as plain text