2016-07-19 18:53:57 +00:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
2017-04-10 13:00:24 +00:00
|
|
|
"encoding/base64"
|
|
|
|
"strings"
|
|
|
|
|
2016-10-20 20:13:41 +00:00
|
|
|
"github.com/Sirupsen/logrus"
|
2016-10-18 14:48:33 +00:00
|
|
|
"github.com/containers/image/copy"
|
2017-04-10 13:00:24 +00:00
|
|
|
"github.com/containers/image/types"
|
2016-07-19 18:53:57 +00:00
|
|
|
"golang.org/x/net/context"
|
2016-09-26 23:55:12 +00:00
|
|
|
pb "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
2016-07-19 18:53:57 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// PullImage pulls a image with authentication config.
|
|
|
|
func (s *Server) PullImage(ctx context.Context, req *pb.PullImageRequest) (*pb.PullImageResponse, error) {
|
2016-10-18 14:48:33 +00:00
|
|
|
logrus.Debugf("PullImageRequest: %+v", req)
|
|
|
|
// TODO(runcom?): deal with AuthConfig in req.GetAuth()
|
|
|
|
// TODO: what else do we need here? (Signatures when the story isn't just pulling from docker://)
|
|
|
|
image := ""
|
|
|
|
img := req.GetImage()
|
|
|
|
if img != nil {
|
2017-02-03 14:41:28 +00:00
|
|
|
image = img.Image
|
2016-07-20 08:42:55 +00:00
|
|
|
}
|
2017-06-07 17:54:02 +00:00
|
|
|
|
2017-04-10 13:00:24 +00:00
|
|
|
var (
|
|
|
|
username string
|
|
|
|
password string
|
|
|
|
)
|
|
|
|
if req.GetAuth() != nil {
|
|
|
|
username = req.GetAuth().Username
|
|
|
|
password = req.GetAuth().Password
|
|
|
|
if req.GetAuth().Auth != "" {
|
|
|
|
var err error
|
|
|
|
username, password, err = decodeDockerAuth(req.GetAuth().Auth)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-06-07 17:54:02 +00:00
|
|
|
options := ©.Options{
|
|
|
|
SourceCtx: &types.SystemContext{},
|
|
|
|
}
|
2017-04-10 13:00:24 +00:00
|
|
|
// a not empty username should be sufficient to decide whether to send auth
|
|
|
|
// or not I guess
|
|
|
|
if username != "" {
|
|
|
|
options.SourceCtx = &types.SystemContext{
|
|
|
|
DockerAuthConfig: &types.DockerAuthConfig{
|
|
|
|
Username: username,
|
|
|
|
Password: password,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
2017-06-07 17:54:02 +00:00
|
|
|
|
2017-06-08 13:45:34 +00:00
|
|
|
canPull, err := s.storageImageServer.CanPull(image, options)
|
2017-06-07 17:54:02 +00:00
|
|
|
if err != nil && !canPull {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// let's be smart, docker doesn't repull if image already exists.
|
|
|
|
if _, err := s.storageImageServer.ImageStatus(s.imageContext, image); err == nil {
|
|
|
|
return &pb.PullImageResponse{
|
|
|
|
ImageRef: image,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := s.storageImageServer.PullImage(s.imageContext, image, options); err != nil {
|
2016-07-20 08:42:55 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2017-01-17 11:21:32 +00:00
|
|
|
resp := &pb.PullImageResponse{
|
2017-02-03 14:41:28 +00:00
|
|
|
ImageRef: image,
|
2017-01-17 11:21:32 +00:00
|
|
|
}
|
2016-10-18 14:48:33 +00:00
|
|
|
logrus.Debugf("PullImageResponse: %+v", resp)
|
|
|
|
return resp, nil
|
2016-07-19 18:53:57 +00:00
|
|
|
}
|
2017-04-10 13:00:24 +00:00
|
|
|
|
|
|
|
func decodeDockerAuth(s string) (string, string, error) {
|
|
|
|
decoded, err := base64.StdEncoding.DecodeString(s)
|
|
|
|
if err != nil {
|
|
|
|
return "", "", err
|
|
|
|
}
|
|
|
|
parts := strings.SplitN(string(decoded), ":", 2)
|
|
|
|
if len(parts) != 2 {
|
|
|
|
// if it's invalid just skip, as docker does
|
|
|
|
return "", "", nil
|
|
|
|
}
|
|
|
|
user := parts[0]
|
|
|
|
password := strings.Trim(parts[1], "\x00")
|
|
|
|
return user, password, nil
|
|
|
|
}
|