func (c *AppConfig) validate() (app.Environment, app.Environment, error) { env, err := app.ParseAndCombineEnvironment(c.Environment, c.EnvironmentFiles, c.In, func(key, file string) error { if file == "" { fmt.Fprintf(c.ErrOut, "warning: Environment variable %q was overwritten\n", key) } else { fmt.Fprintf(c.ErrOut, "warning: Environment variable %q already defined, ignoring value from file %q\n", key, file) } return nil }) if err != nil { return nil, nil, err } params, err := app.ParseAndCombineEnvironment(c.TemplateParameters, c.TemplateParameterFiles, c.In, func(key, file string) error { if file == "" { fmt.Fprintf(c.ErrOut, "warning: Template parameter %q was overwritten\n", key) } else { fmt.Fprintf(c.ErrOut, "warning: Template parameter %q already defined, ignoring value from file %q\n", key, file) } return nil }) if err != nil { return nil, nil, err } return env, params, nil }
// RunProcess contains all the necessary functionality for the OpenShift cli process command func RunProcess(f *clientcmd.Factory, in io.Reader, out, errout io.Writer, cmd *cobra.Command, args []string) error { templateName, templateParams := "", []string{} for _, s := range args { isValue := strings.Contains(s, "=") switch { case isValue: templateParams = append(templateParams, 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) } } if cmd.Flag("value").Changed || cmd.Flag("param").Changed { flagValues := getFlagStringArray(cmd, "param") cmdutil.WarnAboutCommaSeparation(errout, flagValues, "--param") templateParams = append(templateParams, flagValues...) } duplicatedKeys := sets.NewString() params, paramErr := app.ParseAndCombineEnvironment(templateParams, getFlagStringArray(cmd, "param-file"), in, func(key, file string) error { if file == "" { duplicatedKeys.Insert(key) } else { fmt.Fprintf(errout, "warning: Template parameter %q already defined, ignoring value from file %q", key, file) } return nil }) if len(duplicatedKeys) != 0 { return kcmdutil.UsageError(cmd, fmt.Sprintf("The following parameters 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", "param", "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 } } 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 } } // Raise parameter parsing errors here after we had chance to return UsageErrors first if paramErr != nil { return paramErr } if errs := injectUserVars(params, 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) } outputFormat := kcmdutil.GetFlagString(cmd, "output") 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...) p, _, err := kcmdutil.PrinterForCommand(cmd) 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) }