github.com/jfrog/jfrog-cli-core/v2@v2.51.0/artifactory/commands/replication/template.go (about)

     1  package replication
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"os"
     7  
     8  	"github.com/c-bata/go-prompt"
     9  	"github.com/jfrog/jfrog-cli-core/v2/utils/config"
    10  	"github.com/jfrog/jfrog-cli-core/v2/utils/ioutils"
    11  	"github.com/jfrog/jfrog-client-go/utils/errorutils"
    12  	"github.com/jfrog/jfrog-client-go/utils/log"
    13  )
    14  
    15  const (
    16  	// Strings for prompt questions
    17  	SelectConfigKeyMsg = "Select the next configuration key" + ioutils.PressTabMsg
    18  
    19  	// Template types
    20  	TemplateType = "templateType"
    21  	JobType      = "jobType"
    22  	Create       = "create"
    23  	Pull         = "pull"
    24  	Push         = "push"
    25  
    26  	// Common replication configuration JSON keys
    27  	ServerId               = "serverId"
    28  	CronExp                = "cronExp"
    29  	RepoKey                = "repoKey"
    30  	TargetRepoKey          = "targetRepoKey"
    31  	EnableEventReplication = "enableEventReplication"
    32  	Enabled                = "enabled"
    33  	SyncDeletes            = "syncDeletes"
    34  	SyncProperties         = "syncProperties"
    35  	SyncStatistics         = "syncStatistics"
    36  	// Deprecated
    37  	PathPrefix               = "pathPrefix"
    38  	IncludePathPrefixPattern = "includePathPrefixPattern"
    39  	SocketTimeoutMillis      = "socketTimeoutMillis"
    40  	DisableProxy             = "disableProxy"
    41  )
    42  
    43  type ReplicationTemplateCommand struct {
    44  	path string
    45  }
    46  
    47  func NewReplicationTemplateCommand() *ReplicationTemplateCommand {
    48  	return &ReplicationTemplateCommand{}
    49  }
    50  
    51  func (rtc *ReplicationTemplateCommand) SetTemplatePath(path string) *ReplicationTemplateCommand {
    52  	rtc.path = path
    53  	return rtc
    54  }
    55  
    56  func (rtc *ReplicationTemplateCommand) CommandName() string {
    57  	return "rt_replication_template"
    58  }
    59  
    60  func (rtc *ReplicationTemplateCommand) ServerDetails() (*config.ServerDetails, error) {
    61  	// Since it's a local command, usage won't be reported.
    62  	return nil, nil
    63  }
    64  
    65  func getArtifactoryServerIds() []prompt.Suggest {
    66  	suggest := make([]prompt.Suggest, 0)
    67  	if configurations, _ := config.GetAllServersConfigs(); configurations != nil {
    68  		for _, conf := range configurations {
    69  			suggest = append(suggest, prompt.Suggest{Text: conf.ServerId})
    70  		}
    71  	}
    72  	return suggest
    73  }
    74  
    75  func (rtc *ReplicationTemplateCommand) Run() (err error) {
    76  	replicationTemplateQuestionnaire := &ioutils.InteractiveQuestionnaire{
    77  		MandatoryQuestionsKeys: []string{JobType, RepoKey},
    78  		QuestionsMap:           questionMap,
    79  	}
    80  	err = replicationTemplateQuestionnaire.Perform()
    81  	if err != nil {
    82  		return err
    83  	}
    84  	resBytes, err := json.Marshal(replicationTemplateQuestionnaire.AnswersMap)
    85  	if err != nil {
    86  		return errorutils.CheckError(err)
    87  	}
    88  	if err = os.WriteFile(rtc.path, resBytes, 0644); err != nil {
    89  		return errorutils.CheckError(err)
    90  	}
    91  	log.Info(fmt.Sprintf("Replication creation config template successfully created at %s.", rtc.path))
    92  	return nil
    93  }
    94  
    95  var questionMap = map[string]ioutils.QuestionInfo{
    96  	ioutils.OptionalKey: {
    97  		Msg:          "",
    98  		PromptPrefix: "Select the next property >",
    99  		AllowVars:    false,
   100  		Writer:       nil,
   101  		MapKey:       "",
   102  		Callback:     ioutils.OptionalKeyCallback,
   103  	},
   104  	TemplateType: {
   105  		Options: []prompt.Suggest{
   106  			{Text: Create, Description: "Template for creating a new replication"},
   107  		},
   108  		Msg:          "",
   109  		PromptPrefix: "Select the template type >",
   110  		AllowVars:    false,
   111  		Writer:       nil,
   112  		MapKey:       "",
   113  		Callback:     nil,
   114  	},
   115  	JobType: {
   116  		Options: []prompt.Suggest{
   117  			{Text: Pull, Description: "Pull replication"},
   118  			{Text: Push, Description: "Push replication"},
   119  		},
   120  		Msg:          "",
   121  		PromptPrefix: "Select replication job type" + ioutils.PressTabMsg,
   122  		AllowVars:    false,
   123  		Writer:       nil,
   124  		MapKey:       "",
   125  		Callback:     jobTypeCallback,
   126  	},
   127  	RepoKey: {
   128  		Msg:          "",
   129  		PromptPrefix: "Enter source repo key >",
   130  		AllowVars:    true,
   131  		Writer:       ioutils.WriteStringAnswer,
   132  		MapKey:       RepoKey,
   133  		Callback:     nil,
   134  	},
   135  	TargetRepoKey: {
   136  		Msg:          "",
   137  		PromptPrefix: "Enter target repo key >",
   138  		AllowVars:    true,
   139  		Writer:       ioutils.WriteStringAnswer,
   140  		MapKey:       TargetRepoKey,
   141  		Callback:     nil,
   142  	},
   143  	ServerId: {
   144  		Options:      getArtifactoryServerIds(),
   145  		Msg:          "",
   146  		PromptPrefix: "Enter target server id" + ioutils.PressTabMsg,
   147  		AllowVars:    true,
   148  		Writer:       ioutils.WriteStringAnswer,
   149  		MapKey:       ServerId,
   150  		Callback:     nil,
   151  	},
   152  	CronExp: {
   153  		Msg:          "",
   154  		PromptPrefix: "Enter cron expression for frequency (for example, 0 0 12 * * ? will replicate daily) >",
   155  		AllowVars:    true,
   156  		Writer:       ioutils.WriteStringAnswer,
   157  		MapKey:       CronExp,
   158  		Callback:     nil,
   159  	},
   160  	EnableEventReplication: BoolToStringQuestionInfo,
   161  	Enabled:                BoolToStringQuestionInfo,
   162  	SyncDeletes:            BoolToStringQuestionInfo,
   163  	SyncProperties:         BoolToStringQuestionInfo,
   164  	SyncStatistics:         BoolToStringQuestionInfo,
   165  	IncludePathPrefixPattern: {
   166  		Msg:          "",
   167  		PromptPrefix: "Enter include path prefix pattern >",
   168  		AllowVars:    true,
   169  		Writer:       ioutils.WriteStringAnswer,
   170  		MapKey:       IncludePathPrefixPattern,
   171  		Callback:     nil,
   172  	},
   173  	SocketTimeoutMillis: {
   174  		Msg:          "",
   175  		PromptPrefix: "Enter socket timeout millis >",
   176  		AllowVars:    true,
   177  		Writer:       ioutils.WriteStringAnswer,
   178  		MapKey:       SocketTimeoutMillis,
   179  		Callback:     nil,
   180  	},
   181  }
   182  
   183  func jobTypeCallback(iq *ioutils.InteractiveQuestionnaire, jobType string) (string, error) {
   184  	if jobType == Pull {
   185  		iq.MandatoryQuestionsKeys = append(iq.MandatoryQuestionsKeys, CronExp)
   186  	} else {
   187  		iq.MandatoryQuestionsKeys = append(iq.MandatoryQuestionsKeys, TargetRepoKey, ServerId, CronExp)
   188  	}
   189  	iq.OptionalKeysSuggests = getAllPossibleOptionalRepoConfKeys()
   190  	return "", nil
   191  }
   192  
   193  func getAllPossibleOptionalRepoConfKeys(values ...string) []prompt.Suggest {
   194  	optionalKeys := []string{ioutils.SaveAndExit, Enabled, SyncDeletes, SyncProperties, SyncStatistics, PathPrefix, IncludePathPrefixPattern, EnableEventReplication, SocketTimeoutMillis}
   195  	if len(values) > 0 {
   196  		optionalKeys = append(optionalKeys, values...)
   197  	}
   198  	return ioutils.GetSuggestsFromKeys(optionalKeys, suggestionMap)
   199  }
   200  
   201  // Specific writers for repo templates, since all the values in the templates should be written as string.
   202  var BoolToStringQuestionInfo = ioutils.QuestionInfo{
   203  	Options:   ioutils.GetBoolSuggests(),
   204  	AllowVars: true,
   205  	Writer:    ioutils.WriteStringAnswer,
   206  }
   207  
   208  var suggestionMap = map[string]prompt.Suggest{
   209  	ioutils.SaveAndExit:      {Text: ioutils.SaveAndExit},
   210  	ServerId:                 {Text: ServerId},
   211  	RepoKey:                  {Text: RepoKey},
   212  	TargetRepoKey:            {Text: TargetRepoKey},
   213  	CronExp:                  {Text: CronExp},
   214  	EnableEventReplication:   {Text: EnableEventReplication},
   215  	Enabled:                  {Text: Enabled},
   216  	SyncDeletes:              {Text: SyncDeletes},
   217  	SyncProperties:           {Text: SyncProperties},
   218  	SyncStatistics:           {Text: SyncStatistics},
   219  	PathPrefix:               {Text: PathPrefix},
   220  	IncludePathPrefixPattern: {Text: IncludePathPrefixPattern},
   221  	SocketTimeoutMillis:      {Text: SocketTimeoutMillis},
   222  	DisableProxy:             {Text: DisableProxy},
   223  }