2015-03-11 21:53:36 +00:00
|
|
|
/*
|
|
|
|
Copyright 2015 Google Inc. All rights reserved.
|
|
|
|
|
|
|
|
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 container
|
|
|
|
|
|
|
|
import (
|
2015-03-23 17:14:30 +00:00
|
|
|
"fmt"
|
2015-04-23 01:09:24 +00:00
|
|
|
"io"
|
2015-03-23 17:14:30 +00:00
|
|
|
"strings"
|
|
|
|
|
2015-03-11 21:53:36 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
2015-03-20 23:05:09 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/volume"
|
2015-03-11 21:53:36 +00:00
|
|
|
)
|
|
|
|
|
2015-04-21 20:02:50 +00:00
|
|
|
type Version interface {
|
|
|
|
// Compare compares two versions of the runtime. On success it returns -1
|
|
|
|
// if the version is less than the other, 1 if it is greater than the other,
|
|
|
|
// or 0 if they are equal.
|
|
|
|
Compare(other string) (int, error)
|
|
|
|
// String returns a string that represents the version.
|
|
|
|
String() string
|
|
|
|
}
|
|
|
|
|
2015-03-11 21:53:36 +00:00
|
|
|
// Runtime interface defines the interfaces that should be implemented
|
|
|
|
// by a container runtime.
|
|
|
|
type Runtime interface {
|
2015-04-21 20:02:50 +00:00
|
|
|
// Version returns the version information of the container runtime.
|
|
|
|
Version() (Version, error)
|
2015-03-11 21:53:36 +00:00
|
|
|
// GetPods returns a list containers group by pods. The boolean parameter
|
|
|
|
// specifies whether the runtime returns all containers including those already
|
|
|
|
// exited and dead containers (used for garbage collection).
|
|
|
|
GetPods(all bool) ([]*Pod, error)
|
|
|
|
// RunPod starts all the containers of a pod within a namespace.
|
2015-03-24 01:23:31 +00:00
|
|
|
RunPod(*api.Pod, map[string]volume.Volume) error
|
2015-03-11 21:53:36 +00:00
|
|
|
// KillPod kills all the containers of a pod.
|
2015-04-27 21:58:08 +00:00
|
|
|
KillPod(pod Pod) error
|
2015-03-11 21:53:36 +00:00
|
|
|
// RunContainerInPod starts a container within the same namespace of a pod.
|
2015-03-24 01:23:31 +00:00
|
|
|
RunContainerInPod(api.Container, *api.Pod, map[string]volume.Volume) error
|
2015-03-11 21:53:36 +00:00
|
|
|
// KillContainerInPod kills a container in the pod.
|
|
|
|
KillContainerInPod(api.Container, *api.Pod) error
|
|
|
|
// GetPodStatus retrieves the status of the pod, including the information of
|
|
|
|
// all containers in the pod.
|
2015-04-28 23:20:11 +00:00
|
|
|
GetPodStatus(*api.Pod) (api.PodStatus, error)
|
2015-03-11 21:53:36 +00:00
|
|
|
// GetContainers returns all containers on the node, including those are
|
|
|
|
// not managed by kubelet. If 'all' is false, then only running containers
|
|
|
|
// are returned.
|
|
|
|
GetContainers(all bool) ([]*Container, error)
|
2015-04-23 01:09:24 +00:00
|
|
|
// TODO(vmarmol): Merge RunInContainer and ExecInContainer.
|
|
|
|
// Runs the command in the container of the specified pod using nsinit.
|
2015-04-28 23:20:11 +00:00
|
|
|
// TODO(yifan): Use strong type for containerID.
|
|
|
|
RunInContainer(containerID string, cmd []string) error
|
2015-04-23 01:09:24 +00:00
|
|
|
// Runs the command in the container of the specified pod using nsenter.
|
|
|
|
// Attaches the processes stdin, stdout, and stderr. Optionally uses a
|
|
|
|
// tty.
|
2015-04-28 23:20:11 +00:00
|
|
|
// TODO(yifan): Use strong type for containerID.
|
|
|
|
ExecInContainer(containerID string, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool) error
|
2015-04-27 21:30:55 +00:00
|
|
|
// Forward the specified port from the specified pod to the stream.
|
2015-04-28 23:20:11 +00:00
|
|
|
PortForward(pod Pod, port uint16, stream io.ReadWriteCloser) error
|
|
|
|
// PullImage pulls an image from the network to local storage.
|
|
|
|
PullImage(image string) error
|
2015-04-23 17:35:14 +00:00
|
|
|
// IsImagePresent checks whether the container image is already in the local storage.
|
|
|
|
IsImagePresent(image string) (bool, error)
|
2015-04-29 03:25:25 +00:00
|
|
|
// GetContainerLogs returns logs of a specific container. By
|
|
|
|
// default, it returns a snapshot of the container log. Set 'follow' to true to
|
|
|
|
// stream the log. Set 'follow' to false and specify the number of lines (e.g.
|
|
|
|
// "100" or "all") to tail the log.
|
|
|
|
GetContainerLogs(containerID, tail string, follow bool, stdout, stderr io.Writer) (err error)
|
2015-03-11 21:53:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Pod is a group of containers, with the status of the pod.
|
|
|
|
type Pod struct {
|
|
|
|
// The ID of the pod, which can be used to retrieve a particular pod
|
|
|
|
// from the pod list returned by GetPods().
|
|
|
|
ID types.UID
|
|
|
|
// The name and namespace of the pod, which is readable by human.
|
|
|
|
Name string
|
|
|
|
Namespace string
|
|
|
|
// List of containers that belongs to this pod. It may contain only
|
|
|
|
// running containers, or mixed with dead ones (when GetPods(true)).
|
|
|
|
Containers []*Container
|
|
|
|
// The status of the pod.
|
|
|
|
// TODO(yifan): Inspect and get the statuses for all pods can be expensive,
|
|
|
|
// maybe we want to get one pod's status at a time (e.g. GetPodStatus()
|
|
|
|
// for the particular pod after we GetPods()).
|
|
|
|
Status api.PodStatus
|
|
|
|
}
|
|
|
|
|
2015-04-22 23:19:05 +00:00
|
|
|
// ContainerID is a type that identifies a container.
|
|
|
|
type ContainerID struct {
|
|
|
|
// The type of the container runtime. e.g. 'docker', 'rkt'.
|
|
|
|
Type string
|
|
|
|
// The identification of the container, this is comsumable by
|
|
|
|
// the underlying container runtime. (Note that the container
|
|
|
|
// runtime interface still takes the whole struct as input).
|
|
|
|
ID string
|
|
|
|
}
|
|
|
|
|
|
|
|
func BuildContainerID(typ, ID string) ContainerID {
|
|
|
|
return ContainerID{Type: typ, ID: ID}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ContainerID) ParseString(data string) error {
|
|
|
|
// Trim the quotes and split the type and ID.
|
|
|
|
parts := strings.Split(strings.Trim(data, "\""), "://")
|
|
|
|
if len(parts) != 2 {
|
|
|
|
return fmt.Errorf("invalid container ID: %q", data)
|
|
|
|
}
|
|
|
|
c.Type, c.ID = parts[0], parts[1]
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ContainerID) String() string {
|
|
|
|
return fmt.Sprintf("%s://%s", c.Type, c.ID)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ContainerID) MarshalJSON() ([]byte, error) {
|
|
|
|
return []byte(fmt.Sprintf("%q", c.String())), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ContainerID) UnmarshalJSON(data []byte) error {
|
|
|
|
return c.ParseString(string(data))
|
|
|
|
}
|
|
|
|
|
2015-03-11 21:53:36 +00:00
|
|
|
// Container provides the runtime information for a container, such as ID, hash,
|
|
|
|
// status of the container.
|
|
|
|
type Container struct {
|
|
|
|
// The ID of the container, used by the container runtime to identify
|
|
|
|
// a container.
|
|
|
|
ID types.UID
|
|
|
|
// The name of the container, which should be the same as specified by
|
|
|
|
// api.Container.
|
|
|
|
Name string
|
|
|
|
// The image name of the container.
|
|
|
|
Image string
|
|
|
|
// Hash of the container, used for comparison. Optional for containers
|
|
|
|
// not managed by kubelet.
|
|
|
|
Hash uint64
|
2015-03-20 21:16:55 +00:00
|
|
|
// The timestamp of the creation time of the container.
|
|
|
|
// TODO(yifan): Consider to move it to api.ContainerStatus.
|
|
|
|
Created int64
|
|
|
|
}
|
|
|
|
|
2015-03-26 18:59:41 +00:00
|
|
|
// RunContainerOptions specify the options which are necessary for running containers
|
|
|
|
type RunContainerOptions struct {
|
|
|
|
// The environment variables, they are in the form of 'key=value'.
|
|
|
|
Envs []string
|
|
|
|
// The mounts for the containers, they are in the form of:
|
|
|
|
// 'hostPath:containerPath', or
|
|
|
|
// 'hostPath:containerPath:ro', if the path read only.
|
|
|
|
Binds []string
|
|
|
|
// If the container has specified the TerminationMessagePath, then
|
|
|
|
// this directory will be used to create and mount the log file to
|
|
|
|
// container.TerminationMessagePath
|
|
|
|
PodContainerDir string
|
|
|
|
// The list of DNS servers for the container to use.
|
|
|
|
DNS []string
|
|
|
|
// The list of DNS search domains.
|
|
|
|
DNSSearch []string
|
|
|
|
// Docker namespace identifiers(currently we have 'NetMode' and 'IpcMode'.
|
|
|
|
// These are for docker to attach a container in a pod to the pod infra
|
|
|
|
// container's namespace.
|
|
|
|
// TODO(yifan): Remove these after we pushed the pod infra container logic
|
|
|
|
// into docker's container runtime.
|
|
|
|
NetMode string
|
|
|
|
IpcMode string
|
|
|
|
}
|
|
|
|
|
2015-03-20 21:16:55 +00:00
|
|
|
type Pods []*Pod
|
|
|
|
|
2015-04-06 23:58:34 +00:00
|
|
|
// FindPodByID finds and returns a pod in the pod list by UID. It will return an empty pod
|
2015-03-20 21:16:55 +00:00
|
|
|
// if not found.
|
|
|
|
func (p Pods) FindPodByID(podUID types.UID) Pod {
|
|
|
|
for i := range p {
|
|
|
|
if p[i].ID == podUID {
|
|
|
|
return *p[i]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Pod{}
|
|
|
|
}
|
|
|
|
|
2015-04-06 23:58:34 +00:00
|
|
|
// FindPodByFullName finds and returns a pod in the pod list by the full name.
|
|
|
|
// It will return an empty pod if not found.
|
|
|
|
func (p Pods) FindPodByFullName(podFullName string) Pod {
|
|
|
|
for i := range p {
|
|
|
|
if BuildPodFullName(p[i].Name, p[i].Namespace) == podFullName {
|
|
|
|
return *p[i]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Pod{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// FindPod combines FindPodByID and FindPodByFullName, it finds and returns a pod in the
|
|
|
|
// pod list either by the full name or the pod ID. It will return an empty pod
|
|
|
|
// if not found.
|
|
|
|
func (p Pods) FindPod(podFullName string, podUID types.UID) Pod {
|
|
|
|
if len(podFullName) > 0 {
|
|
|
|
return p.FindPodByFullName(podFullName)
|
|
|
|
}
|
|
|
|
return p.FindPodByID(podUID)
|
|
|
|
}
|
|
|
|
|
2015-03-20 21:16:55 +00:00
|
|
|
// FindContainerByName returns a container in the pod with the given name.
|
|
|
|
// When there are multiple containers with the same name, the first match will
|
|
|
|
// be returned.
|
|
|
|
func (p *Pod) FindContainerByName(containerName string) *Container {
|
|
|
|
for _, c := range p.Containers {
|
|
|
|
if c.Name == containerName {
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
2015-03-11 21:53:36 +00:00
|
|
|
}
|
2015-03-23 17:14:30 +00:00
|
|
|
|
|
|
|
// GetPodFullName returns a name that uniquely identifies a pod.
|
|
|
|
func GetPodFullName(pod *api.Pod) string {
|
|
|
|
// Use underscore as the delimiter because it is not allowed in pod name
|
|
|
|
// (DNS subdomain format), while allowed in the container name format.
|
|
|
|
return fmt.Sprintf("%s_%s", pod.Name, pod.Namespace)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build the pod full name from pod name and namespace.
|
|
|
|
func BuildPodFullName(name, namespace string) string {
|
|
|
|
return name + "_" + namespace
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the pod full name.
|
|
|
|
func ParsePodFullName(podFullName string) (string, string, error) {
|
|
|
|
parts := strings.Split(podFullName, "_")
|
|
|
|
if len(parts) != 2 {
|
|
|
|
return "", "", fmt.Errorf("failed to parse the pod full name %q", podFullName)
|
|
|
|
}
|
|
|
|
return parts[0], parts[1], nil
|
|
|
|
}
|