package node
import (
"errors"
"fmt"
"io"
"github.com/spf13/cobra"
kcmdutil "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd/util"
"github.com/openshift/origin/pkg/cmd/util/clientcmd"
)
const (
ManageNodeCommandName = "manage-node"
manageNodeLong = `Manage node operations
schedulable: Marking node schedulable will allow pods to be schedulable on the node and
marking node unschedulable will block pods to be scheduled on the node.
evacuate: Migrate all/selected pods. There is an option to delete the bare pods.
It can list all pods that will be migrated before performing evacuation.
list-pods: List all/selected pods on given/selected nodes. It can list the output in json/yaml format.`
manageNodeExample = ` // Block accepting any pods on given nodes
$ %[1]s <mynode> --schedulable=false
// Mark selected nodes as schedulable
$ %[1]s --selector="<env=dev>" --schedulable=true
// Migrate selected pods
$ %[1]s <mynode> --evacuate --pod-selector="<service=myapp>"
// Show pods that will be migrated
$ %[1]s <mynode> --evacuate --dry-run --pod-selector="<service=myapp>"
// List all pods on given nodes
$ %[1]s <mynode1> <mynode2> --list-pods`
)
var schedulable, evacuate, listpods bool
func NewCommandManageNode(f *clientcmd.Factory, commandName, fullName string, out io.Writer) *cobra.Command {
opts := &NodeOptions{}
schedulableOp := &SchedulableOptions{Options: opts}
evacuateOp := &EvacuateOptions{Options: opts}
listpodsOp := &ListPodsOptions{Options: opts}
cmd := &cobra.Command{
Use: commandName,
Short: "Manage nodes - list pods, evacuate, or mark ready",
Long: manageNodeLong,
Example: fmt.Sprintf(manageNodeExample, fullName),
Run: func(c *cobra.Command, args []string) {
if err := ValidOperation(c); err != nil {
kcmdutil.CheckErr(kcmdutil.UsageError(c, err.Error()))
}
if err := opts.Complete(f, c, args, out); err != nil {
kcmdutil.CheckErr(err)
}
checkNodeSelector := c.Flag("selector").Changed
if err := opts.Validate(checkNodeSelector); err != nil {
kcmdutil.CheckErr(kcmdutil.UsageError(c, err.Error()))
}
// Cross op validations
if evacuateOp.DryRun && !evacuate {
err := errors.New("--dry-run is only applicable for --evacuate")
kcmdutil.CheckErr(kcmdutil.UsageError(c, err.Error()))
}
var err error
if c.Flag("schedulable").Changed {
schedulableOp.Schedulable = schedulable
err = schedulableOp.Run()
} else if evacuate {
err = evacuateOp.Run()
} else if listpods {
err = listpodsOp.Run()
}
kcmdutil.CheckErr(err)
},
}
flags := cmd.Flags()
// Supported operations
flags.BoolVar(&schedulable, "schedulable", false, "Control pod schedulability on the node.")
flags.BoolVar(&evacuate, "evacuate", false, "Migrate all/selected pods on the node.")
flags.BoolVar(&listpods, "list-pods", false, "List all/selected pods on the node. Printer flags --output, etc. are only valid for this option.")
// Common optional params
flags.StringVar(&opts.PodSelector, "pod-selector", "", "Label selector to filter pods on the node. Optional param for --evacuate or --list-pods")
flags.StringVar(&opts.Selector, "selector", "", "Label selector to filter nodes. Either pass one/more nodes as arguments or use this node selector")
// Operation specific params
evacuateOp.AddFlags(cmd)
listpodsOp.AddFlags(cmd)
return cmd
}
func ValidOperation(c *cobra.Command) error {
numOps := 0
if c.Flag("schedulable").Changed {
numOps++
}
if evacuate {
numOps++
}
if listpods {
numOps++
}
if numOps == 0 {
return errors.New("must provide a node operation. Supported operations: --schedulable, --evacuate and --list-pods")
} else if numOps != 1 {
return errors.New("must provide only one node operation at a time")
}
return nil
}