docker_api_containers_test.go 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623
  1. package main
  2. import (
  3. "archive/tar"
  4. "bytes"
  5. "encoding/json"
  6. "fmt"
  7. "io"
  8. "net/http"
  9. "net/http/httputil"
  10. "net/url"
  11. "os"
  12. "regexp"
  13. "strconv"
  14. "strings"
  15. "time"
  16. "github.com/docker/docker/pkg/integration"
  17. "github.com/docker/docker/pkg/integration/checker"
  18. "github.com/docker/docker/pkg/stringid"
  19. "github.com/docker/engine-api/types"
  20. containertypes "github.com/docker/engine-api/types/container"
  21. networktypes "github.com/docker/engine-api/types/network"
  22. "github.com/go-check/check"
  23. )
  24. var sleepCmd = "/bin/sleep"
  25. func init() {
  26. if daemonPlatform == "windows" {
  27. sleepCmd = "sleep"
  28. }
  29. }
  30. func (s *DockerSuite) TestContainerApiGetAll(c *check.C) {
  31. startCount, err := getContainerCount()
  32. c.Assert(err, checker.IsNil, check.Commentf("Cannot query container count"))
  33. name := "getall"
  34. dockerCmd(c, "run", "--name", name, "busybox", "true")
  35. status, body, err := sockRequest("GET", "/containers/json?all=1", nil)
  36. c.Assert(err, checker.IsNil)
  37. c.Assert(status, checker.Equals, http.StatusOK)
  38. var inspectJSON []struct {
  39. Names []string
  40. }
  41. err = json.Unmarshal(body, &inspectJSON)
  42. c.Assert(err, checker.IsNil, check.Commentf("unable to unmarshal response body"))
  43. c.Assert(inspectJSON, checker.HasLen, startCount+1)
  44. actual := inspectJSON[0].Names[0]
  45. c.Assert(actual, checker.Equals, "/"+name)
  46. }
  47. // regression test for empty json field being omitted #13691
  48. func (s *DockerSuite) TestContainerApiGetJSONNoFieldsOmitted(c *check.C) {
  49. dockerCmd(c, "run", "busybox", "true")
  50. status, body, err := sockRequest("GET", "/containers/json?all=1", nil)
  51. c.Assert(err, checker.IsNil)
  52. c.Assert(status, checker.Equals, http.StatusOK)
  53. // empty Labels field triggered this bug, make sense to check for everything
  54. // cause even Ports for instance can trigger this bug
  55. // better safe than sorry..
  56. fields := []string{
  57. "Id",
  58. "Names",
  59. "Image",
  60. "Command",
  61. "Created",
  62. "Ports",
  63. "Labels",
  64. "Status",
  65. "NetworkSettings",
  66. }
  67. // decoding into types.Container do not work since it eventually unmarshal
  68. // and empty field to an empty go map, so we just check for a string
  69. for _, f := range fields {
  70. if !strings.Contains(string(body), f) {
  71. c.Fatalf("Field %s is missing and it shouldn't", f)
  72. }
  73. }
  74. }
  75. type containerPs struct {
  76. Names []string
  77. Ports []map[string]interface{}
  78. }
  79. // regression test for non-empty fields from #13901
  80. func (s *DockerSuite) TestContainerApiPsOmitFields(c *check.C) {
  81. // Problematic for Windows porting due to networking not yet being passed back
  82. testRequires(c, DaemonIsLinux)
  83. name := "pstest"
  84. port := 80
  85. dockerCmd(c, "run", "-d", "--name", name, "--expose", strconv.Itoa(port), "busybox", sleepCmd, "60")
  86. status, body, err := sockRequest("GET", "/containers/json?all=1", nil)
  87. c.Assert(err, checker.IsNil)
  88. c.Assert(status, checker.Equals, http.StatusOK)
  89. var resp []containerPs
  90. err = json.Unmarshal(body, &resp)
  91. c.Assert(err, checker.IsNil)
  92. var foundContainer *containerPs
  93. for _, container := range resp {
  94. for _, testName := range container.Names {
  95. if "/"+name == testName {
  96. foundContainer = &container
  97. break
  98. }
  99. }
  100. }
  101. c.Assert(foundContainer.Ports, checker.HasLen, 1)
  102. c.Assert(foundContainer.Ports[0]["PrivatePort"], checker.Equals, float64(port))
  103. _, ok := foundContainer.Ports[0]["PublicPort"]
  104. c.Assert(ok, checker.Not(checker.Equals), true)
  105. _, ok = foundContainer.Ports[0]["IP"]
  106. c.Assert(ok, checker.Not(checker.Equals), true)
  107. }
  108. func (s *DockerSuite) TestContainerApiGetExport(c *check.C) {
  109. // TODO: Investigate why this fails on Windows to Windows CI
  110. testRequires(c, DaemonIsLinux)
  111. name := "exportcontainer"
  112. dockerCmd(c, "run", "--name", name, "busybox", "touch", "/test")
  113. status, body, err := sockRequest("GET", "/containers/"+name+"/export", nil)
  114. c.Assert(err, checker.IsNil)
  115. c.Assert(status, checker.Equals, http.StatusOK)
  116. found := false
  117. for tarReader := tar.NewReader(bytes.NewReader(body)); ; {
  118. h, err := tarReader.Next()
  119. if err != nil && err == io.EOF {
  120. break
  121. }
  122. if h.Name == "test" {
  123. found = true
  124. break
  125. }
  126. }
  127. c.Assert(found, checker.True, check.Commentf("The created test file has not been found in the exported image"))
  128. }
  129. func (s *DockerSuite) TestContainerApiGetChanges(c *check.C) {
  130. // Not supported on Windows as Windows does not support docker diff (/containers/name/changes)
  131. testRequires(c, DaemonIsLinux)
  132. name := "changescontainer"
  133. dockerCmd(c, "run", "--name", name, "busybox", "rm", "/etc/passwd")
  134. status, body, err := sockRequest("GET", "/containers/"+name+"/changes", nil)
  135. c.Assert(err, checker.IsNil)
  136. c.Assert(status, checker.Equals, http.StatusOK)
  137. changes := []struct {
  138. Kind int
  139. Path string
  140. }{}
  141. c.Assert(json.Unmarshal(body, &changes), checker.IsNil, check.Commentf("unable to unmarshal response body"))
  142. // Check the changelog for removal of /etc/passwd
  143. success := false
  144. for _, elem := range changes {
  145. if elem.Path == "/etc/passwd" && elem.Kind == 2 {
  146. success = true
  147. }
  148. }
  149. c.Assert(success, checker.True, check.Commentf("/etc/passwd has been removed but is not present in the diff"))
  150. }
  151. func (s *DockerSuite) TestContainerApiStartVolumeBinds(c *check.C) {
  152. // TODO Windows CI: Investigate further why this fails on Windows to Windows CI.
  153. testRequires(c, DaemonIsLinux)
  154. path := "/foo"
  155. if daemonPlatform == "windows" {
  156. path = `c:\foo`
  157. }
  158. name := "testing"
  159. config := map[string]interface{}{
  160. "Image": "busybox",
  161. "Volumes": map[string]struct{}{path: {}},
  162. }
  163. status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
  164. c.Assert(err, checker.IsNil)
  165. c.Assert(status, checker.Equals, http.StatusCreated)
  166. bindPath := randomTmpDirPath("test", daemonPlatform)
  167. config = map[string]interface{}{
  168. "Binds": []string{bindPath + ":" + path},
  169. }
  170. status, _, err = sockRequest("POST", "/containers/"+name+"/start", config)
  171. c.Assert(err, checker.IsNil)
  172. c.Assert(status, checker.Equals, http.StatusNoContent)
  173. pth, err := inspectMountSourceField(name, path)
  174. c.Assert(err, checker.IsNil)
  175. c.Assert(pth, checker.Equals, bindPath, check.Commentf("expected volume host path to be %s, got %s", bindPath, pth))
  176. }
  177. // Test for GH#10618
  178. func (s *DockerSuite) TestContainerApiStartDupVolumeBinds(c *check.C) {
  179. // TODO Windows to Windows CI - Port this
  180. testRequires(c, DaemonIsLinux)
  181. name := "testdups"
  182. config := map[string]interface{}{
  183. "Image": "busybox",
  184. "Volumes": map[string]struct{}{"/tmp": {}},
  185. }
  186. status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
  187. c.Assert(err, checker.IsNil)
  188. c.Assert(status, checker.Equals, http.StatusCreated)
  189. bindPath1 := randomTmpDirPath("test1", daemonPlatform)
  190. bindPath2 := randomTmpDirPath("test2", daemonPlatform)
  191. config = map[string]interface{}{
  192. "Binds": []string{bindPath1 + ":/tmp", bindPath2 + ":/tmp"},
  193. }
  194. status, body, err := sockRequest("POST", "/containers/"+name+"/start", config)
  195. c.Assert(err, checker.IsNil)
  196. c.Assert(status, checker.Equals, http.StatusInternalServerError)
  197. c.Assert(string(body), checker.Contains, "Duplicate mount point", check.Commentf("Expected failure due to duplicate bind mounts to same path, instead got: %q with error: %v", string(body), err))
  198. }
  199. func (s *DockerSuite) TestContainerApiStartVolumesFrom(c *check.C) {
  200. // TODO Windows to Windows CI - Port this
  201. testRequires(c, DaemonIsLinux)
  202. volName := "voltst"
  203. volPath := "/tmp"
  204. dockerCmd(c, "run", "-d", "--name", volName, "-v", volPath, "busybox")
  205. name := "TestContainerApiStartVolumesFrom"
  206. config := map[string]interface{}{
  207. "Image": "busybox",
  208. "Volumes": map[string]struct{}{volPath: {}},
  209. }
  210. status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
  211. c.Assert(err, checker.IsNil)
  212. c.Assert(status, checker.Equals, http.StatusCreated)
  213. config = map[string]interface{}{
  214. "VolumesFrom": []string{volName},
  215. }
  216. status, _, err = sockRequest("POST", "/containers/"+name+"/start", config)
  217. c.Assert(err, checker.IsNil)
  218. c.Assert(status, checker.Equals, http.StatusNoContent)
  219. pth, err := inspectMountSourceField(name, volPath)
  220. c.Assert(err, checker.IsNil)
  221. pth2, err := inspectMountSourceField(volName, volPath)
  222. c.Assert(err, checker.IsNil)
  223. c.Assert(pth, checker.Equals, pth2, check.Commentf("expected volume host path to be %s, got %s", pth, pth2))
  224. }
  225. func (s *DockerSuite) TestGetContainerStats(c *check.C) {
  226. // Problematic on Windows as Windows does not support stats
  227. testRequires(c, DaemonIsLinux)
  228. var (
  229. name = "statscontainer"
  230. )
  231. dockerCmd(c, "run", "-d", "--name", name, "busybox", "top")
  232. type b struct {
  233. status int
  234. body []byte
  235. err error
  236. }
  237. bc := make(chan b, 1)
  238. go func() {
  239. status, body, err := sockRequest("GET", "/containers/"+name+"/stats", nil)
  240. bc <- b{status, body, err}
  241. }()
  242. // allow some time to stream the stats from the container
  243. time.Sleep(4 * time.Second)
  244. dockerCmd(c, "rm", "-f", name)
  245. // collect the results from the stats stream or timeout and fail
  246. // if the stream was not disconnected.
  247. select {
  248. case <-time.After(2 * time.Second):
  249. c.Fatal("stream was not closed after container was removed")
  250. case sr := <-bc:
  251. c.Assert(sr.err, checker.IsNil)
  252. c.Assert(sr.status, checker.Equals, http.StatusOK)
  253. dec := json.NewDecoder(bytes.NewBuffer(sr.body))
  254. var s *types.Stats
  255. // decode only one object from the stream
  256. c.Assert(dec.Decode(&s), checker.IsNil)
  257. }
  258. }
  259. func (s *DockerSuite) TestGetContainerStatsRmRunning(c *check.C) {
  260. // Problematic on Windows as Windows does not support stats
  261. testRequires(c, DaemonIsLinux)
  262. out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
  263. id := strings.TrimSpace(out)
  264. buf := &integration.ChannelBuffer{make(chan []byte, 1)}
  265. defer buf.Close()
  266. chErr := make(chan error)
  267. go func() {
  268. _, body, err := sockRequestRaw("GET", "/containers/"+id+"/stats?stream=1", nil, "application/json")
  269. if err != nil {
  270. chErr <- err
  271. }
  272. defer body.Close()
  273. _, err = io.Copy(buf, body)
  274. chErr <- err
  275. }()
  276. defer func() {
  277. c.Assert(<-chErr, checker.IsNil)
  278. }()
  279. b := make([]byte, 32)
  280. // make sure we've got some stats
  281. _, err := buf.ReadTimeout(b, 2*time.Second)
  282. c.Assert(err, checker.IsNil)
  283. // Now remove without `-f` and make sure we are still pulling stats
  284. _, _, err = dockerCmdWithError("rm", id)
  285. c.Assert(err, checker.Not(checker.IsNil), check.Commentf("rm should have failed but didn't"))
  286. _, err = buf.ReadTimeout(b, 2*time.Second)
  287. c.Assert(err, checker.IsNil)
  288. dockerCmd(c, "rm", "-f", id)
  289. _, err = buf.ReadTimeout(b, 2*time.Second)
  290. c.Assert(err, checker.Not(checker.IsNil))
  291. }
  292. // regression test for gh13421
  293. // previous test was just checking one stat entry so it didn't fail (stats with
  294. // stream false always return one stat)
  295. func (s *DockerSuite) TestGetContainerStatsStream(c *check.C) {
  296. // Problematic on Windows as Windows does not support stats
  297. testRequires(c, DaemonIsLinux)
  298. name := "statscontainer"
  299. dockerCmd(c, "run", "-d", "--name", name, "busybox", "top")
  300. type b struct {
  301. status int
  302. body []byte
  303. err error
  304. }
  305. bc := make(chan b, 1)
  306. go func() {
  307. status, body, err := sockRequest("GET", "/containers/"+name+"/stats", nil)
  308. bc <- b{status, body, err}
  309. }()
  310. // allow some time to stream the stats from the container
  311. time.Sleep(4 * time.Second)
  312. dockerCmd(c, "rm", "-f", name)
  313. // collect the results from the stats stream or timeout and fail
  314. // if the stream was not disconnected.
  315. select {
  316. case <-time.After(2 * time.Second):
  317. c.Fatal("stream was not closed after container was removed")
  318. case sr := <-bc:
  319. c.Assert(sr.err, checker.IsNil)
  320. c.Assert(sr.status, checker.Equals, http.StatusOK)
  321. s := string(sr.body)
  322. // count occurrences of "read" of types.Stats
  323. if l := strings.Count(s, "read"); l < 2 {
  324. c.Fatalf("Expected more than one stat streamed, got %d", l)
  325. }
  326. }
  327. }
  328. func (s *DockerSuite) TestGetContainerStatsNoStream(c *check.C) {
  329. // Problematic on Windows as Windows does not support stats
  330. testRequires(c, DaemonIsLinux)
  331. name := "statscontainer"
  332. dockerCmd(c, "run", "-d", "--name", name, "busybox", "top")
  333. type b struct {
  334. status int
  335. body []byte
  336. err error
  337. }
  338. bc := make(chan b, 1)
  339. go func() {
  340. status, body, err := sockRequest("GET", "/containers/"+name+"/stats?stream=0", nil)
  341. bc <- b{status, body, err}
  342. }()
  343. // allow some time to stream the stats from the container
  344. time.Sleep(4 * time.Second)
  345. dockerCmd(c, "rm", "-f", name)
  346. // collect the results from the stats stream or timeout and fail
  347. // if the stream was not disconnected.
  348. select {
  349. case <-time.After(2 * time.Second):
  350. c.Fatal("stream was not closed after container was removed")
  351. case sr := <-bc:
  352. c.Assert(sr.err, checker.IsNil)
  353. c.Assert(sr.status, checker.Equals, http.StatusOK)
  354. s := string(sr.body)
  355. // count occurrences of "read" of types.Stats
  356. c.Assert(strings.Count(s, "read"), checker.Equals, 1, check.Commentf("Expected only one stat streamed, got %d", strings.Count(s, "read")))
  357. }
  358. }
  359. func (s *DockerSuite) TestGetStoppedContainerStats(c *check.C) {
  360. // Problematic on Windows as Windows does not support stats
  361. testRequires(c, DaemonIsLinux)
  362. // TODO: this test does nothing because we are c.Assert'ing in goroutine
  363. var (
  364. name = "statscontainer"
  365. )
  366. dockerCmd(c, "create", "--name", name, "busybox", "top")
  367. go func() {
  368. // We'll never get return for GET stats from sockRequest as of now,
  369. // just send request and see if panic or error would happen on daemon side.
  370. status, _, err := sockRequest("GET", "/containers/"+name+"/stats", nil)
  371. c.Assert(err, checker.IsNil)
  372. c.Assert(status, checker.Equals, http.StatusOK)
  373. }()
  374. // allow some time to send request and let daemon deal with it
  375. time.Sleep(1 * time.Second)
  376. }
  377. // #9981 - Allow a docker created volume (ie, one in /var/lib/docker/volumes) to be used to overwrite (via passing in Binds on api start) an existing volume
  378. func (s *DockerSuite) TestPostContainerBindNormalVolume(c *check.C) {
  379. // TODO Windows to Windows CI - Port this
  380. testRequires(c, DaemonIsLinux)
  381. dockerCmd(c, "create", "-v", "/foo", "--name=one", "busybox")
  382. fooDir, err := inspectMountSourceField("one", "/foo")
  383. c.Assert(err, checker.IsNil)
  384. dockerCmd(c, "create", "-v", "/foo", "--name=two", "busybox")
  385. bindSpec := map[string][]string{"Binds": {fooDir + ":/foo"}}
  386. status, _, err := sockRequest("POST", "/containers/two/start", bindSpec)
  387. c.Assert(err, checker.IsNil)
  388. c.Assert(status, checker.Equals, http.StatusNoContent)
  389. fooDir2, err := inspectMountSourceField("two", "/foo")
  390. c.Assert(err, checker.IsNil)
  391. c.Assert(fooDir2, checker.Equals, fooDir, check.Commentf("expected volume path to be %s, got: %s", fooDir, fooDir2))
  392. }
  393. func (s *DockerSuite) TestContainerApiPause(c *check.C) {
  394. // Problematic on Windows as Windows does not support pause
  395. testRequires(c, DaemonIsLinux)
  396. defer unpauseAllContainers()
  397. out, _ := dockerCmd(c, "run", "-d", "busybox", "sleep", "30")
  398. ContainerID := strings.TrimSpace(out)
  399. status, _, err := sockRequest("POST", "/containers/"+ContainerID+"/pause", nil)
  400. c.Assert(err, checker.IsNil)
  401. c.Assert(status, checker.Equals, http.StatusNoContent)
  402. pausedContainers, err := getSliceOfPausedContainers()
  403. c.Assert(err, checker.IsNil, check.Commentf("error thrown while checking if containers were paused"))
  404. if len(pausedContainers) != 1 || stringid.TruncateID(ContainerID) != pausedContainers[0] {
  405. c.Fatalf("there should be one paused container and not %d", len(pausedContainers))
  406. }
  407. status, _, err = sockRequest("POST", "/containers/"+ContainerID+"/unpause", nil)
  408. c.Assert(err, checker.IsNil)
  409. c.Assert(status, checker.Equals, http.StatusNoContent)
  410. pausedContainers, err = getSliceOfPausedContainers()
  411. c.Assert(err, checker.IsNil, check.Commentf("error thrown while checking if containers were paused"))
  412. c.Assert(pausedContainers, checker.IsNil, check.Commentf("There should be no paused container."))
  413. }
  414. func (s *DockerSuite) TestContainerApiTop(c *check.C) {
  415. // Problematic on Windows as Windows does not support top
  416. testRequires(c, DaemonIsLinux)
  417. out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "top")
  418. id := strings.TrimSpace(string(out))
  419. c.Assert(waitRun(id), checker.IsNil)
  420. type topResp struct {
  421. Titles []string
  422. Processes [][]string
  423. }
  424. var top topResp
  425. status, b, err := sockRequest("GET", "/containers/"+id+"/top?ps_args=aux", nil)
  426. c.Assert(err, checker.IsNil)
  427. c.Assert(status, checker.Equals, http.StatusOK)
  428. c.Assert(json.Unmarshal(b, &top), checker.IsNil)
  429. c.Assert(top.Titles, checker.HasLen, 11, check.Commentf("expected 11 titles, found %d: %v", len(top.Titles), top.Titles))
  430. if top.Titles[0] != "USER" || top.Titles[10] != "COMMAND" {
  431. c.Fatalf("expected `USER` at `Titles[0]` and `COMMAND` at Titles[10]: %v", top.Titles)
  432. }
  433. c.Assert(top.Processes, checker.HasLen, 2, check.Commentf("expected 2 processes, found %d: %v", len(top.Processes), top.Processes))
  434. c.Assert(top.Processes[0][10], checker.Equals, "/bin/sh -c top")
  435. c.Assert(top.Processes[1][10], checker.Equals, "top")
  436. }
  437. func (s *DockerSuite) TestContainerApiCommit(c *check.C) {
  438. cName := "testapicommit"
  439. dockerCmd(c, "run", "--name="+cName, "busybox", "/bin/sh", "-c", "touch /test")
  440. name := "testcontainerapicommit"
  441. status, b, err := sockRequest("POST", "/commit?repo="+name+"&testtag=tag&container="+cName, nil)
  442. c.Assert(err, checker.IsNil)
  443. c.Assert(status, checker.Equals, http.StatusCreated)
  444. type resp struct {
  445. ID string
  446. }
  447. var img resp
  448. c.Assert(json.Unmarshal(b, &img), checker.IsNil)
  449. cmd, err := inspectField(img.ID, "Config.Cmd")
  450. c.Assert(err, checker.IsNil)
  451. c.Assert(cmd, checker.Equals, "{[/bin/sh -c touch /test]}", check.Commentf("got wrong Cmd from commit: %q", cmd))
  452. // sanity check, make sure the image is what we think it is
  453. dockerCmd(c, "run", img.ID, "ls", "/test")
  454. }
  455. func (s *DockerSuite) TestContainerApiCommitWithLabelInConfig(c *check.C) {
  456. cName := "testapicommitwithconfig"
  457. dockerCmd(c, "run", "--name="+cName, "busybox", "/bin/sh", "-c", "touch /test")
  458. config := map[string]interface{}{
  459. "Labels": map[string]string{"key1": "value1", "key2": "value2"},
  460. }
  461. name := "testcontainerapicommitwithconfig"
  462. status, b, err := sockRequest("POST", "/commit?repo="+name+"&container="+cName, config)
  463. c.Assert(err, checker.IsNil)
  464. c.Assert(status, checker.Equals, http.StatusCreated)
  465. type resp struct {
  466. ID string
  467. }
  468. var img resp
  469. c.Assert(json.Unmarshal(b, &img), checker.IsNil)
  470. label1, err := inspectFieldMap(img.ID, "Config.Labels", "key1")
  471. c.Assert(err, checker.IsNil)
  472. c.Assert(label1, checker.Equals, "value1")
  473. label2, err := inspectFieldMap(img.ID, "Config.Labels", "key2")
  474. c.Assert(err, checker.IsNil)
  475. c.Assert(label2, checker.Equals, "value2")
  476. cmd, err := inspectField(img.ID, "Config.Cmd")
  477. c.Assert(err, checker.IsNil)
  478. c.Assert(cmd, checker.Equals, "{[/bin/sh -c touch /test]}", check.Commentf("got wrong Cmd from commit: %q", cmd))
  479. // sanity check, make sure the image is what we think it is
  480. dockerCmd(c, "run", img.ID, "ls", "/test")
  481. }
  482. func (s *DockerSuite) TestContainerApiBadPort(c *check.C) {
  483. // TODO Windows to Windows CI - Port this test
  484. testRequires(c, DaemonIsLinux)
  485. config := map[string]interface{}{
  486. "Image": "busybox",
  487. "Cmd": []string{"/bin/sh", "-c", "echo test"},
  488. "PortBindings": map[string]interface{}{
  489. "8080/tcp": []map[string]interface{}{
  490. {
  491. "HostIP": "",
  492. "HostPort": "aa80",
  493. },
  494. },
  495. },
  496. }
  497. jsonData := bytes.NewBuffer(nil)
  498. json.NewEncoder(jsonData).Encode(config)
  499. status, b, err := sockRequest("POST", "/containers/create", config)
  500. c.Assert(err, checker.IsNil)
  501. c.Assert(status, checker.Equals, http.StatusInternalServerError)
  502. c.Assert(strings.TrimSpace(string(b)), checker.Equals, `Invalid port specification: "aa80"`, check.Commentf("Incorrect error msg: %s", string(b)))
  503. }
  504. func (s *DockerSuite) TestContainerApiCreate(c *check.C) {
  505. config := map[string]interface{}{
  506. "Image": "busybox",
  507. "Cmd": []string{"/bin/sh", "-c", "touch /test && ls /test"},
  508. }
  509. status, b, err := sockRequest("POST", "/containers/create", config)
  510. c.Assert(err, checker.IsNil)
  511. c.Assert(status, checker.Equals, http.StatusCreated)
  512. type createResp struct {
  513. ID string
  514. }
  515. var container createResp
  516. c.Assert(json.Unmarshal(b, &container), checker.IsNil)
  517. out, _ := dockerCmd(c, "start", "-a", container.ID)
  518. c.Assert(strings.TrimSpace(out), checker.Equals, "/test")
  519. }
  520. func (s *DockerSuite) TestContainerApiCreateEmptyConfig(c *check.C) {
  521. config := map[string]interface{}{}
  522. status, b, err := sockRequest("POST", "/containers/create", config)
  523. c.Assert(err, checker.IsNil)
  524. c.Assert(status, checker.Equals, http.StatusInternalServerError)
  525. expected := "Config cannot be empty in order to create a container\n"
  526. c.Assert(string(b), checker.Equals, expected)
  527. }
  528. func (s *DockerSuite) TestContainerApiCreateMultipleNetworksConfig(c *check.C) {
  529. // Container creation must fail if client specified configurations for more than one network
  530. config := map[string]interface{}{
  531. "Image": "busybox",
  532. "NetworkingConfig": networktypes.NetworkingConfig{
  533. EndpointsConfig: map[string]*networktypes.EndpointSettings{
  534. "net1": {},
  535. "net2": {},
  536. "net3": {},
  537. },
  538. },
  539. }
  540. status, b, err := sockRequest("POST", "/containers/create", config)
  541. c.Assert(err, checker.IsNil)
  542. c.Assert(status, checker.Equals, http.StatusBadRequest)
  543. // network name order in error message is not deterministic
  544. c.Assert(string(b), checker.Contains, "Container cannot be connected to [")
  545. c.Assert(string(b), checker.Contains, "net1")
  546. c.Assert(string(b), checker.Contains, "net2")
  547. c.Assert(string(b), checker.Contains, "net3")
  548. }
  549. func (s *DockerSuite) TestContainerApiCreateWithHostName(c *check.C) {
  550. // TODO Windows: Port this test once hostname is supported
  551. testRequires(c, DaemonIsLinux)
  552. hostName := "test-host"
  553. config := map[string]interface{}{
  554. "Image": "busybox",
  555. "Hostname": hostName,
  556. }
  557. status, body, err := sockRequest("POST", "/containers/create", config)
  558. c.Assert(err, checker.IsNil)
  559. c.Assert(status, checker.Equals, http.StatusCreated)
  560. var container types.ContainerCreateResponse
  561. c.Assert(json.Unmarshal(body, &container), checker.IsNil)
  562. status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil)
  563. c.Assert(err, checker.IsNil)
  564. c.Assert(status, checker.Equals, http.StatusOK)
  565. var containerJSON types.ContainerJSON
  566. c.Assert(json.Unmarshal(body, &containerJSON), checker.IsNil)
  567. c.Assert(containerJSON.Config.Hostname, checker.Equals, hostName, check.Commentf("Mismatched Hostname"))
  568. }
  569. func (s *DockerSuite) TestContainerApiCreateWithDomainName(c *check.C) {
  570. // TODO Windows: Port this test once domain name is supported
  571. testRequires(c, DaemonIsLinux)
  572. domainName := "test-domain"
  573. config := map[string]interface{}{
  574. "Image": "busybox",
  575. "Domainname": domainName,
  576. }
  577. status, body, err := sockRequest("POST", "/containers/create", config)
  578. c.Assert(err, checker.IsNil)
  579. c.Assert(status, checker.Equals, http.StatusCreated)
  580. var container types.ContainerCreateResponse
  581. c.Assert(json.Unmarshal(body, &container), checker.IsNil)
  582. status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil)
  583. c.Assert(err, checker.IsNil)
  584. c.Assert(status, checker.Equals, http.StatusOK)
  585. var containerJSON types.ContainerJSON
  586. c.Assert(json.Unmarshal(body, &containerJSON), checker.IsNil)
  587. c.Assert(containerJSON.Config.Domainname, checker.Equals, domainName, check.Commentf("Mismatched Domainname"))
  588. }
  589. func (s *DockerSuite) TestContainerApiCreateBridgeNetworkMode(c *check.C) {
  590. // Windows does not support bridge
  591. testRequires(c, DaemonIsLinux)
  592. UtilCreateNetworkMode(c, "bridge")
  593. }
  594. func (s *DockerSuite) TestContainerApiCreateOtherNetworkModes(c *check.C) {
  595. // Windows does not support these network modes
  596. testRequires(c, DaemonIsLinux, NotUserNamespace)
  597. UtilCreateNetworkMode(c, "host")
  598. UtilCreateNetworkMode(c, "container:web1")
  599. }
  600. func UtilCreateNetworkMode(c *check.C, networkMode string) {
  601. config := map[string]interface{}{
  602. "Image": "busybox",
  603. "HostConfig": map[string]interface{}{"NetworkMode": networkMode},
  604. }
  605. status, body, err := sockRequest("POST", "/containers/create", config)
  606. c.Assert(err, checker.IsNil)
  607. c.Assert(status, checker.Equals, http.StatusCreated)
  608. var container types.ContainerCreateResponse
  609. c.Assert(json.Unmarshal(body, &container), checker.IsNil)
  610. status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil)
  611. c.Assert(err, checker.IsNil)
  612. c.Assert(status, checker.Equals, http.StatusOK)
  613. var containerJSON types.ContainerJSON
  614. c.Assert(json.Unmarshal(body, &containerJSON), checker.IsNil)
  615. c.Assert(containerJSON.HostConfig.NetworkMode, checker.Equals, containertypes.NetworkMode(networkMode), check.Commentf("Mismatched NetworkMode"))
  616. }
  617. func (s *DockerSuite) TestContainerApiCreateWithCpuSharesCpuset(c *check.C) {
  618. // TODO Windows to Windows CI. The CpuShares part could be ported.
  619. testRequires(c, DaemonIsLinux)
  620. config := map[string]interface{}{
  621. "Image": "busybox",
  622. "CpuShares": 512,
  623. "CpusetCpus": "0",
  624. }
  625. status, body, err := sockRequest("POST", "/containers/create", config)
  626. c.Assert(err, checker.IsNil)
  627. c.Assert(status, checker.Equals, http.StatusCreated)
  628. var container types.ContainerCreateResponse
  629. c.Assert(json.Unmarshal(body, &container), checker.IsNil)
  630. status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil)
  631. c.Assert(err, checker.IsNil)
  632. c.Assert(status, checker.Equals, http.StatusOK)
  633. var containerJSON types.ContainerJSON
  634. c.Assert(json.Unmarshal(body, &containerJSON), checker.IsNil)
  635. out, err := inspectField(containerJSON.ID, "HostConfig.CpuShares")
  636. c.Assert(err, checker.IsNil)
  637. c.Assert(out, checker.Equals, "512")
  638. outCpuset, errCpuset := inspectField(containerJSON.ID, "HostConfig.CpusetCpus")
  639. c.Assert(errCpuset, checker.IsNil, check.Commentf("Output: %s", outCpuset))
  640. c.Assert(outCpuset, checker.Equals, "0")
  641. }
  642. func (s *DockerSuite) TestContainerApiVerifyHeader(c *check.C) {
  643. config := map[string]interface{}{
  644. "Image": "busybox",
  645. }
  646. create := func(ct string) (*http.Response, io.ReadCloser, error) {
  647. jsonData := bytes.NewBuffer(nil)
  648. c.Assert(json.NewEncoder(jsonData).Encode(config), checker.IsNil)
  649. return sockRequestRaw("POST", "/containers/create", jsonData, ct)
  650. }
  651. // Try with no content-type
  652. res, body, err := create("")
  653. c.Assert(err, checker.IsNil)
  654. c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
  655. body.Close()
  656. // Try with wrong content-type
  657. res, body, err = create("application/xml")
  658. c.Assert(err, checker.IsNil)
  659. c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
  660. body.Close()
  661. // now application/json
  662. res, body, err = create("application/json")
  663. c.Assert(err, checker.IsNil)
  664. c.Assert(res.StatusCode, checker.Equals, http.StatusCreated)
  665. body.Close()
  666. }
  667. //Issue 14230. daemon should return 500 for invalid port syntax
  668. func (s *DockerSuite) TestContainerApiInvalidPortSyntax(c *check.C) {
  669. config := `{
  670. "Image": "busybox",
  671. "HostConfig": {
  672. "NetworkMode": "default",
  673. "PortBindings": {
  674. "19039;1230": [
  675. {}
  676. ]
  677. }
  678. }
  679. }`
  680. res, body, err := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json")
  681. c.Assert(err, checker.IsNil)
  682. c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
  683. b, err := readBody(body)
  684. c.Assert(err, checker.IsNil)
  685. c.Assert(string(b[:]), checker.Contains, "Invalid port")
  686. }
  687. // Issue 7941 - test to make sure a "null" in JSON is just ignored.
  688. // W/o this fix a null in JSON would be parsed into a string var as "null"
  689. func (s *DockerSuite) TestContainerApiPostCreateNull(c *check.C) {
  690. // TODO Windows to Windows CI. Bit of this with alternate fields checked
  691. // can probably be ported.
  692. testRequires(c, DaemonIsLinux)
  693. config := `{
  694. "Hostname":"",
  695. "Domainname":"",
  696. "Memory":0,
  697. "MemorySwap":0,
  698. "CpuShares":0,
  699. "Cpuset":null,
  700. "AttachStdin":true,
  701. "AttachStdout":true,
  702. "AttachStderr":true,
  703. "ExposedPorts":{},
  704. "Tty":true,
  705. "OpenStdin":true,
  706. "StdinOnce":true,
  707. "Env":[],
  708. "Cmd":"ls",
  709. "Image":"busybox",
  710. "Volumes":{},
  711. "WorkingDir":"",
  712. "Entrypoint":null,
  713. "NetworkDisabled":false,
  714. "OnBuild":null}`
  715. res, body, err := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json")
  716. c.Assert(err, checker.IsNil)
  717. c.Assert(res.StatusCode, checker.Equals, http.StatusCreated)
  718. b, err := readBody(body)
  719. c.Assert(err, checker.IsNil)
  720. type createResp struct {
  721. ID string
  722. }
  723. var container createResp
  724. c.Assert(json.Unmarshal(b, &container), checker.IsNil)
  725. out, err := inspectField(container.ID, "HostConfig.CpusetCpus")
  726. c.Assert(err, checker.IsNil)
  727. c.Assert(out, checker.Equals, "")
  728. outMemory, errMemory := inspectField(container.ID, "HostConfig.Memory")
  729. c.Assert(outMemory, checker.Equals, "0")
  730. c.Assert(errMemory, checker.IsNil)
  731. outMemorySwap, errMemorySwap := inspectField(container.ID, "HostConfig.MemorySwap")
  732. c.Assert(outMemorySwap, checker.Equals, "0")
  733. c.Assert(errMemorySwap, checker.IsNil)
  734. }
  735. func (s *DockerSuite) TestCreateWithTooLowMemoryLimit(c *check.C) {
  736. // TODO Windows: Port once memory is supported
  737. testRequires(c, DaemonIsLinux)
  738. config := `{
  739. "Image": "busybox",
  740. "Cmd": "ls",
  741. "OpenStdin": true,
  742. "CpuShares": 100,
  743. "Memory": 524287
  744. }`
  745. res, body, err := sockRequestRaw("POST", "/containers/create", strings.NewReader(config), "application/json")
  746. c.Assert(err, checker.IsNil)
  747. b, err2 := readBody(body)
  748. c.Assert(err2, checker.IsNil)
  749. c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
  750. c.Assert(string(b), checker.Contains, "Minimum memory limit allowed is 4MB")
  751. }
  752. func (s *DockerSuite) TestStartWithTooLowMemoryLimit(c *check.C) {
  753. // TODO Windows: Port once memory is supported
  754. testRequires(c, DaemonIsLinux)
  755. out, _ := dockerCmd(c, "create", "busybox")
  756. containerID := strings.TrimSpace(out)
  757. config := `{
  758. "CpuShares": 100,
  759. "Memory": 524287
  760. }`
  761. res, body, err := sockRequestRaw("POST", "/containers/"+containerID+"/start", strings.NewReader(config), "application/json")
  762. c.Assert(err, checker.IsNil)
  763. b, err2 := readBody(body)
  764. c.Assert(err2, checker.IsNil)
  765. c.Assert(res.StatusCode, checker.Equals, http.StatusInternalServerError)
  766. c.Assert(string(b), checker.Contains, "Minimum memory limit allowed is 4MB")
  767. }
  768. func (s *DockerSuite) TestContainerApiRename(c *check.C) {
  769. // TODO Windows: Enable for TP5. Fails on TP4.
  770. testRequires(c, DaemonIsLinux)
  771. out, _ := dockerCmd(c, "run", "--name", "TestContainerApiRename", "-d", "busybox", "sh")
  772. containerID := strings.TrimSpace(out)
  773. newName := "TestContainerApiRenameNew"
  774. statusCode, _, err := sockRequest("POST", "/containers/"+containerID+"/rename?name="+newName, nil)
  775. c.Assert(err, checker.IsNil)
  776. // 204 No Content is expected, not 200
  777. c.Assert(statusCode, checker.Equals, http.StatusNoContent)
  778. name, err := inspectField(containerID, "Name")
  779. c.Assert(name, checker.Equals, "/"+newName, check.Commentf("Failed to rename container"))
  780. }
  781. func (s *DockerSuite) TestContainerApiKill(c *check.C) {
  782. name := "test-api-kill"
  783. dockerCmd(c, "run", "-di", "--name", name, "busybox", sleepCmd, "60")
  784. status, _, err := sockRequest("POST", "/containers/"+name+"/kill", nil)
  785. c.Assert(err, checker.IsNil)
  786. c.Assert(status, checker.Equals, http.StatusNoContent)
  787. state, err := inspectField(name, "State.Running")
  788. c.Assert(err, checker.IsNil)
  789. c.Assert(state, checker.Equals, "false", check.Commentf("got wrong State from container %s: %q", name, state))
  790. }
  791. func (s *DockerSuite) TestContainerApiRestart(c *check.C) {
  792. // TODO Windows to Windows CI. This is flaky due to the timing
  793. testRequires(c, DaemonIsLinux)
  794. name := "test-api-restart"
  795. dockerCmd(c, "run", "-di", "--name", name, "busybox", "top")
  796. status, _, err := sockRequest("POST", "/containers/"+name+"/restart?t=1", nil)
  797. c.Assert(err, checker.IsNil)
  798. c.Assert(status, checker.Equals, http.StatusNoContent)
  799. c.Assert(waitInspect(name, "{{ .State.Restarting }} {{ .State.Running }}", "false true", 5*time.Second), checker.IsNil)
  800. }
  801. func (s *DockerSuite) TestContainerApiRestartNotimeoutParam(c *check.C) {
  802. // TODO Windows to Windows CI. This is flaky due to the timing
  803. testRequires(c, DaemonIsLinux)
  804. name := "test-api-restart-no-timeout-param"
  805. out, _ := dockerCmd(c, "run", "-di", "--name", name, "busybox", "top")
  806. id := strings.TrimSpace(out)
  807. c.Assert(waitRun(id), checker.IsNil)
  808. status, _, err := sockRequest("POST", "/containers/"+name+"/restart", nil)
  809. c.Assert(err, checker.IsNil)
  810. c.Assert(status, checker.Equals, http.StatusNoContent)
  811. c.Assert(waitInspect(name, "{{ .State.Restarting }} {{ .State.Running }}", "false true", 5*time.Second), checker.IsNil)
  812. }
  813. func (s *DockerSuite) TestContainerApiStart(c *check.C) {
  814. name := "testing-start"
  815. config := map[string]interface{}{
  816. "Image": "busybox",
  817. "Cmd": []string{"/bin/sh", "-c", sleepCmd, "60"},
  818. "OpenStdin": true,
  819. }
  820. status, _, err := sockRequest("POST", "/containers/create?name="+name, config)
  821. c.Assert(err, checker.IsNil)
  822. c.Assert(status, checker.Equals, http.StatusCreated)
  823. conf := make(map[string]interface{})
  824. status, _, err = sockRequest("POST", "/containers/"+name+"/start", conf)
  825. c.Assert(err, checker.IsNil)
  826. c.Assert(status, checker.Equals, http.StatusNoContent)
  827. // second call to start should give 304
  828. status, _, err = sockRequest("POST", "/containers/"+name+"/start", conf)
  829. c.Assert(err, checker.IsNil)
  830. c.Assert(status, checker.Equals, http.StatusNotModified)
  831. }
  832. func (s *DockerSuite) TestContainerApiStop(c *check.C) {
  833. name := "test-api-stop"
  834. dockerCmd(c, "run", "-di", "--name", name, "busybox", sleepCmd, "60")
  835. status, _, err := sockRequest("POST", "/containers/"+name+"/stop?t=30", nil)
  836. c.Assert(err, checker.IsNil)
  837. c.Assert(status, checker.Equals, http.StatusNoContent)
  838. c.Assert(waitInspect(name, "{{ .State.Running }}", "false", 60*time.Second), checker.IsNil)
  839. // second call to start should give 304
  840. status, _, err = sockRequest("POST", "/containers/"+name+"/stop?t=30", nil)
  841. c.Assert(err, checker.IsNil)
  842. c.Assert(status, checker.Equals, http.StatusNotModified)
  843. }
  844. func (s *DockerSuite) TestContainerApiWait(c *check.C) {
  845. name := "test-api-wait"
  846. dockerCmd(c, "run", "--name", name, "busybox", sleepCmd, "5")
  847. status, body, err := sockRequest("POST", "/containers/"+name+"/wait", nil)
  848. c.Assert(err, checker.IsNil)
  849. c.Assert(status, checker.Equals, http.StatusOK)
  850. c.Assert(waitInspect(name, "{{ .State.Running }}", "false", 60*time.Second), checker.IsNil)
  851. var waitres types.ContainerWaitResponse
  852. c.Assert(json.Unmarshal(body, &waitres), checker.IsNil)
  853. c.Assert(waitres.StatusCode, checker.Equals, 0)
  854. }
  855. func (s *DockerSuite) TestContainerApiCopy(c *check.C) {
  856. // TODO Windows to Windows CI. This can be ported.
  857. testRequires(c, DaemonIsLinux)
  858. name := "test-container-api-copy"
  859. dockerCmd(c, "run", "--name", name, "busybox", "touch", "/test.txt")
  860. postData := types.CopyConfig{
  861. Resource: "/test.txt",
  862. }
  863. status, body, err := sockRequest("POST", "/containers/"+name+"/copy", postData)
  864. c.Assert(err, checker.IsNil)
  865. c.Assert(status, checker.Equals, http.StatusOK)
  866. found := false
  867. for tarReader := tar.NewReader(bytes.NewReader(body)); ; {
  868. h, err := tarReader.Next()
  869. if err != nil {
  870. if err == io.EOF {
  871. break
  872. }
  873. c.Fatal(err)
  874. }
  875. if h.Name == "test.txt" {
  876. found = true
  877. break
  878. }
  879. }
  880. c.Assert(found, checker.True)
  881. }
  882. func (s *DockerSuite) TestContainerApiCopyResourcePathEmpty(c *check.C) {
  883. // TODO Windows to Windows CI. This can be ported.
  884. testRequires(c, DaemonIsLinux)
  885. name := "test-container-api-copy-resource-empty"
  886. dockerCmd(c, "run", "--name", name, "busybox", "touch", "/test.txt")
  887. postData := types.CopyConfig{
  888. Resource: "",
  889. }
  890. status, body, err := sockRequest("POST", "/containers/"+name+"/copy", postData)
  891. c.Assert(err, checker.IsNil)
  892. c.Assert(status, checker.Equals, http.StatusInternalServerError)
  893. c.Assert(string(body), checker.Matches, "Path cannot be empty\n")
  894. }
  895. func (s *DockerSuite) TestContainerApiCopyResourcePathNotFound(c *check.C) {
  896. // TODO Windows to Windows CI. This can be ported.
  897. testRequires(c, DaemonIsLinux)
  898. name := "test-container-api-copy-resource-not-found"
  899. dockerCmd(c, "run", "--name", name, "busybox")
  900. postData := types.CopyConfig{
  901. Resource: "/notexist",
  902. }
  903. status, body, err := sockRequest("POST", "/containers/"+name+"/copy", postData)
  904. c.Assert(err, checker.IsNil)
  905. c.Assert(status, checker.Equals, http.StatusInternalServerError)
  906. c.Assert(string(body), checker.Matches, "Could not find the file /notexist in container "+name+"\n")
  907. }
  908. func (s *DockerSuite) TestContainerApiCopyContainerNotFound(c *check.C) {
  909. postData := types.CopyConfig{
  910. Resource: "/something",
  911. }
  912. status, _, err := sockRequest("POST", "/containers/notexists/copy", postData)
  913. c.Assert(err, checker.IsNil)
  914. c.Assert(status, checker.Equals, http.StatusNotFound)
  915. }
  916. func (s *DockerSuite) TestContainerApiDelete(c *check.C) {
  917. out, _ := dockerCmd(c, "run", "-d", "busybox", sleepCmd, "60")
  918. id := strings.TrimSpace(out)
  919. c.Assert(waitRun(id), checker.IsNil)
  920. dockerCmd(c, "stop", id)
  921. status, _, err := sockRequest("DELETE", "/containers/"+id, nil)
  922. c.Assert(err, checker.IsNil)
  923. c.Assert(status, checker.Equals, http.StatusNoContent)
  924. }
  925. func (s *DockerSuite) TestContainerApiDeleteNotExist(c *check.C) {
  926. status, body, err := sockRequest("DELETE", "/containers/doesnotexist", nil)
  927. c.Assert(err, checker.IsNil)
  928. c.Assert(status, checker.Equals, http.StatusNotFound)
  929. c.Assert(string(body), checker.Matches, "No such container: doesnotexist\n")
  930. }
  931. func (s *DockerSuite) TestContainerApiDeleteForce(c *check.C) {
  932. out, _ := dockerCmd(c, "run", "-d", "busybox", sleepCmd, "60")
  933. id := strings.TrimSpace(out)
  934. c.Assert(waitRun(id), checker.IsNil)
  935. status, _, err := sockRequest("DELETE", "/containers/"+id+"?force=1", nil)
  936. c.Assert(err, checker.IsNil)
  937. c.Assert(status, checker.Equals, http.StatusNoContent)
  938. }
  939. func (s *DockerSuite) TestContainerApiDeleteRemoveLinks(c *check.C) {
  940. // Windows does not support links
  941. testRequires(c, DaemonIsLinux)
  942. out, _ := dockerCmd(c, "run", "-d", "--name", "tlink1", "busybox", "top")
  943. id := strings.TrimSpace(out)
  944. c.Assert(waitRun(id), checker.IsNil)
  945. out, _ = dockerCmd(c, "run", "--link", "tlink1:tlink1", "--name", "tlink2", "-d", "busybox", "top")
  946. id2 := strings.TrimSpace(out)
  947. c.Assert(waitRun(id2), checker.IsNil)
  948. links, err := inspectFieldJSON(id2, "HostConfig.Links")
  949. c.Assert(err, checker.IsNil)
  950. c.Assert(links, checker.Equals, "[\"/tlink1:/tlink2/tlink1\"]", check.Commentf("expected to have links between containers"))
  951. status, b, err := sockRequest("DELETE", "/containers/tlink2/tlink1?link=1", nil)
  952. c.Assert(err, check.IsNil)
  953. c.Assert(status, check.Equals, http.StatusNoContent, check.Commentf(string(b)))
  954. linksPostRm, err := inspectFieldJSON(id2, "HostConfig.Links")
  955. c.Assert(err, checker.IsNil)
  956. c.Assert(linksPostRm, checker.Equals, "null", check.Commentf("call to api deleteContainer links should have removed the specified links"))
  957. }
  958. func (s *DockerSuite) TestContainerApiDeleteConflict(c *check.C) {
  959. out, _ := dockerCmd(c, "run", "-d", "busybox", sleepCmd, "60")
  960. id := strings.TrimSpace(out)
  961. c.Assert(waitRun(id), checker.IsNil)
  962. status, _, err := sockRequest("DELETE", "/containers/"+id, nil)
  963. c.Assert(err, checker.IsNil)
  964. c.Assert(status, checker.Equals, http.StatusConflict)
  965. }
  966. func (s *DockerSuite) TestContainerApiDeleteRemoveVolume(c *check.C) {
  967. testRequires(c, SameHostDaemon)
  968. vol := "/testvolume"
  969. if daemonPlatform == "windows" {
  970. vol = `c:\testvolume`
  971. }
  972. out, _ := dockerCmd(c, "run", "-d", "-v", vol, "busybox", sleepCmd, "60")
  973. id := strings.TrimSpace(out)
  974. c.Assert(waitRun(id), checker.IsNil)
  975. source, err := inspectMountSourceField(id, vol)
  976. _, err = os.Stat(source)
  977. c.Assert(err, checker.IsNil)
  978. status, _, err := sockRequest("DELETE", "/containers/"+id+"?v=1&force=1", nil)
  979. c.Assert(err, checker.IsNil)
  980. c.Assert(status, checker.Equals, http.StatusNoContent)
  981. _, err = os.Stat(source)
  982. c.Assert(os.IsNotExist(err), checker.True, check.Commentf("expected to get ErrNotExist error, got %v", err))
  983. }
  984. // Regression test for https://github.com/docker/docker/issues/6231
  985. func (s *DockerSuite) TestContainerApiChunkedEncoding(c *check.C) {
  986. // TODO Windows CI: This can be ported
  987. testRequires(c, DaemonIsLinux)
  988. out, _ := dockerCmd(c, "create", "-v", "/foo", "busybox", "true")
  989. id := strings.TrimSpace(out)
  990. conn, err := sockConn(time.Duration(10 * time.Second))
  991. c.Assert(err, checker.IsNil)
  992. client := httputil.NewClientConn(conn, nil)
  993. defer client.Close()
  994. bindCfg := strings.NewReader(`{"Binds": ["/tmp:/foo"]}`)
  995. req, err := http.NewRequest("POST", "/containers/"+id+"/start", bindCfg)
  996. c.Assert(err, checker.IsNil)
  997. req.Header.Set("Content-Type", "application/json")
  998. // This is a cheat to make the http request do chunked encoding
  999. // Otherwise (just setting the Content-Encoding to chunked) net/http will overwrite
  1000. // https://golang.org/src/pkg/net/http/request.go?s=11980:12172
  1001. req.ContentLength = -1
  1002. resp, err := client.Do(req)
  1003. c.Assert(err, checker.IsNil, check.Commentf("error starting container with chunked encoding"))
  1004. resp.Body.Close()
  1005. c.Assert(resp.StatusCode, checker.Equals, 204)
  1006. out, err = inspectFieldJSON(id, "HostConfig.Binds")
  1007. c.Assert(err, checker.IsNil)
  1008. var binds []string
  1009. c.Assert(json.NewDecoder(strings.NewReader(out)).Decode(&binds), checker.IsNil)
  1010. c.Assert(binds, checker.HasLen, 1, check.Commentf("Got unexpected binds: %v", binds))
  1011. expected := "/tmp:/foo"
  1012. c.Assert(binds[0], checker.Equals, expected, check.Commentf("got incorrect bind spec"))
  1013. }
  1014. func (s *DockerSuite) TestContainerApiPostContainerStop(c *check.C) {
  1015. out, _ := dockerCmd(c, "run", "-d", "busybox", sleepCmd, "60")
  1016. containerID := strings.TrimSpace(out)
  1017. c.Assert(waitRun(containerID), checker.IsNil)
  1018. statusCode, _, err := sockRequest("POST", "/containers/"+containerID+"/stop", nil)
  1019. c.Assert(err, checker.IsNil)
  1020. // 204 No Content is expected, not 200
  1021. c.Assert(statusCode, checker.Equals, http.StatusNoContent)
  1022. c.Assert(waitInspect(containerID, "{{ .State.Running }}", "false", 5*time.Second), checker.IsNil)
  1023. }
  1024. // #14170
  1025. func (s *DockerSuite) TestPostContainerApiCreateWithStringOrSliceEntrypoint(c *check.C) {
  1026. config := struct {
  1027. Image string
  1028. Entrypoint string
  1029. Cmd []string
  1030. }{"busybox", "echo", []string{"hello", "world"}}
  1031. _, _, err := sockRequest("POST", "/containers/create?name=echotest", config)
  1032. c.Assert(err, checker.IsNil)
  1033. out, _ := dockerCmd(c, "start", "-a", "echotest")
  1034. c.Assert(strings.TrimSpace(out), checker.Equals, "hello world")
  1035. config2 := struct {
  1036. Image string
  1037. Entrypoint []string
  1038. Cmd []string
  1039. }{"busybox", []string{"echo"}, []string{"hello", "world"}}
  1040. _, _, err = sockRequest("POST", "/containers/create?name=echotest2", config2)
  1041. c.Assert(err, checker.IsNil)
  1042. out, _ = dockerCmd(c, "start", "-a", "echotest2")
  1043. c.Assert(strings.TrimSpace(out), checker.Equals, "hello world")
  1044. }
  1045. // #14170
  1046. func (s *DockerSuite) TestPostContainersCreateWithStringOrSliceCmd(c *check.C) {
  1047. config := struct {
  1048. Image string
  1049. Entrypoint string
  1050. Cmd string
  1051. }{"busybox", "echo", "hello world"}
  1052. _, _, err := sockRequest("POST", "/containers/create?name=echotest", config)
  1053. c.Assert(err, checker.IsNil)
  1054. out, _ := dockerCmd(c, "start", "-a", "echotest")
  1055. c.Assert(strings.TrimSpace(out), checker.Equals, "hello world")
  1056. config2 := struct {
  1057. Image string
  1058. Cmd []string
  1059. }{"busybox", []string{"echo", "hello", "world"}}
  1060. _, _, err = sockRequest("POST", "/containers/create?name=echotest2", config2)
  1061. c.Assert(err, checker.IsNil)
  1062. out, _ = dockerCmd(c, "start", "-a", "echotest2")
  1063. c.Assert(strings.TrimSpace(out), checker.Equals, "hello world")
  1064. }
  1065. // regression #14318
  1066. func (s *DockerSuite) TestPostContainersCreateWithStringOrSliceCapAddDrop(c *check.C) {
  1067. // Windows doesn't support CapAdd/CapDrop
  1068. testRequires(c, DaemonIsLinux)
  1069. config := struct {
  1070. Image string
  1071. CapAdd string
  1072. CapDrop string
  1073. }{"busybox", "NET_ADMIN", "SYS_ADMIN"}
  1074. status, _, err := sockRequest("POST", "/containers/create?name=capaddtest0", config)
  1075. c.Assert(err, checker.IsNil)
  1076. c.Assert(status, checker.Equals, http.StatusCreated)
  1077. config2 := struct {
  1078. Image string
  1079. CapAdd []string
  1080. CapDrop []string
  1081. }{"busybox", []string{"NET_ADMIN", "SYS_ADMIN"}, []string{"SETGID"}}
  1082. status, _, err = sockRequest("POST", "/containers/create?name=capaddtest1", config2)
  1083. c.Assert(err, checker.IsNil)
  1084. c.Assert(status, checker.Equals, http.StatusCreated)
  1085. }
  1086. // #14640
  1087. func (s *DockerSuite) TestPostContainersStartWithoutLinksInHostConfig(c *check.C) {
  1088. // TODO Windows: Windows doesn't support supplying a hostconfig on start.
  1089. // An alternate test could be written to validate the negative testing aspect of this
  1090. testRequires(c, DaemonIsLinux)
  1091. name := "test-host-config-links"
  1092. dockerCmd(c, "create", "--name", name, "busybox", sleepCmd, "60")
  1093. hc, err := inspectFieldJSON(name, "HostConfig")
  1094. c.Assert(err, checker.IsNil)
  1095. config := `{"HostConfig":` + hc + `}`
  1096. res, b, err := sockRequestRaw("POST", "/containers/"+name+"/start", strings.NewReader(config), "application/json")
  1097. c.Assert(err, checker.IsNil)
  1098. c.Assert(res.StatusCode, checker.Equals, http.StatusNoContent)
  1099. b.Close()
  1100. }
  1101. // #14640
  1102. func (s *DockerSuite) TestPostContainersStartWithLinksInHostConfig(c *check.C) {
  1103. // TODO Windows: Windows doesn't support supplying a hostconfig on start.
  1104. // An alternate test could be written to validate the negative testing aspect of this
  1105. testRequires(c, DaemonIsLinux)
  1106. name := "test-host-config-links"
  1107. dockerCmd(c, "run", "--name", "foo", "-d", "busybox", "top")
  1108. dockerCmd(c, "create", "--name", name, "--link", "foo:bar", "busybox", "top")
  1109. hc, err := inspectFieldJSON(name, "HostConfig")
  1110. c.Assert(err, checker.IsNil)
  1111. config := `{"HostConfig":` + hc + `}`
  1112. res, b, err := sockRequestRaw("POST", "/containers/"+name+"/start", strings.NewReader(config), "application/json")
  1113. c.Assert(err, checker.IsNil)
  1114. c.Assert(res.StatusCode, checker.Equals, http.StatusNoContent)
  1115. b.Close()
  1116. }
  1117. // #14640
  1118. func (s *DockerSuite) TestPostContainersStartWithLinksInHostConfigIdLinked(c *check.C) {
  1119. // Windows does not support links
  1120. testRequires(c, DaemonIsLinux)
  1121. name := "test-host-config-links"
  1122. out, _ := dockerCmd(c, "run", "--name", "link0", "-d", "busybox", "top")
  1123. id := strings.TrimSpace(out)
  1124. dockerCmd(c, "create", "--name", name, "--link", id, "busybox", "top")
  1125. hc, err := inspectFieldJSON(name, "HostConfig")
  1126. c.Assert(err, checker.IsNil)
  1127. config := `{"HostConfig":` + hc + `}`
  1128. res, b, err := sockRequestRaw("POST", "/containers/"+name+"/start", strings.NewReader(config), "application/json")
  1129. c.Assert(err, checker.IsNil)
  1130. c.Assert(res.StatusCode, checker.Equals, http.StatusNoContent)
  1131. b.Close()
  1132. }
  1133. // #14915
  1134. func (s *DockerSuite) TestContainerApiCreateNoHostConfig118(c *check.C) {
  1135. config := struct {
  1136. Image string
  1137. }{"busybox"}
  1138. status, _, err := sockRequest("POST", "/v1.18/containers/create", config)
  1139. c.Assert(err, checker.IsNil)
  1140. c.Assert(status, checker.Equals, http.StatusCreated)
  1141. }
  1142. // Ensure an error occurs when you have a container read-only rootfs but you
  1143. // extract an archive to a symlink in a writable volume which points to a
  1144. // directory outside of the volume.
  1145. func (s *DockerSuite) TestPutContainerArchiveErrSymlinkInVolumeToReadOnlyRootfs(c *check.C) {
  1146. // Windows does not support read-only rootfs
  1147. // Requires local volume mount bind.
  1148. // --read-only + userns has remount issues
  1149. testRequires(c, SameHostDaemon, NotUserNamespace, DaemonIsLinux)
  1150. testVol := getTestDir(c, "test-put-container-archive-err-symlink-in-volume-to-read-only-rootfs-")
  1151. defer os.RemoveAll(testVol)
  1152. makeTestContentInDir(c, testVol)
  1153. cID := makeTestContainer(c, testContainerOptions{
  1154. readOnly: true,
  1155. volumes: defaultVolumes(testVol), // Our bind mount is at /vol2
  1156. })
  1157. defer deleteContainer(cID)
  1158. // Attempt to extract to a symlink in the volume which points to a
  1159. // directory outside the volume. This should cause an error because the
  1160. // rootfs is read-only.
  1161. query := make(url.Values, 1)
  1162. query.Set("path", "/vol2/symlinkToAbsDir")
  1163. urlPath := fmt.Sprintf("/v1.20/containers/%s/archive?%s", cID, query.Encode())
  1164. statusCode, body, err := sockRequest("PUT", urlPath, nil)
  1165. c.Assert(err, checker.IsNil)
  1166. if !isCpCannotCopyReadOnly(fmt.Errorf(string(body))) {
  1167. c.Fatalf("expected ErrContainerRootfsReadonly error, but got %d: %s", statusCode, string(body))
  1168. }
  1169. }
  1170. func (s *DockerSuite) TestContainerApiGetContainersJSONEmpty(c *check.C) {
  1171. status, body, err := sockRequest("GET", "/containers/json?all=1", nil)
  1172. c.Assert(err, checker.IsNil)
  1173. c.Assert(status, checker.Equals, http.StatusOK)
  1174. c.Assert(string(body), checker.Equals, "[]\n")
  1175. }
  1176. func (s *DockerSuite) TestPostContainersCreateWithWrongCpusetValues(c *check.C) {
  1177. // Not supported on Windows
  1178. testRequires(c, DaemonIsLinux)
  1179. c1 := struct {
  1180. Image string
  1181. CpusetCpus string
  1182. }{"busybox", "1-42,,"}
  1183. name := "wrong-cpuset-cpus"
  1184. status, body, err := sockRequest("POST", "/containers/create?name="+name, c1)
  1185. c.Assert(err, checker.IsNil)
  1186. c.Assert(status, checker.Equals, http.StatusInternalServerError)
  1187. expected := "Invalid value 1-42,, for cpuset cpus.\n"
  1188. c.Assert(string(body), checker.Equals, expected)
  1189. c2 := struct {
  1190. Image string
  1191. CpusetMems string
  1192. }{"busybox", "42-3,1--"}
  1193. name = "wrong-cpuset-mems"
  1194. status, body, err = sockRequest("POST", "/containers/create?name="+name, c2)
  1195. c.Assert(err, checker.IsNil)
  1196. c.Assert(status, checker.Equals, http.StatusInternalServerError)
  1197. expected = "Invalid value 42-3,1-- for cpuset mems.\n"
  1198. c.Assert(string(body), checker.Equals, expected)
  1199. }
  1200. func (s *DockerSuite) TestStartWithNilDNS(c *check.C) {
  1201. // TODO Windows: Add once DNS is supported
  1202. testRequires(c, DaemonIsLinux)
  1203. out, _ := dockerCmd(c, "create", "busybox")
  1204. containerID := strings.TrimSpace(out)
  1205. config := `{"HostConfig": {"Dns": null}}`
  1206. res, b, err := sockRequestRaw("POST", "/containers/"+containerID+"/start", strings.NewReader(config), "application/json")
  1207. c.Assert(err, checker.IsNil)
  1208. c.Assert(res.StatusCode, checker.Equals, http.StatusNoContent)
  1209. b.Close()
  1210. dns, err := inspectFieldJSON(containerID, "HostConfig.Dns")
  1211. c.Assert(err, checker.IsNil)
  1212. c.Assert(dns, checker.Equals, "[]")
  1213. }
  1214. func (s *DockerSuite) TestPostContainersCreateShmSizeNegative(c *check.C) {
  1215. // ShmSize is not supported on Windows
  1216. testRequires(c, DaemonIsLinux)
  1217. config := map[string]interface{}{
  1218. "Image": "busybox",
  1219. "HostConfig": map[string]interface{}{"ShmSize": -1},
  1220. }
  1221. status, body, err := sockRequest("POST", "/containers/create", config)
  1222. c.Assert(err, check.IsNil)
  1223. c.Assert(status, check.Equals, http.StatusInternalServerError)
  1224. c.Assert(string(body), checker.Contains, "SHM size must be greater then 0")
  1225. }
  1226. func (s *DockerSuite) TestPostContainersCreateShmSizeHostConfigOmitted(c *check.C) {
  1227. // ShmSize is not supported on Windows
  1228. testRequires(c, DaemonIsLinux)
  1229. var defaultSHMSize int64 = 67108864
  1230. config := map[string]interface{}{
  1231. "Image": "busybox",
  1232. "Cmd": "mount",
  1233. }
  1234. status, body, err := sockRequest("POST", "/containers/create", config)
  1235. c.Assert(err, check.IsNil)
  1236. c.Assert(status, check.Equals, http.StatusCreated)
  1237. var container types.ContainerCreateResponse
  1238. c.Assert(json.Unmarshal(body, &container), check.IsNil)
  1239. status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil)
  1240. c.Assert(err, check.IsNil)
  1241. c.Assert(status, check.Equals, http.StatusOK)
  1242. var containerJSON types.ContainerJSON
  1243. c.Assert(json.Unmarshal(body, &containerJSON), check.IsNil)
  1244. c.Assert(containerJSON.HostConfig.ShmSize, check.Equals, defaultSHMSize)
  1245. out, _ := dockerCmd(c, "start", "-i", containerJSON.ID)
  1246. shmRegexp := regexp.MustCompile(`shm on /dev/shm type tmpfs(.*)size=65536k`)
  1247. if !shmRegexp.MatchString(out) {
  1248. c.Fatalf("Expected shm of 64MB in mount command, got %v", out)
  1249. }
  1250. }
  1251. func (s *DockerSuite) TestPostContainersCreateShmSizeOmitted(c *check.C) {
  1252. // ShmSize is not supported on Windows
  1253. testRequires(c, DaemonIsLinux)
  1254. config := map[string]interface{}{
  1255. "Image": "busybox",
  1256. "HostConfig": map[string]interface{}{},
  1257. "Cmd": "mount",
  1258. }
  1259. status, body, err := sockRequest("POST", "/containers/create", config)
  1260. c.Assert(err, check.IsNil)
  1261. c.Assert(status, check.Equals, http.StatusCreated)
  1262. var container types.ContainerCreateResponse
  1263. c.Assert(json.Unmarshal(body, &container), check.IsNil)
  1264. status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil)
  1265. c.Assert(err, check.IsNil)
  1266. c.Assert(status, check.Equals, http.StatusOK)
  1267. var containerJSON types.ContainerJSON
  1268. c.Assert(json.Unmarshal(body, &containerJSON), check.IsNil)
  1269. c.Assert(containerJSON.HostConfig.ShmSize, check.Equals, int64(67108864))
  1270. out, _ := dockerCmd(c, "start", "-i", containerJSON.ID)
  1271. shmRegexp := regexp.MustCompile(`shm on /dev/shm type tmpfs(.*)size=65536k`)
  1272. if !shmRegexp.MatchString(out) {
  1273. c.Fatalf("Expected shm of 64MB in mount command, got %v", out)
  1274. }
  1275. }
  1276. func (s *DockerSuite) TestPostContainersCreateWithShmSize(c *check.C) {
  1277. // ShmSize is not supported on Windows
  1278. testRequires(c, DaemonIsLinux)
  1279. config := map[string]interface{}{
  1280. "Image": "busybox",
  1281. "Cmd": "mount",
  1282. "HostConfig": map[string]interface{}{"ShmSize": 1073741824},
  1283. }
  1284. status, body, err := sockRequest("POST", "/containers/create", config)
  1285. c.Assert(err, check.IsNil)
  1286. c.Assert(status, check.Equals, http.StatusCreated)
  1287. var container types.ContainerCreateResponse
  1288. c.Assert(json.Unmarshal(body, &container), check.IsNil)
  1289. status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil)
  1290. c.Assert(err, check.IsNil)
  1291. c.Assert(status, check.Equals, http.StatusOK)
  1292. var containerJSON types.ContainerJSON
  1293. c.Assert(json.Unmarshal(body, &containerJSON), check.IsNil)
  1294. c.Assert(containerJSON.HostConfig.ShmSize, check.Equals, int64(1073741824))
  1295. out, _ := dockerCmd(c, "start", "-i", containerJSON.ID)
  1296. shmRegex := regexp.MustCompile(`shm on /dev/shm type tmpfs(.*)size=1048576k`)
  1297. if !shmRegex.MatchString(out) {
  1298. c.Fatalf("Expected shm of 1GB in mount command, got %v", out)
  1299. }
  1300. }
  1301. func (s *DockerSuite) TestPostContainersCreateMemorySwappinessHostConfigOmitted(c *check.C) {
  1302. // Swappiness is not supported on Windows
  1303. testRequires(c, DaemonIsLinux)
  1304. config := map[string]interface{}{
  1305. "Image": "busybox",
  1306. }
  1307. status, body, err := sockRequest("POST", "/containers/create", config)
  1308. c.Assert(err, check.IsNil)
  1309. c.Assert(status, check.Equals, http.StatusCreated)
  1310. var container types.ContainerCreateResponse
  1311. c.Assert(json.Unmarshal(body, &container), check.IsNil)
  1312. status, body, err = sockRequest("GET", "/containers/"+container.ID+"/json", nil)
  1313. c.Assert(err, check.IsNil)
  1314. c.Assert(status, check.Equals, http.StatusOK)
  1315. var containerJSON types.ContainerJSON
  1316. c.Assert(json.Unmarshal(body, &containerJSON), check.IsNil)
  1317. c.Assert(*containerJSON.HostConfig.MemorySwappiness, check.Equals, int64(-1))
  1318. }
  1319. // check validation is done daemon side and not only in cli
  1320. func (s *DockerSuite) TestPostContainersCreateWithOomScoreAdjInvalidRange(c *check.C) {
  1321. // OomScoreAdj is not supported on Windows
  1322. testRequires(c, DaemonIsLinux)
  1323. config := struct {
  1324. Image string
  1325. OomScoreAdj int
  1326. }{"busybox", 1001}
  1327. name := "oomscoreadj-over"
  1328. status, b, err := sockRequest("POST", "/containers/create?name="+name, config)
  1329. c.Assert(err, check.IsNil)
  1330. c.Assert(status, check.Equals, http.StatusInternalServerError)
  1331. expected := "Invalid value 1001, range for oom score adj is [-1000, 1000]."
  1332. if !strings.Contains(string(b), expected) {
  1333. c.Fatalf("Expected output to contain %q, got %q", expected, string(b))
  1334. }
  1335. config = struct {
  1336. Image string
  1337. OomScoreAdj int
  1338. }{"busybox", -1001}
  1339. name = "oomscoreadj-low"
  1340. status, b, err = sockRequest("POST", "/containers/create?name="+name, config)
  1341. c.Assert(err, check.IsNil)
  1342. c.Assert(status, check.Equals, http.StatusInternalServerError)
  1343. expected = "Invalid value -1001, range for oom score adj is [-1000, 1000]."
  1344. if !strings.Contains(string(b), expected) {
  1345. c.Fatalf("Expected output to contain %q, got %q", expected, string(b))
  1346. }
  1347. }