mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 12:15:52 +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",
|
||||
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,54 +39,67 @@ $ 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)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
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)
|
||||
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().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(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
|
||||
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,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 {
|
||||
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")
|
||||
}
|
||||
|
||||
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()
|
||||
err := RunExec(f, cmdIn, cmdOut, cmdErr, cmd, args)
|
||||
util.CheckErr(err)
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringVarP(&flags.pod, "pod", "p", "", "Pod name")
|
||||
cmd.Flags().StringP("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")
|
||||
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 {
|
||||
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,
|
||||
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,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.",
|
||||
Example: log_example,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) == 0 {
|
||||
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)
|
||||
err := RunLog(f, out, cmd, args)
|
||||
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.")
|
||||
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
|
||||
|
||||
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,65 +42,75 @@ $ 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")
|
||||
}
|
||||
|
||||
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()
|
||||
err := RunPortForward(f, cmd, args)
|
||||
util.CheckErr(err)
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringVarP(&flags.pod, "pod", "p", "", "Pod name")
|
||||
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 {
|
||||
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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
@ -32,25 +33,8 @@ 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) {
|
||||
port := util.GetFlagInt(cmd, "port")
|
||||
glog.Infof("Starting to serve on localhost:%d", port)
|
||||
|
||||
clientConfig, err := f.ClientConfig(cmd)
|
||||
err := RunProxy(f, out, cmd)
|
||||
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.")
|
||||
@ -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.")
|
||||
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,
|
||||
Example: resize_example,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
count := util.GetFlagInt(cmd, "replicas")
|
||||
if len(args) != 2 || count < 0 {
|
||||
usageError(cmd, "--replicas=<count> <resource> <id>")
|
||||
}
|
||||
|
||||
cmdNamespace, err := f.DefaultNamespace(cmd)
|
||||
err := RunResize(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)
|
||||
|
||||
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.")
|
||||
@ -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.")
|
||||
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,
|
||||
Example: rollingupdate_example,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
filename := util.GetFlagString(cmd, "filename")
|
||||
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)
|
||||
err := RunRollingUpdate(f, out, cmd, args)
|
||||
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".`)
|
||||
@ -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.")
|
||||
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,
|
||||
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,91 +41,115 @@ $ 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)
|
||||
|
||||
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.")
|
||||
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)
|
||||
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)
|
||||
// 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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user