// NewCmdWhoCan implements the OpenShift cli who-can command func NewCmdWhoCan(name, fullName string, f *clientcmd.Factory, out io.Writer) *cobra.Command { options := &whoCanOptions{} cmd := &cobra.Command{ Use: "who-can VERB RESOURCE", Short: "List who can perform the specified action on a resource", Long: "List who can perform the specified action on a resource", Run: func(cmd *cobra.Command, args []string) { if err := options.complete(args); err != nil { kcmdutil.CheckErr(kcmdutil.UsageError(cmd, err.Error())) } var err error if options.client, _, err = f.Clients(); err != nil { kcmdutil.CheckErr(err) } if options.bindingNamespace, err = f.DefaultNamespace(); err != nil { kcmdutil.CheckErr(err) } if err := options.run(); err != nil { kcmdutil.CheckErr(err) } }, } return cmd }
func (n *NodeOptions) Complete(f *clientcmd.Factory, c *cobra.Command, args []string, out io.Writer) error { defaultNamespace, err := f.DefaultNamespace() if err != nil { return err } _, kc, err := f.Clients() if err != nil { return err } cmdPrinter, output, err := kcmdutil.PrinterForCommand(c) if err != nil { return err } mapper, typer := f.Object() n.DefaultNamespace = defaultNamespace n.Kclient = kc n.Writer = out n.Mapper = mapper n.Typer = typer n.RESTClientFactory = f.Factory.RESTClient n.Printer = f.Printer n.NodeNames = []string{} n.CmdPrinter = cmdPrinter n.CmdPrinterOutput = false if output { n.CmdPrinterOutput = true } if len(args) != 0 { n.NodeNames = append(n.NodeNames, args...) } return nil }
func (o *RoleModificationOptions) Complete(f *clientcmd.Factory, args []string, target *[]string, targetName string, isNamespaced bool) error { if len(args) < 2 { return fmt.Errorf("You must specify at least two arguments: <role> <%s> [%s]...", targetName, targetName) } o.RoleName = args[0] *target = append(*target, args[1:]...) osClient, _, err := f.Clients() if err != nil { return err } if isNamespaced { roleBindingNamespace, err := f.DefaultNamespace() if err != nil { return err } o.RoleBindingAccessor = NewLocalRoleBindingAccessor(roleBindingNamespace, osClient) } else { o.RoleBindingAccessor = NewClusterRoleBindingAccessor(osClient) } return nil }
func setupAppConfig(f *clientcmd.Factory, c *cobra.Command, args []string, config *newcmd.AppConfig) error { namespace, err := f.DefaultNamespace() if err != nil { return err } dockerClient, _, err := dockerutil.NewHelper().GetClient() if err == nil { if err = dockerClient.Ping(); err == nil { config.SetDockerClient(dockerClient) } } if err != nil { glog.V(2).Infof("No local Docker daemon detected: %v", err) } osclient, _, err := f.Clients() if err != nil { return err } config.SetOpenShiftClient(osclient, namespace) unknown := config.AddArguments(args) if len(unknown) != 0 { return cmdutil.UsageError(c, "Did not recognize the following arguments: %v", unknown) } return nil }
func (v *VolumeOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command, out io.Writer) error { clientConfig, err := f.ClientConfig() if err != nil { return err } v.OutputVersion = kcmdutil.OutputVersion(cmd, clientConfig.Version) cmdNamespace, err := f.DefaultNamespace() if err != nil { return err } mapper, typer := f.Object() v.DefaultNamespace = cmdNamespace v.Writer = out v.Mapper = mapper v.Typer = typer v.RESTClientFactory = f.Factory.RESTClient v.UpdatePodSpecForObject = f.UpdatePodSpecForObject if v.Add && len(v.Name) == 0 { v.Name = string(kutil.NewUUID()) if len(v.Output) == 0 { fmt.Fprintf(v.Writer, "Generated volume name: %s\n", v.Name) } } // In case of volume source ignore the default volume type if len(v.AddOpts.Source) > 0 { v.AddOpts.Type = "" } return nil }
// RunImportImage contains all the necessary functionality for the OpenShift cli import-image command. func RunImportImage(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 an image stream.") } streamName := args[0] namespace, err := f.DefaultNamespace() if err != nil { return err } osClient, _, err := f.Clients() if err != nil { return err } imageStreamClient := osClient.ImageStreams(namespace) stream, err := imageStreamClient.Get(streamName) if err != nil { return err } if len(stream.Spec.DockerImageRepository) == 0 { return errors.New("only image streams with spec.dockerImageRepository set may have images imported") } if stream.Annotations == nil { stream.Annotations = make(map[string]string) } stream.Annotations[imageapi.DockerImageRepositoryCheckAnnotation] = "" updatedStream, err := imageStreamClient.Update(stream) if err != nil { return err } resourceVersion := updatedStream.ResourceVersion fmt.Fprintln(cmd.Out(), "Waiting for the import to complete, CTRL+C to stop waiting.") updatedStream, err = waitForImport(imageStreamClient, stream.Name, resourceVersion) if err != nil { return fmt.Errorf("unable to determine if the import completed successfully - please run 'oc describe -n %s imagestream/%s' to see if the tags were updated as expected: %v", stream.Namespace, stream.Name, err) } fmt.Fprintln(cmd.Out(), "The import completed successfully.\n") d := describe.ImageStreamDescriber{osClient} info, err := d.Describe(updatedStream.Namespace, updatedStream.Name) if err != nil { return err } fmt.Fprintln(out, info) return nil }
func (o *RemoveFromProjectOptions) Complete(f *clientcmd.Factory, args []string, target *[]string, targetName string) error { if len(args) < 1 { return fmt.Errorf("You must specify at least one argument: <%s> [%s]...", targetName, targetName) } *target = append(*target, args...) var err error if o.Client, _, err = f.Clients(); err != nil { return err } if o.BindingNamespace, err = f.DefaultNamespace(); err != nil { return err } return nil }
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 } o.out = out if len(args) > 0 { o.deploymentConfigName = args[0] } return nil }
// RunBuildLogs contains all the necessary functionality for the OpenShift cli build-logs command func RunBuildLogs(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, opts api.BuildLogOptions, args []string) error { if len(args) != 1 { return cmdutil.UsageError(cmd, "A build name is required") } namespace, err := f.DefaultNamespace() if err != nil { return err } c, _, err := f.Clients() if err != nil { return err } readCloser, err := c.BuildLogs(namespace).Get(args[0], opts).Stream() if err != nil { return err } defer readCloser.Close() _, err = io.Copy(out, readCloser) return err }
// RunBuildChain contains all the necessary functionality for the OpenShift // experimental build-chain command func RunBuildChain(f *clientcmd.Factory, cmd *cobra.Command, args []string) error { all := cmdutil.GetFlagBool(cmd, "all") allTags := cmdutil.GetFlagBool(cmd, "all-tags") if len(args) > 1 || (len(args) == 1 && all) || (len(args) == 0 && allTags) || (all && allTags) { return cmdutil.UsageError(cmd, "Must pass nothing, an ImageStream name:tag combination, or specify the --all flag") } oc, _, err := f.Clients() if err != nil { return err } // Retrieve namespace(s) namespace := cmdutil.GetFlagString(cmd, "namespace") if len(namespace) == 0 { namespace, err = f.DefaultNamespace() if err != nil { return err } } namespaces := make([]string, 0) if all { projectList, err := oc.Projects().List(labels.Everything(), fields.Everything()) if err != nil { return err } for _, project := range projectList.Items { glog.V(4).Infof("Found namespace %s", project.Name) namespaces = append(namespaces, project.Name) } } if len(namespaces) == 0 { namespaces = append(namespaces, namespace) } // Get all build configurations buildConfigList := make([]buildapi.BuildConfig, 0) for _, namespace := range namespaces { cfgList, err := oc.BuildConfigs(namespace).List(labels.Everything(), fields.Everything()) if err != nil { return err } buildConfigList = append(buildConfigList, cfgList.Items...) } // Parse user input and validate specified image stream streams := make(map[string][]string) if !all && len(args) != 0 { name, specifiedTag, err := parseTag(args[0]) if err != nil { return err } // Validate the specified image stream is, err := oc.ImageStreams(namespace).Get(name) if err != nil { return err } stream := join(namespace, name) // Validate specified tag tags := make([]string, 0) exists := false for tag := range is.Status.Tags { tags = append(tags, tag) if specifiedTag == tag { exists = true } } if !exists && !allTags { // The specified tag isn't a part of our image stream return fmt.Errorf("no tag %s exists in %s", specifiedTag, stream) } else if !allTags { // Use only the specified tag tags = []string{specifiedTag} } // Set the specified stream as the only one to output dependencies for streams[stream] = tags } else { streams = getStreams(buildConfigList) } if len(streams) == 0 { return fmt.Errorf("no ImageStream available for building its dependency tree") } output := cmdutil.GetFlagString(cmd, "output") for stream, tags := range streams { for _, tag := range tags { glog.V(4).Infof("Checking dependencies of stream %s tag %s", stream, tag) root, err := findStreamDeps(stream, tag, buildConfigList) if err != nil { return err } // Check if the given image stream doesn't have any dependencies if treeSize(root) < 2 { glog.Infof("%s:%s has no dependencies\n", root.FullName, tag) continue } switch output { case "json": jsonDump, err := json.MarshalIndent(root, "", "\t") if err != nil { return err } fmt.Println(string(jsonDump)) case "dot": g := dot.NewGraph() _, name, err := split(stream) if err != nil { return err } graphName := validDOT(name) g.SetName(graphName) // Directed graph since we illustrate dependencies g.SetDir(true) // Explicitly allow multiple pairs of edges between // the same pair of nodes g.SetStrict(false) out, err := dotDump(root, g, graphName) if err != nil { return err } fmt.Println(out) case "ast": fmt.Println(root) default: return cmdutil.UsageError(cmd, "Wrong output format specified: %s", output) } } } return nil }
// 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) build, err := buildClient.Get(buildName) if err != nil { return err } if !isBuildCancellable(build) { return nil } // Print build logs before cancelling build. if cmdutil.GetFlagBool(cmd, "dump-logs") { opts := buildapi.BuildLogOptions{ NoWait: true, Follow: false, } response, err := client.BuildLogs(namespace).Get(buildName, opts).Do().Raw() if err != nil { glog.Errorf("Could not fetch build logs for %s: %v", buildName, err) } else { glog.Infof("Build logs for %s:\n%v", buildName, string(response)) } } // Mark build to be cancelled. for { build.Cancelled = true if _, err = buildClient.Update(build); err != nil && errors.IsConflict(err) { build, err = buildClient.Get(buildName) if err != nil { return err } continue } if err != nil { return err } break } glog.V(2).Infof("Build %s was cancelled.", buildName) // Create a new build with the same configuration. if cmdutil.GetFlagBool(cmd, "restart") { request := &buildapi.BuildRequest{ ObjectMeta: kapi.ObjectMeta{Name: build.Name}, } newBuild, err := client.Builds(namespace).Clone(request) if err != nil { return err } glog.V(2).Infof("Restarted build %s.", buildName) fmt.Fprintf(out, "%s\n", newBuild.Name) } else { fmt.Fprintf(out, "%s\n", build.Name) } return nil }
// NewCmdRollback creates a CLI rollback command. func NewCmdRollback(fullName string, f *clientcmd.Factory, out io.Writer) *cobra.Command { rollback := &deployapi.DeploymentConfigRollback{ Spec: deployapi.DeploymentConfigRollbackSpec{ IncludeTemplate: true, }, } cmd := &cobra.Command{ Use: "rollback DEPLOYMENT", Short: "Revert part of an application back to a previous deployment", Long: rollbackLong, Example: fmt.Sprintf(rollbackExample, fullName), Run: func(cmd *cobra.Command, args []string) { // Validate arguments if len(args) == 0 || len(args[0]) == 0 { cmdutil.CheckErr(cmdutil.UsageError(cmd, "A deployment name is required.")) } // Extract arguments format := cmdutil.GetFlagString(cmd, "output") template := cmdutil.GetFlagString(cmd, "template") dryRun := cmdutil.GetFlagBool(cmd, "dry-run") // Get globally provided stuff namespace, err := f.DefaultNamespace() cmdutil.CheckErr(err) oClient, kClient, err := f.Clients() cmdutil.CheckErr(err) // Set up the rollback config rollback.Spec.From.Name = args[0] // Make a helper and generate a rolled back config helper := newHelper(oClient, kClient) config, err := helper.Generate(namespace, rollback) cmdutil.CheckErr(err) // If this is a dry run, print and exit if dryRun { err := helper.Describe(config, out) cmdutil.CheckErr(err) return } // If an output format is specified, print and exit if len(format) > 0 { err := helper.Print(config, format, template, out) cmdutil.CheckErr(err) return } // Perform the rollback rolledback, err := helper.Update(config) cmdutil.CheckErr(err) // Notify the user of any disabled image triggers fmt.Fprintf(out, "#%d rolled back to %s\n", rolledback.LatestVersion, rollback.Spec.From.Name) for _, trigger := range rolledback.Triggers { disabled := []string{} if trigger.Type == deployapi.DeploymentTriggerOnImageChange && !trigger.ImageChangeParams.Automatic { disabled = append(disabled, trigger.ImageChangeParams.From.Name) } if len(disabled) > 0 { reenable := fmt.Sprintf("%s deploy %s --enable-triggers", fullName, rolledback.Name) fmt.Fprintf(cmd.Out(), "Warning: the following images triggers were disabled: %s\n You can re-enable them with: %s\n", strings.Join(disabled, ","), reenable) } } }, } cmd.Flags().BoolVar(&rollback.Spec.IncludeTriggers, "change-triggers", false, "Include the previous deployment's triggers in the rollback") cmd.Flags().BoolVar(&rollback.Spec.IncludeStrategy, "change-strategy", false, "Include the previous deployment's strategy in the rollback") cmd.Flags().BoolVar(&rollback.Spec.IncludeReplicationMeta, "change-scaling-settings", false, "Include the previous deployment's replicationController replica count and selector in the rollback") cmd.Flags().BoolP("dry-run", "d", false, "Instead of performing the rollback, describe what the rollback will look like in human-readable form") cmd.Flags().StringP("output", "o", "", "Instead of performing the rollback, print the updated deployment configuration in the specified format (json|yaml|template|templatefile)") cmd.Flags().StringP("template", "t", "", "Template string or path to template file to use when -o=template or -o=templatefile.") return cmd }
// RunProject contains all the necessary functionality for the OpenShift cli process command func RunProcess(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string) error { storedTemplate := "" if len(args) > 0 { storedTemplate = args[0] } filename := kcmdutil.GetFlagString(cmd, "filename") if len(storedTemplate) == 0 && len(filename) == 0 { return kcmdutil.UsageError(cmd, "Must pass a filename or name of stored template") } namespace, err := f.DefaultNamespace() if err != nil { return err } mapper, typer := f.Object() client, _, err := f.Clients() if err != nil { return err } var ( objects []runtime.Object infos []*resource.Info mapping *meta.RESTMapping ) version, kind, err := mapper.VersionAndKindForResource("template") if mapping, err = mapper.RESTMapping(kind, version); err != nil { return err } // When storedTemplate is not empty, then we fetch the template from the // server, otherwise we require to set the `-f` parameter. if len(storedTemplate) > 0 { templateObj, err := client.Templates(namespace).Get(storedTemplate) if err != nil { if errors.IsNotFound(err) { return fmt.Errorf("template %q could not be found", storedTemplate) } return err } templateObj.CreationTimestamp = util.Now() infos = append(infos, &resource.Info{Object: templateObj}) } else { infos, err = resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). NamespaceParam(namespace).RequireNamespace(). FilenameParam(filename). Do(). Infos() if err != nil { return err } } outputFormat := kcmdutil.GetFlagString(cmd, "output") for i := range infos { obj, ok := infos[i].Object.(*api.Template) if !ok { sourceName := filename if len(storedTemplate) > 0 { sourceName = namespace + "/" + storedTemplate } fmt.Fprintf(cmd.Out(), "unable to parse %q, not a valid Template but %s\n", sourceName, reflect.TypeOf(infos[i].Object)) continue } // If 'parameters' flag is set it does not do processing but only print // the template parameters to console for inspection. // If multiple templates are passed, this will print combined output for all // templates. if kcmdutil.GetFlagBool(cmd, "parameters") { if len(infos) > 1 { fmt.Fprintf(out, "\n%s:\n", obj.Name) } if err := describe.PrintTemplateParameters(obj.Parameters, out); err != nil { fmt.Fprintf(cmd.Out(), "error printing parameters for %q: %v\n", obj.Name, err) } continue } if label := kcmdutil.GetFlagString(cmd, "labels"); len(label) > 0 { lbl, err := kubectl.ParseLabels(label) if err != nil { fmt.Fprintf(cmd.Out(), "error parsing labels: %v\n", err) continue } if obj.ObjectLabels == nil { obj.ObjectLabels = make(map[string]string) } for key, value := range lbl { obj.ObjectLabels[key] = value } } // Override the values for the current template parameters // when user specify the --value if cmd.Flag("value").Changed { injectUserVars(cmd, obj) } resultObj, err := client.TemplateConfigs(namespace).Create(obj) if err != nil { fmt.Fprintf(cmd.Out(), "error processing the template %q: %v\n", obj.Name, err) continue } if outputFormat == "describe" { if s, err := (&describe.TemplateDescriber{ MetadataAccessor: meta.NewAccessor(), ObjectTyper: kapi.Scheme, ObjectDescriber: nil, }).DescribeTemplate(resultObj); err != nil { fmt.Fprintf(cmd.Out(), "error describing %q: %v\n", obj.Name, err) } else { fmt.Fprintf(out, s) } continue } objects = append(objects, resultObj.Objects...) } // Do not print the processed templates when asked to only show parameters or // describe. if kcmdutil.GetFlagBool(cmd, "parameters") || outputFormat == "describe" { return nil } p, _, err := kubectl.GetPrinter(outputFormat, "") if err != nil { return err } p = kubectl.NewVersionedPrinter(p, kapi.Scheme, kcmdutil.OutputVersion(cmd, mapping.APIVersion)) // use generic output if kcmdutil.GetFlagBool(cmd, "raw") { for i := range objects { p.PrintObj(objects[i], out) } return nil } return p.PrintObj(&kapi.List{ ListMeta: kapi.ListMeta{}, Items: objects, }, out) }
// RunListBuildWebHooks prints the webhooks for the provided build config. func RunListBuildWebHooks(f *clientcmd.Factory, out, errOut io.Writer, name string, isBuild bool, webhookFilter string) error { generic, github := false, false prefix := false switch webhookFilter { case "all": generic, github = true, true prefix = true case "generic": generic = true case "github": github = true default: return fmt.Errorf("--list-webhooks must be 'all', 'generic', or 'github'") } client, _, err := f.Clients() if err != nil { return err } namespace, err := f.DefaultNamespace() if err != nil { return err } if isBuild { build, err := client.Builds(namespace).Get(name) if err != nil { return err } ref := build.Config if ref == nil { return fmt.Errorf("the provided Build %q was not created from a BuildConfig and cannot have webhooks", name) } if len(ref.Namespace) > 0 { namespace = ref.Namespace } name = ref.Name } config, err := client.BuildConfigs(namespace).Get(name) if err != nil { return err } for _, t := range config.Triggers { hookType := "" switch { case t.GenericWebHook != nil && generic: if prefix { hookType = "generic " } case t.GitHubWebHook != nil && github: if prefix { hookType = "github " } default: continue } url, err := client.BuildConfigs(namespace).WebHookURL(name, &t) if err != nil { if err != osclient.ErrTriggerIsNotAWebHook { fmt.Fprintf(errOut, "error: unable to get webhook for %s: %v", name, err) } continue } fmt.Fprintf(out, "%s%s\n", hookType, url.String()) } return nil }
// RunTag contains all the necessary functionality for the OpenShift cli tag command. func RunTag(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string, sourceKind string) error { if len(args) < 2 { return cmdutil.UsageError(cmd, "you must specify a source and at least one destination") } original := sourceKind if len(sourceKind) > 0 { sourceKind = determineSourceKind(f, sourceKind) } if len(sourceKind) > 0 { validSources := util.NewStringSet("imagestreamtag", "istag", "imagestreamimage", "isimage", "docker", "dockerimage") if !validSources.Has(strings.ToLower(sourceKind)) { cmdutil.CheckErr(cmdutil.UsageError(cmd, "invalid source %q; valid values are %v", original, strings.Join(validSources.List(), ", "))) } } namespace, err := f.DefaultNamespace() if err != nil { return err } sourceNamespace, sourceNameAndRef, err := parseStreamName(args[0], namespace) if err != nil { return err } osClient, _, err := f.Clients() if err != nil { return err } if len(sourceKind) == 0 { if sourceName, sourceTag, ok := imageapi.SplitImageStreamTag(sourceNameAndRef); ok { if _, err := osClient.ImageStreamTags(sourceNamespace).Get(sourceName, sourceTag); err == nil { sourceKind = "ImageStreamTag" } } } if len(sourceKind) == 0 { if sourceName, sourceID, err := imagestreamimage.ParseNameAndID(sourceNameAndRef); err == nil { if _, err := osClient.ImageStreamImages(sourceNamespace).Get(sourceName, sourceID); err == nil { sourceKind = "ImageStreamImage" } } } if len(sourceKind) == 0 { sourceKind = "DockerImage" } for _, arg := range args[1:] { destNamespace, destNameAndTag, err := parseStreamName(arg, namespace) if err != nil { return err } destName, destTag, ok := imageapi.SplitImageStreamTag(destNameAndTag) if !ok { return fmt.Errorf("%q must be of the form <namespace>/<stream name>:<tag>", arg) } isc := osClient.ImageStreams(destNamespace) target, err := isc.Get(destName) if err != nil { if !kerrors.IsNotFound(err) { return err } // try to create the target if it doesn't exist target = &imageapi.ImageStream{ ObjectMeta: kapi.ObjectMeta{ Name: destName, }, } target, err = isc.Create(target) if err != nil { return nil } } if target.Spec.Tags == nil { target.Spec.Tags = make(map[string]imageapi.TagReference) } targetRef, ok := target.Spec.Tags[destTag] if !ok { targetRef = imageapi.TagReference{} } targetRef.From = &kapi.ObjectReference{ Kind: sourceKind, } switch sourceKind { case "DockerImage": targetRef.From.Name = args[0] default: targetRef.From.Namespace = sourceNamespace targetRef.From.Name = sourceNameAndRef } target.Spec.Tags[destTag] = targetRef if _, err = isc.Update(target); err != nil { return err } } return nil }
// RunStartBuild contains all the necessary functionality for the OpenShift cli start-build command func RunStartBuild(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string, webhooks util.StringFlag) error { webhook := cmdutil.GetFlagString(cmd, "from-webhook") buildName := cmdutil.GetFlagString(cmd, "from-build") follow := cmdutil.GetFlagBool(cmd, "follow") switch { case len(webhook) > 0: if len(args) > 0 || len(buildName) > 0 { return cmdutil.UsageError(cmd, "The '--from-webhook' flag is incompatible with arguments or '--from-build'") } path := cmdutil.GetFlagString(cmd, "git-repository") postReceivePath := cmdutil.GetFlagString(cmd, "git-post-receive") repo := git.NewRepository() return RunStartBuildWebHook(f, out, webhook, path, postReceivePath, repo) case len(args) != 1 && len(buildName) == 0: return cmdutil.UsageError(cmd, "Must pass a name of a BuildConfig or specify build name with '--from-build' flag") } name := buildName isBuild := true if len(name) == 0 { name = args[0] isBuild = false } if webhooks.Provided() { return RunListBuildWebHooks(f, out, cmd.Out(), name, isBuild, webhooks.String()) } client, _, err := f.Clients() if err != nil { return err } namespace, err := f.DefaultNamespace() if err != nil { return err } request := &buildapi.BuildRequest{ ObjectMeta: kapi.ObjectMeta{Name: name}, } var newBuild *buildapi.Build if isBuild { if newBuild, err = client.Builds(namespace).Clone(request); err != nil { return err } } else { if newBuild, err = client.BuildConfigs(namespace).Instantiate(request); err != nil { return err } } fmt.Fprintf(out, "%s\n", newBuild.Name) if follow { opts := buildapi.BuildLogOptions{ Follow: true, NoWait: false, } rd, err := client.BuildLogs(namespace).Get(newBuild.Name, opts).Stream() if err != nil { return fmt.Errorf("error getting logs: %v", err) } defer rd.Close() _, err = io.Copy(out, rd) if err != nil { return fmt.Errorf("error streaming logs: %v", err) } } return nil }
func RunExport(f *clientcmd.Factory, exporter Exporter, in io.Reader, out io.Writer, cmd *cobra.Command, args []string, filenames util.StringList) error { selector := cmdutil.GetFlagString(cmd, "selector") all := cmdutil.GetFlagBool(cmd, "all") exact := cmdutil.GetFlagBool(cmd, "exact") asTemplate := cmdutil.GetFlagString(cmd, "as-template") raw := cmdutil.GetFlagBool(cmd, "raw") if exact && raw { return cmdutil.UsageError(cmd, "--exact and --raw may not both be specified") } clientConfig, err := f.ClientConfig() if err != nil { return err } outputVersion := cmdutil.OutputVersion(cmd, clientConfig.Version) cmdNamespace, err := f.DefaultNamespace() if err != nil { return err } mapper, typer := f.Object() b := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(filenames...). SelectorParam(selector). ResourceTypeOrNameArgs(all, args...). Flatten() one := false infos, err := b.Do().IntoSingular(&one).Infos() if err != nil { return err } if len(infos) == 0 { return fmt.Errorf("no resources found - nothing to export") } if !raw { newInfos := []*resource.Info{} errs := []error{} for _, info := range infos { if err := exporter.Export(info.Object, exact); err != nil { if err == ErrExportOmit { continue } errs = append(errs, err) } newInfos = append(newInfos, info) } if len(errs) > 0 { return utilerrors.NewAggregate(errs) } infos = newInfos } var result runtime.Object if len(asTemplate) > 0 { objects, err := resource.AsVersionedObjects(infos, outputVersion) if err != nil { return err } template := &templateapi.Template{ Objects: objects, } template.Name = asTemplate result, err = kapi.Scheme.ConvertToVersion(template, outputVersion) if err != nil { return err } } else { object, err := resource.AsVersionedObject(infos, !one, outputVersion) if err != nil { return err } result = object } // use YAML as the default format outputFormat := cmdutil.GetFlagString(cmd, "output") templateFile := cmdutil.GetFlagString(cmd, "template") if len(outputFormat) == 0 && len(templateFile) != 0 { outputFormat = "template" } if len(outputFormat) == 0 { outputFormat = "yaml" } p, _, err := kubectl.GetPrinter(outputFormat, templateFile) if err != nil { return err } return p.PrintObj(result, out) }
// 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 }
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, 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(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).Update(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 }