From 3962f6ffdfc51dc7d232c2ea03c5ef6091570c0a Mon Sep 17 00:00:00 2001 From: Xian Chaobo Date: Wed, 6 May 2015 04:14:36 +0800 Subject: [PATCH 1/5] add-support-images-save Signed-off-by: Xian Chaobo --- api/handlers.go | 53 ++++++++++++++++++++++++++++++++++ api/router.go | 2 +- test/integration/api/save.bats | 28 ++++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) diff --git a/api/handlers.go b/api/handlers.go index 39ab133980..832e01d2e7 100644 --- a/api/handlers.go +++ b/api/handlers.go @@ -62,6 +62,59 @@ func getVersion(c *context, w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(version) } +// GET /images/get +func getImages(c *context, w http.ResponseWriter, r *http.Request) { + if err := r.ParseForm(); err != nil { + httpError(w, err.Error(), http.StatusInternalServerError) + return + } + names := r.Form["names"] + + // find an engine which has all images + // Engine.Addr : [found names] + dict := make(map[string][]string) + bFoundEngine := false + var foundEngineAddr string + for _, image := range c.cluster.Images() { + for _, name := range names { + if image.Match(name) { + // check if engine addr already exists + value, exists := dict[image.Engine.Addr] + if exists { + // check if name already exists + found := false + for _, tempName := range value { + if tempName == name { + found = true + } + } + if found == false { + dict[image.Engine.Addr] = append(value, name) + if len(names) == len(dict[image.Engine.Addr]) { + bFoundEngine = true + foundEngineAddr = image.Engine.Addr + } + } + } else { + dict[image.Engine.Addr] = []string{name} + } + } + if bFoundEngine { + break + } + } + if bFoundEngine { + break + } + } + + if bFoundEngine { + proxy(c.tlsConfig, foundEngineAddr, w, r) + } else { + httpError(w, fmt.Sprintf("Not found an engine which has all images: %s", names), http.StatusNotFound) + } +} + // GET /images/json func getImagesJSON(c *context, w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { diff --git a/api/router.go b/api/router.go index a0722f66c0..fbf95025e0 100644 --- a/api/router.go +++ b/api/router.go @@ -28,7 +28,7 @@ var routes = map[string]map[string]handler{ "/images/json": getImagesJSON, "/images/viz": notImplementedHandler, "/images/search": proxyRandom, - "/images/get": notImplementedHandler, + "/images/get": getImages, "/images/{name:.*}/get": proxyImage, "/images/{name:.*}/history": proxyImage, "/images/{name:.*}/json": proxyImage, diff --git a/test/integration/api/save.bats b/test/integration/api/save.bats index 5c2e009644..25dc27ee2a 100644 --- a/test/integration/api/save.bats +++ b/test/integration/api/save.bats @@ -42,3 +42,31 @@ function teardown() { rm -f $temp_file_name rm -f $temp_file_name_o } + +@test "docker save muti-images" { + start_docker_with_busybox 1 + start_docker 1 + swarm_manage + + # tag busybox + run docker_swarm tag busybox testimage + [ "$status" -eq 0 ] + + # make sure image exists + run docker_swarm images + [ "$status" -eq 0 ] + [[ "${output}" == *"busybox"* ]] + [[ "${output}" == *"testimage"* ]] + + temp_file_name=$(mktemp) + + docker_swarm save busybox testimage > $temp_file_name + + # saved image file exists, not empty and is tar file + [ -s $temp_file_name ] + run file $temp_file_name + [ "$status" -eq 0 ] + [[ "${output}" == *"tar archive"* ]] + + rm -f $temp_file_name +} From 42af0fadd7891069147b3961257b8d48d13066a0 Mon Sep 17 00:00:00 2001 From: Xian Chaobo Date: Wed, 6 May 2015 22:15:54 +0800 Subject: [PATCH 2/5] fix var name and integration test Signed-off-by: Xian Chaobo --- api/handlers.go | 24 +++++++++++------------- test/integration/api/save.bats | 32 ++++++++++++++++++++++++-------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/api/handlers.go b/api/handlers.go index 832e01d2e7..0ec317b0f1 100644 --- a/api/handlers.go +++ b/api/handlers.go @@ -72,43 +72,41 @@ func getImages(c *context, w http.ResponseWriter, r *http.Request) { // find an engine which has all images // Engine.Addr : [found names] - dict := make(map[string][]string) - bFoundEngine := false + imageMap := make(map[string][]string) var foundEngineAddr string for _, image := range c.cluster.Images() { for _, name := range names { if image.Match(name) { // check if engine addr already exists - value, exists := dict[image.Engine.Addr] + value, exists := imageMap[image.Engine.Addr] if exists { // check if name already exists - found := false + nameAlreadyExisted := false for _, tempName := range value { if tempName == name { - found = true + nameAlreadyExisted = true } } - if found == false { - dict[image.Engine.Addr] = append(value, name) - if len(names) == len(dict[image.Engine.Addr]) { - bFoundEngine = true + if nameAlreadyExisted == false { + imageMap[image.Engine.Addr] = append(value, name) + if len(names) == len(imageMap[image.Engine.Addr]) { foundEngineAddr = image.Engine.Addr } } } else { - dict[image.Engine.Addr] = []string{name} + imageMap[image.Engine.Addr] = []string{name} } } - if bFoundEngine { + if foundEngineAddr != "" { break } } - if bFoundEngine { + if foundEngineAddr != "" { break } } - if bFoundEngine { + if foundEngineAddr != "" { proxy(c.tlsConfig, foundEngineAddr, w, r) } else { httpError(w, fmt.Sprintf("Not found an engine which has all images: %s", names), http.StatusNotFound) diff --git a/test/integration/api/save.bats b/test/integration/api/save.bats index 25dc27ee2a..c06731603f 100644 --- a/test/integration/api/save.bats +++ b/test/integration/api/save.bats @@ -43,24 +43,32 @@ function teardown() { rm -f $temp_file_name_o } -@test "docker save muti-images" { - start_docker_with_busybox 1 +@test "docker save multi-images" { + start_docker_with_busybox 2 start_docker 1 - swarm_manage - # tag busybox - run docker_swarm tag busybox testimage - [ "$status" -eq 0 ] + docker -H ${HOSTS[0]} tag busybox test1 + docker -H ${HOSTS[1]} tag busybox test2 + + # start manage + swarm_manage # make sure image exists run docker_swarm images [ "$status" -eq 0 ] [[ "${output}" == *"busybox"* ]] - [[ "${output}" == *"testimage"* ]] + [[ "${output}" == *"test1"* ]] + [[ "${output}" == *"test2"* ]] temp_file_name=$(mktemp) - docker_swarm save busybox testimage > $temp_file_name + # do not support save images which are on multi machine + run docker_swarm save busybox test1 test2 > $temp_file_name + [ "$status" -ne 0 ] + [[ "${output}" == *"Not found an engine which has all images"* ]] + + # save images which are on same machine + docker_swarm save busybox test1 > $temp_file_name # saved image file exists, not empty and is tar file [ -s $temp_file_name ] @@ -68,5 +76,13 @@ function teardown() { [ "$status" -eq 0 ] [[ "${output}" == *"tar archive"* ]] + # load image on node-3 + docker -H ${HOSTS[2]} load < $temp_file_name + # check image + run docker -H ${HOSTS[2]} images + [ "$status" -eq 0 ] + [[ "${output}" == *"busybox"* ]] + [[ "${output}" == *"test1"* ]] + rm -f $temp_file_name } From 7403991caca7daf583b8c711f0e6867ea4c8954b Mon Sep 17 00:00:00 2001 From: Andrea Luzzardi Date: Fri, 8 May 2015 15:33:13 -0700 Subject: [PATCH 3/5] API: Simplify getImages. Signed-off-by: Andrea Luzzardi --- api/handlers.go | 53 +++++++++++++++++++------------------------------ 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/api/handlers.go b/api/handlers.go index 0ec317b0f1..e8158a60e9 100644 --- a/api/handlers.go +++ b/api/handlers.go @@ -70,47 +70,34 @@ func getImages(c *context, w http.ResponseWriter, r *http.Request) { } names := r.Form["names"] - // find an engine which has all images - // Engine.Addr : [found names] - imageMap := make(map[string][]string) - var foundEngineAddr string + // Create a map of engine address to the list of images it holds. + engineImages := make(map[string][]*cluster.Image) for _, image := range c.cluster.Images() { + engineImages[image.Engine.Addr] = append(engineImages[image.Engine.Addr], image) + } + + // Look for an engine that has all the images we need. + for engine, images := range engineImages { + matchedImages := 0 + + // Count how many images we need it has. for _, name := range names { - if image.Match(name) { - // check if engine addr already exists - value, exists := imageMap[image.Engine.Addr] - if exists { - // check if name already exists - nameAlreadyExisted := false - for _, tempName := range value { - if tempName == name { - nameAlreadyExisted = true - } - } - if nameAlreadyExisted == false { - imageMap[image.Engine.Addr] = append(value, name) - if len(names) == len(imageMap[image.Engine.Addr]) { - foundEngineAddr = image.Engine.Addr - } - } - } else { - imageMap[image.Engine.Addr] = []string{name} + for _, image := range images { + if image.Match(name) { + matchedImages = matchedImages + 1 + break } } - if foundEngineAddr != "" { - break - } } - if foundEngineAddr != "" { - break + + // If the engine has all images, stop our search here. + if matchedImages == len(names) { + proxy(c.tlsConfig, engine, w, r) + return } } - if foundEngineAddr != "" { - proxy(c.tlsConfig, foundEngineAddr, w, r) - } else { - httpError(w, fmt.Sprintf("Not found an engine which has all images: %s", names), http.StatusNotFound) - } + httpError(w, fmt.Sprintf("Not found an engine which has all images: %s", names), http.StatusNotFound) } // GET /images/json From 9e2863ec7166913db85b51aeaf97900b63bd3d50 Mon Sep 17 00:00:00 2001 From: Andrea Luzzardi Date: Fri, 8 May 2015 15:44:28 -0700 Subject: [PATCH 4/5] api: getImages: changed error message Signed-off-by: Andrea Luzzardi --- api/handlers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/handlers.go b/api/handlers.go index e8158a60e9..5f3996637d 100644 --- a/api/handlers.go +++ b/api/handlers.go @@ -97,7 +97,7 @@ func getImages(c *context, w http.ResponseWriter, r *http.Request) { } } - httpError(w, fmt.Sprintf("Not found an engine which has all images: %s", names), http.StatusNotFound) + httpError(w, fmt.Sprintf("Unable to find an engine containing all images: %s", names), http.StatusNotFound) } // GET /images/json From d88105dbfe03d1ba3f52668c6fecb96abd3cb6ba Mon Sep 17 00:00:00 2001 From: Andrea Luzzardi Date: Fri, 8 May 2015 15:45:03 -0700 Subject: [PATCH 5/5] integration: minor cleanup of docker save multi-images Signed-off-by: Andrea Luzzardi --- test/integration/api/save.bats | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/test/integration/api/save.bats b/test/integration/api/save.bats index c06731603f..5765c07f12 100644 --- a/test/integration/api/save.bats +++ b/test/integration/api/save.bats @@ -45,7 +45,6 @@ function teardown() { @test "docker save multi-images" { start_docker_with_busybox 2 - start_docker 1 # tag busybox docker -H ${HOSTS[0]} tag busybox test1 docker -H ${HOSTS[1]} tag busybox test2 @@ -60,15 +59,15 @@ function teardown() { [[ "${output}" == *"test1"* ]] [[ "${output}" == *"test2"* ]] - temp_file_name=$(mktemp) + local temp_file_name=$(mktemp) # do not support save images which are on multi machine - run docker_swarm save busybox test1 test2 > $temp_file_name + run docker_swarm save -o "$temp_file_name" busybox test1 test2 [ "$status" -ne 0 ] - [[ "${output}" == *"Not found an engine which has all images"* ]] + [[ "${output}" == *"Unable to find an engine containing all images"* ]] # save images which are on same machine - docker_swarm save busybox test1 > $temp_file_name + docker_swarm save -o "$temp_file_name" busybox test1 # saved image file exists, not empty and is tar file [ -s $temp_file_name ] @@ -76,9 +75,12 @@ function teardown() { [ "$status" -eq 0 ] [[ "${output}" == *"tar archive"* ]] - # load image on node-3 - docker -H ${HOSTS[2]} load < $temp_file_name - # check image + # Try to load our image back on an empty docker engine. + start_docker 1 + run docker -H "${HOSTS[2]}" images -q + [ "$status" -eq 0 ] + [ "${#lines[@]}" -eq 0 ] + docker -H "${HOSTS[2]}" load -i "$temp_file_name" run docker -H ${HOSTS[2]} images [ "$status" -eq 0 ] [[ "${output}" == *"busybox"* ]]