plugin_test.go 5.3 KB

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