kubelet/rkt: minor updates to match rkt v0.7.0.

pull/6/head
Yifan Gu 2015-08-13 16:39:17 -07:00
parent ea59172874
commit 558e692f93
3 changed files with 74 additions and 68 deletions

View File

@ -25,28 +25,26 @@ import (
// be returned to kubelet, and kubelet will use this for
// container level operations.
type containerID struct {
uuid string // uuid of the pod.
appName string // name of the app in that pod.
imageID string // id of the image. TODO(yifan): Depreciate this.
uuid string // rkt uuid of the pod.
appName string // Name of the app in that pod.
}
// buildContainerID constructs the containers's ID using containerID,
// which containers the pod uuid and the container name.
// The result can be used to globally identify a container.
// which consists of the pod uuid and the container name.
// The result can be used to uniquely identify a container.
func buildContainerID(c *containerID) string {
return fmt.Sprintf("%s:%s:%s", c.uuid, c.appName, c.imageID)
return fmt.Sprintf("%s:%s", c.uuid, c.appName)
}
// parseContainerID parses the containerID into pod uuid and the container name. The
// results can be used to get more information of the container.
func parseContainerID(id string) (*containerID, error) {
tuples := strings.Split(id, ":")
if len(tuples) != 3 {
if len(tuples) != 2 {
return nil, fmt.Errorf("rkt: cannot parse container ID for: %v", id)
}
return &containerID{
uuid: tuples[0],
appName: tuples[1],
imageID: tuples[2],
}, nil
}

View File

@ -38,6 +38,9 @@ const (
Deleting = "deleting" // This covers pod.isExitedDeleting and pod.isDeleting.
Exited = "exited" // This covers pod.isExited and pod.isExitedGarbage.
Garbage = "garbage"
// The prefix before the app name for each app's exit code in the output of 'rkt status'.
exitCodePrefix = "app-"
)
// podInfo is the internal type that represents the state of
@ -49,12 +52,21 @@ type podInfo struct {
ip string
// The pid of the init process in the pod.
pid int
// A map from image hashes to exit codes.
// TODO(yifan): Should be appName to exit code in the future.
// A map of [app name]:[exit code].
exitCodes map[string]int
// TODO(yifan): Expose [app name]:[image id].
}
// parsePodInfo parses the result of 'rkt status' into podInfo.
//
// Example output of 'rkt status':
//
// state=exited
// pid=-1
// exited=true
// app-etcd=0 # The exit code of the app "etcd" in the pod.
// app-redis=0 # The exit code of the app "redis" in the pod.
//
func parsePodInfo(status []string) (*podInfo, error) {
p := &podInfo{
pid: -1,
@ -80,12 +92,14 @@ func parsePodInfo(status []string) (*podInfo, error) {
}
p.pid = pid
}
if strings.HasPrefix(tuples[0], "sha512") {
if strings.HasPrefix(tuples[0], exitCodePrefix) {
exitcode, err := strconv.Atoi(tuples[1])
if err != nil {
return nil, fmt.Errorf("cannot parse exit code from %s : %v", tuples[1], err)
}
p.exitCodes[tuples[0]] = exitcode
appName := strings.TrimPrefix(tuples[0], exitCodePrefix)
p.exitCodes[appName] = exitcode
}
}
return p, nil
@ -94,30 +108,27 @@ func parsePodInfo(status []string) (*podInfo, error) {
// getIPFromNetworkInfo returns the IP of a pod by parsing the network info.
// The network info looks like this:
//
// default:ip4=172.16.28.3, database:ip4=172.16.28.42
// default:ip4=172.16.28.3
// database:ip4=172.16.28.42
//
func getIPFromNetworkInfo(networkInfo string) string {
parts := strings.Split(networkInfo, ",")
for _, part := range parts {
if strings.HasPrefix(part, "default:") {
tuples := strings.Split(part, "=")
if len(tuples) == 2 {
return tuples[1]
}
}
}
return ""
}
// getContainerStatus creates the api.containerStatus of a container from the podInfo.
// TODO(yifan): Get more detailed info such as Image, ImageID, etc.
func (p *podInfo) getContainerStatus(container *kubecontainer.Container) api.ContainerStatus {
var status api.ContainerStatus
status.Name = container.Name
status.Image = container.Image
containerID, _ := parseContainerID(string(container.ID))
status.ImageID = containerID.imageID
status.ContainerID = string(container.ID)
// TODO(yifan): Add image ID info.
switch p.state {
case Running:
@ -130,11 +141,12 @@ func (p *podInfo) getContainerStatus(container *kubecontainer.Container) api.Con
case Embryo, Preparing, Prepared:
status.State = api.ContainerState{Waiting: &api.ContainerStateWaiting{}}
case AbortedPrepare, Deleting, Exited, Garbage:
exitCode, ok := p.exitCodes[status.ImageID]
exitCode, ok := p.exitCodes[status.Name]
if !ok {
glog.Warningf("rkt: Cannot get exit code for container %v", container)
}
exitCode = -1
}
status.State = api.ContainerState{
Terminated: &api.ContainerStateTerminated{
ExitCode: exitCode,

View File

@ -48,17 +48,13 @@ import (
)
const (
rktBinName = "rkt"
acversion = "0.5.1"
rktMinimumVersion = "0.5.4"
systemdMinimumVersion = "215"
acVersion = "0.6.1"
rktMinimumVersion = "0.7.0"
systemdMinimumVersion = "219"
systemdServiceDir = "/run/systemd/system"
rktDataDir = "/var/lib/rkt"
rktLocalConfigDir = "/etc/rkt"
rktMetadataServiceFile = "rkt-metadata.service"
rktMetadataSocketFile = "rkt-metadata.socket"
kubernetesUnitPrefix = "k8s"
unitKubernetesSection = "X-Kubernetes"
@ -133,7 +129,8 @@ func New(config *Config,
}
// Test if rkt binary is in $PATH.
rktBinAbsPath, err := exec.LookPath(rktBinName)
// TODO(yifan): Use a kubelet flag to read the path.
rktBinAbsPath, err := exec.LookPath("rkt")
if err != nil {
return nil, fmt.Errorf("cannot find rkt binary: %v", err)
}
@ -167,7 +164,7 @@ func New(config *Config,
}
func (r *runtime) buildCommand(args ...string) *exec.Cmd {
cmd := exec.Command(rktBinName)
cmd := exec.Command(r.rktBinAbsPath)
cmd.Args = append(cmd.Args, r.config.buildGlobalOptions()...)
cmd.Args = append(cmd.Args, args...)
return cmd
@ -187,7 +184,8 @@ func (r *runtime) runCommand(args ...string) ([]string, error) {
// makePodServiceFileName constructs the unit file name for a pod using its UID.
func makePodServiceFileName(uid types.UID) string {
// TODO(yifan): Revisit this later, decide whether we want to use UID.
// TODO(yifan): Add name for readability? We need to consider the
// limit of the length.
return fmt.Sprintf("%s_%s.service", kubernetesUnitPrefix, uid)
}
@ -377,7 +375,6 @@ func (r *runtime) getImageManifest(image string) (*appcschema.ImageManifest, err
}
// makePodManifest transforms a kubelet pod spec to the rkt pod manifest.
// TODO(yifan): Use the RunContainerOptions generated by GenerateRunContainerOptions().
func (r *runtime) makePodManifest(pod *api.Pod) (*appcschema.PodManifest, error) {
var globalPortMappings []kubecontainer.PortMapping
manifest := appcschema.BlankPodManifest()
@ -463,8 +460,7 @@ func newUnitOption(section, name, value string) *unit.UnitOption {
return &unit.UnitOption{Section: section, Name: name, Value: value}
}
// TODO(yifan): Remove the receiver once we can solve the appName->imageID problem.
func (r *runtime) apiPodToruntimePod(uuid string, pod *api.Pod) *kubecontainer.Pod {
func apiPodToruntimePod(uuid string, pod *api.Pod) *kubecontainer.Pod {
p := &kubecontainer.Pod{
ID: pod.UID,
Name: pod.Name,
@ -472,12 +468,8 @@ func (r *runtime) apiPodToruntimePod(uuid string, pod *api.Pod) *kubecontainer.P
}
for i := range pod.Spec.Containers {
c := &pod.Spec.Containers[i]
img, err := r.getImageByName(c.Image)
if err != nil {
glog.Warningf("rkt: Cannot get image for %q: %v", c.Image, err)
}
p.Containers = append(p.Containers, &kubecontainer.Container{
ID: types.UID(buildContainerID(&containerID{uuid, c.Name, img.id})),
ID: types.UID(buildContainerID(&containerID{uuid, c.Name})),
Name: c.Name,
Image: c.Image,
Hash: kubecontainer.HashContainer(c),
@ -503,7 +495,7 @@ func (r *runtime) preparePod(pod *api.Pod) (string, bool, error) {
if err != nil {
return "", false, err
}
manifestFile, err := ioutil.TempFile("", "manifest")
manifestFile, err := ioutil.TempFile("", fmt.Sprintf("manifest-%s-", pod.Name))
if err != nil {
return "", false, err
}
@ -533,18 +525,26 @@ func (r *runtime) preparePod(pod *api.Pod) (string, bool, error) {
return "", false, fmt.Errorf("cannot get uuid from 'rkt prepare'")
}
uuid := output[0]
glog.V(4).Infof("'rkt prepare' returns %q.", uuid)
glog.V(4).Infof("'rkt prepare' returns %q", uuid)
p := r.apiPodToruntimePod(uuid, pod)
p := apiPodToruntimePod(uuid, pod)
b, err := json.Marshal(p)
if err != nil {
return "", false, err
}
runPrepared := fmt.Sprintf("%s run-prepared --private-net=%v %s", r.rktBinAbsPath, !pod.Spec.HostNetwork, uuid)
var runPrepared string
if pod.Spec.HostNetwork {
runPrepared = fmt.Sprintf("%s run-prepared --mds-register=false %s", r.rktBinAbsPath, uuid)
} else {
runPrepared = fmt.Sprintf("%s run-prepared --mds-register=false --private-net %s", r.rktBinAbsPath, uuid)
}
units := []*unit.UnitOption{
newUnitOption(unitKubernetesSection, unitRktID, uuid),
newUnitOption(unitKubernetesSection, unitPodName, string(b)),
// This makes the service show up for 'systemctl list-units' even if it exits successfully.
newUnitOption("Service", "RemainAfterExit", "true"),
newUnitOption("Service", "ExecStart", runPrepared),
}
@ -934,7 +934,7 @@ func (r *runtime) GarbageCollect() error {
return nil
}
// Note: In rkt, the container ID is in the form of "UUID:appName:ImageID", where
// Note: In rkt, the container ID is in the form of "UUID:appName", where
// appName is the container name.
func (r *runtime) RunInContainer(containerID string, cmd []string) ([]byte, error) {
glog.V(4).Infof("Rkt running in container.")
@ -943,9 +943,7 @@ func (r *runtime) RunInContainer(containerID string, cmd []string) ([]byte, erro
if err != nil {
return nil, err
}
// TODO(yifan): Use appName instead of imageID.
// see https://github.com/coreos/rkt/pull/640
args := append([]string{}, "enter", "--imageid", id.imageID, id.uuid)
args := append([]string{}, "enter", fmt.Sprintf("--app=%s", id.appName), id.uuid)
args = append(args, cmd...)
result, err := r.runCommand(args...)
@ -956,8 +954,8 @@ func (r *runtime) AttachContainer(containerID string, stdin io.Reader, stdout, s
return errors.New("unimplemented")
}
// Note: In rkt, the container ID is in the form of "UUID:appName:ImageID", where
// appName is the container name.
// Note: In rkt, the container ID is in the form of "UUID:appName", where UUID is
// the rkt UUID, and appName is the container name.
func (r *runtime) ExecInContainer(containerID string, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool) error {
glog.V(4).Infof("Rkt execing in container.")
@ -965,9 +963,7 @@ func (r *runtime) ExecInContainer(containerID string, cmd []string, stdin io.Rea
if err != nil {
return err
}
// TODO(yifan): Use appName instead of imageID.
// see https://github.com/coreos/rkt/pull/640
args := append([]string{}, "enter", "--imageid", id.imageID, id.uuid)
args := append([]string{}, "enter", fmt.Sprintf("--app=%s", id.appName), id.uuid)
args = append(args, cmd...)
command := r.buildCommand(args...)
@ -1116,12 +1112,13 @@ func (r *runtime) getPodInfos() (map[string]*podInfo, error) {
return result, nil
}
// Example output of current 'rkt list --full' (version == 0.4.2):
// UUID ACI STATE NETWORKS
// 2372bc17-47cb-43fb-8d78-20b31729feda foo running default:ip4=172.16.28.3
// bar
// 40e2813b-9d5d-4146-a817-0de92646da96 foo exited
// 40e2813b-9d5d-4146-a817-0de92646da96 bar exited
// Example output of 'rkt list --full' (version == 0.7.0):
//
// UUID APP ACI STATE NETWORKS
// 2372bc17-47cb-43fb-8d78-20b31729feda foo coreos.com/etcd running default:ip4=172.16.28.3
// bar nginx running
// 40e2813b-9d5d-4146-a817-0de92646da96 foo redis exited
// 40e2813b-9d5d-4146-a817-0de92646da96 bar busybox exited
//
// With '--no-legend', the first line is eliminated.
for _, line := range output {
@ -1171,8 +1168,9 @@ func (r *runtime) listImages() ([]image, error) {
}
// getImageByName tries to find the image info with the given image name.
// TODO(yifan): Replace with 'rkt image cat-manifest'.
func (r *runtime) getImageByName(imageName string) (image, error) {
// TODO(yifan): Print hash in rkt image?
// TODO(yifan): Print hash in 'rkt image cat-manifest'?
images, err := r.listImages()
if err != nil {
return image{}, err
@ -1181,9 +1179,7 @@ func (r *runtime) getImageByName(imageName string) (image, error) {
var name, version string
nameVersion := strings.Split(imageName, ":")
// TODO(yifan): Currently the name cannot include "_", it is replaced
// by "-". See the issue in appc/spec: https://github.com/appc/spec/issues/406.
name, err = appctypes.SanitizeACName(nameVersion[0])
name, err = appctypes.SanitizeACIdentifier(nameVersion[0])
if err != nil {
return image{}, err
}