dotcloud/docker

View on GitHub
daemon/devices.go

Summary

Maintainability
A
0 mins
Test Coverage
package daemon // import "github.com/docker/docker/daemon"

import (
    "github.com/docker/docker/api/types/container"
    "github.com/docker/docker/daemon/internal/capabilities"
    specs "github.com/opencontainers/runtime-spec/specs-go"
)

var deviceDrivers = map[string]*deviceDriver{}

type deviceDriver struct {
    capset     capabilities.Set
    updateSpec func(*specs.Spec, *deviceInstance) error
}

type deviceInstance struct {
    req          container.DeviceRequest
    selectedCaps []string
}

func registerDeviceDriver(name string, d *deviceDriver) {
    deviceDrivers[name] = d
}

func (daemon *Daemon) handleDevice(req container.DeviceRequest, spec *specs.Spec) error {
    if req.Driver == "" {
        for _, dd := range deviceDrivers {
            if selected := dd.capset.Match(req.Capabilities); selected != nil {
                return dd.updateSpec(spec, &deviceInstance{req: req, selectedCaps: selected})
            }
        }
    } else if dd := deviceDrivers[req.Driver]; dd != nil {
        // We add a special case for the CDI driver here as the cdi driver does
        // not distinguish between capabilities.
        // Furthermore, the "OR" and "AND" matching logic for the capability
        // sets requires that a dummy capability be specified when constructing a
        // DeviceRequest.
        // This workaround can be removed once these device driver are
        // refactored to be plugins, with each driver implementing its own
        // matching logic, for example.
        if req.Driver == "cdi" {
            return dd.updateSpec(spec, &deviceInstance{req: req})
        }
        if selected := dd.capset.Match(req.Capabilities); selected != nil {
            return dd.updateSpec(spec, &deviceInstance{req: req, selectedCaps: selected})
        }
    }
    return incompatibleDeviceRequest{req.Driver, req.Capabilities}
}