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