config_test.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. package config // import "github.com/docker/docker/integration/config"
  2. import (
  3. "bytes"
  4. "context"
  5. "encoding/json"
  6. "sort"
  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/client"
  13. "github.com/docker/docker/integration/internal/swarm"
  14. "github.com/docker/docker/pkg/stdcopy"
  15. "github.com/gotestyourself/gotestyourself/assert"
  16. is "github.com/gotestyourself/gotestyourself/assert/cmp"
  17. "github.com/gotestyourself/gotestyourself/skip"
  18. )
  19. func TestConfigList(t *testing.T) {
  20. skip.If(t, testEnv.DaemonInfo.OSType != "linux")
  21. defer setupTest(t)()
  22. d := swarm.NewSwarm(t, testEnv)
  23. defer d.Stop(t)
  24. client := d.NewClientT(t)
  25. defer client.Close()
  26. ctx := context.Background()
  27. // This test case is ported from the original TestConfigsEmptyList
  28. configs, err := client.ConfigList(ctx, types.ConfigListOptions{})
  29. assert.NilError(t, err)
  30. assert.Check(t, is.Equal(len(configs), 0))
  31. testName0 := "test0-" + t.Name()
  32. testName1 := "test1-" + t.Name()
  33. testNames := []string{testName0, testName1}
  34. sort.Strings(testNames)
  35. // create config test0
  36. createConfig(ctx, t, client, testName0, []byte("TESTINGDATA0"), map[string]string{"type": "test"})
  37. config1ID := createConfig(ctx, t, client, testName1, []byte("TESTINGDATA1"), map[string]string{"type": "production"})
  38. names := func(entries []swarmtypes.Config) []string {
  39. var values []string
  40. for _, entry := range entries {
  41. values = append(values, entry.Spec.Name)
  42. }
  43. sort.Strings(values)
  44. return values
  45. }
  46. // test by `config ls`
  47. entries, err := client.ConfigList(ctx, types.ConfigListOptions{})
  48. assert.NilError(t, err)
  49. assert.Check(t, is.DeepEqual(names(entries), testNames))
  50. testCases := []struct {
  51. filters filters.Args
  52. expected []string
  53. }{
  54. // test filter by name `config ls --filter name=xxx`
  55. {
  56. filters: filters.NewArgs(filters.Arg("name", testName0)),
  57. expected: []string{testName0},
  58. },
  59. // test filter by id `config ls --filter id=xxx`
  60. {
  61. filters: filters.NewArgs(filters.Arg("id", config1ID)),
  62. expected: []string{testName1},
  63. },
  64. // test filter by label `config ls --filter label=xxx`
  65. {
  66. filters: filters.NewArgs(filters.Arg("label", "type")),
  67. expected: testNames,
  68. },
  69. {
  70. filters: filters.NewArgs(filters.Arg("label", "type=test")),
  71. expected: []string{testName0},
  72. },
  73. {
  74. filters: filters.NewArgs(filters.Arg("label", "type=production")),
  75. expected: []string{testName1},
  76. },
  77. }
  78. for _, tc := range testCases {
  79. entries, err = client.ConfigList(ctx, types.ConfigListOptions{
  80. Filters: tc.filters,
  81. })
  82. assert.NilError(t, err)
  83. assert.Check(t, is.DeepEqual(names(entries), tc.expected))
  84. }
  85. }
  86. func createConfig(ctx context.Context, t *testing.T, client client.APIClient, name string, data []byte, labels map[string]string) string {
  87. config, err := client.ConfigCreate(ctx, swarmtypes.ConfigSpec{
  88. Annotations: swarmtypes.Annotations{
  89. Name: name,
  90. Labels: labels,
  91. },
  92. Data: data,
  93. })
  94. assert.NilError(t, err)
  95. assert.Check(t, config.ID != "")
  96. return config.ID
  97. }
  98. func TestConfigsCreateAndDelete(t *testing.T) {
  99. skip.If(t, testEnv.DaemonInfo.OSType != "linux")
  100. defer setupTest(t)()
  101. d := swarm.NewSwarm(t, testEnv)
  102. defer d.Stop(t)
  103. client := d.NewClientT(t)
  104. defer client.Close()
  105. ctx := context.Background()
  106. testName := "test_config-" + t.Name()
  107. // This test case is ported from the original TestConfigsCreate
  108. configID := createConfig(ctx, t, client, testName, []byte("TESTINGDATA"), nil)
  109. insp, _, err := client.ConfigInspectWithRaw(ctx, configID)
  110. assert.NilError(t, err)
  111. assert.Check(t, is.Equal(insp.Spec.Name, testName))
  112. // This test case is ported from the original TestConfigsDelete
  113. err = client.ConfigRemove(ctx, configID)
  114. assert.NilError(t, err)
  115. insp, _, err = client.ConfigInspectWithRaw(ctx, configID)
  116. assert.Check(t, is.ErrorContains(err, "No such config"))
  117. }
  118. func TestConfigsUpdate(t *testing.T) {
  119. skip.If(t, testEnv.DaemonInfo.OSType != "linux")
  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. ctx := context.Background()
  126. testName := "test_config-" + t.Name()
  127. // This test case is ported from the original TestConfigsCreate
  128. configID := createConfig(ctx, t, client, testName, []byte("TESTINGDATA"), nil)
  129. insp, _, err := client.ConfigInspectWithRaw(ctx, configID)
  130. assert.NilError(t, err)
  131. assert.Check(t, is.Equal(insp.ID, configID))
  132. // test UpdateConfig with full ID
  133. insp.Spec.Labels = map[string]string{"test": "test1"}
  134. err = client.ConfigUpdate(ctx, configID, insp.Version, insp.Spec)
  135. assert.NilError(t, err)
  136. insp, _, err = client.ConfigInspectWithRaw(ctx, configID)
  137. assert.NilError(t, err)
  138. assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test1"))
  139. // test UpdateConfig with full name
  140. insp.Spec.Labels = map[string]string{"test": "test2"}
  141. err = client.ConfigUpdate(ctx, testName, insp.Version, insp.Spec)
  142. assert.NilError(t, err)
  143. insp, _, err = client.ConfigInspectWithRaw(ctx, configID)
  144. assert.NilError(t, err)
  145. assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test2"))
  146. // test UpdateConfig with prefix ID
  147. insp.Spec.Labels = map[string]string{"test": "test3"}
  148. err = client.ConfigUpdate(ctx, configID[:1], insp.Version, insp.Spec)
  149. assert.NilError(t, err)
  150. insp, _, err = client.ConfigInspectWithRaw(ctx, configID)
  151. assert.NilError(t, err)
  152. assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test3"))
  153. // test UpdateConfig in updating Data which is not supported in daemon
  154. // this test will produce an error in func UpdateConfig
  155. insp.Spec.Data = []byte("TESTINGDATA2")
  156. err = client.ConfigUpdate(ctx, configID, insp.Version, insp.Spec)
  157. assert.Check(t, is.ErrorContains(err, "only updates to Labels are allowed"))
  158. }
  159. func TestTemplatedConfig(t *testing.T) {
  160. d := swarm.NewSwarm(t, testEnv)
  161. defer d.Stop(t)
  162. client := d.NewClientT(t)
  163. defer client.Close()
  164. ctx := context.Background()
  165. referencedSecretName := "referencedsecret-" + t.Name()
  166. referencedSecretSpec := swarmtypes.SecretSpec{
  167. Annotations: swarmtypes.Annotations{
  168. Name: referencedSecretName,
  169. },
  170. Data: []byte("this is a secret"),
  171. }
  172. referencedSecret, err := client.SecretCreate(ctx, referencedSecretSpec)
  173. assert.Check(t, err)
  174. referencedConfigName := "referencedconfig-" + t.Name()
  175. referencedConfigSpec := swarmtypes.ConfigSpec{
  176. Annotations: swarmtypes.Annotations{
  177. Name: referencedConfigName,
  178. },
  179. Data: []byte("this is a config"),
  180. }
  181. referencedConfig, err := client.ConfigCreate(ctx, referencedConfigSpec)
  182. assert.Check(t, err)
  183. templatedConfigName := "templated_config-" + t.Name()
  184. configSpec := swarmtypes.ConfigSpec{
  185. Annotations: swarmtypes.Annotations{
  186. Name: templatedConfigName,
  187. },
  188. Templating: &swarmtypes.Driver{
  189. Name: "golang",
  190. },
  191. Data: []byte("SERVICE_NAME={{.Service.Name}}\n" +
  192. "{{secret \"referencedsecrettarget\"}}\n" +
  193. "{{config \"referencedconfigtarget\"}}\n"),
  194. }
  195. templatedConfig, err := client.ConfigCreate(ctx, configSpec)
  196. assert.Check(t, err)
  197. serviceID := swarm.CreateService(t, d,
  198. swarm.ServiceWithConfig(
  199. &swarmtypes.ConfigReference{
  200. File: &swarmtypes.ConfigReferenceFileTarget{
  201. Name: "/" + templatedConfigName,
  202. UID: "0",
  203. GID: "0",
  204. Mode: 0600,
  205. },
  206. ConfigID: templatedConfig.ID,
  207. ConfigName: templatedConfigName,
  208. },
  209. ),
  210. swarm.ServiceWithConfig(
  211. &swarmtypes.ConfigReference{
  212. File: &swarmtypes.ConfigReferenceFileTarget{
  213. Name: "referencedconfigtarget",
  214. UID: "0",
  215. GID: "0",
  216. Mode: 0600,
  217. },
  218. ConfigID: referencedConfig.ID,
  219. ConfigName: referencedConfigName,
  220. },
  221. ),
  222. swarm.ServiceWithSecret(
  223. &swarmtypes.SecretReference{
  224. File: &swarmtypes.SecretReferenceFileTarget{
  225. Name: "referencedsecrettarget",
  226. UID: "0",
  227. GID: "0",
  228. Mode: 0600,
  229. },
  230. SecretID: referencedSecret.ID,
  231. SecretName: referencedSecretName,
  232. },
  233. ),
  234. swarm.ServiceWithName("svc"),
  235. )
  236. var tasks []swarmtypes.Task
  237. waitAndAssert(t, 60*time.Second, func(t *testing.T) bool {
  238. tasks = swarm.GetRunningTasks(t, d, serviceID)
  239. return len(tasks) > 0
  240. })
  241. task := tasks[0]
  242. waitAndAssert(t, 60*time.Second, func(t *testing.T) bool {
  243. if task.NodeID == "" || (task.Status.ContainerStatus == nil || task.Status.ContainerStatus.ContainerID == "") {
  244. task, _, _ = client.TaskInspectWithRaw(context.Background(), task.ID)
  245. }
  246. return task.NodeID != "" && task.Status.ContainerStatus != nil && task.Status.ContainerStatus.ContainerID != ""
  247. })
  248. attach := swarm.ExecTask(t, d, task, types.ExecConfig{
  249. Cmd: []string{"/bin/cat", "/" + templatedConfigName},
  250. AttachStdout: true,
  251. AttachStderr: true,
  252. })
  253. expect := "SERVICE_NAME=svc\n" +
  254. "this is a secret\n" +
  255. "this is a config\n"
  256. assertAttachedStream(t, attach, expect)
  257. attach = swarm.ExecTask(t, d, task, types.ExecConfig{
  258. Cmd: []string{"mount"},
  259. AttachStdout: true,
  260. AttachStderr: true,
  261. })
  262. assertAttachedStream(t, attach, "tmpfs on /"+templatedConfigName+" type tmpfs")
  263. }
  264. func assertAttachedStream(t *testing.T, attach types.HijackedResponse, expect string) {
  265. buf := bytes.NewBuffer(nil)
  266. _, err := stdcopy.StdCopy(buf, buf, attach.Reader)
  267. assert.NilError(t, err)
  268. assert.Check(t, is.Contains(buf.String(), expect))
  269. }
  270. func waitAndAssert(t *testing.T, timeout time.Duration, f func(*testing.T) bool) {
  271. t.Helper()
  272. after := time.After(timeout)
  273. for {
  274. select {
  275. case <-after:
  276. t.Fatalf("timed out waiting for condition")
  277. default:
  278. }
  279. if f(t) {
  280. return
  281. }
  282. time.Sleep(100 * time.Millisecond)
  283. }
  284. }
  285. func TestConfigInspect(t *testing.T) {
  286. skip.If(t, testEnv.DaemonInfo.OSType != "linux")
  287. defer setupTest(t)()
  288. d := swarm.NewSwarm(t, testEnv)
  289. defer d.Stop(t)
  290. client := d.NewClientT(t)
  291. defer client.Close()
  292. ctx := context.Background()
  293. testName := t.Name()
  294. configID := createConfig(ctx, t, client, testName, []byte("TESTINGDATA"), nil)
  295. insp, body, err := client.ConfigInspectWithRaw(ctx, configID)
  296. assert.NilError(t, err)
  297. assert.Check(t, is.Equal(insp.Spec.Name, testName))
  298. var config swarmtypes.Config
  299. err = json.Unmarshal(body, &config)
  300. assert.NilError(t, err)
  301. assert.Check(t, is.DeepEqual(config, insp))
  302. }