-
Notifications
You must be signed in to change notification settings - Fork 18
Implement video feature in docker engine #383
base: master
Are you sure you want to change the base?
Conversation
engines/docker/engine.go
Outdated
@@ -100,6 +121,13 @@ func (e *engine) NewSandboxBuilder(options engines.SandboxOptions) (engines.Sand | |||
var p payloadType | |||
schematypes.MustValidateAndMap(e.PayloadSchema(), options.Payload, &p) | |||
|
|||
p.Devices = funk.UniqString(p.Devices) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this for deduplication? If so, just add Unique: true
in the JSON schema for array
...
Description: "List of host devices required.", | ||
Items: schematypes.StringEnum{ | ||
Options: []string{ | ||
"video", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could just make the option of video
be dependent on whether devices are enabled or not... anyways, nit... I'm still not sure what's ideal in either case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I would suggest that we do:
devices: [
{type: 'video'},
],
That way, if in some future we decide we want additional options, we can add them to the object...
@@ -43,6 +45,20 @@ func newSandbox(sb *sandboxBuilder, image *docker.Image) (*sandbox, error) { | |||
return nil, errors.Wrap(err, "docker.CreateNetwork failed") | |||
} | |||
|
|||
devices := []docker.Device{} | |||
var dev *device | |||
if funk.InStrings(sb.payload.Devices, "video") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for loop + a switch is likely better...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe when we add more options.
return nil, errors.Wrap(err, "Failed to call filepath.Glob function") | ||
} | ||
|
||
r := regexp.MustCompile("/dev/video[0-9]+") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we want to make the devices in here? Also I think a devices
sub-package would be neat.
That way we can hide some of the locking and internals away, and the engine just deals with a device which is something that has a path... and is created when the array from payload is passed to the device manager...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't know if I followed the idea, but let's keep things simple for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the test case :)
And this doesn't have to be a glorified as I suggest in my comments... I just think it's not that hard to isolate the various aspects, so that things will be extensible.
But at a minimum we should fix missing locking and ensure we do life-cycle management correctly.
} | ||
|
||
func (d *videoDeviceManager) claim() *device { | ||
for i := range d.devices { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
locking?
func (d *videoDeviceManager) claim() *device { | ||
for i := range d.devices { | ||
if !d.devices[i].claimed { | ||
return &d.devices[i] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
returning a reference to an object stored in a list... it's probably better to make a list pointers to devices..
Just so we don't have to think too much about happens when if we mutate the device... or something like that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At no point do you set, dev.claimed = true
@@ -277,5 +298,9 @@ func (s *sandbox) dispose() error { | |||
if hasErr { | |||
return runtime.ErrNonFatalInternalError | |||
} | |||
|
|||
if s.videoDev != nil { | |||
s.videoDev.claimed = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's probably best to decide what is ecapsulated where... You have a method videoDeviceManager.release
@@ -87,6 +106,7 @@ func newSandbox(sb *sandboxBuilder) (*sandbox, error) { | |||
storage, err := sb.e.Environment.TemporaryStorage.NewFolder() | |||
if err != nil { | |||
imageHandle.Release() | |||
sb.e.video.release(dev) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably too soon to release, the container still exists...
devices []device | ||
} | ||
|
||
func newVideoDeviceManager() (*videoDeviceManager, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest something like:
package dockerengine
import (
"errors"
"sync"
"github.com/taskcluster/taskcluster-worker/runtime/atomics"
)
type deviceHandle interface {
Path() string
Release()
}
type videoDeviceManager struct {
m sync.Mutex
devices []string
}
// newVideoDeviceManager creates a new videoDeviceManager
func newVideoDeviceManager() (*videoDeviceManager, error) {
// TODO: Find or create devices
devices := []string{"/dev/video0"}
return &videoDeviceManager{devices: devices}, nil
}
// GetVideoDevice returns an idle video device
func (vdm *videoDeviceManager) GetVideoDevice() deviceHandle {
vdm.m.Lock()
defer vdm.m.Unlock()
// ensure we have enough devices
if len(vdm.devices) < 1 {
panic(errors.New("insufficent number of video devices available"))
}
// Create a device handle, ensuring we can't release twice
vdh := &videoDeviceHandle{owner: vdm}
vdh.path, vdm.devices = vdm.devices[0], vdm.devices[1:]
return vdh
}
// Dispose releases all resources assocated with the videoDeviceManager
func (vdm *videoDeviceManager) Dispose() error {
vdm.m.Lock()
defer vdm.m.Unlock()
return nil // TODO: remove devices if any was created
}
type videoDeviceHandle struct {
owner *videoDeviceManager
path string
released atomics.Once
}
func (vdh *videoDeviceHandle) Path() string {
if vdh.released.IsDone() {
panic(errors.New("videoDeviceHandle.Path() was called after release"))
}
return vdh.path
}
func (vdh *videoDeviceHandle) Release() string {
ok := vdh.released.Do(func() {
vdh.owner.m.Lock()
defer vdh.owner.m.Unlock()
vdh.owner.devices = append(vdh.owner.devices, vdh.path)
})
if !ok {
debug("WARNING: harmless double release() of videoDeviceHandle")
}
}
In the sandbox and resultset code you just release() the deviceHandle
the same way we release imageHandle
and pass it around the same way.
While techincally all this is in the same package, I only use methods starting with capital outside this file... the only exception being: newVideoDeviceManager()
. This makes it easier to track life-cycles, and it is a motivation for moving device management into separate package, though that's a lot less important..
Description: "List of host devices required.", | ||
Items: schematypes.StringEnum{ | ||
Options: []string{ | ||
"video", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I would suggest that we do:
devices: [
{type: 'video'},
],
That way, if in some future we decide we want additional options, we can add them to the object...
No description provided.