mirror of https://github.com/kubernetes/kops.git
starting porting node code
This commit is contained in:
parent
8d1a921e8b
commit
89ac0d24f8
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kutil
|
||||
|
||||
import (
|
||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
"time"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/pkg/util/wait"
|
||||
"k8s.io/kubernetes/pkg/fields"
|
||||
)
|
||||
|
||||
const (
|
||||
// How often to Poll pods, nodes and claims.
|
||||
Poll = 2 * time.Second
|
||||
|
||||
// How long to try single API calls (like 'get' or 'list'). Used to prevent
|
||||
// transient failures from failing tests.
|
||||
// TODO: client should not apply this timeout to Watch calls. Increased from 30s until that is fixed.
|
||||
SingleCallTimeout = 5 * time.Minute
|
||||
)
|
||||
|
||||
|
||||
// GetReadySchedulableNodesOrDie addresses the common use case of getting nodes you can do work on.
|
||||
// 1) Needs to be schedulable.
|
||||
// 2) Needs to be ready.
|
||||
// If EITHER 1 or 2 is not true, most tests will want to ignore the node entirely.
|
||||
func GetReadySchedulableNodesOrDie(c *client.Client) (nodes *api.NodeList) {
|
||||
nodes = waitListSchedulableNodesOrDie(c)
|
||||
// previous tests may have cause failures of some nodes. Let's skip
|
||||
// 'Not Ready' nodes, just in case (there is no need to fail the test).
|
||||
FilterNodes(nodes, func(node api.Node) bool {
|
||||
return isNodeSchedulable(&node)
|
||||
})
|
||||
return nodes
|
||||
}
|
||||
|
||||
// waitListSchedulableNodesOrDie is a wrapper around listing nodes supporting retries.
|
||||
func waitListSchedulableNodesOrDie(c *client.Client) *api.NodeList {
|
||||
var nodes *api.NodeList
|
||||
var err error
|
||||
if wait.PollImmediate(Poll, SingleCallTimeout, func() (bool, error) {
|
||||
nodes, err = c.Nodes().List(api.ListOptions{FieldSelector: fields.Set{
|
||||
"spec.unschedulable": "false",
|
||||
}.AsSelector()})
|
||||
return err == nil, nil
|
||||
}) != nil {
|
||||
ExpectNoError(err, "Timed out while listing nodes for e2e cluster.")
|
||||
}
|
||||
return nodes
|
||||
}
|
||||
|
||||
// Node is schedulable if:
|
||||
// 1) doesn't have "unschedulable" field set
|
||||
// 2) it's Ready condition is set to true
|
||||
// 3) doesn't have NetworkUnavailable condition set to true
|
||||
func isNodeSchedulable(node *api.Node) bool {
|
||||
nodeReady := IsNodeConditionSetAsExpected(node, api.NodeReady, true)
|
||||
networkReady := IsNodeConditionUnset(node, api.NodeNetworkUnavailable) ||
|
||||
IsNodeConditionSetAsExpectedSilent(node, api.NodeNetworkUnavailable, false)
|
||||
return !node.Spec.Unschedulable && nodeReady && networkReady
|
||||
}
|
||||
|
||||
func IsNodeConditionSetAsExpectedSilent(node *api.Node, conditionType api.NodeConditionType, wantTrue bool) bool {
|
||||
return isNodeConditionSetAsExpected(node, conditionType, wantTrue, true)
|
||||
}
|
||||
|
||||
func IsNodeConditionUnset(node *api.Node, conditionType api.NodeConditionType) bool {
|
||||
for _, cond := range node.Status.Conditions {
|
||||
if cond.Type == conditionType {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
func FilterNodes(nodeList *api.NodeList, fn func(node api.Node) bool) {
|
||||
var l []api.Node
|
||||
|
||||
for _, node := range nodeList.Items {
|
||||
if fn(node) {
|
||||
l = append(l, node)
|
||||
}
|
||||
}
|
||||
nodeList.Items = l
|
||||
}
|
||||
|
||||
// waitListSchedulableNodesOrDie is a wrapper around listing nodes supporting retries.
|
||||
func waitListSchedulableNodesOrDie(c *client.Client) (*api.NodeList, error) {
|
||||
var nodes *api.NodeList
|
||||
var err error
|
||||
if wait.PollImmediate(Poll, SingleCallTimeout, func() (bool, error) {
|
||||
nodes, err = c.Nodes().List(api.ListOptions{FieldSelector: fields.Set{
|
||||
"spec.unschedulable": "false",
|
||||
}.AsSelector()})
|
||||
return nodes, err
|
||||
}) != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
// WaitForNodeToBeReady returns whether node name is ready within timeout.
|
||||
func WaitForNodeToBeReady(c *client.Client, name string, timeout time.Duration) bool {
|
||||
return WaitForNodeToBe(c, name, api.NodeReady, true, timeout)
|
||||
}
|
||||
|
||||
// WaitForNodeToBeNotReady returns whether node name is not ready (i.e. the
|
||||
// readiness condition is anything but ready, e.g false or unknown) within
|
||||
// timeout.
|
||||
func WaitForNodeToBeNotReady(c *client.Client, name string, timeout time.Duration) bool {
|
||||
return WaitForNodeToBe(c, name, api.NodeReady, false, timeout)
|
||||
}
|
||||
|
||||
// WaitForNodeToBe returns whether node "name's" condition state matches wantTrue
|
||||
// within timeout. If wantTrue is true, it will ensure the node condition status
|
||||
// is ConditionTrue; if it's false, it ensures the node condition is in any state
|
||||
// other than ConditionTrue (e.g. not true or unknown).
|
||||
func WaitForNodeToBe(c *client.Client, name string, conditionType api.NodeConditionType, wantTrue bool, timeout time.Duration) bool {
|
||||
glog.V(4).Infof("Waiting up to %v for node %s condition %s to be %t", timeout, name, conditionType, wantTrue)
|
||||
for start := time.Now(); time.Since(start) < timeout; time.Sleep(Poll) {
|
||||
node, err := c.Nodes().Get(name)
|
||||
if err != nil {
|
||||
glog.V(4).Infof("Couldn't get node %s", name)
|
||||
continue
|
||||
}
|
||||
|
||||
if IsNodeConditionSetAsExpected(node, conditionType, wantTrue) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
glog.V(4).Infof("Node %s didn't reach desired %s condition status (%t) within %v", name, conditionType, wantTrue, timeout)
|
||||
return false
|
||||
}
|
||||
|
||||
func IsNodeConditionSetAsExpected(node *api.Node, conditionType api.NodeConditionType, wantTrue bool) bool {
|
||||
return isNodeConditionSetAsExpected(node, conditionType, wantTrue, false)
|
||||
}
|
||||
|
||||
func isNodeConditionSetAsExpected(node *api.Node, conditionType api.NodeConditionType, wantTrue, silent bool) bool {
|
||||
// Check the node readiness condition (logging all).
|
||||
for _, cond := range node.Status.Conditions {
|
||||
// Ensure that the condition type and the status matches as desired.
|
||||
if cond.Type == conditionType {
|
||||
if (cond.Status == api.ConditionTrue) == wantTrue {
|
||||
return true
|
||||
} else {
|
||||
if !silent {
|
||||
glog.V(4).Infof(
|
||||
"Condition %s of node %s is %v instead of %t. Reason: %v, message: %v",
|
||||
conditionType, node.Name, cond.Status == api.ConditionTrue, wantTrue, cond.Reason, cond.Message)
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
if !silent {
|
||||
glog.V(4).Infof("Couldn't find condition %v on node %v", conditionType, node.Name)
|
||||
}
|
||||
return false
|
||||
}
|
||||
Loading…
Reference in New Issue