create_test.go 15 KB

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