// RunExplain executes the appropriate steps to print a model's documentation func RunExplain(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error { if len(args) != 1 { return cmdutil.UsageError(cmd, "We accept only this format: explain RESOURCE") } client, err := f.Client() if err != nil { return err } recursive := cmdutil.GetFlagBool(cmd, "recursive") apiV := cmdutil.GetFlagString(cmd, "api-version") swagSchema, err := kubectl.GetSwaggerSchema(apiV, client) if err != nil { return err } mapper, _ := f.Object() inModel, fieldsPath, err := kubectl.SplitAndParseResourceRequest(args[0], mapper) if err != nil { return err } return kubectl.PrintModelDescription(inModel, fieldsPath, out, swagSchema, recursive) }
func (o *LogsOptions) Complete(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error { switch len(args) { case 0: return cmdutil.UsageError(cmd, "POD is required for log") case 1: o.PodName = args[0] case 2: o.PodName = args[0] o.ContainerName = args[1] default: return cmdutil.UsageError(cmd, "log POD [CONTAINER]") } var err error o.PodNamespace, _, err = f.DefaultNamespace() if err != nil { return err } o.Client, err = f.Client() if err != nil { return err } return nil }
func RunApiVersions(f *cmdutil.Factory, w io.Writer) error { if len(os.Args) > 1 && os.Args[1] == "apiversions" { printDeprecationWarning("api-versions", "apiversions") } client, err := f.Client() if err != nil { return err } apiVersions, err := client.ServerAPIVersions() if err != nil { fmt.Printf("Couldn't get available api versions from server: %v\n", err) os.Exit(1) } var expAPIVersions *unversioned.APIVersions expAPIVersions, err = client.Experimental().ServerAPIVersions() fmt.Fprintf(w, "Available Server Api Versions: %#v\n", *apiVersions) if err == nil { fmt.Fprintf(w, "Available Server Experimental Api Versions: %#v\n", *expAPIVersions) } return nil }
// 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 }
// Complete fills CreateBasicAuthSecretOptions fields with data and checks for mutual exclusivity // between flags from different option groups. func (o *CreateBasicAuthSecretOptions) Complete(f *kcmdutil.Factory, args []string) error { if len(args) != 1 { return errors.New("must have exactly one argument: secret name") } o.SecretName = args[0] if o.PromptForPassword { if len(o.Password) != 0 { return errors.New("must provide either --prompt or --password flag") } if !term.IsTerminal(o.Reader) { return errors.New("provided reader is not a terminal") } o.Password = cmdutil.PromptForPasswordString(o.Reader, o.Out, "Password: "******"password must be provided") } } if f != nil { client, err := f.Client() if err != nil { return err } namespace, _, err := f.DefaultNamespace() if err != nil { return err } o.SecretsInterface = client.Secrets(namespace) } return nil }
// Complete completes all the required options for port-forward cmd. func (o *PortForwardOptions) Complete(f *cmdutil.Factory, cmd *cobra.Command, args []string, cmdOut io.Writer, cmdErr io.Writer) error { var err error o.PodName = cmdutil.GetFlagString(cmd, "pod") if len(o.PodName) == 0 && len(args) == 0 { return cmdutil.UsageError(cmd, "POD is required for port-forward") } if len(o.PodName) != 0 { printDeprecationWarning("port-forward POD", "-p POD") o.Ports = args } else { o.PodName = args[0] o.Ports = args[1:] } o.Namespace, _, err = f.DefaultNamespace() if err != nil { return err } o.Client, err = f.Client() if err != nil { return err } o.Config, err = f.ClientConfig() if err != nil { return err } o.StopChannel = make(chan struct{}, 1) o.ReadyChannel = make(chan struct{}) return nil }
// RunLog retrieves a pod log func RunLog(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, p *logParams) error { if len(os.Args) > 1 && os.Args[1] == "log" { printDeprecationWarning("logs", "log") } if len(args) == 0 { return cmdutil.UsageError(cmd, "POD is required for log") } if len(args) > 2 { return cmdutil.UsageError(cmd, "log POD [CONTAINER]") } namespace, _, err := f.DefaultNamespace() if err != nil { return err } client, err := f.Client() if err != nil { return err } podID := args[0] pod, err := client.Pods(namespace).Get(podID) if err != nil { return err } // [-c CONTAINER] container := p.containerName if len(container) == 0 { // [CONTAINER] (container as arg not flag) is supported as legacy behavior. See PR #10519 for more details. if len(args) == 1 { if len(pod.Spec.Containers) != 1 { podContainersNames := []string{} for _, container := range pod.Spec.Containers { podContainersNames = append(podContainersNames, container.Name) } return fmt.Errorf("Pod %s has the following containers: %s; please specify the container to print logs for with -c", pod.ObjectMeta.Name, strings.Join(podContainersNames, ", ")) } container = pod.Spec.Containers[0].Name } else { container = args[1] } } follow := false if cmdutil.GetFlagBool(cmd, "follow") { follow = true } previous := false if cmdutil.GetFlagBool(cmd, "previous") { previous = true } return handleLog(client, namespace, podID, container, follow, previous, out) }
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) }
func Run(f *cmdutil.Factory, out 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) != 1 { return cmdutil.UsageError(cmd, "NAME is required for run") } namespace, _, err := f.DefaultNamespace() if err != nil { return err } client, err := f.Client() if err != nil { return err } generatorName := cmdutil.GetFlagString(cmd, "generator") generator, found := f.Generator(generatorName) if !found { return cmdutil.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 := cmdutil.GetFlagString(cmd, "overrides") if len(inline) > 0 { controller, err = cmdutil.Merge(controller, inline, "ReplicationController") if err != nil { return err } } // TODO: extract this flag to a central location, when such a location exists. if !cmdutil.GetFlagBool(cmd, "dry-run") { controller, err = client.ReplicationControllers(namespace).Create(controller.(*api.ReplicationController)) if err != nil { return err } } return f.PrintObject(cmd, controller, out) }
func RunApiVersions(f *cmdutil.Factory, out io.Writer) error { if len(os.Args) > 1 && os.Args[1] == "apiversions" { printDeprecationWarning("api-versions", "apiversions") } client, err := f.Client() if err != nil { return err } kubectl.GetApiVersions(out, client) return nil }
func RunVersion(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command) error { kubectl.GetClientVersion(out) if cmdutil.GetFlagBool(cmd, "client") { return nil } client, err := f.Client() if err != nil { return err } kubectl.GetServerVersion(out, client) return nil }
// RunExplain executes the appropriate steps to print a model's documentation func RunExplain(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error { if len(args) != 1 { return cmdutil.UsageError(cmd, "We accept only this format: explain RESOURCE") } client, err := f.Client() if err != nil { return err } recursive := cmdutil.GetFlagBool(cmd, "recursive") apiVersionString := cmdutil.GetFlagString(cmd, "api-version") apiVersion := unversioned.GroupVersion{} mapper, _ := f.Object() // TODO: After we figured out the new syntax to separate group and resource, allow // the users to use it in explain (kubectl explain <group><syntax><resource>). // Refer to issue #16039 for why we do this. Refer to PR #15808 that used "/" syntax. inModel, fieldsPath, err := kubectl.SplitAndParseResourceRequest(args[0], mapper) if err != nil { return err } // TODO: We should deduce the group for a resource by discovering the supported resources at server. gvk, err := mapper.KindFor(inModel) if err != nil { return err } if len(apiVersionString) == 0 { groupMeta, err := latest.Group(gvk.Group) if err != nil { return err } apiVersion = groupMeta.GroupVersion } else { apiVersion, err = unversioned.ParseGroupVersion(apiVersionString) if err != nil { return nil } } swagSchema, err := kubectl.GetSwaggerSchema(apiVersion, client) if err != nil { return err } return kubectl.PrintModelDescription(inModel, fieldsPath, out, swagSchema, recursive) }
func (o *TopNodeOptions) Complete(f *cmdutil.Factory, cmd *cobra.Command, args []string, out io.Writer) error { var err error if len(args) == 1 { o.ResourceName = args[0] } else if len(args) > 1 { return cmdutil.UsageError(cmd, cmd.Use) } cli, err := f.Client() if err != nil { return err } o.Client = metricsutil.DefaultHeapsterMetricsClient(cli) o.Printer = metricsutil.NewTopCmdPrinter(out) return nil }
// 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, execUsageStr) } if len(p.PodName) != 0 { printDeprecationWarning("exec POD_NAME", "-p POD_NAME") if len(argsIn) < 1 { return cmdutil.UsageError(cmd, execUsageStr) } p.Command = argsIn } else { p.PodName = argsIn[0] p.Command = argsIn[1:] if len(p.Command) < 1 { return cmdutil.UsageError(cmd, execUsageStr) } } cmdParent := cmd.Parent() if cmdParent != nil { p.FullCmdName = cmdParent.CommandPath() } if len(p.FullCmdName) > 0 && cmdutil.IsSiblingCommandExists(cmd, "describe") { p.SuggestedCmdUsage = fmt.Sprintf("Use '%s describe pod/%s' to see all of the containers in this pod.", p.FullCmdName, p.PodName) } 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 }
// 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 { if len(p.FullCmdName) == 0 { p.FullCmdName = "kubectl" } // 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 }
func (o *CreateDockerConfigOptions) Complete(f *kcmdutil.Factory, args []string) error { if len(args) != 1 { return errors.New("must have exactly one argument: secret name") } o.SecretName = args[0] client, err := f.Client() if err != nil { return err } namespace, _, err := f.DefaultNamespace() if err != nil { return err } o.SecretsInterface = client.Secrets(namespace) return nil }
func (o *TopPodOptions) Complete(f *cmdutil.Factory, cmd *cobra.Command, args []string, out io.Writer) error { var err error if len(args) == 1 { o.ResourceName = args[0] } else if len(args) > 1 { return cmdutil.UsageError(cmd, cmd.Use) } o.Namespace, _, err = f.DefaultNamespace() if err != nil { return err } cli, err := f.Client() if err != nil { return err } o.Client = metricsutil.NewHeapsterMetricsClient(cli, o.HeapsterOptions.Namespace, o.HeapsterOptions.Scheme, o.HeapsterOptions.Service, o.HeapsterOptions.Port) o.Printer = metricsutil.NewTopCmdPrinter(out) return nil }
// RunExplain executes the appropriate steps to print a model's documentation func RunExplain(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error { if len(args) != 1 { return cmdutil.UsageError(cmd, "We accept only this format: explain RESOURCE") } client, err := f.Client() if err != nil { return err } recursive := cmdutil.GetFlagBool(cmd, "recursive") apiV := cmdutil.GetFlagString(cmd, "api-version") mapper, _ := f.Object() group, inModel, fieldsPath, err := kubectl.SplitAndParseResourceRequest(args[0], mapper) if err != nil { return err } if len(group) == 0 { // TODO: We should deduce the group for a resource by discovering the supported resources at server. group, err = mapper.GroupForResource(inModel) if err != nil { return err } } if len(apiV) == 0 { groupMeta, err := latest.Group(group) if err != nil { return err } apiV = groupMeta.GroupVersion } swagSchema, err := kubectl.GetSwaggerSchema(apiV, client) if err != nil { return err } return kubectl.PrintModelDescription(inModel, fieldsPath, out, swagSchema, recursive) }
func RunApiVersions(f *cmdutil.Factory, w io.Writer) error { if len(os.Args) > 1 && os.Args[1] == "apiversions" { printDeprecationWarning("api-versions", "apiversions") } client, err := f.Client() if err != nil { return err } groupList, err := client.Discovery().ServerGroups() if err != nil { return fmt.Errorf("Couldn't get available api versions from server: %v\n", err) } apiVersions := unversioned.ExtractGroupVersions(groupList) sort.Strings(apiVersions) for _, v := range apiVersions { fmt.Fprintln(w, v) } return nil }
func (o *LogsOptions) Complete(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error { switch len(args) { case 0: return cmdutil.UsageError(cmd, "POD is required for log") case 1: o.PodName = args[0] case 2: if cmd.Flag("container").Changed { return cmdutil.UsageError(cmd, "only one of -c, [CONTAINER] arg is allowed") } o.PodName = args[0] o.ContainerName = args[1] default: return cmdutil.UsageError(cmd, "log POD [-c CONTAINER]") } var err error o.PodNamespace, _, err = f.DefaultNamespace() if err != nil { return err } o.Client, err = f.Client() if err != nil { return err } sinceTime := cmdutil.GetFlagString(cmd, "since-time") if len(sinceTime) > 0 { t, err := api.ParseRFC3339(sinceTime, unversioned.Now) if err != nil { return err } o.SinceTime = &t } return nil }
func (o *AddSecretOptions) Complete(f *cmdutil.Factory, args []string, typeFlags []string) error { if len(args) < 2 { return errors.New("must have service account name and at least one secret name") } o.TargetName = args[0] o.SecretNames = args[1:] if len(typeFlags) == 0 { o.ForMount = true } else { for _, flag := range typeFlags { loweredValue := strings.ToLower(flag) switch loweredValue { case "pull": o.ForPull = true case "mount": o.ForMount = true default: return fmt.Errorf("unknown for: %v", flag) } } } var err error o.ClientInterface, err = f.Client() if err != nil { return err } o.Namespace, _, err = f.DefaultNamespace() if err != nil { return err } o.Mapper, o.Typer = f.Object() o.ClientMapper = f.ClientMapperForCommand() return nil }
// 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 }
// Complete Parses the command line arguments and populates SecretOptions func (o *SecretOptions) Complete(f *kcmdutil.Factory, args []string) error { if len(args) < 2 { return errors.New("must have service account name and at least one secret name") } o.TargetName = args[0] o.SecretNames = args[1:] var err error o.ClientInterface, err = f.Client() if err != nil { return err } o.Namespace, _, err = f.DefaultNamespace() if err != nil { return err } o.Mapper, o.Typer = f.Object(false) o.ClientMapper = resource.ClientMapperFunc(f.ClientForMapping) return nil }
// RunLog retrieves a pod log func RunLog(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, p *logParams) error { if len(os.Args) > 1 && os.Args[1] == "log" { printDeprecationWarning("logs", "log") } if len(args) == 0 { return cmdutil.UsageError(cmd, "POD is required for log") } if len(args) > 2 { return cmdutil.UsageError(cmd, "log POD [CONTAINER]") } sinceSeconds := cmdutil.GetFlagDuration(cmd, "since") sinceTime := cmdutil.GetFlagString(cmd, "since-time") if len(sinceTime) > 0 && sinceSeconds > 0 { return cmdutil.UsageError(cmd, "only one of --since, --since-time may be specified") } namespace, _, err := f.DefaultNamespace() if err != nil { return err } client, err := f.Client() if err != nil { return err } podID := args[0] pod, err := client.Pods(namespace).Get(podID) if err != nil { return err } // [-c CONTAINER] container := p.containerName if len(container) == 0 { // [CONTAINER] (container as arg not flag) is supported as legacy behavior. See PR #10519 for more details. if len(args) == 1 { if len(pod.Spec.Containers) != 1 { podContainersNames := []string{} for _, container := range pod.Spec.Containers { podContainersNames = append(podContainersNames, container.Name) } return fmt.Errorf("Pod %s has the following containers: %s; please specify the container to print logs for with -c", pod.ObjectMeta.Name, strings.Join(podContainersNames, ", ")) } container = pod.Spec.Containers[0].Name } else { container = args[1] } } logOptions := &api.PodLogOptions{ Container: container, Follow: cmdutil.GetFlagBool(cmd, "follow"), Previous: cmdutil.GetFlagBool(cmd, "previous"), Timestamps: cmdutil.GetFlagBool(cmd, "timestamps"), } if sinceSeconds > 0 { // round up to the nearest second sec := int64(math.Ceil(float64(sinceSeconds) / float64(time.Second))) logOptions.SinceSeconds = &sec } if t, err := api.ParseRFC3339(sinceTime, unversioned.Now); err == nil { logOptions.SinceTime = &t } if limitBytes := cmdutil.GetFlagInt(cmd, "limit-bytes"); limitBytes != 0 { i := int64(limitBytes) logOptions.LimitBytes = &i } if tail := cmdutil.GetFlagInt(cmd, "tail"); tail >= 0 { i := int64(tail) logOptions.TailLines = &i } return handleLog(client, namespace, podID, logOptions, out) }
func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error { if len(os.Args) > 1 && os.Args[1] == "rollingupdate" { printDeprecationWarning("rolling-update", "rollingupdate") } deploymentKey, filename, image, oldName, err := validateArguments(cmd, args) if err != nil { return err } period := cmdutil.GetFlagDuration(cmd, "update-period") interval := cmdutil.GetFlagDuration(cmd, "poll-interval") timeout := cmdutil.GetFlagDuration(cmd, "timeout") dryrun := cmdutil.GetFlagBool(cmd, "dry-run") cmdNamespace, enforceNamespace, err := f.DefaultNamespace() if err != nil { return err } client, err := f.Client() if err != nil { return err } updaterClient := kubectl.NewRollingUpdaterClient(client) var newRc *api.ReplicationController // fetch rc oldRc, err := client.ReplicationControllers(cmdNamespace).Get(oldName) if err != nil { if !errors.IsNotFound(err) || len(image) == 0 || len(args) > 1 { return err } // We're in the middle of a rename, look for an RC with a source annotation of oldName newRc, err := kubectl.FindSourceController(updaterClient, cmdNamespace, oldName) if err != nil { return err } return kubectl.Rename(kubectl.NewRollingUpdaterClient(client), newRc, oldName) } var keepOldName bool var replicasDefaulted bool mapper, typer := f.Object() if len(filename) != 0 { schema, err := f.Validator() if err != nil { return err } request := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). Schema(schema). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(enforceNamespace, filename). Do() obj, err := request.Object() if err != nil { return err } var ok bool // Handle filename input from stdin. The resource builder always returns an api.List // when creating resource(s) from a stream. if list, ok := obj.(*api.List); ok { if len(list.Items) > 1 { return cmdutil.UsageError(cmd, "%s specifies multiple items", filename) } obj = list.Items[0] } newRc, ok = obj.(*api.ReplicationController) if !ok { if _, kind, err := typer.ObjectVersionAndKind(obj); err == nil { return cmdutil.UsageError(cmd, "%s contains a %s not a ReplicationController", filename, kind) } glog.V(4).Infof("Object %#v is not a ReplicationController", obj) return cmdutil.UsageError(cmd, "%s does not specify a valid ReplicationController", filename) } infos, err := request.Infos() if err != nil || len(infos) != 1 { glog.V(2).Infof("was not able to recover adequate information to discover if .spec.replicas was defaulted") } else { replicasDefaulted = isReplicasDefaulted(infos[0]) } } // If the --image option is specified, we need to create a new rc with at least one different selector // than the old rc. This selector is the hash of the rc, which will differ because the new rc has a // different image. if len(image) != 0 { keepOldName = len(args) == 1 newName := findNewName(args, oldRc) if newRc, err = kubectl.LoadExistingNextReplicationController(client, cmdNamespace, newName); err != nil { return err } if newRc != nil { fmt.Fprintf(out, "Found existing update in progress (%s), resuming.\n", newRc.Name) } else { newRc, err = kubectl.CreateNewControllerFromCurrentController(client, cmdNamespace, oldName, newName, image, deploymentKey) if err != nil { return err } } // Update the existing replication controller with pointers to the 'next' controller // and adding the <deploymentKey> label if necessary to distinguish it from the 'next' controller. oldHash, err := api.HashObject(oldRc, client.Codec) if err != nil { return err } oldRc, err = kubectl.UpdateExistingReplicationController(client, oldRc, cmdNamespace, newRc.Name, deploymentKey, oldHash, out) if err != nil { return err } } if oldName == newRc.Name { return cmdutil.UsageError(cmd, "%s cannot have the same name as the existing ReplicationController %s", filename, oldName) } updater := kubectl.NewRollingUpdater(newRc.Namespace, updaterClient) // To successfully pull off a rolling update the new and old rc have to differ // by at least one selector. Every new pod should have the selector and every // old pod should not have the selector. 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 cmdutil.UsageError(cmd, "%s must specify a matching key with non-equal value in Selector for %s", filename, oldName) } // TODO: handle scales during rolling update if replicasDefaulted { newRc.Spec.Replicas = oldRc.Spec.Replicas } if dryrun { oldRcData := &bytes.Buffer{} if err := f.PrintObject(cmd, oldRc, oldRcData); err != nil { return err } newRcData := &bytes.Buffer{} if err := f.PrintObject(cmd, newRc, newRcData); err != nil { return err } fmt.Fprintf(out, "Rolling from:\n%s\nTo:\n%s\n", string(oldRcData.Bytes()), string(newRcData.Bytes())) return nil } updateCleanupPolicy := kubectl.DeleteRollingUpdateCleanupPolicy if keepOldName { updateCleanupPolicy = kubectl.RenameRollingUpdateCleanupPolicy } config := &kubectl.RollingUpdaterConfig{ Out: out, OldRc: oldRc, NewRc: newRc, UpdatePeriod: period, Interval: interval, Timeout: timeout, CleanupPolicy: updateCleanupPolicy, UpdateAcceptor: kubectl.DefaultUpdateAcceptor, } if cmdutil.GetFlagBool(cmd, "rollback") { kubectl.AbortRollingUpdate(config) client.ReplicationControllers(config.NewRc.Namespace).Update(config.NewRc) } err = updater.Update(config) if err != nil { return err } if keepOldName { fmt.Fprintf(out, "%s\n", oldName) } else { fmt.Fprintf(out, "%s\n", newRc.Name) } return nil }
func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, options *RollingUpdateOptions) error { if len(os.Args) > 1 && os.Args[1] == "rollingupdate" { printDeprecationWarning("rolling-update", "rollingupdate") } err := validateArguments(cmd, options.Filenames, args) if err != nil { return err } deploymentKey := cmdutil.GetFlagString(cmd, "deployment-label-key") filename := "" image := cmdutil.GetFlagString(cmd, "image") pullPolicy := cmdutil.GetFlagString(cmd, "image-pull-policy") oldName := args[0] rollback := cmdutil.GetFlagBool(cmd, "rollback") period := cmdutil.GetFlagDuration(cmd, "update-period") interval := cmdutil.GetFlagDuration(cmd, "poll-interval") timeout := cmdutil.GetFlagDuration(cmd, "timeout") dryrun := cmdutil.GetFlagBool(cmd, "dry-run") outputFormat := cmdutil.GetFlagString(cmd, "output") container := cmdutil.GetFlagString(cmd, "container") if len(options.Filenames) > 0 { filename = options.Filenames[0] } cmdNamespace, enforceNamespace, err := f.DefaultNamespace() if err != nil { return err } client, err := f.Client() if err != nil { return err } var newRc *api.ReplicationController // fetch rc oldRc, err := client.ReplicationControllers(cmdNamespace).Get(oldName) if err != nil { if !errors.IsNotFound(err) || len(image) == 0 || len(args) > 1 { return err } // We're in the middle of a rename, look for an RC with a source annotation of oldName newRc, err := kubectl.FindSourceController(client, cmdNamespace, oldName) if err != nil { return err } return kubectl.Rename(client, newRc, oldName) } var keepOldName bool var replicasDefaulted bool mapper, typer := f.Object(cmdutil.GetIncludeThirdPartyAPIs(cmd)) if len(filename) != 0 { schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"), cmdutil.GetFlagString(cmd, "schema-cache-dir")) if err != nil { return err } request := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)). Schema(schema). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(enforceNamespace, false, filename). Do() obj, err := request.Object() if err != nil { return err } var ok bool // Handle filename input from stdin. The resource builder always returns an api.List // when creating resource(s) from a stream. if list, ok := obj.(*api.List); ok { if len(list.Items) > 1 { return cmdutil.UsageError(cmd, "%s specifies multiple items", filename) } obj = list.Items[0] } newRc, ok = obj.(*api.ReplicationController) if !ok { if gvk, err := typer.ObjectKind(obj); err == nil { return cmdutil.UsageError(cmd, "%s contains a %v not a ReplicationController", filename, gvk) } glog.V(4).Infof("Object %#v is not a ReplicationController", obj) return cmdutil.UsageError(cmd, "%s does not specify a valid ReplicationController", filename) } infos, err := request.Infos() if err != nil || len(infos) != 1 { glog.V(2).Infof("was not able to recover adequate information to discover if .spec.replicas was defaulted") } else { replicasDefaulted = isReplicasDefaulted(infos[0]) } } // If the --image option is specified, we need to create a new rc with at least one different selector // than the old rc. This selector is the hash of the rc, with a suffix to provide uniqueness for // same-image updates. if len(image) != 0 { codec := api.Codecs.LegacyCodec(client.APIVersion()) keepOldName = len(args) == 1 newName := findNewName(args, oldRc) if newRc, err = kubectl.LoadExistingNextReplicationController(client, cmdNamespace, newName); err != nil { return err } if newRc != nil { if inProgressImage := newRc.Spec.Template.Spec.Containers[0].Image; inProgressImage != image { return cmdutil.UsageError(cmd, "Found existing in-progress update to image (%s).\nEither continue in-progress update with --image=%s or rollback with --rollback", inProgressImage, inProgressImage) } fmt.Fprintf(out, "Found existing update in progress (%s), resuming.\n", newRc.Name) } else { config := &kubectl.NewControllerConfig{ Namespace: cmdNamespace, OldName: oldName, NewName: newName, Image: image, Container: container, DeploymentKey: deploymentKey, } if oldRc.Spec.Template.Spec.Containers[0].Image == image { if len(pullPolicy) == 0 { return cmdutil.UsageError(cmd, "--image-pull-policy (Always|Never|IfNotPresent) must be provided when --image is the same as existing container image") } config.PullPolicy = api.PullPolicy(pullPolicy) } newRc, err = kubectl.CreateNewControllerFromCurrentController(client, codec, config) if err != nil { return err } } // Update the existing replication controller with pointers to the 'next' controller // and adding the <deploymentKey> label if necessary to distinguish it from the 'next' controller. oldHash, err := api.HashObject(oldRc, codec) if err != nil { return err } // If new image is same as old, the hash may not be distinct, so add a suffix. oldHash += "-orig" oldRc, err = kubectl.UpdateExistingReplicationController(client, oldRc, cmdNamespace, newRc.Name, deploymentKey, oldHash, out) if err != nil { return err } } if rollback { keepOldName = len(args) == 1 newName := findNewName(args, oldRc) if newRc, err = kubectl.LoadExistingNextReplicationController(client, cmdNamespace, newName); err != nil { return err } if newRc == nil { return cmdutil.UsageError(cmd, "Could not find %s to rollback.\n", newName) } } if oldName == newRc.Name { return cmdutil.UsageError(cmd, "%s cannot have the same name as the existing ReplicationController %s", filename, oldName) } updater := kubectl.NewRollingUpdater(newRc.Namespace, client) // To successfully pull off a rolling update the new and old rc have to differ // by at least one selector. Every new pod should have the selector and every // old pod should not have the selector. 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 cmdutil.UsageError(cmd, "%s must specify a matching key with non-equal value in Selector for %s", filename, oldName) } // TODO: handle scales during rolling update if replicasDefaulted { newRc.Spec.Replicas = oldRc.Spec.Replicas } if dryrun { oldRcData := &bytes.Buffer{} newRcData := &bytes.Buffer{} if outputFormat == "" { oldRcData.WriteString(oldRc.Name) newRcData.WriteString(newRc.Name) } else { if err := f.PrintObject(cmd, mapper, oldRc, oldRcData); err != nil { return err } if err := f.PrintObject(cmd, mapper, newRc, newRcData); err != nil { return err } } fmt.Fprintf(out, "Rolling from:\n%s\nTo:\n%s\n", string(oldRcData.Bytes()), string(newRcData.Bytes())) return nil } updateCleanupPolicy := kubectl.DeleteRollingUpdateCleanupPolicy if keepOldName { updateCleanupPolicy = kubectl.RenameRollingUpdateCleanupPolicy } config := &kubectl.RollingUpdaterConfig{ Out: out, OldRc: oldRc, NewRc: newRc, UpdatePeriod: period, Interval: interval, Timeout: timeout, CleanupPolicy: updateCleanupPolicy, MaxUnavailable: intstr.FromInt(0), MaxSurge: intstr.FromInt(1), } if rollback { err = kubectl.AbortRollingUpdate(config) if err != nil { return err } client.ReplicationControllers(config.NewRc.Namespace).Update(config.NewRc) } err = updater.Update(config) if err != nil { return err } message := "rolling updated" if keepOldName { newRc.Name = oldName } else { message = fmt.Sprintf("rolling updated to %q", newRc.Name) } newRc, err = client.ReplicationControllers(cmdNamespace).Get(newRc.Name) if err != nil { return err } if outputFormat != "" { return f.PrintObject(cmd, mapper, newRc, out) } kind, err := api.Scheme.ObjectKind(newRc) if err != nil { return err } _, res := meta.KindToResource(kind) cmdutil.PrintSuccess(mapper, false, out, res.Resource, oldName, message) return nil }
func Run(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cobra.Command, args []string, argsLenAtDash int) error { if len(os.Args) > 1 && os.Args[1] == "run-container" { printDeprecationWarning("run", "run-container") } // Let kubectl run follow rules for `--`, see #13004 issue if len(args) == 0 || argsLenAtDash == 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 -t/--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 { client, err := f.Client() if err != nil { return err } resourcesList, err := client.Discovery().ServerResources() if err != nil { // this cover the cases where old servers do not expose discovery resourcesList = nil } if restartPolicy == api.RestartPolicyAlways { if contains(resourcesList, v1beta1.SchemeGroupVersion.WithResource("deployments")) { generatorName = "deployment/v1beta1" } else { generatorName = "run/v1" } } else { if contains(resourcesList, batchv1.SchemeGroupVersion.WithResource("jobs")) { generatorName = "job/v1" } else if contains(resourcesList, v1beta1.SchemeGroupVersion.WithResource("jobs")) { generatorName = "job/v1beta1" } else { generatorName = "run-pod/v1" } } } generators := f.Generators("run") generator, found := generators[generatorName] if !found { return cmdutil.UsageError(cmd, fmt.Sprintf("generator %q 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") obj, _, mapper, mapping, err := createGeneratedObject(f, cmd, generator, names, params, cmdutil.GetFlagString(cmd, "overrides"), namespace) if err != nil { return err } 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 } } attachFlag := cmd.Flags().Lookup("attach") attach := cmdutil.GetFlagBool(cmd, "attach") if !attachFlag.Changed && interactive { attach = true } remove := cmdutil.GetFlagBool(cmd, "rm") if !attach && remove { return cmdutil.UsageError(cmd, "--rm should only be used for attached containers") } 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 } err = handleAttachPod(f, client, attachablePod, opts) if err != nil { return err } if remove { namespace, err = mapping.MetadataAccessor.Namespace(obj) if err != nil { return err } var name string name, err = mapping.MetadataAccessor.Name(obj) if err != nil { return err } _, typer := f.Object(cmdutil.GetIncludeThirdPartyAPIs(cmd)) r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)). ContinueOnError(). NamespaceParam(namespace).DefaultNamespace(). ResourceNames(mapping.Resource, name). Flatten(). Do() return ReapResult(r, f, cmdOut, true, true, 0, -1, false, mapper) } return nil } outputFormat := cmdutil.GetFlagString(cmd, "output") if outputFormat != "" { return f.PrintObject(cmd, mapper, obj, cmdOut) } cmdutil.PrintSuccess(mapper, false, cmdOut, mapping.Resource, args[0], "created") return nil }
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) != 1 { 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 --repliacs=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] 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") { data, err := mapping.Codec.Encode(obj) if err != nil { return err } obj, err = resource.NewHelper(client, mapping).Create(namespace, false, data) 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) } } return f.PrintObject(cmd, obj, cmdOut) }
func Run(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cobra.Command, args []string, argsLenAtDash int) error { if len(os.Args) > 1 && os.Args[1] == "run-container" { printDeprecationWarning("run", "run-container") } // Let kubectl run follow rules for `--`, see #13004 issue if len(args) == 0 || argsLenAtDash == 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 { // TODO: Change the default to "deployment/v1beta1" when deployment reaches beta (#15313) if restartPolicy == api.RestartPolicyAlways { generatorName = "run/v1" } else { generatorName = "job/v1beta1" } } 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(f, 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 }
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") postErr := fw.ForwardPorts("POST", req.URL(), config, args, stopCh) // if we don't have an error, return. If we did get an error, try a GET because v3.0.0 shipped with port-forward running as a GET. if postErr == nil { return nil } // only try the get if the error is either a forbidden or method not supported, otherwise trying with a GET probably won't help if !apierrors.IsForbidden(postErr) && !apierrors.IsMethodNotSupported(postErr) { return postErr } getReq := client.RESTClient.Get(). Resource("pods"). Namespace(namespace). Name(pod.Name). SubResource("portforward") getErr := fw.ForwardPorts("GET", getReq.URL(), config, args, stopCh) if getErr == nil { return nil } // if we got a getErr, return the postErr because it's more likely to be correct. GET is legacy return postErr }