github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/engine/pkg/cmd/cli/cli_job_create.go (about)

     1  // Copyright 2022 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package cli
    15  
    16  import (
    17  	"context"
    18  	"fmt"
    19  	"io"
    20  	"os"
    21  
    22  	"github.com/pingcap/log"
    23  	"github.com/pingcap/tiflow/engine/enginepb"
    24  	cmdcontext "github.com/pingcap/tiflow/pkg/cmd/context"
    25  	"github.com/pingcap/tiflow/pkg/errors"
    26  	"github.com/spf13/cobra"
    27  	"go.uber.org/zap"
    28  )
    29  
    30  // jobCreateOptions defines flags for job create.
    31  type jobCreateOptions struct {
    32  	generalOpts *jobGeneralOptions
    33  
    34  	jobConfigStr string
    35  
    36  	jobID     string
    37  	jobType   enginepb.Job_Type
    38  	jobConfig []byte
    39  }
    40  
    41  // newJobCreateOptions creates new job options.
    42  func newJobCreateOptions(generalOpts *jobGeneralOptions) *jobCreateOptions {
    43  	return &jobCreateOptions{generalOpts: generalOpts}
    44  }
    45  
    46  // addFlags receives a *cobra.Command reference and binds
    47  // flags related to template printing to it.
    48  func (o *jobCreateOptions) addFlags(cmd *cobra.Command) {
    49  	if o == nil {
    50  		return
    51  	}
    52  
    53  	cmd.Flags().Var(newJobTypeValue(enginepb.Job_TypeUnknown, &o.jobType), "job-type", "job type, one of [FakeJob, CVSDemo, DM]")
    54  	cmd.Flags().StringVar(&o.jobConfigStr, "job-config", "", "path of config file for the job")
    55  	cmd.Flags().StringVar(&o.jobID, "job-id", "", "job id")
    56  
    57  	_ = cmd.MarkFlagRequired("job-type")
    58  }
    59  
    60  type jobTypeValue enginepb.Job_Type
    61  
    62  func newJobTypeValue(jobType enginepb.Job_Type, p *enginepb.Job_Type) *jobTypeValue {
    63  	*p = jobType
    64  	return (*jobTypeValue)(p)
    65  }
    66  
    67  func (v *jobTypeValue) String() string {
    68  	if enginepb.Job_Type(*v) == enginepb.Job_TypeUnknown {
    69  		return ""
    70  	}
    71  	return enginepb.Job_Type(*v).String()
    72  }
    73  
    74  func (v *jobTypeValue) Set(val string) error {
    75  	switch val {
    76  	case "FakeJob":
    77  		*v = jobTypeValue(enginepb.Job_FakeJob)
    78  	case "CVSDemo":
    79  		*v = jobTypeValue(enginepb.Job_CVSDemo)
    80  	case "DM":
    81  		*v = jobTypeValue(enginepb.Job_DM)
    82  	default:
    83  		return fmt.Errorf("job type must be one of [FakeJob, CVSDemo, DM]")
    84  	}
    85  	return nil
    86  }
    87  
    88  func (v *jobTypeValue) Type() string {
    89  	return "job-type"
    90  }
    91  
    92  // validate checks that the provided job options are valid.
    93  func (o *jobCreateOptions) validate(ctx context.Context) error {
    94  	if err := o.generalOpts.validate(ctx); err != nil {
    95  		return errors.WrapError(errors.ErrInvalidCliParameter, err)
    96  	}
    97  
    98  	jobConfig, err := openFileAndReadString(o.jobConfigStr)
    99  	if err != nil {
   100  		return errors.WrapError(errors.ErrInvalidCliParameter, err)
   101  	}
   102  	o.jobConfig = jobConfig
   103  
   104  	return nil
   105  }
   106  
   107  func openFileAndReadString(path string) (content []byte, err error) {
   108  	if path == "" {
   109  		log.Warn("create job with empty config file")
   110  		return nil, nil
   111  	}
   112  	fp, err := os.Open(path)
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	defer fp.Close()
   117  	return io.ReadAll(fp)
   118  }
   119  
   120  // run the `cli job create` command.
   121  func (o *jobCreateOptions) run(ctx context.Context) error {
   122  	job, err := o.generalOpts.jobManagerCli.CreateJob(ctx, &enginepb.CreateJobRequest{
   123  		Job: &enginepb.Job{
   124  			Type:   o.jobType,
   125  			Config: o.jobConfig,
   126  		},
   127  		TenantId:  o.generalOpts.tenant.TenantID(),
   128  		ProjectId: o.generalOpts.tenant.ProjectID(),
   129  	})
   130  	if err != nil {
   131  		return err
   132  	}
   133  	log.Info("create job successfully", zap.Any("job", job))
   134  	return nil
   135  }
   136  
   137  // newCmdJobCreate creates the `cli job create` command.
   138  func newCmdJobCreate(generalOpts *jobGeneralOptions) *cobra.Command {
   139  	o := newJobCreateOptions(generalOpts)
   140  
   141  	command := &cobra.Command{
   142  		Use:   "create",
   143  		Short: "Create a new job",
   144  		Args:  cobra.NoArgs,
   145  		RunE: func(cmd *cobra.Command, args []string) error {
   146  			ctx := cmdcontext.GetDefaultContext()
   147  			if err := o.validate(ctx); err != nil {
   148  				return err
   149  			}
   150  
   151  			return o.run(ctx)
   152  		},
   153  	}
   154  
   155  	o.addFlags(command)
   156  
   157  	return command
   158  }