container_create: correctly set user

We had a bug in ImageStatus where we weren't returning the default
image user if set, thus running all containers as root despite a user
being set in the image config. We weren't populating the Username field
of ImageStatus.
This patch fixes that along with the handling of multiple images based
on the registry patch for multiple images.
It also fixes ListImages to return Username as well.

Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
Antonio Murdaca 2018-02-14 13:16:55 +01:00
parent 9128ffc226
commit 96fb47213e
No known key found for this signature in database
GPG key ID: B2BEAD150DE936B9
4 changed files with 103 additions and 28 deletions

View file

@ -39,6 +39,7 @@ type ImageResult struct {
Size *uint64 Size *uint64
Digest digest.Digest Digest digest.Digest
ConfigDigest digest.Digest ConfigDigest digest.Digest
User string
} }
type indexInfo struct { type indexInfo struct {
@ -181,6 +182,16 @@ func (svc *imageService) ListImages(systemContext *types.SystemContext, filter s
if err != nil { if err != nil {
return nil, err return nil, err
} }
imageFull, err := ref.NewImage(systemContext)
if err != nil {
return nil, err
}
defer imageFull.Close()
imageConfig, err := imageFull.OCIConfig()
if err != nil {
return nil, err
}
name, tags, digests := sortNamesByType(image.Names) name, tags, digests := sortNamesByType(image.Names)
imageDigest, repoDigests := svc.makeRepoDigests(digests, tags, image.ID) imageDigest, repoDigests := svc.makeRepoDigests(digests, tags, image.ID)
results = append(results, ImageResult{ results = append(results, ImageResult{
@ -191,6 +202,7 @@ func (svc *imageService) ListImages(systemContext *types.SystemContext, filter s
Size: size, Size: size,
Digest: imageDigest, Digest: imageDigest,
ConfigDigest: configDigest, ConfigDigest: configDigest,
User: imageConfig.Config.User,
}) })
} }
} else { } else {
@ -213,6 +225,16 @@ func (svc *imageService) ListImages(systemContext *types.SystemContext, filter s
if err != nil { if err != nil {
return nil, err return nil, err
} }
imageFull, err := ref.NewImage(systemContext)
if err != nil {
return nil, err
}
defer imageFull.Close()
imageConfig, err := imageFull.OCIConfig()
if err != nil {
return nil, err
}
name, tags, digests := sortNamesByType(image.Names) name, tags, digests := sortNamesByType(image.Names)
imageDigest, repoDigests := svc.makeRepoDigests(digests, tags, image.ID) imageDigest, repoDigests := svc.makeRepoDigests(digests, tags, image.ID)
results = append(results, ImageResult{ results = append(results, ImageResult{
@ -223,6 +245,7 @@ func (svc *imageService) ListImages(systemContext *types.SystemContext, filter s
Size: size, Size: size,
Digest: imageDigest, Digest: imageDigest,
ConfigDigest: configDigest, ConfigDigest: configDigest,
User: imageConfig.Config.User,
}) })
} }
} }
@ -246,6 +269,16 @@ func (svc *imageService) ImageStatus(systemContext *types.SystemContext, nameOrI
if err != nil { if err != nil {
return nil, err return nil, err
} }
imageFull, err := ref.NewImage(systemContext)
if err != nil {
return nil, err
}
defer imageFull.Close()
imageConfig, err := imageFull.OCIConfig()
if err != nil {
return nil, err
}
img, err := ref.NewImageSource(systemContext) img, err := ref.NewImageSource(systemContext)
if err != nil { if err != nil {
@ -268,6 +301,7 @@ func (svc *imageService) ImageStatus(systemContext *types.SystemContext, nameOrI
Size: size, Size: size,
Digest: imageDigest, Digest: imageDigest,
ConfigDigest: configDigest, ConfigDigest: configDigest,
User: imageConfig.Config.User,
} }
return &result, nil return &result, nil

View file

@ -449,7 +449,7 @@ func setupContainerUser(specgen *generate.Generator, rootfs string, sc *pb.Linux
containerUser := "" containerUser := ""
// Case 1: run as user is set by kubelet // Case 1: run as user is set by kubelet
if sc.GetRunAsUser() != nil { if sc.GetRunAsUser() != nil {
containerUser = strconv.FormatInt(sc.GetRunAsUser().Value, 10) containerUser = strconv.FormatInt(sc.GetRunAsUser().GetValue(), 10)
} else { } else {
// Case 2: run as username is set by kubelet // Case 2: run as username is set by kubelet
userName := sc.GetRunAsUsername() userName := sc.GetRunAsUsername()

View file

@ -31,20 +31,20 @@ func (s *Server) ListImages(ctx context.Context, req *pb.ListImagesRequest) (res
} }
resp = &pb.ListImagesResponse{} resp = &pb.ListImagesResponse{}
for _, result := range results { for _, result := range results {
if result.Size != nil { resImg := &pb.Image{
resp.Images = append(resp.Images, &pb.Image{
Id: result.ID, Id: result.ID,
RepoTags: result.RepoTags, RepoTags: result.RepoTags,
RepoDigests: result.RepoDigests, RepoDigests: result.RepoDigests,
Size_: *result.Size,
})
} else {
resp.Images = append(resp.Images, &pb.Image{
Id: result.ID,
RepoTags: result.RepoTags,
RepoDigests: result.RepoDigests,
})
} }
uid, username := getUserFromImage(result.User)
if uid != nil {
resImg.Uid = &pb.Int64Value{Value: *uid}
}
resImg.Username = username
if result.Size != nil {
resImg.Size_ = *result.Size
}
resp.Images = append(resp.Images, resImg)
} }
logrus.Debugf("ListImagesResponse: %+v", resp) logrus.Debugf("ListImagesResponse: %+v", resp)
return resp, nil return resp, nil

View file

@ -2,6 +2,8 @@ package server
import ( import (
"fmt" "fmt"
"strconv"
"strings"
"time" "time"
"github.com/containers/storage" "github.com/containers/storage"
@ -37,14 +39,21 @@ func (s *Server) ImageStatus(ctx context.Context, req *pb.ImageStatusRequest) (r
return nil, err return nil, err
} }
} }
// match just the first registry as that's what kube meant var (
image = images[0] notfound bool
lastErr error
)
for _, image := range images {
status, err := s.StorageImageServer().ImageStatus(s.ImageContext(), image) status, err := s.StorageImageServer().ImageStatus(s.ImageContext(), image)
if err != nil { if err != nil {
if errors.Cause(err) == storage.ErrImageUnknown { if errors.Cause(err) == storage.ErrImageUnknown {
return &pb.ImageStatusResponse{}, nil logrus.Warnf("imageStatus: can't find %s", image)
notfound = true
continue
} }
return nil, err logrus.Warnf("imageStatus: error getting status from %s: %v", image, err)
lastErr = err
continue
} }
resp = &pb.ImageStatusResponse{ resp = &pb.ImageStatusResponse{
Image: &pb.Image{ Image: &pb.Image{
@ -54,6 +63,38 @@ func (s *Server) ImageStatus(ctx context.Context, req *pb.ImageStatusRequest) (r
Size_: *status.Size, Size_: *status.Size,
}, },
} }
uid, username := getUserFromImage(status.User)
if uid != nil {
resp.Image.Uid = &pb.Int64Value{Value: *uid}
}
resp.Image.Username = username
break
}
if lastErr != nil && resp == nil {
return nil, lastErr
}
if notfound && resp == nil {
return &pb.ImageStatusResponse{}, nil
}
logrus.Debugf("ImageStatusResponse: %+v", resp) logrus.Debugf("ImageStatusResponse: %+v", resp)
return resp, nil return resp, nil
} }
// getUserFromImage gets uid or user name of the image user.
// If user is numeric, it will be treated as uid; or else, it is treated as user name.
func getUserFromImage(user string) (*int64, string) {
// return both empty if user is not specified in the image.
if user == "" {
return nil, ""
}
// split instances where the id may contain user:group
user = strings.Split(user, ":")[0]
// user could be either uid or user name. Try to interpret as numeric uid.
uid, err := strconv.ParseInt(user, 10, 64)
if err != nil {
// If user is non numeric, assume it's user name.
return nil, user
}
// If user is a numeric uid.
return &uid, ""
}