Skip to content

Commit da01dd3

Browse files
committed
Merge remote-tracking branch 'origin/registry-update'
+ Registry: Add the new registry support
2 parents 58ca46a + 09f1cba commit da01dd3

7 files changed

Lines changed: 564 additions & 243 deletions

File tree

auth/auth.go

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package auth
33
import (
44
"encoding/base64"
55
"encoding/json"
6-
"errors"
76
"fmt"
87
"io/ioutil"
98
"net/http"
@@ -16,7 +15,7 @@ import (
1615
const CONFIGFILE = ".dockercfg"
1716

1817
// the registry server we want to login against
19-
const REGISTRY_SERVER = "https://registry.docker.io"
18+
const INDEX_SERVER = "https://index.docker.io"
2019

2120
type AuthConfig struct {
2221
Username string `json:"username"`
@@ -76,6 +75,9 @@ func LoadConfig(rootPath string) (*AuthConfig, error) {
7675
return nil, err
7776
}
7877
arr := strings.Split(string(b), "\n")
78+
if len(arr) < 2 {
79+
return nil, fmt.Errorf("The Auth config file is empty")
80+
}
7981
origAuth := strings.Split(arr[0], " = ")
8082
origEmail := strings.Split(arr[1], " = ")
8183
authConfig, err := DecodeAuth(origAuth[1])
@@ -89,9 +91,14 @@ func LoadConfig(rootPath string) (*AuthConfig, error) {
8991

9092
// save the auth config
9193
func saveConfig(rootPath, authStr string, email string) error {
94+
confFile := path.Join(rootPath, CONFIGFILE)
95+
if len(email) == 0 {
96+
os.Remove(confFile)
97+
return nil
98+
}
9299
lines := "auth = " + authStr + "\n" + "email = " + email + "\n"
93100
b := []byte(lines)
94-
err := ioutil.WriteFile(path.Join(rootPath, CONFIGFILE), b, 0600)
101+
err := ioutil.WriteFile(confFile, b, 0600)
95102
if err != nil {
96103
return err
97104
}
@@ -101,40 +108,38 @@ func saveConfig(rootPath, authStr string, email string) error {
101108
// try to register/login to the registry server
102109
func Login(authConfig *AuthConfig) (string, error) {
103110
storeConfig := false
111+
client := &http.Client{}
104112
reqStatusCode := 0
105113
var status string
106-
var errMsg string
107114
var reqBody []byte
108115
jsonBody, err := json.Marshal(authConfig)
109116
if err != nil {
110-
errMsg = fmt.Sprintf("Config Error: %s", err)
111-
return "", errors.New(errMsg)
117+
return "", fmt.Errorf("Config Error: %s", err)
112118
}
113119

114120
// using `bytes.NewReader(jsonBody)` here causes the server to respond with a 411 status.
115121
b := strings.NewReader(string(jsonBody))
116-
req1, err := http.Post(REGISTRY_SERVER+"/v1/users", "application/json; charset=utf-8", b)
122+
req1, err := http.Post(INDEX_SERVER+"/v1/users/", "application/json; charset=utf-8", b)
117123
if err != nil {
118-
errMsg = fmt.Sprintf("Server Error: %s", err)
119-
return "", errors.New(errMsg)
124+
return "", fmt.Errorf("Server Error: %s", err)
120125
}
121-
122126
reqStatusCode = req1.StatusCode
123127
defer req1.Body.Close()
124128
reqBody, err = ioutil.ReadAll(req1.Body)
125129
if err != nil {
126-
errMsg = fmt.Sprintf("Server Error: [%#v] %s", reqStatusCode, err)
127-
return "", errors.New(errMsg)
130+
return "", fmt.Errorf("Server Error: [%#v] %s", reqStatusCode, err)
128131
}
129132

130133
if reqStatusCode == 201 {
131-
status = "Account Created\n"
134+
status = "Account created. Please use the confirmation link we sent" +
135+
" to your e-mail to activate it.\n"
132136
storeConfig = true
137+
} else if reqStatusCode == 403 {
138+
return "", fmt.Errorf("Login: Your account hasn't been activated. " +
139+
"Please check your e-mail for a confirmation link.")
133140
} else if reqStatusCode == 400 {
134-
// FIXME: This should be 'exists', not 'exist'. Need to change on the server first.
135-
if string(reqBody) == "Username or email already exist" {
136-
client := &http.Client{}
137-
req, err := http.NewRequest("GET", REGISTRY_SERVER+"/v1/users", nil)
141+
if string(reqBody) == "\"Username or email already exists\"" {
142+
req, err := http.NewRequest("GET", INDEX_SERVER+"/v1/users/", nil)
138143
req.SetBasicAuth(authConfig.Username, authConfig.Password)
139144
resp, err := client.Do(req)
140145
if err != nil {
@@ -148,17 +153,18 @@ func Login(authConfig *AuthConfig) (string, error) {
148153
if resp.StatusCode == 200 {
149154
status = "Login Succeeded\n"
150155
storeConfig = true
156+
} else if resp.StatusCode == 401 {
157+
saveConfig(authConfig.rootPath, "", "")
158+
return "", fmt.Errorf("Wrong login/password, please try again")
151159
} else {
152-
status = fmt.Sprintf("Login: %s", body)
153-
return "", errors.New(status)
160+
return "", fmt.Errorf("Login: %s (Code: %d; Headers: %s)", body,
161+
resp.StatusCode, resp.Header)
154162
}
155163
} else {
156-
status = fmt.Sprintf("Registration: %s", reqBody)
157-
return "", errors.New(status)
164+
return "", fmt.Errorf("Registration: %s", reqBody)
158165
}
159166
} else {
160-
status = fmt.Sprintf("[%s] : %s", reqStatusCode, reqBody)
161-
return "", errors.New(status)
167+
return "", fmt.Errorf("Unexpected status code [%d] : %s", reqStatusCode, reqBody)
162168
}
163169
if storeConfig {
164170
authStr := EncodeAuth(authConfig)

commands.go

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,7 @@ func (srv *Server) CmdImport(stdin io.ReadCloser, stdout rcli.DockerConn, args .
521521

522522
func (srv *Server) CmdPush(stdin io.ReadCloser, stdout rcli.DockerConn, args ...string) error {
523523
cmd := rcli.Subcmd(stdout, "push", "NAME", "Push an image or a repository to the registry")
524+
registry := cmd.String("registry", "", "Registry host to push the image to")
524525
if err := cmd.Parse(args); err != nil {
525526
return nil
526527
}
@@ -531,8 +532,8 @@ func (srv *Server) CmdPush(stdin io.ReadCloser, stdout rcli.DockerConn, args ...
531532
return nil
532533
}
533534

534-
// If the login failed, abort
535-
if srv.runtime.authConfig == nil || srv.runtime.authConfig.Username == "" {
535+
// If the login failed AND we're using the index, abort
536+
if *registry == "" && (srv.runtime.authConfig == nil || srv.runtime.authConfig.Username == "") {
536537
if err := srv.CmdLogin(stdin, stdout, args...); err != nil {
537538
return err
538539
}
@@ -555,9 +556,6 @@ func (srv *Server) CmdPush(stdin io.ReadCloser, stdout rcli.DockerConn, args ...
555556
Debugf("Pushing [%s] to [%s]\n", local, remote)
556557

557558
// Try to get the image
558-
// FIXME: Handle lookup
559-
// FIXME: Also push the tags in case of ./docker push myrepo:mytag
560-
// img, err := srv.runtime.LookupImage(cmd.Arg(0))
561559
img, err := srv.runtime.graph.Get(local)
562560
if err != nil {
563561
Debugf("The push refers to a repository [%s] (len: %d)\n", local, len(srv.runtime.repositories.Repositories[local]))
@@ -571,7 +569,7 @@ func (srv *Server) CmdPush(stdin io.ReadCloser, stdout rcli.DockerConn, args ...
571569

572570
return err
573571
}
574-
err = srv.runtime.graph.PushImage(stdout, img, srv.runtime.authConfig)
572+
err = srv.runtime.graph.PushImage(stdout, img, *registry, nil)
575573
if err != nil {
576574
return err
577575
}
@@ -580,6 +578,8 @@ func (srv *Server) CmdPush(stdin io.ReadCloser, stdout rcli.DockerConn, args ...
580578

581579
func (srv *Server) CmdPull(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
582580
cmd := rcli.Subcmd(stdout, "pull", "NAME", "Pull an image or a repository from the registry")
581+
tag := cmd.String("t", "", "Download tagged image in repository")
582+
registry := cmd.String("registry", "", "Registry to download from. Necessary if image is pulled by ID")
583583
if err := cmd.Parse(args); err != nil {
584584
return nil
585585
}
@@ -589,15 +589,20 @@ func (srv *Server) CmdPull(stdin io.ReadCloser, stdout io.Writer, args ...string
589589
return nil
590590
}
591591

592+
if strings.Contains(remote, ":") {
593+
remoteParts := strings.Split(remote, ":")
594+
tag = &remoteParts[1]
595+
remote = remoteParts[0]
596+
}
597+
592598
// FIXME: CmdPull should be a wrapper around Runtime.Pull()
593-
if srv.runtime.graph.LookupRemoteImage(remote, srv.runtime.authConfig) {
594-
if err := srv.runtime.graph.PullImage(stdout, remote, srv.runtime.authConfig); err != nil {
599+
if *registry != "" {
600+
if err := srv.runtime.graph.PullImage(stdout, remote, *registry, nil); err != nil {
595601
return err
596602
}
597603
return nil
598604
}
599-
// FIXME: Allow pull repo:tag
600-
if err := srv.runtime.graph.PullRepository(stdout, remote, "", srv.runtime.repositories, srv.runtime.authConfig); err != nil {
605+
if err := srv.runtime.graph.PullRepository(stdout, remote, *tag, srv.runtime.repositories, srv.runtime.authConfig); err != nil {
601606
return err
602607
}
603608
return nil

container.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,14 @@ func (container *Container) ExportRw() (Archive, error) {
736736
return Tar(container.rwPath(), Uncompressed)
737737
}
738738

739+
func (container *Container) RwChecksum() (string, error) {
740+
rwData, err := Tar(container.rwPath(), Xz)
741+
if err != nil {
742+
return "", err
743+
}
744+
return HashData(rwData)
745+
}
746+
739747
func (container *Container) Export() (Archive, error) {
740748
if err := container.EnsureMounted(); err != nil {
741749
return nil, err

graph.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"io"
66
"io/ioutil"
7+
"net/http"
78
"os"
89
"path"
910
"path/filepath"
@@ -13,8 +14,9 @@ import (
1314

1415
// A Graph is a store for versioned filesystem images and the relationship between them.
1516
type Graph struct {
16-
Root string
17-
idIndex *TruncIndex
17+
Root string
18+
idIndex *TruncIndex
19+
httpClient *http.Client
1820
}
1921

2022
// NewGraph instantiates a new graph at the given root path in the filesystem.
@@ -97,15 +99,11 @@ func (graph *Graph) Create(layerData Archive, container *Container, comment, aut
9799
img.Parent = container.Image
98100
img.Container = container.Id
99101
img.ContainerConfig = *container.Config
100-
if config == nil {
101-
if parentImage, err := graph.Get(container.Image); err == nil && parentImage != nil {
102-
img.Config = parentImage.Config
103-
}
104-
}
105102
}
106103
if err := graph.Register(layerData, img); err != nil {
107104
return nil, err
108105
}
106+
img.Checksum()
109107
return img, nil
110108
}
111109

image.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package docker
22

33
import (
44
"crypto/rand"
5+
"crypto/sha256"
56
"encoding/hex"
67
"encoding/json"
78
"fmt"
@@ -51,6 +52,7 @@ func LoadImage(root string) (*Image, error) {
5152
} else if !stat.IsDir() {
5253
return nil, fmt.Errorf("Couldn't load image %s: %s is not a directory", img.Id, layerPath(root))
5354
}
55+
5456
return &img, nil
5557
}
5658

@@ -257,3 +259,62 @@ func (img *Image) layer() (string, error) {
257259
}
258260
return layerPath(root), nil
259261
}
262+
263+
func (img *Image) Checksum() (string, error) {
264+
root, err := img.root()
265+
if err != nil {
266+
return "", err
267+
}
268+
269+
checksumDictPth := path.Join(root, "..", "..", "checksums")
270+
checksums := new(map[string]string)
271+
272+
if checksumDict, err := ioutil.ReadFile(checksumDictPth); err == nil {
273+
if err := json.Unmarshal(checksumDict, checksums); err != nil {
274+
return "", err
275+
}
276+
if checksum, ok := (*checksums)[img.Id]; ok {
277+
return checksum, nil
278+
}
279+
}
280+
281+
layer, err := img.layer()
282+
if err != nil {
283+
return "", err
284+
}
285+
jsonData, err := ioutil.ReadFile(jsonPath(root))
286+
if err != nil {
287+
return "", err
288+
}
289+
290+
layerData, err := Tar(layer, Xz)
291+
if err != nil {
292+
return "", err
293+
}
294+
295+
h := sha256.New()
296+
if _, err := h.Write(jsonData); err != nil {
297+
return "", err
298+
}
299+
if _, err := h.Write([]byte("\n")); err != nil {
300+
return "", err
301+
}
302+
if _, err := io.Copy(h, layerData); err != nil {
303+
return "", err
304+
}
305+
306+
hash := "sha256:" + hex.EncodeToString(h.Sum(nil))
307+
if *checksums == nil {
308+
*checksums = map[string]string{}
309+
}
310+
(*checksums)[img.Id] = hash
311+
checksumJson, err := json.Marshal(checksums)
312+
if err != nil {
313+
return hash, err
314+
}
315+
316+
if err := ioutil.WriteFile(checksumDictPth, checksumJson, 0600); err != nil {
317+
return hash, err
318+
}
319+
return hash, nil
320+
}

0 commit comments

Comments
 (0)