skip to Main Content

So I’m trying use the SYNC Redis command over an ssh session from a PowerShell script to sync data between a master-replica Redis databases (which are hosted on remote Linux hosts). Due to the infrastructure my project has, I cannot have these two databases as a master-replica relationship, so these databases are both masters. So part of this process involves setting a temporary master-replica relation ship between the two DBs to able to do the SYNC.

So the flow of the script is:

  1. Opens a SSH connection to the replica server.
  2. Get into Redis-cli tool and Run SLAVEOF $masterServer $masterPort to create the master-replica relationship.
  3. Run SYNC to sync data between the master-replica.
  4. Undo the relationship master – replica and set it to be none replication by running SLAVEOF NO ONE on the replica server.

There’s two issues:

  1. When the SYNC is executed it fails with the following error:
    SYNC with master failed: -NOMASTERLINK Can't SYNC while not connected with my master which doesn’t makes sense if we check the entire script log output:
    18:35:39 Output     : {OK}
    18:35:39 ExitStatus : 0
    18:35:39 Error      : 
    18:35:39 Host       : x.x.x.x
    18:35:39 Duration   : 00:00:00.2536566
    18:35:39 
    18:35:39 
    18:35:39 Output     : {Entering replica output mode...  (press Ctrl-C to quit)}
    18:35:39 ExitStatus : 1
    18:35:39 Error      : SYNC with master failed: -NOMASTERLINK Can't SYNC while not connected with my master
    18:35:39              
    18:35:39 Host       : x.x.x.x
    18:35:39 Duration   : 00:00:00.1155349

The first {OK} status output is from setting the master-replica relationship. I can confirm that is working because if I execute the script again without undoing the the master-replica relationship, instead {OK} status it says {OK Already connected to specified master}.
Initially I suspected that it was an async issue, thinking that the SYNC was executed to fast before the echo SLAVEOF $masterServer $masterPort | redis-cli finishes, but it does not explains what status messages I just mentioned nor the following issues #2. (Though I don’t know how to handle async processes on linux/bash)

  1. If I set manually the master-replica relationship to just test the SYNC command, it times out with this error:
    ForEach-Object : Exception calling "EndExecute" with "1" argument(s): "Command 'echo SYNC | redis-cli' has timed out." This might be related to the fact that when the SYNC command finishes, it puts the bash in a listening state just listening to sequential pings suggesting that connection works, but for escaping this state I must send a Ctrl + C combination which I don’t know how to do. I’ve tried to send send -- x03 as an extra command but it does not work. Any idea of how to do this?

Powershell Script:

    param(
    [Parameter(Mandatory=$true, Position=0)]
    [string] $MasterServer,

    [Parameter(Mandatory=$true, Position=1)]
    [string] $MasterPort,

    [Parameter(Mandatory=$true, Position=2)]
    [string] $ReplicaServer,

    [Parameter(Mandatory=$true, Position=3)]
    [string] $UserReplicaServer,

    [Parameter(Mandatory=$true, Position=4)]
    [string] $PwdReplicaServer
)

$SecurePasswd = ConvertTo-SecureString $PwdReplicaServer -AsPlainText -Force
$Credentials = New-Object System.Management.Automation.PSCredential($UserReplicaServer, $SecurePasswd)

Write-Host "Connecting to Redis host over SSH..."
# Connect Over SSH and getting session id.
$SessionID = New-SSHSession -ComputerName $ReplicaServer -Credential $Credentials -Force

if($SessionID -eq $null){
    Write-Host "Error: An error occurred trying to setup the SSH session. Please check the connection string/credentials for the SSH session."
    exit 1
} else {
    Write-Host "SSH session created successfully. Running Redis SYNC."
}

# Commands.
$commands = @(
    @{
        Command = "echo SLAVEOF $MasterServer $MasterPort | redis-cli"
        Description = "Configure replication"
    },
    @{
        Command = "echo SYNC | redis-cli"
        Description = "Sync replication"
    },
    @{
        Command = "echo SLAVEOF NO ONE | redis-cli"
        Description = "Undo replication"
    }
)

# Execute commands on Redis Host
foreach ($command in $commands) {
    $result = Invoke-SSHCommand -Index $SessionID.sessionid -Command $command.Command
    if ($result.ExitStatus -ne 0) {
        Write-Host "Error: Failed to execute command '$($command.Command)'. Description: $($command.Description) Error message: $($result.StandardError)"
        exit 1
    }
    Write-Host "Success: Command '$($command.Command)' executed successfully. Description: $($command.Description)"
}

Write-Host "Script Worked and Finished!"

2

Answers


  1. Chosen as BEST ANSWER

    Some modifications to the commands and adding trap '' INT to execute a Ctrl+C worked.

    $commands = @(
        @{
            Command = "redis-cli SLAVEOF $MasterServer $MasterPort"
            Description = "Configure replication"
        },
        @{
    
            Command = "redis-cli SYNC & sleep 10 & trap '' INT"
            Description = "Sync replication"
        },
        @{
            Command = "redis-cli SLAVEOF NO ONE"
            Description = "Undo replication"
        }
    )
    

  2. Here is a rewrite, I can’t be of much help with as to the reason why without actually doing a hands on. But hopefully this helps you a bit.

    Here is a re-write that focuses on

    • Uses param block with named/indexed parameters
    • Uses Pascal casing for parameter names as a best practice
    • Displays the result of each command
    • Provides error handling for each command
    • Iterates through an array of commands and de-duplicates Invoke-SSHCommand
    param(
        [Parameter(Mandatory=$true, Position=0)]
        [string] $MasterServer,
    
        [Parameter(Mandatory=$true, Position=1)]
        [string] $MasterPort,
    
        [Parameter(Mandatory=$true, Position=2)]
        [string] $ReplicaServer,
    
        [Parameter(Mandatory=$true, Position=3)]
        [string] $UserReplicaServer,
    
        [Parameter(Mandatory=$true, Position=4)]
        [string] $PwdReplicaServer
    )
    
    $SecurePasswd = ConvertTo-SecureString $PwdReplicaServer -AsPlainText -Force
    $Credentials = New-Object System.Management.Automation.PSCredential($UserReplicaServer, $SecurePasswd)
    
    Write-Host "Connecting to Redis host over SSH..."
    # Connect Over SSH and getting session id.
    $SessionID = New-SSHSession -ComputerName $ReplicaServer -Credential $Credentials -Force
    
    if($SessionID -eq $null){
        Write-Host "Error: An error occurred trying to setup the SSH session. Please check the connection string/credentials for the SSH session."
        exit 1
    } else {
        Write-Host "SSH session created successfully. Running Redis SYNC."
    }
    
    # Commands - updated to reflect OP's confirmed working version
    $commands = @(
        @{
            Command = "redis-cli SLAVEOF $MasterServer $MasterPort"
            Description = "Configure replication"
        },
        @{
    
            Command = "redis-cli SYNC & sleep 10 & trap '' INT"
            Description = "Sync replication"
        },
        @{
            Command = "redis-cli SLAVEOF NO ONE"
            Description = "Undo replication"
        }
    )
    # Execute commands on Redis Host
    foreach ($command in $commands) {
        $result = Invoke-SSHCommand -Index $SessionID.sessionid -Command $command.Command
        if ($result.ExitStatus -ne 0) {
            Write-Host "Error: Failed to execute command '$($command.Command)'. Description: $($command.Description) Error message: $($result.StandardError)"
            exit 1
        }
        Write-Host "Success: Command '$($command.Command)' executed successfully. Description: $($command.Description)"
    }
    
    Write-Host "Script Finished! Check For errors"
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search