github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/engine/integration/service/plugin_test.go (about) 1 package service 2 3 import ( 4 "context" 5 "io" 6 "os" 7 "path" 8 "strings" 9 "testing" 10 11 "github.com/docker/docker/api/types" 12 "github.com/docker/docker/api/types/filters" 13 swarmtypes "github.com/docker/docker/api/types/swarm" 14 "github.com/docker/docker/api/types/swarm/runtime" 15 "github.com/docker/docker/integration/internal/swarm" 16 "github.com/docker/docker/testutil/daemon" 17 "github.com/docker/docker/testutil/fixtures/plugin" 18 "github.com/docker/docker/testutil/registry" 19 "gotest.tools/v3/assert" 20 "gotest.tools/v3/poll" 21 "gotest.tools/v3/skip" 22 ) 23 24 func TestServicePlugin(t *testing.T) { 25 skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon") 26 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 27 skip.If(t, os.Getenv("DOCKER_ENGINE_GOARCH") != "amd64") 28 defer setupTest(t)() 29 30 reg := registry.NewV2(t) 31 defer reg.Close() 32 33 name := "test-" + strings.ToLower(t.Name()) 34 repo := path.Join(registry.DefaultURL, "swarm", name+":v1") 35 repo2 := path.Join(registry.DefaultURL, "swarm", name+":v2") 36 37 d := daemon.New(t) 38 d.StartWithBusybox(t) 39 apiclient := d.NewClientT(t) 40 err := plugin.Create(context.Background(), apiclient, repo) 41 assert.NilError(t, err) 42 r, err := apiclient.PluginPush(context.Background(), repo, "") 43 assert.NilError(t, err) 44 _, err = io.Copy(io.Discard, r) 45 assert.NilError(t, err) 46 err = apiclient.PluginRemove(context.Background(), repo, types.PluginRemoveOptions{}) 47 assert.NilError(t, err) 48 err = plugin.Create(context.Background(), apiclient, repo2) 49 assert.NilError(t, err) 50 r, err = apiclient.PluginPush(context.Background(), repo2, "") 51 assert.NilError(t, err) 52 _, err = io.Copy(io.Discard, r) 53 assert.NilError(t, err) 54 err = apiclient.PluginRemove(context.Background(), repo2, types.PluginRemoveOptions{}) 55 assert.NilError(t, err) 56 d.Stop(t) 57 58 d1 := swarm.NewSwarm(t, testEnv, daemon.WithExperimental()) 59 defer d1.Stop(t) 60 d2 := daemon.New(t, daemon.WithExperimental(), daemon.WithSwarmPort(daemon.DefaultSwarmPort+1)) 61 d2.StartAndSwarmJoin(t, d1, true) 62 defer d2.Stop(t) 63 d3 := daemon.New(t, daemon.WithExperimental(), daemon.WithSwarmPort(daemon.DefaultSwarmPort+2)) 64 d3.StartAndSwarmJoin(t, d1, false) 65 defer d3.Stop(t) 66 67 id := d1.CreateService(t, makePlugin(repo, name, nil)) 68 poll.WaitOn(t, d1.PluginIsRunning(t, name), swarm.ServicePoll) 69 poll.WaitOn(t, d2.PluginIsRunning(t, name), swarm.ServicePoll) 70 poll.WaitOn(t, d3.PluginIsRunning(t, name), swarm.ServicePoll) 71 72 // test that environment variables are passed from plugin service to plugin instance 73 service := d1.GetService(t, id) 74 tasks := d1.GetServiceTasks(t, service.Spec.Annotations.Name, filters.Arg("runtime", "plugin")) 75 if len(tasks) == 0 { 76 t.Log("No tasks found for plugin service") 77 t.Fail() 78 } 79 plugin, _, err := d1.NewClientT(t).PluginInspectWithRaw(context.Background(), name) 80 assert.NilError(t, err, "Error inspecting service plugin") 81 found := false 82 for _, env := range plugin.Settings.Env { 83 assert.Equal(t, strings.HasPrefix(env, "baz"), false, "Environment variable entry %q is invalid and should not be present", "baz") 84 if strings.HasPrefix(env, "foo=") { 85 found = true 86 assert.Equal(t, env, "foo=bar") 87 } 88 } 89 assert.Equal(t, true, found, "Environment variable %q not found in plugin", "foo") 90 91 d1.UpdateService(t, service, makePlugin(repo2, name, nil)) 92 poll.WaitOn(t, d1.PluginReferenceIs(t, name, repo2), swarm.ServicePoll) 93 poll.WaitOn(t, d2.PluginReferenceIs(t, name, repo2), swarm.ServicePoll) 94 poll.WaitOn(t, d3.PluginReferenceIs(t, name, repo2), swarm.ServicePoll) 95 poll.WaitOn(t, d1.PluginIsRunning(t, name), swarm.ServicePoll) 96 poll.WaitOn(t, d2.PluginIsRunning(t, name), swarm.ServicePoll) 97 poll.WaitOn(t, d3.PluginIsRunning(t, name), swarm.ServicePoll) 98 99 d1.RemoveService(t, id) 100 poll.WaitOn(t, d1.PluginIsNotPresent(t, name), swarm.ServicePoll) 101 poll.WaitOn(t, d2.PluginIsNotPresent(t, name), swarm.ServicePoll) 102 poll.WaitOn(t, d3.PluginIsNotPresent(t, name), swarm.ServicePoll) 103 104 // constrain to managers only 105 id = d1.CreateService(t, makePlugin(repo, name, []string{"node.role==manager"})) 106 poll.WaitOn(t, d1.PluginIsRunning(t, name), swarm.ServicePoll) 107 poll.WaitOn(t, d2.PluginIsRunning(t, name), swarm.ServicePoll) 108 poll.WaitOn(t, d3.PluginIsNotPresent(t, name), swarm.ServicePoll) 109 110 d1.RemoveService(t, id) 111 poll.WaitOn(t, d1.PluginIsNotPresent(t, name), swarm.ServicePoll) 112 poll.WaitOn(t, d2.PluginIsNotPresent(t, name), swarm.ServicePoll) 113 poll.WaitOn(t, d3.PluginIsNotPresent(t, name), swarm.ServicePoll) 114 115 // with no name 116 id = d1.CreateService(t, makePlugin(repo, "", nil)) 117 poll.WaitOn(t, d1.PluginIsRunning(t, repo), swarm.ServicePoll) 118 poll.WaitOn(t, d2.PluginIsRunning(t, repo), swarm.ServicePoll) 119 poll.WaitOn(t, d3.PluginIsRunning(t, repo), swarm.ServicePoll) 120 121 d1.RemoveService(t, id) 122 poll.WaitOn(t, d1.PluginIsNotPresent(t, repo), swarm.ServicePoll) 123 poll.WaitOn(t, d2.PluginIsNotPresent(t, repo), swarm.ServicePoll) 124 poll.WaitOn(t, d3.PluginIsNotPresent(t, repo), swarm.ServicePoll) 125 } 126 127 func makePlugin(repo, name string, constraints []string) func(*swarmtypes.Service) { 128 return func(s *swarmtypes.Service) { 129 s.Spec.TaskTemplate.Runtime = swarmtypes.RuntimePlugin 130 s.Spec.TaskTemplate.PluginSpec = &runtime.PluginSpec{ 131 Name: name, 132 Remote: repo, 133 Env: []string{ 134 "baz", // invalid environment variable entries are ignored 135 "foo=bar", // "foo" will be the single environment variable 136 }, 137 } 138 if constraints != nil { 139 s.Spec.TaskTemplate.Placement = &swarmtypes.Placement{ 140 Constraints: constraints, 141 } 142 } 143 } 144 }