Skip to content

Commit

Permalink
Add flag to Wait for node to reach ready state
Browse files Browse the repository at this point in the history
Add --wait flag which will make kind block until the master node of the
cluster reaches a ready state.

Resolves #42

/kind feature

Signed-off-by: Jorge Alarcon Ochoa <[email protected]>
  • Loading branch information
alejandrox1 committed Dec 5, 2018
1 parent 77d7fde commit e73d96f
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 8 deletions.
5 changes: 4 additions & 1 deletion cmd/kind/create/cluster/createcluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package cluster

import (
"fmt"
"time"

log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
Expand All @@ -33,6 +34,7 @@ type flagpole struct {
Config string
ImageName string
Retain bool
Wait time.Duration
}

// NewCommand returns a new cobra.Command for cluster creation
Expand All @@ -50,6 +52,7 @@ func NewCommand() *cobra.Command {
cmd.Flags().StringVar(&flags.Config, "config", "", "path to a kind config file")
cmd.Flags().StringVar(&flags.ImageName, "image", "", "node docker image to use for booting the cluster")
cmd.Flags().BoolVar(&flags.Retain, "retain", false, "retain nodes for debugging when cluster creation fails")
cmd.Flags().DurationVar(&flags.Wait, "wait", time.Duration(0), "Wait for control plane node to be ready (default 0s)")
return cmd
}

Expand Down Expand Up @@ -81,7 +84,7 @@ func runE(flags *flagpole, cmd *cobra.Command, args []string) error {
return fmt.Errorf("aborting due to invalid configuration")
}
}
if err = ctx.Create(cfg, flags.Retain); err != nil {
if err = ctx.Create(cfg, flags.Retain, flags.Wait); err != nil {
return fmt.Errorf("failed to create cluster: %v", err)
}

Expand Down
5 changes: 5 additions & 0 deletions docs/user/user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ For a sample kind configuration file see
To use a kind configuration file use the `--config` flag and pass the path to
the file.

If you want the `create cluster` command to block until the control plane
reaches a ready status, you can use the `--wait` flag and specify a timeout.
To use `--wait` you must specify the units of the time to wait. For example, to
wait for 30 seconds, do `--wait 30s`, for 5 minutes do `--wait 5m`, etc.


## Building Images

Expand Down
24 changes: 17 additions & 7 deletions pkg/cluster/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ type Context struct {
// createContext is a superset of Context used by helpers for Context.Create()
type createContext struct {
*Context
status *logutil.Status
config *config.Config
retain bool // if we should retain nodes after failing to create
status *logutil.Status
config *config.Config
retain bool // if we should retain nodes after failing to create.
waitForReady time.Duration // Wait for the control plane node to be ready.
}

// similar to valid docker container names, but since we will prefix
Expand Down Expand Up @@ -121,16 +122,17 @@ func (c *Context) KubeConfigPath() string {
}

// Create provisions and starts a kubernetes-in-docker cluster
func (c *Context) Create(cfg *config.Config, retain bool) error {
func (c *Context) Create(cfg *config.Config, retain bool, wait time.Duration) error {
// validate config first
if err := cfg.Validate(); err != nil {
return err
}

cc := &createContext{
Context: c,
config: cfg,
retain: retain,
Context: c,
config: cfg,
retain: retain,
waitForReady: wait,
}

fmt.Printf("Creating cluster '%s' ...\n", c.ClusterName())
Expand Down Expand Up @@ -349,6 +351,14 @@ func (cc *createContext) provisionControlPlane(
}
}

// Wait for the control plane node to reach Ready status.
isReady := nodes.WaitForReady(node, time.Now().Add(cc.waitForReady))
if cc.waitForReady > 0 {
if !isReady {
log.Warn("timed out waiting for control plane to be ready")
}
}

return kubeadmConfig, nil
}

Expand Down
35 changes: 35 additions & 0 deletions pkg/cluster/nodes/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package nodes
import (
"fmt"
"strings"
"time"

"github.com/pkg/errors"
"sigs.k8s.io/kind/pkg/cluster/consts"
Expand Down Expand Up @@ -99,3 +100,37 @@ func list(visit func(string, *Node), filters ...string) error {
}
return nil
}

// WaitForReady uses kubectl inside the "node" container to check if the
// control plane nodes are "Ready".
func WaitForReady(node *Node, until time.Time) bool {
return tryUntil(until, func() bool {
cmd := node.Command(
"kubectl",
"--kubeconfig=/etc/kubernetes/admin.conf",
"get",
"nodes",
"--selector=node-role.kubernetes.io/master",
// When the node reaches status ready, the status field will be set
// to true.
"-o=jsonpath='{.items..status.conditions[-1:].status}'",
)
lines, err := exec.CombinedOutputLines(cmd)
if err != nil {
return false
}

// 'lines' will return the status of all nodes labeled as master. For
// example, if we have three control plane nodes, and all are ready,
// then the status will have the following format: `True True True'.
status := strings.Fields(lines[0])
for _, s := range status {
// Check node status. If node is ready then this wil be 'True',
// 'False' or 'Unkown' otherwise.
if !strings.Contains(s, "True") {
return false
}
}
return true
})
}

0 comments on commit e73d96f

Please sign in to comment.