rkt: Implement pod FinishedAt

This is implemented via touching a file on stop as a hook in the systemd
unit. The ctime of this file is then used to get the `finishedAt` time
in the future.
In addition, this changes the `startedAt` and `createdAt` to use the api
server's results rather than the annotations it previously used.

It's possible we might want to move this into the api in the future.

Fixes #23887
This commit is contained in:
Euan Kemp
2016-04-14 18:01:40 -07:00
parent 82f3ec14fb
commit a6718f5969
9 changed files with 306 additions and 85 deletions

View File

@@ -27,11 +27,14 @@ import (
appcschema "github.com/appc/spec/schema"
appctypes "github.com/appc/spec/schema/types"
rktapi "github.com/coreos/rkt/api/v1alpha"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
containertesting "k8s.io/kubernetes/pkg/kubelet/container/testing"
"k8s.io/kubernetes/pkg/kubelet/lifecycle"
"k8s.io/kubernetes/pkg/kubelet/rkt/mock_os"
"k8s.io/kubernetes/pkg/util/errors"
utiltesting "k8s.io/kubernetes/pkg/util/testing"
)
@@ -62,9 +65,10 @@ func mustRktHash(hash string) *appctypes.Hash {
func makeRktPod(rktPodState rktapi.PodState,
rktPodID, podUID, podName, podNamespace,
podIP, podCreationTs, podRestartCount string,
appNames, imgIDs, imgNames, containerHashes []string,
appStates []rktapi.AppState, exitcodes []int32) *rktapi.Pod {
podIP string, podCreatedAt, podStartedAt int64,
podRestartCount string, appNames, imgIDs, imgNames,
containerHashes []string, appStates []rktapi.AppState,
exitcodes []int32) *rktapi.Pod {
podManifest := &appcschema.PodManifest{
ACKind: appcschema.PodManifestKind,
@@ -86,10 +90,6 @@ func makeRktPod(rktPodState rktapi.PodState,
Name: *appctypes.MustACIdentifier(k8sRktNamespaceAnno),
Value: podNamespace,
},
appctypes.Annotation{
Name: *appctypes.MustACIdentifier(k8sRktCreationTimeAnno),
Value: podCreationTs,
},
appctypes.Annotation{
Name: *appctypes.MustACIdentifier(k8sRktRestartCountAnno),
Value: podRestartCount,
@@ -143,11 +143,13 @@ func makeRktPod(rktPodState rktapi.PodState,
}
return &rktapi.Pod{
Id: rktPodID,
State: rktPodState,
Networks: []*rktapi.Network{{Name: defaultNetworkName, Ipv4: podIP}},
Apps: apps,
Manifest: mustMarshalPodManifest(podManifest),
Id: rktPodID,
State: rktPodState,
Networks: []*rktapi.Network{{Name: defaultNetworkName, Ipv4: podIP}},
Apps: apps,
Manifest: mustMarshalPodManifest(podManifest),
StartedAt: podStartedAt,
CreatedAt: podCreatedAt,
}
}
@@ -346,6 +348,10 @@ func TestGetPods(t *testing.T) {
fs := newFakeSystemd()
r := &Runtime{apisvc: fr, systemd: fs}
ns := func(seconds int64) int64 {
return seconds * 1e9
}
tests := []struct {
pods []*rktapi.Pod
result []*kubecontainer.Pod
@@ -357,7 +363,7 @@ func TestGetPods(t *testing.T) {
[]*rktapi.Pod{
makeRktPod(rktapi.PodState_POD_STATE_RUNNING,
"uuid-4002", "42", "guestbook", "default",
"10.10.10.42", "100000", "7",
"10.10.10.42", ns(10), ns(10), "7",
[]string{"app-1", "app-2"},
[]string{"img-id-1", "img-id-2"},
[]string{"img-name-1", "img-name-2"},
@@ -377,7 +383,7 @@ func TestGetPods(t *testing.T) {
Name: "app-1",
Image: "img-name-1:latest",
Hash: 1001,
Created: 100000,
Created: 10,
State: "running",
},
{
@@ -385,7 +391,7 @@ func TestGetPods(t *testing.T) {
Name: "app-2",
Image: "img-name-2:latest",
Hash: 1002,
Created: 100000,
Created: 10,
State: "exited",
},
},
@@ -397,7 +403,7 @@ func TestGetPods(t *testing.T) {
[]*rktapi.Pod{
makeRktPod(rktapi.PodState_POD_STATE_RUNNING,
"uuid-4002", "42", "guestbook", "default",
"10.10.10.42", "100000", "7",
"10.10.10.42", ns(10), ns(20), "7",
[]string{"app-1", "app-2"},
[]string{"img-id-1", "img-id-2"},
[]string{"img-name-1", "img-name-2"},
@@ -407,7 +413,7 @@ func TestGetPods(t *testing.T) {
),
makeRktPod(rktapi.PodState_POD_STATE_EXITED,
"uuid-4003", "43", "guestbook", "default",
"10.10.10.43", "90000", "7",
"10.10.10.43", ns(30), ns(40), "7",
[]string{"app-11", "app-22"},
[]string{"img-id-11", "img-id-22"},
[]string{"img-name-11", "img-name-22"},
@@ -417,7 +423,7 @@ func TestGetPods(t *testing.T) {
),
makeRktPod(rktapi.PodState_POD_STATE_EXITED,
"uuid-4004", "43", "guestbook", "default",
"10.10.10.44", "100000", "8",
"10.10.10.44", ns(50), ns(60), "8",
[]string{"app-11", "app-22"},
[]string{"img-id-11", "img-id-22"},
[]string{"img-name-11", "img-name-22"},
@@ -437,7 +443,7 @@ func TestGetPods(t *testing.T) {
Name: "app-1",
Image: "img-name-1:latest",
Hash: 1001,
Created: 100000,
Created: 10,
State: "running",
},
{
@@ -445,7 +451,7 @@ func TestGetPods(t *testing.T) {
Name: "app-2",
Image: "img-name-2:latest",
Hash: 1002,
Created: 100000,
Created: 10,
State: "exited",
},
},
@@ -460,7 +466,7 @@ func TestGetPods(t *testing.T) {
Name: "app-11",
Image: "img-name-11:latest",
Hash: 10011,
Created: 90000,
Created: 30,
State: "exited",
},
{
@@ -468,7 +474,7 @@ func TestGetPods(t *testing.T) {
Name: "app-22",
Image: "img-name-22:latest",
Hash: 10022,
Created: 90000,
Created: 30,
State: "exited",
},
{
@@ -476,7 +482,7 @@ func TestGetPods(t *testing.T) {
Name: "app-11",
Image: "img-name-11:latest",
Hash: 10011,
Created: 100000,
Created: 50,
State: "running",
},
{
@@ -484,7 +490,7 @@ func TestGetPods(t *testing.T) {
Name: "app-22",
Image: "img-name-22:latest",
Hash: 10022,
Created: 100000,
Created: 50,
State: "running",
},
},
@@ -557,7 +563,18 @@ func TestGetPodsFilters(t *testing.T) {
func TestGetPodStatus(t *testing.T) {
fr := newFakeRktInterface()
fs := newFakeSystemd()
r := &Runtime{apisvc: fr, systemd: fs}
fos := &containertesting.FakeOS{}
frh := &fakeRuntimeHelper{}
r := &Runtime{
apisvc: fr,
systemd: fs,
runtimeHelper: frh,
os: fos,
}
ns := func(seconds int64) int64 {
return seconds * 1e9
}
tests := []struct {
pods []*rktapi.Pod
@@ -573,7 +590,7 @@ func TestGetPodStatus(t *testing.T) {
[]*rktapi.Pod{
makeRktPod(rktapi.PodState_POD_STATE_RUNNING,
"uuid-4002", "42", "guestbook", "default",
"10.10.10.42", "100000", "7",
"10.10.10.42", ns(10), ns(20), "7",
[]string{"app-1", "app-2"},
[]string{"img-id-1", "img-id-2"},
[]string{"img-name-1", "img-name-2"},
@@ -592,8 +609,9 @@ func TestGetPodStatus(t *testing.T) {
ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-1"),
Name: "app-1",
State: kubecontainer.ContainerStateRunning,
CreatedAt: time.Unix(100000, 0),
StartedAt: time.Unix(100000, 0),
CreatedAt: time.Unix(10, 0),
StartedAt: time.Unix(20, 0),
FinishedAt: time.Unix(0, 30),
Image: "img-name-1:latest",
ImageID: "rkt://img-id-1",
Hash: 1001,
@@ -603,8 +621,9 @@ func TestGetPodStatus(t *testing.T) {
ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-2"),
Name: "app-2",
State: kubecontainer.ContainerStateExited,
CreatedAt: time.Unix(100000, 0),
StartedAt: time.Unix(100000, 0),
CreatedAt: time.Unix(10, 0),
StartedAt: time.Unix(20, 0),
FinishedAt: time.Unix(0, 30),
Image: "img-name-2:latest",
ImageID: "rkt://img-id-2",
Hash: 1002,
@@ -619,7 +638,7 @@ func TestGetPodStatus(t *testing.T) {
[]*rktapi.Pod{
makeRktPod(rktapi.PodState_POD_STATE_EXITED,
"uuid-4002", "42", "guestbook", "default",
"10.10.10.42", "90000", "7",
"10.10.10.42", ns(10), ns(20), "7",
[]string{"app-1", "app-2"},
[]string{"img-id-1", "img-id-2"},
[]string{"img-name-1", "img-name-2"},
@@ -629,7 +648,7 @@ func TestGetPodStatus(t *testing.T) {
),
makeRktPod(rktapi.PodState_POD_STATE_RUNNING, // The latest pod is running.
"uuid-4003", "42", "guestbook", "default",
"10.10.10.42", "100000", "10",
"10.10.10.42", ns(10), ns(20), "10",
[]string{"app-1", "app-2"},
[]string{"img-id-1", "img-id-2"},
[]string{"img-name-1", "img-name-2"},
@@ -649,8 +668,9 @@ func TestGetPodStatus(t *testing.T) {
ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-1"),
Name: "app-1",
State: kubecontainer.ContainerStateRunning,
CreatedAt: time.Unix(90000, 0),
StartedAt: time.Unix(90000, 0),
CreatedAt: time.Unix(10, 0),
StartedAt: time.Unix(20, 0),
FinishedAt: time.Unix(0, 30),
Image: "img-name-1:latest",
ImageID: "rkt://img-id-1",
Hash: 1001,
@@ -660,8 +680,9 @@ func TestGetPodStatus(t *testing.T) {
ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-2"),
Name: "app-2",
State: kubecontainer.ContainerStateExited,
CreatedAt: time.Unix(90000, 0),
StartedAt: time.Unix(90000, 0),
CreatedAt: time.Unix(10, 0),
StartedAt: time.Unix(20, 0),
FinishedAt: time.Unix(0, 30),
Image: "img-name-2:latest",
ImageID: "rkt://img-id-2",
Hash: 1002,
@@ -672,8 +693,9 @@ func TestGetPodStatus(t *testing.T) {
ID: kubecontainer.BuildContainerID("rkt", "uuid-4003:app-1"),
Name: "app-1",
State: kubecontainer.ContainerStateRunning,
CreatedAt: time.Unix(100000, 0),
StartedAt: time.Unix(100000, 0),
CreatedAt: time.Unix(10, 0),
StartedAt: time.Unix(20, 0),
FinishedAt: time.Unix(0, 30),
Image: "img-name-1:latest",
ImageID: "rkt://img-id-1",
Hash: 1001,
@@ -683,8 +705,9 @@ func TestGetPodStatus(t *testing.T) {
ID: kubecontainer.BuildContainerID("rkt", "uuid-4003:app-2"),
Name: "app-2",
State: kubecontainer.ContainerStateExited,
CreatedAt: time.Unix(100000, 0),
StartedAt: time.Unix(100000, 0),
CreatedAt: time.Unix(10, 0),
StartedAt: time.Unix(20, 0),
FinishedAt: time.Unix(0, 30),
Image: "img-name-2:latest",
ImageID: "rkt://img-id-2",
Hash: 1002,
@@ -697,10 +720,28 @@ func TestGetPodStatus(t *testing.T) {
},
}
ctrl := gomock.NewController(t)
defer ctrl.Finish()
for i, tt := range tests {
testCaseHint := fmt.Sprintf("test case #%d", i)
fr.pods = tt.pods
podTimes := map[string]time.Time{}
for _, pod := range tt.pods {
podTimes[podFinishedMarkerPath(r.runtimeHelper.GetPodDir(tt.result.ID), pod.Id)] = tt.result.ContainerStatuses[0].FinishedAt
}
r.os.(*containertesting.FakeOS).StatFn = func(name string) (os.FileInfo, error) {
podTime, ok := podTimes[name]
if !ok {
t.Errorf("osStat called with %v, but only knew about %#v", name, podTimes)
}
mockFI := mock_os.NewMockFileInfo(ctrl)
mockFI.EXPECT().ModTime().Return(podTime)
return mockFI, nil
}
status, err := r.GetPodStatus("42", "guestbook", "default")
if err != nil {
t.Errorf("test case #%d: unexpected error: %v", i, err)