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