mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Factorize the pull/push commands and create a registry.go
This commit is contained in:
parent
f50dcbe404
commit
da266e6c7b
3 changed files with 220 additions and 190 deletions
191
commands.go
191
commands.go
|
@ -8,12 +8,10 @@ import (
|
||||||
"github.com/dotcloud/docker/auth"
|
"github.com/dotcloud/docker/auth"
|
||||||
"github.com/dotcloud/docker/rcli"
|
"github.com/dotcloud/docker/rcli"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -23,7 +21,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const VERSION = "0.0.3"
|
const VERSION = "0.0.3"
|
||||||
const REGISTRY_ENDPOINT = "http://registry-creack.dotcloud.com/v1"
|
|
||||||
|
|
||||||
func (srv *Server) Name() string {
|
func (srv *Server) Name() string {
|
||||||
return "docker"
|
return "docker"
|
||||||
|
@ -434,168 +431,16 @@ func (srv *Server) CmdPush(stdin io.ReadCloser, stdout io.Writer, args ...string
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
client := &http.Client{}
|
img, err := srv.runtime.graph.Get(cmd.Arg(0))
|
||||||
if img, err := srv.runtime.graph.Get(cmd.Arg(0)); err != nil {
|
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
img.WalkHistory(func(img *Image) {
|
|
||||||
fmt.Fprintf(stdout, "Pushing %s\n", img.Id)
|
|
||||||
|
|
||||||
jsonRaw, err := ioutil.ReadFile(path.Join(srv.runtime.graph.Root, img.Id, "json"))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(stdout, "Error while retreiving the path for {%s}: %s\n", img.Id, err)
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
jsonData := strings.NewReader(string(jsonRaw))
|
// FIXME: Handle repositories, etc. Not jist images
|
||||||
req, err := http.NewRequest("PUT", REGISTRY_ENDPOINT+"/images/"+img.Id+"/json", jsonData)
|
return srv.runtime.graph.PushImage(img)
|
||||||
res, err := client.Do(req)
|
|
||||||
if err != nil || res.StatusCode != 200 {
|
|
||||||
if res == nil {
|
|
||||||
fmt.Fprintf(stdout,
|
|
||||||
"Error: Internal server error trying to push image {%s} (json): %s\n",
|
|
||||||
img.Id, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
switch res.StatusCode {
|
|
||||||
case 204:
|
|
||||||
fmt.Fprintf(stdout, "Image already on the repository\n")
|
|
||||||
return
|
|
||||||
case 400:
|
|
||||||
fmt.Fprintf(stdout, "Error: Invalid Json\n")
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
fmt.Fprintf(stdout,
|
|
||||||
"Error: Internal server error trying to push image {%s} (json): %s (%d)\n",
|
|
||||||
img.Id, err, res.StatusCode)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
req2, err := http.NewRequest("PUT", REGISTRY_ENDPOINT+"/images/"+img.Id+"/layer", nil)
|
|
||||||
res2, err := client.Do(req2)
|
|
||||||
if err != nil || res2.StatusCode != 307 {
|
|
||||||
fmt.Fprintf(stdout,
|
|
||||||
"Error trying to push image {%s} (layer 1): %s\n",
|
|
||||||
img.Id, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
url, err := res2.Location()
|
|
||||||
if err != nil || url == nil {
|
|
||||||
fmt.Fprintf(stdout,
|
|
||||||
"Fail to retrieve layer storage URL for image {%s}: %s\n",
|
|
||||||
img.Id, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// FIXME: Don't do this :D. Check the S3 requierement and implement chunks of 5MB
|
|
||||||
layerData2, err := Tar(path.Join(srv.runtime.graph.Root, img.Id, "layer"), Gzip)
|
|
||||||
layerData, err := Tar(path.Join(srv.runtime.graph.Root, img.Id, "layer"), Gzip)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(stdout,
|
|
||||||
"Error while retrieving layer for {%s}: %s\n",
|
|
||||||
img.Id, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
req3, err := http.NewRequest("PUT", url.String(), layerData)
|
|
||||||
tmp, _ := ioutil.ReadAll(layerData2)
|
|
||||||
req3.ContentLength = int64(len(tmp))
|
|
||||||
|
|
||||||
req3.TransferEncoding = []string{"none"}
|
|
||||||
res3, err := client.Do(req3)
|
|
||||||
if err != nil || res3.StatusCode != 200 {
|
|
||||||
if res3 == nil {
|
|
||||||
fmt.Fprintf(stdout,
|
|
||||||
"Error trying to push image {%s} (layer 2): %s\n",
|
|
||||||
img.Id, err)
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(stdout,
|
|
||||||
"Error trying to push image {%s} (layer 2): %s (%d)\n",
|
|
||||||
img.Id, err, res3.StatusCode)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newImgJson(src []byte) (*Image, error) {
|
func (srv *Server) CmdPull(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||||
ret := &Image{}
|
cmd := rcli.Subcmd(stdout, "pull", "[OPTIONS] IMAGE", "Pull an image from the registry")
|
||||||
|
|
||||||
fmt.Printf("Json string: {%s}\n", src)
|
|
||||||
// FIXME: Is there a cleaner way to "puryfy" the input json?
|
|
||||||
src = []byte(strings.Replace(string(src), "null", "\"\"", -1))
|
|
||||||
|
|
||||||
if err := json.Unmarshal(src, ret); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ret, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMultipleImgJson(src []byte) (map[*Image]Archive, error) {
|
|
||||||
ret := map[*Image]Archive{}
|
|
||||||
|
|
||||||
fmt.Printf("Json string2: {%s}\n", src)
|
|
||||||
dec := json.NewDecoder(strings.NewReader(strings.Replace(string(src), "null", "\"\"", -1)))
|
|
||||||
for {
|
|
||||||
m := &Image{}
|
|
||||||
if err := dec.Decode(m); err == io.EOF {
|
|
||||||
break
|
|
||||||
} else if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ret[m] = nil
|
|
||||||
}
|
|
||||||
return ret, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getHistory(base_uri, id string) (map[*Image]Archive, error) {
|
|
||||||
res, err := http.Get(base_uri + id + "/history")
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Error while getting from the server: %s\n", err)
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
|
|
||||||
jsonString, err := ioutil.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Error while reading the http response: %s\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
history, err := newMultipleImgJson(jsonString)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Error while parsing the json: %s\n", err)
|
|
||||||
}
|
|
||||||
return history, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getRemoteImage(base_uri, id string) (*Image, Archive, error) {
|
|
||||||
// Get the Json
|
|
||||||
res, err := http.Get(base_uri + id + "/json")
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, fmt.Errorf("Error while getting from the server: %s\n", err)
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
|
|
||||||
jsonString, err := ioutil.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, fmt.Errorf("Error while reading the http response: %s\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
img, err := newImgJson(jsonString)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, fmt.Errorf("Error while parsing the json: %s\n", err)
|
|
||||||
}
|
|
||||||
img.Id = id
|
|
||||||
|
|
||||||
// Get the layer
|
|
||||||
res, err = http.Get(base_uri + id + "/layer")
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, fmt.Errorf("Error while getting from the server: %s\n", err)
|
|
||||||
}
|
|
||||||
return img, res.Body, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (srv *Server) CmdPulli(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
|
||||||
cmd := rcli.Subcmd(stdout, "pulli", "[OPTIONS] IMAGE", "Pull an image from the registry")
|
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -603,28 +448,8 @@ func (srv *Server) CmdPulli(stdin io.ReadCloser, stdout io.Writer, args ...strin
|
||||||
cmd.Usage()
|
cmd.Usage()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
// FIXME: Handle repositories, etc. Not jist images
|
||||||
// First, retrieve the history
|
return srv.runtime.graph.PullImage(cmd.Arg(0))
|
||||||
base_uri := REGISTRY_ENDPOINT + "/images/"
|
|
||||||
|
|
||||||
// Now we have the history, remove the images we already have
|
|
||||||
history, err := getHistory(base_uri, cmd.Arg(0))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for j := range history {
|
|
||||||
if !srv.runtime.graph.Exists(j.Id) {
|
|
||||||
img, layer, err := getRemoteImage(base_uri, j.Id)
|
|
||||||
if err != nil {
|
|
||||||
// FIXME: Keep goging in case of error?
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err = srv.runtime.graph.Register(layer, img); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
||||||
|
|
16
image.go
16
image.go
|
@ -181,12 +181,12 @@ func ComputeId(content io.Reader) (string, error) {
|
||||||
// Image includes convenience proxy functions to its graph
|
// Image includes convenience proxy functions to its graph
|
||||||
// These functions will return an error if the image is not registered
|
// These functions will return an error if the image is not registered
|
||||||
// (ie. if image.graph == nil)
|
// (ie. if image.graph == nil)
|
||||||
|
|
||||||
func (img *Image) History() ([]*Image, error) {
|
func (img *Image) History() ([]*Image, error) {
|
||||||
var parents []*Image
|
var parents []*Image
|
||||||
if err := img.WalkHistory(
|
if err := img.WalkHistory(
|
||||||
func(img *Image) {
|
func(img *Image) error {
|
||||||
parents = append(parents, img)
|
parents = append(parents, img)
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -195,16 +195,19 @@ func (img *Image) History() ([]*Image, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// layers returns all the filesystem layers needed to mount an image
|
// layers returns all the filesystem layers needed to mount an image
|
||||||
|
// FIXME: @shykes refactor this function with the new error handling
|
||||||
|
// (I'll do it if I have time tonight, I focus on the rest)
|
||||||
func (img *Image) layers() ([]string, error) {
|
func (img *Image) layers() ([]string, error) {
|
||||||
var list []string
|
var list []string
|
||||||
var e error
|
var e error
|
||||||
if err := img.WalkHistory(
|
if err := img.WalkHistory(
|
||||||
func(img *Image) {
|
func(img *Image) (err error) {
|
||||||
if layer, err := img.layer(); err != nil {
|
if layer, err := img.layer(); err != nil {
|
||||||
e = err
|
e = err
|
||||||
} else if layer != "" {
|
} else if layer != "" {
|
||||||
list = append(list, layer)
|
list = append(list, layer)
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
},
|
},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -217,12 +220,13 @@ func (img *Image) layers() ([]string, error) {
|
||||||
return list, nil
|
return list, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (img *Image) WalkHistory(handler func(*Image)) error {
|
func (img *Image) WalkHistory(handler func(*Image) error) (err error) {
|
||||||
var err error
|
|
||||||
currentImg := img
|
currentImg := img
|
||||||
for currentImg != nil {
|
for currentImg != nil {
|
||||||
if handler != nil {
|
if handler != nil {
|
||||||
handler(currentImg)
|
if err := handler(currentImg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
currentImg, err = currentImg.GetParent()
|
currentImg, err = currentImg.GetParent()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
201
registry.go
Normal file
201
registry.go
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
package docker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
//FIXME: Set the endpoint in a conf file or via commandline
|
||||||
|
//const REGISTRY_ENDPOINT = "http://registry-creack.dotcloud.com/v1"
|
||||||
|
const REGISTRY_ENDPOINT = "http://192.168.56.1:5000/v1"
|
||||||
|
|
||||||
|
// Build an Image object from raw json data
|
||||||
|
func NewImgJson(src []byte) (*Image, error) {
|
||||||
|
ret := &Image{}
|
||||||
|
|
||||||
|
fmt.Printf("Json string: {%s}\n", src)
|
||||||
|
// FIXME: Is there a cleaner way to "puryfy" the input json?
|
||||||
|
src = []byte(strings.Replace(string(src), "null", "\"\"", -1))
|
||||||
|
|
||||||
|
if err := json.Unmarshal(src, ret); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build an Image object list from a raw json data
|
||||||
|
// FIXME: Do this in "stream" mode
|
||||||
|
func NewMultipleImgJson(src []byte) ([]*Image, error) {
|
||||||
|
ret := []*Image{}
|
||||||
|
|
||||||
|
dec := json.NewDecoder(strings.NewReader(strings.Replace(string(src), "null", "\"\"", -1)))
|
||||||
|
for {
|
||||||
|
m := &Image{}
|
||||||
|
if err := dec.Decode(m); err == io.EOF {
|
||||||
|
break
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ret = append(ret, m)
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the history of a given image from the Registry.
|
||||||
|
// Return a list of the parent's json (requested image included)
|
||||||
|
func (graph *Graph) getRemoteHistory(imgId string) ([]*Image, error) {
|
||||||
|
res, err := http.Get(REGISTRY_ENDPOINT + "/images/" + imgId + "/history")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error while getting from the server: %s\n", err)
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
jsonString, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error while reading the http response: %s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
history, err := NewMultipleImgJson(jsonString)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error while parsing the json: %s\n", err)
|
||||||
|
}
|
||||||
|
return history, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve an image from the Registry.
|
||||||
|
// Returns the Image object as well as the layer as an Archive (io.Reader)
|
||||||
|
func (graph *Graph) getRemoteImage(imgId string) (*Image, Archive, error) {
|
||||||
|
// Get the Json
|
||||||
|
res, err := http.Get(REGISTRY_ENDPOINT + "/images/" + imgId + "/json")
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("Error while getting from the server: %s\n", err)
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
jsonString, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("Error while reading the http response: %s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
img, err := NewImgJson(jsonString)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("Error while parsing the json: %s\n", err)
|
||||||
|
}
|
||||||
|
img.Id = imgId
|
||||||
|
|
||||||
|
// Get the layer
|
||||||
|
res, err = http.Get(REGISTRY_ENDPOINT + "/images/" + imgId + "/layer")
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("Error while getting from the server: %s\n", err)
|
||||||
|
}
|
||||||
|
return img, res.Body, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (graph *Graph) PullImage(imgId string) error {
|
||||||
|
history, err := graph.getRemoteHistory(imgId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// FIXME: Try to stream the images?
|
||||||
|
// FIXME: Lunch the getRemoteImage() in goroutines
|
||||||
|
for _, j := range history {
|
||||||
|
if !graph.Exists(j.Id) {
|
||||||
|
img, layer, err := graph.getRemoteImage(j.Id)
|
||||||
|
if err != nil {
|
||||||
|
// FIXME: Keep goging in case of error?
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = graph.Register(layer, img); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push a local image to the registry with its history if needed
|
||||||
|
func (graph *Graph) PushImage(imgOrig *Image) error {
|
||||||
|
client := &http.Client{}
|
||||||
|
|
||||||
|
// FIXME: Factorize the code
|
||||||
|
// FIXME: Do the puts in goroutines
|
||||||
|
if err := imgOrig.WalkHistory(func(img *Image) error {
|
||||||
|
|
||||||
|
jsonRaw, err := ioutil.ReadFile(path.Join(graph.Root, img.Id, "json"))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error while retreiving the path for {%s}: %s", img.Id, err)
|
||||||
|
}
|
||||||
|
// FIXME: try json with URF8
|
||||||
|
jsonData := strings.NewReader(string(jsonRaw))
|
||||||
|
req, err := http.NewRequest("PUT", REGISTRY_ENDPOINT+"/images/"+img.Id+"/json", jsonData)
|
||||||
|
res, err := client.Do(req)
|
||||||
|
if err != nil || res.StatusCode != 200 {
|
||||||
|
if res == nil {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"Error: Internal server error trying to push image {%s} (json): %s",
|
||||||
|
img.Id, err)
|
||||||
|
}
|
||||||
|
switch res.StatusCode {
|
||||||
|
case 204:
|
||||||
|
// Case where the image is already on the Registry
|
||||||
|
// FIXME: Do not be silent?
|
||||||
|
return nil
|
||||||
|
case 400:
|
||||||
|
return fmt.Errorf("Error: Invalid Json")
|
||||||
|
default:
|
||||||
|
return fmt.Errorf(
|
||||||
|
"Error: Internal server error trying to push image {%s} (json): %s (%d)\n",
|
||||||
|
img.Id, err, res.StatusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
req2, err := http.NewRequest("PUT", REGISTRY_ENDPOINT+"/images/"+img.Id+"/layer", nil)
|
||||||
|
res2, err := client.Do(req2)
|
||||||
|
if err != nil || res2.StatusCode != 307 {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"Error trying to push image {%s} (layer 1): %s\n",
|
||||||
|
img.Id, err)
|
||||||
|
}
|
||||||
|
url, err := res2.Location()
|
||||||
|
if err != nil || url == nil {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"Fail to retrieve layer storage URL for image {%s}: %s\n",
|
||||||
|
img.Id, err)
|
||||||
|
}
|
||||||
|
// FIXME: Don't do this :D. Check the S3 requierement and implement chunks of 5MB
|
||||||
|
// FIXME2: I won't stress it enough, DON'T DO THIS! very high priority
|
||||||
|
layerData2, err := Tar(path.Join(graph.Root, img.Id, "layer"), Gzip)
|
||||||
|
layerData, err := Tar(path.Join(graph.Root, img.Id, "layer"), Gzip)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"Error while retrieving layer for {%s}: %s\n",
|
||||||
|
img.Id, err)
|
||||||
|
}
|
||||||
|
req3, err := http.NewRequest("PUT", url.String(), layerData)
|
||||||
|
tmp, _ := ioutil.ReadAll(layerData2)
|
||||||
|
req3.ContentLength = int64(len(tmp))
|
||||||
|
|
||||||
|
req3.TransferEncoding = []string{"none"}
|
||||||
|
res3, err := client.Do(req3)
|
||||||
|
if err != nil || res3.StatusCode != 200 {
|
||||||
|
if res3 == nil {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"Error trying to push image {%s} (layer 2): %s\n",
|
||||||
|
img.Id, err)
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"Error trying to push image {%s} (layer 2): %s (%d)\n",
|
||||||
|
img.Id, err, res3.StatusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Reference in a new issue