dockershim: implement ContainerStatus()

This commit is contained in:
Yu-Ju Hong 2016-07-25 14:39:31 -07:00
parent 7aa592bfa3
commit 03971d3992
5 changed files with 137 additions and 9 deletions

View File

@ -19,12 +19,15 @@ package dockershim
import (
"fmt"
"io"
"time"
dockertypes "github.com/docker/engine-api/types"
dockercontainer "github.com/docker/engine-api/types/container"
dockerfilters "github.com/docker/engine-api/types/filters"
dockerstrslice "github.com/docker/engine-api/types/strslice"
runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
"k8s.io/kubernetes/pkg/kubelet/dockertools"
)
// ListContainers lists all containers matching the filter.
@ -190,14 +193,112 @@ func (ds *dockerService) RemoveContainer(rawContainerID string) error {
return ds.client.RemoveContainer(rawContainerID, dockertypes.ContainerRemoveOptions{RemoveVolumes: true})
}
func getContainerTimestamps(r *dockertypes.ContainerJSON) (time.Time, time.Time, time.Time, error) {
var createdAt, startedAt, finishedAt time.Time
var err error
createdAt, err = dockertools.ParseDockerTimestamp(r.Created)
if err != nil {
return createdAt, startedAt, finishedAt, err
}
startedAt, err = dockertools.ParseDockerTimestamp(r.State.StartedAt)
if err != nil {
return createdAt, startedAt, finishedAt, err
}
finishedAt, err = dockertools.ParseDockerTimestamp(r.State.FinishedAt)
if err != nil {
return createdAt, startedAt, finishedAt, err
}
return createdAt, startedAt, finishedAt, nil
}
// ContainerStatus returns the container status.
// TODO: Implement the function.
func (ds *dockerService) ContainerStatus(rawContainerID string) (*runtimeApi.ContainerStatus, error) {
return nil, fmt.Errorf("not implemented")
r, err := ds.client.InspectContainer(rawContainerID)
if err != nil {
return nil, err
}
// Parse the timstamps.
createdAt, startedAt, finishedAt, err := getContainerTimestamps(r)
if err != nil {
return nil, fmt.Errorf("failed to parse timestamp for container %q: %v", rawContainerID, err)
}
// Convert the mounts.
mounts := []*runtimeApi.Mount{}
for _, m := range r.Mounts {
readonly := !m.RW
mounts = append(mounts, &runtimeApi.Mount{
Name: &m.Name,
HostPath: &m.Source,
ContainerPath: &m.Destination,
Readonly: &readonly,
// Note: Can't set SeLinuxRelabel
})
}
// Interpret container states.
var state runtimeApi.ContainerState
var reason string
if r.State.Running {
// Container is running.
state = runtimeApi.ContainerState_RUNNING
} else {
// Container is *not* running. We need to get more details.
// * Case 1: container has run and exited with non-zero finishedAt
// time.
// * Case 2: container has failed to start; it has a zero finishedAt
// time, but a non-zero exit code.
// * Case 3: container has been created, but not started (yet).
if !finishedAt.IsZero() { // Case 1
state = runtimeApi.ContainerState_EXITED
switch {
case r.State.OOMKilled:
// TODO: consider exposing OOMKilled via the runtimeAPI.
// Note: if an application handles OOMKilled gracefully, the
// exit code could be zero.
reason = "OOMKilled"
case r.State.ExitCode == 0:
reason = "Completed"
default:
reason = fmt.Sprintf("Error: %s", r.State.Error)
}
} else if !finishedAt.IsZero() && r.State.ExitCode != 0 { // Case 2
state = runtimeApi.ContainerState_EXITED
// Adjust finshedAt and startedAt time to createdAt time to avoid
// the confusion.
finishedAt, startedAt = createdAt, createdAt
reason = "ContainerCannotRun"
} else { // Case 3
state = runtimeApi.ContainerState_CREATED
}
}
// Convert to unix timestamps.
ct, st, ft := createdAt.Unix(), startedAt.Unix(), finishedAt.Unix()
exitCode := int32(r.State.ExitCode)
return &runtimeApi.ContainerStatus{
Id: &r.ID,
Name: &r.Name,
Image: &runtimeApi.ImageSpec{Image: &r.Config.Image},
ImageRef: &r.Image,
Mounts: mounts,
ExitCode: &exitCode,
State: &state,
CreatedAt: &ct,
StartedAt: &st,
FinishedAt: &ft,
Reason: &reason,
// TODO: We write annotations as labels on the docker containers. All
// these annotations will be read back as labels. Need to fix this.
Labels: r.Config.Labels,
}, nil
}
// Exec execute a command in the container.
// TODO: Implement the function.
// TODO: Need to handle terminal resizing before implementing this function.
// https://github.com/kubernetes/kubernetes/issues/29579.
func (ds *dockerService) Exec(rawContainerID string, cmd []string, tty bool, stdin io.Reader, stdout, stderr io.WriteCloser) error {
return fmt.Errorf("not implemented")
}

View File

@ -0,0 +1,27 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package dockershim
import (
"k8s.io/kubernetes/pkg/kubelet/dockertools"
)
func newFakeDockerSevice() *dockerService {
return &dockerService{
client: dockertools.NewFakeDockerClient(),
}
}

View File

@ -139,7 +139,7 @@ func (cgc *containerGC) evictableContainers(minAge time.Duration) (containersByE
continue
}
created, err := parseDockerTimestamp(data.Created)
created, err := ParseDockerTimestamp(data.Created)
if err != nil {
glog.Errorf("Failed to parse Created timestamp %q for container %q", data.Created, container.ID)
}

View File

@ -374,13 +374,13 @@ func (dm *DockerManager) inspectContainer(id string, podName, podNamespace strin
glog.Errorf("Failed to parse %q timestamp %q for container %q of pod %q", label, s, id, kubecontainer.BuildPodFullName(podName, podNamespace))
}
var createdAt, startedAt, finishedAt time.Time
if createdAt, err = parseDockerTimestamp(iResult.Created); err != nil {
if createdAt, err = ParseDockerTimestamp(iResult.Created); err != nil {
parseTimestampError("Created", iResult.Created)
}
if startedAt, err = parseDockerTimestamp(iResult.State.StartedAt); err != nil {
if startedAt, err = ParseDockerTimestamp(iResult.State.StartedAt); err != nil {
parseTimestampError("StartedAt", iResult.State.StartedAt)
}
if finishedAt, err = parseDockerTimestamp(iResult.State.FinishedAt); err != nil {
if finishedAt, err = ParseDockerTimestamp(iResult.State.FinishedAt); err != nil {
parseTimestampError("FinishedAt", iResult.State.FinishedAt)
}

View File

@ -531,8 +531,8 @@ func (d *kubeDockerClient) getTimeoutContext() (context.Context, context.CancelF
return context.WithTimeout(context.Background(), d.timeout)
}
// parseDockerTimestamp parses the timestamp returned by DockerInterface from string to time.Time
func parseDockerTimestamp(s string) (time.Time, error) {
// ParseDockerTimestamp parses the timestamp returned by DockerInterface from string to time.Time
func ParseDockerTimestamp(s string) (time.Time, error) {
// Timestamp returned by Docker is in time.RFC3339Nano format.
return time.Parse(time.RFC3339Nano, s)
}