func describeGeneratedJob(out io.Writer, ref app.ComponentReference, pod *kapi.Pod, secret *kapi.Secret, baseNamespace string) { refInput := ref.Input() generatorInput := refInput.ResolvedMatch.GeneratorInput hasToken := generatorInput.Token != nil fmt.Fprintf(out, "--> Installing application from %q\n", refInput) if locatedImage := describeLocatedImage(refInput, baseNamespace); len(locatedImage) > 0 { fmt.Fprintf(out, " * %s\n", locatedImage) } fmt.Fprintf(out, " * Install will run in pod %q\n", localOrRemoteName(pod.ObjectMeta, baseNamespace)) switch { case secret != nil: fmt.Fprintf(out, " * The pod has access to your current session token through the secret %q\n", localOrRemoteName(secret.ObjectMeta, baseNamespace)) fmt.Fprintf(out, " * If you cancel the install, you should delete the secret or log out of your session\n") case hasToken && generatorInput.Token.Env != nil: fmt.Fprintf(out, " * The pod has access to your current session token via environment variable %s\n", *generatorInput.Token.Env) fmt.Fprintf(out, " * If you cancel the install, you should delete the pod or log out of your session\n") case hasToken: fmt.Fprintf(out, " * The pod has access to your current session token. Please delete the pod if you cancel the install\n") } if hasToken { fmt.Fprintf(out, "--> WARNING: The pod requires access to your current session token to install this image. Only\n") fmt.Fprintf(out, " grant access to images whose source you trust. The image will be able to perform any\n") fmt.Fprintf(out, " action you can take on the cluster.\n") } }
func describeGeneratedTemplate(out io.Writer, ref app.ComponentReference, result *templateapi.Template, baseNamespace string) { fmt.Fprintf(out, "--> Deploying template %s for %q\n", localOrRemoteName(ref.Input().ResolvedMatch.Template.ObjectMeta, baseNamespace), ref.Input()) if len(result.Parameters) > 0 { fmt.Fprintf(out, " With parameters:\n") for _, p := range result.Parameters { name := p.DisplayName if len(name) == 0 { name = p.Name } var generated string if len(p.Generate) > 0 { generated = " # generated" } fmt.Fprintf(out, " %s=%s%s\n", name, p.Value, generated) } } }
func describeGeneratedJob(out io.Writer, ref app.ComponentReference, pod *kapi.Pod, secret *kapi.Secret, baseNamespace string) { refInput := ref.Input() generatorInput := refInput.ResolvedMatch.GeneratorInput hasToken := generatorInput.Token != nil fmt.Fprintf(out, "--> Installing application from %q\n", refInput) if locatedImage := describeLocatedImage(refInput, baseNamespace); len(locatedImage) > 0 { fmt.Fprintf(out, " * %s\n", locatedImage) } fmt.Fprintf(out, " * Install will run in pod %s\n", localOrRemoteName(pod.ObjectMeta, baseNamespace)) switch { case secret != nil: fmt.Fprintf(out, " * The pod has access to your current session token through the secret %s.\n", localOrRemoteName(secret.ObjectMeta, baseNamespace)) fmt.Fprintf(out, " If you cancel the install, you should delete the secret or log out of your session.\n") case hasToken && generatorInput.Token.Env != nil: fmt.Fprintf(out, " * The pod has access to your current session token via environment variable %s.\n", *generatorInput.Token.Env) fmt.Fprintf(out, " If you cancel the install, you should delete the pod or log out of your session.\n") case hasToken && generatorInput.Token.ServiceAccount: fmt.Fprintf(out, " * The pod will use the 'installer' service account. If this account does not exist\n") fmt.Fprintf(out, " with sufficient permissions, you may need to ask a project admin set it up.\n") case hasToken: fmt.Fprintf(out, " * The pod has access to your current session token. Please delete the pod if you cancel the install.\n") } if hasToken { if generatorInput.Token.ServiceAccount { fmt.Fprintf(out, "--> WARNING: The pod requires access to the 'installer' service account to install this\n") fmt.Fprintf(out, " image. Only grant access to images whose source you trust. The image will be able\n") fmt.Fprintf(out, " to act as an editor within this project.\n") } else { fmt.Fprintf(out, "--> WARNING: The pod requires access to your current session token to install this image. Only\n") fmt.Fprintf(out, " grant access to images whose source you trust. The image will be able to perform any\n") fmt.Fprintf(out, " action you can take on the cluster.\n") } } }
func describeBuildPipelineWithImage(out io.Writer, ref app.ComponentReference, pipeline *app.Pipeline, baseNamespace string) { refInput := ref.Input() match := refInput.ResolvedMatch if locatedImage := describeLocatedImage(refInput, baseNamespace); len(locatedImage) > 0 { fmt.Fprintf(out, "--> %s\n", locatedImage) } trackedImage := extractFirstImageStreamTag(true, pipeline.InputImage, pipeline.Image) if len(trackedImage) > 0 { fmt.Fprintf(out, " * An image stream will be created as %q that will track this image\n", trackedImage) } if pipeline.Build != nil { if refInput.Uses != nil && refInput.Uses.Info() != nil { matches := []string{} for _, t := range refInput.Uses.Info().Types { if len(t.Platform) == 0 { continue } if len(t.Version) > 0 { matches = append(matches, fmt.Sprintf("%s %s", t.Platform, t.Version)) } matches = append(matches, t.Platform) } if len(matches) > 0 { fmt.Fprintf(out, " * The source repository appears to match: %s\n", strings.Join(matches, ", ")) } } var strategy string if pipeline.Build.Strategy.IsDockerBuild { strategy = "Docker" } else { strategy = "source" } var source string switch s := pipeline.Build.Source; { case s.Binary: source = "binary input" case len(s.DockerfileContents) > 0: source = "a predefined Dockerfile" case s.URL != nil: source = fmt.Sprintf("source code from %s", s.URL) default: source = "<unknown>" } fmt.Fprintf(out, " * A %s build using %s will be created\n", strategy, source) if buildOut, err := pipeline.Build.Output.BuildOutput(); err == nil && buildOut != nil && buildOut.To != nil { switch to := buildOut.To; { case to.Kind == "ImageStreamTag": fmt.Fprintf(out, " * The resulting image will be pushed to image stream %q\n", to.Name) case to.Kind == "DockerImage": fmt.Fprintf(out, " * The resulting image will be pushed with Docker to %q\n", to.Name) default: fmt.Fprintf(out, " * The resulting image will be pushed to %s %q\n", to.Kind, to.Name) } } if len(trackedImage) > 0 && !pipeline.Build.Source.Binary { fmt.Fprintf(out, " * Every time %q changes a new build will be triggered\n", trackedImage) } } if pipeline.Deployment != nil { if len(pipeline.Deployment.Images) > 1 { fmt.Fprintf(out, " * This image will be deployed as part of deployment config %q\n", pipeline.Deployment.Name) } else { fmt.Fprintf(out, " * This image will be deployed in deployment config %q\n", pipeline.Deployment.Name) } if pipeline.Image != nil && pipeline.Image.HasEmptyDir { fmt.Fprintf(out, " * This image declares volumes and will default to use non-persistent, host-local storage.\n") fmt.Fprintf(out, " You can add persistent volumes later by running 'volume dc/%s --add ...'\n", pipeline.Deployment.Name) } } if match.Image != nil { if pipeline.Deployment != nil { ports := sets.NewString() if match.Image.Config != nil { for k := range match.Image.Config.ExposedPorts { ports.Insert(k) } } switch len(ports) { case 0: fmt.Fprintf(out, " * The image does not expose any ports - if you want to load balance or send traffic to this component\n") fmt.Fprintf(out, " you will need to create a service with 'expose dc/%s --port=[port]' later\n", pipeline.Deployment.Name) default: orderedPorts := ports.List() sort.Sort(sort.StringSlice(orderedPorts)) if len(orderedPorts) == 1 { fmt.Fprintf(out, " * Port %s will be load balanced by service %q\n", orderedPorts[0], pipeline.Deployment.Name) } else { fmt.Fprintf(out, " * Ports %s will be load balanced by service %q\n", strings.Join(orderedPorts, ", "), pipeline.Deployment.Name) } } } } }
func describeBuildPipelineWithImage(out io.Writer, ref app.ComponentReference, pipeline *app.Pipeline, baseNamespace string) { refInput := ref.Input() match := refInput.ResolvedMatch if locatedImage := describeLocatedImage(refInput, baseNamespace); len(locatedImage) > 0 { fmt.Fprintf(out, "--> %s\n", locatedImage) annotations := inputAnnotations(refInput.ResolvedMatch) if desc := annotations["io.k8s.display-name"]; len(desc) > 0 { fmt.Fprintln(out) fmt.Fprintf(out, " %s \n", desc) fmt.Fprintf(out, " %s \n", strings.Repeat("-", len(desc))) } else { fmt.Fprintln(out) } if desc := annotations["io.k8s.description"]; len(desc) > 0 { fmt.Fprintf(out, " %s\n\n", desc) } if desc := annotations["io.openshift.tags"]; len(desc) > 0 { desc = strings.Join(strings.Split(desc, ","), ", ") fmt.Fprintf(out, " Tags: %s\n\n", desc) } } if pipeline.Build == nil { trackedImage := extractFirstImageStreamTag(true, pipeline.InputImage, pipeline.Image) if len(trackedImage) > 0 { fmt.Fprintf(out, " * An image stream will be created as %q that will track this image\n", trackedImage) } } else { trackedImage := extractFirstImageStreamTag(true, pipeline.InputImage) if len(trackedImage) > 0 { fmt.Fprintf(out, " * An image stream will be created as %q that will track the source image\n", trackedImage) } if refInput.Uses != nil && refInput.Uses.Info() != nil { matches := []string{} for _, t := range refInput.Uses.Info().Types { if len(t.Platform) == 0 { continue } if len(t.Version) > 0 { matches = append(matches, fmt.Sprintf("%s %s", t.Platform, t.Version)) } matches = append(matches, t.Platform) } if len(matches) > 0 && !pipeline.Build.Strategy.IsDockerBuild { fmt.Fprintf(out, " * The source repository appears to match: %s\n", strings.Join(matches, ", ")) } } var strategy string if pipeline.Build.Strategy.IsDockerBuild { strategy = "Docker" } else { strategy = "source" } noSource := false var source string switch s := pipeline.Build.Source; { case s.Binary: noSource = true source = "binary input" case len(s.DockerfileContents) > 0: source = "a predefined Dockerfile" case s.URL != nil && len(s.URL.Host) > 0: source = fmt.Sprintf("source code from %s", s.URL) case s.URL != nil: noSource = true source = "uploaded code" default: source = "<unknown>" } fmt.Fprintf(out, " * A %s build using %s will be created\n", strategy, source) if buildOut, err := pipeline.Build.Output.BuildOutput(); err == nil && buildOut != nil && buildOut.To != nil { switch to := buildOut.To; { case to.Kind == "ImageStreamTag": fmt.Fprintf(out, " * The resulting image will be pushed to image stream %q\n", to.Name) case to.Kind == "DockerImage": fmt.Fprintf(out, " * The resulting image will be pushed with Docker to %q\n", to.Name) default: fmt.Fprintf(out, " * The resulting image will be pushed to %s %q\n", to.Kind, to.Name) } } if noSource { // if we have no source, the user must always provide the source from the local dir(binary build) fmt.Fprintf(out, " * Use 'start-build --from-dir=DIR|--from-repo=DIR|--from-file=FILE' to trigger a new build\n") fmt.Fprintf(out, " * WARNING: a binary build was created, you must specify one of --from-dir|--from-file|--from-repo when starting builds\n") } else { if len(trackedImage) > 0 { // if we have a trackedImage/ICT and we have source, the build will be triggered automatically. fmt.Fprintf(out, " * Every time %q changes a new build will be triggered\n", trackedImage) } else { // if we have source (but not a tracked image), the user must manually trigger a build. fmt.Fprintf(out, " * Use 'start-build to trigger a new build\n") } } } if pipeline.Deployment != nil { if pipeline.Deployment.AsTest { if len(pipeline.Deployment.Images) > 1 { fmt.Fprintf(out, " * This image will be test deployed as part of deployment config %q\n", pipeline.Deployment.Name) } else { fmt.Fprintf(out, " * This image will be test deployed in deployment config %q\n", pipeline.Deployment.Name) } } else { if len(pipeline.Deployment.Images) > 1 { fmt.Fprintf(out, " * This image will be deployed as part of deployment config %q\n", pipeline.Deployment.Name) } else { fmt.Fprintf(out, " * This image will be deployed in deployment config %q\n", pipeline.Deployment.Name) } } } if match != nil && match.Image != nil { if pipeline.Deployment != nil { ports := sets.NewString() if match.Image.Config != nil { for k := range match.Image.Config.ExposedPorts { ports.Insert(k) } } switch len(ports) { case 0: fmt.Fprintf(out, " * The image does not expose any ports - if you want to load balance or send traffic to this component\n") fmt.Fprintf(out, " you will need to create a service with 'expose dc/%s --port=[port]' later\n", pipeline.Deployment.Name) default: orderedPorts := ports.List() sort.Sort(sort.StringSlice(orderedPorts)) if len(orderedPorts) == 1 { fmt.Fprintf(out, " * Port %s will be load balanced by service %q\n", orderedPorts[0], pipeline.Deployment.Name) } else { fmt.Fprintf(out, " * Ports %s will be load balanced by service %q\n", strings.Join(orderedPorts, ", "), pipeline.Deployment.Name) } fmt.Fprintf(out, " * Other containers can access this service through the hostname %q\n", pipeline.Deployment.Name) } if hasEmptyDir(match.Image) { fmt.Fprintf(out, " * This image declares volumes and will default to use non-persistent, host-local storage.\n") fmt.Fprintf(out, " You can add persistent volumes later by running 'volume dc/%s --add ...'\n", pipeline.Deployment.Name) } if hasRootUser(match.Image) { fmt.Fprintf(out, " * WARNING: Image %q runs as the 'root' user which may not be permitted by your cluster administrator\n", match.Name) } } } fmt.Fprintln(out) }