config_test.go 10 KB

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