func (o *DeployOptions) Complete(f *clientcmd.Factory, args []string, out io.Writer) error { if len(args) > 1 { return errors.New("only one deployment config name is supported as argument.") } var err error o.osClient, o.kubeClient, err = f.Clients() if err != nil { return err } o.namespace, _, err = f.DefaultNamespace() if err != nil { return err } mapper, typer := f.Object() o.builder = resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()) o.out = out if len(args) > 0 { o.deploymentConfigName = args[0] } return nil }
// NewCmdNewBuild implements the OpenShift cli new-build command func NewCmdNewBuild(fullName string, f *clientcmd.Factory, out io.Writer) *cobra.Command { mapper, typer := f.Object() clientMapper := f.ClientMapperForCommand() config := newcmd.NewAppConfig(typer, mapper, clientMapper) cmd := &cobra.Command{ Use: "new-build (IMAGE | IMAGESTREAM | PATH | URL ...)", Short: "Create a new build configuration", Long: newBuildLong, Example: fmt.Sprintf(newBuildExample, fullName), Run: func(c *cobra.Command, args []string) { err := RunNewBuild(fullName, f, out, c, args, config) if err == errExit { os.Exit(1) } cmdutil.CheckErr(err) }, } cmd.Flags().Var(&config.SourceRepositories, "code", "Source code in the build configuration.") cmd.Flags().VarP(&config.ImageStreams, "image", "i", "Name of an OpenShift image stream to to use as a builder.") cmd.Flags().Var(&config.DockerImages, "docker-image", "Name of a Docker image to use as a builder.") cmd.Flags().StringVar(&config.Name, "name", "", "Set name to use for generated build artifacts") cmd.Flags().StringVar(&config.Strategy, "strategy", "", "Specify the build strategy to use if you don't want to detect (docker|source).") cmd.Flags().BoolVar(&config.OutputDocker, "to-docker", false, "Force the Build output to be DockerImage.") cmd.Flags().StringP("labels", "l", "", "Label to set in all generated resources.") cmdutil.AddPrinterFlags(cmd) return cmd }
// NewCmdNewBuild implements the OpenShift cli new-build command func NewCmdNewBuild(fullName string, f *clientcmd.Factory, in io.Reader, out io.Writer) *cobra.Command { mapper, typer := f.Object() clientMapper := f.ClientMapperForCommand() config := newcmd.NewAppConfig(typer, mapper, clientMapper) cmd := &cobra.Command{ Use: "new-build (IMAGE | IMAGESTREAM | PATH | URL ...)", Short: "Create a new build configuration", Long: newBuildLong, Example: fmt.Sprintf(newBuildExample, fullName), Run: func(c *cobra.Command, args []string) { config.AddEnvironmentToBuild = true err := RunNewBuild(fullName, f, out, in, c, args, config) if err == errExit { os.Exit(1) } cmdutil.CheckErr(err) }, } cmd.Flags().Var(&config.SourceRepositories, "code", "Source code in the build configuration.") cmd.Flags().VarP(&config.ImageStreams, "image", "i", "Name of an image stream to to use as a builder.") cmd.Flags().Var(&config.DockerImages, "docker-image", "Name of a Docker image to use as a builder.") cmd.Flags().StringVar(&config.Name, "name", "", "Set name to use for generated build artifacts") cmd.Flags().VarP(&config.Environment, "env", "e", "Specify key value pairs of environment variables to set into resulting image.") cmd.Flags().StringVar(&config.Strategy, "strategy", "", "Specify the build strategy to use if you don't want to detect (docker|source).") cmd.Flags().StringVarP(&config.Dockerfile, "dockerfile", "D", "", "Specify the contents of a Dockerfile to build directly, implies --strategy=docker. Pass '-' to read from STDIN.") cmd.Flags().BoolVar(&config.OutputDocker, "to-docker", false, "Have the build output push to a Docker repository.") cmd.Flags().StringP("labels", "l", "", "Label to set in all generated resources.") cmdutil.AddPrinterFlags(cmd) return cmd }
func (o *DeployOptions) Complete(f *clientcmd.Factory, args []string, out io.Writer) error { var err error o.osClient, o.kubeClient, err = f.Clients() if err != nil { return err } o.namespace, _, err = f.DefaultNamespace() if err != nil { return err } mapper, typer := f.Object() o.builder = resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()) o.out = out if len(args) > 0 { name := args[0] if strings.Index(name, "/") == -1 { name = fmt.Sprintf("dc/%s", name) } o.deploymentConfigName = name } return nil }
// Complete turns a partially defined RollbackActions into a solvent structure // which can be validated and used for a rollback. func (o *RollbackOptions) Complete(f *clientcmd.Factory, args []string, out io.Writer) error { // Extract basic flags. if len(args) == 1 { o.TargetName = args[0] } namespace, _, err := f.DefaultNamespace() if err != nil { return err } o.Namespace = namespace // Set up client based support. mapper, typer := f.Object() o.getBuilder = func() *resource.Builder { return resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()) } oClient, kClient, err := f.Clients() if err != nil { return err } o.oc = oClient o.kc = kClient o.out = out return nil }
// NewCmdNewApplication implements the OpenShift cli new-app command func NewCmdNewApplication(fullName string, f *clientcmd.Factory, out io.Writer) *cobra.Command { config := newcmd.NewAppConfig() config.Deploy = true cmd := &cobra.Command{ Use: "new-app (IMAGE | IMAGESTREAM | TEMPLATE | PATH | URL ...)", Short: "Create a new application", Long: fmt.Sprintf(newAppLong, fullName), Example: fmt.Sprintf(newAppExample, fullName), SuggestFor: []string{"app", "application"}, Run: func(c *cobra.Command, args []string) { mapper, typer := f.Object() config.SetMapper(mapper) config.SetTyper(typer) config.SetClientMapper(f.ClientMapperForCommand()) err := RunNewApplication(fullName, f, out, c, args, config) if err == errExit { os.Exit(1) } cmdutil.CheckErr(err) }, } cmd.Flags().BoolVar(&config.AsTestDeployment, "as-test", config.AsTestDeployment, "If true create this application as a test deployment, which validates that the deployment succeeds and then scales down.") cmd.Flags().StringSliceVar(&config.SourceRepositories, "code", config.SourceRepositories, "Source code to use to build this application.") cmd.Flags().StringVar(&config.ContextDir, "context-dir", "", "Context directory to be used for the build.") cmd.Flags().StringSliceVarP(&config.ImageStreams, "image", "", config.ImageStreams, "Name of an image stream to use in the app. (deprecated)") cmd.Flags().StringSliceVarP(&config.ImageStreams, "image-stream", "i", config.ImageStreams, "Name of an image stream to use in the app.") cmd.Flags().StringSliceVar(&config.DockerImages, "docker-image", config.DockerImages, "Name of a Docker image to include in the app.") cmd.Flags().StringSliceVar(&config.Templates, "template", config.Templates, "Name of a stored template to use in the app.") cmd.Flags().StringSliceVarP(&config.TemplateFiles, "file", "f", config.TemplateFiles, "Path to a template file to use for the app.") cmd.Flags().StringSliceVarP(&config.TemplateParameters, "param", "p", config.TemplateParameters, "Specify a list of key value pairs (e.g., -p FOO=BAR,BAR=FOO) to set/override parameter values in the template.") cmd.Flags().StringSliceVar(&config.Groups, "group", config.Groups, "Indicate components that should be grouped together as <comp1>+<comp2>.") cmd.Flags().StringSliceVarP(&config.Environment, "env", "e", config.Environment, "Specify key value pairs of environment variables to set into each container.") cmd.Flags().StringVar(&config.Name, "name", "", "Set name to use for generated application artifacts") cmd.Flags().StringVar(&config.Strategy, "strategy", "", "Specify the build strategy to use if you don't want to detect (docker|source).") cmd.Flags().StringP("labels", "l", "", "Label to set in all resources for this application.") cmd.Flags().BoolVar(&config.InsecureRegistry, "insecure-registry", false, "If true, indicates that the referenced Docker images are on insecure registries and should bypass certificate checking") cmd.Flags().BoolVarP(&config.AsList, "list", "L", false, "List all local templates and image streams that can be used to create.") cmd.Flags().BoolVarP(&config.AsSearch, "search", "S", false, "Search all templates, image streams, and Docker images that match the arguments provided.") cmd.Flags().BoolVar(&config.AllowMissingImages, "allow-missing-images", false, "If true, indicates that referenced Docker images that cannot be found locally or in a registry should still be used.") cmd.Flags().BoolVar(&config.AllowSecretUse, "grant-install-rights", false, "If true, a component that requires access to your account may use your token to install software into your project. Only grant images you trust the right to run with your token.") cmd.Flags().BoolVar(&config.SkipGeneration, "no-install", false, "Do not attempt to run images that describe themselves as being installable") cmd.Flags().BoolVar(&config.DryRun, "dry-run", false, "If true, do not actually create resources.") // TODO AddPrinterFlags disabled so that it doesn't conflict with our own "template" flag. // Need a better solution. // cmdutil.AddPrinterFlags(cmd) cmd.Flags().StringP("output", "o", "", "Output format. One of: json|yaml|template|templatefile.") cmd.Flags().String("output-version", "", "Output the formatted object with the given version (default api-version).") cmd.Flags().Bool("no-headers", false, "When using the default output, don't print headers.") cmd.Flags().String("output-template", "", "Template string or path to template file to use when -o=template or -o=templatefile. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview]") return cmd }
// Complete calls the upstream Complete for the logs command and then resolves the // resource a user requested to view its logs and creates the appropriate logOptions // object for it. func (o *OpenShiftLogsOptions) Complete(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string) error { if err := o.KubeLogOptions.Complete(f.Factory, out, cmd, args); err != nil { return err } namespace, _, err := f.DefaultNamespace() if err != nil { return err } podLogOptions := o.KubeLogOptions.Options.(*kapi.PodLogOptions) mapper, typer := f.Object() infos, err := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). NamespaceParam(namespace).DefaultNamespace(). ResourceNames("pods", args...). SingleResourceType().RequireObject(false). Do().Infos() if err != nil { return err } if len(infos) != 1 { return errors.New("expected a resource") } _, resource := meta.KindToResource(infos[0].Mapping.Kind, false) // TODO: podLogOptions should be included in our own logOptions objects. switch resource { case "build", "buildconfig": o.Options = &buildapi.BuildLogOptions{ Follow: podLogOptions.Follow, SinceSeconds: podLogOptions.SinceSeconds, SinceTime: podLogOptions.SinceTime, Timestamps: podLogOptions.Timestamps, TailLines: podLogOptions.TailLines, LimitBytes: podLogOptions.LimitBytes, } case "deploymentconfig": o.Options = &deployapi.DeploymentLogOptions{ Follow: podLogOptions.Follow, SinceSeconds: podLogOptions.SinceSeconds, SinceTime: podLogOptions.SinceTime, Timestamps: podLogOptions.Timestamps, TailLines: podLogOptions.TailLines, LimitBytes: podLogOptions.LimitBytes, } default: o.Options = nil } return nil }
// NewCmdNewBuild implements the OpenShift cli new-build command func NewCmdNewBuild(fullName string, f *clientcmd.Factory, in io.Reader, out io.Writer) *cobra.Command { config := newcmd.NewAppConfig() config.ExpectToBuild = true cmd := &cobra.Command{ Use: "new-build (IMAGE | IMAGESTREAM | PATH | URL ...)", Short: "Create a new build configuration", Long: fmt.Sprintf(newBuildLong, fullName), Example: fmt.Sprintf(newBuildExample, fullName), SuggestFor: []string{"build", "builds"}, Run: func(c *cobra.Command, args []string) { mapper, typer := f.Object() config.SetMapper(mapper) config.SetTyper(typer) config.SetClientMapper(f.ClientMapperForCommand()) config.AddEnvironmentToBuild = true err := RunNewBuild(fullName, f, out, in, c, args, config) if err == errExit { os.Exit(1) } cmdutil.CheckErr(err) }, } cmd.Flags().StringSliceVar(&config.SourceRepositories, "code", config.SourceRepositories, "Source code in the build configuration.") cmd.Flags().StringSliceVarP(&config.ImageStreams, "image", "i", config.ImageStreams, "Name of an image stream to to use as a builder.") cmd.Flags().StringSliceVar(&config.DockerImages, "docker-image", config.DockerImages, "Name of a Docker image to use as a builder.") cmd.Flags().StringSliceVar(&config.Secrets, "build-secret", config.Secrets, "Secret and destination to use as an input for the build.") cmd.Flags().StringVar(&config.Name, "name", "", "Set name to use for generated build artifacts.") cmd.Flags().StringVar(&config.To, "to", "", "Push built images to this image stream tag (or Docker image repository if --to-docker is set).") cmd.Flags().BoolVar(&config.OutputDocker, "to-docker", false, "Have the build output push to a Docker repository.") cmd.Flags().StringSliceVarP(&config.Environment, "env", "e", config.Environment, "Specify key value pairs of environment variables to set into resulting image.") cmd.Flags().StringVar(&config.Strategy, "strategy", "", "Specify the build strategy to use if you don't want to detect (docker|source).") cmd.Flags().StringVarP(&config.Dockerfile, "dockerfile", "D", "", "Specify the contents of a Dockerfile to build directly, implies --strategy=docker. Pass '-' to read from STDIN.") cmd.Flags().BoolVar(&config.BinaryBuild, "binary", false, "Instead of expecting a source URL, set the build to expect binary contents. Will disable triggers.") cmd.Flags().StringP("labels", "l", "", "Label to set in all generated resources.") cmd.Flags().BoolVar(&config.AllowMissingImages, "allow-missing-images", false, "If true, indicates that referenced Docker images that cannot be found locally or in a registry should still be used.") cmd.Flags().StringVar(&config.ContextDir, "context-dir", "", "Context directory to be used for the build.") cmd.Flags().BoolVar(&config.DryRun, "dry-run", false, "If true, do not actually create resources.") cmd.Flags().BoolVar(&config.NoOutput, "no-output", false, "If true, the build output will not be pushed anywhere.") cmd.Flags().StringVar(&config.SourceImage, "source-image", "", "Specify an image to use as source for the build. You must also specify --source-image-path.") cmd.Flags().StringVar(&config.SourceImagePath, "source-image-path", "", "Specify the file or directory to copy from the source image and its destination in the build directory. Format: [source]:[destination-dir].") cmdutil.AddPrinterFlags(cmd) return cmd }
// NewCmdNewApplication implements the OpenShift cli new-app command func NewCmdNewApplication(fullName string, f *clientcmd.Factory, out io.Writer) *cobra.Command { mapper, typer := f.Object() clientMapper := f.ClientMapperForCommand() config := newcmd.NewAppConfig(typer, mapper, clientMapper) cmd := &cobra.Command{ Use: "new-app (IMAGE | IMAGESTREAM | TEMPLATE | PATH | URL ...)", Short: "Create a new application", Long: newAppLong, Example: fmt.Sprintf(newAppExample, fullName), Run: func(c *cobra.Command, args []string) { err := RunNewApplication(fullName, f, out, c, args, config) if err == errExit { os.Exit(1) } cmdutil.CheckErr(err) }, } cmd.Flags().Var(&config.SourceRepositories, "code", "Source code to use to build this application.") cmd.Flags().StringVar(&config.ContextDir, "context-dir", "", "Context directory to be used for the build.") cmd.Flags().VarP(&config.ImageStreams, "image", "", "Name of an image stream to use in the app. (deprecated)") cmd.Flags().VarP(&config.ImageStreams, "image-stream", "i", "Name of an image stream to use in the app.") cmd.Flags().Var(&config.DockerImages, "docker-image", "Name of a Docker image to include in the app.") cmd.Flags().Var(&config.Templates, "template", "Name of a stored template to use in the app.") cmd.Flags().VarP(&config.TemplateFiles, "file", "f", "Path to a template file to use for the app.") cmd.Flags().VarP(&config.TemplateParameters, "param", "p", "Specify a list of key value pairs (eg. -p FOO=BAR,BAR=FOO) to set/override parameter values in the template.") cmd.Flags().Var(&config.Groups, "group", "Indicate components that should be grouped together as <comp1>+<comp2>.") cmd.Flags().VarP(&config.Environment, "env", "e", "Specify key value pairs of environment variables to set into each container.") cmd.Flags().StringVar(&config.Name, "name", "", "Set name to use for generated application artifacts") cmd.Flags().StringVar(&config.Strategy, "strategy", "", "Specify the build strategy to use if you don't want to detect (docker|source).") cmd.Flags().StringP("labels", "l", "", "Label to set in all resources for this application.") cmd.Flags().BoolVar(&config.InsecureRegistry, "insecure-registry", false, "If true, indicates that the referenced Docker images are on insecure registries and should bypass certificate checking") cmd.Flags().BoolVarP(&config.AsSearch, "search", "S", false, "Search for components that match the arguments provided and print the results.") // TODO AddPrinterFlags disabled so that it doesn't conflict with our own "template" flag. // Need a better solution. // cmdutil.AddPrinterFlags(cmd) cmd.Flags().StringP("output", "o", "", "Output format. One of: json|yaml|template|templatefile.") cmd.Flags().String("output-version", "", "Output the formatted object with the given version (default api-version).") cmd.Flags().Bool("no-headers", false, "When using the default output, don't print headers.") cmd.Flags().String("output-template", "", "Template string or path to template file to use when -o=template or -o=templatefile. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview]") return cmd }
// Complete completes struct variables. func (o *EditOptions) Complete(fullName string, f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string) error { o.fullName = fullName o.args = args o.out = out switch format := cmdutil.GetFlagString(cmd, "output"); format { case "json": o.printer = &kubectl.JSONPrinter{} o.ext = ".json" case "yaml": o.printer = &kubectl.YAMLPrinter{} o.ext = ".yaml" default: return cmdutil.UsageError(cmd, "The flag 'output' must be one of yaml|json") } cmdNamespace, explicit, err := f.DefaultNamespace() if err != nil { return err } o.namespace = cmdNamespace mapper, typer := f.Object() o.rmap = &resource.Mapper{ ObjectTyper: typer, RESTMapper: mapper, ClientMapper: f.ClientMapperForCommand(), } o.builder = resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). NamespaceParam(o.namespace).DefaultNamespace(). FilenameParam(explicit, o.filenames...). // SelectorParam(selector). ResourceTypeOrNameArgs(true, o.args...). Latest() clientConfig, err := f.ClientConfig() if err != nil { return err } o.version = cmdutil.OutputVersion(cmd, clientConfig.Version) return nil }
func followInstallation(f *clientcmd.Factory, input string, pod *kapi.Pod, kclient kclient.Interface, out io.Writer) error { fmt.Fprintf(out, "--> Installing ...\n") // we cannot retrieve logs until the pod is out of pending // TODO: move this to the server side podClient := kclient.Pods(pod.Namespace) if err := wait.PollImmediate(500*time.Millisecond, 60*time.Second, installationStarted(podClient, pod.Name, kclient.Secrets(pod.Namespace))); err != nil { return err } mapper, typer := f.Object() opts := &kcmd.LogsOptions{ Namespace: pod.Namespace, ResourceArg: pod.Name, Options: &kapi.PodLogOptions{ Follow: true, Container: pod.Spec.Containers[0].Name, }, Mapper: mapper, Typer: typer, ClientMapper: f.ClientMapperForCommand(), LogsForObject: f.LogsForObject, Out: out, } _, logErr := opts.RunLog() // status of the pod may take tens of seconds to propagate if err := wait.PollImmediate(500*time.Millisecond, 30*time.Second, installationComplete(podClient, pod.Name, out)); err != nil { if err == wait.ErrWaitTimeout { if logErr != nil { // output the log error if one occurred err = logErr } else { err = fmt.Errorf("installation may not have completed, see logs for %q for more information", pod.Name) } } return err } 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 := "" if len(args) > 0 { templateName = args[0] } 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 *meta.RESTMapping ) gvk, err := mapper.KindFor("template") if mapping, err = mapper.RESTMapping(gvk.GroupKind(), gvk.Version); 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, f.ClientMapperForCommand()). 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.(*api.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 { 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 } 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) }
// validate adds one layer of validation prior to calling the upstream // expose command. Used only for validating services that are about // to be exposed as routes. func validate(cmd *cobra.Command, f *clientcmd.Factory, args []string) error { if cmdutil.GetFlagString(cmd, "generator") != "route/v1" { if len(cmdutil.GetFlagString(cmd, "hostname")) > 0 { return fmt.Errorf("cannot use --hostname without generating a route") } return nil } if err := validateFlags(cmd); err != nil { return err } namespace, _, err := f.DefaultNamespace() if err != nil { return err } _, kc, err := f.Clients() 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] switch mapping.Kind { case "Service": svc, err := kc.Services(info.Namespace).Get(info.Name) if err != nil { return err } supportsTCP := false for _, port := range svc.Spec.Ports { if port.Protocol == kapi.ProtocolTCP { supportsTCP = true break } } if !supportsTCP { return fmt.Errorf("service %s doesn't support TCP", info.Name) } default: return fmt.Errorf("cannot expose a %s as a route", mapping.Kind) } 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) mapper, typer := f.Object() obj, err := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). NamespaceParam(namespace). ResourceNames("builds", buildName). SingleResourceType(). Do().Object() if err != nil { return err } build, ok := obj.(*buildapi.Build) if !ok { return fmt.Errorf("%q is not a valid build", buildName) } if !isBuildCancellable(build, out) { return nil } // Print build logs before cancelling build. if cmdutil.GetFlagBool(cmd, "dump-logs") { opts := buildapi.BuildLogOptions{ NoWait: true, } response, err := client.BuildLogs(namespace).Get(build.Name, opts).Do().Raw() if err != nil { glog.Errorf("Could not fetch build logs for %s: %v", build.Name, err) } else { glog.Infof("Build logs for %s:\n%v", build.Name, 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(build.Name) if err != nil { return err } continue } if err != nil { return err } break } fmt.Fprintf(out, "Build %s was cancelled.\n", build.Name) // mapper, typer := f.Object() // resourceMapper := &resource.Mapper{ObjectTyper: typer, RESTMapper: mapper, ClientMapper: f.ClientMapperForCommand()} // shortOutput := cmdutil.GetFlagString(cmd, "output") == "name" // 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 } fmt.Fprintf(out, "Restarted build %s.\n", build.Name) fmt.Fprintf(out, "%s\n", newBuild.Name) // fmt.Fprintf(out, "%s\n", newBuild.Name) // info, err := resourceMapper.InfoForObject(newBuild) // if err != nil { // return err // } //cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, "restarted") } else { fmt.Fprintf(out, "%s\n", build.Name) // info, err := resourceMapper.InfoForObject(build) // if err != nil { // return err // } // cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, "cancelled") } return nil }
// validate adds one layer of validation prior to calling the upstream // expose command. func validate(cmd *cobra.Command, f *clientcmd.Factory, args []string) error { namespace, enforceNamespace, err := f.DefaultNamespace() if err != nil { return err } _, kc, err := f.Clients() if err != nil { return err } mapper, typer := f.Object() r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). ContinueOnError(). NamespaceParam(namespace).DefaultNamespace(). FilenameParam(enforceNamespace, cmdutil.GetFlagStringSlice(cmd, "filename")...). ResourceTypeOrNameArgs(false, args...). Flatten(). Do() infos, err := r.Infos() if err != nil { return err } if len(infos) > 1 { return fmt.Errorf("multiple resources provided: %v", args) } info := infos[0] mapping := info.ResourceMapping() generator := cmdutil.GetFlagString(cmd, "generator") switch mapping.Kind { case "Service": switch generator { case "service/v1", "service/v2": // Set default protocol back for generating services if len(cmdutil.GetFlagString(cmd, "protocol")) == 0 { cmd.Flags().Set("protocol", "TCP") } return validateFlags(cmd, generator) case "": // Default exposing services as a route generator = "route/v1" cmd.Flags().Set("generator", generator) fallthrough case "route/v1": // We need to validate services exposed as routes if err := validateFlags(cmd, generator); err != nil { return err } svc, err := kc.Services(info.Namespace).Get(info.Name) if err != nil { return err } supportsTCP := false for _, port := range svc.Spec.Ports { if port.Protocol == kapi.ProtocolTCP { if len(port.Name) > 0 { // Pass service port name as the route target port, if it is named cmd.Flags().Set("target-port", port.Name) } supportsTCP = true break } } if !supportsTCP { return fmt.Errorf("service %q doesn't support TCP", info.Name) } } default: switch generator { case "route/v1": return fmt.Errorf("cannot expose a %s as a route", mapping.Kind) case "": // Default exposing everything except services as a service generator = "service/v2" cmd.Flags().Set("generator", generator) fallthrough case "service/v1", "service/v2": // Set default protocol back for generating services if len(cmdutil.GetFlagString(cmd, "protocol")) == 0 { cmd.Flags().Set("protocol", "TCP") } return validateFlags(cmd, generator) } } 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) }
// 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 []string) 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 } 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") } // 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.Version) if err != nil { return err } if len(oldObjects) != len(infos) { return fmt.Errorf("could not convert all objects to API version %q", clientConfig.Version) } 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 := cmdutil.OutputVersion(cmd, clientConfig.Version) objects, err := resource.AsVersionedObjects(infos, 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.Version) if err != nil { return err } if len(objects) != len(infos) { return fmt.Errorf("could not convert all objects to API version %q", clientConfig.Version) } 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 := cmdutil.GetFlagString(cmd, "output") == "name" cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, "updated") } if failed { return errExit } return nil }
// RunEdit contains all the necessary functionality for the OpenShift cli edit command func RunEdit(fullName string, f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string, filenames util.StringList) error { var printer kubectl.ResourcePrinter var ext string switch format := cmdutil.GetFlagString(cmd, "output"); format { case "json": printer = &kubectl.JSONPrinter{} ext = ".json" case "yaml": printer = &kubectl.YAMLPrinter{} ext = ".yaml" default: return cmdutil.UsageError(cmd, "The flag 'output' must be one of yaml|json") } cmdNamespace, explicit, err := f.DefaultNamespace() if err != nil { return err } mapper, typer := f.Object() rmap := &resource.Mapper{ ObjectTyper: typer, RESTMapper: mapper, ClientMapper: f.ClientMapperForCommand(), } b := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(explicit, filenames...). //SelectorParam(selector). ResourceTypeOrNameArgs(true, args...). Latest() if err != nil { return err } clientConfig, err := f.ClientConfig() if err != nil { return err } r := b.Flatten().Do() infos, err := r.Infos() if err != nil { return err } defaultVersion := cmdutil.OutputVersion(cmd, clientConfig.Version) results := editResults{} for { obj, err := resource.AsVersionedObject(infos, false, defaultVersion) if err != nil { return preservedFile(err, results.file, cmd.Out()) } // TODO: add an annotating YAML printer that can print inline comments on each field, // including descriptions or validation errors // generate the file to edit buf := &bytes.Buffer{} if err := results.header.WriteTo(buf); err != nil { return preservedFile(err, results.file, cmd.Out()) } if err := printer.PrintObj(obj, buf); err != nil { return preservedFile(err, results.file, cmd.Out()) } original := buf.Bytes() // launch the editor edit := editor.NewDefaultEditor() edited, file, err := edit.LaunchTempFile("oc-edit-", ext, buf) if err != nil { return preservedFile(err, results.file, cmd.Out()) } // cleanup any file from the previous pass if len(results.file) > 0 { os.Remove(results.file) } glog.V(4).Infof("User edited:\n%s", string(edited)) lines, err := hasLines(bytes.NewBuffer(edited)) if err != nil { return preservedFile(err, file, cmd.Out()) } if bytes.Equal(original, edited) { if len(results.edit) > 0 { preservedFile(nil, file, cmd.Out()) } else { os.Remove(file) } fmt.Fprintln(cmd.Out(), "Edit cancelled, no changes made.") return nil } if !lines { if len(results.edit) > 0 { preservedFile(nil, file, cmd.Out()) } else { os.Remove(file) } fmt.Fprintln(cmd.Out(), "Edit cancelled, saved file was empty.") return nil } results = editResults{ file: file, } // parse the edited file updates, err := rmap.InfoForData(edited, "edited-file") if err != nil { results.header.reasons = append(results.header.reasons, editReason{ head: fmt.Sprintf("The edited file had a syntax error: %v", err), }) continue } visitor := resource.NewFlattenListVisitor(updates, rmap) // need to make sure the original namespace wasn't changed while editing if err = visitor.Visit(resource.RequireNamespace(cmdNamespace)); err != nil { return preservedFile(err, file, cmd.Out()) } // attempt to calculate a delta for merging conflicts delta, err := jsonmerge.NewDelta(original, edited) if err != nil { glog.V(4).Infof("Unable to calculate diff, no merge is possible: %v", err) delta = nil } else { delta.AddPreconditions(jsonmerge.RequireKeyUnchanged("apiVersion")) results.delta = delta results.version = defaultVersion } err = visitor.Visit(func(info *resource.Info) error { data, err := info.Mapping.Codec.Encode(info.Object) if err != nil { return err } updated, err := resource.NewHelper(info.Client, info.Mapping).Replace(info.Namespace, info.Name, false, data) if err != nil { fmt.Fprintln(cmd.Out(), results.AddError(err, info)) return nil } info.Refresh(updated, true) fmt.Fprintf(out, "%s/%s\n", info.Mapping.Resource, info.Name) return nil }) if err != nil { return preservedFile(err, file, cmd.Out()) } if results.retryable > 0 { fmt.Fprintf(cmd.Out(), "You can run `%s update -f %s` to try this update again.\n", fullName, file) return errExit } if results.conflict > 0 { fmt.Fprintf(cmd.Out(), "You must update your local resource version and run `%s update -f %s` to overwrite the remote changes.\n", fullName, file) return errExit } if len(results.edit) == 0 { if results.notfound == 0 { os.Remove(file) } else { fmt.Fprintf(cmd.Out(), "The edits you made on deleted resources have been saved to %q\n", file) } return nil } // loop again and edit the remaining items infos = results.edit } 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, 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 }