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 bug

Signed-off-by: Jorge Alarcon Ochoa <[email protected]>
  • Loading branch information
alejandrox1 committed Nov 28, 2018
1 parent a90494d commit 9d9e612
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 8 deletions.
4 changes: 3 additions & 1 deletion cmd/kind/create/cluster/createcluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type flagpole struct {
Config string
ImageName string
Retain bool
Wait bool
}

// NewCommand returns a new cobra.Command for cluster creation
Expand All @@ -50,6 +51,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().BoolVar(&flags.Wait, "wait", false, "Wait for master node to be ready")
return cmd
}

Expand Down Expand Up @@ -81,7 +83,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
27 changes: 20 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.
waitForControlPlane bool // Wait for master 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, wait bool) 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,
waitForControlPlane: wait,
}

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

// Wait for control plane node to reach Ready status.
if cc.waitForControlPlane {
if !node.WaitForControlPlane(time.Now().Add(time.Second * 30)) {
// TODO: logging here
if !cc.retain {
nodes.Delete(*node)
}
return "", fmt.Errorf("timed out waiting for control plane to be ready")
}
}

return kubeadmConfig, nil
}

Expand Down
31 changes: 31 additions & 0 deletions pkg/cluster/nodes/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"os"
"path/filepath"
"regexp"
"strings"
"time"

"github.com/pkg/errors"
Expand Down Expand Up @@ -224,3 +225,33 @@ func (n *Node) WriteKubeConfig(dest string) error {

return ioutil.WriteFile(dest, buff.Bytes(), 0600)
}

// WaitForControlPlane uses kubectl inside the "node" container to check if
// the control plane node status is "Ready". The control plane node is found by
// looking for the node containing the substring "control-plane" in its name.
func (n *Node) WaitForControlPlane(until time.Time) bool {
return tryUntil(until, func() bool {
cmd := n.Command("kubectl", "--kubeconfig=/etc/kubernetes/admin.conf", "get", "nodes")
lines, err := exec.CombinedOutputLines(cmd)
if err != nil {
return false
}
if len(lines) <= 1 {
return false
}

for _, line := range lines {
// We assume the control plane node contains the "control-plane"
// substring.
if strings.Contains(line, "control-plane") {
// Each line will have the following fields:
// NAME STATUS ROLES AGE VERSION
fields := strings.Fields(line)
if fields[1] == "Ready" {
return true
}
}
}
return false
})
}

0 comments on commit 9d9e612

Please sign in to comment.