func RunDelete(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, filenames util.StringList) error { cmdNamespace, enforceNamespace, err := f.DefaultNamespace() if err != nil { return err } mapper, typer := f.Object() r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). ContinueOnError(). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(enforceNamespace, filenames...). SelectorParam(cmdutil.GetFlagString(cmd, "selector")). SelectAllParam(cmdutil.GetFlagBool(cmd, "all")). ResourceTypeOrNameArgs(false, args...).RequireObject(false). Flatten(). Do() err = r.Err() if err != nil { return err } ignoreNotFound := cmdutil.GetFlagBool(cmd, "ignore-not-found") // By default use a reaper to delete all related resources. if cmdutil.GetFlagBool(cmd, "cascade") { return ReapResult(r, f, out, cmdutil.GetFlagBool(cmd, "cascade"), ignoreNotFound, cmdutil.GetFlagDuration(cmd, "timeout"), cmdutil.GetFlagInt(cmd, "grace-period")) } return DeleteResult(r, out, ignoreNotFound) }
func RunWhoAmI(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string, o *WhoAmIOptions) error { if kcmdutil.GetFlagBool(cmd, "token") { cfg, err := f.OpenShiftClientConfig.ClientConfig() if err != nil { return err } if len(cfg.BearerToken) == 0 { return fmt.Errorf("no token is currently in use for this session") } fmt.Fprintf(out, "%s\n", cfg.BearerToken) return nil } if kcmdutil.GetFlagBool(cmd, "context") { cfg, err := f.OpenShiftClientConfig.RawConfig() if err != nil { return err } if len(cfg.CurrentContext) == 0 { return fmt.Errorf("no context has been set") } fmt.Fprintf(out, "%s\n", cfg.CurrentContext) return nil } client, _, err := f.Clients() if err != nil { return err } o.UserInterface = client.Users() o.Out = out _, err = o.WhoAmI() return err }
// PrinterForMapping returns a printer suitable for displaying the provided resource type. // Requires that printer flags have been added to cmd (see AddPrinterFlags). func (f *Factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping) (kubectl.ResourcePrinter, error) { printer, ok, err := cmdutil.PrinterForCommand(cmd) if err != nil { return nil, err } if ok { clientConfig, err := f.ClientConfig() if err != nil { return nil, err } defaultVersion := clientConfig.Version version := cmdutil.OutputVersion(cmd, defaultVersion) if len(version) == 0 { version = mapping.APIVersion } if len(version) == 0 { return nil, fmt.Errorf("you must specify an output-version when using this output format") } printer = kubectl.NewVersionedPrinter(printer, mapping.ObjectConvertor, version) } else { printer, err = f.Printer(mapping, cmdutil.GetFlagBool(cmd, "no-headers")) if err != nil { return nil, err } } return printer, nil }
func (o *LoginOptions) Complete(f *osclientcmd.Factory, cmd *cobra.Command, args []string) error { kubeconfig, err := f.OpenShiftClientConfig.RawConfig() o.StartingKubeConfig = &kubeconfig if err != nil { if !os.IsNotExist(err) { return err } // build a valid object to use if we failed on a non-existent file o.StartingKubeConfig = kclientcmdapi.NewConfig() } addr := flagtypes.Addr{Value: "localhost:8443", DefaultScheme: "https", DefaultPort: 8443, AllowPrefix: true}.Default() if serverFlag := kcmdutil.GetFlagString(cmd, "server"); len(serverFlag) > 0 { if err := addr.Set(serverFlag); err != nil { return err } o.Server = addr.String() } else if len(args) == 1 { if err := addr.Set(args[0]); err != nil { return err } o.Server = addr.String() } else if len(o.Server) == 0 { if defaultContext, defaultContextExists := o.StartingKubeConfig.Contexts[o.StartingKubeConfig.CurrentContext]; defaultContextExists { if cluster, exists := o.StartingKubeConfig.Clusters[defaultContext.Cluster]; exists { o.Server = cluster.Server } } } o.CertFile = kcmdutil.GetFlagString(cmd, "client-certificate") o.KeyFile = kcmdutil.GetFlagString(cmd, "client-key") o.APIVersion = kcmdutil.GetFlagString(cmd, "api-version") // if the API version isn't explicitly passed, use the API version from the default context (same rules as the server above) if len(o.APIVersion) == 0 { if defaultContext, defaultContextExists := o.StartingKubeConfig.Contexts[o.StartingKubeConfig.CurrentContext]; defaultContextExists { if cluster, exists := o.StartingKubeConfig.Clusters[defaultContext.Cluster]; exists { o.APIVersion = cluster.APIVersion } } } o.CAFile = kcmdutil.GetFlagString(cmd, "certificate-authority") o.InsecureTLS = kcmdutil.GetFlagBool(cmd, "insecure-skip-tls-verify") o.Token = kcmdutil.GetFlagString(cmd, "token") o.DefaultNamespace, _ = f.OpenShiftClientConfig.Namespace() o.PathOptions = config.NewPathOptions(cmd) return nil }
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 RunLog(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error { 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 } var container string if len(args) == 1 { if len(pod.Spec.Containers) != 1 { return fmt.Errorf("POD %s has more than one container; please specify the container to print logs for", pod.ObjectMeta.Name) } container = pod.Spec.Containers[0].Name } else { container = args[1] } follow := false if cmdutil.GetFlagBool(cmd, "follow") { follow = true } readCloser, err := client.RESTClient.Get(). Prefix("proxy"). Resource("nodes"). Name(pod.Spec.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 }
func RunStop(f *cmdutil.Factory, cmd *cobra.Command, args []string, filenames util.StringList, out io.Writer) error { cmdNamespace, enforceNamespace, err := f.DefaultNamespace() if err != nil { return err } mapper, typer := f.Object() r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). ContinueOnError(). NamespaceParam(cmdNamespace).DefaultNamespace(). ResourceTypeOrNameArgs(false, args...). FilenameParam(enforceNamespace, filenames...). SelectorParam(cmdutil.GetFlagString(cmd, "selector")). SelectAllParam(cmdutil.GetFlagBool(cmd, "all")). Flatten(). Do() if r.Err() != nil { return r.Err() } return ReapResult(r, f, out, false, cmdutil.GetFlagBool(cmd, "ignore-not-found"), cmdutil.GetFlagDuration(cmd, "timeout"), cmdutil.GetFlagInt(cmd, "grace-period")) }
func RunDelete(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, filenames util.StringList, shortOutput bool) error { cmdNamespace, enforceNamespace, err := f.DefaultNamespace() if err != nil { return err } deleteAll := cmdutil.GetFlagBool(cmd, "all") mapper, typer := f.Object() r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). ContinueOnError(). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(enforceNamespace, filenames...). SelectorParam(cmdutil.GetFlagString(cmd, "selector")). SelectAllParam(deleteAll). ResourceTypeOrNameArgs(false, args...).RequireObject(false). Flatten(). Do() err = r.Err() if err != nil { return err } ignoreNotFound := cmdutil.GetFlagBool(cmd, "ignore-not-found") if deleteAll { f := cmd.Flags().Lookup("ignore-not-found") // The flag should never be missing if f == nil { return fmt.Errorf("missing --ignore-not-found flag") } // If the user didn't explicitly set the option, default to ignoring NotFound errors when used with --all if !f.Changed { ignoreNotFound = true } } // By default use a reaper to delete all related resources. if cmdutil.GetFlagBool(cmd, "cascade") { return ReapResult(r, f, out, cmdutil.GetFlagBool(cmd, "cascade"), ignoreNotFound, cmdutil.GetFlagDuration(cmd, "timeout"), cmdutil.GetFlagInt(cmd, "grace-period"), shortOutput, mapper) } return DeleteResult(r, out, ignoreNotFound, shortOutput, mapper) }
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() 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 } 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 }
func RunReplace(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, filenames util.StringList) error { if os.Args[1] == "update" { printDeprecationWarning("replace", "update") } schema, err := f.Validator() if err != nil { return err } cmdNamespace, enforceNamespace, err := f.DefaultNamespace() if err != nil { return err } force := cmdutil.GetFlagBool(cmd, "force") if len(filenames) == 0 { return cmdutil.UsageError(cmd, "Must specify --filename to replace") } if force { return forceReplace(f, out, cmd, args, filenames) } mapper, typer := f.Object() r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). Schema(schema). ContinueOnError(). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(enforceNamespace, 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 cmdutil.AddSourceToErr("replacing", info.Source, err) } obj, err := resource.NewHelper(info.Client, info.Mapping).Replace(info.Namespace, info.Name, true, data) if err != nil { return cmdutil.AddSourceToErr("replacing", info.Source, err) } info.Refresh(obj, true) printObjectSpecificMessage(obj, out) fmt.Fprintf(out, "%s/%s\n", info.Mapping.Resource, info.Name) return nil }) }
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() if err != nil { return err } kubectl.GetVersion(out, client) return 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() if err != nil { return err } mapper, _ := f.Object() // TODO: use resource.Builder instead mapping, namespace, name, err := util.ResourceFromArgs(cmd, res, mapper, cmdNamespace) if err != nil { return err } client, err := f.RESTClient(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 }
// validateFlags filters out flags that are not supposed to be used // when exposing a resource; depends on the provided generator func validateFlags(cmd *cobra.Command, generator string) error { invalidFlags := []string{} if generator == "service/v1" { if len(cmdutil.GetFlagString(cmd, "hostname")) != 0 { invalidFlags = append(invalidFlags, "--hostname") } } else if generator == "route/v1" { if len(cmdutil.GetFlagString(cmd, "protocol")) != 0 { invalidFlags = append(invalidFlags, "--protocol") } if len(cmdutil.GetFlagString(cmd, "type")) != 0 { invalidFlags = append(invalidFlags, "--type") } if len(cmdutil.GetFlagString(cmd, "selector")) != 0 { invalidFlags = append(invalidFlags, "--selector") } if len(cmdutil.GetFlagString(cmd, "container-port")) != 0 { invalidFlags = append(invalidFlags, "--container-port") } if len(cmdutil.GetFlagString(cmd, "target-port")) != 0 { invalidFlags = append(invalidFlags, "--target-port") } if len(cmdutil.GetFlagString(cmd, "public-ip")) != 0 { invalidFlags = append(invalidFlags, "--public-ip") } if cmdutil.GetFlagInt(cmd, "port") != -1 { invalidFlags = append(invalidFlags, "--port") } if cmdutil.GetFlagBool(cmd, "create-external-load-balancer") { invalidFlags = append(invalidFlags, "--create-external-load-balancer") } } msg := "" switch len(invalidFlags) { case 0: return nil case 1: msg = invalidFlags[0] default: commaSeparated, last := invalidFlags[:len(invalidFlags)-1], invalidFlags[len(invalidFlags)-1] msg = fmt.Sprintf("%s or %s", strings.Join(commaSeparated, ", "), last) } return fmt.Errorf("cannot use %s when generating a %s", msg, strings.Split(generator, "/")[0]) }
func RunProxy(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command) error { port := cmdutil.GetFlagInt(cmd, "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") { glog.Warning("Request filter disabled, your proxy is vulnerable to XSRF attacks, please be cautious") filter = nil } server, err := kubectl.NewProxyServer(port, cmdutil.GetFlagString(cmd, "www"), apiProxyPrefix, staticPrefix, filter, clientConfig) if err != nil { return err } // Separate listening from serving so we can report the bound port // when it is chosen by os (port == 0) l, err := server.Listen() if err != nil { glog.Fatal(err) } fmt.Fprintf(out, "Starting to serve on %s", l.Addr().String()) glog.Fatal(server.ServeOnListener(l)) return nil }
func (f *Factory) NewCmdStop(out io.Writer) *cobra.Command { flags := &struct { Filenames util.StringList }{} cmd := &cobra.Command{ Use: "stop (-f FILENAME | RESOURCE (ID | -l label | --all))", Short: "Gracefully shut down a resource by id or filename.", Long: stop_long, Example: stop_example, Run: func(cmd *cobra.Command, args []string) { cmdNamespace, err := f.DefaultNamespace() cmdutil.CheckErr(err) mapper, typer := f.Object() r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand(cmd)). ContinueOnError(). NamespaceParam(cmdNamespace).RequireNamespace(). ResourceTypeOrNameArgs(false, args...). FilenameParam(flags.Filenames...). SelectorParam(cmdutil.GetFlagString(cmd, "selector")). SelectAllParam(cmdutil.GetFlagBool(cmd, "all")). Flatten(). Do() cmdutil.CheckErr(r.Err()) r.Visit(func(info *resource.Info) error { reaper, err := f.Reaper(info.Mapping) cmdutil.CheckErr(err) s, err := reaper.Stop(info.Namespace, info.Name) if err != nil { return err } fmt.Fprintf(out, "%s\n", s) return nil }) }, } cmd.Flags().VarP(&flags.Filenames, "filename", "f", "Filename, directory, or URL to file of resource(s) to be stopped") 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 *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, filenames util.StringList) error { cmdNamespace, err := f.DefaultNamespace() if err != nil { return err } mapper, typer := f.Object() r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). ContinueOnError(). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(filenames...). SelectorParam(cmdutil.GetFlagString(cmd, "selector")). SelectAllParam(cmdutil.GetFlagBool(cmd, "all")). ResourceTypeOrNameArgs(false, args...).RequireObject(false). 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/%s\n", r.Mapping.Resource, r.Name) return nil }) if err != nil { return err } if found == 0 { fmt.Fprintf(cmd.Out(), "No resources found\n") } return nil }
func RunProxy(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command) error { port := cmdutil.GetFlagInt(cmd, "port") fmt.Fprintf(out, "Starting to serve on localhost:%d", 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") { 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) if err != nil { return err } glog.Fatal(server.Serve(port)) return nil }
func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error { if 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, } 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 }
// NewCmdRollback creates a CLI rollback command. func NewCmdRollback(fullName string, f *clientcmd.Factory, out io.Writer) *cobra.Command { rollback := &deployapi.DeploymentConfigRollback{ Spec: deployapi.DeploymentConfigRollbackSpec{ IncludeTemplate: true, }, } cmd := &cobra.Command{ Use: "rollback DEPLOYMENT", Short: "Revert part of an application back to a previous deployment", Long: rollbackLong, Example: fmt.Sprintf(rollbackExample, fullName), Run: func(cmd *cobra.Command, args []string) { // Validate arguments if len(args) == 0 || len(args[0]) == 0 { cmdutil.CheckErr(cmdutil.UsageError(cmd, "A deployment name is required.")) } // Extract arguments format := cmdutil.GetFlagString(cmd, "output") template := cmdutil.GetFlagString(cmd, "template") dryRun := cmdutil.GetFlagBool(cmd, "dry-run") // Get globally provided stuff namespace, err := f.DefaultNamespace() cmdutil.CheckErr(err) oClient, kClient, err := f.Clients() cmdutil.CheckErr(err) // Set up the rollback config rollback.Spec.From.Name = args[0] // Make a helper and generate a rolled back config helper := newHelper(oClient, kClient) config, err := helper.Generate(namespace, rollback) cmdutil.CheckErr(err) // If this is a dry run, print and exit if dryRun { err := helper.Describe(config, out) cmdutil.CheckErr(err) return } // If an output format is specified, print and exit if len(format) > 0 { err := helper.Print(config, format, template, out) cmdutil.CheckErr(err) return } // Perform the rollback rolledback, err := helper.Update(config) cmdutil.CheckErr(err) // Notify the user of any disabled image triggers fmt.Fprintf(out, "#%d rolled back to %s\n", rolledback.LatestVersion, rollback.Spec.From.Name) for _, trigger := range rolledback.Triggers { disabled := []string{} if trigger.Type == deployapi.DeploymentTriggerOnImageChange && !trigger.ImageChangeParams.Automatic { disabled = append(disabled, trigger.ImageChangeParams.From.Name) } if len(disabled) > 0 { reenable := fmt.Sprintf("%s deploy %s --enable-triggers", fullName, rolledback.Name) fmt.Fprintf(cmd.Out(), "Warning: the following images triggers were disabled: %s\n You can re-enable them with: %s\n", strings.Join(disabled, ","), reenable) } } }, } cmd.Flags().BoolVar(&rollback.Spec.IncludeTriggers, "change-triggers", false, "Include the previous deployment's triggers in the rollback") cmd.Flags().BoolVar(&rollback.Spec.IncludeStrategy, "change-strategy", false, "Include the previous deployment's strategy in the rollback") cmd.Flags().BoolVar(&rollback.Spec.IncludeReplicationMeta, "change-scaling-settings", false, "Include the previous deployment's replicationController replica count and selector in the rollback") cmd.Flags().BoolP("dry-run", "d", false, "Instead of performing the rollback, describe what the rollback will look like in human-readable form") cmd.Flags().StringP("output", "o", "", "Instead of performing the rollback, print the updated deployment configuration in the specified format (json|yaml|template|templatefile)") cmd.Flags().StringP("template", "t", "", "Template string or path to template file to use when -o=template or -o=templatefile.") 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() 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) } 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() 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() }
// RunBuildChain contains all the necessary functionality for the OpenShift // experimental build-chain command func RunBuildChain(f *clientcmd.Factory, cmd *cobra.Command, args []string) error { all := cmdutil.GetFlagBool(cmd, "all") allTags := cmdutil.GetFlagBool(cmd, "all-tags") if len(args) > 1 || (len(args) == 1 && all) || (len(args) == 0 && allTags) || (all && allTags) { return cmdutil.UsageError(cmd, "Must pass nothing, an ImageStream name:tag combination, or specify the --all flag") } oc, _, err := f.Clients() if err != nil { return err } // Retrieve namespace(s) namespace := cmdutil.GetFlagString(cmd, "namespace") if len(namespace) == 0 { namespace, err = f.DefaultNamespace() if err != nil { return err } } namespaces := make([]string, 0) if all { projectList, err := oc.Projects().List(labels.Everything(), fields.Everything()) if err != nil { return err } for _, project := range projectList.Items { glog.V(4).Infof("Found namespace %s", project.Name) namespaces = append(namespaces, project.Name) } } if len(namespaces) == 0 { namespaces = append(namespaces, namespace) } // Get all build configurations buildConfigList := make([]buildapi.BuildConfig, 0) for _, namespace := range namespaces { cfgList, err := oc.BuildConfigs(namespace).List(labels.Everything(), fields.Everything()) if err != nil { return err } buildConfigList = append(buildConfigList, cfgList.Items...) } // Parse user input and validate specified image stream streams := make(map[string][]string) if !all && len(args) != 0 { name, specifiedTag, err := parseTag(args[0]) if err != nil { return err } // Validate the specified image stream is, err := oc.ImageStreams(namespace).Get(name) if err != nil { return err } stream := join(namespace, name) // Validate specified tag tags := make([]string, 0) exists := false for tag := range is.Status.Tags { tags = append(tags, tag) if specifiedTag == tag { exists = true } } if !exists && !allTags { // The specified tag isn't a part of our image stream return fmt.Errorf("no tag %s exists in %s", specifiedTag, stream) } else if !allTags { // Use only the specified tag tags = []string{specifiedTag} } // Set the specified stream as the only one to output dependencies for streams[stream] = tags } else { streams = getStreams(buildConfigList) } if len(streams) == 0 { return fmt.Errorf("no ImageStream available for building its dependency tree") } output := cmdutil.GetFlagString(cmd, "output") for stream, tags := range streams { for _, tag := range tags { glog.V(4).Infof("Checking dependencies of stream %s tag %s", stream, tag) root, err := findStreamDeps(stream, tag, buildConfigList) if err != nil { return err } // Check if the given image stream doesn't have any dependencies if treeSize(root) < 2 { glog.Infof("%s:%s has no dependencies\n", root.FullName, tag) continue } switch output { case "json": jsonDump, err := json.MarshalIndent(root, "", "\t") if err != nil { return err } fmt.Println(string(jsonDump)) case "dot": g := dot.NewGraph() _, name, err := split(stream) if err != nil { return err } graphName := validDOT(name) g.SetName(graphName) // Directed graph since we illustrate dependencies g.SetDir(true) // Explicitly allow multiple pairs of edges between // the same pair of nodes g.SetStrict(false) out, err := dotDump(root, g, graphName) if err != nil { return err } fmt.Println(out) case "ast": fmt.Println(root) default: return cmdutil.UsageError(cmd, "Wrong output format specified: %s", output) } } } return nil }
func RunExpose(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error { namespace, _, err := f.DefaultNamespace() if err != nil { return err } mapper, typer := f.Object() r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). ContinueOnError(). NamespaceParam(namespace).DefaultNamespace(). ResourceTypeOrNameArgs(false, args...). Flatten(). Do() err = r.Err() if err != nil { return err } mapping, err := r.ResourceMapping() if err != nil { return err } infos, err := r.Infos() if err != nil { return err } if len(infos) > 1 { return fmt.Errorf("multiple resources provided: %v", args) } info := infos[0] // Get the input object client, err := f.RESTClient(mapping) if err != nil { return err } inputObject, err := resource.NewHelper(client, mapping).Get(info.Namespace, info.Name) if err != nil { return err } // Get the generator, setup and validate all required parameters generatorName := cmdutil.GetFlagString(cmd, "generator") generator, found := f.Generator(generatorName) if !found { return cmdutil.UsageError(cmd, fmt.Sprintf("generator %q not found.", generatorName)) } names := generator.ParamNames() params := kubectl.MakeParams(cmd, names) params["default-name"] = info.Name if s, found := params["selector"]; !found || len(s) == 0 || cmdutil.GetFlagInt(cmd, "port") < 1 { if len(s) == 0 { s, err := f.PodSelectorForObject(inputObject) if err != nil { return cmdutil.UsageError(cmd, fmt.Sprintf("couldn't find selectors via --selector flag or introspection: %s", err)) } params["selector"] = s } noPorts := true for _, param := range names { if param.Name == "port" { noPorts = false break } } if cmdutil.GetFlagInt(cmd, "port") < 0 && !noPorts { ports, err := f.PortsForObject(inputObject) if err != nil { return cmdutil.UsageError(cmd, fmt.Sprintf("couldn't find port via --port flag or introspection: %s", err)) } switch len(ports) { case 0: return cmdutil.UsageError(cmd, "couldn't find port via --port flag or introspection") case 1: params["port"] = ports[0] default: return cmdutil.UsageError(cmd, fmt.Sprintf("multiple ports to choose from: %v, please explicitly specify a port using the --port flag.", ports)) } } } if cmdutil.GetFlagBool(cmd, "create-external-load-balancer") { params["create-external-load-balancer"] = "true" } if len(params["labels"]) == 0 { labels, err := f.LabelsForObject(inputObject) if err != nil { return err } params["labels"] = kubectl.MakeLabels(labels) } if v := cmdutil.GetFlagString(cmd, "type"); v != "" { params["type"] = v } err = kubectl.ValidateParams(names, params) if err != nil { return err } // Expose new object object, err := generator.Generate(params) if err != nil { return err } inline := cmdutil.GetFlagString(cmd, "overrides") if len(inline) > 0 { object, err = cmdutil.Merge(object, inline, mapping.Kind) 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{typer, mapper, f.ClientMapperForCommand()} info, err := resourceMapper.InfoForObject(object) if err != nil { return err } data, err := info.Mapping.Codec.Encode(object) if err != nil { return err } _, err = resource.NewHelper(info.Client, info.Mapping).Create(namespace, false, data) if err != nil { return err } } return f.PrintObject(cmd, object, out) }
func forceReplace(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, filenames util.StringList) error { schema, err := f.Validator() if err != nil { return err } cmdNamespace, enforceNamespace, err := f.DefaultNamespace() if err != nil { return err } mapper, typer := f.Object() r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). ContinueOnError(). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(enforceNamespace, filenames...). ResourceTypeOrNameArgs(false, args...).RequireObject(false). Flatten(). Do() err = r.Err() if err != nil { return err } //Replace will create a resource if it doesn't exist already, so ignore not found error ignoreNotFound := true // By default use a reaper to delete all related resources. if cmdutil.GetFlagBool(cmd, "cascade") { glog.Warningf("\"cascade\" is set, kubectl will delete and re-create all resources managed by this resource (e.g. Pods created by a ReplicationController). Consider using \"kubectl rolling-update\" if you want to update a ReplicationController together with its Pods.") err = ReapResult(r, f, out, cmdutil.GetFlagBool(cmd, "cascade"), ignoreNotFound, cmdutil.GetFlagDuration(cmd, "timeout"), cmdutil.GetFlagInt(cmd, "grace-period")) } else { err = DeleteResult(r, out, ignoreNotFound) } if err != nil { return err } r = resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). Schema(schema). ContinueOnError(). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(enforceNamespace, 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 } obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, data) if err != nil { return err } count++ info.Refresh(obj, true) printObjectSpecificMessage(obj, out) fmt.Fprintf(out, "%s/%s\n", info.Mapping.Resource, info.Name) return nil }) if err != nil { return err } if count == 0 { return fmt.Errorf("no objects passed to replace") } return nil }
// RunProject contains all the necessary functionality for the OpenShift cli process command func RunProcess(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string) error { storedTemplate := "" if len(args) > 0 { storedTemplate = args[0] } filename := kcmdutil.GetFlagString(cmd, "filename") if len(storedTemplate) == 0 && len(filename) == 0 { return kcmdutil.UsageError(cmd, "Must pass a filename or name of stored template") } namespace, err := f.DefaultNamespace() if err != nil { return err } mapper, typer := f.Object() client, _, err := f.Clients() if err != nil { return err } var ( objects []runtime.Object infos []*resource.Info mapping *meta.RESTMapping ) version, kind, err := mapper.VersionAndKindForResource("template") if mapping, err = mapper.RESTMapping(kind, version); err != nil { return err } // When storedTemplate is not empty, then we fetch the template from the // server, otherwise we require to set the `-f` parameter. if len(storedTemplate) > 0 { templateObj, err := client.Templates(namespace).Get(storedTemplate) if err != nil { if errors.IsNotFound(err) { return fmt.Errorf("template %q could not be found", storedTemplate) } return err } templateObj.CreationTimestamp = util.Now() infos = append(infos, &resource.Info{Object: templateObj}) } else { infos, err = resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). NamespaceParam(namespace).RequireNamespace(). FilenameParam(filename). Do(). Infos() if err != nil { return err } } outputFormat := kcmdutil.GetFlagString(cmd, "output") for i := range infos { obj, ok := infos[i].Object.(*api.Template) if !ok { sourceName := filename if len(storedTemplate) > 0 { sourceName = namespace + "/" + storedTemplate } fmt.Fprintf(cmd.Out(), "unable to parse %q, not a valid Template but %s\n", sourceName, reflect.TypeOf(infos[i].Object)) continue } // If 'parameters' flag is set it does not do processing but only print // the template parameters to console for inspection. // If multiple templates are passed, this will print combined output for all // templates. if kcmdutil.GetFlagBool(cmd, "parameters") { if len(infos) > 1 { fmt.Fprintf(out, "\n%s:\n", obj.Name) } if err := describe.PrintTemplateParameters(obj.Parameters, out); err != nil { fmt.Fprintf(cmd.Out(), "error printing parameters for %q: %v\n", obj.Name, err) } continue } if label := kcmdutil.GetFlagString(cmd, "labels"); len(label) > 0 { lbl, err := kubectl.ParseLabels(label) if err != nil { fmt.Fprintf(cmd.Out(), "error parsing labels: %v\n", err) continue } if obj.ObjectLabels == nil { obj.ObjectLabels = make(map[string]string) } for key, value := range lbl { obj.ObjectLabels[key] = value } } // Override the values for the current template parameters // when user specify the --value if cmd.Flag("value").Changed { injectUserVars(cmd, obj) } resultObj, err := client.TemplateConfigs(namespace).Create(obj) if err != nil { fmt.Fprintf(cmd.Out(), "error processing the template %q: %v\n", obj.Name, err) continue } if outputFormat == "describe" { if s, err := (&describe.TemplateDescriber{ MetadataAccessor: meta.NewAccessor(), ObjectTyper: kapi.Scheme, ObjectDescriber: nil, }).DescribeTemplate(resultObj); err != nil { fmt.Fprintf(cmd.Out(), "error describing %q: %v\n", obj.Name, err) } else { fmt.Fprintf(out, s) } continue } objects = append(objects, resultObj.Objects...) } // Do not print the processed templates when asked to only show parameters or // describe. if kcmdutil.GetFlagBool(cmd, "parameters") || outputFormat == "describe" { return nil } p, _, err := kubectl.GetPrinter(outputFormat, "") if err != nil { return err } p = kubectl.NewVersionedPrinter(p, kapi.Scheme, kcmdutil.OutputVersion(cmd, mapping.APIVersion)) // use generic output if kcmdutil.GetFlagBool(cmd, "raw") { for i := range objects { p.PrintObj(objects[i], out) } return nil } return p.PrintObj(&kapi.List{ ListMeta: kapi.ListMeta{}, Items: objects, }, out) }
func RunExport(f *clientcmd.Factory, exporter Exporter, in io.Reader, out io.Writer, cmd *cobra.Command, args []string, filenames util.StringList) error { selector := cmdutil.GetFlagString(cmd, "selector") all := cmdutil.GetFlagBool(cmd, "all") exact := cmdutil.GetFlagBool(cmd, "exact") asTemplate := cmdutil.GetFlagString(cmd, "as-template") raw := cmdutil.GetFlagBool(cmd, "raw") if exact && raw { return cmdutil.UsageError(cmd, "--exact and --raw may not both be specified") } clientConfig, err := f.ClientConfig() if err != nil { return err } outputVersion := cmdutil.OutputVersion(cmd, clientConfig.Version) cmdNamespace, explicit, err := f.DefaultNamespace() if err != nil { return err } mapper, typer := f.Object() b := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(explicit, filenames...). SelectorParam(selector). ResourceTypeOrNameArgs(all, args...). Flatten() one := false infos, err := b.Do().IntoSingular(&one).Infos() if err != nil { return err } if len(infos) == 0 { return fmt.Errorf("no resources found - nothing to export") } if !raw { newInfos := []*resource.Info{} errs := []error{} for _, info := range infos { if err := exporter.Export(info.Object, exact); err != nil { if err == ErrExportOmit { continue } errs = append(errs, err) } newInfos = append(newInfos, info) } if len(errs) > 0 { return utilerrors.NewAggregate(errs) } infos = newInfos } var result runtime.Object if len(asTemplate) > 0 { objects, err := resource.AsVersionedObjects(infos, outputVersion) if err != nil { return err } template := &templateapi.Template{ Objects: objects, } template.Name = asTemplate result, err = kapi.Scheme.ConvertToVersion(template, outputVersion) if err != nil { return err } } else { object, err := resource.AsVersionedObject(infos, !one, outputVersion) if err != nil { return err } result = object } // use YAML as the default format outputFormat := cmdutil.GetFlagString(cmd, "output") templateFile := cmdutil.GetFlagString(cmd, "template") if len(outputFormat) == 0 && len(templateFile) != 0 { outputFormat = "template" } if len(outputFormat) == 0 { outputFormat = "yaml" } p, _, err := kubectl.GetPrinter(outputFormat, templateFile) if err != nil { return err } return p.PrintObj(result, out) }
// 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) error { selector := cmdutil.GetFlagString(cmd, "selector") allNamespaces := cmdutil.GetFlagBool(cmd, "all-namespaces") mapper, typer := f.Object() cmdNamespace, _, err := f.DefaultNamespace() if err != nil { return err } if len(args) == 0 { fmt.Fprint(out, ` You must specify the type of resource to get. Valid resource types include: * pods (aka 'po') * replicationcontrollers (aka 'rc') * services * nodes (aka 'no') * events (aka 'ev') * secrets * limits * persistentVolumes (aka 'pv') * persistentVolumeClaims (aka 'pvc') * quota `) return errors.New("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). SelectorParam(selector). ResourceTypeOrNameArgs(true, args...). SingleResourceType(). Do() if err != nil { return err } mapping, err := r.ResourceMapping() if err != nil { return err } 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). 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 return b.Do().Visit(func(r *resource.Info) error { printer, err := f.PrinterForMapping(cmd, r.Mapping, allNamespaces) if err != nil { return err } return printer.PrintObj(r.Object, out) }) }
// RunEnv contains all the necessary functionality for the OpenShift cli env command func RunEnv(f *clientcmd.Factory, in io.Reader, out io.Writer, cmd *cobra.Command, args []string, envParams, filenames kutil.StringList) error { resources, envArgs := []string{}, []string{} first := true for _, s := range args { isEnv := strings.Contains(s, "=") || strings.HasSuffix(s, "-") switch { case first && isEnv: first = false fallthrough case !first && isEnv: envArgs = append(envArgs, s) case first && !isEnv: resources = append(resources, s) case !first && !isEnv: return cmdutil.UsageError(cmd, "all resources must be specified before environment changes: %s", s) } } if len(filenames) == 0 && len(resources) < 1 { return cmdutil.UsageError(cmd, "one or more resources must be specified as <resource> <name> or <resource>/<name>") } containerMatch := cmdutil.GetFlagString(cmd, "containers") list := cmdutil.GetFlagBool(cmd, "list") selector := cmdutil.GetFlagString(cmd, "selector") all := cmdutil.GetFlagBool(cmd, "all") //overwrite := cmdutil.GetFlagBool(cmd, "overwrite") resourceVersion := cmdutil.GetFlagString(cmd, "resource-version") outputFormat := cmdutil.GetFlagString(cmd, "output") if list && len(outputFormat) > 0 { return cmdutil.UsageError(cmd, "--list and --output may not be specified together") } clientConfig, err := f.ClientConfig() if err != nil { return err } outputVersion := cmdutil.OutputVersion(cmd, clientConfig.Version) cmdNamespace, err := f.DefaultNamespace() if err != nil { return err } env, remove, err := parseEnv(append(envParams, envArgs...), in) if err != nil { return err } mapper, typer := f.Object() b := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). ContinueOnError(). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(filenames...). SelectorParam(selector). ResourceTypeOrNameArgs(all, resources...). Flatten() one := false infos, err := b.Do().IntoSingular(&one).Infos() if err != nil { return err } // only apply resource version locking on a single resource if !one && len(resourceVersion) > 0 { return cmdutil.UsageError(cmd, "--resource-version may only be used with a single resource") } skipped := 0 for _, info := range infos { ok, err := f.UpdatePodSpecForObject(info.Object, func(spec *kapi.PodSpec) error { containers, _ := selectContainers(spec.Containers, containerMatch) if len(containers) == 0 { fmt.Fprintf(cmd.Out(), "warning: %s/%s does not have any containers matching %q\n", info.Mapping.Resource, info.Name, containerMatch) return nil } for _, c := range containers { c.Env = updateEnv(c.Env, env, remove) if list { fmt.Fprintf(out, "# %s %s, container %s\n", info.Mapping.Resource, info.Name, c.Name) for _, env := range c.Env { // if env.ValueFrom != nil && env.ValueFrom.FieldRef != nil { // fmt.Fprintf(cmd.Out(), "%s= # calculated from pod %s %s\n", env.Name, env.ValueFrom.FieldRef.FieldPath, env.ValueFrom.FieldRef.APIVersion) // continue // } fmt.Fprintf(out, "%s=%s\n", env.Name, env.Value) } } } return nil }) if !ok { skipped++ continue } if err != nil { fmt.Fprintf(cmd.Out(), "error: %s/%s %v\n", info.Mapping.Resource, info.Name, err) continue } } if one && skipped == len(infos) { return fmt.Errorf("the %s %s is not a pod or does not have a pod template", infos[0].Mapping.Resource, infos[0].Name) } if list { return nil } objects, err := resource.AsVersionedObject(infos, false, outputVersion) if err != nil { return err } if len(outputFormat) != 0 { p, _, err := kubectl.GetPrinter(outputFormat, "") if err != nil { return err } return p.PrintObj(objects, out) } failed := false for _, info := range infos { data, err := info.Mapping.Codec.Encode(info.Object) if err != nil { fmt.Fprintf(cmd.Out(), "Error: %v\n", err) failed = true continue } obj, err := resource.NewHelper(info.Client, info.Mapping).Update(info.Namespace, info.Name, true, data) if err != nil { handlePodUpdateError(cmd.Out(), err, "environment variables") failed = true continue } info.Refresh(obj, true) fmt.Fprintf(out, "%s/%s\n", info.Mapping.Resource, info.Name) } if failed { return errExit } return nil }
// RunCancelBuild contains all the necessary functionality for the OpenShift cli cancel-build command func RunCancelBuild(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string) error { if len(args) == 0 || len(args[0]) == 0 { return cmdutil.UsageError(cmd, "You must specify the name of a build to cancel.") } buildName := args[0] namespace, _, err := f.DefaultNamespace() if err != nil { return err } client, _, err := f.Clients() if err != nil { return err } buildClient := client.Builds(namespace) build, err := buildClient.Get(buildName) if err != nil { return err } if !isBuildCancellable(build) { return nil } // Print build logs before cancelling build. if cmdutil.GetFlagBool(cmd, "dump-logs") { opts := buildapi.BuildLogOptions{ NoWait: true, Follow: false, } response, err := client.BuildLogs(namespace).Get(buildName, opts).Do().Raw() if err != nil { glog.Errorf("Could not fetch build logs for %s: %v", buildName, err) } else { glog.Infof("Build logs for %s:\n%v", buildName, string(response)) } } // Mark build to be cancelled. for { build.Status.Cancelled = true if _, err = buildClient.Update(build); err != nil && errors.IsConflict(err) { build, err = buildClient.Get(buildName) if err != nil { return err } continue } if err != nil { return err } break } glog.V(2).Infof("Build %s was cancelled.", buildName) // Create a new build with the same configuration. if cmdutil.GetFlagBool(cmd, "restart") { request := &buildapi.BuildRequest{ ObjectMeta: kapi.ObjectMeta{Name: build.Name}, } newBuild, err := client.Builds(namespace).Clone(request) if err != nil { return err } glog.V(2).Infof("Restarted build %s.", buildName) fmt.Fprintf(out, "%s\n", newBuild.Name) } else { fmt.Fprintf(out, "%s\n", build.Name) } return nil }
func RunLabel(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error { resources, labelArgs := []string{}, []string{} first := true for _, s := range args { isLabel := strings.Contains(s, "=") || strings.HasSuffix(s, "-") switch { case first && isLabel: first = false fallthrough case !first && isLabel: labelArgs = append(labelArgs, s) case first && !isLabel: resources = append(resources, s) case !first && !isLabel: return cmdutil.UsageError(cmd, "all resources must be specified before label changes: %s", s) } } if len(resources) < 1 { return cmdutil.UsageError(cmd, "one or more resources must be specified as <resource> <name> or <resource>/<name>") } if len(labelArgs) < 1 { return cmdutil.UsageError(cmd, "at least one label update is required") } selector := cmdutil.GetFlagString(cmd, "selector") all := cmdutil.GetFlagBool(cmd, "all") overwrite := cmdutil.GetFlagBool(cmd, "overwrite") resourceVersion := cmdutil.GetFlagString(cmd, "resource-version") cmdNamespace, err := f.DefaultNamespace() if err != nil { return err } labels, remove, err := parseLabels(labelArgs) if err != nil { return cmdutil.UsageError(cmd, err.Error()) } mapper, typer := f.Object() b := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). ContinueOnError(). NamespaceParam(cmdNamespace).DefaultNamespace(). SelectorParam(selector). ResourceTypeOrNameArgs(all, resources...). Flatten(). Latest() one := false r := b.Do().IntoSingular(&one) if err := r.Err(); err != nil { return err } // only apply resource version locking on a single resource if !one && len(resourceVersion) > 0 { return cmdutil.UsageError(cmd, "--resource-version may only be used with a single resource") } // TODO: support bulk generic output a la Get return r.Visit(func(info *resource.Info) error { obj, err := updateObject(info, 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, info.Mapping, false) if err != nil { return err } return printer.PrintObj(obj, out) }) }
// 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 } var container string if cmdutil.GetFlagString(cmd, "container") != "" { // [-c CONTAINER] container = p.containerName } else { // [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 { return fmt.Errorf("POD %s has more than one container; please specify the container to print logs for", pod.ObjectMeta.Name) } 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 } readCloser, err := client.RESTClient.Get(). Namespace(namespace). Name(podID). Resource("pods"). SubResource("log"). Param("follow", strconv.FormatBool(follow)). Param("container", container). Param("previous", strconv.FormatBool(previous)). Stream() if err != nil { return err } defer readCloser.Close() _, err = io.Copy(out, readCloser) return err }