From 4aeb631c540fbfb737ededa3e8802f2615e78942 Mon Sep 17 00:00:00 2001 From: Blaize Kaye Date: Thu, 11 Apr 2024 07:50:45 +1200 Subject: [PATCH] Further work on option wrappers --- cmd/sync.go | 68 ++++++++++++++++++++++++++++++- synchers/prerequisiteSyncUtils.go | 4 +- synchers/sshOptionWrapper.go | 11 ++++- synchers/sshOptionWrapper_test.go | 8 ++-- synchers/syncdefs.go | 1 + synchers/syncutils.go | 23 +++++------ 6 files changed, 94 insertions(+), 21 deletions(-) diff --git a/cmd/sync.go b/cmd/sync.go index 28a358d..6d99b00 100644 --- a/cmd/sync.go +++ b/cmd/sync.go @@ -1,6 +1,7 @@ package cmd import ( + "errors" "fmt" "log" "os" @@ -38,6 +39,10 @@ var skipTargetImport bool var localTransferResourceName string var namedTransferResource string +var apiEndpoint string +var useSshPortal bool // This is our feature flag for now. With the major version, we change the ssh config details for lagoon-sync files +const fallbackApi = "https://api.lagoon.amazeeio.cloud/graphql" + var syncCmd = &cobra.Command{ Use: "sync [mariadb|files|mongodb|postgres|etc.]", Short: "Sync a resource type", @@ -168,6 +173,33 @@ func syncCommandRun(cmd *cobra.Command, args []string) { sshOptionWrapper := synchers.NewSshOptionWrapper(ProjectName, sshOptions) + if useSshPortal { + + //Let's work out the api endpoint + if configRoot.Api != "" && apiEndpoint != "" { + apiEndpoint = configRoot.Api + } + + apiConn := utils.ApiConn{} + err := apiConn.Init(apiEndpoint, sshKey, "ssh.main.lagoon-core.test6.amazee.io", "22") + if err != nil { + fmt.Println(err.Error()) + return + } + + defaultSshOption, sshopts, err := getEnvironmentSshDetails(apiConn, ProjectName, sshOptions) + if err != nil { + fmt.Println(err.Error()) + return + } + + sshOptionWrapper.SetDefaultSshOptions(defaultSshOption) + for envName, option := range sshopts { + sshOptionWrapper.AddSsshOptionForEnvironment(envName, option) + } + + } + // let's update the named transfer resource if it is set if namedTransferResource != "" { err = lagoonSyncer.SetTransferResource(namedTransferResource) @@ -208,6 +240,39 @@ func getServiceName(SyncerType string) string { return "cli" } +func getEnvironmentSshDetails(conn utils.ApiConn, projectName string, defaultSshOptions synchers.SSHOptions) (synchers.SSHOptions, map[string]synchers.SSHOptions, error) { + environments, err := conn.GetProjectEnvironmentDeployTargets(projectName) + retMap := map[string]synchers.SSHOptions{} + + if err != nil { + return synchers.SSHOptions{}, retMap, err + } + + var defaultOptions synchers.SSHOptions + defaultSet := false + + for _, environment := range *environments { + fmt.Println("Got environment %v - type: %v \n", environment.Name, environment.EnvironmentType) + retMap[environment.Name] = synchers.SSHOptions{ + Host: environment.DeployTarget.SSHHost, + Port: environment.DeployTarget.SSHPort, + Verbose: defaultSshOptions.Verbose, + PrivateKey: "", + SkipAgent: defaultSshOptions.SkipAgent, + RsyncArgs: defaultSshOptions.RsyncArgs, + } + + if environment.EnvironmentType == "production" { + defaultOptions = retMap[environment.Name] + defaultSet = true + } + } + if defaultSet == false { + return synchers.SSHOptions{}, retMap, errors.New("COULD NOT FIND DEFAULT OPTION SET") + } + return defaultOptions, retMap, nil +} + func confirmPrompt(message string) (bool, error) { prompt := promptui.Prompt{ Label: message, @@ -240,7 +305,8 @@ func init() { syncCmd.PersistentFlags().BoolVar(&skipTargetCleanup, "skip-target-cleanup", false, "Don't clean up any of the files generated on the target") syncCmd.PersistentFlags().BoolVar(&skipTargetImport, "skip-target-import", false, "This will skip the import step on the target, in combination with 'no-target-cleanup' this essentially produces a resource dump") syncCmd.PersistentFlags().StringVarP(&namedTransferResource, "transfer-resource-name", "", "", "The name of the temporary file to be used to transfer generated resources (db dumps, etc) - random /tmp file otherwise") - + syncCmd.PersistentFlags().StringVarP(&apiEndpoint, "api", "A", "", "Specify your lagoon api endpoint - required for ssh-portal integration") + syncCmd.PersistentFlags().BoolVar(&useSshPortal, "use-ssh-portal", false, "This will use the SSH Portal rather than the (soon to be removed) SSH Service on Lagoon core. Will become default in a future release.") // By default, we hook up the syncers.RunSyncProcess function to the runSyncProcess variable // by doing this, it lets us easily override it for testing the command - but for most of the time // this should be okay. diff --git a/synchers/prerequisiteSyncUtils.go b/synchers/prerequisiteSyncUtils.go index 53a3319..07a14b6 100644 --- a/synchers/prerequisiteSyncUtils.go +++ b/synchers/prerequisiteSyncUtils.go @@ -16,7 +16,7 @@ import ( func RunPrerequisiteCommand(environment Environment, syncer Syncer, syncerType string, dryRun bool, sshOptionWrapper *SSHOptionWrapper) (Environment, error) { - sshOptions := sshOptionWrapper.getSSHOptionsForEnvironment(environment.EnvironmentName) + sshOptions := sshOptionWrapper.GetSSHOptionsForEnvironment(environment.EnvironmentName) // We don't run prerequisite checks on these syncers for now. if syncerType == "files" || syncerType == "drupalconfig" { @@ -109,7 +109,7 @@ func RunPrerequisiteCommand(environment Environment, syncer Syncer, syncerType s func PrerequisiteCleanUp(environment Environment, rsyncPath string, dryRun bool, sshOptionWrapper *SSHOptionWrapper) error { - sshOptions := sshOptionWrapper.getSSHOptionsForEnvironment(environment.EnvironmentName) + sshOptions := sshOptionWrapper.GetSSHOptionsForEnvironment(environment.EnvironmentName) if rsyncPath == "" || rsyncPath == "rsync" || !strings.Contains(rsyncPath, "/tmp/") { return nil diff --git a/synchers/sshOptionWrapper.go b/synchers/sshOptionWrapper.go index 8647af0..b3d16d8 100644 --- a/synchers/sshOptionWrapper.go +++ b/synchers/sshOptionWrapper.go @@ -1,5 +1,7 @@ package synchers +import "fmt" + // sshOptionWrapper.go contains the logic for the new system for passing ssh portal data // SSHOptionWrapper is passed around instead of specific SSHOptions - this allows resolution of the ssh endpoint when and where it's needed @@ -17,7 +19,8 @@ func NewSshOptionWrapper(projectName string, defaultSshOptions SSHOptions) *SSHO } } -func (receiver *SSHOptionWrapper) getSSHOptionsForEnvironment(environmentName string) SSHOptions { +func (receiver *SSHOptionWrapper) GetSSHOptionsForEnvironment(environmentName string) SSHOptions { + fmt.Println("Got a request for : ", environmentName) sshOptionsMapValue, ok := receiver.Options[environmentName] if ok { return sshOptionsMapValue @@ -25,6 +28,10 @@ func (receiver *SSHOptionWrapper) getSSHOptionsForEnvironment(environmentName st return receiver.Default } -func (receiver *SSHOptionWrapper) addSsshOptionForEnvironment(environmentName string, sshOptions SSHOptions) { +func (receiver *SSHOptionWrapper) AddSsshOptionForEnvironment(environmentName string, sshOptions SSHOptions) { receiver.Options[environmentName] = sshOptions } + +func (receiver *SSHOptionWrapper) SetDefaultSshOptions(sshOptions SSHOptions) { + receiver.Default = sshOptions +} diff --git a/synchers/sshOptionWrapper_test.go b/synchers/sshOptionWrapper_test.go index 683744c..09a5182 100644 --- a/synchers/sshOptionWrapper_test.go +++ b/synchers/sshOptionWrapper_test.go @@ -65,8 +65,8 @@ func TestSSHOptionWrapper_getSSHOptionsForEnvironment(t *testing.T) { Options: tt.fields.Options, Default: tt.fields.Default, } - if got := receiver.getSSHOptionsForEnvironment(tt.args.environmentName); !reflect.DeepEqual(got, tt.want) { - t.Errorf("getSSHOptionsForEnvironment() = %v, want %v", got, tt.want) + if got := receiver.GetSSHOptionsForEnvironment(tt.args.environmentName); !reflect.DeepEqual(got, tt.want) { + t.Errorf("GetSSHOptionsForEnvironment() = %v, want %v", got, tt.want) } }) } @@ -115,8 +115,8 @@ func TestSSHOptionWrapper_addSsshOptionForEnvironment(t *testing.T) { Options: tt.fields.Options, Default: tt.fields.Default, } - receiver.addSsshOptionForEnvironment(tt.args.environmentName, tt.args.environmentSSHOptions) - if got := receiver.getSSHOptionsForEnvironment(tt.args.environmentName); !reflect.DeepEqual(got, tt.want) { + receiver.AddSsshOptionForEnvironment(tt.args.environmentName, tt.args.environmentSSHOptions) + if got := receiver.GetSSHOptionsForEnvironment(tt.args.environmentName); !reflect.DeepEqual(got, tt.want) { t.Errorf("getSSHOptionsForEnvironment() = %v, want %v", got, tt.want) } }) diff --git a/synchers/syncdefs.go b/synchers/syncdefs.go index 1de7e41..110d4fb 100644 --- a/synchers/syncdefs.go +++ b/synchers/syncdefs.go @@ -55,6 +55,7 @@ type Environment struct { // SyncherConfigRoot is used to unmarshall yaml config details generally type SyncherConfigRoot struct { + Api string `yaml:"api,omitempty" json:"api,omitempty"` Project string `yaml:"project" json:"project,omitempty"` LagoonSync map[string]interface{} `yaml:"lagoon-sync" json:"lagoonSync,omitempty"` Prerequisites []prerequisite.GatheredPrerequisite `yaml:"prerequisites" json:"prerequisites,omitempty"` diff --git a/synchers/syncutils.go b/synchers/syncutils.go index 3102fdc..f319523 100644 --- a/synchers/syncutils.go +++ b/synchers/syncutils.go @@ -28,12 +28,11 @@ func UnmarshallLagoonYamlToLagoonSyncStructure(data []byte) (SyncherConfigRoot, } type RunSyncProcessFunctionTypeArguments struct { - SourceEnvironment Environment - TargetEnvironment Environment - LagoonSyncer Syncer - SyncerType string - DryRun bool - //SshOptions SSHOptions + SourceEnvironment Environment + TargetEnvironment Environment + LagoonSyncer Syncer + SyncerType string + DryRun bool SshOptionWrapper *SSHOptionWrapper SkipSourceCleanup bool SkipTargetCleanup bool @@ -110,7 +109,7 @@ func SyncRunSourceCommand(remoteEnvironment Environment, syncer Syncer, dryRun b utils.LogProcessStep("Beginning export on source environment", remoteEnvironment.EnvironmentName) - sshOptions := sshOptionWrapper.getSSHOptionsForEnvironment(remoteEnvironment.EnvironmentName) + sshOptions := sshOptionWrapper.GetSSHOptionsForEnvironment(remoteEnvironment.EnvironmentName) remoteCommands := syncer.GetRemoteCommand(remoteEnvironment) for _, remoteCommand := range remoteCommands { @@ -225,8 +224,9 @@ func SyncRunTransfer(sourceEnvironment Environment, targetEnvironment Environmen sshOptionsStr.WriteString(fmt.Sprintf(" -i %s", sshOptions.PrivateKey)) } - sourceEnvSshOptions := sshOptionWrapper.getSSHOptionsForEnvironment(sourceEnvironmentName) + sourceEnvSshOptions := sshOptionWrapper.GetSSHOptionsForEnvironment(targetEnvironment.EnvironmentName) rsyncArgs := sshOptions.RsyncArgs + execString := fmt.Sprintf("%s %s --rsync-path=%s %s -e \"ssh%s -o LogLevel=FATAL -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p %s -l %s %s service=%s\" %s %s %s", targetEnvironment.RsyncPath, rsyncArgs, @@ -244,9 +244,8 @@ func SyncRunTransfer(sourceEnvironment Environment, targetEnvironment Environmen utils.LogExecutionStep(fmt.Sprintf("Running the following for target (%s)", targetEnvironment.EnvironmentName), execString) if !dryRun { - if executeRsyncRemotelyOnTarget { - TargetEnvSshOptions := sshOptionWrapper.getSSHOptionsForEnvironment(targetEnvironmentName) + TargetEnvSshOptions := sshOptionWrapper.GetSSHOptionsForEnvironment(targetEnvironmentName) err, output := utils.RemoteShellout(execString, targetEnvironment.GetOpenshiftProjectName(), TargetEnvSshOptions.Host, TargetEnvSshOptions.Port, TargetEnvSshOptions.PrivateKey, TargetEnvSshOptions.SkipAgent) utils.LogDebugInfo(output, nil) if err != nil { @@ -268,7 +267,7 @@ func SyncRunTargetCommand(targetEnvironment Environment, syncer Syncer, dryRun b utils.LogProcessStep("Beginning import on target environment", targetEnvironment.EnvironmentName) - sshOptions := sshOptionWrapper.getSSHOptionsForEnvironment(targetEnvironment.EnvironmentName) + sshOptions := sshOptionWrapper.GetSSHOptionsForEnvironment(targetEnvironment.EnvironmentName) targetCommands := syncer.GetLocalCommand(targetEnvironment) @@ -309,7 +308,7 @@ func SyncRunTargetCommand(targetEnvironment Environment, syncer Syncer, dryRun b func SyncCleanUp(environment Environment, syncer Syncer, dryRun bool, sshOptionWrapper *SSHOptionWrapper) error { transferResouce := syncer.GetTransferResource(environment) - sshOptions := sshOptionWrapper.getSSHOptionsForEnvironment(environment.EnvironmentName) + sshOptions := sshOptionWrapper.GetSSHOptionsForEnvironment(environment.EnvironmentName) if transferResouce.SkipCleanup == true { log.Printf("Skipping cleanup for %v on %v environment", transferResouce.Name, environment.EnvironmentName)