mirror of https://github.com/k3s-io/k3s
Add RuntimeStatus in container/runtime.go
parent
55c5232810
commit
4bd9dbf6ad
|
@ -70,8 +70,9 @@ type Runtime interface {
|
||||||
// This may be different from the runtime engine's version.
|
// This may be different from the runtime engine's version.
|
||||||
// TODO(random-liu): We should fold this into Version()
|
// TODO(random-liu): We should fold this into Version()
|
||||||
APIVersion() (Version, error)
|
APIVersion() (Version, error)
|
||||||
// Status returns error if the runtime is unhealthy; nil otherwise.
|
// Status returns the status of the runtime. An error is returned if the Status
|
||||||
Status() error
|
// function itself fails, nil otherwise.
|
||||||
|
Status() (*RuntimeStatus, error)
|
||||||
// GetPods returns a list of containers grouped by pods. The boolean parameter
|
// GetPods returns a list of containers grouped by pods. The boolean parameter
|
||||||
// specifies whether the runtime returns all containers including those already
|
// specifies whether the runtime returns all containers including those already
|
||||||
// exited and dead containers (used for garbage collection).
|
// exited and dead containers (used for garbage collection).
|
||||||
|
@ -446,6 +447,59 @@ type VolumeInfo struct {
|
||||||
|
|
||||||
type VolumeMap map[string]VolumeInfo
|
type VolumeMap map[string]VolumeInfo
|
||||||
|
|
||||||
|
// RuntimeConditionType is the types of required runtime conditions.
|
||||||
|
type RuntimeConditionType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// RuntimeReady means the runtime is up and ready to accept basic containers.
|
||||||
|
RuntimeReady RuntimeConditionType = "RuntimeReady"
|
||||||
|
// NetworkReady means the runtime network is up and ready to accept containers which require network.
|
||||||
|
NetworkReady RuntimeConditionType = "NetworkReady"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RuntimeStatus contains the status of the runtime.
|
||||||
|
type RuntimeStatus struct {
|
||||||
|
// Conditions is an array of current observed runtime conditions.
|
||||||
|
Conditions []RuntimeCondition
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRuntimeCondition gets a specified runtime condition from the runtime status.
|
||||||
|
func (r *RuntimeStatus) GetRuntimeCondition(t RuntimeConditionType) *RuntimeCondition {
|
||||||
|
for i := range r.Conditions {
|
||||||
|
c := &r.Conditions[i]
|
||||||
|
if c.Type == t {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String formats the runtime status into human readable string.
|
||||||
|
func (s *RuntimeStatus) String() string {
|
||||||
|
var ss []string
|
||||||
|
for _, c := range s.Conditions {
|
||||||
|
ss = append(ss, c.String())
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Runtime Conditions: %s", strings.Join(ss, ", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RuntimeCondition contains condition information for the runtime.
|
||||||
|
type RuntimeCondition struct {
|
||||||
|
// Type of runtime condition.
|
||||||
|
Type RuntimeConditionType
|
||||||
|
// Status of the condition, one of true/false.
|
||||||
|
Status bool
|
||||||
|
// Reason is brief reason for the condition's last transition.
|
||||||
|
Reason string
|
||||||
|
// Message is human readable message indicating details about last transition.
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
// String formats the runtime condition into human readable string.
|
||||||
|
func (c *RuntimeCondition) String() string {
|
||||||
|
return fmt.Sprintf("%s=%t reason:%s message:%s", c.Type, c.Status, c.Reason, c.Message)
|
||||||
|
}
|
||||||
|
|
||||||
type Pods []*Pod
|
type Pods []*Pod
|
||||||
|
|
||||||
// FindPodByID finds and returns a pod in the pod list by UID. It will return an empty pod
|
// FindPodByID finds and returns a pod in the pod list by UID. It will return an empty pod
|
||||||
|
|
|
@ -50,6 +50,7 @@ type FakeRuntime struct {
|
||||||
KilledPods []string
|
KilledPods []string
|
||||||
StartedContainers []string
|
StartedContainers []string
|
||||||
KilledContainers []string
|
KilledContainers []string
|
||||||
|
RuntimeStatus *RuntimeStatus
|
||||||
VersionInfo string
|
VersionInfo string
|
||||||
APIVersionInfo string
|
APIVersionInfo string
|
||||||
RuntimeType string
|
RuntimeType string
|
||||||
|
@ -137,6 +138,7 @@ func (f *FakeRuntime) ClearCalls() {
|
||||||
f.KilledPods = []string{}
|
f.KilledPods = []string{}
|
||||||
f.StartedContainers = []string{}
|
f.StartedContainers = []string{}
|
||||||
f.KilledContainers = []string{}
|
f.KilledContainers = []string{}
|
||||||
|
f.RuntimeStatus = nil
|
||||||
f.VersionInfo = ""
|
f.VersionInfo = ""
|
||||||
f.RuntimeType = ""
|
f.RuntimeType = ""
|
||||||
f.Err = nil
|
f.Err = nil
|
||||||
|
@ -207,12 +209,12 @@ func (f *FakeRuntime) APIVersion() (Version, error) {
|
||||||
return &FakeVersion{Version: f.APIVersionInfo}, f.Err
|
return &FakeVersion{Version: f.APIVersionInfo}, f.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FakeRuntime) Status() error {
|
func (f *FakeRuntime) Status() (*RuntimeStatus, error) {
|
||||||
f.Lock()
|
f.Lock()
|
||||||
defer f.Unlock()
|
defer f.Unlock()
|
||||||
|
|
||||||
f.CalledFunctions = append(f.CalledFunctions, "Status")
|
f.CalledFunctions = append(f.CalledFunctions, "Status")
|
||||||
return f.StatusErr
|
return f.RuntimeStatus, f.StatusErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FakeRuntime) GetPods(all bool) ([]*Pod, error) {
|
func (f *FakeRuntime) GetPods(all bool) ([]*Pod, error) {
|
||||||
|
|
|
@ -54,9 +54,9 @@ func (r *Mock) APIVersion() (Version, error) {
|
||||||
return args.Get(0).(Version), args.Error(1)
|
return args.Get(0).(Version), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Mock) Status() error {
|
func (r *Mock) Status() (*RuntimeStatus, error) {
|
||||||
args := r.Called()
|
args := r.Called()
|
||||||
return args.Error(0)
|
return args.Get(0).(*RuntimeStatus), args.Error(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Mock) GetPods(all bool) ([]*Pod, error) {
|
func (r *Mock) GetPods(all bool) ([]*Pod, error) {
|
||||||
|
|
|
@ -60,7 +60,7 @@ const (
|
||||||
sandboxIDLabelKey = "io.kubernetes.sandbox.id"
|
sandboxIDLabelKey = "io.kubernetes.sandbox.id"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NetworkPluginArgs is the subset of kubelet runtime args we pass
|
// NetworkPluginSettings is the subset of kubelet runtime args we pass
|
||||||
// to the container runtime shim so it can probe for network plugins.
|
// to the container runtime shim so it can probe for network plugins.
|
||||||
// In the future we will feed these directly to a standalone container
|
// In the future we will feed these directly to a standalone container
|
||||||
// runtime process.
|
// runtime process.
|
||||||
|
|
|
@ -1107,8 +1107,8 @@ func (dm *DockerManager) APIVersion() (kubecontainer.Version, error) {
|
||||||
// Now we do this by checking whether:
|
// Now we do this by checking whether:
|
||||||
// 1) `docker version` works
|
// 1) `docker version` works
|
||||||
// 2) docker version is compatible with minimum requirement
|
// 2) docker version is compatible with minimum requirement
|
||||||
func (dm *DockerManager) Status() error {
|
func (dm *DockerManager) Status() (*kubecontainer.RuntimeStatus, error) {
|
||||||
return dm.checkVersionCompatibility()
|
return nil, dm.checkVersionCompatibility()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dm *DockerManager) checkVersionCompatibility() error {
|
func (dm *DockerManager) checkVersionCompatibility() error {
|
||||||
|
|
|
@ -1944,10 +1944,34 @@ func (kl *Kubelet) PLEGHealthCheck() (bool, error) {
|
||||||
// and returns an error if the status check fails. If the status check is OK,
|
// and returns an error if the status check fails. If the status check is OK,
|
||||||
// update the container runtime uptime in the kubelet runtimeState.
|
// update the container runtime uptime in the kubelet runtimeState.
|
||||||
func (kl *Kubelet) updateRuntimeUp() {
|
func (kl *Kubelet) updateRuntimeUp() {
|
||||||
if err := kl.containerRuntime.Status(); err != nil {
|
s, err := kl.containerRuntime.Status()
|
||||||
|
if err != nil {
|
||||||
glog.Errorf("Container runtime sanity check failed: %v", err)
|
glog.Errorf("Container runtime sanity check failed: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Only check specific conditions when runtime integration type is cri,
|
||||||
|
// because the old integration doesn't populate any runtime condition.
|
||||||
|
// TODO(random-liu): Add runtime error in runtimeState, and update it
|
||||||
|
// when when runtime is not ready, so that the information in RuntimeReady
|
||||||
|
// condition will be propagated to NodeReady condition.
|
||||||
|
// TODO(random-liu): Update network state according to NetworkReady runtime
|
||||||
|
// condition once it is implemented in dockershim.
|
||||||
|
if kl.kubeletConfiguration.ExperimentalRuntimeIntegrationType == "cri" {
|
||||||
|
if s == nil {
|
||||||
|
glog.Errorf("Container runtime status is nil")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
runtimeReady := s.GetRuntimeCondition(kubecontainer.RuntimeReady)
|
||||||
|
// Periodically log the whole runtime status for debugging.
|
||||||
|
// TODO(random-liu): Consider to send node event when optional
|
||||||
|
// condition is unmet.
|
||||||
|
glog.V(4).Infof("Container runtime status: %v", s)
|
||||||
|
// If RuntimeReady is not set or is false, report an error.
|
||||||
|
if runtimeReady == nil || !runtimeReady.Status {
|
||||||
|
glog.Errorf("Container runtime not ready: %v", runtimeReady)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
kl.oneTimeInitializer.Do(kl.initializeRuntimeDependentModules)
|
kl.oneTimeInitializer.Do(kl.initializeRuntimeDependentModules)
|
||||||
kl.runtimeState.setRuntimeSync(kl.clock.Now())
|
kl.runtimeState.setRuntimeSync(kl.clock.Now())
|
||||||
}
|
}
|
||||||
|
|
|
@ -865,6 +865,38 @@ func TestUpdateNodeStatusWithRuntimeStateError(t *testing.T) {
|
||||||
clock.SetTime(time.Now())
|
clock.SetTime(time.Now())
|
||||||
kubelet.updateRuntimeUp()
|
kubelet.updateRuntimeUp()
|
||||||
checkNodeStatus(api.ConditionFalse, "KubeletNotReady", downMessage)
|
checkNodeStatus(api.ConditionFalse, "KubeletNotReady", downMessage)
|
||||||
|
|
||||||
|
// Test cri integration.
|
||||||
|
kubelet.kubeletConfiguration.ExperimentalRuntimeIntegrationType = "cri"
|
||||||
|
fakeRuntime.StatusErr = nil
|
||||||
|
|
||||||
|
// Should report node not ready if runtime status is nil.
|
||||||
|
fakeRuntime.RuntimeStatus = nil
|
||||||
|
kubelet.updateRuntimeUp()
|
||||||
|
checkNodeStatus(api.ConditionFalse, "KubeletNotReady", downMessage)
|
||||||
|
|
||||||
|
// Should report node not ready if runtime status is empty.
|
||||||
|
fakeRuntime.RuntimeStatus = &kubecontainer.RuntimeStatus{}
|
||||||
|
kubelet.updateRuntimeUp()
|
||||||
|
checkNodeStatus(api.ConditionFalse, "KubeletNotReady", downMessage)
|
||||||
|
|
||||||
|
// Should report node not ready if RuntimeReady is false.
|
||||||
|
fakeRuntime.RuntimeStatus = &kubecontainer.RuntimeStatus{
|
||||||
|
Conditions: []kubecontainer.RuntimeCondition{
|
||||||
|
{Type: kubecontainer.RuntimeReady, Status: false},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
kubelet.updateRuntimeUp()
|
||||||
|
checkNodeStatus(api.ConditionFalse, "KubeletNotReady", downMessage)
|
||||||
|
|
||||||
|
// Should report node ready if RuntimeReady is true.
|
||||||
|
fakeRuntime.RuntimeStatus = &kubecontainer.RuntimeStatus{
|
||||||
|
Conditions: []kubecontainer.RuntimeCondition{
|
||||||
|
{Type: kubecontainer.RuntimeReady, Status: true},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
kubelet.updateRuntimeUp()
|
||||||
|
checkNodeStatus(api.ConditionTrue, "KubeletReady", readyMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateNodeStatusError(t *testing.T) {
|
func TestUpdateNodeStatusError(t *testing.T) {
|
||||||
|
|
|
@ -217,13 +217,16 @@ func buildPodLogsDirectory(podUID types.UID) string {
|
||||||
return filepath.Join(podLogsRootDirectory, string(podUID))
|
return filepath.Join(podLogsRootDirectory, string(podUID))
|
||||||
}
|
}
|
||||||
|
|
||||||
// getRuntimeCondition gets specified runtime condition from the runtime status.
|
// toKubeRuntimeStatus converts the runtimeApi.RuntimeStatus to kubecontainer.RuntimeStatus.
|
||||||
func getRuntimeCondition(status *runtimeApi.RuntimeStatus, t string) *runtimeApi.RuntimeCondition {
|
func toKubeRuntimeStatus(status *runtimeApi.RuntimeStatus) *kubecontainer.RuntimeStatus {
|
||||||
conditions := status.GetConditions()
|
conditions := []kubecontainer.RuntimeCondition{}
|
||||||
for _, condition := range conditions {
|
for _, c := range status.GetConditions() {
|
||||||
if condition.GetType() == t {
|
conditions = append(conditions, kubecontainer.RuntimeCondition{
|
||||||
return condition
|
Type: kubecontainer.RuntimeConditionType(c.GetType()),
|
||||||
}
|
Status: c.GetStatus(),
|
||||||
|
Reason: c.GetReason(),
|
||||||
|
Message: c.GetMessage(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return nil
|
return &kubecontainer.RuntimeStatus{Conditions: conditions}
|
||||||
}
|
}
|
||||||
|
|
|
@ -268,25 +268,14 @@ func (m *kubeGenericRuntimeManager) APIVersion() (kubecontainer.Version, error)
|
||||||
return newRuntimeVersion(typedVersion.GetRuntimeApiVersion())
|
return newRuntimeVersion(typedVersion.GetRuntimeApiVersion())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status returns error if the runtime is unhealthy; nil otherwise.
|
// Status returns the status of the runtime. An error is returned if the Status
|
||||||
// TODO(random-liu): Change the Status in runtime interface to return runtime status.
|
// function itself fails, nil otherwise.
|
||||||
// TODO(random-liu): Add unit test for this function after addressing the TODO above.
|
func (m *kubeGenericRuntimeManager) Status() (*kubecontainer.RuntimeStatus, error) {
|
||||||
func (m *kubeGenericRuntimeManager) Status() error {
|
|
||||||
status, err := m.runtimeService.Status()
|
status, err := m.runtimeService.Status()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to checkout runtime status: %v", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
networkReady := getRuntimeCondition(status, runtimeApi.NetworkReady)
|
return toKubeRuntimeStatus(status), nil
|
||||||
if networkReady == nil || !networkReady.GetStatus() {
|
|
||||||
return fmt.Errorf("runtime network not ready: reason: %q, message: %q",
|
|
||||||
networkReady.GetReason(), networkReady.GetMessage())
|
|
||||||
}
|
|
||||||
runtimeReady := getRuntimeCondition(status, runtimeApi.RuntimeReady)
|
|
||||||
if runtimeReady == nil || !runtimeReady.GetStatus() {
|
|
||||||
return fmt.Errorf("runtime not ready: reason: %q, message: %q",
|
|
||||||
runtimeReady.GetReason(), runtimeReady.GetMessage())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPods returns a list of containers grouped by pods. The boolean parameter
|
// GetPods returns a list of containers grouped by pods. The boolean parameter
|
||||||
|
|
|
@ -1701,8 +1701,8 @@ func (r *Runtime) APIVersion() (kubecontainer.Version, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status returns error if rkt is unhealthy, nil otherwise.
|
// Status returns error if rkt is unhealthy, nil otherwise.
|
||||||
func (r *Runtime) Status() error {
|
func (r *Runtime) Status() (*kubecontainer.RuntimeStatus, error) {
|
||||||
return r.checkVersion(minimumRktBinVersion, minimumRktApiVersion, minimumSystemdVersion)
|
return nil, r.checkVersion(minimumRktBinVersion, minimumRktApiVersion, minimumSystemdVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SyncPod syncs the running pod to match the specified desired pod.
|
// SyncPod syncs the running pod to match the specified desired pod.
|
||||||
|
|
Loading…
Reference in New Issue