From ad4646255d90edf1504897172ead0090f71ccf9d Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Mon, 28 Jul 2025 17:27:57 -0700 Subject: [PATCH] Move swarm runtime plugin spec to swarm types - Move swarm runtime plugin spec to swarm types - Move swarm runtime plugin storage type to internal Signed-off-by: Derek McGowan (cherry picked from commit 86190e73665d5df19c48043a8895f3146a53404b) (cherry picked from commit ee24dcec3d5a5b0cc7c6e9897837aa07b020e14e) Signed-off-by: Sebastiaan van Stijn --- api/types/swarm/runtime.go | 18 +++++++ api/types/swarm/runtime/gen.go | 3 -- api/types/swarm/task.go | 3 +- .../cluster/controllers/plugin/controller.go | 14 +++--- .../controllers/plugin/controller_test.go | 4 +- daemon/cluster/convert/service.go | 8 +-- daemon/cluster/convert/service_test.go | 5 +- daemon/cluster/internal/runtime/convert.go | 49 +++++++++++++++++++ daemon/cluster/internal/runtime/gen.go | 3 ++ .../cluster/internal}/runtime/plugin.pb.go | 0 .../cluster/internal}/runtime/plugin.proto | 0 integration/service/plugin_test.go | 3 +- 12 files changed, 89 insertions(+), 21 deletions(-) delete mode 100644 api/types/swarm/runtime/gen.go create mode 100644 daemon/cluster/internal/runtime/convert.go create mode 100644 daemon/cluster/internal/runtime/gen.go rename {api/types/swarm => daemon/cluster/internal}/runtime/plugin.pb.go (100%) rename {api/types/swarm => daemon/cluster/internal}/runtime/plugin.proto (100%) diff --git a/api/types/swarm/runtime.go b/api/types/swarm/runtime.go index 8a28320f7b..23ea712c47 100644 --- a/api/types/swarm/runtime.go +++ b/api/types/swarm/runtime.go @@ -25,3 +25,21 @@ const ( type NetworkAttachmentSpec struct { ContainerID string } + +// RuntimeSpec defines the base payload which clients can specify for creating +// a service with the plugin runtime. +type RuntimeSpec struct { + Name string `json:"name,omitempty"` + Remote string `json:"remote,omitempty"` + Privileges []*RuntimePrivilege `json:"privileges,omitempty"` + Disabled bool `json:"disabled,omitempty"` + Env []string `json:"env,omitempty"` +} + +// RuntimePrivilege describes a permission the user has to accept +// upon installing a plugin. +type RuntimePrivilege struct { + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + Value []string `json:"value,omitempty"` +} diff --git a/api/types/swarm/runtime/gen.go b/api/types/swarm/runtime/gen.go deleted file mode 100644 index 90e572cf9c..0000000000 --- a/api/types/swarm/runtime/gen.go +++ /dev/null @@ -1,3 +0,0 @@ -//go:generate protoc --gogofaster_out=import_path=github.com/docker/docker/api/types/swarm/runtime:. plugin.proto - -package runtime diff --git a/api/types/swarm/task.go b/api/types/swarm/task.go index 4dc95e8b1d..e143f844fa 100644 --- a/api/types/swarm/task.go +++ b/api/types/swarm/task.go @@ -4,7 +4,6 @@ import ( "time" "github.com/docker/docker/api/types/filters" - "github.com/docker/docker/api/types/swarm/runtime" ) // TaskState represents the state of a task. @@ -77,7 +76,7 @@ type TaskSpec struct { // NetworkAttachmentSpec is used if the `Runtime` field is set to // `attachment`. ContainerSpec *ContainerSpec `json:",omitempty"` - PluginSpec *runtime.PluginSpec `json:",omitempty"` + PluginSpec *RuntimeSpec `json:",omitempty"` NetworkAttachmentSpec *NetworkAttachmentSpec `json:",omitempty"` Resources *ResourceRequirements `json:",omitempty"` diff --git a/daemon/cluster/controllers/plugin/controller.go b/daemon/cluster/controllers/plugin/controller.go index 6420321983..a2cde31a1b 100644 --- a/daemon/cluster/controllers/plugin/controller.go +++ b/daemon/cluster/controllers/plugin/controller.go @@ -11,7 +11,8 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/backend" "github.com/docker/docker/api/types/registry" - "github.com/docker/docker/api/types/swarm/runtime" + "github.com/docker/docker/api/types/swarm" + "github.com/docker/docker/daemon/cluster/internal/runtime" "github.com/docker/docker/plugin" v2 "github.com/docker/docker/plugin/v2" "github.com/gogo/protobuf/proto" @@ -30,7 +31,7 @@ import ( // the right way to pass registry credentials via secrets. type Controller struct { backend Backend - spec runtime.PluginSpec + spec swarm.RuntimeSpec logger *log.Entry pluginID string @@ -70,14 +71,15 @@ func NewController(backend Backend, t *api.Task) (*Controller, error) { }, nil } -func readSpec(t *api.Task) (runtime.PluginSpec, error) { +func readSpec(t *api.Task) (swarm.RuntimeSpec, error) { var cfg runtime.PluginSpec generic := t.Spec.GetGeneric() if err := proto.Unmarshal(generic.Payload.Value, &cfg); err != nil { - return cfg, errors.Wrap(err, "error reading plugin spec") + return swarm.RuntimeSpec{}, errors.Wrap(err, "error reading plugin spec") } - return cfg, nil + + return runtime.ToAPI(cfg), nil } // Update is the update phase from swarmkit @@ -248,7 +250,7 @@ func (p *Controller) Close() error { return nil } -func convertPrivileges(ls []*runtime.PluginPrivilege) types.PluginPrivileges { +func convertPrivileges(ls []*swarm.RuntimePrivilege) types.PluginPrivileges { var out types.PluginPrivileges for _, p := range ls { pp := types.PluginPrivilege{ diff --git a/daemon/cluster/controllers/plugin/controller_test.go b/daemon/cluster/controllers/plugin/controller_test.go index 28ca16fa97..4b291ab766 100644 --- a/daemon/cluster/controllers/plugin/controller_test.go +++ b/daemon/cluster/controllers/plugin/controller_test.go @@ -14,7 +14,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/backend" "github.com/docker/docker/api/types/registry" - "github.com/docker/docker/api/types/swarm/runtime" + "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/plugin" v2 "github.com/docker/docker/plugin/v2" "github.com/moby/pubsub" @@ -325,7 +325,7 @@ func newTestController(b Backend, disabled bool) *Controller { return &Controller{ logger: &log.Entry{Logger: &logrus.Logger{Out: io.Discard}}, backend: b, - spec: runtime.PluginSpec{ + spec: swarm.RuntimeSpec{ Name: pluginTestName, Remote: pluginTestRemote, Disabled: disabled, diff --git a/daemon/cluster/convert/service.go b/daemon/cluster/convert/service.go index 1a86bbb9ab..7c00b6c663 100644 --- a/daemon/cluster/convert/service.go +++ b/daemon/cluster/convert/service.go @@ -5,7 +5,7 @@ import ( "strings" types "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/api/types/swarm/runtime" + "github.com/docker/docker/daemon/cluster/internal/runtime" "github.com/docker/docker/pkg/namesgenerator" "github.com/gogo/protobuf/proto" gogotypes "github.com/gogo/protobuf/types" @@ -210,7 +210,8 @@ func ServiceSpecToGRPC(s types.ServiceSpec) (swarmapi.ServiceSpec, error) { s.Mode.Global = &types.GlobalService{} // must always be global - pluginSpec, err := proto.Marshal(s.TaskTemplate.PluginSpec) + ps := runtime.FromAPI(*s.TaskTemplate.PluginSpec) + pluginSpec, err := proto.Marshal(&ps) if err != nil { return swarmapi.ServiceSpec{}, err } @@ -699,7 +700,8 @@ func taskSpecFromGRPC(taskSpec swarmapi.TaskSpec) (types.TaskSpec, error) { if err := proto.Unmarshal(g.Payload.Value, &p); err != nil { return t, errors.Wrap(err, "error unmarshalling plugin spec") } - t.PluginSpec = &p + ap := runtime.ToAPI(p) + t.PluginSpec = &ap } } case *swarmapi.TaskSpec_Attachment: diff --git a/daemon/cluster/convert/service_test.go b/daemon/cluster/convert/service_test.go index b45f0103f2..05086f85ff 100644 --- a/daemon/cluster/convert/service_test.go +++ b/daemon/cluster/convert/service_test.go @@ -7,7 +7,6 @@ import ( containertypes "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/mount" swarmtypes "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/api/types/swarm/runtime" google_protobuf3 "github.com/gogo/protobuf/types" swarmapi "github.com/moby/swarmkit/v2/api" "gotest.tools/v3/assert" @@ -89,7 +88,7 @@ func TestServiceConvertToGRPCGenericRuntimePlugin(t *testing.T) { s := swarmtypes.ServiceSpec{ TaskTemplate: swarmtypes.TaskSpec{ Runtime: swarmtypes.RuntimePlugin, - PluginSpec: &runtime.PluginSpec{}, + PluginSpec: &swarmtypes.RuntimeSpec{}, }, Mode: swarmtypes.ServiceMode{ Global: &swarmtypes.GlobalService{}, @@ -425,7 +424,7 @@ func TestServiceConvertToGRPCMismatchedRuntime(t *testing.T) { } { for j, spec := range []swarmtypes.TaskSpec{ {ContainerSpec: &swarmtypes.ContainerSpec{}}, - {PluginSpec: &runtime.PluginSpec{}}, + {PluginSpec: &swarmtypes.RuntimeSpec{}}, } { // skip the cases, where the indices match, which would not error if i == j { diff --git a/daemon/cluster/internal/runtime/convert.go b/daemon/cluster/internal/runtime/convert.go new file mode 100644 index 0000000000..05e53699d9 --- /dev/null +++ b/daemon/cluster/internal/runtime/convert.go @@ -0,0 +1,49 @@ +package runtime + +import "github.com/docker/docker/api/types/swarm" + +func privilegesFromAPI(privs []*swarm.RuntimePrivilege) []*PluginPrivilege { + var out []*PluginPrivilege + for _, p := range privs { + out = append(out, &PluginPrivilege{ + Name: p.Name, + Description: p.Description, + Value: p.Value, + }) + } + return out +} + +// FromAPI converts an API RuntimeSpec to a PluginSpec, +// which can be proto encoded. +func FromAPI(spec swarm.RuntimeSpec) PluginSpec { + return PluginSpec{ + Name: spec.Name, + Remote: spec.Remote, + Privileges: privilegesFromAPI(spec.Privileges), + Disabled: spec.Disabled, + Env: spec.Env, + } +} + +func privilegesToAPI(privs []*PluginPrivilege) []*swarm.RuntimePrivilege { + var out []*swarm.RuntimePrivilege + for _, p := range privs { + out = append(out, &swarm.RuntimePrivilege{ + Name: p.Name, + Description: p.Description, + Value: p.Value, + }) + } + return out +} + +func ToAPI(spec PluginSpec) swarm.RuntimeSpec { + return swarm.RuntimeSpec{ + Name: spec.Name, + Remote: spec.Remote, + Privileges: privilegesToAPI(spec.Privileges), + Disabled: spec.Disabled, + Env: spec.Env, + } +} diff --git a/daemon/cluster/internal/runtime/gen.go b/daemon/cluster/internal/runtime/gen.go new file mode 100644 index 0000000000..ccfac75c7b --- /dev/null +++ b/daemon/cluster/internal/runtime/gen.go @@ -0,0 +1,3 @@ +//go:generate protoc --gogofaster_out=import_path=runtime:. plugin.proto + +package runtime diff --git a/api/types/swarm/runtime/plugin.pb.go b/daemon/cluster/internal/runtime/plugin.pb.go similarity index 100% rename from api/types/swarm/runtime/plugin.pb.go rename to daemon/cluster/internal/runtime/plugin.pb.go diff --git a/api/types/swarm/runtime/plugin.proto b/daemon/cluster/internal/runtime/plugin.proto similarity index 100% rename from api/types/swarm/runtime/plugin.proto rename to daemon/cluster/internal/runtime/plugin.proto diff --git a/integration/service/plugin_test.go b/integration/service/plugin_test.go index 47f2ef7c00..ef04cfe4d5 100644 --- a/integration/service/plugin_test.go +++ b/integration/service/plugin_test.go @@ -9,7 +9,6 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" swarmtypes "github.com/docker/docker/api/types/swarm" - "github.com/docker/docker/api/types/swarm/runtime" "github.com/docker/docker/integration/internal/swarm" "github.com/docker/docker/testutil/daemon" "github.com/docker/docker/testutil/fixtures/plugin" @@ -125,7 +124,7 @@ func TestServicePlugin(t *testing.T) { func makePlugin(repo, name string, constraints []string) func(*swarmtypes.Service) { return func(s *swarmtypes.Service) { s.Spec.TaskTemplate.Runtime = swarmtypes.RuntimePlugin - s.Spec.TaskTemplate.PluginSpec = &runtime.PluginSpec{ + s.Spec.TaskTemplate.PluginSpec = &swarmtypes.RuntimeSpec{ Name: name, Remote: repo, Env: []string{