From 23fdb0c390194a60f9eadf021ea91a4d05a75568 Mon Sep 17 00:00:00 2001 From: Martin Koppehel Date: Wed, 28 Feb 2018 16:45:07 +0100 Subject: [PATCH 1/2] Add support for device passthrough --- README.md | 19 ++++++++++++++++--- context.go | 7 +++++++ generator.go | 9 +++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d1e23cfb..22fed92b 100644 --- a/README.md +++ b/README.md @@ -209,6 +209,7 @@ type RuntimeContainer struct { ID string Addresses []Address Networks []Network + Devices []Device Gateway string Name string Hostname string @@ -277,6 +278,12 @@ type State struct { Running bool } +type Device struct { + PathOnHost string + PathInContainer string + Permissions string +} + // Accessible from the root in templates as .Docker type Docker struct { Name string @@ -308,7 +315,14 @@ For example, this is a JSON version of an emitted RuntimeContainer struct: "HostPort":"2222" } ], - "Gateway":"172.17.42.1", + "Devices":[ + { + "PathOnHost": "/dev/ttyACM0", + "PathInContainer": "/dev/ttyUSB0", + "Permissions": "rwm" + } + ], + "Gateway": "172.17.42.1", "Node": { "ID":"I2VY:P7PF:TZD5:PGWB:QTI7:QDSP:C5UD:DYKR:XKKK:TRG2:M2BL:DFUN", "Name":"docker-test", @@ -363,7 +377,7 @@ For example, this is a JSON version of an emitted RuntimeContainer struct: * *`json $value`*: Returns the JSON representation of `$value` as a `string`. * *`keys $map`*: Returns the keys from `$map`. If `$map` is `nil`, a `nil` is returned. If `$map` is not a `map`, an error will be thrown. * *`last $array`*: Returns the last value of an array. -* *`parseBool $string`*: parseBool returns the boolean value represented by the string. It accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False. Any other value returns an error. Alias for [`strconv.ParseBool`](http://golang.org/pkg/strconv/#ParseBool) +* *`parseBool $string`*: parseBool returns the boolean value represented by the string. It accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False. Any other value returns an error. Alias for [`strconv.ParseBool`](http://golang.org/pkg/strconv/#ParseBool) * *`replace $string $old $new $count`*: Replaces up to `$count` occurences of `$old` with `$new` in `$string`. Alias for [`strings.Replace`](http://golang.org/pkg/strings/#Replace) * *`sha1 $string`*: Returns the hexadecimal representation of the SHA1 hash of `$string`. * *`split $string $sep`*: Splits `$string` into a slice of substrings delimited by `$sep`. Alias for [`strings.Split`](http://golang.org/pkg/strings/#Split) @@ -451,4 +465,3 @@ $ make ### License MIT - diff --git a/context.go b/context.go index 80a6bd7d..7237137c 100644 --- a/context.go +++ b/context.go @@ -71,6 +71,12 @@ type Network struct { IPPrefixLen int } +type Device struct { + PathOnHost string + PathInContainer string + Permissions string +} + type Volume struct { Path string HostPath string @@ -85,6 +91,7 @@ type RuntimeContainer struct { ID string Addresses []Address Networks []Network + Devices []Device Gateway string Name string Hostname string diff --git a/generator.go b/generator.go index bf68be66..65d56207 100644 --- a/generator.go +++ b/generator.go @@ -381,6 +381,7 @@ func (g *generator) getContainers() ([]*RuntimeContainer, error) { Gateway: container.NetworkSettings.Gateway, Addresses: []Address{}, Networks: []Network{}, + Devices: []Device{}, Env: make(map[string]string), Volumes: make(map[string]Volume), Node: SwarmNode{}, @@ -447,6 +448,14 @@ func (g *generator) getContainers() ([]*RuntimeContainer, error) { }) } + for _, v := range container.HostConfig.Devices { + runtimeContainer.Devices = append(runtimeContainer.Devices, Device{ + PathOnHost: v.PathOnHost, + PathInContainer: v.PathInContainer, + Permissions: v.CgroupPermissions, + }) + } + runtimeContainer.Env = splitKeyValueSlice(container.Config.Env) runtimeContainer.Labels = container.Config.Labels containers = append(containers, runtimeContainer) From 879795b1e95d679679122589aade4046cc3e9d27 Mon Sep 17 00:00:00 2001 From: Martin Koppehel Date: Wed, 28 Feb 2018 17:05:47 +0100 Subject: [PATCH 2/2] Include HostConfig/Devices in test framework Additionally some string formatting issues were fixed to allow the tests to run against go 1.10 --- generator_test.go | 9 +++++++++ template_test.go | 8 ++++---- utils_test.go | 4 ++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/generator_test.go b/generator_test.go index 87b8ce71..e2c56e74 100644 --- a/generator_test.go +++ b/generator_test.go @@ -95,6 +95,15 @@ func TestGenerateFromEvents(t *testing.T) { Ports: map[docker.Port][]docker.PortBinding{}, }, ResolvConfPath: "/etc/resolv.conf", + HostConfig: &docker.HostConfig{ + Devices: []docker.Device{ + docker.Device{ + PathOnHost: "/dev/ttyACM0", + PathInContainer: "/dev/ttyUSB0", + CgroupPermissions: "rwm", + }, + }, + }, } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) diff --git a/template_test.go b/template_test.go index dd1d58c3..71501ada 100644 --- a/template_test.go +++ b/template_test.go @@ -71,7 +71,7 @@ func TestKeysEmpty(t *testing.T) { } if len(input) != vk.Len() { - t.Fatalf("Incorrect key count; expected %s, got %s", len(input), vk.Len()) + t.Fatalf("Incorrect key count; expected %d, got %d", len(input), vk.Len()) } } @@ -269,11 +269,11 @@ func TestGroupByMulti(t *testing.T) { } if len(groups["demo1.localhost"]) != 2 { - t.Fatalf("expected 2 got %s", len(groups["demo1.localhost"])) + t.Fatalf("expected 2 got %d", len(groups["demo1.localhost"])) } if len(groups["demo2.localhost"]) != 1 { - t.Fatalf("expected 1 got %s", len(groups["demo2.localhost"])) + t.Fatalf("expected 1 got %d", len(groups["demo2.localhost"])) } if groups["demo2.localhost"][0].(RuntimeContainer).ID != "3" { t.Fatalf("expected 2 got %s", groups["demo2.localhost"][0].(RuntimeContainer).ID) @@ -785,7 +785,7 @@ func TestJson(t *testing.T) { t.Fatal(err) } if len(decoded) != len(containers) { - t.Fatal("Incorrect unmarshaled container count. Expected %d, got %d.", len(containers), len(decoded)) + t.Fatalf("Incorrect unmarshaled container count. Expected %d, got %d.", len(containers), len(decoded)) } } diff --git a/utils_test.go b/utils_test.go index 45186ac3..c5a8c17b 100644 --- a/utils_test.go +++ b/utils_test.go @@ -30,7 +30,7 @@ func TestDockerHostEndpoint(t *testing.T) { endpoint, err := GetEndpoint("") if err != nil { - t.Fatal("%s", err) + t.Fatalf("%s", err) } if endpoint != "tcp://127.0.0.1:4243" { @@ -48,7 +48,7 @@ func TestDockerFlagEndpoint(t *testing.T) { // flag value should override DOCKER_HOST and default value endpoint, err := GetEndpoint("tcp://127.0.0.1:5555") if err != nil { - t.Fatal("%s", err) + t.Fatalf("%s", err) } if endpoint != "tcp://127.0.0.1:5555" { t.Fatalf("Expected tcp://127.0.0.1:5555, got %s", endpoint)