mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
6f1d7ddfa4
The Swarmkit api specifies a target for configs called called "Runtime" which indicates that the config is not mounted into the container but has some other use. This commit updates the Docker api to reflect this. Signed-off-by: Drew Erny <drew.erny@docker.com>
613 lines
17 KiB
Go
613 lines
17 KiB
Go
package convert // import "github.com/docker/docker/daemon/cluster/convert"
|
|
|
|
import (
|
|
"testing"
|
|
|
|
containertypes "github.com/docker/docker/api/types/container"
|
|
swarmtypes "github.com/docker/docker/api/types/swarm"
|
|
"github.com/docker/docker/api/types/swarm/runtime"
|
|
swarmapi "github.com/docker/swarmkit/api"
|
|
google_protobuf3 "github.com/gogo/protobuf/types"
|
|
"gotest.tools/assert"
|
|
)
|
|
|
|
func TestServiceConvertFromGRPCRuntimeContainer(t *testing.T) {
|
|
gs := swarmapi.Service{
|
|
Meta: swarmapi.Meta{
|
|
Version: swarmapi.Version{
|
|
Index: 1,
|
|
},
|
|
CreatedAt: nil,
|
|
UpdatedAt: nil,
|
|
},
|
|
SpecVersion: &swarmapi.Version{
|
|
Index: 1,
|
|
},
|
|
Spec: swarmapi.ServiceSpec{
|
|
Task: swarmapi.TaskSpec{
|
|
Runtime: &swarmapi.TaskSpec_Container{
|
|
Container: &swarmapi.ContainerSpec{
|
|
Image: "alpine:latest",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
svc, err := ServiceFromGRPC(gs)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if svc.Spec.TaskTemplate.Runtime != swarmtypes.RuntimeContainer {
|
|
t.Fatalf("expected type %s; received %T", swarmtypes.RuntimeContainer, svc.Spec.TaskTemplate.Runtime)
|
|
}
|
|
}
|
|
|
|
func TestServiceConvertFromGRPCGenericRuntimePlugin(t *testing.T) {
|
|
kind := string(swarmtypes.RuntimePlugin)
|
|
url := swarmtypes.RuntimeURLPlugin
|
|
gs := swarmapi.Service{
|
|
Meta: swarmapi.Meta{
|
|
Version: swarmapi.Version{
|
|
Index: 1,
|
|
},
|
|
CreatedAt: nil,
|
|
UpdatedAt: nil,
|
|
},
|
|
SpecVersion: &swarmapi.Version{
|
|
Index: 1,
|
|
},
|
|
Spec: swarmapi.ServiceSpec{
|
|
Task: swarmapi.TaskSpec{
|
|
Runtime: &swarmapi.TaskSpec_Generic{
|
|
Generic: &swarmapi.GenericRuntimeSpec{
|
|
Kind: kind,
|
|
Payload: &google_protobuf3.Any{
|
|
TypeUrl: string(url),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
svc, err := ServiceFromGRPC(gs)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if svc.Spec.TaskTemplate.Runtime != swarmtypes.RuntimePlugin {
|
|
t.Fatalf("expected type %s; received %T", swarmtypes.RuntimePlugin, svc.Spec.TaskTemplate.Runtime)
|
|
}
|
|
}
|
|
|
|
func TestServiceConvertToGRPCGenericRuntimePlugin(t *testing.T) {
|
|
s := swarmtypes.ServiceSpec{
|
|
TaskTemplate: swarmtypes.TaskSpec{
|
|
Runtime: swarmtypes.RuntimePlugin,
|
|
PluginSpec: &runtime.PluginSpec{},
|
|
},
|
|
Mode: swarmtypes.ServiceMode{
|
|
Global: &swarmtypes.GlobalService{},
|
|
},
|
|
}
|
|
|
|
svc, err := ServiceSpecToGRPC(s)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
v, ok := svc.Task.Runtime.(*swarmapi.TaskSpec_Generic)
|
|
if !ok {
|
|
t.Fatal("expected type swarmapi.TaskSpec_Generic")
|
|
}
|
|
|
|
if v.Generic.Payload.TypeUrl != string(swarmtypes.RuntimeURLPlugin) {
|
|
t.Fatalf("expected url %s; received %s", swarmtypes.RuntimeURLPlugin, v.Generic.Payload.TypeUrl)
|
|
}
|
|
}
|
|
|
|
func TestServiceConvertToGRPCContainerRuntime(t *testing.T) {
|
|
image := "alpine:latest"
|
|
s := swarmtypes.ServiceSpec{
|
|
TaskTemplate: swarmtypes.TaskSpec{
|
|
ContainerSpec: &swarmtypes.ContainerSpec{
|
|
Image: image,
|
|
},
|
|
},
|
|
Mode: swarmtypes.ServiceMode{
|
|
Global: &swarmtypes.GlobalService{},
|
|
},
|
|
}
|
|
|
|
svc, err := ServiceSpecToGRPC(s)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
v, ok := svc.Task.Runtime.(*swarmapi.TaskSpec_Container)
|
|
if !ok {
|
|
t.Fatal("expected type swarmapi.TaskSpec_Container")
|
|
}
|
|
|
|
if v.Container.Image != image {
|
|
t.Fatalf("expected image %s; received %s", image, v.Container.Image)
|
|
}
|
|
}
|
|
|
|
func TestServiceConvertToGRPCGenericRuntimeCustom(t *testing.T) {
|
|
s := swarmtypes.ServiceSpec{
|
|
TaskTemplate: swarmtypes.TaskSpec{
|
|
Runtime: "customruntime",
|
|
},
|
|
Mode: swarmtypes.ServiceMode{
|
|
Global: &swarmtypes.GlobalService{},
|
|
},
|
|
}
|
|
|
|
if _, err := ServiceSpecToGRPC(s); err != ErrUnsupportedRuntime {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestServiceConvertToGRPCIsolation(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
from containertypes.Isolation
|
|
to swarmapi.ContainerSpec_Isolation
|
|
}{
|
|
{name: "empty", from: containertypes.IsolationEmpty, to: swarmapi.ContainerIsolationDefault},
|
|
{name: "default", from: containertypes.IsolationDefault, to: swarmapi.ContainerIsolationDefault},
|
|
{name: "process", from: containertypes.IsolationProcess, to: swarmapi.ContainerIsolationProcess},
|
|
{name: "hyperv", from: containertypes.IsolationHyperV, to: swarmapi.ContainerIsolationHyperV},
|
|
{name: "proCess", from: containertypes.Isolation("proCess"), to: swarmapi.ContainerIsolationProcess},
|
|
{name: "hypErv", from: containertypes.Isolation("hypErv"), to: swarmapi.ContainerIsolationHyperV},
|
|
}
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
s := swarmtypes.ServiceSpec{
|
|
TaskTemplate: swarmtypes.TaskSpec{
|
|
ContainerSpec: &swarmtypes.ContainerSpec{
|
|
Image: "alpine:latest",
|
|
Isolation: c.from,
|
|
},
|
|
},
|
|
Mode: swarmtypes.ServiceMode{
|
|
Global: &swarmtypes.GlobalService{},
|
|
},
|
|
}
|
|
res, err := ServiceSpecToGRPC(s)
|
|
assert.NilError(t, err)
|
|
v, ok := res.Task.Runtime.(*swarmapi.TaskSpec_Container)
|
|
if !ok {
|
|
t.Fatal("expected type swarmapi.TaskSpec_Container")
|
|
}
|
|
assert.Equal(t, c.to, v.Container.Isolation)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestServiceConvertFromGRPCIsolation(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
from swarmapi.ContainerSpec_Isolation
|
|
to containertypes.Isolation
|
|
}{
|
|
{name: "default", to: containertypes.IsolationDefault, from: swarmapi.ContainerIsolationDefault},
|
|
{name: "process", to: containertypes.IsolationProcess, from: swarmapi.ContainerIsolationProcess},
|
|
{name: "hyperv", to: containertypes.IsolationHyperV, from: swarmapi.ContainerIsolationHyperV},
|
|
}
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
gs := swarmapi.Service{
|
|
Meta: swarmapi.Meta{
|
|
Version: swarmapi.Version{
|
|
Index: 1,
|
|
},
|
|
CreatedAt: nil,
|
|
UpdatedAt: nil,
|
|
},
|
|
SpecVersion: &swarmapi.Version{
|
|
Index: 1,
|
|
},
|
|
Spec: swarmapi.ServiceSpec{
|
|
Task: swarmapi.TaskSpec{
|
|
Runtime: &swarmapi.TaskSpec_Container{
|
|
Container: &swarmapi.ContainerSpec{
|
|
Image: "alpine:latest",
|
|
Isolation: c.from,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
svc, err := ServiceFromGRPC(gs)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
assert.Equal(t, c.to, svc.Spec.TaskTemplate.ContainerSpec.Isolation)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestServiceConvertToGRPCCredentialSpec(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
from swarmtypes.CredentialSpec
|
|
to swarmapi.Privileges_CredentialSpec
|
|
expectedErr string
|
|
}{
|
|
{
|
|
name: "empty credential spec",
|
|
from: swarmtypes.CredentialSpec{},
|
|
to: swarmapi.Privileges_CredentialSpec{},
|
|
expectedErr: `invalid CredentialSpec: must either provide "file", "registry", or "config" for credential spec`,
|
|
},
|
|
{
|
|
name: "config and file credential spec",
|
|
from: swarmtypes.CredentialSpec{
|
|
Config: "0bt9dmxjvjiqermk6xrop3ekq",
|
|
File: "spec.json",
|
|
},
|
|
to: swarmapi.Privileges_CredentialSpec{},
|
|
expectedErr: `invalid CredentialSpec: cannot specify both "config" and "file" credential specs`,
|
|
},
|
|
{
|
|
name: "config and registry credential spec",
|
|
from: swarmtypes.CredentialSpec{
|
|
Config: "0bt9dmxjvjiqermk6xrop3ekq",
|
|
Registry: "testing",
|
|
},
|
|
to: swarmapi.Privileges_CredentialSpec{},
|
|
expectedErr: `invalid CredentialSpec: cannot specify both "config" and "registry" credential specs`,
|
|
},
|
|
{
|
|
name: "file and registry credential spec",
|
|
from: swarmtypes.CredentialSpec{
|
|
File: "spec.json",
|
|
Registry: "testing",
|
|
},
|
|
to: swarmapi.Privileges_CredentialSpec{},
|
|
expectedErr: `invalid CredentialSpec: cannot specify both "file" and "registry" credential specs`,
|
|
},
|
|
{
|
|
name: "config and file and registry credential spec",
|
|
from: swarmtypes.CredentialSpec{
|
|
Config: "0bt9dmxjvjiqermk6xrop3ekq",
|
|
File: "spec.json",
|
|
Registry: "testing",
|
|
},
|
|
to: swarmapi.Privileges_CredentialSpec{},
|
|
expectedErr: `invalid CredentialSpec: cannot specify both "config", "file", and "registry" credential specs`,
|
|
},
|
|
{
|
|
name: "config credential spec",
|
|
from: swarmtypes.CredentialSpec{Config: "0bt9dmxjvjiqermk6xrop3ekq"},
|
|
to: swarmapi.Privileges_CredentialSpec{
|
|
Source: &swarmapi.Privileges_CredentialSpec_Config{Config: "0bt9dmxjvjiqermk6xrop3ekq"},
|
|
},
|
|
},
|
|
{
|
|
name: "file credential spec",
|
|
from: swarmtypes.CredentialSpec{File: "foo.json"},
|
|
to: swarmapi.Privileges_CredentialSpec{
|
|
Source: &swarmapi.Privileges_CredentialSpec_File{File: "foo.json"},
|
|
},
|
|
},
|
|
{
|
|
name: "registry credential spec",
|
|
from: swarmtypes.CredentialSpec{Registry: "testing"},
|
|
to: swarmapi.Privileges_CredentialSpec{
|
|
Source: &swarmapi.Privileges_CredentialSpec_Registry{Registry: "testing"},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, c := range cases {
|
|
c := c
|
|
t.Run(c.name, func(t *testing.T) {
|
|
s := swarmtypes.ServiceSpec{
|
|
TaskTemplate: swarmtypes.TaskSpec{
|
|
ContainerSpec: &swarmtypes.ContainerSpec{
|
|
Privileges: &swarmtypes.Privileges{
|
|
CredentialSpec: &c.from,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
res, err := ServiceSpecToGRPC(s)
|
|
if c.expectedErr != "" {
|
|
assert.Error(t, err, c.expectedErr)
|
|
return
|
|
}
|
|
|
|
assert.NilError(t, err)
|
|
v, ok := res.Task.Runtime.(*swarmapi.TaskSpec_Container)
|
|
if !ok {
|
|
t.Fatal("expected type swarmapi.TaskSpec_Container")
|
|
}
|
|
assert.DeepEqual(t, c.to, *v.Container.Privileges.CredentialSpec)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestServiceConvertFromGRPCCredentialSpec(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
from swarmapi.Privileges_CredentialSpec
|
|
to *swarmtypes.CredentialSpec
|
|
}{
|
|
{
|
|
name: "empty credential spec",
|
|
from: swarmapi.Privileges_CredentialSpec{},
|
|
to: &swarmtypes.CredentialSpec{},
|
|
},
|
|
{
|
|
name: "config credential spec",
|
|
from: swarmapi.Privileges_CredentialSpec{
|
|
Source: &swarmapi.Privileges_CredentialSpec_Config{Config: "0bt9dmxjvjiqermk6xrop3ekq"},
|
|
},
|
|
to: &swarmtypes.CredentialSpec{Config: "0bt9dmxjvjiqermk6xrop3ekq"},
|
|
},
|
|
{
|
|
name: "file credential spec",
|
|
from: swarmapi.Privileges_CredentialSpec{
|
|
Source: &swarmapi.Privileges_CredentialSpec_File{File: "foo.json"},
|
|
},
|
|
to: &swarmtypes.CredentialSpec{File: "foo.json"},
|
|
},
|
|
{
|
|
name: "registry credential spec",
|
|
from: swarmapi.Privileges_CredentialSpec{
|
|
Source: &swarmapi.Privileges_CredentialSpec_Registry{Registry: "testing"},
|
|
},
|
|
to: &swarmtypes.CredentialSpec{Registry: "testing"},
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
tc := tc
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
gs := swarmapi.Service{
|
|
Spec: swarmapi.ServiceSpec{
|
|
Task: swarmapi.TaskSpec{
|
|
Runtime: &swarmapi.TaskSpec_Container{
|
|
Container: &swarmapi.ContainerSpec{
|
|
Privileges: &swarmapi.Privileges{
|
|
CredentialSpec: &tc.from,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
svc, err := ServiceFromGRPC(gs)
|
|
assert.NilError(t, err)
|
|
assert.DeepEqual(t, svc.Spec.TaskTemplate.ContainerSpec.Privileges.CredentialSpec, tc.to)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestServiceConvertToGRPCNetworkAtachmentRuntime(t *testing.T) {
|
|
someid := "asfjkl"
|
|
s := swarmtypes.ServiceSpec{
|
|
TaskTemplate: swarmtypes.TaskSpec{
|
|
Runtime: swarmtypes.RuntimeNetworkAttachment,
|
|
NetworkAttachmentSpec: &swarmtypes.NetworkAttachmentSpec{
|
|
ContainerID: someid,
|
|
},
|
|
},
|
|
}
|
|
|
|
// discard the service, which will be empty
|
|
_, err := ServiceSpecToGRPC(s)
|
|
if err == nil {
|
|
t.Fatalf("expected error %v but got no error", ErrUnsupportedRuntime)
|
|
}
|
|
if err != ErrUnsupportedRuntime {
|
|
t.Fatalf("expected error %v but got error %v", ErrUnsupportedRuntime, err)
|
|
}
|
|
}
|
|
|
|
func TestServiceConvertToGRPCMismatchedRuntime(t *testing.T) {
|
|
// NOTE(dperny): an earlier version of this test was for code that also
|
|
// converted network attachment tasks to GRPC. that conversion code was
|
|
// removed, so if this loop body seems a bit complicated, that's why.
|
|
for i, rt := range []swarmtypes.RuntimeType{
|
|
swarmtypes.RuntimeContainer,
|
|
swarmtypes.RuntimePlugin,
|
|
} {
|
|
for j, spec := range []swarmtypes.TaskSpec{
|
|
{ContainerSpec: &swarmtypes.ContainerSpec{}},
|
|
{PluginSpec: &runtime.PluginSpec{}},
|
|
} {
|
|
// skip the cases, where the indices match, which would not error
|
|
if i == j {
|
|
continue
|
|
}
|
|
// set the task spec, then change the runtime
|
|
s := swarmtypes.ServiceSpec{
|
|
TaskTemplate: spec,
|
|
}
|
|
s.TaskTemplate.Runtime = rt
|
|
|
|
if _, err := ServiceSpecToGRPC(s); err != ErrMismatchedRuntime {
|
|
t.Fatalf("expected %v got %v", ErrMismatchedRuntime, err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTaskConvertFromGRPCNetworkAttachment(t *testing.T) {
|
|
containerID := "asdfjkl"
|
|
s := swarmapi.TaskSpec{
|
|
Runtime: &swarmapi.TaskSpec_Attachment{
|
|
Attachment: &swarmapi.NetworkAttachmentSpec{
|
|
ContainerID: containerID,
|
|
},
|
|
},
|
|
}
|
|
ts, err := taskSpecFromGRPC(s)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ts.NetworkAttachmentSpec == nil {
|
|
t.Fatal("expected task spec to have network attachment spec")
|
|
}
|
|
if ts.NetworkAttachmentSpec.ContainerID != containerID {
|
|
t.Fatalf("expected network attachment spec container id to be %q, was %q", containerID, ts.NetworkAttachmentSpec.ContainerID)
|
|
}
|
|
if ts.Runtime != swarmtypes.RuntimeNetworkAttachment {
|
|
t.Fatalf("expected Runtime to be %v", swarmtypes.RuntimeNetworkAttachment)
|
|
}
|
|
}
|
|
|
|
// TestServiceConvertFromGRPCConfigs tests that converting config references
|
|
// from GRPC is correct
|
|
func TestServiceConvertFromGRPCConfigs(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
from *swarmapi.ConfigReference
|
|
to *swarmtypes.ConfigReference
|
|
}{
|
|
{
|
|
name: "file",
|
|
from: &swarmapi.ConfigReference{
|
|
ConfigID: "configFile",
|
|
ConfigName: "configFile",
|
|
Target: &swarmapi.ConfigReference_File{
|
|
// skip mode, if everything else here works mode will too. otherwise we'd need to import os.
|
|
File: &swarmapi.FileTarget{Name: "foo", UID: "bar", GID: "baz"},
|
|
},
|
|
},
|
|
to: &swarmtypes.ConfigReference{
|
|
ConfigID: "configFile",
|
|
ConfigName: "configFile",
|
|
File: &swarmtypes.ConfigReferenceFileTarget{Name: "foo", UID: "bar", GID: "baz"},
|
|
},
|
|
},
|
|
{
|
|
name: "runtime",
|
|
from: &swarmapi.ConfigReference{
|
|
ConfigID: "configRuntime",
|
|
ConfigName: "configRuntime",
|
|
Target: &swarmapi.ConfigReference_Runtime{Runtime: &swarmapi.RuntimeTarget{}},
|
|
},
|
|
to: &swarmtypes.ConfigReference{
|
|
ConfigID: "configRuntime",
|
|
ConfigName: "configRuntime",
|
|
Runtime: &swarmtypes.ConfigReferenceRuntimeTarget{},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
grpcService := swarmapi.Service{
|
|
Spec: swarmapi.ServiceSpec{
|
|
Task: swarmapi.TaskSpec{
|
|
Runtime: &swarmapi.TaskSpec_Container{
|
|
Container: &swarmapi.ContainerSpec{
|
|
Configs: []*swarmapi.ConfigReference{tc.from},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
engineService, err := ServiceFromGRPC(grpcService)
|
|
assert.NilError(t, err)
|
|
assert.DeepEqual(t,
|
|
engineService.Spec.TaskTemplate.ContainerSpec.Configs[0],
|
|
tc.to,
|
|
)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestServiceConvertToGRPCConfigs tests that converting config references to
|
|
// GRPC is correct
|
|
func TestServiceConvertToGRPCConfigs(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
from *swarmtypes.ConfigReference
|
|
to *swarmapi.ConfigReference
|
|
expectedErr string
|
|
}{
|
|
{
|
|
name: "file",
|
|
from: &swarmtypes.ConfigReference{
|
|
ConfigID: "configFile",
|
|
ConfigName: "configFile",
|
|
File: &swarmtypes.ConfigReferenceFileTarget{Name: "foo", UID: "bar", GID: "baz"},
|
|
},
|
|
to: &swarmapi.ConfigReference{
|
|
ConfigID: "configFile",
|
|
ConfigName: "configFile",
|
|
Target: &swarmapi.ConfigReference_File{
|
|
// skip mode, if everything else here works mode will too. otherwise we'd need to import os.
|
|
File: &swarmapi.FileTarget{Name: "foo", UID: "bar", GID: "baz"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "runtime",
|
|
from: &swarmtypes.ConfigReference{
|
|
ConfigID: "configRuntime",
|
|
ConfigName: "configRuntime",
|
|
Runtime: &swarmtypes.ConfigReferenceRuntimeTarget{},
|
|
},
|
|
to: &swarmapi.ConfigReference{
|
|
ConfigID: "configRuntime",
|
|
ConfigName: "configRuntime",
|
|
Target: &swarmapi.ConfigReference_Runtime{Runtime: &swarmapi.RuntimeTarget{}},
|
|
},
|
|
},
|
|
{
|
|
name: "file and runtime",
|
|
from: &swarmtypes.ConfigReference{
|
|
ConfigID: "fileAndRuntime",
|
|
ConfigName: "fileAndRuntime",
|
|
File: &swarmtypes.ConfigReferenceFileTarget{},
|
|
Runtime: &swarmtypes.ConfigReferenceRuntimeTarget{},
|
|
},
|
|
expectedErr: "invalid Config: cannot specify both File and Runtime",
|
|
},
|
|
{
|
|
name: "none",
|
|
from: &swarmtypes.ConfigReference{
|
|
ConfigID: "none",
|
|
ConfigName: "none",
|
|
},
|
|
expectedErr: "invalid Config: either File or Runtime should be set",
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
engineServiceSpec := swarmtypes.ServiceSpec{
|
|
TaskTemplate: swarmtypes.TaskSpec{
|
|
ContainerSpec: &swarmtypes.ContainerSpec{
|
|
Configs: []*swarmtypes.ConfigReference{tc.from},
|
|
},
|
|
},
|
|
}
|
|
|
|
grpcServiceSpec, err := ServiceSpecToGRPC(engineServiceSpec)
|
|
if tc.expectedErr != "" {
|
|
assert.Error(t, err, tc.expectedErr)
|
|
return
|
|
}
|
|
|
|
assert.NilError(t, err)
|
|
taskRuntime := grpcServiceSpec.Task.Runtime.(*swarmapi.TaskSpec_Container)
|
|
assert.DeepEqual(t, taskRuntime.Container.Configs[0], tc.to)
|
|
})
|
|
}
|
|
}
|