Merge pull request #29580 from yujuhong/dshim2

Automatic merge from submit-queue

dockershim: Implement more functions.

Based on #29553. Only the last two commits are new.
This commit is contained in:
k8s-merge-robot 2016-07-29 12:55:56 -07:00 committed by GitHub
commit 94b5d52b90
6 changed files with 156 additions and 16 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

@ -22,6 +22,7 @@ import (
"k8s.io/kubernetes/pkg/api"
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
"k8s.io/kubernetes/pkg/kubelet/dockertools"
"k8s.io/kubernetes/pkg/util/term"
)
@ -31,11 +32,11 @@ import (
// TODO: implement the methods in this file.
func (ds *dockerService) AttachContainer(id kubecontainer.ContainerID, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan term.Size) (err error) {
return fmt.Errorf("not implemented")
return dockertools.AttachContainer(ds.client, id, stdin, stdout, stderr, tty, resize)
}
func (ds *dockerService) GetContainerLogs(pod *api.Pod, containerID kubecontainer.ContainerID, logOptions *api.PodLogOptions, stdout, stderr io.Writer) (err error) {
return fmt.Errorf("not implemented")
return dockertools.GetContainerLogs(ds.client, pod, containerID, logOptions, stdout, stderr)
}
func (ds *dockerService) PortForward(pod *kubecontainer.Pod, port uint16, stream io.ReadWriteCloser) error {

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

@ -285,7 +285,13 @@ func NewDockerManager(
// stream the log. Set 'follow' to false and specify the number of lines (e.g.
// "100" or "all") to tail the log.
// TODO: Make 'RawTerminal' option flagable.
func (dm *DockerManager) GetContainerLogs(pod *api.Pod, containerID kubecontainer.ContainerID, logOptions *api.PodLogOptions, stdout, stderr io.Writer) (err error) {
func (dm *DockerManager) GetContainerLogs(pod *api.Pod, containerID kubecontainer.ContainerID, logOptions *api.PodLogOptions, stdout, stderr io.Writer) error {
return GetContainerLogs(dm.client, pod, containerID, logOptions, stdout, stderr)
}
// Temporarily export this function to share with dockershim.
// TODO: clean this up.
func GetContainerLogs(client DockerInterface, pod *api.Pod, containerID kubecontainer.ContainerID, logOptions *api.PodLogOptions, stdout, stderr io.Writer) error {
var since int64
if logOptions.SinceSeconds != nil {
t := unversioned.Now().Add(-time.Duration(*logOptions.SinceSeconds) * time.Second)
@ -309,8 +315,7 @@ func (dm *DockerManager) GetContainerLogs(pod *api.Pod, containerID kubecontaine
ErrorStream: stderr,
RawTerminal: false,
}
err = dm.client.Logs(containerID.ID, opts, sopts)
return
return client.Logs(containerID.ID, opts, sopts)
}
var (
@ -374,13 +379,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)
}
@ -1123,10 +1128,16 @@ func (dm *DockerManager) ExecInContainer(containerID kubecontainer.ContainerID,
}
func (dm *DockerManager) AttachContainer(containerID kubecontainer.ContainerID, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan term.Size) error {
return AttachContainer(dm.client, containerID, stdin, stdout, stderr, tty, resize)
}
// Temporarily export this function to share with dockershim.
// TODO: clean this up.
func AttachContainer(client DockerInterface, containerID kubecontainer.ContainerID, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan term.Size) error {
// Have to start this before the call to client.AttachToContainer because client.AttachToContainer is a blocking
// call :-( Otherwise, resize events don't get processed and the terminal never resizes.
kubecontainer.HandleResizing(resize, func(size term.Size) {
dm.client.ResizeContainerTTY(containerID.ID, int(size.Height), int(size.Width))
client.ResizeContainerTTY(containerID.ID, int(size.Height), int(size.Width))
})
// TODO(random-liu): Do we really use the *Logs* field here?
@ -1142,7 +1153,7 @@ func (dm *DockerManager) AttachContainer(containerID kubecontainer.ContainerID,
ErrorStream: stderr,
RawTerminal: tty,
}
return dm.client.AttachToContainer(containerID.ID, opts, sopts)
return client.AttachToContainer(containerID.ID, opts, sopts)
}
func noPodInfraContainerError(podName, podNamespace string) error {

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)
}