Merge branch 'graph' of ssh://github.com/dotcloud/docker into graph

This commit is contained in:
Solomon Hykes 2013-03-22 17:40:32 -07:00
commit 56752158af
6 changed files with 107 additions and 73 deletions

1
.gitignore vendored
View file

@ -7,3 +7,4 @@ build_src
command-line-arguments.test
.flymake*
docker.test
auth/auth.test

View file

@ -8,11 +8,12 @@ import (
"io/ioutil"
"net/http"
"os"
"path"
"strings"
)
// Where we store the config file
const CONFIGFILE = "/var/lib/docker/.dockercfg"
const CONFIGFILE = ".dockercfg"
// the registry server we want to login against
//const REGISTRY_SERVER = "https://registry.docker.io"
@ -22,10 +23,11 @@ type AuthConfig struct {
Username string `json:"username"`
Password string `json:"password"`
Email string `json:"email"`
rootPath string `json:-`
}
// create a base64 encoded auth string to store in config
func EncodeAuth(authConfig AuthConfig) string {
func EncodeAuth(authConfig *AuthConfig) string {
authStr := authConfig.Username + ":" + authConfig.Password
msg := []byte(authStr)
encoded := make([]byte, base64.StdEncoding.EncodedLen(len(msg)))
@ -34,50 +36,54 @@ func EncodeAuth(authConfig AuthConfig) string {
}
// decode the auth string
func DecodeAuth(authStr string) (AuthConfig, error) {
func DecodeAuth(authStr string) (*AuthConfig, error) {
decLen := base64.StdEncoding.DecodedLen(len(authStr))
decoded := make([]byte, decLen)
authByte := []byte(authStr)
n, err := base64.StdEncoding.Decode(decoded, authByte)
if err != nil {
return AuthConfig{}, err
return nil, err
}
if n > decLen {
return AuthConfig{}, errors.New("something went wrong decoding auth config")
return nil, fmt.Errorf("Something went wrong decoding auth config")
}
arr := strings.Split(string(decoded), ":")
if len(arr) != 2 {
return nil, fmt.Errorf("Invalid auth configuration file")
}
password := strings.Trim(arr[1], "\x00")
return AuthConfig{Username: arr[0], Password: password}, nil
return &AuthConfig{Username: arr[0], Password: password}, nil
}
// load up the auth config information and return values
func LoadConfig() (AuthConfig, error) {
if _, err := os.Stat(CONFIGFILE); err == nil {
b, err := ioutil.ReadFile(CONFIGFILE)
if err != nil {
return AuthConfig{}, err
}
arr := strings.Split(string(b), "\n")
orig_auth := strings.Split(arr[0], " = ")
orig_email := strings.Split(arr[1], " = ")
authConfig, err := DecodeAuth(orig_auth[1])
if err != nil {
return AuthConfig{}, err
}
authConfig.Email = orig_email[1]
return authConfig, nil
} else {
return AuthConfig{}, nil
// FIXME: use the internal golang config parser
func LoadConfig(rootPath string) (*AuthConfig, error) {
confFile := path.Join(rootPath, CONFIGFILE)
if _, err := os.Stat(confFile); err != nil {
return &AuthConfig{}, fmt.Errorf("The Auth config file is missing")
}
return AuthConfig{}, nil
b, err := ioutil.ReadFile(confFile)
if err != nil {
return nil, err
}
arr := strings.Split(string(b), "\n")
orig_auth := strings.Split(arr[0], " = ")
orig_email := strings.Split(arr[1], " = ")
authConfig, err := DecodeAuth(orig_auth[1])
if err != nil {
return nil, err
}
authConfig.Email = orig_email[1]
authConfig.rootPath = rootPath
return authConfig, nil
}
// save the auth config
func saveConfig(authStr string, email string) error {
func saveConfig(rootPath, authStr string, email string) error {
lines := "auth = " + authStr + "\n" + "email = " + email + "\n"
b := []byte(lines)
err := ioutil.WriteFile(CONFIGFILE, b, 0600)
err := ioutil.WriteFile(path.Join(rootPath, CONFIGFILE), b, 0600)
if err != nil {
return err
}
@ -85,7 +91,7 @@ func saveConfig(authStr string, email string) error {
}
// try to register/login to the registry server
func Login(authConfig AuthConfig) (string, error) {
func Login(authConfig *AuthConfig) (string, error) {
storeConfig := false
reqStatusCode := 0
var status string
@ -146,7 +152,7 @@ func Login(authConfig AuthConfig) (string, error) {
}
if storeConfig {
authStr := EncodeAuth(authConfig)
saveConfig(authStr, authConfig.Email)
saveConfig(authConfig.rootPath, authStr, authConfig.Email)
}
return status, nil
}

View file

@ -5,7 +5,7 @@ import (
)
func TestEncodeAuth(t *testing.T) {
newAuthConfig := AuthConfig{Username: "ken", Password: "test", Email: "test@example.com"}
newAuthConfig := &AuthConfig{Username: "ken", Password: "test", Email: "test@example.com"}
authStr := EncodeAuth(newAuthConfig)
decAuthConfig, err := DecodeAuth(authStr)
if err != nil {

View file

@ -69,17 +69,13 @@ func (srv *Server) CmdLogin(stdin io.ReadCloser, stdout io.Writer, args ...strin
var username string
var password string
var email string
authConfig, err := auth.LoadConfig()
if err != nil {
fmt.Fprintf(stdout, "Error : %s\n", err)
}
fmt.Fprint(stdout, "Username (", authConfig.Username, "): ")
fmt.Fprint(stdout, "Username (", srv.runtime.authConfig.Username, "): ")
fmt.Fscanf(stdin, "%s", &username)
if username == "" {
username = authConfig.Username
username = srv.runtime.authConfig.Username
}
if username != authConfig.Username {
if username != srv.runtime.authConfig.Username {
fmt.Fprint(stdout, "Password: ")
fmt.Fscanf(stdin, "%s", &password)
@ -87,16 +83,16 @@ func (srv *Server) CmdLogin(stdin io.ReadCloser, stdout io.Writer, args ...strin
return errors.New("Error : Password Required\n")
}
fmt.Fprint(stdout, "Email (", authConfig.Email, "): ")
fmt.Fprint(stdout, "Email (", srv.runtime.authConfig.Email, "): ")
fmt.Fscanf(stdin, "%s", &email)
if email == "" {
email = authConfig.Email
email = srv.runtime.authConfig.Email
}
} else {
password = authConfig.Password
email = authConfig.Email
password = srv.runtime.authConfig.Password
email = srv.runtime.authConfig.Email
}
newAuthConfig := auth.AuthConfig{Username: username, Password: password, Email: email}
newAuthConfig := &auth.AuthConfig{Username: username, Password: password, Email: email}
status, err := auth.Login(newAuthConfig)
if err != nil {
fmt.Fprintf(stdout, "Error : %s\n", err)
@ -445,7 +441,7 @@ func (srv *Server) CmdPush(stdin io.ReadCloser, stdout io.Writer, args ...string
}
// If it fails, try to get the repository
if repo, exists := srv.runtime.repositories.Repositories[cmd.Arg(0)]; exists {
if err := srv.runtime.graph.PushRepository(*user, cmd.Arg(0), repo); err != nil {
if err := srv.runtime.graph.PushRepository(*user, cmd.Arg(0), repo, srv.runtime.authConfig); err != nil {
return err
}
} else {
@ -453,7 +449,7 @@ func (srv *Server) CmdPush(stdin io.ReadCloser, stdout io.Writer, args ...string
}
return nil
}
return srv.runtime.graph.PushImage(img)
return srv.runtime.graph.PushImage(img, srv.runtime.authConfig)
}
func (srv *Server) CmdPull(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
@ -467,14 +463,14 @@ func (srv *Server) CmdPull(stdin io.ReadCloser, stdout io.Writer, args ...string
return nil
}
if srv.runtime.graph.LookupRemoteImage(cmd.Arg(0)) {
return srv.runtime.graph.PullImage(cmd.Arg(0))
if srv.runtime.graph.LookupRemoteImage(cmd.Arg(0), srv.runtime.authConfig) {
return srv.runtime.graph.PullImage(cmd.Arg(0), srv.runtime.authConfig)
}
if *user == "" {
return fmt.Errorf("Not loggin and no user specified\n")
}
// FIXME: Allow pull repo:tag
return srv.runtime.graph.PullRepository(*user, cmd.Arg(0), "", srv.runtime.repositories)
return srv.runtime.graph.PullRepository(*user, cmd.Arg(0), "", srv.runtime.repositories, srv.runtime.authConfig)
}
func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
@ -868,9 +864,6 @@ func NewServer() (*Server, error) {
if runtime.GOARCH != "amd64" {
log.Fatalf("The docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting.", runtime.GOARCH)
}
// if err != nil {
// return nil, err
// }
runtime, err := NewRuntime()
if err != nil {
return nil, err

View file

@ -49,10 +49,17 @@ func NewMultipleImgJson(src []byte) ([]*Image, error) {
// 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")
func (graph *Graph) getRemoteHistory(imgId string, authConfig *auth.AuthConfig) ([]*Image, error) {
client := &http.Client{}
req, err := http.NewRequest("GET", REGISTRY_ENDPOINT+"/images/"+imgId+"/history", nil)
if err != nil {
return nil, fmt.Errorf("Error while getting from the server: %s\n", err)
return nil, err
}
req.SetBasicAuth(authConfig.Username, authConfig.Password)
res, err := client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
@ -69,8 +76,15 @@ func (graph *Graph) getRemoteHistory(imgId string) ([]*Image, error) {
}
// Check if an image exists in the Registry
func (graph *Graph) LookupRemoteImage(imgId string) bool {
res, err := http.Get(REGISTRY_ENDPOINT + "/images/" + imgId + "/json")
func (graph *Graph) LookupRemoteImage(imgId string, authConfig *auth.AuthConfig) bool {
client := &http.Client{}
req, err := http.NewRequest("GET", REGISTRY_ENDPOINT+"/images/"+imgId+"/json", nil)
if err != nil {
return false
}
req.SetBasicAuth(authConfig.Username, authConfig.Password)
res, err := client.Do(req)
if err != nil {
return false
}
@ -79,12 +93,19 @@ func (graph *Graph) LookupRemoteImage(imgId string) bool {
// 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) {
func (graph *Graph) getRemoteImage(imgId string, authConfig *auth.AuthConfig) (*Image, Archive, error) {
client := &http.Client{}
// Get the Json
res, err := http.Get(REGISTRY_ENDPOINT + "/images/" + imgId + "/json")
req, err := http.NewRequest("GET", REGISTRY_ENDPOINT+"/images/"+imgId+"/json", nil)
if err != nil {
return nil, nil, fmt.Errorf("Error while getting from the server: %s\n", err)
}
req.SetBasicAuth(authConfig.Username, authConfig.Password)
res, err := client.Do(req)
if err != nil {
return nil, nil, err
}
defer res.Body.Close()
jsonString, err := ioutil.ReadAll(res.Body)
@ -106,8 +127,8 @@ func (graph *Graph) getRemoteImage(imgId string) (*Image, Archive, error) {
return img, res.Body, nil
}
func (graph *Graph) PullImage(imgId string) error {
history, err := graph.getRemoteHistory(imgId)
func (graph *Graph) PullImage(imgId string, authConfig *auth.AuthConfig) error {
history, err := graph.getRemoteHistory(imgId, authConfig)
if err != nil {
return err
}
@ -115,7 +136,7 @@ func (graph *Graph) PullImage(imgId string) error {
// FIXME: Lunch the getRemoteImage() in goroutines
for _, j := range history {
if !graph.Exists(j.Id) {
img, layer, err := graph.getRemoteImage(j.Id)
img, layer, err := graph.getRemoteImage(j.Id, authConfig)
if err != nil {
// FIXME: Keep goging in case of error?
return err
@ -129,23 +150,19 @@ func (graph *Graph) PullImage(imgId string) error {
}
// FIXME: Handle the askedTag parameter
func (graph *Graph) PullRepository(user, repoName, askedTag string, repositories *TagStore) error {
func (graph *Graph) PullRepository(user, repoName, askedTag string, repositories *TagStore, authConfig *auth.AuthConfig) error {
client := &http.Client{}
req, err := http.NewRequest("GET", REGISTRY_ENDPOINT+"/users/"+user+"/"+repoName, nil)
if err != nil {
return err
}
authStruct, err := auth.LoadConfig()
if err != nil {
return err
}
req.SetBasicAuth(authStruct.Username, authStruct.Password)
req.SetBasicAuth(authConfig.Username, authConfig.Password)
res, err := client.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
rawJson, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
@ -155,7 +172,7 @@ func (graph *Graph) PullRepository(user, repoName, askedTag string, repositories
return err
}
for tag, rev := range t {
if err = graph.PullImage(rev); err != nil {
if err = graph.PullImage(rev, authConfig); err != nil {
return err
}
if err = repositories.Set(repoName, tag, rev); err != nil {
@ -169,7 +186,7 @@ func (graph *Graph) PullRepository(user, repoName, askedTag string, repositories
}
// Push a local image to the registry with its history if needed
func (graph *Graph) PushImage(imgOrig *Image) error {
func (graph *Graph) PushImage(imgOrig *Image, authConfig *auth.AuthConfig) error {
client := &http.Client{}
// FIXME: Factorize the code
@ -186,6 +203,7 @@ func (graph *Graph) PushImage(imgOrig *Image) error {
if err != nil {
return err
}
req.SetBasicAuth(authConfig.Username, authConfig.Password)
res, err := client.Do(req)
if err != nil || res.StatusCode != 200 {
if res == nil {
@ -208,6 +226,7 @@ func (graph *Graph) PushImage(imgOrig *Image) error {
}
req2, err := http.NewRequest("PUT", REGISTRY_ENDPOINT+"/images/"+img.Id+"/layer", nil)
req2.SetBasicAuth(authConfig.Username, authConfig.Password)
res2, err := client.Do(req2)
if err != nil || res2.StatusCode != 307 {
return fmt.Errorf(
@ -230,7 +249,13 @@ func (graph *Graph) PushImage(imgOrig *Image) error {
img.Id, err)
}
req3, err := http.NewRequest("PUT", url.String(), layerData)
tmp, _ := ioutil.ReadAll(layerData2)
if err != nil {
return err
}
tmp, err := ioutil.ReadAll(layerData2)
if err != nil {
return err
}
req3.ContentLength = int64(len(tmp))
req3.TransferEncoding = []string{"none"}
@ -253,7 +278,7 @@ func (graph *Graph) PushImage(imgOrig *Image) error {
return nil
}
func (graph *Graph) pushTag(user, repo, revision, tag string) error {
func (graph *Graph) pushTag(user, repo, revision, tag string, authConfig *auth.AuthConfig) error {
if tag == "" {
tag = "lastest"
@ -264,6 +289,7 @@ func (graph *Graph) pushTag(user, repo, revision, tag string) error {
client := &http.Client{}
req, err := http.NewRequest("PUT", REGISTRY_ENDPOINT+"/users/"+user+"/"+repo+"/"+tag, strings.NewReader(revision))
req.Header.Add("Content-type", "application/json")
req.SetBasicAuth(authConfig.Username, authConfig.Password)
res, err := client.Do(req)
if err != nil {
return err
@ -278,17 +304,17 @@ func (graph *Graph) pushTag(user, repo, revision, tag string) error {
return nil
}
func (graph *Graph) PushRepository(user, repoName string, repo Repository) error {
func (graph *Graph) PushRepository(user, repoName string, repo Repository, authConfig *auth.AuthConfig) error {
for tag, imgId := range repo {
fmt.Printf("tag: %s, imgId: %s\n", tag, imgId)
img, err := graph.Get(imgId)
if err != nil {
return err
}
if err = graph.PushImage(img); err != nil {
if err = graph.PushImage(img, authConfig); err != nil {
return err
}
if err = graph.pushTag(user, repoName, imgId, tag); err != nil {
if err = graph.pushTag(user, repoName, imgId, tag, authConfig); err != nil {
return err
}
}

View file

@ -3,6 +3,7 @@ package docker
import (
"container/list"
"fmt"
"github.com/dotcloud/docker/auth"
"io"
"io/ioutil"
"log"
@ -20,6 +21,7 @@ type Runtime struct {
networkManager *NetworkManager
graph *Graph
repositories *TagStore
authConfig *auth.AuthConfig
}
var sysInitPath string
@ -246,6 +248,11 @@ func NewRuntimeFromDirectory(root string) (*Runtime, error) {
if err != nil {
return nil, err
}
authConfig, err := auth.LoadConfig(root)
if err != nil && authConfig == nil {
// If the auth file does not exist, keep going
return nil, err
}
runtime := &Runtime{
root: root,
@ -254,6 +261,7 @@ func NewRuntimeFromDirectory(root string) (*Runtime, error) {
networkManager: netManager,
graph: g,
repositories: repositories,
authConfig: authConfig,
}
if err := runtime.restore(); err != nil {