cri-o/server/container_status.go
Antonio Murdaca 22d055869d
server: container_status: return image name if available
If we create a container using the image ID like
771cd5947d5ea4bf8e8f4900dd357dbb67e7b16486c270f8274087d182d457c6, then
a call to container_status will return that same ID for the "Image"
field in ContainerStatusResponse.

This patch matches dockershim behavior and return the first tagged name
if available from the image store.

This is also needed to fix a failure in k8s e2d tests.

Reference:
https://github.com/kubernetes/kubernetes/pull/39298/files#diff-c7dd39479fd733354254e70845075db5R369
Reference:
67a5bf8454/test/e2e/framework/util.go (L1941)

Signed-off-by: Antonio Murdaca <runcom@redhat.com>
2017-05-22 16:37:46 +02:00

138 lines
3.4 KiB
Go

package server
import (
"encoding/json"
"fmt"
"github.com/Sirupsen/logrus"
"github.com/docker/distribution/reference"
"github.com/kubernetes-incubator/cri-o/oci"
rspec "github.com/opencontainers/runtime-spec/specs-go"
"golang.org/x/net/context"
pb "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
)
// ContainerStatus returns status of the container.
func (s *Server) ContainerStatus(ctx context.Context, req *pb.ContainerStatusRequest) (*pb.ContainerStatusResponse, error) {
logrus.Debugf("ContainerStatusRequest %+v", req)
c, err := s.getContainerFromRequest(req.ContainerId)
if err != nil {
return nil, err
}
if err = s.runtime.UpdateStatus(c); err != nil {
return nil, err
}
s.containerStateToDisk(c)
containerID := c.ID()
resp := &pb.ContainerStatusResponse{
Status: &pb.ContainerStatus{
Id: containerID,
Metadata: c.Metadata(),
Labels: c.Labels(),
Annotations: c.Annotations(),
},
}
mounts, err := s.getMounts(containerID)
if err != nil {
return nil, err
}
resp.Status.Mounts = mounts
imageName := c.Image().Image
status, err := s.storageImageServer.ImageStatus(s.imageContext, imageName)
if err != nil {
return nil, err
}
// TODO: use status.ID only if no digested names!!!
// need to modify ImageStatus to split tagged and digested!
resp.Status.ImageRef = status.ID
for _, n := range status.Names {
r, err := reference.ParseNormalizedNamed(n)
if err != nil {
return nil, fmt.Errorf("failed to normalize image name for Image: %v", err)
}
if tagged, isTagged := r.(reference.Tagged); isTagged {
imageName = reference.FamiliarString(tagged)
break
}
}
resp.Status.Image = &pb.ImageSpec{Image: imageName}
cState := s.runtime.ContainerStatus(c)
rStatus := pb.ContainerState_CONTAINER_UNKNOWN
switch cState.Status {
case oci.ContainerStateCreated:
rStatus = pb.ContainerState_CONTAINER_CREATED
created := cState.Created.UnixNano()
resp.Status.CreatedAt = created
case oci.ContainerStateRunning:
rStatus = pb.ContainerState_CONTAINER_RUNNING
created := cState.Created.UnixNano()
resp.Status.CreatedAt = created
started := cState.Started.UnixNano()
resp.Status.StartedAt = started
case oci.ContainerStateStopped:
rStatus = pb.ContainerState_CONTAINER_EXITED
created := cState.Created.UnixNano()
resp.Status.CreatedAt = created
started := cState.Started.UnixNano()
resp.Status.StartedAt = started
finished := cState.Finished.UnixNano()
resp.Status.FinishedAt = finished
resp.Status.ExitCode = cState.ExitCode
}
resp.Status.State = rStatus
logrus.Debugf("ContainerStatusResponse: %+v", resp)
return resp, nil
}
func (s *Server) getMounts(id string) ([]*pb.Mount, error) {
config, err := s.store.FromContainerDirectory(id, "config.json")
if err != nil {
return nil, err
}
var m rspec.Spec
if err = json.Unmarshal(config, &m); err != nil {
return nil, err
}
isRO := func(m rspec.Mount) bool {
var ro bool
for _, o := range m.Options {
if o == "ro" {
ro = true
break
}
}
return ro
}
isBind := func(m rspec.Mount) bool {
var bind bool
for _, o := range m.Options {
if o == "bind" || o == "rbind" {
bind = true
break
}
}
return bind
}
mounts := []*pb.Mount{}
for _, b := range m.Mounts {
if !isBind(b) {
continue
}
mounts = append(mounts, &pb.Mount{
ContainerPath: b.Destination,
HostPath: b.Source,
Readonly: isRO(b),
})
}
return mounts, nil
}