@@ -43,6 +43,10 @@ const (
4343 cdiDeviceKey = "cdi-devices.noderesource.dev"
4444 // Deprecated: Prefix of the key used for CDI device annotations.
4545 oldCDIDeviceKey = "cdi-devices.nri.io"
46+ // Prefix of the key used for I/O priority adjustment.
47+ ioPrioKey = "io-priority.noderesource.dev"
48+ // Deprecated: Prefix of the key used for I/O priority adjustment.
49+ oldIoPrioKey = "io-priority.nri.io"
4650)
4751
4852var (
@@ -69,6 +73,12 @@ type mount struct {
6973 Options []string `json:"options"`
7074}
7175
76+ // an I/O priority adjustment
77+ type ioPrio struct {
78+ Class string `json:"class"`
79+ Priority int32 `json:"priority"`
80+ }
81+
7282// our injector plugin
7383type plugin struct {
7484 stub stub.Stub
@@ -94,6 +104,10 @@ func (p *plugin) CreateContainer(_ context.Context, pod *api.PodSandbox, ctr *ap
94104 return nil , nil , err
95105 }
96106
107+ if err := setIOPriority (pod , ctr , adjust ); err != nil {
108+ return nil , nil , err
109+ }
110+
97111 if verbose {
98112 dump (containerName (pod , ctr ), "ContainerAdjustment" , adjust )
99113 }
@@ -232,6 +246,46 @@ func parseMounts(ctr string, annotations map[string]string) ([]mount, error) {
232246 return mounts , nil
233247}
234248
249+ func setIOPriority (pod * api.PodSandbox , ctr * api.Container , a * api.ContainerAdjustment ) error {
250+ priority , err := parseIOPriority (ctr .Name , pod .Annotations )
251+ if err != nil {
252+ return err
253+ }
254+
255+ if priority == nil {
256+ log .Debugf ("%s: no I/O priority annotated..." , containerName (pod , ctr ))
257+ return nil
258+ }
259+
260+ if verbose {
261+ dump (containerName (pod , ctr ), "annotated I/O priority" , priority )
262+ }
263+
264+ a .SetLinuxIOPriority (priority .toNRI ())
265+ if ! verbose {
266+ log .Infof ("%s: injected I/O priority %+v..." , containerName (pod , ctr ), priority )
267+ }
268+
269+ return nil
270+ }
271+
272+ func parseIOPriority (ctr string , annotations map [string ]string ) (* ioPrio , error ) {
273+ var (
274+ priority = & ioPrio {}
275+ )
276+
277+ annotation := getAnnotation (annotations , ioPrioKey , oldIoPrioKey , ctr )
278+ if annotation == nil {
279+ return nil , nil
280+ }
281+
282+ if err := yaml .Unmarshal (annotation , priority ); err != nil {
283+ return nil , fmt .Errorf ("invalid I/O priority annotation %q: %w" , string (annotation ), err )
284+ }
285+
286+ return priority , nil
287+ }
288+
235289func getAnnotation (annotations map [string ]string , mainKey , oldKey , ctr string ) []byte {
236290 for _ , key := range []string {
237291 mainKey + "/container." + ctr ,
@@ -280,6 +334,41 @@ func (m *mount) toNRI() *api.Mount {
280334 return apiMnt
281335}
282336
337+ // Convert ioPrio to NRI API representation.
338+ func (p * ioPrio ) toNRI () * api.LinuxIOPriority {
339+ if p == nil {
340+ return nil
341+ }
342+
343+ var class api.IOPrioClass
344+
345+ switch p .Class {
346+ case "IOPRIO_CLASS_NONE" :
347+ class = api .IOPrioClass_IOPRIO_CLASS_NONE
348+ case "IOPRIO_CLASS_RT" :
349+ class = api .IOPrioClass_IOPRIO_CLASS_RT
350+ case "IOPRIO_CLASS_BE" :
351+ class = api .IOPrioClass_IOPRIO_CLASS_BE
352+ case "IOPRIO_CLASS_IDLE" :
353+ class = api .IOPrioClass_IOPRIO_CLASS_IDLE
354+ default :
355+ log .Warnf ("unknown I/O priority class %q, using IOPRIO_CLASS_BE" , p .Class )
356+ return nil
357+ }
358+
359+ return & api.LinuxIOPriority {
360+ Class : class ,
361+ Priority : p .Priority ,
362+ }
363+ }
364+
365+ func (p * ioPrio ) String () string {
366+ if p == nil {
367+ return "<no I/O priority>"
368+ }
369+ return fmt .Sprintf ("<I/O priority class %s:%d>" , p .Class , p .Priority )
370+ }
371+
283372// Construct a container name for log messages.
284373func containerName (pod * api.PodSandbox , container * api.Container ) string {
285374 if pod != nil {
0 commit comments