Пример #1
0
// Complete collects information required to run Convert command from command line.
func (o *ConvertOptions) Complete(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) (err error) {
	o.outputVersion = cmdutil.OutputVersion(cmd, latest.GroupOrDie("").Version)
	if !registered.IsRegisteredAPIVersion(o.outputVersion) {
		cmdutil.UsageError(cmd, "'%s' is not a registered version.", o.outputVersion)
	}

	// build the builder
	mapper, typer := f.Object()
	if o.local {
		fmt.Fprintln(out, "running in local mode...")
		o.builder = resource.NewBuilder(mapper, typer, f.NilClientMapperForCommand())
	} else {
		o.builder = resource.NewBuilder(mapper, typer, f.ClientMapperForCommand())
		schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"), cmdutil.GetFlagString(cmd, "schema-cache-dir"))
		if err != nil {
			return err
		}
		o.builder = o.builder.Schema(schema)
	}
	cmdNamespace, _, err := f.DefaultNamespace()
	if err != nil {
		return err
	}
	o.builder = o.builder.NamespaceParam(cmdNamespace).
		ContinueOnError().
		FilenameParam(false, o.filenames...).
		Flatten()

	// build the printer
	o.out = out
	outputFormat := cmdutil.GetFlagString(cmd, "output")
	templateFile := cmdutil.GetFlagString(cmd, "template")
	if len(outputFormat) == 0 {
		if len(templateFile) == 0 {
			outputFormat = "yaml"
		} else {
			outputFormat = "template"
		}
	}
	o.printer, _, err = kubectl.GetPrinter(outputFormat, templateFile)
	if err != nil {
		return err
	}

	return nil
}
Пример #2
0
func NewCmdConfigView(out io.Writer, ConfigAccess ConfigAccess) *cobra.Command {
	options := &ViewOptions{ConfigAccess: ConfigAccess}

	cmd := &cobra.Command{
		Use:     "view",
		Short:   "Displays merged kubeconfig settings or a specified kubeconfig file.",
		Long:    view_long,
		Example: view_example,
		Run: func(cmd *cobra.Command, args []string) {
			options.Complete()

			printer, _, err := cmdutil.PrinterForCommand(cmd)
			if err != nil {
				glog.FatalDepth(1, err)
			}
			version := cmdutil.OutputVersion(cmd, latest.Version)
			printer = kubectl.NewVersionedPrinter(printer, clientcmdapi.Scheme, version)

			if err := options.Run(out, printer); err != nil {
				glog.FatalDepth(1, err)
			}

		},
	}

	cmdutil.AddPrinterFlags(cmd)
	// Default to yaml
	cmd.Flags().Set("output", "yaml")

	options.Merge.Default(true)
	cmd.Flags().Var(&options.Merge, "merge", "merge together the full hierarchy of kubeconfig files")
	cmd.Flags().BoolVar(&options.RawByteData, "raw", false, "display raw byte data")
	cmd.Flags().BoolVar(&options.Flatten, "flatten", false, "flatten the resulting kubeconfig file into self contained output (useful for creating portable kubeconfig files)")
	cmd.Flags().BoolVar(&options.Minify, "minify", false, "remove all information not used by current-context from the output")
	return cmd
}
Пример #3
0
// RunGet implements the generic Get command
// TODO: convert all direct flag accessors to a struct and pass that instead of cmd
func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, options *GetOptions) error {
	selector := cmdutil.GetFlagString(cmd, "selector")
	allNamespaces := cmdutil.GetFlagBool(cmd, "all-namespaces")
	mapper, typer := f.Object()

	cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
	if err != nil {
		return err
	}

	if len(args) == 0 && len(options.Filenames) == 0 {
		fmt.Fprint(out, "You must specify the type of resource to get. ", valid_resources, `   * componentstatuses (aka 'cs')
   * endpoints (aka 'ep')
`)
		return cmdutil.UsageError(cmd, "Required resource not specified.")
	}

	// handle watch separately since we cannot watch multiple resource types
	isWatch, isWatchOnly := cmdutil.GetFlagBool(cmd, "watch"), cmdutil.GetFlagBool(cmd, "watch-only")
	if isWatch || isWatchOnly {
		r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
			NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
			FilenameParam(enforceNamespace, options.Filenames...).
			SelectorParam(selector).
			ResourceTypeOrNameArgs(true, args...).
			SingleResourceType().
			Latest().
			Do()
		err := r.Err()
		if err != nil {
			return err
		}
		infos, err := r.Infos()
		if err != nil {
			return err
		}
		if len(infos) != 1 {
			return fmt.Errorf("watch is only supported on individual resources and resource collections - %d resources were found", len(infos))
		}
		info := infos[0]
		mapping := info.ResourceMapping()
		printer, err := f.PrinterForMapping(cmd, mapping, allNamespaces)
		if err != nil {
			return err
		}

		obj, err := r.Object()
		if err != nil {
			return err
		}
		rv, err := mapping.MetadataAccessor.ResourceVersion(obj)
		if err != nil {
			return err
		}

		// print the current object
		if !isWatchOnly {
			if err := printer.PrintObj(obj, out); err != nil {
				return fmt.Errorf("unable to output the provided object: %v", err)
			}
		}

		// print watched changes
		w, err := r.Watch(rv)
		if err != nil {
			return err
		}

		kubectl.WatchLoop(w, func(e watch.Event) error {
			return printer.PrintObj(e.Object, out)
		})
		return nil
	}

	b := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
		NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
		FilenameParam(enforceNamespace, options.Filenames...).
		SelectorParam(selector).
		ResourceTypeOrNameArgs(true, args...).
		ContinueOnError().
		Latest()
	printer, generic, err := cmdutil.PrinterForCommand(cmd)
	if err != nil {
		return err
	}

	if generic {
		clientConfig, err := f.ClientConfig()
		if err != nil {
			return err
		}
		defaultVersion := clientConfig.Version

		singular := false
		r := b.Flatten().Do()
		infos, err := r.IntoSingular(&singular).Infos()
		if err != nil {
			return err
		}

		// the outermost object will be converted to the output-version, but inner
		// objects can use their mappings
		version := cmdutil.OutputVersion(cmd, defaultVersion)
		obj, err := resource.AsVersionedObject(infos, !singular, version)
		if err != nil {
			return err
		}

		return printer.PrintObj(obj, out)
	}

	// use the default printer for each object
	printer = nil
	var lastMapping *meta.RESTMapping
	w := kubectl.GetNewTabWriter(out)
	defer w.Flush()
	return b.Flatten().Do().Visit(func(r *resource.Info, err error) error {
		if err != nil {
			return err
		}
		if printer == nil || lastMapping == nil || r.Mapping == nil || r.Mapping.Resource != lastMapping.Resource {
			printer, err = f.PrinterForMapping(cmd, r.Mapping, allNamespaces)
			if err != nil {
				return err
			}
			lastMapping = r.Mapping
		}
		if _, found := printer.(*kubectl.HumanReadablePrinter); found {
			return printer.PrintObj(r.Object, w)
		}
		return printer.PrintObj(r.Object, out)
	})
}
Пример #4
0
func RunEdit(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, filenames []string) 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, enforceNamespace, err := f.DefaultNamespace()
	if err != nil {
		return err
	}

	mapper, typer := f.Object()
	rmap := &resource.Mapper{
		ObjectTyper:  typer,
		RESTMapper:   mapper,
		ClientMapper: f.ClientMapperForCommand(),
	}

	r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
		NamespaceParam(cmdNamespace).DefaultNamespace().
		FilenameParam(enforceNamespace, filenames...).
		ResourceTypeOrNameArgs(true, args...).
		Latest().
		Flatten().
		Do()
	err = r.Err()
	if err != nil {
		return err
	}

	infos, err := r.Infos()
	if err != nil {
		return err
	}

	clientConfig, err := f.ClientConfig()
	if err != nil {
		return err
	}

	defaultVersion := cmdutil.OutputVersion(cmd, clientConfig.Version)
	results := editResults{}
	for {
		objs, err := resource.AsVersionedObjects(infos, defaultVersion)
		if err != nil {
			return preservedFile(err, results.file, out)
		}
		// if input object is a list, traverse and edit each item one at a time
		for _, obj := range objs {
			// 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, out)
			}
			if err := printer.PrintObj(obj, buf); err != nil {
				return preservedFile(err, results.file, out)
			}
			original := buf.Bytes()

			// launch the editor
			edit := editor.NewDefaultEditor()
			edited, file, err := edit.LaunchTempFile("kubectl-edit-", ext, buf)
			if err != nil {
				return preservedFile(err, results.file, 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, out)
			}
			// Compare content without comments
			if bytes.Equal(stripComments(original), stripComments(edited)) {
				if len(results.edit) > 0 {
					preservedFile(nil, file, out)
				} else {
					os.Remove(file)
				}
				fmt.Fprintln(out, "Edit cancelled, no changes made.")
				continue
			}
			if !lines {
				if len(results.edit) > 0 {
					preservedFile(nil, file, out)
				} else {
					os.Remove(file)
				}
				fmt.Fprintln(out, "Edit cancelled, saved file was empty.")
				continue
			}

			results = editResults{
				file: file,
			}

			// parse the edited file
			updates, err := rmap.InfoForData(edited, "edited-file")
			if err != nil {
				return fmt.Errorf("The edited file had a syntax error: %v", err)
			}

			// annotate the edited object for kubectl apply
			if err := kubectl.UpdateApplyAnnotation(updates); err != nil {
				return preservedFile(err, file, out)
			}

			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, out)
			}

			// use strategic merge to create a patch
			originalJS, err := yaml.ToJSON(original)
			if err != nil {
				return preservedFile(err, file, out)
			}
			editedJS, err := yaml.ToJSON(edited)
			if err != nil {
				return preservedFile(err, file, out)
			}
			patch, err := strategicpatch.CreateStrategicMergePatch(originalJS, editedJS, obj)
			// TODO: change all jsonmerge to strategicpatch
			// for checking preconditions
			preconditions := []jsonmerge.PreconditionFunc{}
			if err != nil {
				glog.V(4).Infof("Unable to calculate diff, no merge is possible: %v", err)
				return preservedFile(err, file, out)
			} else {
				preconditions = append(preconditions, jsonmerge.RequireKeyUnchanged("apiVersion"))
				preconditions = append(preconditions, jsonmerge.RequireKeyUnchanged("kind"))
				preconditions = append(preconditions, jsonmerge.RequireMetadataKeyUnchanged("name"))
				results.version = defaultVersion
			}

			if hold, msg := jsonmerge.TestPreconditionsHold(patch, preconditions); !hold {
				fmt.Fprintf(out, "error: %s", msg)
				return preservedFile(nil, file, out)
			}

			err = visitor.Visit(func(info *resource.Info, err error) error {
				patched, err := resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, api.StrategicMergePatchType, patch)
				if err != nil {
					fmt.Fprintln(out, results.addError(err, info))
					return nil
				}
				info.Refresh(patched, true)
				cmdutil.PrintSuccess(mapper, false, out, info.Mapping.Resource, info.Name, "edited")
				return nil
			})
			if err != nil {
				return preservedFile(err, file, out)
			}

			if results.retryable > 0 {
				fmt.Fprintf(out, "You can run `kubectl replace -f %s` to try this update again.\n", file)
				return errExit
			}
			if results.conflict > 0 {
				fmt.Fprintf(out, "You must update your local resource version and run `kubectl replace -f %s` to overwrite the remote changes.\n", file)
				return errExit
			}
			if len(results.edit) == 0 {
				if results.notfound == 0 {
					os.Remove(file)
				} else {
					fmt.Fprintf(out, "The edits you made on deleted resources have been saved to %q\n", file)
				}
			}
		}
		if len(results.edit) == 0 {
			return nil
		}

		// loop again and edit the remaining items
		infos = results.edit
	}
	return nil
}