// PrinterForCommand returns the default printer for this command. // Requires that printer flags have been added to cmd (see AddPrinterFlags). func PrinterForCommand(cmd *cobra.Command) (kubectl.ResourcePrinter, bool, error) { outputFormat := GetFlagString(cmd, "output") // templates are logically optional for specifying a format. // TODO once https://github.com/kubernetes/kubernetes/issues/12668 is fixed, this should fall back to GetFlagString templateFile, _ := cmd.Flags().GetString("template") if len(outputFormat) == 0 && len(templateFile) != 0 { outputFormat = "template" } templateFormat := []string{"go-template=", "go-template-file=", "jsonpath=", "jsonpath-file="} for _, format := range templateFormat { if strings.HasPrefix(outputFormat, format) { templateFile = outputFormat[len(format):] outputFormat = format[:len(format)-1] } } printer, generic, err := kubectl.GetPrinter(outputFormat, templateFile) if err != nil { return nil, generic, err } return maybeWrapSortingPrinter(cmd, printer), generic, nil }
// PrinterForCommand returns the default printer for this command. // Requires that printer flags have been added to cmd (see AddPrinterFlags). func PrinterForCommand(cmd *cobra.Command) (kubectl.ResourcePrinter, bool, error) { outputFormat := GetFlagString(cmd, "output") // templates are logically optional for specifying a format. // TODO once https://github.com/kubernetes/kubernetes/issues/12668 is fixed, this should fall back to GetFlagString templateFile, _ := cmd.Flags().GetString("template") if len(outputFormat) == 0 && len(templateFile) != 0 { outputFormat = "template" } templateFormat := []string{ "go-template=", "go-template-file=", "jsonpath=", "jsonpath-file=", "custom-columns=", "custom-columns-file=", } for _, format := range templateFormat { if strings.HasPrefix(outputFormat, format) { templateFile = outputFormat[len(format):] outputFormat = format[:len(format)-1] } } // this function may be invoked by a command that did not call AddPrinterFlags first, so we need // to be safe about how we access the allow-missing-template-keys flag allowMissingTemplateKeys := false if cmd.Flags().Lookup("allow-missing-template-keys") != nil { allowMissingTemplateKeys = GetFlagBool(cmd, "allow-missing-template-keys") } printer, generic, err := kubectl.GetPrinter(outputFormat, templateFile, GetFlagBool(cmd, "no-headers"), allowMissingTemplateKeys) if err != nil { return nil, generic, err } return maybeWrapSortingPrinter(cmd, printer), generic, nil }
// PrinterForCommand returns the default printer for this command. // Requires that printer flags have been added to cmd (see AddPrinterFlags). func PrinterForCommand(cmd *cobra.Command) (kubectl.ResourcePrinter, bool, error) { outputFormat := GetFlagString(cmd, "output") templateFile := GetFlagString(cmd, "template") if len(outputFormat) == 0 && len(templateFile) != 0 { outputFormat = "template" } return kubectl.GetPrinter(outputFormat, templateFile) }
// PrinterForCommand returns the default printer for this command. // Requires that printer flags have been added to cmd (see AddPrinterFlags). func PrinterForCommand(cmd *cobra.Command) (kubectl.ResourcePrinter, bool, error) { outputFormat := GetFlagString(cmd, "output") // TODO this is a bandaid until https://github.com/kubernetes/kubernetes/issues/12668 is fixed templateFile, _ := cmd.Flags().GetString("template") if len(outputFormat) == 0 && len(templateFile) != 0 { outputFormat = "template" } return kubectl.GetPrinter(outputFormat, templateFile) }
// Complete collects information required to run Convert command from command line. func (o *ConvertOptions) Complete(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) (err error) { o.outputVersion, err = cmdutil.OutputVersion(cmd, ®istered.EnabledVersionsForGroup(api.GroupName)[0]) if err != nil { return err } if !registered.IsEnabledVersion(o.outputVersion) { cmdutil.UsageError(cmd, "'%s' is not a registered version.", o.outputVersion) } // build the builder mapper, typer := f.Object(cmdutil.GetIncludeThirdPartyAPIs(cmd)) clientMapper := resource.ClientMapperFunc(f.ClientForMapping) if o.local { fmt.Fprintln(os.Stderr, "running in local mode...") o.builder = resource.NewBuilder(mapper, typer, resource.DisabledClientForMapping{ClientMapper: clientMapper}, f.Decoder(true)) } else { o.builder = resource.NewBuilder(mapper, typer, clientMapper, f.Decoder(true)) schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"), cmdutil.GetFlagString(cmd, "schema-cache-dir")) if err != nil { return err } o.builder = o.builder.Schema(schema) } cmdNamespace, _, err := f.DefaultNamespace() if err != nil { return err } o.builder = o.builder.NamespaceParam(cmdNamespace). ContinueOnError(). FilenameParam(false, o.recursive, o.filenames...). Flatten() // build the printer o.out = out outputFormat := cmdutil.GetFlagString(cmd, "output") templateFile := cmdutil.GetFlagString(cmd, "template") if len(outputFormat) == 0 { if len(templateFile) == 0 { outputFormat = "yaml" } else { outputFormat = "template" } } o.encoder = f.JSONEncoder() o.printer, _, err = kubectl.GetPrinter(outputFormat, templateFile, false) if err != nil { return err } return nil }
// PrinterForCommand returns the default printer for this command. // Requires that printer flags have been added to cmd (see AddPrinterFlags). func PrinterForCommand(cmd *cobra.Command) (kubectl.ResourcePrinter, bool, error) { outputFormat := GetFlagString(cmd, "output") templateFile := GetFlagString(cmd, "template") if len(outputFormat) == 0 && len(templateFile) != 0 { outputFormat = "template" } printer, generic, err := kubectl.GetPrinter(outputFormat, templateFile) if err != nil { return nil, generic, err } return maybeWrapSortingPrinter(cmd, printer), generic, nil }
// Complete collects information required to run Convert command from command line. func (o *ConvertOptions) Complete(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) (err error) { o.outputVersion = cmdutil.OutputVersion(cmd, latest.GroupOrDie("").Version) outputGV, err := unversioned.ParseGroupVersion(o.outputVersion) if err != nil { return fmt.Errorf("unable to parse group/version from %q: %v", o.outputVersion, err) } if !registered.IsRegisteredAPIGroupVersion(outputGV) { cmdutil.UsageError(cmd, "'%s' is not a registered version.", o.outputVersion) } // build the builder mapper, typer := f.Object() if o.local { fmt.Fprintln(out, "running in local mode...") o.builder = resource.NewBuilder(mapper, typer, f.NilClientMapperForCommand()) } else { o.builder = resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()) schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"), cmdutil.GetFlagString(cmd, "schema-cache-dir")) if err != nil { return err } o.builder = o.builder.Schema(schema) } cmdNamespace, _, err := f.DefaultNamespace() if err != nil { return err } o.builder = o.builder.NamespaceParam(cmdNamespace). ContinueOnError(). FilenameParam(false, o.filenames...). Flatten() // build the printer o.out = out outputFormat := cmdutil.GetFlagString(cmd, "output") templateFile := cmdutil.GetFlagString(cmd, "template") if len(outputFormat) == 0 { if len(templateFile) == 0 { outputFormat = "yaml" } else { outputFormat = "template" } } o.printer, _, err = kubectl.GetPrinter(outputFormat, templateFile) if err != nil { return err } return nil }
func (o *PatchOptions) RunPatch() error { patchBytes, err := yaml.ToJSON([]byte(o.Patch)) if err != nil { return fmt.Errorf("unable to parse %q: %v", o.Patch, err) } r := o.Builder. FilenameParam(false, false, o.Filename). Flatten(). Do() err = r.Err() if err != nil { return err } infos, err := r.Infos() if err != nil { return err } if len(infos) > 1 { return fmt.Errorf("multiple resources provided") } info := infos[0] originalObjJS, err := runtime.Encode(configapi.Codecs.LegacyCodec(info.Mapping.GroupVersionKind.GroupVersion()), info.VersionedObject.(runtime.Object)) if err != nil { return err } patchedObj, err := configapi.Scheme.DeepCopy(info.VersionedObject) if err != nil { return err } originalPatchedObjJS, err := getPatchedJS(o.PatchType, originalObjJS, patchBytes, patchedObj.(runtime.Object)) if err != nil { return err } rawExtension := &runtime.Unknown{ Raw: originalPatchedObjJS, } printer, _, err := kubectl.GetPrinter("yaml", "") if err != nil { return err } if err := printer.PrintObj(rawExtension, o.Out); err != nil { return err } return nil }
// PrinterForCommand returns the default printer for this command. // Requires that printer flags have been added to cmd (see AddPrinterFlags). func PrinterForCommand(cmd *cobra.Command) (kubectl.ResourcePrinter, bool, error) { outputFormat := GetFlagString(cmd, "output") // templates are logically optional for specifying a format. // TODO once https://github.com/kubernetes/kubernetes/issues/12668 is fixed, this should fall back to GetFlagString templateFile, _ := cmd.Flags().GetString("template") if len(outputFormat) == 0 && len(templateFile) != 0 { outputFormat = "template" } printer, generic, err := kubectl.GetPrinter(outputFormat, templateFile) if err != nil { return nil, generic, err } return maybeWrapSortingPrinter(cmd, printer), generic, nil }
func GenDocs(cmd *cobra.Command, filename string) error { out := new(bytes.Buffer) templateFile, err := filepath.Abs("hack/clibyexample/template") if err != nil { return err } template, err := ioutil.ReadFile(templateFile) if err != nil { return err } examples := extractExamples(cmd) items := []runtime.Object{} for _, example := range examples { items = append(items, example) } printer, _, err := kubectl.GetPrinter("template", string(template)) if err != nil { return err } err = printer.PrintObj(&kapi.List{ ListMeta: kapi.ListMeta{}, Items: items, }, out) if err != nil { return err } outFile, err := os.Create(filename) if err != nil { return err } defer outFile.Close() _, err = outFile.Write(out.Bytes()) if err != nil { return err } return nil }
func (o *NewGroupOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command, args []string) error { if len(args) < 1 { return errors.New("You must specify at least one argument: GROUP [USER ...]") } o.Group = args[0] if len(args) > 1 { o.Users = append(o.Users, args[1:]...) } osClient, _, err := f.Clients() if err != nil { return err } o.GroupClient = osClient.Groups() outputFormat := kcmdutil.GetFlagString(cmd, "output") templateFile := kcmdutil.GetFlagString(cmd, "template") noHeaders := kcmdutil.GetFlagBool(cmd, "no-headers") printer, _, err := kubectl.GetPrinter(outputFormat, templateFile, noHeaders) if err != nil { return err } if printer != nil { o.Printer = printer.PrintObj } else { o.Printer = func(obj runtime.Object, out io.Writer) error { mapper, _ := f.Object(false) return f.PrintObject(cmd, mapper, obj, out) } } return nil }
// RunEnv contains all the necessary functionality for the OpenShift cli env command // TODO: refactor to share the common "patch resource" pattern of probe func RunEnv(f *clientcmd.Factory, in io.Reader, out io.Writer, cmd *cobra.Command, args []string, envParams, filenames []string) error { resources, envArgs, ok := cmdutil.SplitEnvironmentFromResources(args) if !ok { return kcmdutil.UsageError(cmd, "all resources must be specified before environment changes: %s", strings.Join(args, " ")) } if len(filenames) == 0 && len(resources) < 1 { return kcmdutil.UsageError(cmd, "one or more resources must be specified as <resource> <name> or <resource>/<name>") } containerMatch := kcmdutil.GetFlagString(cmd, "containers") list := kcmdutil.GetFlagBool(cmd, "list") selector := kcmdutil.GetFlagString(cmd, "selector") all := kcmdutil.GetFlagBool(cmd, "all") //overwrite := kcmdutil.GetFlagBool(cmd, "overwrite") resourceVersion := kcmdutil.GetFlagString(cmd, "resource-version") outputFormat := kcmdutil.GetFlagString(cmd, "output") if list && len(outputFormat) > 0 { return kcmdutil.UsageError(cmd, "--list and --output may not be specified together") } clientConfig, err := f.ClientConfig() if err != nil { return err } cmdNamespace, explicit, err := f.DefaultNamespace() if err != nil { return err } env, remove, err := cmdutil.ParseEnv(append(envParams, envArgs...), in) if err != nil { return err } mapper, typer := f.Object() b := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), kapi.Codecs.UniversalDecoder()). ContinueOnError(). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(explicit, 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 kcmdutil.UsageError(cmd, "--resource-version may only be used with a single resource") } // Keep a copy of the original objects prior to updating their environment. // Used in constructing the patch(es) that will be applied in the server. oldObjects, err := resource.AsVersionedObjects(infos, clientConfig.GroupVersion.String(), kapi.Codecs.LegacyCodec(*clientConfig.GroupVersion)) if err != nil { return err } if len(oldObjects) != len(infos) { return fmt.Errorf("could not convert all objects to API version %q", clientConfig.GroupVersion) } oldData := make([][]byte, len(infos)) for i := range oldObjects { old, err := json.Marshal(oldObjects[i]) if err != nil { return err } oldData[i] = old } 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("%s/%s is not a pod or does not have a pod template", infos[0].Mapping.Resource, infos[0].Name) } if list { return nil } if len(outputFormat) != 0 { outputVersion, err := kcmdutil.OutputVersion(cmd, clientConfig.GroupVersion) if err != nil { return err } objects, err := resource.AsVersionedObjects(infos, outputVersion.String(), kapi.Codecs.LegacyCodec(outputVersion)) if err != nil { return err } if len(objects) != len(infos) { return fmt.Errorf("could not convert all objects to API version %q", outputVersion) } p, _, err := kubectl.GetPrinter(outputFormat, "") if err != nil { return err } for _, object := range objects { if err := p.PrintObj(object, out); err != nil { return err } } return nil } objects, err := resource.AsVersionedObjects(infos, clientConfig.GroupVersion.String(), kapi.Codecs.LegacyCodec(*clientConfig.GroupVersion)) if err != nil { return err } if len(objects) != len(infos) { return fmt.Errorf("could not convert all objects to API version %q", clientConfig.GroupVersion) } failed := false for i, info := range infos { newData, err := json.Marshal(objects[i]) if err != nil { return err } patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData[i], newData, objects[i]) if err != nil { return err } obj, err := resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, kapi.StrategicMergePatchType, patchBytes) if err != nil { handlePodUpdateError(cmd.Out(), err, "environment variables") failed = true continue } info.Refresh(obj, true) shortOutput := kcmdutil.GetFlagString(cmd, "output") == "name" kcmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, "updated") } if failed { return cmdutil.ErrExit } return nil }
func (v *VolumeOptions) RunVolume(args []string) error { mapper := resource.ClientMapperFunc(v.RESTClientFactory) b := resource.NewBuilder(v.Mapper, v.Typer, mapper). ContinueOnError(). NamespaceParam(v.DefaultNamespace).DefaultNamespace(). FilenameParam(v.ExplicitNamespace, v.Filenames...). SelectorParam(v.Selector). ResourceTypeOrNameArgs(v.All, args...). Flatten() singular := false infos, err := b.Do().IntoSingular(&singular).Infos() if err != nil { return err } updateInfos := []*resource.Info{} // if a claim should be created, generate the info we'll add to the flow if v.Add && v.AddOpts.CreateClaim { claim := v.AddOpts.createClaim() m, err := v.Mapper.RESTMapping("PersistentVolumeClaim") if err != nil { return err } client, err := mapper.ClientForMapping(m) if err != nil { return err } info := &resource.Info{ Mapping: m, Client: client, Namespace: v.DefaultNamespace, Object: claim, } infos = append(infos, info) updateInfos = append(updateInfos, info) } skipped := 0 for _, info := range infos { ok, err := v.UpdatePodSpecForObject(info.Object, func(spec *kapi.PodSpec) error { var e error switch { case v.Add: e = v.addVolumeToSpec(spec, info, singular) case v.Remove: e = v.removeVolumeFromSpec(spec, info) case v.List: e = v.listVolumeForSpec(spec, info) } return e }) if !ok { skipped++ continue } if err != nil { fmt.Fprintf(v.Err, "error: %s/%s %v\n", info.Mapping.Resource, info.Name, err) continue } updateInfos = append(updateInfos, info) } if singular && 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) } updatePodSpecFailed := len(updateInfos) != len(infos) if v.List { if updatePodSpecFailed { return errExit } return nil } objects, err := resource.AsVersionedObject(infos, false, v.OutputVersion) if err != nil { return err } if len(v.Output) != 0 { p, _, err := kubectl.GetPrinter(v.Output, "") if err != nil { return err } return p.PrintObj(objects, v.Out) } failed := false for _, info := range updateInfos { var obj runtime.Object if len(info.ResourceVersion) == 0 { obj, err = resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, false, info.Object) } else { obj, err = resource.NewHelper(info.Client, info.Mapping).Replace(info.Namespace, info.Name, true, info.Object) } if err != nil { handlePodUpdateError(v.Err, err, "volume") failed = true continue } info.Refresh(obj, true) fmt.Fprintf(v.Out, "%s/%s\n", info.Mapping.Resource, info.Name) } if failed || updatePodSpecFailed { return errExit } 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 { templateName, valueArgs := "", []string{} for _, s := range args { isValue := strings.Contains(s, "=") switch { case isValue: valueArgs = append(valueArgs, s) case !isValue && len(templateName) == 0: templateName = s case !isValue && len(templateName) > 0: return kcmdutil.UsageError(cmd, "template name must be specified only once: %s", s) } } filename := kcmdutil.GetFlagString(cmd, "filename") if len(templateName) == 0 && len(filename) == 0 { return kcmdutil.UsageError(cmd, "Must pass a filename or name of stored template") } if kcmdutil.GetFlagBool(cmd, "parameters") { for _, flag := range []string{"value", "labels", "output", "output-version", "raw", "template"} { if f := cmd.Flags().Lookup(flag); f != nil && f.Changed { return kcmdutil.UsageError(cmd, "The --parameters flag does not process the template, can't be used with --%v", flag) } } } namespace, explicit, 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, err := mapper.RESTMapping(templateapi.Kind("Template")) if err != nil { return err } // When templateName is not empty, then we fetch the template from the // server, otherwise we require to set the `-f` parameter. if len(templateName) > 0 { var ( storedTemplate, rs string sourceNamespace string ok bool ) sourceNamespace, rs, storedTemplate, ok = parseNamespaceResourceName(templateName, namespace) if !ok { return fmt.Errorf("invalid argument %q", templateName) } if len(rs) > 0 && (rs != "template" && rs != "templates") { return fmt.Errorf("unable to process invalid resource %q", rs) } if len(storedTemplate) == 0 { return fmt.Errorf("invalid value syntax %q", templateName) } templateObj, err := client.Templates(sourceNamespace).Get(storedTemplate) if err != nil { if errors.IsNotFound(err) { return fmt.Errorf("template %q could not be found", storedTemplate) } return err } templateObj.CreationTimestamp = unversioned.Now() infos = append(infos, &resource.Info{Object: templateObj}) } else { infos, err = resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), kapi.Codecs.UniversalDecoder()). NamespaceParam(namespace).RequireNamespace(). FilenameParam(explicit, filename). Do(). Infos() if err != nil { return err } } outputFormat := kcmdutil.GetFlagString(cmd, "output") for i := range infos { obj, ok := infos[i].Object.(*templateapi.Template) if !ok { sourceName := filename if len(templateName) > 0 { sourceName = namespace + "/" + templateName } 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 { values := kcmdutil.GetFlagStringSlice(cmd, "value") injectUserVars(values, out, obj) } injectUserVars(valueArgs, out, 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 } gv := mapping.GroupVersionKind.GroupVersion() version, err := kcmdutil.OutputVersion(cmd, &gv) if err != nil { return err } p = kubectl.NewVersionedPrinter(p, kapi.Scheme, version) // 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: unversioned.ListMeta{}, Items: objects, }, out) }
func (v *VolumeOptions) RunVolume(args []string) error { mapper := resource.ClientMapperFunc(v.RESTClientFactory) b := resource.NewBuilder(v.Mapper, v.Typer, mapper, kapi.Codecs.UniversalDecoder()). ContinueOnError(). NamespaceParam(v.DefaultNamespace).DefaultNamespace(). FilenameParam(v.ExplicitNamespace, false, v.Filenames...). SelectorParam(v.Selector). ResourceTypeOrNameArgs(v.All, args...). Flatten() singular := false infos, err := b.Do().IntoSingular(&singular).Infos() if err != nil { return err } if v.List { listingErrors := v.printVolumes(infos) if len(listingErrors) > 0 { return cmdutil.ErrExit } return nil } updateInfos := []*resource.Info{} // if a claim should be created, generate the info we'll add to the flow if v.Add && v.AddOpts.CreateClaim { claim := v.AddOpts.createClaim() m, err := v.Mapper.RESTMapping(kapi.Kind("PersistentVolumeClaim")) if err != nil { return err } client, err := mapper.ClientForMapping(m) if err != nil { return err } info := &resource.Info{ Mapping: m, Client: client, Namespace: v.DefaultNamespace, Object: claim, } infos = append(infos, info) updateInfos = append(updateInfos, info) } patches, patchError := v.getVolumeUpdatePatches(infos, singular) if patchError != nil { return patchError } objects, err := resource.AsVersionedObject(infos, false, v.OutputVersion, kapi.Codecs.LegacyCodec(v.OutputVersion)) if err != nil { return err } if len(v.Output) != 0 { p, _, err := kubectl.GetPrinter(v.Output, "", false) if err != nil { return err } return p.PrintObj(objects, v.Out) } failed := false for _, info := range updateInfos { var obj runtime.Object if len(info.ResourceVersion) == 0 { obj, err = resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, false, info.Object) } else { obj, err = resource.NewHelper(info.Client, info.Mapping).Replace(info.Namespace, info.Name, true, info.Object) } if err != nil { handlePodUpdateError(v.Err, err, "volume") failed = true continue } info.Refresh(obj, true) fmt.Fprintf(v.Out, "%s/%s\n", info.Mapping.Resource, info.Name) } for _, patch := range patches { info := patch.Info if patch.Err != nil { failed = true fmt.Fprintf(v.Err, "error: %s/%s %v\n", info.Mapping.Resource, info.Name, patch.Err) continue } if string(patch.Patch) == "{}" || len(patch.Patch) == 0 { fmt.Fprintf(v.Err, "info: %s %q was not changed\n", info.Mapping.Resource, info.Name) continue } glog.V(4).Infof("Calculated patch %s", patch.Patch) obj, err := resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, kapi.StrategicMergePatchType, patch.Patch) if err != nil { handlePodUpdateError(v.Err, err, "volume") failed = true continue } info.Refresh(obj, true) kcmdutil.PrintSuccess(v.Mapper, false, v.Out, info.Mapping.Resource, info.Name, "updated") } if failed { return cmdutil.ErrExit } return nil }
func RunExport(f *clientcmd.Factory, exporter Exporter, in io.Reader, out io.Writer, cmd *cobra.Command, args []string, filenames []string) error { selector := cmdutil.GetFlagString(cmd, "selector") allNamespaces := cmdutil.GetFlagBool(cmd, "all-namespaces") 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, err := cmdutil.OutputVersion(cmd, clientConfig.GroupVersion) if err != nil { return err } cmdNamespace, explicit, err := f.DefaultNamespace() if err != nil { return err } mapper, typer := f.Object() b := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces). FilenameParam(explicit, filenames...). SelectorParam(selector). ResourceTypeOrNameArgs(true, 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.String()) if err != nil { return err } template := &templateapi.Template{ Objects: objects, } template.Name = asTemplate result, err = kapi.Scheme.ConvertToVersion(template, outputVersion.String()) if err != nil { return err } } else { object, err := resource.AsVersionedObject(infos, !one, outputVersion.String()) 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) }
// 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 { templateName, valueArgs := "", []string{} for _, s := range args { isValue := strings.Contains(s, "=") switch { case isValue: valueArgs = append(valueArgs, s) case !isValue && len(templateName) == 0: templateName = s case !isValue && len(templateName) > 0: return kcmdutil.UsageError(cmd, "template name must be specified only once: %s", s) } } keys := sets.NewString() duplicatedKeys := sets.NewString() var flagValues []string if cmd.Flag("value").Changed { flagValues = kcmdutil.GetFlagStringSlice(cmd, "value") } for _, value := range flagValues { key := strings.Split(value, "=")[0] if keys.Has(key) { duplicatedKeys.Insert(key) } keys.Insert(key) } for _, value := range valueArgs { key := strings.Split(value, "=")[0] if keys.Has(key) { duplicatedKeys.Insert(key) } keys.Insert(key) } if len(duplicatedKeys) != 0 { return kcmdutil.UsageError(cmd, fmt.Sprintf("The following values were provided more than once: %s", strings.Join(duplicatedKeys.List(), ", "))) } filename := kcmdutil.GetFlagString(cmd, "filename") if len(templateName) == 0 && len(filename) == 0 { return kcmdutil.UsageError(cmd, "Must pass a filename or name of stored template") } if kcmdutil.GetFlagBool(cmd, "parameters") { for _, flag := range []string{"value", "labels", "output", "output-version", "raw", "template"} { if f := cmd.Flags().Lookup(flag); f != nil && f.Changed { return kcmdutil.UsageError(cmd, "The --parameters flag does not process the template, can't be used with --%v", flag) } } } namespace, explicit, err := f.DefaultNamespace() if err != nil { return err } mapper, typer := f.Object(false) client, _, err := f.Clients() if err != nil { return err } var ( objects []runtime.Object infos []*resource.Info ) mapping, err := mapper.RESTMapping(templateapi.Kind("Template")) if err != nil { return err } // When templateName is not empty, then we fetch the template from the // server, otherwise we require to set the `-f` parameter. if len(templateName) > 0 { var ( storedTemplate, rs string sourceNamespace string ok bool ) sourceNamespace, rs, storedTemplate, ok = parseNamespaceResourceName(templateName, namespace) if !ok { return fmt.Errorf("invalid argument %q", templateName) } if len(rs) > 0 && (rs != "template" && rs != "templates") { return fmt.Errorf("unable to process invalid resource %q", rs) } if len(storedTemplate) == 0 { return fmt.Errorf("invalid value syntax %q", templateName) } templateObj, err := client.Templates(sourceNamespace).Get(storedTemplate) if err != nil { if errors.IsNotFound(err) { return fmt.Errorf("template %q could not be found", storedTemplate) } return err } templateObj.CreationTimestamp = unversioned.Now() infos = append(infos, &resource.Info{Object: templateObj}) } else { infos, err = resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), kapi.Codecs.UniversalDecoder()). NamespaceParam(namespace).RequireNamespace(). FilenameParam(explicit, false, filename). Do(). Infos() if err != nil { return err } } outputFormat := kcmdutil.GetFlagString(cmd, "output") if len(infos) > 1 { // in order to run validation on the input given to us by a user, we only support the processing // of one template in a list. For instance, we want to be able to fail when a user does not give // a parameter that the template wants or when they give a parameter the template doesn't need, // as this may indicate that they have mis-used `oc process`. This is much less complicated when // we process at most one template. fmt.Fprintf(out, "%d input templates found, but only the first will be processed", len(infos)) } obj, ok := infos[0].Object.(*templateapi.Template) if !ok { sourceName := filename if len(templateName) > 0 { sourceName = namespace + "/" + templateName } return fmt.Errorf("unable to parse %q, not a valid Template but %s\n", sourceName, reflect.TypeOf(infos[0].Object)) } // If 'parameters' flag is set it does not do processing but only print // the template parameters to console for inspection. if kcmdutil.GetFlagBool(cmd, "parameters") { return describe.PrintTemplateParameters(obj.Parameters, out) } if label := kcmdutil.GetFlagString(cmd, "labels"); len(label) > 0 { lbl, err := kubectl.ParseLabels(label) if err != nil { return fmt.Errorf("error parsing labels: %v\n", err) } 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 { values := kcmdutil.GetFlagStringSlice(cmd, "value") if errs := injectUserVars(values, obj); errs != nil { return kerrors.NewAggregate(errs) } } if errs := injectUserVars(valueArgs, obj); errs != nil { return kerrors.NewAggregate(errs) } resultObj, err := client.TemplateConfigs(namespace).Create(obj) if err != nil { return fmt.Errorf("error processing the template %q: %v\n", obj.Name, err) } if outputFormat == "describe" { if s, err := (&describe.TemplateDescriber{ MetadataAccessor: meta.NewAccessor(), ObjectTyper: kapi.Scheme, ObjectDescriber: nil, }).DescribeTemplate(resultObj); err != nil { return fmt.Errorf("error describing %q: %v\n", obj.Name, err) } else { _, err := fmt.Fprintf(out, s) return err } } 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 } gv := mapping.GroupVersionKind.GroupVersion() version, err := kcmdutil.OutputVersion(cmd, &gv) if err != nil { return err } p = kubectl.NewVersionedPrinter(p, kapi.Scheme, version) // 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: unversioned.ListMeta{}, Items: objects, }, out) }
func (o *ResourceOptions) Complete(f *clientcmd.Factory, c *cobra.Command) error { switch { case len(o.Output) > 0: printer, _, err := kubectl.GetPrinter(o.Output, "", false) if err != nil { return err } first := true o.PrintFn = func(info *resource.Info, _ Reporter) error { obj, err := info.Mapping.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion()) if err != nil { return err } // TODO: PrintObj is not correct for YAML - it should inject document separators itself if o.Output == "yaml" && !first { fmt.Fprintln(o.Out, "---") } first = false printer.PrintObj(obj, o.Out) return nil } o.DryRun = true case o.Confirm: o.DryRun = false default: o.DryRun = true } namespace, explicitNamespace, err := f.Factory.DefaultNamespace() if err != nil { return err } allNamespaces := !explicitNamespace && o.AllNamespaces if len(o.FromKey) > 0 || len(o.ToKey) > 0 { o.FilterFn = func(info *resource.Info) (bool, error) { var key string if info.Mapping.Scope.Name() == meta.RESTScopeNameNamespace { key = info.Namespace + "/" + info.Name } else { if !allNamespaces { return false, nil } key = info.Name } if len(o.FromKey) > 0 && o.FromKey > key { return false, nil } if len(o.ToKey) > 0 && o.ToKey <= key { return false, nil } return true, nil } } oclient, _, err := f.Clients() if err != nil { return err } mapper, _ := f.Object(false) resourceNames := sets.NewString() for i, s := range o.Include { if resourceNames.Has(s) { continue } if s != "*" { resourceNames.Insert(s) break } all, err := clientcmd.FindAllCanonicalResources(oclient.Discovery(), mapper) if err != nil { return fmt.Errorf("could not calculate the list of available resources: %v", err) } exclude := sets.NewString() for _, gr := range o.DefaultExcludes { exclude.Insert(gr.String()) } candidate := sets.NewString() for _, gr := range all { // if the user specifies a resource that matches resource or resource+group, skip it if resourceNames.Has(gr.Resource) || resourceNames.Has(gr.String()) || exclude.Has(gr.String()) { continue } candidate.Insert(gr.String()) } candidate.Delete(exclude.List()...) include := candidate if len(o.OverlappingResources) > 0 { include = sets.NewString() for _, k := range candidate.List() { reduce := k for _, others := range o.OverlappingResources { if !others.Has(k) { continue } reduce = others.List()[0] break } include.Insert(reduce) } } glog.V(4).Infof("Found the following resources from the server: %v", include.List()) last := o.Include[i+1:] o.Include = append([]string{}, o.Include[:i]...) o.Include = append(o.Include, include.List()...) o.Include = append(o.Include, last...) break } o.Builder = f.Factory.NewBuilder(false). AllNamespaces(allNamespaces). FilenameParam(false, false, o.Filenames...). ContinueOnError(). DefaultNamespace(). RequireObject(true). SelectAllParam(true). Flatten() if !allNamespaces { o.Builder.NamespaceParam(namespace) } if len(o.Filenames) == 0 { o.Builder.ResourceTypes(o.Include...) } return nil }
// 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, explicit, 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(explicit, 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).Replace(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 }
func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, args []string, out io.Writer) error { clientset, err := f.ClientSet() if err != nil { return err } printer, _, err := kubectl.GetPrinter("json", "", false, true) if err != nil { return err } nodes, err := clientset.Core().Nodes().List(api.ListOptions{}) if err != nil { return err } if err := printer.PrintObj(nodes, setupOutputWriter(cmd, out, "nodes.json")); err != nil { return err } var namespaces []string if cmdutil.GetFlagBool(cmd, "all-namespaces") { namespaceList, err := clientset.Core().Namespaces().List(api.ListOptions{}) if err != nil { return err } for ix := range namespaceList.Items { namespaces = append(namespaces, namespaceList.Items[ix].Name) } } else { namespaces = cmdutil.GetFlagStringSlice(cmd, "namespaces") if len(namespaces) == 0 { cmdNamespace, _, err := f.DefaultNamespace() if err != nil { return err } namespaces = []string{ api.NamespaceSystem, cmdNamespace, } } } for _, namespace := range namespaces { // TODO: this is repetitive in the extreme. Use reflection or // something to make this a for loop. events, err := clientset.Core().Events(namespace).List(api.ListOptions{}) if err != nil { return err } if err := printer.PrintObj(events, setupOutputWriter(cmd, out, path.Join(namespace, "events.json"))); err != nil { return err } rcs, err := clientset.Core().ReplicationControllers(namespace).List(api.ListOptions{}) if err != nil { return err } if err := printer.PrintObj(rcs, setupOutputWriter(cmd, out, path.Join(namespace, "replication-controllers.json"))); err != nil { return err } svcs, err := clientset.Core().Services(namespace).List(api.ListOptions{}) if err != nil { return err } if err := printer.PrintObj(svcs, setupOutputWriter(cmd, out, path.Join(namespace, "services.json"))); err != nil { return err } sets, err := clientset.Extensions().DaemonSets(namespace).List(api.ListOptions{}) if err != nil { return err } if err := printer.PrintObj(sets, setupOutputWriter(cmd, out, path.Join(namespace, "daemonsets.json"))); err != nil { return err } deps, err := clientset.Extensions().Deployments(namespace).List(api.ListOptions{}) if err != nil { return err } if err := printer.PrintObj(deps, setupOutputWriter(cmd, out, path.Join(namespace, "deployments.json"))); err != nil { return err } rps, err := clientset.Extensions().ReplicaSets(namespace).List(api.ListOptions{}) if err != nil { return err } if err := printer.PrintObj(rps, setupOutputWriter(cmd, out, path.Join(namespace, "replicasets.json"))); err != nil { return err } pods, err := clientset.Core().Pods(namespace).List(api.ListOptions{}) if err != nil { return err } if err := printer.PrintObj(pods, setupOutputWriter(cmd, out, path.Join(namespace, "pods.json"))); err != nil { return err } for ix := range pods.Items { pod := &pods.Items[ix] writer := setupOutputWriter(cmd, out, path.Join(namespace, pod.Name, "logs.txt")) writer.Write([]byte(fmt.Sprintf("==== START logs for %s/%s ====\n", pod.Namespace, pod.Name))) request, err := f.LogsForObject(pod, &api.PodLogOptions{}) if err != nil { return err } data, err := request.DoRaw() if err != nil { return err } writer.Write(data) writer.Write([]byte(fmt.Sprintf("==== END logs for %s/%s ====\n", pod.Namespace, pod.Name))) } } dir := cmdutil.GetFlagString(cmd, "output-directory") if len(dir) == 0 { dir = "." } if dir != "-" { fmt.Fprintf(out, "Cluster info dumped to %s", dir) } return nil }
// Run performs a rollback. func (o *RollbackOptions) Run() error { // Get the resource referenced in the command args. obj, err := o.findResource(o.TargetName) if err != nil { return err } // Interpret the resource to resolve a target for rollback. var target *kapi.ReplicationController switch r := obj.(type) { case *kapi.ReplicationController: dcName := deployutil.DeploymentConfigNameFor(r) dc, err := o.oc.DeploymentConfigs(r.Namespace).Get(dcName) if err != nil { return err } if dc.Spec.Paused { return fmt.Errorf("cannot rollback a paused deployment config") } // A specific deployment was used. target = r case *deployapi.DeploymentConfig: if r.Spec.Paused { return fmt.Errorf("cannot rollback a paused deployment config") } // A deploymentconfig was used. Find the target deployment by the // specified version, or by a lookup of the last completed deployment if // no version was supplied. deployment, err := o.findTargetDeployment(r, o.DesiredVersion) if err != nil { return err } target = deployment } if target == nil { return fmt.Errorf("%s is not a valid deployment or deployment config", o.TargetName) } // Set up the rollback and generate a new rolled back config. rollback := &deployapi.DeploymentConfigRollback{ Spec: deployapi.DeploymentConfigRollbackSpec{ From: kapi.ObjectReference{ Name: target.Name, }, IncludeTemplate: true, IncludeTriggers: o.IncludeTriggers, IncludeStrategy: o.IncludeStrategy, IncludeReplicationMeta: o.IncludeScalingSettings, }, } newConfig, err := o.oc.DeploymentConfigs(o.Namespace).Rollback(rollback) if err != nil { return err } // If this is a dry run, print and exit. if o.DryRun { describer := describe.NewDeploymentConfigDescriber(o.oc, o.kc, newConfig) description, err := describer.Describe(newConfig.Namespace, newConfig.Name, kubectl.DescriberSettings{}) if err != nil { return err } o.out.Write([]byte(description)) return nil } // If an output format is specified, print and exit. if len(o.Format) > 0 { printer, _, err := kubectl.GetPrinter(o.Format, o.Template) if err != nil { return err } versionedPrinter := kubectl.NewVersionedPrinter(printer, kapi.Scheme, latest.Version) versionedPrinter.PrintObj(newConfig, o.out) return nil } // Perform a real rollback. rolledback, err := o.oc.DeploymentConfigs(newConfig.Namespace).Update(newConfig) if err != nil { return err } // Print warnings about any image triggers disabled during the rollback. fmt.Fprintf(o.out, "#%d rolled back to %s\n", rolledback.Status.LatestVersion, rollback.Spec.From.Name) for _, trigger := range rolledback.Spec.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("oc deploy %s --enable-triggers -n %s", rolledback.Name, o.Namespace) fmt.Fprintf(o.out, "Warning: the following images triggers were disabled: %s\n You can re-enable them with: %s\n", strings.Join(disabled, ","), reenable) } } return nil }
// RunEnv contains all the necessary functionality for the OpenShift cli env command // TODO: refactor to share the common "patch resource" pattern of probe func RunEnv(f *clientcmd.Factory, in io.Reader, out io.Writer, cmd *cobra.Command, args []string, envParams, filenames []string) error { resources, envArgs, ok := cmdutil.SplitEnvironmentFromResources(args) if !ok { return kcmdutil.UsageError(cmd, "all resources must be specified before environment changes: %s", strings.Join(args, " ")) } if len(filenames) == 0 && len(resources) < 1 { return kcmdutil.UsageError(cmd, "one or more resources must be specified as <resource> <name> or <resource>/<name>") } containerMatch := kcmdutil.GetFlagString(cmd, "containers") list := kcmdutil.GetFlagBool(cmd, "list") resolve := kcmdutil.GetFlagBool(cmd, "resolve") selector := kcmdutil.GetFlagString(cmd, "selector") all := kcmdutil.GetFlagBool(cmd, "all") overwrite := kcmdutil.GetFlagBool(cmd, "overwrite") resourceVersion := kcmdutil.GetFlagString(cmd, "resource-version") outputFormat := kcmdutil.GetFlagString(cmd, "output") from := kcmdutil.GetFlagString(cmd, "from") prefix := kcmdutil.GetFlagString(cmd, "prefix") if list && len(outputFormat) > 0 { return kcmdutil.UsageError(cmd, "--list and --output may not be specified together") } clientConfig, err := f.ClientConfig() if err != nil { return err } cmdNamespace, explicit, err := f.DefaultNamespace() if err != nil { return err } env, remove, err := cmdutil.ParseEnv(append(envParams, envArgs...), in) if err != nil { return err } if len(from) != 0 { mapper, typer := f.Object(false) b := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), kapi.Codecs.UniversalDecoder()). ContinueOnError(). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(explicit, false, filenames...). SelectorParam(selector). ResourceTypeOrNameArgs(all, from). Flatten() one := false infos, err := b.Do().IntoSingular(&one).Infos() if err != nil { return err } for _, info := range infos { switch from := info.Object.(type) { case *kapi.Secret: for key := range from.Data { envVar := kapi.EnvVar{ Name: keyToEnvName(key), ValueFrom: &kapi.EnvVarSource{ SecretKeyRef: &kapi.SecretKeySelector{ LocalObjectReference: kapi.LocalObjectReference{ Name: from.Name, }, Key: key, }, }, } env = append(env, envVar) } case *kapi.ConfigMap: for key := range from.Data { envVar := kapi.EnvVar{ Name: keyToEnvName(key), ValueFrom: &kapi.EnvVarSource{ ConfigMapKeyRef: &kapi.ConfigMapKeySelector{ LocalObjectReference: kapi.LocalObjectReference{ Name: from.Name, }, Key: key, }, }, } env = append(env, envVar) } default: return fmt.Errorf("unsupported resource specified in --from") } } } if len(prefix) != 0 { for i := range env { env[i].Name = fmt.Sprintf("%s%s", prefix, env[i].Name) } } mapper, typer := f.Object(false) b := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), kapi.Codecs.UniversalDecoder()). ContinueOnError(). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(explicit, false, 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 kcmdutil.UsageError(cmd, "--resource-version may only be used with a single resource") } // Keep a copy of the original objects prior to updating their environment. // Used in constructing the patch(es) that will be applied in the server. gv := *clientConfig.GroupVersion oldObjects, err := resource.AsVersionedObjects(infos, gv, kapi.Codecs.LegacyCodec(gv)) if err != nil { return err } if len(oldObjects) != len(infos) { return fmt.Errorf("could not convert all objects to API version %q", clientConfig.GroupVersion) } oldData := make([][]byte, len(infos)) for i := range oldObjects { old, err := json.Marshal(oldObjects[i]) if err != nil { return err } oldData[i] = old } skipped := 0 errored := []*resource.Info{} for _, info := range infos { ok, err := f.UpdatePodSpecForObject(info.Object, func(spec *kapi.PodSpec) error { resolutionErrorsEncountered := false containers, _ := selectContainers(spec.Containers, containerMatch) if len(containers) == 0 { fmt.Fprintf(cmd.OutOrStderr(), "warning: %s/%s does not have any containers matching %q\n", info.Mapping.Resource, info.Name, containerMatch) return nil } for _, c := range containers { if !overwrite { if err := validateNoOverwrites(c.Env, env); err != nil { errored = append(errored, info) return err } } c.Env = updateEnv(c.Env, env, remove) if list { resolveErrors := map[string][]string{} store := newResourceStore() fmt.Fprintf(out, "# %s %s, container %s\n", info.Mapping.Resource, info.Name, c.Name) for _, env := range c.Env { // Print the simple value if env.ValueFrom == nil { fmt.Fprintf(out, "%s=%s\n", env.Name, env.Value) continue } // Print the reference version if !resolve { fmt.Fprintf(out, "# %s from %s\n", env.Name, getEnvVarRefString(env.ValueFrom)) continue } value, err := getEnvVarRefValue(f, store, env.ValueFrom, info.Object, c) // Print the resolved value if err == nil { fmt.Fprintf(out, "%s=%s\n", env.Name, value) continue } // Print the reference version and save the resolve error fmt.Fprintf(out, "# %s from %s\n", env.Name, getEnvVarRefString(env.ValueFrom)) errString := err.Error() resolveErrors[errString] = append(resolveErrors[errString], env.Name) resolutionErrorsEncountered = true } // Print any resolution errors errs := []string{} for err, vars := range resolveErrors { sort.Strings(vars) errs = append(errs, fmt.Sprintf("error retrieving reference for %s: %v", strings.Join(vars, ", "), err)) } sort.Strings(errs) for _, err := range errs { fmt.Fprintln(cmd.OutOrStderr(), err) } } } if resolutionErrorsEncountered { errored = append(errored, info) return errors.New("failed to retrieve valueFrom references") } return nil }) if !ok { // This is a fallback function for objects that don't have pod spec. ok, err = f.UpdateObjectEnvironment(info.Object, func(vars *[]kapi.EnvVar) error { if vars == nil { return fmt.Errorf("no environment variables provided") } if !overwrite { if err := validateNoOverwrites(*vars, env); err != nil { errored = append(errored, info) return err } } *vars = updateEnv(*vars, env, remove) if list { fmt.Fprintf(out, "# %s %s\n", info.Mapping.Resource, info.Name) for _, env := range *vars { fmt.Fprintf(out, "%s=%s\n", env.Name, env.Value) } } return nil }) if !ok { skipped++ continue } } if err != nil { fmt.Fprintf(cmd.OutOrStderr(), "error: %s/%s %v\n", info.Mapping.Resource, info.Name, err) continue } } if one && skipped == len(infos) { return fmt.Errorf("%s/%s is not a pod or does not have a pod template", infos[0].Mapping.Resource, infos[0].Name) } if len(errored) == len(infos) { return cmdutil.ErrExit } if list { return nil } if len(outputFormat) != 0 { outputVersion, err := kcmdutil.OutputVersion(cmd, clientConfig.GroupVersion) if err != nil { return err } objects, err := resource.AsVersionedObjects(infos, outputVersion, kapi.Codecs.LegacyCodec(outputVersion)) if err != nil { return err } if len(objects) != len(infos) { return fmt.Errorf("could not convert all objects to API version %q", outputVersion) } p, _, err := kubectl.GetPrinter(outputFormat, "", false) if err != nil { return err } for _, object := range objects { if err := p.PrintObj(object, out); err != nil { return err } } return nil } objects, err := resource.AsVersionedObjects(infos, gv, kapi.Codecs.LegacyCodec(gv)) if err != nil { return err } if len(objects) != len(infos) { return fmt.Errorf("could not convert all objects to API version %q", clientConfig.GroupVersion) } failed := false updates: for i, info := range infos { for _, erroredInfo := range errored { if info == erroredInfo { continue updates } } newData, err := json.Marshal(objects[i]) if err != nil { return err } patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData[i], newData, objects[i]) if err != nil { return err } obj, err := resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, kapi.StrategicMergePatchType, patchBytes) if err != nil { handlePodUpdateError(cmd.OutOrStderr(), err, "environment variables") failed = true continue } info.Refresh(obj, true) // make sure arguments to set or replace environment variables are set // before returning a successful message if len(env) == 0 && len(envArgs) == 0 { return fmt.Errorf("at least one environment variable must be provided") } shortOutput := kcmdutil.GetFlagString(cmd, "output") == "name" kcmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, "updated") } if failed { return cmdutil.ErrExit } return nil }