Merge pull request #19856 from yifan-gu/termination_path

Auto commit by PR queue bot
This commit is contained in:
k8s-merge-robot 2016-02-01 07:16:16 -08:00
commit 174521ee1a
2 changed files with 118 additions and 32 deletions

View File

@ -78,11 +78,11 @@ const (
k8sRktNameAnno = "rkt.kubernetes.io/name" k8sRktNameAnno = "rkt.kubernetes.io/name"
k8sRktNamespaceAnno = "rkt.kubernetes.io/namespace" k8sRktNamespaceAnno = "rkt.kubernetes.io/namespace"
//TODO: remove the creation time annotation once this is closed: https://github.com/coreos/rkt/issues/1789 //TODO: remove the creation time annotation once this is closed: https://github.com/coreos/rkt/issues/1789
k8sRktCreationTimeAnno = "rkt.kubernetes.io/created" k8sRktCreationTimeAnno = "rkt.kubernetes.io/created"
k8sRktContainerHashAnno = "rkt.kubernetes.io/containerhash" k8sRktContainerHashAnno = "rkt.kubernetes.io/containerhash"
k8sRktRestartCountAnno = "rkt.kubernetes.io/restartcount" k8sRktRestartCountAnno = "rkt.kubernetes.io/restartcount"
k8sRktTerminationMessagePathAnno = "rkt.kubernetes.io/terminationMessagePath"
dockerPrefix = "docker://" dockerPrefix = "docker://"
authDir = "auth.d" authDir = "auth.d"
dockerAuthTemplate = `{"rktKind":"dockerAuth","rktVersion":"v1","registries":[%q],"credentials":{"user":%q,"password":%q}}` dockerAuthTemplate = `{"rktKind":"dockerAuth","rktVersion":"v1","registries":[%q],"credentials":{"user":%q,"password":%q}}`
@ -450,7 +450,6 @@ func setApp(app *appctypes.App, c *api.Container, opts *kubecontainer.RunContain
// makePodManifest transforms a kubelet pod spec to the rkt pod manifest. // makePodManifest transforms a kubelet pod spec to the rkt pod manifest.
func (r *Runtime) makePodManifest(pod *api.Pod, pullSecrets []api.Secret) (*appcschema.PodManifest, error) { func (r *Runtime) makePodManifest(pod *api.Pod, pullSecrets []api.Secret) (*appcschema.PodManifest, error) {
var globalPortMappings []kubecontainer.PortMapping
manifest := appcschema.BlankPodManifest() manifest := appcschema.BlankPodManifest()
listResp, err := r.apisvc.ListPods(context.Background(), &rktapi.ListPodsRequest{ listResp, err := r.apisvc.ListPods(context.Background(), &rktapi.ListPodsRequest{
@ -490,12 +489,10 @@ func (r *Runtime) makePodManifest(pod *api.Pod, pullSecrets []api.Secret) (*appc
manifest.Annotations.Set(*appctypes.MustACIdentifier(k8sRktRestartCountAnno), strconv.Itoa(restartCount)) manifest.Annotations.Set(*appctypes.MustACIdentifier(k8sRktRestartCountAnno), strconv.Itoa(restartCount))
for _, c := range pod.Spec.Containers { for _, c := range pod.Spec.Containers {
app, portMappings, err := r.newAppcRuntimeApp(pod, c, pullSecrets) err := r.newAppcRuntimeApp(pod, c, pullSecrets, manifest)
if err != nil { if err != nil {
return nil, err return nil, err
} }
manifest.Apps = append(manifest.Apps, *app)
globalPortMappings = append(globalPortMappings, portMappings...)
} }
volumeMap, ok := r.volumeGetter.GetVolumes(pod.UID) volumeMap, ok := r.volumeGetter.GetVolumes(pod.UID)
@ -512,24 +509,52 @@ func (r *Runtime) makePodManifest(pod *api.Pod, pullSecrets []api.Secret) (*appc
}) })
} }
// Set global ports.
for _, port := range globalPortMappings {
manifest.Ports = append(manifest.Ports, appctypes.ExposedPort{
Name: convertToACName(port.Name),
HostPort: uint(port.HostPort),
})
}
// TODO(yifan): Set pod-level isolators once it's supported in kubernetes. // TODO(yifan): Set pod-level isolators once it's supported in kubernetes.
return manifest, nil return manifest, nil
} }
func (r *Runtime) newAppcRuntimeApp(pod *api.Pod, c api.Container, pullSecrets []api.Secret) (*appcschema.RuntimeApp, []kubecontainer.PortMapping, error) { func makeContainerLogMount(opts *kubecontainer.RunContainerOptions, container *api.Container) (*kubecontainer.Mount, error) {
if opts.PodContainerDir == "" || container.TerminationMessagePath == "" {
return nil, nil
}
// In docker runtime, the container log path contains the container ID.
// However, for rkt runtime, we cannot get the container ID before the
// the container is launched, so here we generate a random uuid to enable
// us to map a container's termination message path to an unique log file
// on the disk.
randomUID := util.NewUUID()
containerLogPath := path.Join(opts.PodContainerDir, string(randomUID))
fs, err := os.Create(containerLogPath)
if err != nil {
return nil, err
}
if err := fs.Close(); err != nil {
return nil, err
}
mnt := &kubecontainer.Mount{
// Use a random name for the termination message mount, so that
// when a container restarts, it will not overwrite the old termination
// message.
Name: fmt.Sprintf("termination-message-%s", randomUID),
ContainerPath: container.TerminationMessagePath,
HostPath: containerLogPath,
ReadOnly: false,
}
opts.Mounts = append(opts.Mounts, *mnt)
return mnt, nil
}
func (r *Runtime) newAppcRuntimeApp(pod *api.Pod, c api.Container, pullSecrets []api.Secret, manifest *appcschema.PodManifest) error {
if err, _ := r.imagePuller.PullImage(pod, &c, pullSecrets); err != nil { if err, _ := r.imagePuller.PullImage(pod, &c, pullSecrets); err != nil {
return nil, nil, err return nil
} }
imgManifest, err := r.getImageManifest(c.Image) imgManifest, err := r.getImageManifest(c.Image)
if err != nil { if err != nil {
return nil, nil, err return err
} }
if imgManifest.App == nil { if imgManifest.App == nil {
@ -538,24 +563,30 @@ func (r *Runtime) newAppcRuntimeApp(pod *api.Pod, c api.Container, pullSecrets [
imageID, err := r.getImageID(c.Image) imageID, err := r.getImageID(c.Image)
if err != nil { if err != nil {
return nil, nil, err return err
} }
hash, err := appctypes.NewHash(imageID) hash, err := appctypes.NewHash(imageID)
if err != nil { if err != nil {
return nil, nil, err return err
} }
opts, err := r.generator.GenerateRunContainerOptions(pod, &c) opts, err := r.generator.GenerateRunContainerOptions(pod, &c)
if err != nil { if err != nil {
return nil, nil, err return err
}
// create the container log file and make a mount pair.
mnt, err := makeContainerLogMount(opts, &c)
if err != nil {
return err
} }
ctx := securitycontext.DetermineEffectiveSecurityContext(pod, &c) ctx := securitycontext.DetermineEffectiveSecurityContext(pod, &c)
if err := setApp(imgManifest.App, &c, opts, ctx, pod.Spec.SecurityContext); err != nil { if err := setApp(imgManifest.App, &c, opts, ctx, pod.Spec.SecurityContext); err != nil {
return nil, nil, err return err
} }
return &appcschema.RuntimeApp{ ra := appcschema.RuntimeApp{
Name: convertToACName(c.Name), Name: convertToACName(c.Name),
Image: appcschema.RuntimeImage{ID: *hash}, Image: appcschema.RuntimeImage{ID: *hash},
App: imgManifest.App, App: imgManifest.App,
@ -565,7 +596,32 @@ func (r *Runtime) newAppcRuntimeApp(pod *api.Pod, c api.Container, pullSecrets [
Value: strconv.FormatUint(kubecontainer.HashContainer(&c), 10), Value: strconv.FormatUint(kubecontainer.HashContainer(&c), 10),
}, },
}, },
}, opts.PortMappings, nil }
if mnt != nil {
ra.Annotations = append(ra.Annotations, appctypes.Annotation{
Name: *appctypes.MustACIdentifier(k8sRktTerminationMessagePathAnno),
Value: mnt.HostPath,
})
manifest.Volumes = append(manifest.Volumes, appctypes.Volume{
Name: convertToACName(mnt.Name),
Kind: "host",
Source: mnt.HostPath,
})
}
manifest.Apps = append(manifest.Apps, ra)
// Set global ports.
for _, port := range opts.PortMappings {
manifest.Ports = append(manifest.Ports, appctypes.ExposedPort{
Name: convertToACName(port.Name),
HostPort: uint(port.HostPort),
})
}
return nil
} }
func runningKubernetesPodFilters(uid types.UID) []*rktapi.PodFilter { func runningKubernetesPodFilters(uid types.UID) []*rktapi.PodFilter {
@ -1299,6 +1355,24 @@ func populateContainerStatus(pod rktapi.Pod, app rktapi.App, runtimeApp appcsche
return nil, err return nil, err
} }
var reason, message string
if app.State == rktapi.AppState_APP_STATE_EXITED {
if app.ExitCode == 0 {
reason = "Completed"
} else {
reason = "Error"
}
}
terminationMessagePath, ok := runtimeApp.Annotations.Get(k8sRktTerminationMessagePathAnno)
if ok {
if data, err := ioutil.ReadFile(terminationMessagePath); err != nil {
message = fmt.Sprintf("Error on reading termination-log %s: %v", terminationMessagePath, err)
} else {
message = string(data)
}
}
return &kubecontainer.ContainerStatus{ return &kubecontainer.ContainerStatus{
ID: buildContainerID(&containerID{uuid: pod.Id, appName: app.Name}), ID: buildContainerID(&containerID{uuid: pod.Id, appName: app.Name}),
Name: app.Name, Name: app.Name,
@ -1314,7 +1388,8 @@ func populateContainerStatus(pod rktapi.Pod, app rktapi.App, runtimeApp appcsche
// change once apps don't share the same lifecycle. // change once apps don't share the same lifecycle.
// See https://github.com/appc/spec/pull/547. // See https://github.com/appc/spec/pull/547.
RestartCount: restartCount, RestartCount: restartCount,
// TODO(yifan): Add reason and message field. Reason: reason,
Message: message,
}, nil }, nil
} }
@ -1383,10 +1458,7 @@ func (s sortByRestartCount) Less(i, j int) bool { return s[i].RestartCount < s[j
// TODO(yifan): Delete this function when the logic is moved to kubelet. // TODO(yifan): Delete this function when the logic is moved to kubelet.
func (r *Runtime) ConvertPodStatusToAPIPodStatus(pod *api.Pod, status *kubecontainer.PodStatus) (*api.PodStatus, error) { func (r *Runtime) ConvertPodStatusToAPIPodStatus(pod *api.Pod, status *kubecontainer.PodStatus) (*api.PodStatus, error) {
apiPodStatus := &api.PodStatus{ apiPodStatus := &api.PodStatus{PodIP: status.IP}
// TODO(yifan): Add reason and message field.
PodIP: status.IP,
}
// Sort in the reverse order of the restart count because the // Sort in the reverse order of the restart count because the
// lastest one will have the largest restart count. // lastest one will have the largest restart count.
@ -1410,7 +1482,9 @@ func (r *Runtime) ConvertPodStatusToAPIPodStatus(pod *api.Pod, status *kubeconta
st.Terminated = &api.ContainerStateTerminated{ st.Terminated = &api.ContainerStateTerminated{
ExitCode: c.ExitCode, ExitCode: c.ExitCode,
StartedAt: unversioned.NewTime(c.StartedAt), StartedAt: unversioned.NewTime(c.StartedAt),
// TODO(yifan): Add reason, message, finishedAt, signal. Reason: c.Reason,
Message: c.Message,
// TODO(yifan): Add finishedAt, signal.
ContainerID: c.ID.String(), ContainerID: c.ID.String(),
} }
default: default:

View File

@ -62,7 +62,7 @@ func makeRktPod(rktPodState rktapi.PodState,
rktPodID, podUID, podName, podNamespace, rktPodID, podUID, podName, podNamespace,
podIP, podCreationTs, podRestartCount string, podIP, podCreationTs, podRestartCount string,
appNames, imgIDs, imgNames, containerHashes []string, appNames, imgIDs, imgNames, containerHashes []string,
appStates []rktapi.AppState) *rktapi.Pod { appStates []rktapi.AppState, exitcodes []int32) *rktapi.Pod {
podManifest := &appcschema.PodManifest{ podManifest := &appcschema.PodManifest{
ACKind: appcschema.PodManifestKind, ACKind: appcschema.PodManifestKind,
@ -125,6 +125,7 @@ func makeRktPod(rktPodState rktapi.PodState,
}, },
), ),
}, },
ExitCode: exitcodes[i],
} }
podManifest.Apps = append(podManifest.Apps, appcschema.RuntimeApp{ podManifest.Apps = append(podManifest.Apps, appcschema.RuntimeApp{
Name: *appctypes.MustACName(appNames[i]), Name: *appctypes.MustACName(appNames[i]),
@ -355,6 +356,7 @@ func TestGetPods(t *testing.T) {
[]string{"img-name-1", "img-name-2"}, []string{"img-name-1", "img-name-2"},
[]string{"1001", "1002"}, []string{"1001", "1002"},
[]rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED}, []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED},
[]int32{0, 0},
), ),
}, },
[]*kubecontainer.Pod{ []*kubecontainer.Pod{
@ -394,6 +396,7 @@ func TestGetPods(t *testing.T) {
[]string{"img-name-1", "img-name-2"}, []string{"img-name-1", "img-name-2"},
[]string{"1001", "1002"}, []string{"1001", "1002"},
[]rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED}, []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED},
[]int32{0, 0},
), ),
makeRktPod(rktapi.PodState_POD_STATE_EXITED, makeRktPod(rktapi.PodState_POD_STATE_EXITED,
"uuid-4003", "43", "guestbook", "default", "uuid-4003", "43", "guestbook", "default",
@ -403,6 +406,7 @@ func TestGetPods(t *testing.T) {
[]string{"img-name-11", "img-name-22"}, []string{"img-name-11", "img-name-22"},
[]string{"10011", "10022"}, []string{"10011", "10022"},
[]rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED}, []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED},
[]int32{0, 0},
), ),
}, },
[]*kubecontainer.Pod{ []*kubecontainer.Pod{
@ -542,6 +546,7 @@ func TestGetPodStatus(t *testing.T) {
[]string{"img-name-1", "img-name-2"}, []string{"img-name-1", "img-name-2"},
[]string{"1001", "1002"}, []string{"1001", "1002"},
[]rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED}, []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED},
[]int32{0, 0},
), ),
}, },
&kubecontainer.PodStatus{ &kubecontainer.PodStatus{
@ -571,6 +576,7 @@ func TestGetPodStatus(t *testing.T) {
ImageID: "rkt://img-id-2", ImageID: "rkt://img-id-2",
Hash: 1002, Hash: 1002,
RestartCount: 7, RestartCount: 7,
Reason: "Completed",
}, },
}, },
}, },
@ -586,6 +592,7 @@ func TestGetPodStatus(t *testing.T) {
[]string{"img-name-1", "img-name-2"}, []string{"img-name-1", "img-name-2"},
[]string{"1001", "1002"}, []string{"1001", "1002"},
[]rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED}, []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED},
[]int32{0, 0},
), ),
makeRktPod(rktapi.PodState_POD_STATE_RUNNING, // The latest pod is running. makeRktPod(rktapi.PodState_POD_STATE_RUNNING, // The latest pod is running.
"uuid-4003", "42", "guestbook", "default", "uuid-4003", "42", "guestbook", "default",
@ -595,6 +602,7 @@ func TestGetPodStatus(t *testing.T) {
[]string{"img-name-1", "img-name-2"}, []string{"img-name-1", "img-name-2"},
[]string{"1001", "1002"}, []string{"1001", "1002"},
[]rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED}, []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED},
[]int32{0, 1},
), ),
}, },
&kubecontainer.PodStatus{ &kubecontainer.PodStatus{
@ -625,6 +633,7 @@ func TestGetPodStatus(t *testing.T) {
ImageID: "rkt://img-id-2", ImageID: "rkt://img-id-2",
Hash: 1002, Hash: 1002,
RestartCount: 7, RestartCount: 7,
Reason: "Completed",
}, },
{ {
ID: kubecontainer.BuildContainerID("rkt", "uuid-4003:app-1"), ID: kubecontainer.BuildContainerID("rkt", "uuid-4003:app-1"),
@ -647,6 +656,8 @@ func TestGetPodStatus(t *testing.T) {
ImageID: "rkt://img-id-2", ImageID: "rkt://img-id-2",
Hash: 1002, Hash: 1002,
RestartCount: 10, RestartCount: 10,
ExitCode: 1,
Reason: "Error",
}, },
}, },
}, },
@ -863,6 +874,7 @@ func TestSetApp(t *testing.T) {
// app should be changed. (env, mounts, ports, are overrided). // app should be changed. (env, mounts, ports, are overrided).
{ {
container: &api.Container{ container: &api.Container{
Name: "hello-world",
Command: []string{"/bin/bar", "$(env-foo)"}, Command: []string{"/bin/bar", "$(env-foo)"},
Args: []string{"hello", "world", "$(env-bar)"}, Args: []string{"hello", "world", "$(env-bar)"},
WorkingDir: tmpDir, WorkingDir: tmpDir,