欢迎关注我的公众号:
————————————————-------------------------------------------------------------
type SetResourcesOptions struct {//setresource结构体
resource.FilenameOptions
PrintFlags *genericclioptions.PrintFlags
RecordFlags *genericclioptions.RecordFlags
Infos []*resource.Info
Selector string
ContainerSelector string
Output string
All bool
Local bool
DryRun bool
PrintObj printers.ResourcePrinterFunc
Recorder genericclioptions.Recorder
Limits string
Requests string
ResourceRequirements v1.ResourceRequirements
UpdatePodSpecForObject polymorphichelpers.UpdatePodSpecForObjectFunc
Resources []string
genericclioptions.IOStreams
}
func NewResourcesOptions(streams genericclioptions.IOStreams) *SetResourcesOptions {
return &SetResourcesOptions{初始化结构体
PrintFlags: genericclioptions.NewPrintFlags("resource requirements updated").WithTypeSetter(scheme.Scheme),
RecordFlags: genericclioptions.NewRecordFlags(),
Recorder: genericclioptions.NoopRecorder{},
ContainerSelector: "*",
IOStreams: streams,
}
}
//创建set resource命令
func NewCmdResources(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
o := NewResourcesOptions(streams)//初始化结构体
cmd := &cobra.Command{//创建cobra命令
Use: "resources (-f FILENAME | TYPE NAME) ([--limits=LIMITS & --requests=REQUESTS]",
DisableFlagsInUseLine: true,
Short: i18n.T("Update resource requests/limits on objects with pod templates"),
Long: fmt.Sprintf(resourcesLong, cmdutil.SuggestAPIResources("kubectl")),
Example: resourcesExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))//准备
cmdutil.CheckErr(o.Validate())//校验
cmdutil.CheckErr(o.Run())//运行
},
}
o.PrintFlags.AddFlags(cmd)//设置打印选项
o.RecordFlags.AddFlags(cmd)//设置record选项
//usage := "Filename, directory, or URL to a file identifying the resource to get from the server"
//kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage)
usage := "identifying the resource to get from a server."
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)//设置文件选项
cmd.Flags().BoolVar(&o.All, "all", o.All, "Select all resources, including uninitialized ones, in the namespace of the specified resource types")//设置all选项
cmd.Flags().StringVarP(&o.Selector, "selector", "l", o.Selector, "Selector (label query) to filter on, not including uninitialized ones,supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")//设置selector选项
cmd.Flags().StringVarP(&o.ContainerSelector, "containers", "c", o.ContainerSelector, "The names of containers in the selected pod templates to change, all containers are selected by default - may use wildcards")//设置container选项
cmd.Flags().BoolVar(&o.Local, "local", o.Local, "If true, set resources will NOT contact api-server but run locally.")//设置local选项
cmdutil.AddDryRunFlag(cmd)//设置干跑选项
cmdutil.AddIncludeUninitializedFlag(cmd)
cmd.Flags().StringVar(&o.Limits, "limits", o.Limits, "The resource requirement requests for this container. For example, 'cpu=100m,memory=256Mi'. Note that server side components may assign requests depending on the server configuration, such as limit ranges.")//设置limits选项
cmd.Flags().StringVar(&o.Requests, "requests", o.Requests, "The resource requirement requests for this container. For example, 'cpu=100m,memory=256Mi'. Note that server side components may assign requests depending on the server configuration, such as limit ranges.")//设置requests选项
return cmd
}
//准备函数
func (o *SetResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
var err error
o.RecordFlags.Complete(cmd)//record complete
o.Recorder, err = o.RecordFlags.ToRecorder()//record flag转recorder
if err != nil {
return err
}
o.UpdatePodSpecForObject = polymorphichelpers.UpdatePodSpecForObjectFn//设置updatePodSpecForObject函数
o.Output = cmdutil.GetFlagString(cmd, "output")//设置output
o.DryRun = cmdutil.GetDryRunFlag(cmd)//设置干跑
if o.DryRun {
o.PrintFlags.Complete("%s (dry run)")
}
printer, err := o.PrintFlags.ToPrinter()//print flag转printer
if err != nil {
return err
}
o.PrintObj = printer.PrintObj//设置printObj函数
cmdNamespace, enforceNamespace, err := f.ToRawKubeConfigLoader().Namespace()//获取namespace和enforceNamespace
if err != nil {
return err
}
builder := f.NewBuilder().
WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
LocalParam(o.Local).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions).
Flatten()//构造info对象
if !o.Local {
builder.LabelSelectorParam(o.Selector).
ResourceTypeOrNameArgs(o.All, args...).
Latest()
} else {
// if a --local flag was provided, and a resource was specified in the form
// <resource>/<name>, fail immediately as --local cannot query the api server
// for the specified resource.
// TODO: this should be in the builder - if someone specifies tuples, fail when
// local is true
if len(args) > 0 {
return resource.LocalResourceError
}
}
o.Infos, err = builder.Do().Infos()//设置info对象
if err != nil {
return err
}
return nil
}
//校验
func (o *SetResourcesOptions) Validate() error {
var err error
if o.All && len(o.Selector) > 0 {//all和selector不能同时设置
return fmt.Errorf("cannot set --all and --selector at the same time")
}
if len(o.Limits) == 0 && len(o.Requests) == 0 {//至少有一个limits或requests
return fmt.Errorf("you must specify an update to requests or limits (in the form of --requests/--limits)")
}
o.ResourceRequirements, err = generateversioned.HandleResourceRequirementsV1(map[string]string{"limits": o.Limits, "requests": o.Requests})//解析limits和requests参数
if err != nil {
return err
}
return nil
}
//运行
func (o *SetResourcesOptions) Run() error {
allErrs := []error{}
patches := CalculatePatches(o.Infos, scheme.DefaultJSONEncoder(), func(obj runtime.Object) ([]byte, error) {//计算patch
transformed := false
_, err := o.UpdatePodSpecForObject(obj, func(spec *v1.PodSpec) error {//更新pod
containers, _ := selectContainers(spec.Containers, o.ContainerSelector)//获取container
if len(containers) != 0 {
for i := range containers {//遍历containers
if len(o.Limits) != 0 && len(containers[i].Resources.Limits) == 0 {
containers[i].Resources.Limits = make(v1.ResourceList)//构造limits
}
for key, value := range o.ResourceRequirements.Limits {
containers[i].Resources.Limits[key] = value//设置limits
}
if len(o.Requests) != 0 && len(containers[i].Resources.Requests) == 0 {
containers[i].Resources.Requests = make(v1.ResourceList)//构造requests
}
for key, value := range o.ResourceRequirements.Requests {
containers[i].Resources.Requests[key] = value//设置requests
}
transformed = true
}
} else {
allErrs = append(allErrs, fmt.Errorf("error: unable to find container named %s", o.ContainerSelector))
}
return nil
})
if err != nil {
return nil, err
}
if !transformed {
return nil, nil
}
// record this change (for rollout history)
if err := o.Recorder.Record(obj); err != nil {//判断是否创建change-cause注解
klog.V(4).Infof("error recording current command: %v", err)
}
return runtime.Encode(scheme.DefaultJSONEncoder(), obj)//obj转json
})
for _, patch := range patches {//遍历patches
info := patch.Info
name := info.ObjectName()
if patch.Err != nil {
allErrs = append(allErrs, fmt.Errorf("error: %s %v\n", name, patch.Err))
continue
}
//no changes
if string(patch.Patch) == "{}" || len(patch.Patch) == 0 {
allErrs = append(allErrs, fmt.Errorf("info: %s was not changed\n", name))
continue
}
if o.Local || o.DryRun {//如果是lcoal或干跑,则打印对象
if err := o.PrintObj(info.Object, o.Out); err != nil {
allErrs = append(allErrs, err)
}
continue
}
actual, err := resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, types.StrategicMergePatchType, patch.Patch, nil)// 应用patch
if err != nil {
allErrs = append(allErrs, fmt.Errorf("failed to patch limit update to pod template %v", err))
continue
}
if err := o.PrintObj(actual, o.Out); err != nil {//打印对象
allErrs = append(allErrs, err)
}
}
return utilerrors.NewAggregate(allErrs)
}