欢迎关注我的公众号:
————————————————----------------------------------------------------------------
type SetImageOptions struct {set image结构体
resource.FilenameOptions
PrintFlags *genericclioptions.PrintFlags
RecordFlags *genericclioptions.RecordFlags
Infos []*resource.Info
Selector string
DryRun bool
All bool
Output string
Local bool
ResolveImage ImageResolver
PrintObj printers.ResourcePrinterFunc
Recorder genericclioptions.Recorder
UpdatePodSpecForObject polymorphichelpers.UpdatePodSpecForObjectFunc
Resources []string
ContainerImages map[string]string
genericclioptions.IOStreams
}
func NewImageOptions(streams genericclioptions.IOStreams) *SetImageOptions {
return &SetImageOptions{//初始化结构体
PrintFlags: genericclioptions.NewPrintFlags("image updated").WithTypeSetter(scheme.Scheme),
RecordFlags: genericclioptions.NewRecordFlags(),
Recorder: genericclioptions.NoopRecorder{},
IOStreams: streams,
}
}
//创建set image 命令
func NewCmdImage(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
o := NewImageOptions(streams)//初始化结构体
cmd := &cobra.Command{//创建cobra命令
Use: "image (-f FILENAME | TYPE NAME) CONTAINER_NAME_1=CONTAINER_IMAGE_1 ... CONTAINER_NAME_N=CONTAINER_IMAGE_N",
DisableFlagsInUseLine: true,
Short: i18n.T("Update image of a pod template"),
Long: imageLong,
Example: imageExample,
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 := "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().BoolVar(&o.Local, "local", o.Local, "If true, set image will NOT contact api-server but run locally.")//设置local选项
cmdutil.AddDryRunFlag(cmd)//设置dryrun选项
cmdutil.AddIncludeUninitializedFlag(cmd)
return cmd
}
//准备运行
func (o *SetImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
var err error
o.RecordFlags.Complete(cmd)//complete record
o.Recorder, err = o.RecordFlags.ToRecorder()//record flag转recorder
if err != nil {
return err
}
o.UpdatePodSpecForObject = polymorphichelpers.UpdatePodSpecForObjectFn//设置updatePodSepc函数
o.DryRun = cmdutil.GetDryRunFlag(cmd)//设置干跑
o.Output = cmdutil.GetFlagString(cmd, "output")//设置output
o.ResolveImage = resolveImageFunc
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
}
o.Resources, o.ContainerImages, err = getResourcesAndImages(args)//设置resource和containerImage
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, o.Resources...).
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.
if len(o.Resources) > 0 {
return resource.LocalResourceError
}
}
o.Infos, err = builder.Do().Infos()//设置info对象
if err != nil {
return err
}
return nil
}
//校验函数
func (o *SetImageOptions) Validate() error {
errors := []error{}
if o.All && len(o.Selector) > 0 {//all和selector不能同时指定
errors = append(errors, fmt.Errorf("cannot set --all and --selector at the same time"))
}
if len(o.Resources) < 1 && cmdutil.IsFilenameSliceEmpty(o.Filenames, o.Kustomize) {//必须指定资源或文件
errors = append(errors, fmt.Errorf("one or more resources must be specified as <resource> <name> or <resource>/<name>"))
}
if len(o.ContainerImages) < 1 {//容器image不能为空
errors = append(errors, fmt.Errorf("at least one image update is required"))
} else if len(o.ContainerImages) > 1 && hasWildcardKey(o.ContainerImages) {//带*的容器image只能有一个
errors = append(errors, fmt.Errorf("all containers are already specified by *, but saw more than one container_name=container_image pairs"))
}
return utilerrors.NewAggregate(errors)
}
//运行命令
func (o *SetImageOptions) Run() error {
allErrs := []error{}
patches := CalculatePatches(o.Infos, scheme.DefaultJSONEncoder(), func(obj runtime.Object) ([]byte, error) {//构造patch
_, err := o.UpdatePodSpecForObject(obj, func(spec *v1.PodSpec) error {//更新对象的ped spec
for name, image := range o.ContainerImages {//遍历containerImage
resolvedImageName, err := o.ResolveImage(image)
if err != nil {
allErrs = append(allErrs, fmt.Errorf("error: unable to resolve image %q for container %q: %v", image, name, err))
if name == "*" {
break
}
continue
}
initContainerFound := setImage(spec.InitContainers, name, resolvedImageName)//更新init container
containerFound := setImage(spec.Containers, name, resolvedImageName)//更新container
if !containerFound && !initContainerFound {
allErrs = append(allErrs, fmt.Errorf("error: unable to find container named %q", name))
}
}
return nil
})
if err != nil {
return nil, err
}
// 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)//编码对象
})
for _, patch := range patches {//遍历patch
info := patch.Info
if patch.Err != nil {
name := info.ObjectName()
allErrs = append(allErrs, fmt.Errorf("error: %s %v\n", name, patch.Err))
continue
}
// no changes
if string(patch.Patch) == "{}" || len(patch.Patch) == 0 {
continue
}
if o.Local || o.DryRun {//如果是local或干跑,打印对象
if err := o.PrintObj(info.Object, o.Out); err != nil {
allErrs = append(allErrs, err)
}
continue
}
// patch the change
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 image update to pod template: %v", err))
continue
}
if err := o.PrintObj(actual, o.Out); err != nil {//打印对象
allErrs = append(allErrs, err)
}
}
return utilerrors.NewAggregate(allErrs)
}