create_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. package service // import "github.com/docker/docker/integration/service"
  2. import (
  3. "context"
  4. "fmt"
  5. "io/ioutil"
  6. "testing"
  7. "time"
  8. "github.com/docker/docker/api/types"
  9. "github.com/docker/docker/api/types/filters"
  10. swarmtypes "github.com/docker/docker/api/types/swarm"
  11. "github.com/docker/docker/api/types/versions"
  12. "github.com/docker/docker/client"
  13. "github.com/docker/docker/errdefs"
  14. "github.com/docker/docker/integration/internal/network"
  15. "github.com/docker/docker/integration/internal/swarm"
  16. "github.com/docker/docker/internal/test/daemon"
  17. "gotest.tools/assert"
  18. is "gotest.tools/assert/cmp"
  19. "gotest.tools/poll"
  20. "gotest.tools/skip"
  21. )
  22. func TestServiceCreateInit(t *testing.T) {
  23. defer setupTest(t)()
  24. t.Run("daemonInitDisabled", testServiceCreateInit(false))
  25. t.Run("daemonInitEnabled", testServiceCreateInit(true))
  26. }
  27. func testServiceCreateInit(daemonEnabled bool) func(t *testing.T) {
  28. return func(t *testing.T) {
  29. var ops = []func(*daemon.Daemon){}
  30. if daemonEnabled {
  31. ops = append(ops, daemon.WithInit)
  32. }
  33. d := swarm.NewSwarm(t, testEnv, ops...)
  34. defer d.Stop(t)
  35. client := d.NewClientT(t)
  36. defer client.Close()
  37. booleanTrue := true
  38. booleanFalse := false
  39. serviceID := swarm.CreateService(t, d)
  40. poll.WaitOn(t, swarm.RunningTasksCount(client, serviceID, 1), swarm.ServicePoll)
  41. i := inspectServiceContainer(t, client, serviceID)
  42. // HostConfig.Init == nil means that it delegates to daemon configuration
  43. assert.Check(t, i.HostConfig.Init == nil)
  44. serviceID = swarm.CreateService(t, d, swarm.ServiceWithInit(&booleanTrue))
  45. poll.WaitOn(t, swarm.RunningTasksCount(client, serviceID, 1), swarm.ServicePoll)
  46. i = inspectServiceContainer(t, client, serviceID)
  47. assert.Check(t, is.Equal(true, *i.HostConfig.Init))
  48. serviceID = swarm.CreateService(t, d, swarm.ServiceWithInit(&booleanFalse))
  49. poll.WaitOn(t, swarm.RunningTasksCount(client, serviceID, 1), swarm.ServicePoll)
  50. i = inspectServiceContainer(t, client, serviceID)
  51. assert.Check(t, is.Equal(false, *i.HostConfig.Init))
  52. }
  53. }
  54. func inspectServiceContainer(t *testing.T, client client.APIClient, serviceID string) types.ContainerJSON {
  55. t.Helper()
  56. filter := filters.NewArgs()
  57. filter.Add("label", fmt.Sprintf("com.docker.swarm.service.id=%s", serviceID))
  58. containers, err := client.ContainerList(context.Background(), types.ContainerListOptions{Filters: filter})
  59. assert.NilError(t, err)
  60. assert.Check(t, is.Len(containers, 1))
  61. i, err := client.ContainerInspect(context.Background(), containers[0].ID)
  62. assert.NilError(t, err)
  63. return i
  64. }
  65. func TestCreateServiceMultipleTimes(t *testing.T) {
  66. skip.If(t, testEnv.DaemonInfo.OSType == "windows")
  67. defer setupTest(t)()
  68. d := swarm.NewSwarm(t, testEnv)
  69. defer d.Stop(t)
  70. client := d.NewClientT(t)
  71. defer client.Close()
  72. ctx := context.Background()
  73. overlayName := "overlay1_" + t.Name()
  74. overlayID := network.CreateNoError(t, ctx, client, overlayName,
  75. network.WithCheckDuplicate(),
  76. network.WithDriver("overlay"),
  77. )
  78. var instances uint64 = 4
  79. serviceName := "TestService_" + t.Name()
  80. serviceSpec := []swarm.ServiceSpecOpt{
  81. swarm.ServiceWithReplicas(instances),
  82. swarm.ServiceWithName(serviceName),
  83. swarm.ServiceWithNetwork(overlayName),
  84. }
  85. serviceID := swarm.CreateService(t, d, serviceSpec...)
  86. poll.WaitOn(t, swarm.RunningTasksCount(client, serviceID, instances), swarm.ServicePoll)
  87. _, _, err := client.ServiceInspectWithRaw(context.Background(), serviceID, types.ServiceInspectOptions{})
  88. assert.NilError(t, err)
  89. err = client.ServiceRemove(context.Background(), serviceID)
  90. assert.NilError(t, err)
  91. poll.WaitOn(t, swarm.NoTasksForService(ctx, client, serviceID), swarm.ServicePoll)
  92. serviceID2 := swarm.CreateService(t, d, serviceSpec...)
  93. poll.WaitOn(t, swarm.RunningTasksCount(client, serviceID2, instances), swarm.ServicePoll)
  94. err = client.ServiceRemove(context.Background(), serviceID2)
  95. assert.NilError(t, err)
  96. poll.WaitOn(t, swarm.NoTasksForService(ctx, client, serviceID2), swarm.ServicePoll)
  97. err = client.NetworkRemove(context.Background(), overlayID)
  98. assert.NilError(t, err)
  99. poll.WaitOn(t, network.IsRemoved(context.Background(), client, overlayID), poll.WithTimeout(1*time.Minute), poll.WithDelay(10*time.Second))
  100. }
  101. func TestCreateServiceConflict(t *testing.T) {
  102. skip.If(t, testEnv.DaemonInfo.OSType == "windows")
  103. defer setupTest(t)()
  104. d := swarm.NewSwarm(t, testEnv)
  105. defer d.Stop(t)
  106. c := d.NewClientT(t)
  107. defer c.Close()
  108. ctx := context.Background()
  109. serviceName := "TestService_" + t.Name()
  110. serviceSpec := []swarm.ServiceSpecOpt{
  111. swarm.ServiceWithName(serviceName),
  112. }
  113. swarm.CreateService(t, d, serviceSpec...)
  114. spec := swarm.CreateServiceSpec(t, serviceSpec...)
  115. _, err := c.ServiceCreate(ctx, spec, types.ServiceCreateOptions{})
  116. assert.Check(t, errdefs.IsConflict(err))
  117. assert.ErrorContains(t, err, "service "+serviceName+" already exists")
  118. }
  119. func TestCreateServiceMaxReplicas(t *testing.T) {
  120. defer setupTest(t)()
  121. d := swarm.NewSwarm(t, testEnv)
  122. defer d.Stop(t)
  123. client := d.NewClientT(t)
  124. defer client.Close()
  125. var maxReplicas uint64 = 2
  126. serviceSpec := []swarm.ServiceSpecOpt{
  127. swarm.ServiceWithReplicas(maxReplicas),
  128. swarm.ServiceWithMaxReplicas(maxReplicas),
  129. }
  130. serviceID := swarm.CreateService(t, d, serviceSpec...)
  131. poll.WaitOn(t, swarm.RunningTasksCount(client, serviceID, maxReplicas), swarm.ServicePoll)
  132. _, _, err := client.ServiceInspectWithRaw(context.Background(), serviceID, types.ServiceInspectOptions{})
  133. assert.NilError(t, err)
  134. }
  135. func TestCreateWithDuplicateNetworkNames(t *testing.T) {
  136. skip.If(t, testEnv.DaemonInfo.OSType == "windows")
  137. defer setupTest(t)()
  138. d := swarm.NewSwarm(t, testEnv)
  139. defer d.Stop(t)
  140. client := d.NewClientT(t)
  141. defer client.Close()
  142. ctx := context.Background()
  143. name := "foo_" + t.Name()
  144. n1 := network.CreateNoError(t, ctx, client, name, network.WithDriver("bridge"))
  145. n2 := network.CreateNoError(t, ctx, client, name, network.WithDriver("bridge"))
  146. // Duplicates with name but with different driver
  147. n3 := network.CreateNoError(t, ctx, client, name, network.WithDriver("overlay"))
  148. // Create Service with the same name
  149. var instances uint64 = 1
  150. serviceName := "top_" + t.Name()
  151. serviceID := swarm.CreateService(t, d,
  152. swarm.ServiceWithReplicas(instances),
  153. swarm.ServiceWithName(serviceName),
  154. swarm.ServiceWithNetwork(name),
  155. )
  156. poll.WaitOn(t, swarm.RunningTasksCount(client, serviceID, instances), swarm.ServicePoll)
  157. resp, _, err := client.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{})
  158. assert.NilError(t, err)
  159. assert.Check(t, is.Equal(n3, resp.Spec.TaskTemplate.Networks[0].Target))
  160. // Remove Service, and wait for its tasks to be removed
  161. err = client.ServiceRemove(ctx, serviceID)
  162. assert.NilError(t, err)
  163. poll.WaitOn(t, swarm.NoTasksForService(ctx, client, serviceID), swarm.ServicePoll)
  164. // Remove networks
  165. err = client.NetworkRemove(context.Background(), n3)
  166. assert.NilError(t, err)
  167. err = client.NetworkRemove(context.Background(), n2)
  168. assert.NilError(t, err)
  169. err = client.NetworkRemove(context.Background(), n1)
  170. assert.NilError(t, err)
  171. // Make sure networks have been destroyed.
  172. poll.WaitOn(t, network.IsRemoved(context.Background(), client, n3), poll.WithTimeout(1*time.Minute), poll.WithDelay(10*time.Second))
  173. poll.WaitOn(t, network.IsRemoved(context.Background(), client, n2), poll.WithTimeout(1*time.Minute), poll.WithDelay(10*time.Second))
  174. poll.WaitOn(t, network.IsRemoved(context.Background(), client, n1), poll.WithTimeout(1*time.Minute), poll.WithDelay(10*time.Second))
  175. }
  176. func TestCreateServiceSecretFileMode(t *testing.T) {
  177. skip.If(t, testEnv.DaemonInfo.OSType == "windows")
  178. defer setupTest(t)()
  179. d := swarm.NewSwarm(t, testEnv)
  180. defer d.Stop(t)
  181. client := d.NewClientT(t)
  182. defer client.Close()
  183. ctx := context.Background()
  184. secretName := "TestSecret_" + t.Name()
  185. secretResp, err := client.SecretCreate(ctx, swarmtypes.SecretSpec{
  186. Annotations: swarmtypes.Annotations{
  187. Name: secretName,
  188. },
  189. Data: []byte("TESTSECRET"),
  190. })
  191. assert.NilError(t, err)
  192. var instances uint64 = 1
  193. serviceName := "TestService_" + t.Name()
  194. serviceID := swarm.CreateService(t, d,
  195. swarm.ServiceWithReplicas(instances),
  196. swarm.ServiceWithName(serviceName),
  197. swarm.ServiceWithCommand([]string{"/bin/sh", "-c", "ls -l /etc/secret || /bin/top"}),
  198. swarm.ServiceWithSecret(&swarmtypes.SecretReference{
  199. File: &swarmtypes.SecretReferenceFileTarget{
  200. Name: "/etc/secret",
  201. UID: "0",
  202. GID: "0",
  203. Mode: 0777,
  204. },
  205. SecretID: secretResp.ID,
  206. SecretName: secretName,
  207. }),
  208. )
  209. poll.WaitOn(t, swarm.RunningTasksCount(client, serviceID, instances), swarm.ServicePoll)
  210. filter := filters.NewArgs()
  211. filter.Add("service", serviceID)
  212. tasks, err := client.TaskList(ctx, types.TaskListOptions{
  213. Filters: filter,
  214. })
  215. assert.NilError(t, err)
  216. assert.Check(t, is.Equal(len(tasks), 1))
  217. body, err := client.ContainerLogs(ctx, tasks[0].Status.ContainerStatus.ContainerID, types.ContainerLogsOptions{
  218. ShowStdout: true,
  219. })
  220. assert.NilError(t, err)
  221. defer body.Close()
  222. content, err := ioutil.ReadAll(body)
  223. assert.NilError(t, err)
  224. assert.Check(t, is.Contains(string(content), "-rwxrwxrwx"))
  225. err = client.ServiceRemove(ctx, serviceID)
  226. assert.NilError(t, err)
  227. poll.WaitOn(t, swarm.NoTasksForService(ctx, client, serviceID), swarm.ServicePoll)
  228. err = client.SecretRemove(ctx, secretName)
  229. assert.NilError(t, err)
  230. }
  231. func TestCreateServiceConfigFileMode(t *testing.T) {
  232. skip.If(t, testEnv.DaemonInfo.OSType == "windows")
  233. defer setupTest(t)()
  234. d := swarm.NewSwarm(t, testEnv)
  235. defer d.Stop(t)
  236. client := d.NewClientT(t)
  237. defer client.Close()
  238. ctx := context.Background()
  239. configName := "TestConfig_" + t.Name()
  240. configResp, err := client.ConfigCreate(ctx, swarmtypes.ConfigSpec{
  241. Annotations: swarmtypes.Annotations{
  242. Name: configName,
  243. },
  244. Data: []byte("TESTCONFIG"),
  245. })
  246. assert.NilError(t, err)
  247. var instances uint64 = 1
  248. serviceName := "TestService_" + t.Name()
  249. serviceID := swarm.CreateService(t, d,
  250. swarm.ServiceWithName(serviceName),
  251. swarm.ServiceWithCommand([]string{"/bin/sh", "-c", "ls -l /etc/config || /bin/top"}),
  252. swarm.ServiceWithReplicas(instances),
  253. swarm.ServiceWithConfig(&swarmtypes.ConfigReference{
  254. File: &swarmtypes.ConfigReferenceFileTarget{
  255. Name: "/etc/config",
  256. UID: "0",
  257. GID: "0",
  258. Mode: 0777,
  259. },
  260. ConfigID: configResp.ID,
  261. ConfigName: configName,
  262. }),
  263. )
  264. poll.WaitOn(t, swarm.RunningTasksCount(client, serviceID, instances))
  265. filter := filters.NewArgs()
  266. filter.Add("service", serviceID)
  267. tasks, err := client.TaskList(ctx, types.TaskListOptions{
  268. Filters: filter,
  269. })
  270. assert.NilError(t, err)
  271. assert.Check(t, is.Equal(len(tasks), 1))
  272. body, err := client.ContainerLogs(ctx, tasks[0].Status.ContainerStatus.ContainerID, types.ContainerLogsOptions{
  273. ShowStdout: true,
  274. })
  275. assert.NilError(t, err)
  276. defer body.Close()
  277. content, err := ioutil.ReadAll(body)
  278. assert.NilError(t, err)
  279. assert.Check(t, is.Contains(string(content), "-rwxrwxrwx"))
  280. err = client.ServiceRemove(ctx, serviceID)
  281. assert.NilError(t, err)
  282. poll.WaitOn(t, swarm.NoTasksForService(ctx, client, serviceID))
  283. err = client.ConfigRemove(ctx, configName)
  284. assert.NilError(t, err)
  285. }
  286. // TestServiceCreateSysctls tests that a service created with sysctl options in
  287. // the ContainerSpec correctly applies those options.
  288. //
  289. // To test this, we're going to create a service with the sysctl option
  290. //
  291. // {"net.ipv4.ip_nonlocal_bind": "0"}
  292. //
  293. // We'll get the service's tasks to get the container ID, and then we'll
  294. // inspect the container. If the output of the container inspect contains the
  295. // sysctl option with the correct value, we can assume that the sysctl has been
  296. // plumbed correctly.
  297. //
  298. // Next, we'll remove that service and create a new service with that option
  299. // set to 1. This means that no matter what the default is, we can be confident
  300. // that the sysctl option is applying as intended.
  301. //
  302. // Additionally, we'll do service and task inspects to verify that the inspect
  303. // output includes the desired sysctl option.
  304. //
  305. // We're using net.ipv4.ip_nonlocal_bind because it's something that I'm fairly
  306. // confident won't be modified by the container runtime, and won't blow
  307. // anything up in the test environment
  308. func TestCreateServiceSysctls(t *testing.T) {
  309. skip.If(
  310. t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.40"),
  311. "setting service sysctls is unsupported before api v1.40",
  312. )
  313. defer setupTest(t)()
  314. d := swarm.NewSwarm(t, testEnv)
  315. defer d.Stop(t)
  316. client := d.NewClientT(t)
  317. defer client.Close()
  318. ctx := context.Background()
  319. // run thie block twice, so that no matter what the default value of
  320. // net.ipv4.ip_nonlocal_bind is, we can verify that setting the sysctl
  321. // options works
  322. for _, expected := range []string{"0", "1"} {
  323. // store the map we're going to be using everywhere.
  324. expectedSysctls := map[string]string{"net.ipv4.ip_nonlocal_bind": expected}
  325. // Create the service with the sysctl options
  326. var instances uint64 = 1
  327. serviceID := swarm.CreateService(t, d,
  328. swarm.ServiceWithSysctls(expectedSysctls),
  329. )
  330. // wait for the service to converge to 1 running task as expected
  331. poll.WaitOn(t, swarm.RunningTasksCount(client, serviceID, instances))
  332. // we're going to check 3 things:
  333. //
  334. // 1. Does the container, when inspected, have the sysctl option set?
  335. // 2. Does the task have the sysctl in the spec?
  336. // 3. Does the service have the sysctl in the spec?
  337. //
  338. // if all 3 of these things are true, we know that the sysctl has been
  339. // plumbed correctly through the engine.
  340. //
  341. // We don't actually have to get inside the container and check its
  342. // logs or anything. If we see the sysctl set on the container inspect,
  343. // we know that the sysctl is plumbed correctly. everything below that
  344. // level has been tested elsewhere. (thanks @thaJeztah, because an
  345. // earlier version of this test had to get container logs and was much
  346. // more complex)
  347. // get all of the tasks of the service, so we can get the container
  348. filter := filters.NewArgs()
  349. filter.Add("service", serviceID)
  350. tasks, err := client.TaskList(ctx, types.TaskListOptions{
  351. Filters: filter,
  352. })
  353. assert.NilError(t, err)
  354. assert.Check(t, is.Equal(len(tasks), 1))
  355. // verify that the container has the sysctl option set
  356. ctnr, err := client.ContainerInspect(ctx, tasks[0].Status.ContainerStatus.ContainerID)
  357. assert.NilError(t, err)
  358. assert.DeepEqual(t, ctnr.HostConfig.Sysctls, expectedSysctls)
  359. // verify that the task has the sysctl option set in the task object
  360. assert.DeepEqual(t, tasks[0].Spec.ContainerSpec.Sysctls, expectedSysctls)
  361. // verify that the service also has the sysctl set in the spec.
  362. service, _, err := client.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{})
  363. assert.NilError(t, err)
  364. assert.DeepEqual(t,
  365. service.Spec.TaskTemplate.ContainerSpec.Sysctls, expectedSysctls,
  366. )
  367. }
  368. }