歡迎關注我的公衆号:
type CreateJobOptions struct {//create job結構體
PrintFlags *genericclioptions.PrintFlags
PrintObj func(obj runtime.Object) error
Name string
Image string
From string
Command []string
Namespace string
Client batchv1client.BatchV1Interface
DryRun bool
Builder *resource.Builder
Cmd *cobra.Command
genericclioptions.IOStreams
}
func NewCreateJobOptions(ioStreams genericclioptions.IOStreams) *CreateJobOptions {
return &CreateJobOptions{//初始化create job結構體
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
IOStreams: ioStreams,
}
}
//建立create job指令
func NewCmdCreateJob(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
o := NewCreateJobOptions(ioStreams)//初始化結構體
cmd := &cobra.Command{//建立cobra指令
Use: "job NAME --image=image [--from=cronjob/name] -- [COMMAND] [args...]",
Short: jobLong,
Long: jobLong,
Example: jobExample,
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)//設定print選項
cmdutil.AddApplyAnnotationFlags(cmd)//設定save-config選項
cmdutil.AddValidateFlags(cmd)//設定validate選項
cmdutil.AddDryRunFlag(cmd)//設定dry-run選項
cmd.Flags().StringVar(&o.Image, "image", o.Image, "Image name to run.")//設定image選項
cmd.Flags().StringVar(&o.From, "from", o.From, "The name of the resource to create a Job from (only cronjob is supported).")//設定from選項
return cmd
}
//準備方法
func (o *CreateJobOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
name, err := NameFromCommandArgs(cmd, args)//擷取名稱
if err != nil {
return err
}
o.Name = name//設定名稱
if len(args) > 1 {
o.Command = args[1:]//設定command參數
}
clientConfig, err := f.ToRESTConfig()//擷取restConfig
if err != nil {
return err
}
o.Client, err = batchv1client.NewForConfig(clientConfig)//根據restConfig擷取client
if err != nil {
return err
}
o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()//設定namespace
if err != nil {
return err
}
o.Builder = f.NewBuilder()//設定builder
o.Cmd = cmd//設定cmd
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 = func(obj runtime.Object) error {//設定printObj函數
return printer.PrintObj(obj, o.Out)
}
return nil
}
//校驗
func (o *CreateJobOptions) Validate() error {
if (len(o.Image) == 0 && len(o.From) == 0) || (len(o.Image) != 0 && len(o.From) != 0) {
return fmt.Errorf("either --image or --from must be specified")//image和from隻能指定一個
}
if o.Command != nil && len(o.Command) != 0 && len(o.From) != 0 {//command和from不能同時指定
return fmt.Errorf("cannot specify --from and command")
}
return nil
}
//運作指令
func (o *CreateJobOptions) Run() error {
var job *batchv1.Job
if len(o.Image) > 0 {//如果指定了image
job = o.createJob()//構造job對象
} else {//如果指定了from
infos, err := o.Builder.
Unstructured().
NamespaceParam(o.Namespace).DefaultNamespace().
ResourceTypeOrNameArgs(false, o.From).
Flatten().
Latest().
Do().
Infos()//擷取cronjob info對象
if err != nil {
return err
}
if len(infos) != 1 {//info必須是一個
return fmt.Errorf("from must be an existing cronjob")
}
uncastVersionedObj, err := scheme.Scheme.ConvertToVersion(infos[0].Object, batchv1beta1.SchemeGroupVersion)
if err != nil {
return fmt.Errorf("from must be an existing cronjob: %v", err)
}
cronJob, ok := uncastVersionedObj.(*batchv1beta1.CronJob)//把obj轉為cronJob
if !ok {
return fmt.Errorf("from must be an existing cronjob")
}
job = o.createJobFromCronJob(cronJob)//從cronjob建立job
}
if !o.DryRun {
var err error
job, err = o.Client.Jobs(o.Namespace).Create(job)//用client建立job
if err != nil {
return fmt.Errorf("failed to create job: %v", err)
}
}
return o.PrintObj(job)//列印結果
}
func (o *CreateJobOptions) createJob() *batchv1.Job {
return &batchv1.Job{//建立job對象
// this is ok because we know exactly how we want to be serialized
TypeMeta: metav1.TypeMeta{APIVersion: batchv1.SchemeGroupVersion.String(), Kind: "Job"},
ObjectMeta: metav1.ObjectMeta{
Name: o.Name,
},
Spec: batchv1.JobSpec{
Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: o.Name,
Image: o.Image,
Command: o.Command,
},
},
RestartPolicy: corev1.RestartPolicyNever,
},
},
},
}
}
//從cronjob建立job對象
func (o *CreateJobOptions) createJobFromCronJob(cronJob *batchv1beta1.CronJob) *batchv1.Job {
annotations := make(map[string]string)
annotations["cronjob.kubernetes.io/instantiate"] = "manual"
for k, v := range cronJob.Spec.JobTemplate.Annotations {
annotations[k] = v
}
return &batchv1.Job{
// this is ok because we know exactly how we want to be serialized
TypeMeta: metav1.TypeMeta{APIVersion: batchv1.SchemeGroupVersion.String(), Kind: "Job"},
ObjectMeta: metav1.ObjectMeta{
Name: o.Name,
Annotations: annotations,
Labels: cronJob.Spec.JobTemplate.Labels,
OwnerReferences: []metav1.OwnerReference{
*metav1.NewControllerRef(cronJob, appsv1.SchemeGroupVersion.WithKind("CronJob")),
},
},
Spec: cronJob.Spec.JobTemplate.Spec,
}
}