diff --git a/cmd/config.go b/cmd/config.go index 9b6021e..8dd86b4 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -35,7 +35,7 @@ func init() { var configCmd = &cobra.Command{ Use: "config", - Short: "Print the onfig that is being used by lagoon-sync", + Short: "Print the config that is being used by lagoon-sync", Run: func(v *cobra.Command, args []string) { PrintConfigOut() }, diff --git a/prerequisite/prerequisitedefs.go b/prerequisite/prerequisitedefs.go index a4a21ae..7bc3199 100644 --- a/prerequisite/prerequisitedefs.go +++ b/prerequisite/prerequisitedefs.go @@ -1,7 +1,5 @@ package prerequisite -import "log" - type GatheredPrerequisite struct { Name string `json:"name"` Value string `json:"value"` @@ -19,7 +17,7 @@ type ConfigPrerequisite interface { var configPrerequisiteList []ConfigPrerequisite func RegisterConfigPrerequisite(name string, config ConfigPrerequisite) { - log.Println("Registering: " + name) + //log.Println("Registering: " + name) configPrerequisiteList = append(configPrerequisiteList, config) } diff --git a/prerequisite/rsyncprerequisite.go b/prerequisite/rsyncprerequisite.go index 1c9cc89..5faa3d8 100644 --- a/prerequisite/rsyncprerequisite.go +++ b/prerequisite/rsyncprerequisite.go @@ -31,7 +31,7 @@ func (p *rsyncPrerequisite) GetValue() bool { } p.RsyncPath = strings.TrimSuffix(stdout.String(), "\n") - log.Println("Found rsync path: " + p.RsyncPath) + //log.Println("Found rsync path: " + p.RsyncPath) return true } diff --git a/synchers/drupalconfig.go b/synchers/drupalconfig.go index a121f34..eeb034b 100644 --- a/synchers/drupalconfig.go +++ b/synchers/drupalconfig.go @@ -54,7 +54,7 @@ func (root DrupalconfigSyncRoot) PrepareSyncer() (Syncer, error) { return root, nil } -func (root DrupalconfigSyncRoot) GetPrerequisiteCommand(environment Environment) SyncCommand { +func (root DrupalconfigSyncRoot) GetPrerequisiteCommand(environment Environment, command string) SyncCommand { return SyncCommand{} } diff --git a/synchers/files.go b/synchers/files.go index 3d9995f..8f43aae 100644 --- a/synchers/files.go +++ b/synchers/files.go @@ -58,7 +58,7 @@ func (root FilesSyncRoot) PrepareSyncer() (Syncer, error) { return root, nil } -func (root FilesSyncRoot) GetPrerequisiteCommand(environment Environment) SyncCommand { +func (root FilesSyncRoot) GetPrerequisiteCommand(environment Environment, command string) SyncCommand { return SyncCommand{} } diff --git a/synchers/mariadb.go b/synchers/mariadb.go index a1e10cc..c9ed5a1 100644 --- a/synchers/mariadb.go +++ b/synchers/mariadb.go @@ -82,11 +82,14 @@ func (root MariadbSyncRoot) PrepareSyncer() (Syncer, error) { return root, nil } -func (root MariadbSyncRoot) GetPrerequisiteCommand(environment Environment) SyncCommand { +func (root MariadbSyncRoot) GetPrerequisiteCommand(environment Environment, command string) SyncCommand { + lagoonSyncBin := "/tmp/lagoon-sync" + return SyncCommand{ - command: fmt.Sprintf("./lagoon-sync {{ .config }}"), + command: fmt.Sprintf("{{ .bin }} {{ .command }} 2> /dev/null"), substitutions: map[string]interface{}{ - "config": "config", + "bin": lagoonSyncBin, + "command": command, }, } } diff --git a/synchers/postgres.go b/synchers/postgres.go index 9eeff67..ef8a88e 100644 --- a/synchers/postgres.go +++ b/synchers/postgres.go @@ -79,11 +79,14 @@ func (root PostgresSyncRoot) PrepareSyncer() (Syncer, error) { return root, nil } -func (root PostgresSyncRoot) GetPrerequisiteCommand(environment Environment) SyncCommand { +func (root PostgresSyncRoot) GetPrerequisiteCommand(environment Environment, command string) SyncCommand { + lagoonSyncBin := "which lagoon-sync" + return SyncCommand{ - command: fmt.Sprintf("./lagoon-sync {{ .config }}"), + command: fmt.Sprintf("{{ .bin }} {{ .command }}"), substitutions: map[string]interface{}{ - "config": "config", + "bin": lagoonSyncBin, + "command": command, }, } } diff --git a/synchers/syncdefs.go b/synchers/syncdefs.go index d81cc8f..443ec0c 100644 --- a/synchers/syncdefs.go +++ b/synchers/syncdefs.go @@ -11,7 +11,7 @@ import ( const LOCAL_ENVIRONMENT_NAME = "local" type Syncer interface { - GetPrerequisiteCommand(environmnt Environment) SyncCommand + GetPrerequisiteCommand(environmnt Environment, command string) SyncCommand // GetRemoteCommand will return the command to be run on the source system GetRemoteCommand(environment Environment) SyncCommand // GetLocalCommand will return the command to be run on the target system @@ -40,6 +40,8 @@ type Environment struct { EnvironmentName string ServiceName string //This is used to determine which Lagoon service we need to rsync RsyncAvailable bool + RsyncPath string + RsyncLocalPath string } func (r Environment) getOpenshiftProjectName() string { diff --git a/synchers/syncutils.go b/synchers/syncutils.go index 58bcc3e..789980f 100644 --- a/synchers/syncutils.go +++ b/synchers/syncutils.go @@ -8,6 +8,7 @@ import ( "log" "os" "os/exec" + "strings" "text/template" "gopkg.in/yaml.v2" @@ -25,13 +26,12 @@ func UnmarshallLagoonYamlToLagoonSyncStructure(data []byte) (SyncherConfigRoot, func RunSyncProcess(sourceEnvironment Environment, targetEnvironment Environment, lagoonSyncer Syncer, dryRun bool) error { var err error - err = RunPrerequisiteCommand(sourceEnvironment, lagoonSyncer, dryRun) + sourceRsyncPath, err := RunPrerequisiteCommand(sourceEnvironment, lagoonSyncer, dryRun) if err != nil { + _ = PrerequisiteCleanUp(sourceEnvironment, sourceRsyncPath, dryRun) return err } - os.Exit(1) - err = SyncRunSourceCommand(sourceEnvironment, lagoonSyncer, dryRun) if err != nil { _ = SyncCleanUp(sourceEnvironment, lagoonSyncer, dryRun) @@ -43,6 +43,11 @@ func RunSyncProcess(sourceEnvironment Environment, targetEnvironment Environment return err } + targetRsyncPath, err := RunPrerequisiteCommand(targetEnvironment, lagoonSyncer, dryRun) + if err != nil { + _ = PrerequisiteCleanUp(targetEnvironment, targetRsyncPath, dryRun) + return err + } err = SyncRunTargetCommand(targetEnvironment, lagoonSyncer, dryRun) if err != nil { _ = SyncCleanUp(sourceEnvironment, lagoonSyncer, dryRun) @@ -50,20 +55,22 @@ func RunSyncProcess(sourceEnvironment Environment, targetEnvironment Environment return err } + _ = PrerequisiteCleanUp(sourceEnvironment, sourceRsyncPath, dryRun) + _ = PrerequisiteCleanUp(targetEnvironment, targetRsyncPath, dryRun) _ = SyncCleanUp(sourceEnvironment, lagoonSyncer, dryRun) _ = SyncCleanUp(targetEnvironment, lagoonSyncer, dryRun) return nil } -func RunPrerequisiteCommand(environment Environment, syncer Syncer, dryRun bool) error { +func RunPrerequisiteCommand(environment Environment, syncer Syncer, dryRun bool) (string, error) { log.Printf("Running prerequisite checks on %s environment", environment.EnvironmentName) var execString string - command, commandErr := syncer.GetPrerequisiteCommand(environment).GetCommand() + command, commandErr := syncer.GetPrerequisiteCommand(environment, "config").GetCommand() if commandErr != nil { - return commandErr + return "", commandErr } if environment.EnvironmentName == LOCAL_ENVIRONMENT_NAME { @@ -78,19 +85,41 @@ func RunPrerequisiteCommand(environment Environment, syncer Syncer, dryRun bool) err, responseJson, errstring := Shellout(execString) if err != nil { fmt.Println(errstring) - return err + return "", err } data := &PreRequisiteResponse{} json.Unmarshal([]byte(responseJson), &data) - fmt.Println("Response: %s", data) + // check if environment has rsync + if data.RysncPrequisite != nil { + environment.RsyncAvailable = true + for _, c := range data.RysncPrequisite { + if c.Value != "" { + environment.RsyncPath = c.Value + } + } + } + + lagoonVersion := "" + if data.Version != "" { + lagoonVersion = data.Version + } - // if data.RysncPrequisite != "" { - // environment.RsyncAvailable = true - // } + if !environment.RsyncAvailable { + // add rsync to env + rsyncPath, err := createRsync(environment, syncer, lagoonVersion) + if err != nil { + fmt.Println(errstring) + return "", err + } + + log.Printf("Rsync path: %s", rsyncPath) + return rsyncPath, nil + } } - return nil + + return "", nil } func SyncRunSourceCommand(remoteEnvironment Environment, syncer Syncer, dryRun bool) error { @@ -190,8 +219,6 @@ func SyncRunTransfer(sourceEnvironment Environment, targetEnvironment Environmen targetEnvironmentName) if executeRsyncRemotelyOnTarget { - log.Print("Check if rsync is available") - execString = generateRemoteCommand(targetEnvironment, execString) } @@ -302,7 +329,7 @@ func (c SyncCommand) GetCommand() (string, error) { } func generateRemoteCommand(remoteEnvironment Environment, command string) string { - return fmt.Sprintf("ssh -t -o \"UserKnownHostsFile=/dev/null\" -o \"StrictHostKeyChecking=no\" -p 32222 %v@ssh.lagoon.amazeeio.cloud '%v'", + return fmt.Sprintf("ssh -tt -o \"UserKnownHostsFile=/dev/null\" -o \"StrictHostKeyChecking=no\" -p 32222 %v@ssh.lagoon.amazeeio.cloud '%v'", remoteEnvironment.getOpenshiftProjectName(), command) } @@ -324,3 +351,89 @@ func getEnv(key string, defaultVal string) string { } return defaultVal } + +const RsyncAssetPath = "./binaries/rsync" + +// will add bundled rsync onto environment and return the new rsync path as string +func createRsync(environment Environment, syncer Syncer, lagoonVersion string) (string, error) { + // if local, we bail out for now. + if environment.EnvironmentName == LOCAL_ENVIRONMENT_NAME { + return "Local environment doesn't have rsync", nil + } + + environmentName := syncer.GetTransferResource(environment).Name + if syncer.GetTransferResource(environment).IsDirectory == true { + environmentName += "/" + } + + rsyncLocalResource := fmt.Sprintf("%vlagoon_sync_rsync_%v", "./binaries/", strings.ReplaceAll(lagoonVersion, ".", "_")) + environment.RsyncLocalPath = rsyncLocalResource + rsyncDestinationPath := fmt.Sprintf("%vlagoon_sync_rsync_%v", "/tmp/", strings.ReplaceAll(lagoonVersion, ".", "_")) + + // rename rsync binary with latest lagoon version + cpRsyncPath := fmt.Sprintf("cp %s %s", + RsyncAssetPath, + fmt.Sprintf("%vlagoon_sync_rsync_%v", "./binaries/", strings.ReplaceAll(lagoonVersion, ".", "_"))) + + if err, _, errstring := Shellout(cpRsyncPath); err != nil { + log.Println(errstring) + return "", err + } + + lagoonRsyncService := "cli" + rsyncRemoteSystemUsername := "" + + if environment.EnvironmentName != LOCAL_ENVIRONMENT_NAME { + environmentName = fmt.Sprintf(":%s", environmentName) + rsyncRemoteSystemUsername = environment.getOpenshiftProjectName() + if environment.ServiceName != "" { + lagoonRsyncService = environment.ServiceName + } + } + + execString := fmt.Sprintf("rsync -a %s -e \"ssh -o LogLevel=ERROR -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p 32222 -l %v ssh.lagoon.amazeeio.cloud service=%v\" :%s", + rsyncLocalResource, + rsyncRemoteSystemUsername, + lagoonRsyncService, + rsyncDestinationPath) + + log.Printf("Running the following for:- %s", execString) + + if err, _, errstring := Shellout(execString); err != nil { + log.Println(errstring) + return "", err + } + + removeLocalRsyncCopyExecString := fmt.Sprintf("rm -rf %v", rsyncLocalResource) + if err, _, errstring := Shellout(removeLocalRsyncCopyExecString); err != nil { + log.Println(errstring) + return "", err + } + + return rsyncDestinationPath, nil +} + +func PrerequisiteCleanUp(environment Environment, rsyncPath string, dryRun bool) error { + log.Printf("Beginning prerequisite resource cleanup on %s", environment.EnvironmentName) + if rsyncPath == "" { + return nil + } + execString := fmt.Sprintf("rm -r %s", rsyncPath) + + if environment.EnvironmentName != LOCAL_ENVIRONMENT_NAME { + execString = generateRemoteCommand(environment, execString) + } + + log.Printf("Running the following: %s", execString) + + if !dryRun { + err, _, errstring := Shellout(execString) + + if err != nil { + fmt.Println(errstring) + return err + } + } + + return nil +}