Пример #1
0
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
}
Пример #2
0
// 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
}
Пример #3
0
// 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
}
Пример #4
0
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
}
Пример #5
0
// 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
}
Пример #6
0
// 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
}
Пример #7
0
// 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
}
Пример #8
0
// 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
}
Пример #9
0
// 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
}
Пример #10
0
// 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
}
Пример #11
0
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
}
Пример #12
0
// 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)
}
Пример #13
0
// 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
}
Пример #14
0
// 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
}
Пример #15
0
// 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
}
Пример #16
0
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)
}
Пример #17
0
// 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
}
Пример #18
0
// 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
}
Пример #19
0
// 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
}