mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Make kubectl commands return errors and centralize exit handling
This commit is contained in:
		@@ -34,20 +34,25 @@ func (f *Factory) NewCmdClusterInfo(out io.Writer) *cobra.Command {
 | 
			
		||||
		Short: "Display cluster info",
 | 
			
		||||
		Long:  "Display addresses of the master and services with label kubernetes.io/cluster-service=true",
 | 
			
		||||
		Run: func(cmd *cobra.Command, args []string) {
 | 
			
		||||
			RunClusterInfo(f, out, cmd)
 | 
			
		||||
			err := RunClusterInfo(f, out, cmd)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	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)
 | 
			
		||||
	util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Fprintf(out, "Kubernetes master is running at %v\n", client.Host)
 | 
			
		||||
 | 
			
		||||
	mapper, typer := factory.Object(cmd)
 | 
			
		||||
	cmdNamespace, err := factory.DefaultNamespace(cmd)
 | 
			
		||||
	util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: use generalized labels once they are implemented (#341)
 | 
			
		||||
	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
 | 
			
		||||
 | 
			
		||||
	// TODO: consider printing more information about cluster
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,6 @@ import (
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
 | 
			
		||||
 | 
			
		||||
	"github.com/golang/glog"
 | 
			
		||||
	"github.com/spf13/cobra"
 | 
			
		||||
	"github.com/spf13/pflag"
 | 
			
		||||
)
 | 
			
		||||
@@ -253,7 +252,9 @@ func (f *Factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMappin
 | 
			
		||||
	}
 | 
			
		||||
	if ok {
 | 
			
		||||
		clientConfig, err := f.ClientConfig(cmd)
 | 
			
		||||
		cmdutil.CheckErr(err)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		defaultVersion := clientConfig.Version
 | 
			
		||||
 | 
			
		||||
		version := cmdutil.OutputVersion(cmd, defaultVersion)
 | 
			
		||||
@@ -329,12 +330,6 @@ func DefaultClientConfig(flags *pflag.FlagSet) clientcmd.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) {
 | 
			
		||||
	cmd.Help()
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -39,29 +39,43 @@ $ cat pod.json | kubectl create -f -`
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (f *Factory) NewCmdCreate(out io.Writer) *cobra.Command {
 | 
			
		||||
	flags := &struct {
 | 
			
		||||
		Filenames util.StringList
 | 
			
		||||
	}{}
 | 
			
		||||
	var filenames util.StringList
 | 
			
		||||
	cmd := &cobra.Command{
 | 
			
		||||
		Use:     "create -f filename",
 | 
			
		||||
		Short:   "Create a resource by filename or stdin",
 | 
			
		||||
		Long:    create_long,
 | 
			
		||||
		Example: create_example,
 | 
			
		||||
		Run: func(cmd *cobra.Command, args []string) {
 | 
			
		||||
			schema, err := f.Validator(cmd)
 | 
			
		||||
			err := RunCreate(f, out, cmd, filenames)
 | 
			
		||||
			cmdutil.CheckErr(err)
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	cmd.Flags().VarP(&filenames, "filename", "f", "Filename, directory, or URL to file to use to create the resource")
 | 
			
		||||
	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)
 | 
			
		||||
			cmdutil.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mapper, typer := f.Object(cmd)
 | 
			
		||||
	r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand(cmd)).
 | 
			
		||||
		ContinueOnError().
 | 
			
		||||
		NamespaceParam(cmdNamespace).RequireNamespace().
 | 
			
		||||
				FilenameParam(flags.Filenames...).
 | 
			
		||||
		FilenameParam(filenames...).
 | 
			
		||||
		Flatten().
 | 
			
		||||
		Do()
 | 
			
		||||
			cmdutil.CheckErr(r.Err())
 | 
			
		||||
	err = r.Err()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	count := 0
 | 
			
		||||
	err = r.Visit(func(info *resource.Info) error {
 | 
			
		||||
@@ -81,12 +95,11 @@ func (f *Factory) NewCmdCreate(out io.Writer) *cobra.Command {
 | 
			
		||||
		fmt.Fprintf(out, "%s\n", info.Name)
 | 
			
		||||
		return nil
 | 
			
		||||
	})
 | 
			
		||||
			cmdutil.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if count == 0 {
 | 
			
		||||
				cmdutil.CheckErr(fmt.Errorf("no objects passed to create"))
 | 
			
		||||
		return 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")
 | 
			
		||||
	return cmd
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -56,28 +56,42 @@ $ kubectl delete pods --all`
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (f *Factory) NewCmdDelete(out io.Writer) *cobra.Command {
 | 
			
		||||
	flags := &struct {
 | 
			
		||||
		Filenames util.StringList
 | 
			
		||||
	}{}
 | 
			
		||||
	var filenames util.StringList
 | 
			
		||||
	cmd := &cobra.Command{
 | 
			
		||||
		Use:     "delete ([-f filename] | (<resource> [(<id> | -l <label> | --all)]",
 | 
			
		||||
		Short:   "Delete a resource by filename, stdin, or resource and ID.",
 | 
			
		||||
		Long:    delete_long,
 | 
			
		||||
		Example: delete_example,
 | 
			
		||||
		Run: func(cmd *cobra.Command, args []string) {
 | 
			
		||||
			cmdNamespace, err := f.DefaultNamespace(cmd)
 | 
			
		||||
			err := RunDelete(f, out, cmd, args, filenames)
 | 
			
		||||
			cmdutil.CheckErr(err)
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	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().Bool("all", false, "[-all] to select all the specified resources")
 | 
			
		||||
	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(flags.Filenames...).
 | 
			
		||||
		FilenameParam(filenames...).
 | 
			
		||||
		SelectorParam(cmdutil.GetFlagString(cmd, "selector")).
 | 
			
		||||
		SelectAllParam(cmdutil.GetFlagBool(cmd, "all")).
 | 
			
		||||
		ResourceTypeOrNameArgs(false, args...).
 | 
			
		||||
		Flatten().
 | 
			
		||||
		Do()
 | 
			
		||||
			cmdutil.CheckErr(r.Err())
 | 
			
		||||
	err = r.Err()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	found := 0
 | 
			
		||||
	err = r.IgnoreErrors(errors.IsNotFound).Visit(func(r *resource.Info) error {
 | 
			
		||||
@@ -88,14 +102,11 @@ func (f *Factory) NewCmdDelete(out io.Writer) *cobra.Command {
 | 
			
		||||
		fmt.Fprintf(out, "%s\n", r.Name)
 | 
			
		||||
		return nil
 | 
			
		||||
	})
 | 
			
		||||
			cmdutil.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 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().StringP("selector", "l", "", "Selector (label query) to filter on")
 | 
			
		||||
	cmd.Flags().Bool("all", false, "[-all] to select all the specified resources")
 | 
			
		||||
	return cmd
 | 
			
		||||
	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
 | 
			
		||||
given resource.`,
 | 
			
		||||
		Run: func(cmd *cobra.Command, args []string) {
 | 
			
		||||
			cmdNamespace, err := f.DefaultNamespace(cmd)
 | 
			
		||||
			err := RunDescribe(f, out, cmd, args)
 | 
			
		||||
			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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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,48 +39,63 @@ $ 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 {
 | 
			
		||||
	flags := &struct {
 | 
			
		||||
		pod       string
 | 
			
		||||
		container string
 | 
			
		||||
		stdin     bool
 | 
			
		||||
		tty       bool
 | 
			
		||||
	}{}
 | 
			
		||||
 | 
			
		||||
	cmd := &cobra.Command{
 | 
			
		||||
		Use:     "exec -p <pod> -c <container> -- <command> [<args...>]",
 | 
			
		||||
		Short:   "Execute a command in a container.",
 | 
			
		||||
		Long:    "Execute a command in a container.",
 | 
			
		||||
		Example: exec_example,
 | 
			
		||||
		Run: func(cmd *cobra.Command, args []string) {
 | 
			
		||||
			if len(flags.pod) == 0 {
 | 
			
		||||
				usageError(cmd, "<pod> is required for exec")
 | 
			
		||||
			err := RunExec(f, cmdIn, cmdOut, cmdErr, cmd, args)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	cmd.Flags().StringP("pod", "p", "", "Pod name")
 | 
			
		||||
	// TODO support UID
 | 
			
		||||
	cmd.Flags().StringP("container", "c", "", "Container name")
 | 
			
		||||
	cmd.Flags().BoolP("stdin", "i", false, "Pass stdin to the container")
 | 
			
		||||
	cmd.Flags().BoolP("tty", "t", false, "Stdin is a TTY")
 | 
			
		||||
	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 {
 | 
			
		||||
				usageError(cmd, "<command> is required for exec")
 | 
			
		||||
		return util.UsageError(cmd, "<command> is required for exec")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	namespace, err := f.DefaultNamespace(cmd)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	client, err := f.Client(cmd)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
			pod, err := client.Pods(namespace).Get(flags.pod)
 | 
			
		||||
			util.CheckErr(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)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
			if len(flags.container) == 0 {
 | 
			
		||||
				flags.container = pod.Spec.Containers[0].Name
 | 
			
		||||
	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 flags.tty {
 | 
			
		||||
		if tty {
 | 
			
		||||
			if file, ok := cmdIn.(*os.File); ok {
 | 
			
		||||
				inFd := file.Fd()
 | 
			
		||||
				if term.IsTerminal(inFd) {
 | 
			
		||||
@@ -106,30 +121,23 @@ func (f *Factory) NewCmdExec(cmdIn io.Reader, cmdOut, cmdErr io.Writer) *cobra.C
 | 
			
		||||
					glog.Warning("Stdin is not a terminal")
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
						flags.tty = false
 | 
			
		||||
				tty = false
 | 
			
		||||
				glog.Warning("Unable to use a TTY")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	config, err := f.ClientConfig(cmd)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	req := client.RESTClient.Get().
 | 
			
		||||
		Prefix("proxy").
 | 
			
		||||
		Resource("minions").
 | 
			
		||||
		Name(pod.Status.Host).
 | 
			
		||||
				Suffix("exec", namespace, flags.pod, flags.container)
 | 
			
		||||
		Suffix("exec", namespace, podName, containerName)
 | 
			
		||||
 | 
			
		||||
			e := remotecommand.New(req, config, args, stdin, cmdOut, cmdErr, flags.tty)
 | 
			
		||||
			err = e.Execute()
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	cmd.Flags().StringVarP(&flags.pod, "pod", "p", "", "Pod name")
 | 
			
		||||
	// TODO support UID
 | 
			
		||||
	cmd.Flags().StringVarP(&flags.container, "container", "c", "", "Container name")
 | 
			
		||||
	cmd.Flags().BoolVarP(&flags.stdin, "stdin", "i", false, "Pass stdin to the container")
 | 
			
		||||
	cmd.Flags().BoolVarP(&flags.tty, "tty", "t", false, "Stdin is a TTY")
 | 
			
		||||
	return cmd
 | 
			
		||||
	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,
 | 
			
		||||
		Example: expose_example,
 | 
			
		||||
		Run: func(cmd *cobra.Command, args []string) {
 | 
			
		||||
			if len(args) != 1 {
 | 
			
		||||
				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)
 | 
			
		||||
			err := RunExpose(f, out, cmd, args)
 | 
			
		||||
			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.")
 | 
			
		||||
	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,
 | 
			
		||||
		Example: get_example,
 | 
			
		||||
		Run: func(cmd *cobra.Command, args []string) {
 | 
			
		||||
			RunGet(f, out, cmd, args)
 | 
			
		||||
			err := RunGet(f, out, cmd, args)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	util.AddPrinterFlags(cmd)
 | 
			
		||||
@@ -75,13 +76,14 @@ func (f *Factory) NewCmdGet(out io.Writer) *cobra.Command {
 | 
			
		||||
 | 
			
		||||
// RunGet implements the generic Get command
 | 
			
		||||
// 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) {
 | 
			
		||||
func RunGet(f *Factory, out io.Writer, cmd *cobra.Command, args []string) error {
 | 
			
		||||
	selector := util.GetFlagString(cmd, "selector")
 | 
			
		||||
	mapper, typer := f.Object(cmd)
 | 
			
		||||
 | 
			
		||||
	cmdNamespace, err := f.DefaultNamespace(cmd)
 | 
			
		||||
	util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// handle watch separately since we cannot watch multiple resource types
 | 
			
		||||
	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...).
 | 
			
		||||
			SingleResourceType().
 | 
			
		||||
			Do()
 | 
			
		||||
		util.CheckErr(r.Err())
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		mapping, err := r.ResourceMapping()
 | 
			
		||||
		util.CheckErr(err)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		printer, err := f.PrinterForMapping(cmd, mapping)
 | 
			
		||||
		util.CheckErr(err)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		obj, err := r.Object()
 | 
			
		||||
		util.CheckErr(err)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		rv, err := mapping.MetadataAccessor.ResourceVersion(obj)
 | 
			
		||||
		util.CheckErr(err)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// print the current object
 | 
			
		||||
		if !isWatchOnly {
 | 
			
		||||
			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
 | 
			
		||||
		w, err := r.Watch(rv)
 | 
			
		||||
		util.CheckErr(err)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		kubectl.WatchLoop(w, func(e watch.Event) error {
 | 
			
		||||
			return printer.PrintObj(e.Object, out)
 | 
			
		||||
		})
 | 
			
		||||
		return
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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...).
 | 
			
		||||
		Latest()
 | 
			
		||||
	printer, generic, err := util.PrinterForCommand(cmd)
 | 
			
		||||
	util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if generic {
 | 
			
		||||
		clientConfig, err := f.ClientConfig(cmd)
 | 
			
		||||
		util.CheckErr(err)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		defaultVersion := clientConfig.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()
 | 
			
		||||
		obj, err := r.Object()
 | 
			
		||||
		util.CheckErr(err)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// try conversion to all the possible versions
 | 
			
		||||
		// 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
 | 
			
		||||
		printer := kubectl.NewVersionedPrinter(printer, api.Scheme, versions...)
 | 
			
		||||
 | 
			
		||||
		err = printer.PrintObj(obj, out)
 | 
			
		||||
		util.CheckErr(err)
 | 
			
		||||
		return
 | 
			
		||||
		return printer.PrintObj(obj, out)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 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)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		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,
 | 
			
		||||
		Example: label_example,
 | 
			
		||||
		Run: func(cmd *cobra.Command, args []string) {
 | 
			
		||||
			if len(args) < 2 {
 | 
			
		||||
				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)
 | 
			
		||||
			err := RunLabel(f, out, cmd, args)
 | 
			
		||||
			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)
 | 
			
		||||
@@ -95,7 +65,7 @@ func (f *Factory) NewCmdLabel(out io.Writer) *cobra.Command {
 | 
			
		||||
	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)
 | 
			
		||||
 | 
			
		||||
	obj, err := helper.Get(namespace, name)
 | 
			
		||||
@@ -103,7 +73,10 @@ func updateObject(client resource.RESTClient, mapping *meta.RESTMapping, namespa
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	obj = updateFn(obj)
 | 
			
		||||
	obj, err = updateFn(obj)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data, err := helper.Codec.Encode(obj)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -177,3 +150,54 @@ func labelFunc(obj runtime.Object, overwrite bool, resourceVersion string, label
 | 
			
		||||
	}
 | 
			
		||||
	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 (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
 | 
			
		||||
@@ -65,36 +64,42 @@ 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.",
 | 
			
		||||
		Example: log_example,
 | 
			
		||||
		Run: func(cmd *cobra.Command, args []string) {
 | 
			
		||||
			err := RunLog(f, out, cmd, args)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	cmd.Flags().BoolP("follow", "f", false, "Specify if the logs should be streamed.")
 | 
			
		||||
	cmd.Flags().Bool("interactive", true, "If true, prompt the user for input when required. Default true.")
 | 
			
		||||
	return cmd
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunLog(f *Factory, out io.Writer, cmd *cobra.Command, args []string) error {
 | 
			
		||||
	if len(args) == 0 {
 | 
			
		||||
				usageError(cmd, "<pod> is required for log")
 | 
			
		||||
		return util.UsageError(cmd, "<pod> is required for log")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(args) > 2 {
 | 
			
		||||
				usageError(cmd, "log <pod> [<container>]")
 | 
			
		||||
		return util.UsageError(cmd, "log <pod> [<container>]")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	namespace, err := f.DefaultNamespace(cmd)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	client, err := f.Client(cmd)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	podID := args[0]
 | 
			
		||||
 | 
			
		||||
	pod, err := client.Pods(namespace).Get(podID)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 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]
 | 
			
		||||
	}
 | 
			
		||||
@@ -111,14 +116,11 @@ func (f *Factory) NewCmdLog(out io.Writer) *cobra.Command {
 | 
			
		||||
		Suffix("containerLogs", namespace, podID, container).
 | 
			
		||||
		Param("follow", strconv.FormatBool(follow)).
 | 
			
		||||
		Stream()
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer readCloser.Close()
 | 
			
		||||
	_, err = io.Copy(out, readCloser)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	cmd.Flags().BoolP("follow", "f", false, "Specify if the logs should be streamed.")
 | 
			
		||||
	cmd.Flags().Bool("interactive", true, "If true, prompt the user for input when required. Default true.")
 | 
			
		||||
	return cmd
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,10 +17,10 @@ limitations under the License.
 | 
			
		||||
package cmd
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"github.com/golang/glog"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd/util"
 | 
			
		||||
	"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.
 | 
			
		||||
`,
 | 
			
		||||
		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.")
 | 
			
		||||
			os.Exit(1)
 | 
			
		||||
			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."))
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	return cmd
 | 
			
		||||
 
 | 
			
		||||
@@ -42,40 +42,54 @@ $ kubectl port-forward -p mypod 0:5000
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (f *Factory) NewCmdPortForward() *cobra.Command {
 | 
			
		||||
	flags := &struct {
 | 
			
		||||
		pod       string
 | 
			
		||||
		container string
 | 
			
		||||
	}{}
 | 
			
		||||
 | 
			
		||||
	cmd := &cobra.Command{
 | 
			
		||||
		Use:     "port-forward -p <pod> [<local port>:]<remote port> [<port>...]",
 | 
			
		||||
		Short:   "Forward 1 or more local ports to a pod.",
 | 
			
		||||
		Long:    "Forward 1 or more local ports to a pod.",
 | 
			
		||||
		Example: portforward_example,
 | 
			
		||||
		Run: func(cmd *cobra.Command, args []string) {
 | 
			
		||||
			if len(flags.pod) == 0 {
 | 
			
		||||
				usageError(cmd, "<pod> is required for exec")
 | 
			
		||||
			err := RunPortForward(f, cmd, args)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	cmd.Flags().StringP("pod", "p", "", "Pod name")
 | 
			
		||||
	// TODO support UID
 | 
			
		||||
	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 {
 | 
			
		||||
				usageError(cmd, "at least 1 <port> is required for port-forward")
 | 
			
		||||
		return util.UsageError(cmd, "at least 1 <port> is required for port-forward")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	namespace, err := f.DefaultNamespace(cmd)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	client, err := f.Client(cmd)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
			pod, err := client.Pods(namespace).Get(flags.pod)
 | 
			
		||||
			util.CheckErr(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)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	signals := make(chan os.Signal, 1)
 | 
			
		||||
	signal.Notify(signals, os.Interrupt)
 | 
			
		||||
@@ -91,16 +105,12 @@ func (f *Factory) NewCmdPortForward() *cobra.Command {
 | 
			
		||||
		Prefix("proxy").
 | 
			
		||||
		Resource("minions").
 | 
			
		||||
		Name(pod.Status.Host).
 | 
			
		||||
				Suffix("portForward", namespace, flags.pod)
 | 
			
		||||
		Suffix("portForward", namespace, podName)
 | 
			
		||||
 | 
			
		||||
	pf, err := portforward.New(req, config, args, stopCh)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
 | 
			
		||||
			err = pf.ForwardPorts()
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
		},
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	cmd.Flags().StringVarP(&flags.pod, "pod", "p", "", "Pod name")
 | 
			
		||||
	// TODO support UID
 | 
			
		||||
	return cmd
 | 
			
		||||
 | 
			
		||||
	return pf.ForwardPorts()
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@ limitations under the License.
 | 
			
		||||
package cmd
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
@@ -32,11 +33,25 @@ func (f *Factory) NewCmdProxy(out io.Writer) *cobra.Command {
 | 
			
		||||
		Short: "Run a proxy to the Kubernetes API server",
 | 
			
		||||
		Long:  `Run a proxy to the Kubernetes API server.`,
 | 
			
		||||
		Run: func(cmd *cobra.Command, args []string) {
 | 
			
		||||
			err := RunProxy(f, out, cmd)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	cmd.Flags().StringP("www", "w", "", "Also serve static files from the given directory under the specified prefix.")
 | 
			
		||||
	cmd.Flags().StringP("www-prefix", "P", "/static/", "Prefix to serve static files under, if static file directory is specified.")
 | 
			
		||||
	cmd.Flags().StringP("api-prefix", "", "/api/", "Prefix to serve the proxied API under.")
 | 
			
		||||
	cmd.Flags().IntP("port", "p", 8001, "The port on which to run the proxy.")
 | 
			
		||||
	return cmd
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunProxy(f *Factory, out io.Writer, cmd *cobra.Command) error {
 | 
			
		||||
	port := util.GetFlagInt(cmd, "port")
 | 
			
		||||
			glog.Infof("Starting to serve on localhost:%d", port)
 | 
			
		||||
	fmt.Fprintf(out, "Starting to serve on localhost:%d", port)
 | 
			
		||||
 | 
			
		||||
	clientConfig, err := f.ClientConfig(cmd)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	staticPrefix := util.GetFlagString(cmd, "www-prefix")
 | 
			
		||||
	if !strings.HasSuffix(staticPrefix, "/") {
 | 
			
		||||
@@ -48,14 +63,10 @@ func (f *Factory) NewCmdProxy(out io.Writer) *cobra.Command {
 | 
			
		||||
		apiProxyPrefix += "/"
 | 
			
		||||
	}
 | 
			
		||||
	server, err := kubectl.NewProxyServer(util.GetFlagString(cmd, "www"), apiProxyPrefix, staticPrefix, clientConfig)
 | 
			
		||||
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
			glog.Fatal(server.Serve(port))
 | 
			
		||||
		},
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	cmd.Flags().StringP("www", "w", "", "Also serve static files from the given directory under the specified prefix.")
 | 
			
		||||
	cmd.Flags().StringP("www-prefix", "P", "/static/", "Prefix to serve static files under, if static file directory is specified.")
 | 
			
		||||
	cmd.Flags().StringP("api-prefix", "", "/api/", "Prefix to serve the proxied API under.")
 | 
			
		||||
	cmd.Flags().IntP("port", "p", 8001, "The port on which to run the proxy.")
 | 
			
		||||
	return cmd
 | 
			
		||||
 | 
			
		||||
	glog.Fatal(server.Serve(port))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -52,20 +52,38 @@ func (f *Factory) NewCmdResize(out io.Writer) *cobra.Command {
 | 
			
		||||
		Long:    resize_long,
 | 
			
		||||
		Example: resize_example,
 | 
			
		||||
		Run: func(cmd *cobra.Command, args []string) {
 | 
			
		||||
			err := RunResize(f, out, cmd, args)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	cmd.Flags().String("resource-version", "", "Precondition for resource version. Requires that the current resource version match this value in order to resize.")
 | 
			
		||||
	cmd.Flags().Int("current-replicas", -1, "Precondition for current size. Requires that the current size of the replication controller match this value in order to resize.")
 | 
			
		||||
	cmd.Flags().Int("replicas", -1, "The new desired number of replicas. Required.")
 | 
			
		||||
	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 {
 | 
			
		||||
				usageError(cmd, "--replicas=<count> <resource> <id>")
 | 
			
		||||
		return util.UsageError(cmd, "--replicas=<count> <resource> <id>")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmdNamespace, err := f.DefaultNamespace(cmd)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mapper, _ := f.Object(cmd)
 | 
			
		||||
	// TODO: use resource.Builder instead
 | 
			
		||||
			mapping, namespace, name := util.ResourceFromArgs(cmd, args, mapper, cmdNamespace)
 | 
			
		||||
	mapping, namespace, name, err := util.ResourceFromArgs(cmd, args, mapper, cmdNamespace)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resizer, err := f.Resizer(cmd, mapping)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resourceVersion := util.GetFlagString(cmd, "resource-version")
 | 
			
		||||
	currentSize := util.GetFlagInt(cmd, "current-replicas")
 | 
			
		||||
@@ -75,13 +93,10 @@ func (f *Factory) NewCmdResize(out io.Writer) *cobra.Command {
 | 
			
		||||
	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)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 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().Int("current-replicas", -1, "Precondition for current size. Requires that the current size of the replication controller match this value in order to resize.")
 | 
			
		||||
	cmd.Flags().Int("replicas", -1, "The new desired number of replicas. Required.")
 | 
			
		||||
	return cmd
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -49,53 +49,82 @@ func (f *Factory) NewCmdRollingUpdate(out io.Writer) *cobra.Command {
 | 
			
		||||
		Long:    rollingupdate_long,
 | 
			
		||||
		Example: rollingupdate_example,
 | 
			
		||||
		Run: func(cmd *cobra.Command, args []string) {
 | 
			
		||||
			err := RunRollingUpdate(f, out, cmd, args)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	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("poll-interval", pollInterval, `Time delay between polling controller status after update. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".`)
 | 
			
		||||
	cmd.Flags().String("timeout", timeout, `Max time to wait for a controller to update before giving up. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".`)
 | 
			
		||||
	cmd.Flags().StringP("filename", "f", "", "Filename or URL to file to use to create the new controller.")
 | 
			
		||||
	return cmd
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunRollingUpdate(f *Factory, out io.Writer, cmd *cobra.Command, args []string) error {
 | 
			
		||||
	filename := util.GetFlagString(cmd, "filename")
 | 
			
		||||
	if len(filename) == 0 {
 | 
			
		||||
				usageError(cmd, "Must specify filename for new controller")
 | 
			
		||||
		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 {
 | 
			
		||||
				usageError(cmd, "Must specify the controller to update")
 | 
			
		||||
		return util.UsageError(cmd, "Must specify the controller to update")
 | 
			
		||||
	}
 | 
			
		||||
	oldName := args[0]
 | 
			
		||||
	schema, err := f.Validator(cmd)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	clientConfig, err := f.ClientConfig(cmd)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 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)
 | 
			
		||||
	mapping, namespace, newName, data, err := util.ResourceFromFile(filename, typer, mapper, schema, cmdApiVersion)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if mapping.Kind != "ReplicationController" {
 | 
			
		||||
				usageError(cmd, "%s does not specify a valid ReplicationController", filename)
 | 
			
		||||
		return util.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",
 | 
			
		||||
		return util.UsageError(cmd, "%s cannot have the same name as the existing ReplicationController %s",
 | 
			
		||||
			filename, oldName)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmdNamespace, err := f.DefaultNamespace(cmd)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	// TODO: use resource.Builder instead
 | 
			
		||||
	err = util.CompareNamespace(cmdNamespace, namespace)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	client, err := f.Client(cmd)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	obj, err := mapping.Codec.Decode(data)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	newRc := obj.(*api.ReplicationController)
 | 
			
		||||
 | 
			
		||||
	updater := kubectl.NewRollingUpdater(cmdNamespace, client)
 | 
			
		||||
 | 
			
		||||
	// fetch rc
 | 
			
		||||
	oldRc, err := client.ReplicationControllers(cmdNamespace).Get(oldName)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var hasLabel bool
 | 
			
		||||
	for key, oldValue := range oldRc.Spec.Selector {
 | 
			
		||||
@@ -105,7 +134,7 @@ func (f *Factory) NewCmdRollingUpdate(out io.Writer) *cobra.Command {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if !hasLabel {
 | 
			
		||||
				usageError(cmd, "%s must specify a matching key with non-equal value in Selector for %s",
 | 
			
		||||
		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
 | 
			
		||||
@@ -113,14 +142,10 @@ func (f *Factory) NewCmdRollingUpdate(out io.Writer) *cobra.Command {
 | 
			
		||||
		newRc.Spec.Replicas = oldRc.Spec.Replicas
 | 
			
		||||
	}
 | 
			
		||||
	err = updater.Update(out, oldRc, newRc, period, interval, timeout)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 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("poll-interval", pollInterval, `Time delay between polling controller status after update. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".`)
 | 
			
		||||
	cmd.Flags().String("timeout", timeout, `Max time to wait for a controller to update before giving up. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".`)
 | 
			
		||||
	cmd.Flags().StringP("filename", "f", "", "Filename or URL to file to use to create the new controller.")
 | 
			
		||||
	return cmd
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -49,44 +49,7 @@ func (f *Factory) NewCmdRunContainer(out io.Writer) *cobra.Command {
 | 
			
		||||
		Long:    run_long,
 | 
			
		||||
		Example: run_example,
 | 
			
		||||
		Run: func(cmd *cobra.Command, args []string) {
 | 
			
		||||
			if len(args) != 1 {
 | 
			
		||||
				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)
 | 
			
		||||
			err := RunRunContainer(f, out, cmd, args)
 | 
			
		||||
			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.")
 | 
			
		||||
	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,46 +41,64 @@ $ kubectl update pods my-pod --patch='{ "apiVersion": "v1beta1", "desiredState":
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (f *Factory) NewCmdUpdate(out io.Writer) *cobra.Command {
 | 
			
		||||
	flags := &struct {
 | 
			
		||||
		Filenames util.StringList
 | 
			
		||||
	}{}
 | 
			
		||||
	var filenames util.StringList
 | 
			
		||||
	cmd := &cobra.Command{
 | 
			
		||||
		Use:     "update -f filename",
 | 
			
		||||
		Short:   "Update a resource by filename or stdin.",
 | 
			
		||||
		Long:    update_long,
 | 
			
		||||
		Example: update_example,
 | 
			
		||||
		Run: func(cmd *cobra.Command, args []string) {
 | 
			
		||||
			schema, err := f.Validator(cmd)
 | 
			
		||||
			err := RunUpdate(f, out, cmd, args, filenames)
 | 
			
		||||
			cmdutil.CheckErr(err)
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	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.")
 | 
			
		||||
	return cmd
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
			cmdutil.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 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(filenames) == 0 && len(patch) == 0 {
 | 
			
		||||
		return cmdutil.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")
 | 
			
		||||
	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(flags.Filenames) == 0 {
 | 
			
		||||
				name := updateWithPatch(cmd, args, f, patch)
 | 
			
		||||
	if len(filenames) == 0 {
 | 
			
		||||
		name, err := updateWithPatch(cmd, args, f, patch)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Fprintf(out, "%s\n", name)
 | 
			
		||||
				return
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mapper, typer := f.Object(cmd)
 | 
			
		||||
	r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand(cmd)).
 | 
			
		||||
		ContinueOnError().
 | 
			
		||||
		NamespaceParam(cmdNamespace).RequireNamespace().
 | 
			
		||||
				FilenameParam(flags.Filenames...).
 | 
			
		||||
		FilenameParam(filenames...).
 | 
			
		||||
		Flatten().
 | 
			
		||||
		Do()
 | 
			
		||||
			cmdutil.CheckErr(r.Err())
 | 
			
		||||
	err = r.Err()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
			err = r.Visit(func(info *resource.Info) error {
 | 
			
		||||
	return r.Visit(func(info *resource.Info) error {
 | 
			
		||||
		data, err := info.Mapping.Codec.Encode(info.Object)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
@@ -96,36 +114,42 @@ func (f *Factory) NewCmdUpdate(out io.Writer) *cobra.Command {
 | 
			
		||||
		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().String("patch", "", "A JSON document to override the existing resource. The resource is downloaded, patched with the JSON, then updated.")
 | 
			
		||||
	return cmd
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func updateWithPatch(cmd *cobra.Command, args []string, f *Factory, patch string) string {
 | 
			
		||||
func updateWithPatch(cmd *cobra.Command, args []string, f *Factory, patch string) (string, error) {
 | 
			
		||||
	cmdNamespace, err := f.DefaultNamespace(cmd)
 | 
			
		||||
	cmdutil.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mapper, _ := f.Object(cmd)
 | 
			
		||||
	// 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)
 | 
			
		||||
	cmdutil.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	helper := resource.NewHelper(client, mapping)
 | 
			
		||||
	obj, err := helper.Get(namespace, name)
 | 
			
		||||
	cmdutil.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	patchedObj, err := cmdutil.Merge(obj, patch, mapping.Kind)
 | 
			
		||||
	cmdutil.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data, err := helper.Codec.Encode(patchedObj)
 | 
			
		||||
	cmdutil.CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = helper.Update(namespace, name, true, data)
 | 
			
		||||
	cmdutil.CheckErr(err)
 | 
			
		||||
	return name
 | 
			
		||||
	return name, err
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -31,10 +31,11 @@ import (
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
 | 
			
		||||
 | 
			
		||||
	"github.com/evanphx/json-patch"
 | 
			
		||||
 | 
			
		||||
	"github.com/golang/glog"
 | 
			
		||||
	"github.com/spf13/cobra"
 | 
			
		||||
	"github.com/spf13/pflag"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func CheckErr(err error) {
 | 
			
		||||
@@ -52,25 +53,26 @@ func CheckErr(err error) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 UsageError(cmd *cobra.Command, format string, args ...interface{}) error {
 | 
			
		||||
	msg := fmt.Sprintf(format, args...)
 | 
			
		||||
	return fmt.Errorf("%s\nsee '%s -h' for help.", msg, cmd.CommandPath())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 {
 | 
			
		||||
	f := cmd.Flags().Lookup(flag)
 | 
			
		||||
	if f == nil {
 | 
			
		||||
		glog.Fatalf("Flag accessed but not defined for command %s: %s", cmd.Name(), flag)
 | 
			
		||||
	}
 | 
			
		||||
	f := getFlag(cmd, flag)
 | 
			
		||||
	return f.Value.String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetFlagBool(cmd *cobra.Command, flag string) bool {
 | 
			
		||||
	f := cmd.Flags().Lookup(flag)
 | 
			
		||||
	if f == nil {
 | 
			
		||||
		glog.Fatalf("Flag accessed but not defined for command %s: %s", cmd.Name(), flag)
 | 
			
		||||
	}
 | 
			
		||||
	f := getFlag(cmd, flag)
 | 
			
		||||
	result, err := strconv.ParseBool(f.Value.String())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		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.
 | 
			
		||||
func GetFlagInt(cmd *cobra.Command, flag string) int {
 | 
			
		||||
	f := cmd.Flags().Lookup(flag)
 | 
			
		||||
	if f == nil {
 | 
			
		||||
		glog.Fatalf("Flag accessed but not defined for command %s: %s", cmd.Name(), flag)
 | 
			
		||||
	}
 | 
			
		||||
	f := getFlag(cmd, flag)
 | 
			
		||||
	v, err := strconv.Atoi(f.Value.String())
 | 
			
		||||
	// This is likely not a sufficiently friendly error message, but cobra
 | 
			
		||||
	// 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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetFlagDuration(cmd *cobra.Command, flag string) time.Duration {
 | 
			
		||||
	f := cmd.Flags().Lookup(flag)
 | 
			
		||||
	if f == nil {
 | 
			
		||||
		glog.Fatalf("Flag accessed but not defined for command %s: %s", cmd.Name(), flag)
 | 
			
		||||
	}
 | 
			
		||||
	f := getFlag(cmd, flag)
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -27,26 +27,29 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 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.
 | 
			
		||||
// 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 {
 | 
			
		||||
		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]
 | 
			
		||||
	namespace = cmdNamespace
 | 
			
		||||
	name = args[1]
 | 
			
		||||
	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)
 | 
			
		||||
	CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mapping, err = mapper.RESTMapping(kind, version)
 | 
			
		||||
	CheckErr(err)
 | 
			
		||||
	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
 | 
			
		||||
// the correct REST endpoint to modify this resource with.
 | 
			
		||||
// 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) {
 | 
			
		||||
	configData, err := ReadConfigData(filename)
 | 
			
		||||
	CheckErr(err)
 | 
			
		||||
	data = configData
 | 
			
		||||
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) {
 | 
			
		||||
	data, err = ReadConfigData(filename)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	objVersion, kind, err := typer.DataVersionAndKind(data)
 | 
			
		||||
	CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: allow unversioned objects?
 | 
			
		||||
	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)
 | 
			
		||||
	CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// decode using the version stored with the object (allows codec to vary across versions)
 | 
			
		||||
	mapping, err = mapper.RESTMapping(kind, objVersion)
 | 
			
		||||
	CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	obj, err := mapping.Codec.Decode(data)
 | 
			
		||||
	CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	meta := mapping.MetadataAccessor
 | 
			
		||||
	namespace, err = meta.Namespace(obj)
 | 
			
		||||
	CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	name, err = meta.Name(obj)
 | 
			
		||||
	CheckErr(err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// if the preferred API version differs, get a different mapper
 | 
			
		||||
	if cmdVersion != objVersion {
 | 
			
		||||
		mapping, err = mapper.RESTMapping(kind, cmdVersion)
 | 
			
		||||
		CheckErr(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -30,17 +30,25 @@ func (f *Factory) NewCmdVersion(out io.Writer) *cobra.Command {
 | 
			
		||||
		Use:   "version",
 | 
			
		||||
		Short: "Print the client and server version information.",
 | 
			
		||||
		Run: func(cmd *cobra.Command, args []string) {
 | 
			
		||||
			if util.GetFlagBool(cmd, "client") {
 | 
			
		||||
				kubectl.GetClientVersion(out)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			client, err := f.Client(cmd)
 | 
			
		||||
			err := RunVersion(f, out, cmd)
 | 
			
		||||
			util.CheckErr(err)
 | 
			
		||||
 | 
			
		||||
			kubectl.GetVersion(out, client)
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	cmd.Flags().BoolP("client", "c", false, "Client version only (no server required).")
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user