mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Output network attachment task information
Adds functionality to parse and return network attachment spec information. Network attachment tasks are phony tasks created in swarmkit to deal with unmanaged containers attached to swarmkit. Before this change, attempting `docker inspect` on the task id of a network attachment task would result in an empty task object. After this change, a full task object is returned Fixes #26548 the correct way. Signed-off-by: Drew Erny <drew.erny@docker.com> Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
bcaf891369
commit
5b69ff466e
7 changed files with 132 additions and 13 deletions
|
@ -2688,6 +2688,13 @@ definitions:
|
|||
- "default"
|
||||
- "process"
|
||||
- "hyperv"
|
||||
NetworkAttachmentSpec:
|
||||
description: "Read-only spec type for non-swarm containers attached to swarm overlay networks"
|
||||
type: "object"
|
||||
properties:
|
||||
ContainerID:
|
||||
description: "ID of the container represented by this task"
|
||||
type: "string"
|
||||
Resources:
|
||||
description: "Resource requirements which apply to each individual container created as part of the service."
|
||||
type: "object"
|
||||
|
|
|
@ -11,9 +11,17 @@ const (
|
|||
RuntimeContainer RuntimeType = "container"
|
||||
// RuntimePlugin is the plugin based runtime
|
||||
RuntimePlugin RuntimeType = "plugin"
|
||||
// RuntimeNetworkAttachment is the network attachment runtime
|
||||
RuntimeNetworkAttachment RuntimeType = "attachment"
|
||||
|
||||
// RuntimeURLContainer is the proto url for the container type
|
||||
RuntimeURLContainer RuntimeURL = "types.docker.com/RuntimeContainer"
|
||||
// RuntimeURLPlugin is the proto url for the plugin type
|
||||
RuntimeURLPlugin RuntimeURL = "types.docker.com/RuntimePlugin"
|
||||
)
|
||||
|
||||
// NetworkAttachmentSpec represents the runtime spec type for network
|
||||
// attachment tasks
|
||||
type NetworkAttachmentSpec struct {
|
||||
ContainerID string
|
||||
}
|
||||
|
|
|
@ -60,10 +60,13 @@ type Task struct {
|
|||
|
||||
// TaskSpec represents the spec of a task.
|
||||
type TaskSpec struct {
|
||||
// ContainerSpec and PluginSpec are mutually exclusive.
|
||||
// PluginSpec will only be used when the `Runtime` field is set to `plugin`
|
||||
ContainerSpec *ContainerSpec `json:",omitempty"`
|
||||
PluginSpec *runtime.PluginSpec `json:",omitempty"`
|
||||
// ContainerSpec, NetworkAttachmentSpec, and PluginSpec are mutually exclusive.
|
||||
// PluginSpec is only used when the `Runtime` field is set to `plugin`
|
||||
// NetworkAttachmentSpec is used if the `Runtime` field is set to
|
||||
// `attachment`.
|
||||
ContainerSpec *ContainerSpec `json:",omitempty"`
|
||||
PluginSpec *runtime.PluginSpec `json:",omitempty"`
|
||||
NetworkAttachmentSpec *NetworkAttachmentSpec `json:",omitempty"`
|
||||
|
||||
Resources *ResourceRequirements `json:",omitempty"`
|
||||
RestartPolicy *RestartPolicy `json:",omitempty"`
|
||||
|
|
|
@ -17,6 +17,8 @@ import (
|
|||
var (
|
||||
// ErrUnsupportedRuntime returns an error if the runtime is not supported by the daemon
|
||||
ErrUnsupportedRuntime = errors.New("unsupported runtime")
|
||||
// ErrMismatchedRuntime returns an error if the runtime does not match the provided spec
|
||||
ErrMismatchedRuntime = errors.New("mismatched Runtime and *Spec fields")
|
||||
)
|
||||
|
||||
// ServiceFromGRPC converts a grpc Service to a Service.
|
||||
|
@ -176,15 +178,18 @@ func ServiceSpecToGRPC(s types.ServiceSpec) (swarmapi.ServiceSpec, error) {
|
|||
return swarmapi.ServiceSpec{}, err
|
||||
}
|
||||
spec.Task.Runtime = &swarmapi.TaskSpec_Container{Container: containerSpec}
|
||||
} else {
|
||||
// If the ContainerSpec is nil, we can't set the task runtime
|
||||
return swarmapi.ServiceSpec{}, ErrMismatchedRuntime
|
||||
}
|
||||
case types.RuntimePlugin:
|
||||
if s.Mode.Replicated != nil {
|
||||
return swarmapi.ServiceSpec{}, errors.New("plugins must not use replicated mode")
|
||||
}
|
||||
|
||||
s.Mode.Global = &types.GlobalService{} // must always be global
|
||||
|
||||
if s.TaskTemplate.PluginSpec != nil {
|
||||
if s.Mode.Replicated != nil {
|
||||
return swarmapi.ServiceSpec{}, errors.New("plugins must not use replicated mode")
|
||||
}
|
||||
|
||||
s.Mode.Global = &types.GlobalService{} // must always be global
|
||||
|
||||
pluginSpec, err := proto.Marshal(s.TaskTemplate.PluginSpec)
|
||||
if err != nil {
|
||||
return swarmapi.ServiceSpec{}, err
|
||||
|
@ -198,7 +203,16 @@ func ServiceSpecToGRPC(s types.ServiceSpec) (swarmapi.ServiceSpec, error) {
|
|||
},
|
||||
},
|
||||
}
|
||||
} else {
|
||||
return swarmapi.ServiceSpec{}, ErrMismatchedRuntime
|
||||
}
|
||||
case types.RuntimeNetworkAttachment:
|
||||
// NOTE(dperny) I'm leaving this case here for completeness. The actual
|
||||
// code is left out out deliberately, as we should refuse to parse a
|
||||
// Network Attachment runtime; it will cause weird behavior all over
|
||||
// the system if we do. Instead, fallthrough and return
|
||||
// ErrUnsupportedRuntime if we get one.
|
||||
fallthrough
|
||||
default:
|
||||
return swarmapi.ServiceSpec{}, ErrUnsupportedRuntime
|
||||
}
|
||||
|
@ -573,6 +587,12 @@ func updateConfigToGRPC(updateConfig *types.UpdateConfig) (*swarmapi.UpdateConfi
|
|||
return converted, nil
|
||||
}
|
||||
|
||||
func networkAttachmentSpecFromGRPC(attachment swarmapi.NetworkAttachmentSpec) *types.NetworkAttachmentSpec {
|
||||
return &types.NetworkAttachmentSpec{
|
||||
ContainerID: attachment.ContainerID,
|
||||
}
|
||||
}
|
||||
|
||||
func taskSpecFromGRPC(taskSpec swarmapi.TaskSpec) (types.TaskSpec, error) {
|
||||
taskNetworks := make([]types.NetworkAttachmentConfig, 0, len(taskSpec.Networks))
|
||||
for _, n := range taskSpec.Networks {
|
||||
|
@ -607,6 +627,12 @@ func taskSpecFromGRPC(taskSpec swarmapi.TaskSpec) (types.TaskSpec, error) {
|
|||
t.PluginSpec = &p
|
||||
}
|
||||
}
|
||||
case *swarmapi.TaskSpec_Attachment:
|
||||
a := taskSpec.GetAttachment()
|
||||
if a != nil {
|
||||
t.NetworkAttachmentSpec = networkAttachmentSpecFromGRPC(*a)
|
||||
}
|
||||
t.Runtime = types.RuntimeNetworkAttachment
|
||||
}
|
||||
|
||||
return t, nil
|
||||
|
|
|
@ -232,3 +232,77 @@ func TestServiceConvertFromGRPCIsolation(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,6 @@ import (
|
|||
|
||||
// TaskFromGRPC converts a grpc Task to a Task.
|
||||
func TaskFromGRPC(t swarmapi.Task) (types.Task, error) {
|
||||
if t.Spec.GetAttachment() != nil {
|
||||
return types.Task{}, nil
|
||||
}
|
||||
containerStatus := t.Status.GetContainer()
|
||||
taskSpec, err := taskSpecFromGRPC(t.Spec)
|
||||
if err != nil {
|
||||
|
|
|
@ -135,6 +135,8 @@ func (c *Cluster) CreateService(s types.ServiceSpec, encodedAuth string, queryRe
|
|||
resp = &apitypes.ServiceCreateResponse{}
|
||||
|
||||
switch serviceSpec.Task.Runtime.(type) {
|
||||
case *swarmapi.TaskSpec_Attachment:
|
||||
return fmt.Errorf("invalid task spec: spec type %q not supported", types.RuntimeNetworkAttachment)
|
||||
// handle other runtimes here
|
||||
case *swarmapi.TaskSpec_Generic:
|
||||
switch serviceSpec.Task.GetGeneric().Kind {
|
||||
|
@ -244,6 +246,8 @@ func (c *Cluster) UpdateService(serviceIDOrName string, version uint64, spec typ
|
|||
resp = &apitypes.ServiceUpdateResponse{}
|
||||
|
||||
switch serviceSpec.Task.Runtime.(type) {
|
||||
case *swarmapi.TaskSpec_Attachment:
|
||||
return fmt.Errorf("invalid task spec: spec type %q not supported", types.RuntimeNetworkAttachment)
|
||||
case *swarmapi.TaskSpec_Generic:
|
||||
switch serviceSpec.Task.GetGeneric().Kind {
|
||||
case string(types.RuntimePlugin):
|
||||
|
|
Loading…
Add table
Reference in a new issue