mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-16 14:45:28 +00:00
Merge pull request #4194 from dchen1107/podstatus
Kubelet decides podStatus
This commit is contained in:
@@ -1037,10 +1037,6 @@ func (kl *Kubelet) syncPod(pod *api.BoundPod, dockerContainers dockertools.Docke
|
||||
if err != nil {
|
||||
glog.Errorf("Unable to get pod with name %q and uid %q info, health checks may be invalid", podFullName, uid)
|
||||
}
|
||||
netInfo, found := podStatus.Info[dockertools.PodInfraContainerName]
|
||||
if found {
|
||||
podStatus.PodIP = netInfo.PodIP
|
||||
}
|
||||
|
||||
for _, container := range pod.Spec.Containers {
|
||||
expectedHash := dockertools.HashContainer(&container)
|
||||
@@ -1427,20 +1423,90 @@ func (kl *Kubelet) GetPodByName(namespace, name string) (*api.BoundPod, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// getPhase returns the phase of a pod given its container info.
|
||||
func getPhase(spec *api.PodSpec, info api.PodInfo) api.PodPhase {
|
||||
if info == nil {
|
||||
return api.PodPending
|
||||
}
|
||||
|
||||
running := 0
|
||||
waiting := 0
|
||||
stopped := 0
|
||||
failed := 0
|
||||
succeeded := 0
|
||||
unknown := 0
|
||||
for _, container := range spec.Containers {
|
||||
if containerStatus, ok := info[container.Name]; ok {
|
||||
if containerStatus.State.Running != nil {
|
||||
running++
|
||||
} else if containerStatus.State.Termination != nil {
|
||||
stopped++
|
||||
if containerStatus.State.Termination.ExitCode == 0 {
|
||||
succeeded++
|
||||
} else {
|
||||
failed++
|
||||
}
|
||||
} else if containerStatus.State.Waiting != nil {
|
||||
waiting++
|
||||
} else {
|
||||
unknown++
|
||||
}
|
||||
} else {
|
||||
unknown++
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case waiting > 0:
|
||||
// One or more containers has not been started
|
||||
return api.PodPending
|
||||
case running > 0 && unknown == 0:
|
||||
// All containers have been started, and at least
|
||||
// one container is running
|
||||
return api.PodRunning
|
||||
case running == 0 && stopped > 0 && unknown == 0:
|
||||
// All containers are terminated
|
||||
if spec.RestartPolicy.Always != nil {
|
||||
// All containers are in the process of restarting
|
||||
return api.PodRunning
|
||||
}
|
||||
if stopped == succeeded {
|
||||
// RestartPolicy is not Always, and all
|
||||
// containers are terminated in success
|
||||
return api.PodSucceeded
|
||||
}
|
||||
if spec.RestartPolicy.Never != nil {
|
||||
// RestartPolicy is Never, and all containers are
|
||||
// terminated with at least one in failure
|
||||
return api.PodFailed
|
||||
}
|
||||
// RestartPolicy is OnFailure, and at least one in failure
|
||||
// and in the process of restarting
|
||||
return api.PodRunning
|
||||
default:
|
||||
return api.PodPending
|
||||
}
|
||||
}
|
||||
|
||||
// GetPodStatus returns information from Docker about the containers in a pod
|
||||
func (kl *Kubelet) GetPodStatus(podFullName string, uid types.UID) (api.PodStatus, error) {
|
||||
var manifest api.PodSpec
|
||||
var spec api.PodSpec
|
||||
for _, pod := range kl.pods {
|
||||
if GetPodFullName(&pod) == podFullName {
|
||||
manifest = pod.Spec
|
||||
spec = pod.Spec
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
info, err := dockertools.GetDockerPodInfo(kl.dockerClient, manifest, podFullName, uid)
|
||||
info, err := dockertools.GetDockerPodInfo(kl.dockerClient, spec, podFullName, uid)
|
||||
|
||||
// TODO(dchen1107): Determine PodPhase here
|
||||
var podStatus api.PodStatus
|
||||
podStatus.Phase = getPhase(&spec, info)
|
||||
netContainerInfo, found := info[dockertools.PodInfraContainerName]
|
||||
if found {
|
||||
podStatus.PodIP = netContainerInfo.PodIP
|
||||
}
|
||||
|
||||
// TODO(dchen1107): Change Info to list from map
|
||||
podStatus.Info = info
|
||||
|
||||
return podStatus, err
|
||||
|
@@ -2240,3 +2240,322 @@ func TestMakeEnvironmentVariables(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPodPhaseWithRestartAlways(t *testing.T) {
|
||||
desiredState := api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{Name: "containerA"},
|
||||
{Name: "containerB"},
|
||||
},
|
||||
RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
|
||||
}
|
||||
currentState := api.PodStatus{
|
||||
Host: "machine",
|
||||
}
|
||||
runningState := api.ContainerStatus{
|
||||
State: api.ContainerState{
|
||||
Running: &api.ContainerStateRunning{},
|
||||
},
|
||||
}
|
||||
stoppedState := api.ContainerStatus{
|
||||
State: api.ContainerState{
|
||||
Termination: &api.ContainerStateTerminated{},
|
||||
},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
pod *api.Pod
|
||||
status api.PodPhase
|
||||
test string
|
||||
}{
|
||||
{&api.Pod{Spec: desiredState, Status: currentState}, api.PodPending, "waiting"},
|
||||
{
|
||||
&api.Pod{
|
||||
Spec: desiredState,
|
||||
Status: api.PodStatus{
|
||||
Info: map[string]api.ContainerStatus{
|
||||
"containerA": runningState,
|
||||
"containerB": runningState,
|
||||
},
|
||||
Host: "machine",
|
||||
},
|
||||
},
|
||||
api.PodRunning,
|
||||
"all running",
|
||||
},
|
||||
{
|
||||
&api.Pod{
|
||||
Spec: desiredState,
|
||||
Status: api.PodStatus{
|
||||
Info: map[string]api.ContainerStatus{
|
||||
"containerA": stoppedState,
|
||||
"containerB": stoppedState,
|
||||
},
|
||||
Host: "machine",
|
||||
},
|
||||
},
|
||||
api.PodRunning,
|
||||
"all stopped with restart always",
|
||||
},
|
||||
{
|
||||
&api.Pod{
|
||||
Spec: desiredState,
|
||||
Status: api.PodStatus{
|
||||
Info: map[string]api.ContainerStatus{
|
||||
"containerA": runningState,
|
||||
"containerB": stoppedState,
|
||||
},
|
||||
Host: "machine",
|
||||
},
|
||||
},
|
||||
api.PodRunning,
|
||||
"mixed state #1 with restart always",
|
||||
},
|
||||
{
|
||||
&api.Pod{
|
||||
Spec: desiredState,
|
||||
Status: api.PodStatus{
|
||||
Info: map[string]api.ContainerStatus{
|
||||
"containerA": runningState,
|
||||
},
|
||||
Host: "machine",
|
||||
},
|
||||
},
|
||||
api.PodPending,
|
||||
"mixed state #2 with restart always",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
if status := getPhase(&test.pod.Spec, test.pod.Status.Info); status != test.status {
|
||||
t.Errorf("In test %s, expected %v, got %v", test.test, test.status, status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPodPhaseWithRestartNever(t *testing.T) {
|
||||
desiredState := api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{Name: "containerA"},
|
||||
{Name: "containerB"},
|
||||
},
|
||||
RestartPolicy: api.RestartPolicy{Never: &api.RestartPolicyNever{}},
|
||||
}
|
||||
currentState := api.PodStatus{
|
||||
Host: "machine",
|
||||
}
|
||||
runningState := api.ContainerStatus{
|
||||
State: api.ContainerState{
|
||||
Running: &api.ContainerStateRunning{},
|
||||
},
|
||||
}
|
||||
succeededState := api.ContainerStatus{
|
||||
State: api.ContainerState{
|
||||
Termination: &api.ContainerStateTerminated{
|
||||
ExitCode: 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
failedState := api.ContainerStatus{
|
||||
State: api.ContainerState{
|
||||
Termination: &api.ContainerStateTerminated{
|
||||
ExitCode: -1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
pod *api.Pod
|
||||
status api.PodPhase
|
||||
test string
|
||||
}{
|
||||
{&api.Pod{Spec: desiredState, Status: currentState}, api.PodPending, "waiting"},
|
||||
{
|
||||
&api.Pod{
|
||||
Spec: desiredState,
|
||||
Status: api.PodStatus{
|
||||
Info: map[string]api.ContainerStatus{
|
||||
"containerA": runningState,
|
||||
"containerB": runningState,
|
||||
},
|
||||
Host: "machine",
|
||||
},
|
||||
},
|
||||
api.PodRunning,
|
||||
"all running with restart never",
|
||||
},
|
||||
{
|
||||
&api.Pod{
|
||||
Spec: desiredState,
|
||||
Status: api.PodStatus{
|
||||
Info: map[string]api.ContainerStatus{
|
||||
"containerA": succeededState,
|
||||
"containerB": succeededState,
|
||||
},
|
||||
Host: "machine",
|
||||
},
|
||||
},
|
||||
api.PodSucceeded,
|
||||
"all succeeded with restart never",
|
||||
},
|
||||
{
|
||||
&api.Pod{
|
||||
Spec: desiredState,
|
||||
Status: api.PodStatus{
|
||||
Info: map[string]api.ContainerStatus{
|
||||
"containerA": failedState,
|
||||
"containerB": failedState,
|
||||
},
|
||||
Host: "machine",
|
||||
},
|
||||
},
|
||||
api.PodFailed,
|
||||
"all failed with restart never",
|
||||
},
|
||||
{
|
||||
&api.Pod{
|
||||
Spec: desiredState,
|
||||
Status: api.PodStatus{
|
||||
Info: map[string]api.ContainerStatus{
|
||||
"containerA": runningState,
|
||||
"containerB": succeededState,
|
||||
},
|
||||
Host: "machine",
|
||||
},
|
||||
},
|
||||
api.PodRunning,
|
||||
"mixed state #1 with restart never",
|
||||
},
|
||||
{
|
||||
&api.Pod{
|
||||
Spec: desiredState,
|
||||
Status: api.PodStatus{
|
||||
Info: map[string]api.ContainerStatus{
|
||||
"containerA": runningState,
|
||||
},
|
||||
Host: "machine",
|
||||
},
|
||||
},
|
||||
api.PodPending,
|
||||
"mixed state #2 with restart never",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
if status := getPhase(&test.pod.Spec, test.pod.Status.Info); status != test.status {
|
||||
t.Errorf("In test %s, expected %v, got %v", test.test, test.status, status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPodPhaseWithRestartOnFailure(t *testing.T) {
|
||||
desiredState := api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{Name: "containerA"},
|
||||
{Name: "containerB"},
|
||||
},
|
||||
RestartPolicy: api.RestartPolicy{OnFailure: &api.RestartPolicyOnFailure{}},
|
||||
}
|
||||
currentState := api.PodStatus{
|
||||
Host: "machine",
|
||||
}
|
||||
runningState := api.ContainerStatus{
|
||||
State: api.ContainerState{
|
||||
Running: &api.ContainerStateRunning{},
|
||||
},
|
||||
}
|
||||
succeededState := api.ContainerStatus{
|
||||
State: api.ContainerState{
|
||||
Termination: &api.ContainerStateTerminated{
|
||||
ExitCode: 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
failedState := api.ContainerStatus{
|
||||
State: api.ContainerState{
|
||||
Termination: &api.ContainerStateTerminated{
|
||||
ExitCode: -1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
pod *api.Pod
|
||||
status api.PodPhase
|
||||
test string
|
||||
}{
|
||||
{&api.Pod{Spec: desiredState, Status: currentState}, api.PodPending, "waiting"},
|
||||
{
|
||||
&api.Pod{
|
||||
Spec: desiredState,
|
||||
Status: api.PodStatus{
|
||||
Info: map[string]api.ContainerStatus{
|
||||
"containerA": runningState,
|
||||
"containerB": runningState,
|
||||
},
|
||||
Host: "machine",
|
||||
},
|
||||
},
|
||||
api.PodRunning,
|
||||
"all running with restart onfailure",
|
||||
},
|
||||
{
|
||||
&api.Pod{
|
||||
Spec: desiredState,
|
||||
Status: api.PodStatus{
|
||||
Info: map[string]api.ContainerStatus{
|
||||
"containerA": succeededState,
|
||||
"containerB": succeededState,
|
||||
},
|
||||
Host: "machine",
|
||||
},
|
||||
},
|
||||
api.PodSucceeded,
|
||||
"all succeeded with restart onfailure",
|
||||
},
|
||||
{
|
||||
&api.Pod{
|
||||
Spec: desiredState,
|
||||
Status: api.PodStatus{
|
||||
Info: map[string]api.ContainerStatus{
|
||||
"containerA": failedState,
|
||||
"containerB": failedState,
|
||||
},
|
||||
Host: "machine",
|
||||
},
|
||||
},
|
||||
api.PodRunning,
|
||||
"all failed with restart never",
|
||||
},
|
||||
{
|
||||
&api.Pod{
|
||||
Spec: desiredState,
|
||||
Status: api.PodStatus{
|
||||
Info: map[string]api.ContainerStatus{
|
||||
"containerA": runningState,
|
||||
"containerB": succeededState,
|
||||
},
|
||||
Host: "machine",
|
||||
},
|
||||
},
|
||||
api.PodRunning,
|
||||
"mixed state #1 with restart onfailure",
|
||||
},
|
||||
{
|
||||
&api.Pod{
|
||||
Spec: desiredState,
|
||||
Status: api.PodStatus{
|
||||
Info: map[string]api.ContainerStatus{
|
||||
"containerA": runningState,
|
||||
},
|
||||
Host: "machine",
|
||||
},
|
||||
},
|
||||
api.PodPending,
|
||||
"mixed state #2 with restart onfailure",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
if status := getPhase(&test.pod.Spec, test.pod.Status.Info); status != test.status {
|
||||
t.Errorf("In test %s, expected %v, got %v", test.test, test.status, status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user