mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-28 05:57:25 +00:00
Merge pull request #5219 from jlowdermilk/kubectl-err-handling
Make kubectl commands return errors and centralize exit handling
This commit is contained in:
commit
9baa261728
@ -34,20 +34,25 @@ func (f *Factory) NewCmdClusterInfo(out io.Writer) *cobra.Command {
|
|||||||
Short: "Display cluster info",
|
Short: "Display cluster info",
|
||||||
Long: "Display addresses of the master and services with label kubernetes.io/cluster-service=true",
|
Long: "Display addresses of the master and services with label kubernetes.io/cluster-service=true",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
RunClusterInfo(f, out, cmd)
|
err := RunClusterInfo(f, out, cmd)
|
||||||
|
util.CheckErr(err)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunClusterInfo(factory *Factory, out io.Writer, cmd *cobra.Command) {
|
func RunClusterInfo(factory *Factory, out io.Writer, cmd *cobra.Command) error {
|
||||||
client, err := factory.ClientConfig(cmd)
|
client, err := factory.ClientConfig(cmd)
|
||||||
util.CheckErr(err)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
fmt.Fprintf(out, "Kubernetes master is running at %v\n", client.Host)
|
fmt.Fprintf(out, "Kubernetes master is running at %v\n", client.Host)
|
||||||
|
|
||||||
mapper, typer := factory.Object(cmd)
|
mapper, typer := factory.Object(cmd)
|
||||||
cmdNamespace, err := factory.DefaultNamespace(cmd)
|
cmdNamespace, err := factory.DefaultNamespace(cmd)
|
||||||
util.CheckErr(err)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: use generalized labels once they are implemented (#341)
|
// TODO: use generalized labels once they are implemented (#341)
|
||||||
b := resource.NewBuilder(mapper, typer, factory.ClientMapperForCommand(cmd)).
|
b := resource.NewBuilder(mapper, typer, factory.ClientMapperForCommand(cmd)).
|
||||||
@ -68,6 +73,7 @@ func RunClusterInfo(factory *Factory, out io.Writer, cmd *cobra.Command) {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
return nil
|
||||||
|
|
||||||
// TODO: consider printing more information about cluster
|
// TODO: consider printing more information about cluster
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,6 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
@ -253,7 +252,9 @@ func (f *Factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMappin
|
|||||||
}
|
}
|
||||||
if ok {
|
if ok {
|
||||||
clientConfig, err := f.ClientConfig(cmd)
|
clientConfig, err := f.ClientConfig(cmd)
|
||||||
cmdutil.CheckErr(err)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
defaultVersion := clientConfig.Version
|
defaultVersion := clientConfig.Version
|
||||||
|
|
||||||
version := cmdutil.OutputVersion(cmd, defaultVersion)
|
version := cmdutil.OutputVersion(cmd, defaultVersion)
|
||||||
@ -329,12 +330,6 @@ func DefaultClientConfig(flags *pflag.FlagSet) clientcmd.ClientConfig {
|
|||||||
return clientConfig
|
return clientConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func usageError(cmd *cobra.Command, format string, args ...interface{}) {
|
|
||||||
glog.Errorf(format, args...)
|
|
||||||
glog.Errorf("See '%s -h' for help.", cmd.CommandPath())
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func runHelp(cmd *cobra.Command, args []string) {
|
func runHelp(cmd *cobra.Command, args []string) {
|
||||||
cmd.Help()
|
cmd.Help()
|
||||||
}
|
}
|
||||||
|
@ -39,54 +39,67 @@ $ cat pod.json | kubectl create -f -`
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (f *Factory) NewCmdCreate(out io.Writer) *cobra.Command {
|
func (f *Factory) NewCmdCreate(out io.Writer) *cobra.Command {
|
||||||
flags := &struct {
|
var filenames util.StringList
|
||||||
Filenames util.StringList
|
|
||||||
}{}
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "create -f filename",
|
Use: "create -f filename",
|
||||||
Short: "Create a resource by filename or stdin",
|
Short: "Create a resource by filename or stdin",
|
||||||
Long: create_long,
|
Long: create_long,
|
||||||
Example: create_example,
|
Example: create_example,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
schema, err := f.Validator(cmd)
|
err := RunCreate(f, out, cmd, filenames)
|
||||||
cmdutil.CheckErr(err)
|
cmdutil.CheckErr(err)
|
||||||
|
|
||||||
cmdNamespace, err := f.DefaultNamespace(cmd)
|
|
||||||
cmdutil.CheckErr(err)
|
|
||||||
|
|
||||||
mapper, typer := f.Object(cmd)
|
|
||||||
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand(cmd)).
|
|
||||||
ContinueOnError().
|
|
||||||
NamespaceParam(cmdNamespace).RequireNamespace().
|
|
||||||
FilenameParam(flags.Filenames...).
|
|
||||||
Flatten().
|
|
||||||
Do()
|
|
||||||
cmdutil.CheckErr(r.Err())
|
|
||||||
|
|
||||||
count := 0
|
|
||||||
err = r.Visit(func(info *resource.Info) error {
|
|
||||||
data, err := info.Mapping.Codec.Encode(info.Object)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := schema.ValidateBytes(data); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, data)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
count++
|
|
||||||
info.Refresh(obj, true)
|
|
||||||
fmt.Fprintf(out, "%s\n", info.Name)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
cmdutil.CheckErr(err)
|
|
||||||
if count == 0 {
|
|
||||||
cmdutil.CheckErr(fmt.Errorf("no objects passed to create"))
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cmd.Flags().VarP(&flags.Filenames, "filename", "f", "Filename, directory, or URL to file to use to create the resource")
|
cmd.Flags().VarP(&filenames, "filename", "f", "Filename, directory, or URL to file to use to create the resource")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RunCreate(f *Factory, out io.Writer, cmd *cobra.Command, filenames util.StringList) error {
|
||||||
|
schema, err := f.Validator(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdNamespace, err := f.DefaultNamespace(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper, typer := f.Object(cmd)
|
||||||
|
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand(cmd)).
|
||||||
|
ContinueOnError().
|
||||||
|
NamespaceParam(cmdNamespace).RequireNamespace().
|
||||||
|
FilenameParam(filenames...).
|
||||||
|
Flatten().
|
||||||
|
Do()
|
||||||
|
err = r.Err()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
err = r.Visit(func(info *resource.Info) error {
|
||||||
|
data, err := info.Mapping.Codec.Encode(info.Object)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := schema.ValidateBytes(data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
count++
|
||||||
|
info.Refresh(obj, true)
|
||||||
|
fmt.Fprintf(out, "%s\n", info.Name)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if count == 0 {
|
||||||
|
return fmt.Errorf("no objects passed to create")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -56,46 +56,57 @@ $ kubectl delete pods --all`
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (f *Factory) NewCmdDelete(out io.Writer) *cobra.Command {
|
func (f *Factory) NewCmdDelete(out io.Writer) *cobra.Command {
|
||||||
flags := &struct {
|
var filenames util.StringList
|
||||||
Filenames util.StringList
|
|
||||||
}{}
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "delete (-f filename | <resource> (<id> | -l <label> | --all))",
|
Use: "delete (-f filename | <resource> (<id> | -l <label> | --all))",
|
||||||
Short: "Delete a resource by filename, stdin, or resource and ID.",
|
Short: "Delete a resource by filename, stdin, or resource and ID.",
|
||||||
Long: delete_long,
|
Long: delete_long,
|
||||||
Example: delete_example,
|
Example: delete_example,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmdNamespace, err := f.DefaultNamespace(cmd)
|
err := RunDelete(f, out, cmd, args, filenames)
|
||||||
cmdutil.CheckErr(err)
|
cmdutil.CheckErr(err)
|
||||||
mapper, typer := f.Object(cmd)
|
|
||||||
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand(cmd)).
|
|
||||||
ContinueOnError().
|
|
||||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
|
||||||
FilenameParam(flags.Filenames...).
|
|
||||||
SelectorParam(cmdutil.GetFlagString(cmd, "selector")).
|
|
||||||
SelectAllParam(cmdutil.GetFlagBool(cmd, "all")).
|
|
||||||
ResourceTypeOrNameArgs(false, args...).
|
|
||||||
Flatten().
|
|
||||||
Do()
|
|
||||||
cmdutil.CheckErr(r.Err())
|
|
||||||
|
|
||||||
found := 0
|
|
||||||
err = r.IgnoreErrors(errors.IsNotFound).Visit(func(r *resource.Info) error {
|
|
||||||
found++
|
|
||||||
if err := resource.NewHelper(r.Client, r.Mapping).Delete(r.Namespace, r.Name); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Fprintf(out, "%s\n", r.Name)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
cmdutil.CheckErr(err)
|
|
||||||
if found == 0 {
|
|
||||||
fmt.Fprintf(cmd.Out(), "No resources found\n")
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cmd.Flags().VarP(&flags.Filenames, "filename", "f", "Filename, directory, or URL to a file containing the resource to delete")
|
cmd.Flags().VarP(&filenames, "filename", "f", "Filename, directory, or URL to a file containing the resource to delete")
|
||||||
cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on")
|
cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on")
|
||||||
cmd.Flags().Bool("all", false, "[-all] to select all the specified resources")
|
cmd.Flags().Bool("all", false, "[-all] to select all the specified resources")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RunDelete(f *Factory, out io.Writer, cmd *cobra.Command, args []string, filenames util.StringList) error {
|
||||||
|
cmdNamespace, err := f.DefaultNamespace(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
mapper, typer := f.Object(cmd)
|
||||||
|
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand(cmd)).
|
||||||
|
ContinueOnError().
|
||||||
|
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||||
|
FilenameParam(filenames...).
|
||||||
|
SelectorParam(cmdutil.GetFlagString(cmd, "selector")).
|
||||||
|
SelectAllParam(cmdutil.GetFlagBool(cmd, "all")).
|
||||||
|
ResourceTypeOrNameArgs(false, args...).
|
||||||
|
Flatten().
|
||||||
|
Do()
|
||||||
|
err = r.Err()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
found := 0
|
||||||
|
err = r.IgnoreErrors(errors.IsNotFound).Visit(func(r *resource.Info) error {
|
||||||
|
found++
|
||||||
|
if err := resource.NewHelper(r.Client, r.Mapping).Delete(r.Namespace, r.Name); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Fprintf(out, "%s\n", r.Name)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if found == 0 {
|
||||||
|
fmt.Fprintf(cmd.Out(), "No resources found\n")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -33,20 +33,35 @@ func (f *Factory) NewCmdDescribe(out io.Writer) *cobra.Command {
|
|||||||
This command joins many API calls together to form a detailed description of a
|
This command joins many API calls together to form a detailed description of a
|
||||||
given resource.`,
|
given resource.`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmdNamespace, err := f.DefaultNamespace(cmd)
|
err := RunDescribe(f, out, cmd, args)
|
||||||
util.CheckErr(err)
|
util.CheckErr(err)
|
||||||
|
|
||||||
mapper, _ := f.Object(cmd)
|
|
||||||
// TODO: use resource.Builder instead
|
|
||||||
mapping, namespace, name := util.ResourceFromArgs(cmd, args, mapper, cmdNamespace)
|
|
||||||
|
|
||||||
describer, err := f.Describer(cmd, mapping)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
s, err := describer.Describe(namespace, name)
|
|
||||||
util.CheckErr(err)
|
|
||||||
fmt.Fprintf(out, "%s\n", s)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RunDescribe(f *Factory, out io.Writer, cmd *cobra.Command, args []string) error {
|
||||||
|
cmdNamespace, err := f.DefaultNamespace(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper, _ := f.Object(cmd)
|
||||||
|
// TODO: use resource.Builder instead
|
||||||
|
mapping, namespace, name, err := util.ResourceFromArgs(cmd, args, mapper, cmdNamespace)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
describer, err := f.Describer(cmd, mapping)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := describer.Describe(namespace, name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Fprintf(out, "%s\n", s)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -39,97 +39,105 @@ $ kubectl exec -p 123456-7890 -c ruby-container -i -t -- bash -il`
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (f *Factory) NewCmdExec(cmdIn io.Reader, cmdOut, cmdErr io.Writer) *cobra.Command {
|
func (f *Factory) NewCmdExec(cmdIn io.Reader, cmdOut, cmdErr io.Writer) *cobra.Command {
|
||||||
flags := &struct {
|
|
||||||
pod string
|
|
||||||
container string
|
|
||||||
stdin bool
|
|
||||||
tty bool
|
|
||||||
}{}
|
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "exec -p <pod> -c <container> -- <command> [<args...>]",
|
Use: "exec -p <pod> -c <container> -- <command> [<args...>]",
|
||||||
Short: "Execute a command in a container.",
|
Short: "Execute a command in a container.",
|
||||||
Long: "Execute a command in a container.",
|
Long: "Execute a command in a container.",
|
||||||
Example: exec_example,
|
Example: exec_example,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
if len(flags.pod) == 0 {
|
err := RunExec(f, cmdIn, cmdOut, cmdErr, cmd, args)
|
||||||
usageError(cmd, "<pod> is required for exec")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(args) < 1 {
|
|
||||||
usageError(cmd, "<command> is required for exec")
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace, err := f.DefaultNamespace(cmd)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
client, err := f.Client(cmd)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
pod, err := client.Pods(namespace).Get(flags.pod)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
if pod.Status.Phase != api.PodRunning {
|
|
||||||
glog.Fatalf("Unable to execute command because pod is not running. Current status=%v", pod.Status.Phase)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(flags.container) == 0 {
|
|
||||||
flags.container = pod.Spec.Containers[0].Name
|
|
||||||
}
|
|
||||||
|
|
||||||
var stdin io.Reader
|
|
||||||
if util.GetFlagBool(cmd, "stdin") {
|
|
||||||
stdin = cmdIn
|
|
||||||
if flags.tty {
|
|
||||||
if file, ok := cmdIn.(*os.File); ok {
|
|
||||||
inFd := file.Fd()
|
|
||||||
if term.IsTerminal(inFd) {
|
|
||||||
oldState, err := term.SetRawTerminal(inFd)
|
|
||||||
if err != nil {
|
|
||||||
glog.Fatal(err)
|
|
||||||
}
|
|
||||||
// this handles a clean exit, where the command finished
|
|
||||||
defer term.RestoreTerminal(inFd, oldState)
|
|
||||||
|
|
||||||
// SIGINT is handled by term.SetRawTerminal (it runs a goroutine that listens
|
|
||||||
// for SIGINT and restores the terminal before exiting)
|
|
||||||
|
|
||||||
// this handles SIGTERM
|
|
||||||
sigChan := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(sigChan, syscall.SIGTERM)
|
|
||||||
go func() {
|
|
||||||
<-sigChan
|
|
||||||
term.RestoreTerminal(inFd, oldState)
|
|
||||||
os.Exit(0)
|
|
||||||
}()
|
|
||||||
} else {
|
|
||||||
glog.Warning("Stdin is not a terminal")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
flags.tty = false
|
|
||||||
glog.Warning("Unable to use a TTY")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
config, err := f.ClientConfig(cmd)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
req := client.RESTClient.Get().
|
|
||||||
Prefix("proxy").
|
|
||||||
Resource("minions").
|
|
||||||
Name(pod.Status.Host).
|
|
||||||
Suffix("exec", namespace, flags.pod, flags.container)
|
|
||||||
|
|
||||||
e := remotecommand.New(req, config, args, stdin, cmdOut, cmdErr, flags.tty)
|
|
||||||
err = e.Execute()
|
|
||||||
util.CheckErr(err)
|
util.CheckErr(err)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cmd.Flags().StringVarP(&flags.pod, "pod", "p", "", "Pod name")
|
cmd.Flags().StringP("pod", "p", "", "Pod name")
|
||||||
// TODO support UID
|
// TODO support UID
|
||||||
cmd.Flags().StringVarP(&flags.container, "container", "c", "", "Container name")
|
cmd.Flags().StringP("container", "c", "", "Container name")
|
||||||
cmd.Flags().BoolVarP(&flags.stdin, "stdin", "i", false, "Pass stdin to the container")
|
cmd.Flags().BoolP("stdin", "i", false, "Pass stdin to the container")
|
||||||
cmd.Flags().BoolVarP(&flags.tty, "tty", "t", false, "Stdin is a TTY")
|
cmd.Flags().BoolP("tty", "t", false, "Stdin is a TTY")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RunExec(f *Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cobra.Command, args []string) error {
|
||||||
|
podName := util.GetFlagString(cmd, "pod")
|
||||||
|
if len(podName) == 0 {
|
||||||
|
return util.UsageError(cmd, "<pod> is required for exec")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(args) < 1 {
|
||||||
|
return util.UsageError(cmd, "<command> is required for exec")
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace, err := f.DefaultNamespace(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := f.Client(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pod, err := client.Pods(namespace).Get(podName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if pod.Status.Phase != api.PodRunning {
|
||||||
|
glog.Fatalf("Unable to execute command because pod is not running. Current status=%v", pod.Status.Phase)
|
||||||
|
}
|
||||||
|
|
||||||
|
containerName := util.GetFlagString(cmd, "container")
|
||||||
|
if len(containerName) == 0 {
|
||||||
|
containerName = pod.Spec.Containers[0].Name
|
||||||
|
}
|
||||||
|
|
||||||
|
var stdin io.Reader
|
||||||
|
tty := util.GetFlagBool(cmd, "tty")
|
||||||
|
if util.GetFlagBool(cmd, "stdin") {
|
||||||
|
stdin = cmdIn
|
||||||
|
if tty {
|
||||||
|
if file, ok := cmdIn.(*os.File); ok {
|
||||||
|
inFd := file.Fd()
|
||||||
|
if term.IsTerminal(inFd) {
|
||||||
|
oldState, err := term.SetRawTerminal(inFd)
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatal(err)
|
||||||
|
}
|
||||||
|
// this handles a clean exit, where the command finished
|
||||||
|
defer term.RestoreTerminal(inFd, oldState)
|
||||||
|
|
||||||
|
// SIGINT is handled by term.SetRawTerminal (it runs a goroutine that listens
|
||||||
|
// for SIGINT and restores the terminal before exiting)
|
||||||
|
|
||||||
|
// this handles SIGTERM
|
||||||
|
sigChan := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigChan, syscall.SIGTERM)
|
||||||
|
go func() {
|
||||||
|
<-sigChan
|
||||||
|
term.RestoreTerminal(inFd, oldState)
|
||||||
|
os.Exit(0)
|
||||||
|
}()
|
||||||
|
} else {
|
||||||
|
glog.Warning("Stdin is not a terminal")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tty = false
|
||||||
|
glog.Warning("Unable to use a TTY")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config, err := f.ClientConfig(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
req := client.RESTClient.Get().
|
||||||
|
Prefix("proxy").
|
||||||
|
Resource("minions").
|
||||||
|
Name(pod.Status.Host).
|
||||||
|
Suffix("exec", namespace, podName, containerName)
|
||||||
|
|
||||||
|
e := remotecommand.New(req, config, args, stdin, cmdOut, cmdErr, tty)
|
||||||
|
return e.Execute()
|
||||||
|
}
|
||||||
|
@ -46,59 +46,7 @@ func (f *Factory) NewCmdExposeService(out io.Writer) *cobra.Command {
|
|||||||
Long: expose_long,
|
Long: expose_long,
|
||||||
Example: expose_example,
|
Example: expose_example,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
if len(args) != 1 {
|
err := RunExpose(f, out, cmd, args)
|
||||||
usageError(cmd, "<name> is required for expose")
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace, err := f.DefaultNamespace(cmd)
|
|
||||||
util.CheckErr(err)
|
|
||||||
client, err := f.Client(cmd)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
generatorName := util.GetFlagString(cmd, "generator")
|
|
||||||
|
|
||||||
generator, found := kubectl.Generators[generatorName]
|
|
||||||
if !found {
|
|
||||||
usageError(cmd, fmt.Sprintf("Generator: %s not found.", generator))
|
|
||||||
}
|
|
||||||
if util.GetFlagInt(cmd, "port") < 1 {
|
|
||||||
usageError(cmd, "--port is required and must be a positive integer.")
|
|
||||||
}
|
|
||||||
names := generator.ParamNames()
|
|
||||||
params := kubectl.MakeParams(cmd, names)
|
|
||||||
if len(util.GetFlagString(cmd, "service-name")) == 0 {
|
|
||||||
params["name"] = args[0]
|
|
||||||
} else {
|
|
||||||
params["name"] = util.GetFlagString(cmd, "service-name")
|
|
||||||
}
|
|
||||||
if _, found := params["selector"]; !found {
|
|
||||||
rc, err := client.ReplicationControllers(namespace).Get(args[0])
|
|
||||||
util.CheckErr(err)
|
|
||||||
params["selector"] = kubectl.MakeLabels(rc.Spec.Selector)
|
|
||||||
}
|
|
||||||
if util.GetFlagBool(cmd, "create-external-load-balancer") {
|
|
||||||
params["create-external-load-balancer"] = "true"
|
|
||||||
}
|
|
||||||
|
|
||||||
err = kubectl.ValidateParams(names, params)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
service, err := generator.Generate(params)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
inline := util.GetFlagString(cmd, "overrides")
|
|
||||||
if len(inline) > 0 {
|
|
||||||
service, err = util.Merge(service, inline, "Service")
|
|
||||||
util.CheckErr(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: extract this flag to a central location, when such a location exists.
|
|
||||||
if !util.GetFlagBool(cmd, "dry-run") {
|
|
||||||
service, err = client.Services(namespace).Create(service.(*api.Service))
|
|
||||||
util.CheckErr(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = f.PrintObject(cmd, service, out)
|
|
||||||
util.CheckErr(err)
|
util.CheckErr(err)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -115,3 +63,73 @@ func (f *Factory) NewCmdExposeService(out io.Writer) *cobra.Command {
|
|||||||
cmd.Flags().String("service-name", "", "The name for the newly created service.")
|
cmd.Flags().String("service-name", "", "The name for the newly created service.")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RunExpose(f *Factory, out io.Writer, cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return util.UsageError(cmd, "<name> is required for expose")
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace, err := f.DefaultNamespace(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
client, err := f.Client(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
generatorName := util.GetFlagString(cmd, "generator")
|
||||||
|
|
||||||
|
generator, found := kubectl.Generators[generatorName]
|
||||||
|
if !found {
|
||||||
|
return util.UsageError(cmd, fmt.Sprintf("Generator: %s not found.", generator))
|
||||||
|
}
|
||||||
|
if util.GetFlagInt(cmd, "port") < 1 {
|
||||||
|
return util.UsageError(cmd, "--port is required and must be a positive integer.")
|
||||||
|
}
|
||||||
|
names := generator.ParamNames()
|
||||||
|
params := kubectl.MakeParams(cmd, names)
|
||||||
|
if len(util.GetFlagString(cmd, "service-name")) == 0 {
|
||||||
|
params["name"] = args[0]
|
||||||
|
} else {
|
||||||
|
params["name"] = util.GetFlagString(cmd, "service-name")
|
||||||
|
}
|
||||||
|
if _, found := params["selector"]; !found {
|
||||||
|
rc, err := client.ReplicationControllers(namespace).Get(args[0])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
params["selector"] = kubectl.MakeLabels(rc.Spec.Selector)
|
||||||
|
}
|
||||||
|
if util.GetFlagBool(cmd, "create-external-load-balancer") {
|
||||||
|
params["create-external-load-balancer"] = "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
err = kubectl.ValidateParams(names, params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
service, err := generator.Generate(params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
inline := util.GetFlagString(cmd, "overrides")
|
||||||
|
if len(inline) > 0 {
|
||||||
|
service, err = util.Merge(service, inline, "Service")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: extract this flag to a central location, when such a location exists.
|
||||||
|
if !util.GetFlagBool(cmd, "dry-run") {
|
||||||
|
service, err = client.Services(namespace).Create(service.(*api.Service))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return f.PrintObject(cmd, service, out)
|
||||||
|
}
|
||||||
|
@ -63,7 +63,8 @@ func (f *Factory) NewCmdGet(out io.Writer) *cobra.Command {
|
|||||||
Long: get_long,
|
Long: get_long,
|
||||||
Example: get_example,
|
Example: get_example,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
RunGet(f, out, cmd, args)
|
err := RunGet(f, out, cmd, args)
|
||||||
|
util.CheckErr(err)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
util.AddPrinterFlags(cmd)
|
util.AddPrinterFlags(cmd)
|
||||||
@ -75,13 +76,14 @@ func (f *Factory) NewCmdGet(out io.Writer) *cobra.Command {
|
|||||||
|
|
||||||
// RunGet implements the generic Get command
|
// RunGet implements the generic Get command
|
||||||
// TODO: convert all direct flag accessors to a struct and pass that instead of cmd
|
// TODO: convert all direct flag accessors to a struct and pass that instead of cmd
|
||||||
// TODO: return an error instead of using glog.Fatal and checkErr
|
func RunGet(f *Factory, out io.Writer, cmd *cobra.Command, args []string) error {
|
||||||
func RunGet(f *Factory, out io.Writer, cmd *cobra.Command, args []string) {
|
|
||||||
selector := util.GetFlagString(cmd, "selector")
|
selector := util.GetFlagString(cmd, "selector")
|
||||||
mapper, typer := f.Object(cmd)
|
mapper, typer := f.Object(cmd)
|
||||||
|
|
||||||
cmdNamespace, err := f.DefaultNamespace(cmd)
|
cmdNamespace, err := f.DefaultNamespace(cmd)
|
||||||
util.CheckErr(err)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// handle watch separately since we cannot watch multiple resource types
|
// handle watch separately since we cannot watch multiple resource types
|
||||||
isWatch, isWatchOnly := util.GetFlagBool(cmd, "watch"), util.GetFlagBool(cmd, "watch-only")
|
isWatch, isWatchOnly := util.GetFlagBool(cmd, "watch"), util.GetFlagBool(cmd, "watch-only")
|
||||||
@ -92,35 +94,47 @@ func RunGet(f *Factory, out io.Writer, cmd *cobra.Command, args []string) {
|
|||||||
ResourceTypeOrNameArgs(true, args...).
|
ResourceTypeOrNameArgs(true, args...).
|
||||||
SingleResourceType().
|
SingleResourceType().
|
||||||
Do()
|
Do()
|
||||||
util.CheckErr(r.Err())
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
mapping, err := r.ResourceMapping()
|
mapping, err := r.ResourceMapping()
|
||||||
util.CheckErr(err)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
printer, err := f.PrinterForMapping(cmd, mapping)
|
printer, err := f.PrinterForMapping(cmd, mapping)
|
||||||
util.CheckErr(err)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
obj, err := r.Object()
|
obj, err := r.Object()
|
||||||
util.CheckErr(err)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
rv, err := mapping.MetadataAccessor.ResourceVersion(obj)
|
rv, err := mapping.MetadataAccessor.ResourceVersion(obj)
|
||||||
util.CheckErr(err)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// print the current object
|
// print the current object
|
||||||
if !isWatchOnly {
|
if !isWatchOnly {
|
||||||
if err := printer.PrintObj(obj, out); err != nil {
|
if err := printer.PrintObj(obj, out); err != nil {
|
||||||
util.CheckErr(fmt.Errorf("unable to output the provided object: %v", err))
|
return fmt.Errorf("unable to output the provided object: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// print watched changes
|
// print watched changes
|
||||||
w, err := r.Watch(rv)
|
w, err := r.Watch(rv)
|
||||||
util.CheckErr(err)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
kubectl.WatchLoop(w, func(e watch.Event) error {
|
kubectl.WatchLoop(w, func(e watch.Event) error {
|
||||||
return printer.PrintObj(e.Object, out)
|
return printer.PrintObj(e.Object, out)
|
||||||
})
|
})
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
b := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand(cmd)).
|
b := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand(cmd)).
|
||||||
@ -129,11 +143,15 @@ func RunGet(f *Factory, out io.Writer, cmd *cobra.Command, args []string) {
|
|||||||
ResourceTypeOrNameArgs(true, args...).
|
ResourceTypeOrNameArgs(true, args...).
|
||||||
Latest()
|
Latest()
|
||||||
printer, generic, err := util.PrinterForCommand(cmd)
|
printer, generic, err := util.PrinterForCommand(cmd)
|
||||||
util.CheckErr(err)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if generic {
|
if generic {
|
||||||
clientConfig, err := f.ClientConfig(cmd)
|
clientConfig, err := f.ClientConfig(cmd)
|
||||||
util.CheckErr(err)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defaultVersion := clientConfig.Version
|
defaultVersion := clientConfig.Version
|
||||||
|
|
||||||
// the outermost object will be converted to the output-version
|
// the outermost object will be converted to the output-version
|
||||||
@ -141,7 +159,9 @@ func RunGet(f *Factory, out io.Writer, cmd *cobra.Command, args []string) {
|
|||||||
|
|
||||||
r := b.Flatten().Do()
|
r := b.Flatten().Do()
|
||||||
obj, err := r.Object()
|
obj, err := r.Object()
|
||||||
util.CheckErr(err)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// try conversion to all the possible versions
|
// try conversion to all the possible versions
|
||||||
// TODO: simplify by adding a ResourceBuilder mode
|
// TODO: simplify by adding a ResourceBuilder mode
|
||||||
@ -157,18 +177,15 @@ func RunGet(f *Factory, out io.Writer, cmd *cobra.Command, args []string) {
|
|||||||
// builder on initialization
|
// builder on initialization
|
||||||
printer := kubectl.NewVersionedPrinter(printer, api.Scheme, versions...)
|
printer := kubectl.NewVersionedPrinter(printer, api.Scheme, versions...)
|
||||||
|
|
||||||
err = printer.PrintObj(obj, out)
|
return printer.PrintObj(obj, out)
|
||||||
util.CheckErr(err)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// use the default printer for each object
|
// use the default printer for each object
|
||||||
err = b.Do().Visit(func(r *resource.Info) error {
|
return b.Do().Visit(func(r *resource.Info) error {
|
||||||
printer, err := f.PrinterForMapping(cmd, r.Mapping)
|
printer, err := f.PrinterForMapping(cmd, r.Mapping)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return printer.PrintObj(r.Object, out)
|
return printer.PrintObj(r.Object, out)
|
||||||
})
|
})
|
||||||
util.CheckErr(err)
|
|
||||||
}
|
}
|
||||||
|
@ -55,38 +55,8 @@ func (f *Factory) NewCmdLabel(out io.Writer) *cobra.Command {
|
|||||||
Long: label_long,
|
Long: label_long,
|
||||||
Example: label_example,
|
Example: label_example,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
if len(args) < 2 {
|
err := RunLabel(f, out, cmd, args)
|
||||||
usageError(cmd, "<resource> <name> is required")
|
|
||||||
}
|
|
||||||
if len(args) < 3 {
|
|
||||||
usageError(cmd, "at least one label update is required.")
|
|
||||||
}
|
|
||||||
res := args[:2]
|
|
||||||
cmdNamespace, err := f.DefaultNamespace(cmd)
|
|
||||||
util.CheckErr(err)
|
util.CheckErr(err)
|
||||||
|
|
||||||
mapper, _ := f.Object(cmd)
|
|
||||||
// TODO: use resource.Builder instead
|
|
||||||
mapping, namespace, name := util.ResourceFromArgs(cmd, res, mapper, cmdNamespace)
|
|
||||||
client, err := f.RESTClient(cmd, mapping)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
labels, remove, err := parseLabels(args[2:])
|
|
||||||
util.CheckErr(err)
|
|
||||||
overwrite := util.GetFlagBool(cmd, "overwrite")
|
|
||||||
resourceVersion := util.GetFlagString(cmd, "resource-version")
|
|
||||||
|
|
||||||
obj, err := updateObject(client, mapping, namespace, name, func(obj runtime.Object) runtime.Object {
|
|
||||||
outObj, err := labelFunc(obj, overwrite, resourceVersion, labels, remove)
|
|
||||||
util.CheckErr(err)
|
|
||||||
return outObj
|
|
||||||
})
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
printer, err := f.PrinterForMapping(cmd, mapping)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
printer.PrintObj(obj, out)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
util.AddPrinterFlags(cmd)
|
util.AddPrinterFlags(cmd)
|
||||||
@ -95,7 +65,7 @@ func (f *Factory) NewCmdLabel(out io.Writer) *cobra.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateObject(client resource.RESTClient, mapping *meta.RESTMapping, namespace, name string, updateFn func(runtime.Object) runtime.Object) (runtime.Object, error) {
|
func updateObject(client resource.RESTClient, mapping *meta.RESTMapping, namespace, name string, updateFn func(runtime.Object) (runtime.Object, error)) (runtime.Object, error) {
|
||||||
helper := resource.NewHelper(client, mapping)
|
helper := resource.NewHelper(client, mapping)
|
||||||
|
|
||||||
obj, err := helper.Get(namespace, name)
|
obj, err := helper.Get(namespace, name)
|
||||||
@ -103,7 +73,10 @@ func updateObject(client resource.RESTClient, mapping *meta.RESTMapping, namespa
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = updateFn(obj)
|
obj, err = updateFn(obj)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
data, err := helper.Codec.Encode(obj)
|
data, err := helper.Codec.Encode(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -177,3 +150,54 @@ func labelFunc(obj runtime.Object, overwrite bool, resourceVersion string, label
|
|||||||
}
|
}
|
||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RunLabel(f *Factory, out io.Writer, cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) < 2 {
|
||||||
|
return util.UsageError(cmd, "<resource> <name> is required")
|
||||||
|
}
|
||||||
|
if len(args) < 3 {
|
||||||
|
return util.UsageError(cmd, "at least one label update is required.")
|
||||||
|
}
|
||||||
|
res := args[:2]
|
||||||
|
cmdNamespace, err := f.DefaultNamespace(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper, _ := f.Object(cmd)
|
||||||
|
// TODO: use resource.Builder instead
|
||||||
|
mapping, namespace, name, err := util.ResourceFromArgs(cmd, res, mapper, cmdNamespace)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
client, err := f.RESTClient(cmd, mapping)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
labels, remove, err := parseLabels(args[2:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
overwrite := util.GetFlagBool(cmd, "overwrite")
|
||||||
|
resourceVersion := util.GetFlagString(cmd, "resource-version")
|
||||||
|
|
||||||
|
obj, err := updateObject(client, mapping, namespace, name, func(obj runtime.Object) (runtime.Object, error) {
|
||||||
|
outObj, err := labelFunc(obj, overwrite, resourceVersion, labels, remove)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return outObj, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
printer, err := f.PrinterForMapping(cmd, mapping)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
printer.PrintObj(obj, out)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -19,7 +19,6 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
@ -65,56 +64,7 @@ func (f *Factory) NewCmdLog(out io.Writer) *cobra.Command {
|
|||||||
Long: "Print the logs for a container in a pod. If the pod has only one container, the container name is optional.",
|
Long: "Print the logs for a container in a pod. If the pod has only one container, the container name is optional.",
|
||||||
Example: log_example,
|
Example: log_example,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
if len(args) == 0 {
|
err := RunLog(f, out, cmd, args)
|
||||||
usageError(cmd, "<pod> is required for log")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(args) > 2 {
|
|
||||||
usageError(cmd, "log <pod> [<container>]")
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace, err := f.DefaultNamespace(cmd)
|
|
||||||
util.CheckErr(err)
|
|
||||||
client, err := f.Client(cmd)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
podID := args[0]
|
|
||||||
|
|
||||||
pod, err := client.Pods(namespace).Get(podID)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
var container string
|
|
||||||
if len(args) == 1 {
|
|
||||||
if len(pod.Spec.Containers) != 1 {
|
|
||||||
if !util.GetFlagBool(cmd, "interactive") {
|
|
||||||
usageError(cmd, "<container> is required for pods with multiple containers")
|
|
||||||
} else {
|
|
||||||
container = selectContainer(pod, os.Stdin, out)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Get logs for the only container in the pod
|
|
||||||
container = pod.Spec.Containers[0].Name
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
container = args[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
follow := false
|
|
||||||
if util.GetFlagBool(cmd, "follow") {
|
|
||||||
follow = true
|
|
||||||
}
|
|
||||||
|
|
||||||
readCloser, err := client.RESTClient.Get().
|
|
||||||
Prefix("proxy").
|
|
||||||
Resource("minions").
|
|
||||||
Name(pod.Status.Host).
|
|
||||||
Suffix("containerLogs", namespace, podID, container).
|
|
||||||
Param("follow", strconv.FormatBool(follow)).
|
|
||||||
Stream()
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
defer readCloser.Close()
|
|
||||||
_, err = io.Copy(out, readCloser)
|
|
||||||
util.CheckErr(err)
|
util.CheckErr(err)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -122,3 +72,55 @@ func (f *Factory) NewCmdLog(out io.Writer) *cobra.Command {
|
|||||||
cmd.Flags().Bool("interactive", true, "If true, prompt the user for input when required. Default true.")
|
cmd.Flags().Bool("interactive", true, "If true, prompt the user for input when required. Default true.")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RunLog(f *Factory, out io.Writer, cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return util.UsageError(cmd, "<pod> is required for log")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(args) > 2 {
|
||||||
|
return util.UsageError(cmd, "log <pod> [<container>]")
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace, err := f.DefaultNamespace(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
client, err := f.Client(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
podID := args[0]
|
||||||
|
|
||||||
|
pod, err := client.Pods(namespace).Get(podID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var container string
|
||||||
|
if len(args) == 1 {
|
||||||
|
} else {
|
||||||
|
container = args[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
follow := false
|
||||||
|
if util.GetFlagBool(cmd, "follow") {
|
||||||
|
follow = true
|
||||||
|
}
|
||||||
|
|
||||||
|
readCloser, err := client.RESTClient.Get().
|
||||||
|
Prefix("proxy").
|
||||||
|
Resource("minions").
|
||||||
|
Name(pod.Status.Host).
|
||||||
|
Suffix("containerLogs", namespace, podID, container).
|
||||||
|
Param("follow", strconv.FormatBool(follow)).
|
||||||
|
Stream()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer readCloser.Close()
|
||||||
|
_, err = io.Copy(out, readCloser)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
@ -17,10 +17,10 @@ limitations under the License.
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd/util"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -34,8 +34,7 @@ func NewCmdNamespace(out io.Writer) *cobra.Command {
|
|||||||
namespace has been superceded by the context.namespace field of .kubeconfig files. See 'kubectl config set-context --help' for more details.
|
namespace has been superceded by the context.namespace field of .kubeconfig files. See 'kubectl config set-context --help' for more details.
|
||||||
`,
|
`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
glog.Errorln("namespace has been superceded by the context.namespace field of .kubeconfig files. See 'kubectl config set-context --help' for more details.")
|
util.CheckErr(fmt.Errorf("namespace has been superceded by the context.namespace field of .kubeconfig files. See 'kubectl config set-context --help' for more details."))
|
||||||
os.Exit(1)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return cmd
|
return cmd
|
||||||
|
@ -42,65 +42,75 @@ $ kubectl port-forward -p mypod 0:5000
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (f *Factory) NewCmdPortForward() *cobra.Command {
|
func (f *Factory) NewCmdPortForward() *cobra.Command {
|
||||||
flags := &struct {
|
|
||||||
pod string
|
|
||||||
container string
|
|
||||||
}{}
|
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "port-forward -p <pod> [<local port>:]<remote port> [<port>...]",
|
Use: "port-forward -p <pod> [<local port>:]<remote port> [<port>...]",
|
||||||
Short: "Forward 1 or more local ports to a pod.",
|
Short: "Forward 1 or more local ports to a pod.",
|
||||||
Long: "Forward 1 or more local ports to a pod.",
|
Long: "Forward 1 or more local ports to a pod.",
|
||||||
Example: portforward_example,
|
Example: portforward_example,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
if len(flags.pod) == 0 {
|
err := RunPortForward(f, cmd, args)
|
||||||
usageError(cmd, "<pod> is required for exec")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(args) < 1 {
|
|
||||||
usageError(cmd, "at least 1 <port> is required for port-forward")
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace, err := f.DefaultNamespace(cmd)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
client, err := f.Client(cmd)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
pod, err := client.Pods(namespace).Get(flags.pod)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
if pod.Status.Phase != api.PodRunning {
|
|
||||||
glog.Fatalf("Unable to execute command because pod is not running. Current status=%v", pod.Status.Phase)
|
|
||||||
}
|
|
||||||
|
|
||||||
config, err := f.ClientConfig(cmd)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
signals := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(signals, os.Interrupt)
|
|
||||||
defer signal.Stop(signals)
|
|
||||||
|
|
||||||
stopCh := make(chan struct{}, 1)
|
|
||||||
go func() {
|
|
||||||
<-signals
|
|
||||||
close(stopCh)
|
|
||||||
}()
|
|
||||||
|
|
||||||
req := client.RESTClient.Get().
|
|
||||||
Prefix("proxy").
|
|
||||||
Resource("minions").
|
|
||||||
Name(pod.Status.Host).
|
|
||||||
Suffix("portForward", namespace, flags.pod)
|
|
||||||
|
|
||||||
pf, err := portforward.New(req, config, args, stopCh)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
err = pf.ForwardPorts()
|
|
||||||
util.CheckErr(err)
|
util.CheckErr(err)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cmd.Flags().StringVarP(&flags.pod, "pod", "p", "", "Pod name")
|
cmd.Flags().StringP("pod", "p", "", "Pod name")
|
||||||
// TODO support UID
|
// TODO support UID
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RunPortForward(f *Factory, cmd *cobra.Command, args []string) error {
|
||||||
|
podName := util.GetFlagString(cmd, "pod")
|
||||||
|
if len(podName) == 0 {
|
||||||
|
return util.UsageError(cmd, "<pod> is required for exec")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(args) < 1 {
|
||||||
|
return util.UsageError(cmd, "at least 1 <port> is required for port-forward")
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace, err := f.DefaultNamespace(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := f.Client(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pod, err := client.Pods(namespace).Get(podName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if pod.Status.Phase != api.PodRunning {
|
||||||
|
glog.Fatalf("Unable to execute command because pod is not running. Current status=%v", pod.Status.Phase)
|
||||||
|
}
|
||||||
|
|
||||||
|
config, err := f.ClientConfig(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
signals := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(signals, os.Interrupt)
|
||||||
|
defer signal.Stop(signals)
|
||||||
|
|
||||||
|
stopCh := make(chan struct{}, 1)
|
||||||
|
go func() {
|
||||||
|
<-signals
|
||||||
|
close(stopCh)
|
||||||
|
}()
|
||||||
|
|
||||||
|
req := client.RESTClient.Get().
|
||||||
|
Prefix("proxy").
|
||||||
|
Resource("minions").
|
||||||
|
Name(pod.Status.Host).
|
||||||
|
Suffix("portForward", namespace, podName)
|
||||||
|
|
||||||
|
pf, err := portforward.New(req, config, args, stopCh)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pf.ForwardPorts()
|
||||||
|
}
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -32,25 +33,8 @@ func (f *Factory) NewCmdProxy(out io.Writer) *cobra.Command {
|
|||||||
Short: "Run a proxy to the Kubernetes API server",
|
Short: "Run a proxy to the Kubernetes API server",
|
||||||
Long: `Run a proxy to the Kubernetes API server.`,
|
Long: `Run a proxy to the Kubernetes API server.`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
port := util.GetFlagInt(cmd, "port")
|
err := RunProxy(f, out, cmd)
|
||||||
glog.Infof("Starting to serve on localhost:%d", port)
|
|
||||||
|
|
||||||
clientConfig, err := f.ClientConfig(cmd)
|
|
||||||
util.CheckErr(err)
|
util.CheckErr(err)
|
||||||
|
|
||||||
staticPrefix := util.GetFlagString(cmd, "www-prefix")
|
|
||||||
if !strings.HasSuffix(staticPrefix, "/") {
|
|
||||||
staticPrefix += "/"
|
|
||||||
}
|
|
||||||
|
|
||||||
apiProxyPrefix := util.GetFlagString(cmd, "api-prefix")
|
|
||||||
if !strings.HasSuffix(apiProxyPrefix, "/") {
|
|
||||||
apiProxyPrefix += "/"
|
|
||||||
}
|
|
||||||
server, err := kubectl.NewProxyServer(util.GetFlagString(cmd, "www"), apiProxyPrefix, staticPrefix, clientConfig)
|
|
||||||
|
|
||||||
util.CheckErr(err)
|
|
||||||
glog.Fatal(server.Serve(port))
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cmd.Flags().StringP("www", "w", "", "Also serve static files from the given directory under the specified prefix.")
|
cmd.Flags().StringP("www", "w", "", "Also serve static files from the given directory under the specified prefix.")
|
||||||
@ -59,3 +43,30 @@ func (f *Factory) NewCmdProxy(out io.Writer) *cobra.Command {
|
|||||||
cmd.Flags().IntP("port", "p", 8001, "The port on which to run the proxy.")
|
cmd.Flags().IntP("port", "p", 8001, "The port on which to run the proxy.")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RunProxy(f *Factory, out io.Writer, cmd *cobra.Command) error {
|
||||||
|
port := util.GetFlagInt(cmd, "port")
|
||||||
|
fmt.Fprintf(out, "Starting to serve on localhost:%d", port)
|
||||||
|
|
||||||
|
clientConfig, err := f.ClientConfig(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
staticPrefix := util.GetFlagString(cmd, "www-prefix")
|
||||||
|
if !strings.HasSuffix(staticPrefix, "/") {
|
||||||
|
staticPrefix += "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
apiProxyPrefix := util.GetFlagString(cmd, "api-prefix")
|
||||||
|
if !strings.HasSuffix(apiProxyPrefix, "/") {
|
||||||
|
apiProxyPrefix += "/"
|
||||||
|
}
|
||||||
|
server, err := kubectl.NewProxyServer(util.GetFlagString(cmd, "www"), apiProxyPrefix, staticPrefix, clientConfig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
glog.Fatal(server.Serve(port))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -52,32 +52,8 @@ func (f *Factory) NewCmdResize(out io.Writer) *cobra.Command {
|
|||||||
Long: resize_long,
|
Long: resize_long,
|
||||||
Example: resize_example,
|
Example: resize_example,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
count := util.GetFlagInt(cmd, "replicas")
|
err := RunResize(f, out, cmd, args)
|
||||||
if len(args) != 2 || count < 0 {
|
|
||||||
usageError(cmd, "--replicas=<count> <resource> <id>")
|
|
||||||
}
|
|
||||||
|
|
||||||
cmdNamespace, err := f.DefaultNamespace(cmd)
|
|
||||||
util.CheckErr(err)
|
util.CheckErr(err)
|
||||||
|
|
||||||
mapper, _ := f.Object(cmd)
|
|
||||||
// TODO: use resource.Builder instead
|
|
||||||
mapping, namespace, name := util.ResourceFromArgs(cmd, args, mapper, cmdNamespace)
|
|
||||||
|
|
||||||
resizer, err := f.Resizer(cmd, mapping)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
resourceVersion := util.GetFlagString(cmd, "resource-version")
|
|
||||||
currentSize := util.GetFlagInt(cmd, "current-replicas")
|
|
||||||
precondition := &kubectl.ResizePrecondition{currentSize, resourceVersion}
|
|
||||||
cond := kubectl.ResizeCondition(resizer, precondition, namespace, name, uint(count))
|
|
||||||
|
|
||||||
msg := "resized"
|
|
||||||
if err = wait.Poll(retryFrequency, retryTimeout, cond); err != nil {
|
|
||||||
msg = fmt.Sprintf("Failed to resize controller in spite of retrying for %s", retryTimeout)
|
|
||||||
util.CheckErr(err)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(out, "%s\n", msg)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cmd.Flags().String("resource-version", "", "Precondition for resource version. Requires that the current resource version match this value in order to resize.")
|
cmd.Flags().String("resource-version", "", "Precondition for resource version. Requires that the current resource version match this value in order to resize.")
|
||||||
@ -85,3 +61,42 @@ func (f *Factory) NewCmdResize(out io.Writer) *cobra.Command {
|
|||||||
cmd.Flags().Int("replicas", -1, "The new desired number of replicas. Required.")
|
cmd.Flags().Int("replicas", -1, "The new desired number of replicas. Required.")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RunResize(f *Factory, out io.Writer, cmd *cobra.Command, args []string) error {
|
||||||
|
count := util.GetFlagInt(cmd, "replicas")
|
||||||
|
if len(args) != 2 || count < 0 {
|
||||||
|
return util.UsageError(cmd, "--replicas=<count> <resource> <id>")
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdNamespace, err := f.DefaultNamespace(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper, _ := f.Object(cmd)
|
||||||
|
// TODO: use resource.Builder instead
|
||||||
|
mapping, namespace, name, err := util.ResourceFromArgs(cmd, args, mapper, cmdNamespace)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
resizer, err := f.Resizer(cmd, mapping)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceVersion := util.GetFlagString(cmd, "resource-version")
|
||||||
|
currentSize := util.GetFlagInt(cmd, "current-replicas")
|
||||||
|
precondition := &kubectl.ResizePrecondition{currentSize, resourceVersion}
|
||||||
|
cond := kubectl.ResizeCondition(resizer, precondition, namespace, name, uint(count))
|
||||||
|
|
||||||
|
msg := "resized"
|
||||||
|
if err = wait.Poll(retryFrequency, retryTimeout, cond); err != nil {
|
||||||
|
msg = fmt.Sprintf("Failed to resize controller in spite of retrying for %s", retryTimeout)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Fprintf(out, "%s\n", msg)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -49,73 +49,8 @@ func (f *Factory) NewCmdRollingUpdate(out io.Writer) *cobra.Command {
|
|||||||
Long: rollingupdate_long,
|
Long: rollingupdate_long,
|
||||||
Example: rollingupdate_example,
|
Example: rollingupdate_example,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
filename := util.GetFlagString(cmd, "filename")
|
err := RunRollingUpdate(f, out, cmd, args)
|
||||||
if len(filename) == 0 {
|
|
||||||
usageError(cmd, "Must specify filename for new controller")
|
|
||||||
}
|
|
||||||
period := util.GetFlagDuration(cmd, "update-period")
|
|
||||||
interval := util.GetFlagDuration(cmd, "poll-interval")
|
|
||||||
timeout := util.GetFlagDuration(cmd, "timeout")
|
|
||||||
if len(args) != 1 {
|
|
||||||
usageError(cmd, "Must specify the controller to update")
|
|
||||||
}
|
|
||||||
oldName := args[0]
|
|
||||||
schema, err := f.Validator(cmd)
|
|
||||||
util.CheckErr(err)
|
util.CheckErr(err)
|
||||||
|
|
||||||
clientConfig, err := f.ClientConfig(cmd)
|
|
||||||
util.CheckErr(err)
|
|
||||||
cmdApiVersion := clientConfig.Version
|
|
||||||
|
|
||||||
mapper, typer := f.Object(cmd)
|
|
||||||
// TODO: use resource.Builder instead
|
|
||||||
mapping, namespace, newName, data := util.ResourceFromFile(filename, typer, mapper, schema, cmdApiVersion)
|
|
||||||
if mapping.Kind != "ReplicationController" {
|
|
||||||
usageError(cmd, "%s does not specify a valid ReplicationController", filename)
|
|
||||||
}
|
|
||||||
if oldName == newName {
|
|
||||||
usageError(cmd, "%s cannot have the same name as the existing ReplicationController %s",
|
|
||||||
filename, oldName)
|
|
||||||
}
|
|
||||||
|
|
||||||
cmdNamespace, err := f.DefaultNamespace(cmd)
|
|
||||||
util.CheckErr(err)
|
|
||||||
// TODO: use resource.Builder instead
|
|
||||||
err = util.CompareNamespace(cmdNamespace, namespace)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
client, err := f.Client(cmd)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
obj, err := mapping.Codec.Decode(data)
|
|
||||||
util.CheckErr(err)
|
|
||||||
newRc := obj.(*api.ReplicationController)
|
|
||||||
|
|
||||||
updater := kubectl.NewRollingUpdater(cmdNamespace, client)
|
|
||||||
|
|
||||||
// fetch rc
|
|
||||||
oldRc, err := client.ReplicationControllers(cmdNamespace).Get(oldName)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
var hasLabel bool
|
|
||||||
for key, oldValue := range oldRc.Spec.Selector {
|
|
||||||
if newValue, ok := newRc.Spec.Selector[key]; ok && newValue != oldValue {
|
|
||||||
hasLabel = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !hasLabel {
|
|
||||||
usageError(cmd, "%s must specify a matching key with non-equal value in Selector for %s",
|
|
||||||
filename, oldName)
|
|
||||||
}
|
|
||||||
// TODO: handle resizes during rolling update
|
|
||||||
if newRc.Spec.Replicas == 0 {
|
|
||||||
newRc.Spec.Replicas = oldRc.Spec.Replicas
|
|
||||||
}
|
|
||||||
err = updater.Update(out, oldRc, newRc, period, interval, timeout)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
fmt.Fprintf(out, "%s\n", newName)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cmd.Flags().String("update-period", updatePeriod, `Time to wait between updating pods. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".`)
|
cmd.Flags().String("update-period", updatePeriod, `Time to wait between updating pods. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".`)
|
||||||
@ -124,3 +59,93 @@ func (f *Factory) NewCmdRollingUpdate(out io.Writer) *cobra.Command {
|
|||||||
cmd.Flags().StringP("filename", "f", "", "Filename or URL to file to use to create the new controller.")
|
cmd.Flags().StringP("filename", "f", "", "Filename or URL to file to use to create the new controller.")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RunRollingUpdate(f *Factory, out io.Writer, cmd *cobra.Command, args []string) error {
|
||||||
|
filename := util.GetFlagString(cmd, "filename")
|
||||||
|
if len(filename) == 0 {
|
||||||
|
return util.UsageError(cmd, "Must specify filename for new controller")
|
||||||
|
}
|
||||||
|
period := util.GetFlagDuration(cmd, "update-period")
|
||||||
|
interval := util.GetFlagDuration(cmd, "poll-interval")
|
||||||
|
timeout := util.GetFlagDuration(cmd, "timeout")
|
||||||
|
if len(args) != 1 {
|
||||||
|
return util.UsageError(cmd, "Must specify the controller to update")
|
||||||
|
}
|
||||||
|
oldName := args[0]
|
||||||
|
schema, err := f.Validator(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
clientConfig, err := f.ClientConfig(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cmdApiVersion := clientConfig.Version
|
||||||
|
|
||||||
|
mapper, typer := f.Object(cmd)
|
||||||
|
// TODO: use resource.Builder instead
|
||||||
|
mapping, namespace, newName, data, err := util.ResourceFromFile(filename, typer, mapper, schema, cmdApiVersion)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if mapping.Kind != "ReplicationController" {
|
||||||
|
return util.UsageError(cmd, "%s does not specify a valid ReplicationController", filename)
|
||||||
|
}
|
||||||
|
if oldName == newName {
|
||||||
|
return util.UsageError(cmd, "%s cannot have the same name as the existing ReplicationController %s",
|
||||||
|
filename, oldName)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdNamespace, err := f.DefaultNamespace(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// TODO: use resource.Builder instead
|
||||||
|
err = util.CompareNamespace(cmdNamespace, namespace)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := f.Client(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
obj, err := mapping.Codec.Decode(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
newRc := obj.(*api.ReplicationController)
|
||||||
|
|
||||||
|
updater := kubectl.NewRollingUpdater(cmdNamespace, client)
|
||||||
|
|
||||||
|
// fetch rc
|
||||||
|
oldRc, err := client.ReplicationControllers(cmdNamespace).Get(oldName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasLabel bool
|
||||||
|
for key, oldValue := range oldRc.Spec.Selector {
|
||||||
|
if newValue, ok := newRc.Spec.Selector[key]; ok && newValue != oldValue {
|
||||||
|
hasLabel = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !hasLabel {
|
||||||
|
return util.UsageError(cmd, "%s must specify a matching key with non-equal value in Selector for %s",
|
||||||
|
filename, oldName)
|
||||||
|
}
|
||||||
|
// TODO: handle resizes during rolling update
|
||||||
|
if newRc.Spec.Replicas == 0 {
|
||||||
|
newRc.Spec.Replicas = oldRc.Spec.Replicas
|
||||||
|
}
|
||||||
|
err = updater.Update(out, oldRc, newRc, period, interval, timeout)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(out, "%s\n", newName)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -49,44 +49,7 @@ func (f *Factory) NewCmdRunContainer(out io.Writer) *cobra.Command {
|
|||||||
Long: run_long,
|
Long: run_long,
|
||||||
Example: run_example,
|
Example: run_example,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
if len(args) != 1 {
|
err := RunRunContainer(f, out, cmd, args)
|
||||||
usageError(cmd, "<name> is required for run-container")
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace, err := f.DefaultNamespace(cmd)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
client, err := f.Client(cmd)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
generatorName := util.GetFlagString(cmd, "generator")
|
|
||||||
generator, found := kubectl.Generators[generatorName]
|
|
||||||
if !found {
|
|
||||||
usageError(cmd, fmt.Sprintf("Generator: %s not found.", generator))
|
|
||||||
}
|
|
||||||
names := generator.ParamNames()
|
|
||||||
params := kubectl.MakeParams(cmd, names)
|
|
||||||
params["name"] = args[0]
|
|
||||||
|
|
||||||
err = kubectl.ValidateParams(names, params)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
controller, err := generator.Generate(params)
|
|
||||||
util.CheckErr(err)
|
|
||||||
|
|
||||||
inline := util.GetFlagString(cmd, "overrides")
|
|
||||||
if len(inline) > 0 {
|
|
||||||
controller, err = util.Merge(controller, inline, "ReplicationController")
|
|
||||||
util.CheckErr(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: extract this flag to a central location, when such a location exists.
|
|
||||||
if !util.GetFlagBool(cmd, "dry-run") {
|
|
||||||
controller, err = client.ReplicationControllers(namespace).Create(controller.(*api.ReplicationController))
|
|
||||||
util.CheckErr(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = f.PrintObject(cmd, controller, out)
|
|
||||||
util.CheckErr(err)
|
util.CheckErr(err)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -100,3 +63,56 @@ func (f *Factory) NewCmdRunContainer(out io.Writer) *cobra.Command {
|
|||||||
cmd.Flags().StringP("labels", "l", "", "Labels to apply to the pod(s) created by this call to run-container.")
|
cmd.Flags().StringP("labels", "l", "", "Labels to apply to the pod(s) created by this call to run-container.")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RunRunContainer(f *Factory, out io.Writer, cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return util.UsageError(cmd, "<name> is required for run-container")
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace, err := f.DefaultNamespace(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := f.Client(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
generatorName := util.GetFlagString(cmd, "generator")
|
||||||
|
generator, found := kubectl.Generators[generatorName]
|
||||||
|
if !found {
|
||||||
|
return util.UsageError(cmd, fmt.Sprintf("Generator: %s not found.", generator))
|
||||||
|
}
|
||||||
|
names := generator.ParamNames()
|
||||||
|
params := kubectl.MakeParams(cmd, names)
|
||||||
|
params["name"] = args[0]
|
||||||
|
|
||||||
|
err = kubectl.ValidateParams(names, params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
controller, err := generator.Generate(params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
inline := util.GetFlagString(cmd, "overrides")
|
||||||
|
if len(inline) > 0 {
|
||||||
|
controller, err = util.Merge(controller, inline, "ReplicationController")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: extract this flag to a central location, when such a location exists.
|
||||||
|
if !util.GetFlagBool(cmd, "dry-run") {
|
||||||
|
controller, err = client.ReplicationControllers(namespace).Create(controller.(*api.ReplicationController))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return f.PrintObject(cmd, controller, out)
|
||||||
|
}
|
||||||
|
@ -41,91 +41,115 @@ $ kubectl update pods my-pod --patch='{ "apiVersion": "v1beta1", "desiredState":
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (f *Factory) NewCmdUpdate(out io.Writer) *cobra.Command {
|
func (f *Factory) NewCmdUpdate(out io.Writer) *cobra.Command {
|
||||||
flags := &struct {
|
var filenames util.StringList
|
||||||
Filenames util.StringList
|
|
||||||
}{}
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "update -f filename",
|
Use: "update -f filename",
|
||||||
Short: "Update a resource by filename or stdin.",
|
Short: "Update a resource by filename or stdin.",
|
||||||
Long: update_long,
|
Long: update_long,
|
||||||
Example: update_example,
|
Example: update_example,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
schema, err := f.Validator(cmd)
|
err := RunUpdate(f, out, cmd, args, filenames)
|
||||||
cmdutil.CheckErr(err)
|
cmdutil.CheckErr(err)
|
||||||
|
|
||||||
cmdNamespace, err := f.DefaultNamespace(cmd)
|
|
||||||
cmdutil.CheckErr(err)
|
|
||||||
|
|
||||||
patch := cmdutil.GetFlagString(cmd, "patch")
|
|
||||||
if len(flags.Filenames) == 0 && len(patch) == 0 {
|
|
||||||
usageError(cmd, "Must specify --filename or --patch to update")
|
|
||||||
}
|
|
||||||
if len(flags.Filenames) != 0 && len(patch) != 0 {
|
|
||||||
usageError(cmd, "Can not specify both --filename and --patch")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Make patching work with -f, updating with patched JSON input files
|
|
||||||
if len(flags.Filenames) == 0 {
|
|
||||||
name := updateWithPatch(cmd, args, f, patch)
|
|
||||||
fmt.Fprintf(out, "%s\n", name)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
mapper, typer := f.Object(cmd)
|
|
||||||
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand(cmd)).
|
|
||||||
ContinueOnError().
|
|
||||||
NamespaceParam(cmdNamespace).RequireNamespace().
|
|
||||||
FilenameParam(flags.Filenames...).
|
|
||||||
Flatten().
|
|
||||||
Do()
|
|
||||||
cmdutil.CheckErr(r.Err())
|
|
||||||
|
|
||||||
err = r.Visit(func(info *resource.Info) error {
|
|
||||||
data, err := info.Mapping.Codec.Encode(info.Object)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := schema.ValidateBytes(data); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
obj, err := resource.NewHelper(info.Client, info.Mapping).Update(info.Namespace, info.Name, true, data)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
info.Refresh(obj, true)
|
|
||||||
fmt.Fprintf(out, "%s\n", info.Name)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
cmdutil.CheckErr(err)
|
|
||||||
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cmd.Flags().VarP(&flags.Filenames, "filename", "f", "Filename, directory, or URL to file to use to update the resource.")
|
cmd.Flags().VarP(&filenames, "filename", "f", "Filename, directory, or URL to file to use to update the resource.")
|
||||||
cmd.Flags().String("patch", "", "A JSON document to override the existing resource. The resource is downloaded, patched with the JSON, then updated.")
|
cmd.Flags().String("patch", "", "A JSON document to override the existing resource. The resource is downloaded, patched with the JSON, then updated.")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateWithPatch(cmd *cobra.Command, args []string, f *Factory, patch string) string {
|
func RunUpdate(f *Factory, out io.Writer, cmd *cobra.Command, args []string, filenames util.StringList) error {
|
||||||
|
schema, err := f.Validator(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
cmdNamespace, err := f.DefaultNamespace(cmd)
|
cmdNamespace, err := f.DefaultNamespace(cmd)
|
||||||
cmdutil.CheckErr(err)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
patch := cmdutil.GetFlagString(cmd, "patch")
|
||||||
|
if len(filenames) == 0 && len(patch) == 0 {
|
||||||
|
return cmdutil.UsageError(cmd, "Must specify --filename or --patch to update")
|
||||||
|
}
|
||||||
|
if len(filenames) != 0 && len(patch) != 0 {
|
||||||
|
return cmdutil.UsageError(cmd, "Can not specify both --filename and --patch")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Make patching work with -f, updating with patched JSON input files
|
||||||
|
if len(filenames) == 0 {
|
||||||
|
name, err := updateWithPatch(cmd, args, f, patch)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Fprintf(out, "%s\n", name)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
mapper, typer := f.Object(cmd)
|
||||||
|
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand(cmd)).
|
||||||
|
ContinueOnError().
|
||||||
|
NamespaceParam(cmdNamespace).RequireNamespace().
|
||||||
|
FilenameParam(filenames...).
|
||||||
|
Flatten().
|
||||||
|
Do()
|
||||||
|
err = r.Err()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.Visit(func(info *resource.Info) error {
|
||||||
|
data, err := info.Mapping.Codec.Encode(info.Object)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := schema.ValidateBytes(data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
obj, err := resource.NewHelper(info.Client, info.Mapping).Update(info.Namespace, info.Name, true, data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
info.Refresh(obj, true)
|
||||||
|
fmt.Fprintf(out, "%s\n", info.Name)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateWithPatch(cmd *cobra.Command, args []string, f *Factory, patch string) (string, error) {
|
||||||
|
cmdNamespace, err := f.DefaultNamespace(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
mapper, _ := f.Object(cmd)
|
mapper, _ := f.Object(cmd)
|
||||||
// TODO: use resource.Builder instead
|
// TODO: use resource.Builder instead
|
||||||
mapping, namespace, name := cmdutil.ResourceFromArgs(cmd, args, mapper, cmdNamespace)
|
mapping, namespace, name, err := cmdutil.ResourceFromArgs(cmd, args, mapper, cmdNamespace)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
client, err := f.RESTClient(cmd, mapping)
|
client, err := f.RESTClient(cmd, mapping)
|
||||||
cmdutil.CheckErr(err)
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
helper := resource.NewHelper(client, mapping)
|
helper := resource.NewHelper(client, mapping)
|
||||||
obj, err := helper.Get(namespace, name)
|
obj, err := helper.Get(namespace, name)
|
||||||
cmdutil.CheckErr(err)
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
patchedObj, err := cmdutil.Merge(obj, patch, mapping.Kind)
|
patchedObj, err := cmdutil.Merge(obj, patch, mapping.Kind)
|
||||||
cmdutil.CheckErr(err)
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
data, err := helper.Codec.Encode(patchedObj)
|
data, err := helper.Codec.Encode(patchedObj)
|
||||||
cmdutil.CheckErr(err)
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
_, err = helper.Update(namespace, name, true, data)
|
_, err = helper.Update(namespace, name, true, data)
|
||||||
cmdutil.CheckErr(err)
|
return name, err
|
||||||
return name
|
|
||||||
}
|
}
|
||||||
|
@ -31,10 +31,11 @@ import (
|
|||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||||
|
|
||||||
"github.com/evanphx/json-patch"
|
"github.com/evanphx/json-patch"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CheckErr(err error) {
|
func CheckErr(err error) {
|
||||||
@ -52,25 +53,26 @@ func CheckErr(err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func usageError(cmd *cobra.Command, format string, args ...interface{}) {
|
func UsageError(cmd *cobra.Command, format string, args ...interface{}) error {
|
||||||
glog.Errorf(format, args...)
|
msg := fmt.Sprintf(format, args...)
|
||||||
glog.Errorf("See '%s -h' for help.", cmd.CommandPath())
|
return fmt.Errorf("%s\nsee '%s -h' for help.", msg, cmd.CommandPath())
|
||||||
os.Exit(1)
|
}
|
||||||
|
|
||||||
|
func getFlag(cmd *cobra.Command, flag string) *pflag.Flag {
|
||||||
|
f := cmd.Flags().Lookup(flag)
|
||||||
|
if f == nil {
|
||||||
|
glog.Fatalf("flag accessed but not defined for command %s: %s", cmd.Name(), flag)
|
||||||
|
}
|
||||||
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetFlagString(cmd *cobra.Command, flag string) string {
|
func GetFlagString(cmd *cobra.Command, flag string) string {
|
||||||
f := cmd.Flags().Lookup(flag)
|
f := getFlag(cmd, flag)
|
||||||
if f == nil {
|
|
||||||
glog.Fatalf("Flag accessed but not defined for command %s: %s", cmd.Name(), flag)
|
|
||||||
}
|
|
||||||
return f.Value.String()
|
return f.Value.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetFlagBool(cmd *cobra.Command, flag string) bool {
|
func GetFlagBool(cmd *cobra.Command, flag string) bool {
|
||||||
f := cmd.Flags().Lookup(flag)
|
f := getFlag(cmd, flag)
|
||||||
if f == nil {
|
|
||||||
glog.Fatalf("Flag accessed but not defined for command %s: %s", cmd.Name(), flag)
|
|
||||||
}
|
|
||||||
result, err := strconv.ParseBool(f.Value.String())
|
result, err := strconv.ParseBool(f.Value.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Invalid value for a boolean flag: %s", f.Value.String())
|
glog.Fatalf("Invalid value for a boolean flag: %s", f.Value.String())
|
||||||
@ -80,24 +82,22 @@ func GetFlagBool(cmd *cobra.Command, flag string) bool {
|
|||||||
|
|
||||||
// Assumes the flag has a default value.
|
// Assumes the flag has a default value.
|
||||||
func GetFlagInt(cmd *cobra.Command, flag string) int {
|
func GetFlagInt(cmd *cobra.Command, flag string) int {
|
||||||
f := cmd.Flags().Lookup(flag)
|
f := getFlag(cmd, flag)
|
||||||
if f == nil {
|
|
||||||
glog.Fatalf("Flag accessed but not defined for command %s: %s", cmd.Name(), flag)
|
|
||||||
}
|
|
||||||
v, err := strconv.Atoi(f.Value.String())
|
v, err := strconv.Atoi(f.Value.String())
|
||||||
// This is likely not a sufficiently friendly error message, but cobra
|
// This is likely not a sufficiently friendly error message, but cobra
|
||||||
// should prevent non-integer values from reaching here.
|
// should prevent non-integer values from reaching here.
|
||||||
CheckErr(err)
|
if err != nil {
|
||||||
|
glog.Fatalf("unable to convert flag value to int: %v", err)
|
||||||
|
}
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetFlagDuration(cmd *cobra.Command, flag string) time.Duration {
|
func GetFlagDuration(cmd *cobra.Command, flag string) time.Duration {
|
||||||
f := cmd.Flags().Lookup(flag)
|
f := getFlag(cmd, flag)
|
||||||
if f == nil {
|
|
||||||
glog.Fatalf("Flag accessed but not defined for command %s: %s", cmd.Name(), flag)
|
|
||||||
}
|
|
||||||
v, err := time.ParseDuration(f.Value.String())
|
v, err := time.ParseDuration(f.Value.String())
|
||||||
CheckErr(err)
|
if err != nil {
|
||||||
|
glog.Fatalf("unable to convert flag value to Duration: %v", err)
|
||||||
|
}
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,26 +27,29 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ResourceFromArgs expects two arguments with a given type, and extracts the fields necessary
|
// ResourceFromArgs expects two arguments with a given type, and extracts the fields necessary
|
||||||
// to uniquely locate a resource. Displays a usageError if that contract is not satisfied, or
|
// to uniquely locate a resource. Displays a UsageError if that contract is not satisfied, or
|
||||||
// a generic error if any other problems occur.
|
// a generic error if any other problems occur.
|
||||||
// DEPRECATED: Use resource.Builder
|
// DEPRECATED: Use resource.Builder
|
||||||
func ResourceFromArgs(cmd *cobra.Command, args []string, mapper meta.RESTMapper, cmdNamespace string) (mapping *meta.RESTMapping, namespace, name string) {
|
func ResourceFromArgs(cmd *cobra.Command, args []string, mapper meta.RESTMapper, cmdNamespace string) (mapping *meta.RESTMapping, namespace, name string, err error) {
|
||||||
if len(args) != 2 {
|
if len(args) != 2 {
|
||||||
usageError(cmd, "Must provide resource and name command line params")
|
err = UsageError(cmd, "Must provide resource and name command line params")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resource := args[0]
|
resource := args[0]
|
||||||
namespace = cmdNamespace
|
namespace = cmdNamespace
|
||||||
name = args[1]
|
name = args[1]
|
||||||
if len(name) == 0 || len(resource) == 0 {
|
if len(name) == 0 || len(resource) == 0 {
|
||||||
usageError(cmd, "Must provide resource and name command line params")
|
err = UsageError(cmd, "Must provide resource and name command line params")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
version, kind, err := mapper.VersionAndKindForResource(resource)
|
version, kind, err := mapper.VersionAndKindForResource(resource)
|
||||||
CheckErr(err)
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
mapping, err = mapper.RESTMapping(kind, version)
|
mapping, err = mapper.RESTMapping(kind, version)
|
||||||
CheckErr(err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,41 +57,52 @@ func ResourceFromArgs(cmd *cobra.Command, args []string, mapper meta.RESTMapper,
|
|||||||
// resolve to a known type an error is returned. The returned mapping can be used to determine
|
// resolve to a known type an error is returned. The returned mapping can be used to determine
|
||||||
// the correct REST endpoint to modify this resource with.
|
// the correct REST endpoint to modify this resource with.
|
||||||
// DEPRECATED: Use resource.Builder
|
// DEPRECATED: Use resource.Builder
|
||||||
func ResourceFromFile(filename string, typer runtime.ObjectTyper, mapper meta.RESTMapper, schema validation.Schema, cmdVersion string) (mapping *meta.RESTMapping, namespace, name string, data []byte) {
|
func ResourceFromFile(filename string, typer runtime.ObjectTyper, mapper meta.RESTMapper, schema validation.Schema, cmdVersion string) (mapping *meta.RESTMapping, namespace, name string, data []byte, err error) {
|
||||||
configData, err := ReadConfigData(filename)
|
data, err = ReadConfigData(filename)
|
||||||
CheckErr(err)
|
if err != nil {
|
||||||
data = configData
|
return
|
||||||
|
}
|
||||||
|
|
||||||
objVersion, kind, err := typer.DataVersionAndKind(data)
|
objVersion, kind, err := typer.DataVersionAndKind(data)
|
||||||
CheckErr(err)
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: allow unversioned objects?
|
// TODO: allow unversioned objects?
|
||||||
if len(objVersion) == 0 {
|
if len(objVersion) == 0 {
|
||||||
CheckErr(fmt.Errorf("the resource in the provided file has no apiVersion defined"))
|
err = fmt.Errorf("the resource in the provided file has no apiVersion defined")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = schema.ValidateBytes(data)
|
err = schema.ValidateBytes(data)
|
||||||
CheckErr(err)
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// decode using the version stored with the object (allows codec to vary across versions)
|
// decode using the version stored with the object (allows codec to vary across versions)
|
||||||
mapping, err = mapper.RESTMapping(kind, objVersion)
|
mapping, err = mapper.RESTMapping(kind, objVersion)
|
||||||
CheckErr(err)
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
obj, err := mapping.Codec.Decode(data)
|
obj, err := mapping.Codec.Decode(data)
|
||||||
CheckErr(err)
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
meta := mapping.MetadataAccessor
|
meta := mapping.MetadataAccessor
|
||||||
namespace, err = meta.Namespace(obj)
|
namespace, err = meta.Namespace(obj)
|
||||||
CheckErr(err)
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
name, err = meta.Name(obj)
|
name, err = meta.Name(obj)
|
||||||
CheckErr(err)
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// if the preferred API version differs, get a different mapper
|
// if the preferred API version differs, get a different mapper
|
||||||
if cmdVersion != objVersion {
|
if cmdVersion != objVersion {
|
||||||
mapping, err = mapper.RESTMapping(kind, cmdVersion)
|
mapping, err = mapper.RESTMapping(kind, cmdVersion)
|
||||||
CheckErr(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,17 +30,25 @@ func (f *Factory) NewCmdVersion(out io.Writer) *cobra.Command {
|
|||||||
Use: "version",
|
Use: "version",
|
||||||
Short: "Print the client and server version information.",
|
Short: "Print the client and server version information.",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
if util.GetFlagBool(cmd, "client") {
|
err := RunVersion(f, out, cmd)
|
||||||
kubectl.GetClientVersion(out)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := f.Client(cmd)
|
|
||||||
util.CheckErr(err)
|
util.CheckErr(err)
|
||||||
|
|
||||||
kubectl.GetVersion(out, client)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cmd.Flags().BoolP("client", "c", false, "Client version only (no server required).")
|
cmd.Flags().BoolP("client", "c", false, "Client version only (no server required).")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RunVersion(f *Factory, out io.Writer, cmd *cobra.Command) error {
|
||||||
|
if util.GetFlagBool(cmd, "client") {
|
||||||
|
kubectl.GetClientVersion(out)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := f.Client(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
kubectl.GetVersion(out, client)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user