Exemplo n.º 1
0
// Complete verifies command line arguments and loads data from the command environment
func (p *AttachOptions) Complete(f *cmdutil.Factory, cmd *cobra.Command, argsIn []string) error {
	if len(argsIn) == 0 {
		return cmdutil.UsageError(cmd, "POD is required for attach")
	}
	if len(argsIn) > 1 {
		return cmdutil.UsageError(cmd, fmt.Sprintf("expected a single argument: POD, saw %d: %s", len(argsIn), argsIn))
	}
	p.PodName = argsIn[0]

	namespace, _, err := f.DefaultNamespace()
	if err != nil {
		return err
	}
	p.Namespace = namespace

	config, err := f.ClientConfig()
	if err != nil {
		return err
	}
	p.Config = config

	client, err := f.Client()
	if err != nil {
		return err
	}
	p.Client = client

	return nil
}
Exemplo n.º 2
0
func RunPortForward(f *cmdutil.Factory, cmd *cobra.Command, args []string, fw portForwarder) error {
	podName := cmdutil.GetFlagString(cmd, "pod")
	if len(podName) == 0 && len(args) == 0 {
		return cmdutil.UsageError(cmd, "POD is required for port-forward")
	}

	if len(podName) != 0 {
		printDeprecationWarning("port-forward POD", "-p POD")
	} else {
		podName = args[0]
		args = args[1:]
	}

	if len(args) < 1 {
		return cmdutil.UsageError(cmd, "at least 1 PORT is required for port-forward")
	}

	namespace, _, err := f.DefaultNamespace()
	if err != nil {
		return err
	}

	client, err := f.Client()
	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()
	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.Post().
		Resource("pods").
		Namespace(namespace).
		Name(pod.Name).
		SubResource("portforward")

	return fw.ForwardPorts("POST", req.URL(), config, args, stopCh)
}
Exemplo n.º 3
0
func RunClusterInfo(factory *cmdutil.Factory, out io.Writer, cmd *cobra.Command) error {
	if len(os.Args) > 1 && os.Args[1] == "clusterinfo" {
		printDeprecationWarning("cluster-info", "clusterinfo")
	}

	client, err := factory.ClientConfig()
	if err != nil {
		return err
	}
	printService(out, "Kubernetes master", client.Host)

	mapper, typer := factory.Object()
	cmdNamespace := cmdutil.GetFlagString(cmd, "namespace")
	if cmdNamespace == "" {
		cmdNamespace = api.NamespaceSystem
	}

	// TODO use generalized labels once they are implemented (#341)
	b := resource.NewBuilder(mapper, typer, factory.ClientMapperForCommand()).
		NamespaceParam(cmdNamespace).DefaultNamespace().
		SelectorParam("kubernetes.io/cluster-service=true").
		ResourceTypeOrNameArgs(false, []string{"services"}...).
		Latest()
	b.Do().Visit(func(r *resource.Info, err error) error {
		if err != nil {
			return err
		}
		services := r.Object.(*api.ServiceList).Items
		for _, service := range services {
			var link string
			if len(service.Status.LoadBalancer.Ingress) > 0 {
				ingress := service.Status.LoadBalancer.Ingress[0]
				ip := ingress.IP
				if ip == "" {
					ip = ingress.Hostname
				}
				for _, port := range service.Spec.Ports {
					link += "http://" + ip + ":" + strconv.Itoa(port.Port) + " "
				}
			} else {
				link = client.Host + "/api/" + client.Version + "/proxy/namespaces/" + service.ObjectMeta.Namespace + "/services/" + service.ObjectMeta.Name
			}
			name := service.ObjectMeta.Labels["kubernetes.io/name"]
			if len(name) == 0 {
				name = service.ObjectMeta.Name
			}
			printService(out, name, link)
		}
		return nil
	})
	return nil

	// TODO consider printing more information about cluster
}
Exemplo n.º 4
0
func RunProxy(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command) error {
	path := cmdutil.GetFlagString(cmd, "unix-socket")
	port := cmdutil.GetFlagInt(cmd, "port")
	address := cmdutil.GetFlagString(cmd, "address")

	if port != default_port && path != "" {
		return errors.New("Don't specify both --unix-socket and --port")
	}

	clientConfig, err := f.ClientConfig()
	if err != nil {
		return err
	}

	staticPrefix := cmdutil.GetFlagString(cmd, "www-prefix")
	if !strings.HasSuffix(staticPrefix, "/") {
		staticPrefix += "/"
	}

	apiProxyPrefix := cmdutil.GetFlagString(cmd, "api-prefix")
	if !strings.HasSuffix(apiProxyPrefix, "/") {
		apiProxyPrefix += "/"
	}
	filter := &kubectl.FilterServer{
		AcceptPaths: kubectl.MakeRegexpArrayOrDie(cmdutil.GetFlagString(cmd, "accept-paths")),
		RejectPaths: kubectl.MakeRegexpArrayOrDie(cmdutil.GetFlagString(cmd, "reject-paths")),
		AcceptHosts: kubectl.MakeRegexpArrayOrDie(cmdutil.GetFlagString(cmd, "accept-hosts")),
	}
	if cmdutil.GetFlagBool(cmd, "disable-filter") {
		if path == "" {
			glog.Warning("Request filter disabled, your proxy is vulnerable to XSRF attacks, please be cautious")
		}
		filter = nil
	}

	server, err := kubectl.NewProxyServer(cmdutil.GetFlagString(cmd, "www"), apiProxyPrefix, staticPrefix, filter, clientConfig)

	// Separate listening from serving so we can report the bound port
	// when it is chosen by os (eg: port == 0)
	var l net.Listener
	if path == "" {
		l, err = server.Listen(address, port)
	} else {
		l, err = server.ListenUnix(path)
	}
	if err != nil {
		glog.Fatal(err)
	}
	fmt.Fprintf(out, "Starting to serve on %s", l.Addr().String())
	glog.Fatal(server.ServeOnListener(l))
	return nil
}
Exemplo n.º 5
0
// Complete verifies command line arguments and loads data from the command environment
func (p *ExecOptions) Complete(f *cmdutil.Factory, cmd *cobra.Command, argsIn []string, argsLenAtDash int) error {
	// Let kubectl exec follow rules for `--`, see #13004 issue
	if len(p.PodName) == 0 && (len(argsIn) == 0 || argsLenAtDash == 0) {
		return cmdutil.UsageError(cmd, "POD is required for exec")
	}
	if len(p.PodName) != 0 {
		printDeprecationWarning("exec POD", "-p POD")
		if len(argsIn) < 1 {
			return cmdutil.UsageError(cmd, "COMMAND is required for exec")
		}
		p.Command = argsIn
	} else {
		p.PodName = argsIn[0]
		p.Command = argsIn[1:]
		if len(p.Command) < 1 {
			return cmdutil.UsageError(cmd, "COMMAND is required for exec")
		}
	}

	namespace, _, err := f.DefaultNamespace()
	if err != nil {
		return err
	}
	p.Namespace = namespace

	config, err := f.ClientConfig()
	if err != nil {
		return err
	}
	p.Config = config

	client, err := f.Client()
	if err != nil {
		return err
	}
	p.Client = client

	return nil
}
Exemplo n.º 6
0
// Complete verifies command line arguments and loads data from the command environment
func (p *ExecOptions) Complete(f *cmdutil.Factory, cmd *cobra.Command, argsIn []string) error {
	if len(p.PodName) == 0 && len(argsIn) == 0 {
		return cmdutil.UsageError(cmd, "POD is required for exec")
	}
	if len(p.PodName) != 0 {
		printDeprecationWarning("exec POD", "-p POD")
		if len(argsIn) < 1 {
			return cmdutil.UsageError(cmd, "COMMAND is required for exec")
		}
		p.Command = argsIn
	} else {
		p.PodName = argsIn[0]
		p.Command = argsIn[1:]
		if len(p.Command) < 1 {
			return cmdutil.UsageError(cmd, "COMMAND is required for exec")
		}
	}

	namespace, _, err := f.DefaultNamespace()
	if err != nil {
		return err
	}
	p.Namespace = namespace

	config, err := f.ClientConfig()
	if err != nil {
		return err
	}
	p.Config = config

	client, err := f.Client()
	if err != nil {
		return err
	}
	p.Client = client

	return nil
}
Exemplo n.º 7
0
func Run(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cobra.Command, args []string) error {
	if len(os.Args) > 1 && os.Args[1] == "run-container" {
		printDeprecationWarning("run", "run-container")
	}

	if len(args) == 0 {
		return cmdutil.UsageError(cmd, "NAME is required for run")
	}

	interactive := cmdutil.GetFlagBool(cmd, "stdin")
	tty := cmdutil.GetFlagBool(cmd, "tty")
	if tty && !interactive {
		return cmdutil.UsageError(cmd, "-i/--stdin is required for containers with --tty=true")
	}
	replicas := cmdutil.GetFlagInt(cmd, "replicas")
	if interactive && replicas != 1 {
		return cmdutil.UsageError(cmd, fmt.Sprintf("-i/--stdin requires that replicas is 1, found %d", replicas))
	}

	namespace, _, err := f.DefaultNamespace()
	if err != nil {
		return err
	}

	restartPolicy, err := getRestartPolicy(cmd, interactive)
	if err != nil {
		return err
	}
	if restartPolicy != api.RestartPolicyAlways && replicas != 1 {
		return cmdutil.UsageError(cmd, fmt.Sprintf("--restart=%s requires that --replicas=1, found %d", restartPolicy, replicas))
	}

	generatorName := cmdutil.GetFlagString(cmd, "generator")
	if len(generatorName) == 0 {
		if restartPolicy == api.RestartPolicyAlways {
			generatorName = "run/v1"
		} else {
			generatorName = "run-pod/v1"
		}
	}
	generator, found := f.Generator(generatorName)
	if !found {
		return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not found.", generatorName))
	}
	names := generator.ParamNames()
	params := kubectl.MakeParams(cmd, names)
	params["name"] = args[0]
	if len(args) > 1 {
		params["args"] = args[1:]
	}

	params["env"] = cmdutil.GetFlagStringSlice(cmd, "env")

	if cmdutil.GetFlagBool(cmd, "expose") {
		serviceGenerator := cmdutil.GetFlagString(cmd, "service-generator")
		if len(serviceGenerator) == 0 {
			return cmdutil.UsageError(cmd, fmt.Sprintf("No service generator specified"))
		}
		if err := generateService(f, cmd, args, serviceGenerator, params, namespace, cmdOut); err != nil {
			return err
		}
	}

	obj, _, mapper, mapping, err := createGeneratedObject(f, cmd, generator, names, params, cmdutil.GetFlagString(cmd, "overrides"), namespace)
	if err != nil {
		return err
	}
	attachFlag := cmd.Flags().Lookup("attach")
	attach := cmdutil.GetFlagBool(cmd, "attach")

	if !attachFlag.Changed && interactive {
		attach = true
	}

	if attach {
		opts := &AttachOptions{
			In:    cmdIn,
			Out:   cmdOut,
			Err:   cmdErr,
			Stdin: interactive,
			TTY:   tty,

			Attach: &DefaultRemoteAttach{},
		}
		config, err := f.ClientConfig()
		if err != nil {
			return err
		}
		opts.Config = config

		client, err := f.Client()
		if err != nil {
			return err
		}
		opts.Client = client

		attachablePod, err := f.AttachablePodForObject(obj)
		if err != nil {
			return err
		}
		return handleAttachPod(client, attachablePod, opts)
	}

	outputFormat := cmdutil.GetFlagString(cmd, "output")
	if outputFormat != "" {
		return f.PrintObject(cmd, obj, cmdOut)
	}
	cmdutil.PrintSuccess(mapper, false, cmdOut, mapping.Resource, args[0], "created")
	return nil
}
Exemplo n.º 8
0
// RunGet implements the generic Get command
// TODO: convert all direct flag accessors to a struct and pass that instead of cmd
func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, options *GetOptions) error {
	selector := cmdutil.GetFlagString(cmd, "selector")
	allNamespaces := cmdutil.GetFlagBool(cmd, "all-namespaces")
	mapper, typer := f.Object()

	cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
	if err != nil {
		return err
	}

	if len(args) == 0 && len(options.Filenames) == 0 {
		fmt.Fprint(out, "You must specify the type of resource to get. ", valid_resources, `   * componentstatuses (aka 'cs')
   * endpoints (aka 'ep')
`)
		return cmdutil.UsageError(cmd, "Required resource not specified.")
	}

	// handle watch separately since we cannot watch multiple resource types
	isWatch, isWatchOnly := cmdutil.GetFlagBool(cmd, "watch"), cmdutil.GetFlagBool(cmd, "watch-only")
	if isWatch || isWatchOnly {
		r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
			NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
			FilenameParam(enforceNamespace, options.Filenames...).
			SelectorParam(selector).
			ResourceTypeOrNameArgs(true, args...).
			SingleResourceType().
			Latest().
			Do()
		err := r.Err()
		if err != nil {
			return err
		}
		infos, err := r.Infos()
		if err != nil {
			return err
		}
		if len(infos) != 1 {
			return fmt.Errorf("watch is only supported on individual resources and resource collections - %d resources were found", len(infos))
		}
		info := infos[0]
		mapping := info.ResourceMapping()
		printer, err := f.PrinterForMapping(cmd, mapping, allNamespaces)
		if err != nil {
			return err
		}

		obj, err := r.Object()
		if err != nil {
			return err
		}
		rv, err := mapping.MetadataAccessor.ResourceVersion(obj)
		if err != nil {
			return err
		}

		// print the current object
		if !isWatchOnly {
			if err := printer.PrintObj(obj, out); err != nil {
				return fmt.Errorf("unable to output the provided object: %v", err)
			}
		}

		// print watched changes
		w, err := r.Watch(rv)
		if err != nil {
			return err
		}

		kubectl.WatchLoop(w, func(e watch.Event) error {
			return printer.PrintObj(e.Object, out)
		})
		return nil
	}

	b := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
		NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
		FilenameParam(enforceNamespace, options.Filenames...).
		SelectorParam(selector).
		ResourceTypeOrNameArgs(true, args...).
		ContinueOnError().
		Latest()
	printer, generic, err := cmdutil.PrinterForCommand(cmd)
	if err != nil {
		return err
	}

	if generic {
		clientConfig, err := f.ClientConfig()
		if err != nil {
			return err
		}
		defaultVersion := clientConfig.Version

		singular := false
		r := b.Flatten().Do()
		infos, err := r.IntoSingular(&singular).Infos()
		if err != nil {
			return err
		}

		// the outermost object will be converted to the output-version, but inner
		// objects can use their mappings
		version := cmdutil.OutputVersion(cmd, defaultVersion)
		obj, err := resource.AsVersionedObject(infos, !singular, version)
		if err != nil {
			return err
		}

		return printer.PrintObj(obj, out)
	}

	// use the default printer for each object
	printer = nil
	var lastMapping *meta.RESTMapping
	w := kubectl.GetNewTabWriter(out)
	defer w.Flush()
	return b.Flatten().Do().Visit(func(r *resource.Info, err error) error {
		if err != nil {
			return err
		}
		if printer == nil || lastMapping == nil || r.Mapping == nil || r.Mapping.Resource != lastMapping.Resource {
			printer, err = f.PrinterForMapping(cmd, r.Mapping, allNamespaces)
			if err != nil {
				return err
			}
			lastMapping = r.Mapping
		}
		if _, found := printer.(*kubectl.HumanReadablePrinter); found {
			return printer.PrintObj(r.Object, w)
		}
		return printer.PrintObj(r.Object, out)
	})
}
Exemplo n.º 9
0
func RunEdit(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, filenames []string) error {
	var printer kubectl.ResourcePrinter
	var ext string
	switch format := cmdutil.GetFlagString(cmd, "output"); format {
	case "json":
		printer = &kubectl.JSONPrinter{}
		ext = ".json"
	case "yaml":
		printer = &kubectl.YAMLPrinter{}
		ext = ".yaml"
	default:
		return cmdutil.UsageError(cmd, "The flag 'output' must be one of yaml|json")
	}

	cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
	if err != nil {
		return err
	}

	mapper, typer := f.Object()
	rmap := &resource.Mapper{
		ObjectTyper:  typer,
		RESTMapper:   mapper,
		ClientMapper: f.ClientMapperForCommand(),
	}

	r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
		NamespaceParam(cmdNamespace).DefaultNamespace().
		FilenameParam(enforceNamespace, filenames...).
		ResourceTypeOrNameArgs(true, args...).
		Latest().
		Flatten().
		Do()
	err = r.Err()
	if err != nil {
		return err
	}

	infos, err := r.Infos()
	if err != nil {
		return err
	}

	clientConfig, err := f.ClientConfig()
	if err != nil {
		return err
	}

	defaultVersion := cmdutil.OutputVersion(cmd, clientConfig.Version)
	results := editResults{}
	for {
		objs, err := resource.AsVersionedObjects(infos, defaultVersion)
		if err != nil {
			return preservedFile(err, results.file, out)
		}
		// if input object is a list, traverse and edit each item one at a time
		for _, obj := range objs {
			// TODO: add an annotating YAML printer that can print inline comments on each field,
			//   including descriptions or validation errors

			// generate the file to edit
			buf := &bytes.Buffer{}
			if err := results.header.writeTo(buf); err != nil {
				return preservedFile(err, results.file, out)
			}
			if err := printer.PrintObj(obj, buf); err != nil {
				return preservedFile(err, results.file, out)
			}
			original := buf.Bytes()

			// launch the editor
			edit := editor.NewDefaultEditor()
			edited, file, err := edit.LaunchTempFile("kubectl-edit-", ext, buf)
			if err != nil {
				return preservedFile(err, results.file, out)
			}

			// cleanup any file from the previous pass
			if len(results.file) > 0 {
				os.Remove(results.file)
			}

			glog.V(4).Infof("User edited:\n%s", string(edited))
			lines, err := hasLines(bytes.NewBuffer(edited))
			if err != nil {
				return preservedFile(err, file, out)
			}
			// Compare content without comments
			if bytes.Equal(stripComments(original), stripComments(edited)) {
				if len(results.edit) > 0 {
					preservedFile(nil, file, out)
				} else {
					os.Remove(file)
				}
				fmt.Fprintln(out, "Edit cancelled, no changes made.")
				continue
			}
			if !lines {
				if len(results.edit) > 0 {
					preservedFile(nil, file, out)
				} else {
					os.Remove(file)
				}
				fmt.Fprintln(out, "Edit cancelled, saved file was empty.")
				continue
			}

			results = editResults{
				file: file,
			}

			// parse the edited file
			updates, err := rmap.InfoForData(edited, "edited-file")
			if err != nil {
				return fmt.Errorf("The edited file had a syntax error: %v", err)
			}

			// annotate the edited object for kubectl apply
			if err := kubectl.UpdateApplyAnnotation(updates); err != nil {
				return preservedFile(err, file, out)
			}

			visitor := resource.NewFlattenListVisitor(updates, rmap)

			// need to make sure the original namespace wasn't changed while editing
			if err = visitor.Visit(resource.RequireNamespace(cmdNamespace)); err != nil {
				return preservedFile(err, file, out)
			}

			// use strategic merge to create a patch
			originalJS, err := yaml.ToJSON(original)
			if err != nil {
				return preservedFile(err, file, out)
			}
			editedJS, err := yaml.ToJSON(edited)
			if err != nil {
				return preservedFile(err, file, out)
			}
			patch, err := strategicpatch.CreateStrategicMergePatch(originalJS, editedJS, obj)
			// TODO: change all jsonmerge to strategicpatch
			// for checking preconditions
			preconditions := []jsonmerge.PreconditionFunc{}
			if err != nil {
				glog.V(4).Infof("Unable to calculate diff, no merge is possible: %v", err)
				return preservedFile(err, file, out)
			} else {
				preconditions = append(preconditions, jsonmerge.RequireKeyUnchanged("apiVersion"))
				preconditions = append(preconditions, jsonmerge.RequireKeyUnchanged("kind"))
				preconditions = append(preconditions, jsonmerge.RequireMetadataKeyUnchanged("name"))
				results.version = defaultVersion
			}

			if hold, msg := jsonmerge.TestPreconditionsHold(patch, preconditions); !hold {
				fmt.Fprintf(out, "error: %s", msg)
				return preservedFile(nil, file, out)
			}

			err = visitor.Visit(func(info *resource.Info, err error) error {
				patched, err := resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, api.StrategicMergePatchType, patch)
				if err != nil {
					fmt.Fprintln(out, results.addError(err, info))
					return nil
				}
				info.Refresh(patched, true)
				cmdutil.PrintSuccess(mapper, false, out, info.Mapping.Resource, info.Name, "edited")
				return nil
			})
			if err != nil {
				return preservedFile(err, file, out)
			}

			if results.retryable > 0 {
				fmt.Fprintf(out, "You can run `kubectl replace -f %s` to try this update again.\n", file)
				return errExit
			}
			if results.conflict > 0 {
				fmt.Fprintf(out, "You must update your local resource version and run `kubectl replace -f %s` to overwrite the remote changes.\n", file)
				return errExit
			}
			if len(results.edit) == 0 {
				if results.notfound == 0 {
					os.Remove(file)
				} else {
					fmt.Fprintf(out, "The edits you made on deleted resources have been saved to %q\n", file)
				}
			}
		}
		if len(results.edit) == 0 {
			return nil
		}

		// loop again and edit the remaining items
		infos = results.edit
	}
	return nil
}
Exemplo n.º 10
0
func Run(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cobra.Command, args []string) error {
	if len(os.Args) > 1 && os.Args[1] == "run-container" {
		printDeprecationWarning("run", "run-container")
	}

	if len(args) == 0 {
		return cmdutil.UsageError(cmd, "NAME is required for run")
	}

	interactive := cmdutil.GetFlagBool(cmd, "stdin")
	tty := cmdutil.GetFlagBool(cmd, "tty")
	if tty && !interactive {
		return cmdutil.UsageError(cmd, "-i/--stdin is required for containers with --tty=true")
	}
	replicas := cmdutil.GetFlagInt(cmd, "replicas")
	if interactive && replicas != 1 {
		return cmdutil.UsageError(cmd, fmt.Sprintf("-i/--stdin requires that replicas is 1, found %d", replicas))
	}

	namespace, _, err := f.DefaultNamespace()
	if err != nil {
		return err
	}

	restartPolicy, err := getRestartPolicy(cmd, interactive)
	if err != nil {
		return err
	}
	if restartPolicy != api.RestartPolicyAlways && replicas != 1 {
		return cmdutil.UsageError(cmd, fmt.Sprintf("--restart=%s requires that --replicas=1, found %d", restartPolicy, replicas))
	}
	generatorName := cmdutil.GetFlagString(cmd, "generator")
	if len(generatorName) == 0 {
		if restartPolicy == api.RestartPolicyAlways {
			generatorName = "run/v1"
		} else {
			generatorName = "run-pod/v1"
		}
	}
	generator, found := f.Generator(generatorName)
	if !found {
		return cmdutil.UsageError(cmd, fmt.Sprintf("Generator: %s not found.", generatorName))
	}
	names := generator.ParamNames()
	params := kubectl.MakeParams(cmd, names)
	params["name"] = args[0]
	if len(args) > 1 {
		params["args"] = args[1:]
	}

	params["env"] = cmdutil.GetFlagStringSlice(cmd, "env")

	err = kubectl.ValidateParams(names, params)
	if err != nil {
		return err
	}

	obj, err := generator.Generate(params)
	if err != nil {
		return err
	}

	mapper, typer := f.Object()
	version, kind, err := typer.ObjectVersionAndKind(obj)
	if err != nil {
		return err
	}

	inline := cmdutil.GetFlagString(cmd, "overrides")
	if len(inline) > 0 {
		obj, err = cmdutil.Merge(obj, inline, kind)
		if err != nil {
			return err
		}
	}

	mapping, err := mapper.RESTMapping(kind, version)
	if err != nil {
		return err
	}
	client, err := f.RESTClient(mapping)
	if err != nil {
		return err
	}

	// TODO: extract this flag to a central location, when such a location exists.
	if !cmdutil.GetFlagBool(cmd, "dry-run") {
		resourceMapper := &resource.Mapper{ObjectTyper: typer, RESTMapper: mapper, ClientMapper: f.ClientMapperForCommand()}
		info, err := resourceMapper.InfoForObject(obj)
		if err != nil {
			return err
		}

		// Serialize the configuration into an annotation.
		if err := kubectl.UpdateApplyAnnotation(info); err != nil {
			return err
		}

		obj, err = resource.NewHelper(client, mapping).Create(namespace, false, info.Object)
		if err != nil {
			return err
		}
	}

	attachFlag := cmd.Flags().Lookup("attach")
	attach := cmdutil.GetFlagBool(cmd, "attach")

	if !attachFlag.Changed && interactive {
		attach = true
	}

	if attach {
		opts := &AttachOptions{
			In:    cmdIn,
			Out:   cmdOut,
			Err:   cmdErr,
			Stdin: interactive,
			TTY:   tty,

			Attach: &DefaultRemoteAttach{},
		}
		config, err := f.ClientConfig()
		if err != nil {
			return err
		}
		opts.Config = config

		client, err := f.Client()
		if err != nil {
			return err
		}
		opts.Client = client
		// TODO: this should be abstracted into Factory to support other types
		switch t := obj.(type) {
		case *api.ReplicationController:
			return handleAttachReplicationController(client, t, opts)
		case *api.Pod:
			return handleAttachPod(client, t, opts)
		default:
			return fmt.Errorf("cannot attach to %s: not implemented", kind)
		}
	}

	outputFormat := cmdutil.GetFlagString(cmd, "output")
	if outputFormat != "" {
		return f.PrintObject(cmd, obj, cmdOut)
	}
	cmdutil.PrintSuccess(mapper, false, cmdOut, mapping.Resource, args[0], "created")
	return nil
}