From c7e7707f7604d35c98ad0641140768e2a154549c Mon Sep 17 00:00:00 2001 From: Kyle Boorky Date: Tue, 31 Mar 2015 11:18:51 -0400 Subject: [PATCH 1/5] adding build image functionality --- auth.go | 13 +++++++++ dockerclient.go | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ types.go | 11 ++++++++ 3 files changed, 97 insertions(+) diff --git a/auth.go b/auth.go index 022d3dd..8a230bf 100644 --- a/auth.go +++ b/auth.go @@ -19,3 +19,16 @@ func (c *AuthConfig) encode() string { json.NewEncoder(&buf).Encode(c) return base64.URLEncoding.EncodeToString(buf.Bytes()) } + +// ConfigFile holds parameters for authenticating during a BuildImage request +type ConfigFile struct { + Configs map[string]AuthConfig `json:"configs,omitempty"` + rootPath string +} + +// encode the configuration struct into base64 for the X-Registry-Config header +func (c *ConfigFile) encode() string { + var buf bytes.Buffer + json.NewEncoder(&buf).Encode(c) + return base64.URLEncoding.EncodeToString(buf.Bytes()) +} diff --git a/dockerclient.go b/dockerclient.go index d427a6f..63ceb34 100644 --- a/dockerclient.go +++ b/dockerclient.go @@ -1,6 +1,7 @@ package dockerclient import ( + "archive/tar" "bytes" "crypto/tls" "encoding/json" @@ -324,6 +325,78 @@ func (client *DockerClient) Version() (*Version, error) { return version, nil } +func (client *DockerClient) BuildImage(image BuildImage, config *ConfigFile) error { + v := url.Values{} + if image.DockerfilePath != "" { + v.Set("dockerfile", image.DockerfilePath) + } + if image.Name != "" { + v.Set("t", image.Name) + } + if image.Remote != "" { + v.Set("remote", image.Remote) + } + if image.NoCache { + v.Set("nocache", "1") + } + if image.Pull { + v.Set("pull", "1") + } + if image.Remove { + v.Set("rm", "1") + } else { + v.Set("rm", "0") + } + if image.ForceRemove { + v.Set("forcerm", "1") + } + v.Set("q", "1") + uri := fmt.Sprintf("/%s/build?%s", APIVersion, v.Encode()) + + buf := new(bytes.Buffer) + tw := tar.NewWriter(buf) + for k, v := range image.Files { + hdr := &tar.Header{ + Name: k, + Size: int64(len(v)), + } + err := tw.WriteHeader(hdr) + if err != nil { + return err + } + _, err = tw.Write([]byte(v)) + if err != nil { + return err + } + } + err := tw.Close() + if err != nil { + return err + } + + body := bytes.NewReader(buf.Bytes()) + req, err := http.NewRequest("POST", client.URL.String()+uri, body) + if config != nil { + req.Header.Add("X-Registry-Config", config.encode()) + } + req.Header.Set("Content-Type", "application/tar") + resp, err := client.HTTPClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + var finalObj map[string]interface{} + for decoder := json.NewDecoder(resp.Body); err == nil; err = decoder.Decode(&finalObj) { + } + if err != io.EOF { + return err + } + if err, ok := finalObj["error"]; ok { + return fmt.Errorf("%v", err) + } + return nil +} + func (client *DockerClient) PullImage(name string, auth *AuthConfig) error { v := url.Values{} v.Set("fromImage", name) diff --git a/types.go b/types.go index 6bf197e..d004d2a 100644 --- a/types.go +++ b/types.go @@ -158,6 +158,17 @@ type Image struct { VirtualSize int64 } +type BuildImage struct { + Name string + Remote string + DockerfilePath string + Files map[string]string + NoCache bool + Pull bool + Remove bool + ForceRemove bool +} + type Info struct { ID string Containers int64 From 869ad11c5f120fc0f79aa2907c3cb0fe5f954794 Mon Sep 17 00:00:00 2001 From: Kyle Boorky Date: Tue, 31 Mar 2015 15:20:03 -0400 Subject: [PATCH 2/5] adding PushImage function --- dockerclient.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/dockerclient.go b/dockerclient.go index 63ceb34..43d2c9c 100644 --- a/dockerclient.go +++ b/dockerclient.go @@ -397,6 +397,33 @@ func (client *DockerClient) BuildImage(image BuildImage, config *ConfigFile) err return nil } +func (client *DockerClient) PushImage(name string, tag string, auth *AuthConfig) error { + v := url.Values{} + if tag != "" { + v.Set("tag", tag) + } + uri := fmt.Sprintf("/%s/images/%s/push?%s", APIVersion, url.QueryEscape(name), v.Encode()) + req, err := http.NewRequest("POST", client.URL.String()+uri, nil) + if auth != nil { + req.Header.Add("X-Registry-Auth", auth.encode()) + } + resp, err := client.HTTPClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + var finalObj map[string]interface{} + for decoder := json.NewDecoder(resp.Body); err == nil; err = decoder.Decode(&finalObj) { + } + if err != io.EOF { + return err + } + if err, ok := finalObj["error"]; ok { + return fmt.Errorf("%v", err) + } + return nil +} + func (client *DockerClient) PullImage(name string, auth *AuthConfig) error { v := url.Values{} v.Set("fromImage", name) From 1e5e20fb7045e5ddd129255a6482b3e44a2a44a4 Mon Sep 17 00:00:00 2001 From: Kyle Boorky Date: Tue, 31 Mar 2015 17:40:06 -0400 Subject: [PATCH 3/5] adding mode support --- dockerclient.go | 9 +++++---- types.go | 8 +++++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/dockerclient.go b/dockerclient.go index 63ceb34..c30ca5a 100644 --- a/dockerclient.go +++ b/dockerclient.go @@ -355,16 +355,17 @@ func (client *DockerClient) BuildImage(image BuildImage, config *ConfigFile) err buf := new(bytes.Buffer) tw := tar.NewWriter(buf) - for k, v := range image.Files { + for _, v := range image.Files { hdr := &tar.Header{ - Name: k, - Size: int64(len(v)), + Name: v.Name, + Size: int64(len(v.Contents)), + Mode: v.Mode, } err := tw.WriteHeader(hdr) if err != nil { return err } - _, err = tw.Write([]byte(v)) + _, err = tw.Write(v.Contents) if err != nil { return err } diff --git a/types.go b/types.go index d004d2a..9a813d6 100644 --- a/types.go +++ b/types.go @@ -158,11 +158,17 @@ type Image struct { VirtualSize int64 } +type File struct { + Name string + Contents []byte + Mode int64 +} + type BuildImage struct { Name string Remote string DockerfilePath string - Files map[string]string + Files []File NoCache bool Pull bool Remove bool From b018d0595bdb51a730dea0f457b4245196ec9f27 Mon Sep 17 00:00:00 2001 From: Kyle Boorky Date: Fri, 24 Apr 2015 11:21:08 -0400 Subject: [PATCH 4/5] switching BuildImage to take an io.Reader Tarfile instead of an array of files. --- dockerclient.go | 26 +------------------------- interface.go | 1 + types.go | 13 +++++-------- 3 files changed, 7 insertions(+), 33 deletions(-) diff --git a/dockerclient.go b/dockerclient.go index c30ca5a..9dd38a1 100644 --- a/dockerclient.go +++ b/dockerclient.go @@ -1,7 +1,6 @@ package dockerclient import ( - "archive/tar" "bytes" "crypto/tls" "encoding/json" @@ -353,30 +352,7 @@ func (client *DockerClient) BuildImage(image BuildImage, config *ConfigFile) err v.Set("q", "1") uri := fmt.Sprintf("/%s/build?%s", APIVersion, v.Encode()) - buf := new(bytes.Buffer) - tw := tar.NewWriter(buf) - for _, v := range image.Files { - hdr := &tar.Header{ - Name: v.Name, - Size: int64(len(v.Contents)), - Mode: v.Mode, - } - err := tw.WriteHeader(hdr) - if err != nil { - return err - } - _, err = tw.Write(v.Contents) - if err != nil { - return err - } - } - err := tw.Close() - if err != nil { - return err - } - - body := bytes.NewReader(buf.Bytes()) - req, err := http.NewRequest("POST", client.URL.String()+uri, body) + req, err := http.NewRequest("POST", client.URL.String()+uri, image.Tarfile) if config != nil { req.Header.Add("X-Registry-Config", config.encode()) } diff --git a/interface.go b/interface.go index 87b69f5..61b8d86 100644 --- a/interface.go +++ b/interface.go @@ -12,6 +12,7 @@ type Client interface { Info() (*Info, error) ListContainers(all, size bool, filters string) ([]Container, error) InspectContainer(id string) (*ContainerInfo, error) + BuildImage(image BuildImage, config *ConfigFile) error CreateContainer(config *ContainerConfig, name string) (string, error) ContainerLogs(id string, options *LogOptions) (io.ReadCloser, error) ContainerChanges(id string) ([]*ContainerChanges, error) diff --git a/types.go b/types.go index 9a813d6..d94986f 100644 --- a/types.go +++ b/types.go @@ -1,6 +1,9 @@ package dockerclient -import "time" +import ( + "io" + "time" +) type ContainerConfig struct { Hostname string @@ -158,17 +161,11 @@ type Image struct { VirtualSize int64 } -type File struct { - Name string - Contents []byte - Mode int64 -} - type BuildImage struct { Name string Remote string DockerfilePath string - Files []File + Tarfile io.Reader NoCache bool Pull bool Remove bool From f06e10afdb03cb0143d125642b69587ef71ca128 Mon Sep 17 00:00:00 2001 From: Kyle Boorky Date: Fri, 24 Apr 2015 11:23:59 -0400 Subject: [PATCH 5/5] adding interface --- interface.go | 1 + 1 file changed, 1 insertion(+) diff --git a/interface.go b/interface.go index 61b8d86..fb94839 100644 --- a/interface.go +++ b/interface.go @@ -27,6 +27,7 @@ type Client interface { StopAllMonitorStats() Version() (*Version, error) PullImage(name string, auth *AuthConfig) error + PushImage(name string, tag string, auth *AuthConfig) error RemoveContainer(id string, force, volumes bool) error ListImages() ([]*Image, error) RemoveImage(name string) ([]*ImageDelete, error)