mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-03 01:06:27 +00:00
Merge pull request #1569 from dchen1107/termination
Initial support to propagating the termination reasons and image failures
This commit is contained in:
commit
fca26ccc65
@ -50,7 +50,7 @@ while [ $ALL_RUNNING -ne 1 ]; do
|
|||||||
ALL_RUNNING=1
|
ALL_RUNNING=1
|
||||||
for id in $POD_ID_LIST; do
|
for id in $POD_ID_LIST; do
|
||||||
CURRENT_STATUS=$($KUBECFG -template '{{and .CurrentState.Info.mynginx.State.Running .CurrentState.Info.net.State.Running}}' get pods/$id)
|
CURRENT_STATUS=$($KUBECFG -template '{{and .CurrentState.Info.mynginx.State.Running .CurrentState.Info.net.State.Running}}' get pods/$id)
|
||||||
if [ "$CURRENT_STATUS" != "{}" ]; then
|
if [ "$CURRENT_STATUS" != "{0001-01-01 00:00:00 +0000 UTC}" ]; then
|
||||||
ALL_RUNNING=0
|
ALL_RUNNING=0
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
@ -47,12 +47,12 @@ function validate() {
|
|||||||
local template_string current_status current_image host_ip
|
local template_string current_status current_image host_ip
|
||||||
template_string="{{and ((index .CurrentState.Info \"${CONTROLLER_NAME}\").State.Running) .CurrentState.Info.net.State.Running}}"
|
template_string="{{and ((index .CurrentState.Info \"${CONTROLLER_NAME}\").State.Running) .CurrentState.Info.net.State.Running}}"
|
||||||
current_status=$($KUBECFG -template="${template_string}" get "pods/$id")
|
current_status=$($KUBECFG -template="${template_string}" get "pods/$id")
|
||||||
if [[ "$current_status" != "{}" ]]; then
|
if [ "$current_status" != "{0001-01-01 00:00:00 +0000 UTC}" ]; then
|
||||||
echo " $id is created but not running"
|
echo " $id is created but not running"
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
template_string="{{(index .CurrentState.Info \"${CONTROLLER_NAME}\").DetailInfo.Config.Image}}"
|
template_string="{{(index .CurrentState.Info \"${CONTROLLER_NAME}\").Image}}"
|
||||||
current_image=$($KUBECFG -template="${template_string}" get "pods/$id")
|
current_image=$($KUBECFG -template="${template_string}" get "pods/$id")
|
||||||
if [[ "$current_image" != "${DOCKER_HUB_USER}/update-demo:${container_image_version}" ]]; then
|
if [[ "$current_image" != "${DOCKER_HUB_USER}/update-demo:${container_image_version}" ]]; then
|
||||||
echo " ${id} is created but running wrong image"
|
echo " ${id} is created but running wrong image"
|
||||||
|
@ -18,9 +18,9 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
"github.com/fsouza/go-dockerclient"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Common string formats
|
// Common string formats
|
||||||
@ -302,12 +302,15 @@ type ContainerStateWaiting struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ContainerStateRunning struct {
|
type ContainerStateRunning struct {
|
||||||
|
StartedAt time.Time `json:"startedAt,omitempty" yaml:"startedAt,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContainerStateTerminated struct {
|
type ContainerStateTerminated struct {
|
||||||
ExitCode int `json:"exitCode,omitempty" yaml:"exitCode,omitempty"`
|
ExitCode int `json:"exitCode" yaml:"exitCode"`
|
||||||
Signal int `json:"signal,omitempty" yaml:"signal,omitempty"`
|
Signal int `json:"signal,omitempty" yaml:"signal,omitempty"`
|
||||||
Reason string `json:"reason,omitempty" yaml:"reason,omitempty"`
|
Reason string `json:"reason,omitempty" yaml:"reason,omitempty"`
|
||||||
|
StartedAt time.Time `json:"startedAt,omitempty" yaml:"startedAt,omitempty"`
|
||||||
|
FinishedAt time.Time `json:"finishedAt,omitempty" yaml:"finishedAt,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContainerState struct {
|
type ContainerState struct {
|
||||||
@ -323,12 +326,13 @@ type ContainerStatus struct {
|
|||||||
// defined for container?
|
// defined for container?
|
||||||
State ContainerState `json:"state,omitempty" yaml:"state,omitempty"`
|
State ContainerState `json:"state,omitempty" yaml:"state,omitempty"`
|
||||||
RestartCount int `json:"restartCount" yaml:"restartCount"`
|
RestartCount int `json:"restartCount" yaml:"restartCount"`
|
||||||
// TODO(dchen1107): Introduce our own NetworkSettings struct here?
|
// TODO(dchen1107): Deprecated this soon once we pull entire PodStatus from node,
|
||||||
|
// not just PodInfo. Now we need this to remove docker.Container from API
|
||||||
|
PodIP string `json:"podIP,omitempty" yaml:"podIP,omitempty"`
|
||||||
|
// TODO(dchen1107): Need to decide how to represent this in v1beta3
|
||||||
|
Image string `yaml:"image" json:"image"`
|
||||||
// TODO(dchen1107): Once we have done with integration with cadvisor, resource
|
// TODO(dchen1107): Once we have done with integration with cadvisor, resource
|
||||||
// usage should be included.
|
// usage should be included.
|
||||||
// TODO(dchen1107): In long run, I think we should replace this with our own struct to remove
|
|
||||||
// the dependency on docker.
|
|
||||||
DetailInfo docker.Container `json:"detailInfo,omitempty" yaml:"detailInfo,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PodInfo contains one entry for every container with available info.
|
// PodInfo contains one entry for every container with available info.
|
||||||
|
@ -17,8 +17,9 @@ limitations under the License.
|
|||||||
package v1beta1
|
package v1beta1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
"github.com/fsouza/go-dockerclient"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Common string formats
|
// Common string formats
|
||||||
@ -286,12 +287,15 @@ type ContainerStateWaiting struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ContainerStateRunning struct {
|
type ContainerStateRunning struct {
|
||||||
|
StartedAt time.Time `json:"startedAt,omitempty" yaml:"startedAt,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContainerStateTerminated struct {
|
type ContainerStateTerminated struct {
|
||||||
ExitCode int `json:"exitCode,omitempty" yaml:"exitCode,omitempty"`
|
ExitCode int `json:"exitCode" yaml:"exitCode"`
|
||||||
Signal int `json:"signal,omitempty" yaml:"signal,omitempty"`
|
Signal int `json:"signal,omitempty" yaml:"signal,omitempty"`
|
||||||
Reason string `json:"reason,omitempty" yaml:"reason,omitempty"`
|
Reason string `json:"reason,omitempty" yaml:"reason,omitempty"`
|
||||||
|
StartedAt time.Time `json:"startedAt,omitempty" yaml:"startedAt,omitempty"`
|
||||||
|
FinishedAt time.Time `json:"finishedAt,omitempty" yaml:"finishedAt,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContainerState struct {
|
type ContainerState struct {
|
||||||
@ -307,12 +311,13 @@ type ContainerStatus struct {
|
|||||||
// defined for container?
|
// defined for container?
|
||||||
State ContainerState `json:"state,omitempty" yaml:"state,omitempty"`
|
State ContainerState `json:"state,omitempty" yaml:"state,omitempty"`
|
||||||
RestartCount int `json:"restartCount" yaml:"restartCount"`
|
RestartCount int `json:"restartCount" yaml:"restartCount"`
|
||||||
// TODO(dchen1107): Introduce our own NetworkSettings struct here?
|
// TODO(dchen1107): Deprecated this soon once we pull entire PodStatus from node,
|
||||||
|
// not just PodInfo. Now we need this to remove docker.Container from API
|
||||||
|
PodIP string `json:"podIP,omitempty" yaml:"podIP,omitempty"`
|
||||||
|
// TODO(dchen1107): Need to decide how to reprensent this in v1beta3
|
||||||
|
Image string `yaml:"image" json:"image"`
|
||||||
// TODO(dchen1107): Once we have done with integration with cadvisor, resource
|
// TODO(dchen1107): Once we have done with integration with cadvisor, resource
|
||||||
// usage should be included.
|
// usage should be included.
|
||||||
// TODO(dchen1107): In long run, I think we should replace this with our own struct to remove
|
|
||||||
// the dependency on docker.
|
|
||||||
DetailInfo docker.Container `json:"detailInfo,omitempty" yaml:"detailInfo,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PodInfo contains one entry for every container with available info.
|
// PodInfo contains one entry for every container with available info.
|
||||||
|
@ -17,8 +17,9 @@ limitations under the License.
|
|||||||
package v1beta2
|
package v1beta2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
"github.com/fsouza/go-dockerclient"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Common string formats
|
// Common string formats
|
||||||
@ -282,12 +283,15 @@ type ContainerStateWaiting struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ContainerStateRunning struct {
|
type ContainerStateRunning struct {
|
||||||
|
StartedAt time.Time `json:"startedAt,omitempty" yaml:"startedAt,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContainerStateTerminated struct {
|
type ContainerStateTerminated struct {
|
||||||
ExitCode int `json:"exitCode,omitempty" yaml:"exitCode,omitempty"`
|
ExitCode int `json:"exitCode" yaml:"exitCode"`
|
||||||
Signal int `json:"signal,omitempty" yaml:"signal,omitempty"`
|
Signal int `json:"signal,omitempty" yaml:"signal,omitempty"`
|
||||||
Reason string `json:"reason,omitempty" yaml:"reason,omitempty"`
|
Reason string `json:"reason,omitempty" yaml:"reason,omitempty"`
|
||||||
|
StartedAt time.Time `json:"startedAt,omitempty" yaml:"startedAt,omitempty"`
|
||||||
|
FinishedAt time.Time `json:"finishedAt,omitempty" yaml:"finishedAt,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContainerState struct {
|
type ContainerState struct {
|
||||||
@ -303,16 +307,16 @@ type ContainerStatus struct {
|
|||||||
// defined for container?
|
// defined for container?
|
||||||
State ContainerState `json:"state,omitempty" yaml:"state,omitempty"`
|
State ContainerState `json:"state,omitempty" yaml:"state,omitempty"`
|
||||||
RestartCount int `json:"restartCount" yaml:"restartCount"`
|
RestartCount int `json:"restartCount" yaml:"restartCount"`
|
||||||
// TODO(dchen1107): Introduce our own NetworkSettings struct here?
|
// TODO(dchen1107): Deprecated this soon once we pull entire PodStatus from node,
|
||||||
|
// not just PodInfo. Now we need this to remove docker.Container from API
|
||||||
|
PodIP string `json:"podIP,omitempty" yaml:"podIP,omitempty"`
|
||||||
|
// TODO(dchen1107): Need to decide how to reprensent this in v1beta3
|
||||||
|
Image string `yaml:"image" json:"image"`
|
||||||
// TODO(dchen1107): Once we have done with integration with cadvisor, resource
|
// TODO(dchen1107): Once we have done with integration with cadvisor, resource
|
||||||
// usage should be included.
|
// usage should be included.
|
||||||
// TODO(dchen1107): In long run, I think we should replace this with our own struct to remove
|
|
||||||
// the dependency on docker.
|
|
||||||
DetailInfo docker.Container `json:"detailInfo,omitempty" yaml:"detailInfo,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PodInfo contains one entry for every container with available info.
|
// PodInfo contains one entry for every container with available info.
|
||||||
// TODO(dchen1107): Replace docker.Container below with ContainerStatus defined above.
|
|
||||||
type PodInfo map[string]ContainerStatus
|
type PodInfo map[string]ContainerStatus
|
||||||
|
|
||||||
type RestartPolicyAlways struct{}
|
type RestartPolicyAlways struct{}
|
||||||
|
@ -17,8 +17,9 @@ limitations under the License.
|
|||||||
package v1beta3
|
package v1beta3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
"github.com/fsouza/go-dockerclient"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Common string formats
|
// Common string formats
|
||||||
@ -312,12 +313,15 @@ type ContainerStateWaiting struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ContainerStateRunning struct {
|
type ContainerStateRunning struct {
|
||||||
|
StartedAt time.Time `json:"startedAt,omitempty" yaml:"startedAt,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContainerStateTerminated struct {
|
type ContainerStateTerminated struct {
|
||||||
ExitCode int `json:"exitCode,omitempty" yaml:"exitCode,omitempty"`
|
ExitCode int `json:"exitCode" yaml:"exitCode"`
|
||||||
Signal int `json:"signal,omitempty" yaml:"signal,omitempty"`
|
Signal int `json:"signal,omitempty" yaml:"signal,omitempty"`
|
||||||
Reason string `json:"reason,omitempty" yaml:"reason,omitempty"`
|
Reason string `json:"reason,omitempty" yaml:"reason,omitempty"`
|
||||||
|
StartedAt time.Time `json:"startedAt,omitempty" yaml:"startedAt,omitempty"`
|
||||||
|
FinishedAt time.Time `json:"finishedAt,omitempty" yaml:"finishedAt,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContainerState struct {
|
type ContainerState struct {
|
||||||
@ -334,16 +338,14 @@ type ContainerStatus struct {
|
|||||||
State ContainerState `json:"state,omitempty" yaml:"state,omitempty"`
|
State ContainerState `json:"state,omitempty" yaml:"state,omitempty"`
|
||||||
RestartCount int `json:"restartCount" yaml:"restartCount"`
|
RestartCount int `json:"restartCount" yaml:"restartCount"`
|
||||||
// TODO(dchen1107): Introduce our own NetworkSettings struct here?
|
// TODO(dchen1107): Introduce our own NetworkSettings struct here?
|
||||||
|
// TODO(dchen1107): Which image the container is running with?
|
||||||
// TODO(dchen1107): Once we have done with integration with cadvisor, resource
|
// TODO(dchen1107): Once we have done with integration with cadvisor, resource
|
||||||
// usage should be included.
|
// usage should be included.
|
||||||
// TODO(dchen1107): In long run, I think we should replace this with our own struct to remove
|
|
||||||
// the dependency on docker.
|
|
||||||
DetailInfo docker.Container `json:"detailInfo,omitempty" yaml:"detailInfo,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PodInfo contains one entry for every container with available info.
|
// PodInfo contains one entry for every container with available info.
|
||||||
// TODO(dchen1107): Replace docker.Container below with ContainerStatus defined above.
|
// TODO(dchen1107): Replace docker.Container below with ContainerStatus defined above.
|
||||||
type PodInfo map[string]docker.Container
|
type PodInfo map[string]ContainerStatus
|
||||||
|
|
||||||
type RestartPolicyAlways struct{}
|
type RestartPolicyAlways struct{}
|
||||||
|
|
||||||
|
@ -27,14 +27,11 @@ import (
|
|||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
"github.com/fsouza/go-dockerclient"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHTTPPodInfoGetter(t *testing.T) {
|
func TestHTTPPodInfoGetter(t *testing.T) {
|
||||||
expectObj := api.PodInfo{
|
expectObj := api.PodInfo{
|
||||||
"myID": api.ContainerStatus{
|
"myID": api.ContainerStatus{},
|
||||||
DetailInfo: docker.Container{ID: "myID"},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
body, err := json.Marshal(expectObj)
|
body, err := json.Marshal(expectObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -69,17 +66,14 @@ func TestHTTPPodInfoGetter(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// reflect.DeepEqual(expectObj, gotObj) doesn't handle blank times well
|
// reflect.DeepEqual(expectObj, gotObj) doesn't handle blank times well
|
||||||
if len(gotObj) != len(expectObj) ||
|
if len(gotObj) != len(expectObj) {
|
||||||
expectObj["myID"].DetailInfo.ID != gotObj["myID"].DetailInfo.ID {
|
|
||||||
t.Errorf("Unexpected response. Expected: %#v, received %#v", expectObj, gotObj)
|
t.Errorf("Unexpected response. Expected: %#v, received %#v", expectObj, gotObj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHTTPPodInfoGetterNotFound(t *testing.T) {
|
func TestHTTPPodInfoGetterNotFound(t *testing.T) {
|
||||||
expectObj := api.PodInfo{
|
expectObj := api.PodInfo{
|
||||||
"myID": api.ContainerStatus{
|
"myID": api.ContainerStatus{},
|
||||||
DetailInfo: docker.Container{ID: "myID"},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
_, err := json.Marshal(expectObj)
|
_, err := json.Marshal(expectObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -270,30 +270,66 @@ func GetKubeletDockerContainerLogs(client DockerInterface, containerID, tail str
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateContainerStatus(inspectResult *docker.Container) api.ContainerStatus {
|
var (
|
||||||
|
// ErrNoContainersInPod is returned when there are no containers for a given pod
|
||||||
|
ErrNoContainersInPod = errors.New("no containers exist for this pod")
|
||||||
|
|
||||||
|
// ErrNoNetworkContainerInPod is returned when there is no network container for a given pod
|
||||||
|
ErrNoNetworkContainerInPod = errors.New("No network container exists for this pod")
|
||||||
|
|
||||||
|
// ErrContainerCannotRun is returned when a container is created, but cannot run properly
|
||||||
|
ErrContainerCannotRun = errors.New("Container cannot run")
|
||||||
|
)
|
||||||
|
|
||||||
|
func inspectContainer(client DockerInterface, dockerID, containerName string) (*api.ContainerStatus, error) {
|
||||||
|
inspectResult, err := client.InspectContainer(dockerID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if inspectResult == nil {
|
if inspectResult == nil {
|
||||||
// Why did we not get an error?
|
// Why did we not get an error?
|
||||||
return api.ContainerStatus{}
|
return &api.ContainerStatus{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var containerStatus api.ContainerStatus
|
glog.V(3).Infof("Container: %s [%s] inspect result %+v", *inspectResult)
|
||||||
|
containerStatus := api.ContainerStatus{
|
||||||
|
Image: inspectResult.Config.Image,
|
||||||
|
}
|
||||||
|
|
||||||
|
waiting := true
|
||||||
if inspectResult.State.Running {
|
if inspectResult.State.Running {
|
||||||
containerStatus.State.Running = &api.ContainerStateRunning{}
|
containerStatus.State.Running = &api.ContainerStateRunning{
|
||||||
} else {
|
StartedAt: inspectResult.State.StartedAt,
|
||||||
|
}
|
||||||
|
if containerName == "net" && inspectResult.NetworkSettings != nil {
|
||||||
|
containerStatus.PodIP = inspectResult.NetworkSettings.IPAddress
|
||||||
|
}
|
||||||
|
waiting = false
|
||||||
|
} else if !inspectResult.State.FinishedAt.IsZero() {
|
||||||
|
// TODO(dchen1107): Integrate with event to provide a better reason
|
||||||
containerStatus.State.Termination = &api.ContainerStateTerminated{
|
containerStatus.State.Termination = &api.ContainerStateTerminated{
|
||||||
ExitCode: inspectResult.State.ExitCode,
|
ExitCode: inspectResult.State.ExitCode,
|
||||||
|
Reason: "",
|
||||||
|
StartedAt: inspectResult.State.StartedAt,
|
||||||
|
FinishedAt: inspectResult.State.FinishedAt,
|
||||||
|
}
|
||||||
|
waiting = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if waiting {
|
||||||
|
// TODO(dchen1107): Separate issue docker/docker#8294 was filed
|
||||||
|
// TODO(dchen1107): Need to figure out why we are still waiting
|
||||||
|
// Check any issue to run container
|
||||||
|
containerStatus.State.Waiting = &api.ContainerStateWaiting{
|
||||||
|
Reason: ErrContainerCannotRun.Error(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
containerStatus.DetailInfo = *inspectResult
|
|
||||||
return containerStatus
|
return &containerStatus, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrNoContainersInPod is returned when there are no containers for a given pod
|
|
||||||
var ErrNoContainersInPod = errors.New("no containers exist for this pod")
|
|
||||||
|
|
||||||
// GetDockerPodInfo returns docker info for all containers in the pod/manifest.
|
// GetDockerPodInfo returns docker info for all containers in the pod/manifest.
|
||||||
func GetDockerPodInfo(client DockerInterface, podFullName, uuid string) (api.PodInfo, error) {
|
func GetDockerPodInfo(client DockerInterface, manifest api.ContainerManifest, podFullName, uuid string) (api.PodInfo, error) {
|
||||||
info := api.PodInfo{}
|
info := api.PodInfo{}
|
||||||
|
|
||||||
containers, err := client.ListContainers(docker.ListContainersOptions{All: true})
|
containers, err := client.ListContainers(docker.ListContainersOptions{All: true})
|
||||||
@ -316,16 +352,53 @@ func GetDockerPodInfo(client DockerInterface, podFullName, uuid string) (api.Pod
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
inspectResult, err := client.InspectContainer(value.ID)
|
containerStatus, err := inspectContainer(client, value.ID, dockerContainerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
info[dockerContainerName] = generateContainerStatus(inspectResult)
|
info[dockerContainerName] = *containerStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(info) == 0 {
|
if len(info) == 0 {
|
||||||
return nil, ErrNoContainersInPod
|
return nil, ErrNoContainersInPod
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// First make sure we are not missing network container
|
||||||
|
if _, found := info["net"]; !found {
|
||||||
|
return nil, ErrNoNetworkContainerInPod
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(info) < (len(manifest.Containers) + 1) {
|
||||||
|
var containerStatus api.ContainerStatus
|
||||||
|
// Not all containers expected are created, verify if there are
|
||||||
|
// image related issues
|
||||||
|
for _, container := range manifest.Containers {
|
||||||
|
if _, found := info[container.Name]; found {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
image := container.Image
|
||||||
|
// Check image is ready on the node or not
|
||||||
|
// TODO(dchen1107): docker/docker/issues/8365 to figure out if the image exists
|
||||||
|
_, err := client.InspectImage(image)
|
||||||
|
if err == nil {
|
||||||
|
containerStatus.State.Waiting = &api.ContainerStateWaiting{
|
||||||
|
Reason: fmt.Sprintf("Image: %s is ready, container is creating", image),
|
||||||
|
}
|
||||||
|
} else if err == docker.ErrNoSuchImage {
|
||||||
|
containerStatus.State.Waiting = &api.ContainerStateWaiting{
|
||||||
|
Reason: fmt.Sprintf("Image: %s is not ready on the node", image),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
containerStatus.State.Waiting = &api.ContainerStateWaiting{
|
||||||
|
Reason: err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info[container.Name] = containerStatus
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return info, nil
|
return info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ type FakeDockerClient struct {
|
|||||||
sync.Mutex
|
sync.Mutex
|
||||||
ContainerList []docker.APIContainers
|
ContainerList []docker.APIContainers
|
||||||
Container *docker.Container
|
Container *docker.Container
|
||||||
|
Image *docker.Image
|
||||||
Err error
|
Err error
|
||||||
called []string
|
called []string
|
||||||
Stopped []string
|
Stopped []string
|
||||||
@ -67,10 +68,19 @@ func (f *FakeDockerClient) ListContainers(options docker.ListContainersOptions)
|
|||||||
func (f *FakeDockerClient) InspectContainer(id string) (*docker.Container, error) {
|
func (f *FakeDockerClient) InspectContainer(id string) (*docker.Container, error) {
|
||||||
f.Lock()
|
f.Lock()
|
||||||
defer f.Unlock()
|
defer f.Unlock()
|
||||||
f.called = append(f.called, "inspect")
|
f.called = append(f.called, "inspect_container")
|
||||||
return f.Container, f.Err
|
return f.Container, f.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InspectImage is a test-spy implementation of DockerInterface.InspectImage.
|
||||||
|
// It adds an entry "inspect" to the internal method call record.
|
||||||
|
func (f *FakeDockerClient) InspectImage(name string) (*docker.Image, error) {
|
||||||
|
f.Lock()
|
||||||
|
defer f.Unlock()
|
||||||
|
f.called = append(f.called, "inspect_image")
|
||||||
|
return f.Image, f.Err
|
||||||
|
}
|
||||||
|
|
||||||
// CreateContainer is a test-spy implementation of DockerInterface.CreateContainer.
|
// CreateContainer is a test-spy implementation of DockerInterface.CreateContainer.
|
||||||
// It adds an entry "create" to the internal method call record.
|
// It adds an entry "create" to the internal method call record.
|
||||||
func (f *FakeDockerClient) CreateContainer(c docker.CreateContainerOptions) (*docker.Container, error) {
|
func (f *FakeDockerClient) CreateContainer(c docker.CreateContainerOptions) (*docker.Container, error) {
|
||||||
@ -130,10 +140,6 @@ func (f *FakeDockerClient) PullImage(opts docker.PullImageOptions, auth docker.A
|
|||||||
return f.Err
|
return f.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FakeDockerClient) InspectImage(name string) (*docker.Image, error) {
|
|
||||||
return nil, f.Err
|
|
||||||
}
|
|
||||||
|
|
||||||
// FakeDockerPuller is a stub implementation of DockerPuller.
|
// FakeDockerPuller is a stub implementation of DockerPuller.
|
||||||
type FakeDockerPuller struct {
|
type FakeDockerPuller struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
|
@ -77,8 +77,8 @@ func (h *httpActionHandler) Run(podFullName, uuid string, container *api.Contain
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
netInfo, found := info[networkContainerName]
|
netInfo, found := info[networkContainerName]
|
||||||
if found && netInfo.DetailInfo.NetworkSettings != nil {
|
if found {
|
||||||
host = netInfo.DetailInfo.NetworkSettings.IPAddress
|
host = netInfo.PodIP
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("failed to find networking container: %v", info)
|
return fmt.Errorf("failed to find networking container: %v", info)
|
||||||
}
|
}
|
||||||
|
@ -113,6 +113,7 @@ type Kubelet struct {
|
|||||||
networkContainerImage string
|
networkContainerImage string
|
||||||
podWorkers podWorkers
|
podWorkers podWorkers
|
||||||
resyncInterval time.Duration
|
resyncInterval time.Duration
|
||||||
|
pods []Pod
|
||||||
|
|
||||||
// Optional, no events will be sent without it
|
// Optional, no events will be sent without it
|
||||||
etcdClient tools.EtcdClient
|
etcdClient tools.EtcdClient
|
||||||
@ -482,8 +483,8 @@ func (kl *Kubelet) syncPod(pod *Pod, dockerContainers dockertools.DockerContaine
|
|||||||
podFullName, uuid)
|
podFullName, uuid)
|
||||||
}
|
}
|
||||||
netInfo, found := info[networkContainerName]
|
netInfo, found := info[networkContainerName]
|
||||||
if found && netInfo.DetailInfo.NetworkSettings != nil {
|
if found {
|
||||||
podState.PodIP = netInfo.DetailInfo.NetworkSettings.IPAddress
|
podState.PodIP = netInfo.PodIP
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, container := range pod.Manifest.Containers {
|
for _, container := range pod.Manifest.Containers {
|
||||||
@ -699,15 +700,14 @@ func filterHostPortConflicts(pods []Pod) []Pod {
|
|||||||
// no changes are seen to the configuration, will synchronize the last known desired
|
// no changes are seen to the configuration, will synchronize the last known desired
|
||||||
// state every sync_frequency seconds. Never returns.
|
// state every sync_frequency seconds. Never returns.
|
||||||
func (kl *Kubelet) syncLoop(updates <-chan PodUpdate, handler SyncHandler) {
|
func (kl *Kubelet) syncLoop(updates <-chan PodUpdate, handler SyncHandler) {
|
||||||
var pods []Pod
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case u := <-updates:
|
case u := <-updates:
|
||||||
switch u.Op {
|
switch u.Op {
|
||||||
case SET:
|
case SET:
|
||||||
glog.V(3).Infof("Containers changed [%s]", kl.hostname)
|
glog.V(3).Infof("Containers changed [%s]", kl.hostname)
|
||||||
pods = u.Pods
|
kl.pods = u.Pods
|
||||||
pods = filterHostPortConflicts(pods)
|
kl.pods = filterHostPortConflicts(kl.pods)
|
||||||
|
|
||||||
case UPDATE:
|
case UPDATE:
|
||||||
//TODO: implement updates of containers
|
//TODO: implement updates of containers
|
||||||
@ -718,12 +718,12 @@ func (kl *Kubelet) syncLoop(updates <-chan PodUpdate, handler SyncHandler) {
|
|||||||
panic("syncLoop does not support incremental changes")
|
panic("syncLoop does not support incremental changes")
|
||||||
}
|
}
|
||||||
case <-time.After(kl.resyncInterval):
|
case <-time.After(kl.resyncInterval):
|
||||||
if pods == nil {
|
if kl.pods == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := handler.SyncPods(pods)
|
err := handler.SyncPods(kl.pods)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Couldn't sync containers : %v", err)
|
glog.Errorf("Couldn't sync containers : %v", err)
|
||||||
}
|
}
|
||||||
@ -769,7 +769,14 @@ func (kl *Kubelet) GetKubeletContainerLogs(podFullName, containerName, tail stri
|
|||||||
|
|
||||||
// GetPodInfo returns information from Docker about the containers in a pod
|
// GetPodInfo returns information from Docker about the containers in a pod
|
||||||
func (kl *Kubelet) GetPodInfo(podFullName, uuid string) (api.PodInfo, error) {
|
func (kl *Kubelet) GetPodInfo(podFullName, uuid string) (api.PodInfo, error) {
|
||||||
return dockertools.GetDockerPodInfo(kl.dockerClient, podFullName, uuid)
|
var manifest api.ContainerManifest
|
||||||
|
for _, pod := range kl.pods {
|
||||||
|
if GetPodFullName(&pod) == podFullName {
|
||||||
|
manifest = pod.Manifest
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dockertools.GetDockerPodInfo(kl.dockerClient, manifest, podFullName, uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetContainerInfo returns stats (from Cadvisor) for a container.
|
// GetContainerInfo returns stats (from Cadvisor) for a container.
|
||||||
|
@ -227,7 +227,7 @@ func TestSyncPodsCreatesNetAndContainer(t *testing.T) {
|
|||||||
kubelet.drainWorkers()
|
kubelet.drainWorkers()
|
||||||
|
|
||||||
verifyCalls(t, fakeDocker, []string{
|
verifyCalls(t, fakeDocker, []string{
|
||||||
"list", "list", "create", "start", "list", "inspect", "list", "create", "start"})
|
"list", "list", "create", "start", "list", "inspect_container", "list", "create", "start"})
|
||||||
|
|
||||||
fakeDocker.Lock()
|
fakeDocker.Lock()
|
||||||
|
|
||||||
@ -273,7 +273,7 @@ func TestSyncPodsCreatesNetAndContainerPullsImage(t *testing.T) {
|
|||||||
kubelet.drainWorkers()
|
kubelet.drainWorkers()
|
||||||
|
|
||||||
verifyCalls(t, fakeDocker, []string{
|
verifyCalls(t, fakeDocker, []string{
|
||||||
"list", "list", "create", "start", "list", "inspect", "list", "create", "start"})
|
"list", "list", "create", "start", "list", "inspect_container", "list", "create", "start"})
|
||||||
|
|
||||||
fakeDocker.Lock()
|
fakeDocker.Lock()
|
||||||
|
|
||||||
@ -316,7 +316,7 @@ func TestSyncPodsWithNetCreatesContainer(t *testing.T) {
|
|||||||
kubelet.drainWorkers()
|
kubelet.drainWorkers()
|
||||||
|
|
||||||
verifyCalls(t, fakeDocker, []string{
|
verifyCalls(t, fakeDocker, []string{
|
||||||
"list", "list", "list", "inspect", "list", "create", "start"})
|
"list", "list", "list", "inspect_container", "list", "create", "start"})
|
||||||
|
|
||||||
fakeDocker.Lock()
|
fakeDocker.Lock()
|
||||||
if len(fakeDocker.Created) != 1 ||
|
if len(fakeDocker.Created) != 1 ||
|
||||||
@ -366,7 +366,7 @@ func TestSyncPodsWithNetCreatesContainerCallsHandler(t *testing.T) {
|
|||||||
kubelet.drainWorkers()
|
kubelet.drainWorkers()
|
||||||
|
|
||||||
verifyCalls(t, fakeDocker, []string{
|
verifyCalls(t, fakeDocker, []string{
|
||||||
"list", "list", "list", "inspect", "list", "create", "start"})
|
"list", "list", "list", "inspect_container", "list", "create", "start"})
|
||||||
|
|
||||||
fakeDocker.Lock()
|
fakeDocker.Lock()
|
||||||
if len(fakeDocker.Created) != 1 ||
|
if len(fakeDocker.Created) != 1 ||
|
||||||
@ -406,7 +406,7 @@ func TestSyncPodsDeletesWithNoNetContainer(t *testing.T) {
|
|||||||
kubelet.drainWorkers()
|
kubelet.drainWorkers()
|
||||||
|
|
||||||
verifyCalls(t, fakeDocker, []string{
|
verifyCalls(t, fakeDocker, []string{
|
||||||
"list", "list", "stop", "create", "start", "list", "list", "inspect", "list", "create", "start"})
|
"list", "list", "stop", "create", "start", "list", "list", "inspect_container", "list", "create", "start"})
|
||||||
|
|
||||||
// A map iteration is used to delete containers, so must not depend on
|
// A map iteration is used to delete containers, so must not depend on
|
||||||
// order here.
|
// order here.
|
||||||
|
@ -85,8 +85,20 @@ func TestRunOnce(t *testing.T) {
|
|||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
inspectContainersResults: []inspectContainersResult{
|
inspectContainersResults: []inspectContainersResult{
|
||||||
{label: "syncPod", container: docker.Container{State: docker.State{Running: true}}},
|
{
|
||||||
{label: "syncPod", container: docker.Container{State: docker.State{Running: true}}},
|
label: "syncPod",
|
||||||
|
container: docker.Container{
|
||||||
|
Config: &docker.Config{Image: "someimage"},
|
||||||
|
State: docker.State{Running: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "syncPod",
|
||||||
|
container: docker.Container{
|
||||||
|
Config: &docker.Config{Image: "someimage"},
|
||||||
|
State: docker.State{Running: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
t: t,
|
t: t,
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,6 @@ import (
|
|||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
"github.com/fsouza/go-dockerclient"
|
|
||||||
"github.com/google/cadvisor/info"
|
"github.com/google/cadvisor/info"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -147,9 +146,7 @@ func TestContainers(t *testing.T) {
|
|||||||
func TestPodInfo(t *testing.T) {
|
func TestPodInfo(t *testing.T) {
|
||||||
fw := newServerTest()
|
fw := newServerTest()
|
||||||
expected := api.PodInfo{
|
expected := api.PodInfo{
|
||||||
"goodpod": api.ContainerStatus{
|
"goodpod": api.ContainerStatus{},
|
||||||
DetailInfo: docker.Container{ID: "myContainerID"},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
fw.fakeKubelet.infoFunc = func(name string) (api.PodInfo, error) {
|
fw.fakeKubelet.infoFunc = func(name string) (api.PodInfo, error) {
|
||||||
if name == "goodpod.etcd" {
|
if name == "goodpod.etcd" {
|
||||||
|
@ -22,7 +22,6 @@ import (
|
|||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
|
||||||
"github.com/fsouza/go-dockerclient"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type FakePodInfoGetter struct {
|
type FakePodInfoGetter struct {
|
||||||
@ -42,9 +41,7 @@ func TestPodCacheGet(t *testing.T) {
|
|||||||
cache := NewPodCache(nil, nil)
|
cache := NewPodCache(nil, nil)
|
||||||
|
|
||||||
expected := api.PodInfo{
|
expected := api.PodInfo{
|
||||||
"foo": api.ContainerStatus{
|
"foo": api.ContainerStatus{},
|
||||||
DetailInfo: docker.Container{ID: "foo"},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
cache.podInfo["foo"] = expected
|
cache.podInfo["foo"] = expected
|
||||||
|
|
||||||
@ -71,9 +68,7 @@ func TestPodCacheGetMissing(t *testing.T) {
|
|||||||
|
|
||||||
func TestPodGetPodInfoGetter(t *testing.T) {
|
func TestPodGetPodInfoGetter(t *testing.T) {
|
||||||
expected := api.PodInfo{
|
expected := api.PodInfo{
|
||||||
"foo": api.ContainerStatus{
|
"foo": api.ContainerStatus{},
|
||||||
DetailInfo: docker.Container{ID: "foo"},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
fake := FakePodInfoGetter{
|
fake := FakePodInfoGetter{
|
||||||
data: expected,
|
data: expected,
|
||||||
@ -107,9 +102,7 @@ func TestPodUpdateAllContainers(t *testing.T) {
|
|||||||
mockRegistry := registrytest.NewPodRegistry(&api.PodList{Items: pods})
|
mockRegistry := registrytest.NewPodRegistry(&api.PodList{Items: pods})
|
||||||
|
|
||||||
expected := api.PodInfo{
|
expected := api.PodInfo{
|
||||||
"foo": api.ContainerStatus{
|
"foo": api.ContainerStatus{},
|
||||||
DetailInfo: docker.Container{ID: "foo"},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
fake := FakePodInfoGetter{
|
fake := FakePodInfoGetter{
|
||||||
data: expected,
|
data: expected,
|
||||||
|
@ -226,8 +226,8 @@ func (rs *REST) fillPodInfo(pod *api.Pod) {
|
|||||||
pod.CurrentState.Info = info
|
pod.CurrentState.Info = info
|
||||||
netContainerInfo, ok := info["net"]
|
netContainerInfo, ok := info["net"]
|
||||||
if ok {
|
if ok {
|
||||||
if netContainerInfo.DetailInfo.NetworkSettings != nil {
|
if netContainerInfo.PodIP != "" {
|
||||||
pod.CurrentState.PodIP = netContainerInfo.DetailInfo.NetworkSettings.IPAddress
|
pod.CurrentState.PodIP = netContainerInfo.PodIP
|
||||||
} else {
|
} else {
|
||||||
glog.Warningf("No network settings: %#v", netContainerInfo)
|
glog.Warningf("No network settings: %#v", netContainerInfo)
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,6 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/registrytest"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
|
|
||||||
"github.com/fsouza/go-dockerclient"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func expectApiStatusError(t *testing.T, ch <-chan runtime.Object, msg string) {
|
func expectApiStatusError(t *testing.T, ch <-chan runtime.Object, msg string) {
|
||||||
@ -605,16 +603,17 @@ func (f *FakePodInfoGetter) GetPodInfo(host, podID string) (api.PodInfo, error)
|
|||||||
|
|
||||||
func TestFillPodInfo(t *testing.T) {
|
func TestFillPodInfo(t *testing.T) {
|
||||||
expectedIP := "1.2.3.4"
|
expectedIP := "1.2.3.4"
|
||||||
|
expectedTime, _ := time.Parse("2013-Feb-03", "2013-Feb-03")
|
||||||
fakeGetter := FakePodInfoGetter{
|
fakeGetter := FakePodInfoGetter{
|
||||||
info: map[string]api.ContainerStatus{
|
info: map[string]api.ContainerStatus{
|
||||||
"net": {
|
"net": {
|
||||||
DetailInfo: docker.Container{
|
State: api.ContainerState{
|
||||||
ID: "foobar",
|
Running: &api.ContainerStateRunning{
|
||||||
Path: "bin/run.sh",
|
StartedAt: expectedTime,
|
||||||
NetworkSettings: &docker.NetworkSettings{
|
|
||||||
IPAddress: expectedIP,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
RestartCount: 1,
|
||||||
|
PodIP: expectedIP,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -636,10 +635,7 @@ func TestFillPodInfoNoData(t *testing.T) {
|
|||||||
fakeGetter := FakePodInfoGetter{
|
fakeGetter := FakePodInfoGetter{
|
||||||
info: map[string]api.ContainerStatus{
|
info: map[string]api.ContainerStatus{
|
||||||
"net": {
|
"net": {
|
||||||
DetailInfo: docker.Container{
|
State: api.ContainerState{},
|
||||||
ID: "foobar",
|
|
||||||
Path: "bin/run.sh",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user