execute mysql on remote server via bash script - mysql

I need to execute a mysql command on a remote server but seem to be hitting problem when it comes to executing the actual mysql bit
#!/usr/bin/expect -f
spawn /usr/bin/ssh -t root#10.0.0.2
expect "password: "
sleep 1
send "password\r"
sleep 2
/usr/bin/mysql databasename -e "update device_log set status = 'Y' where device_id in ('1','2');"
basically I want to change the flag to Y on device id's 1&2
but the script outputs
invalid command name "/usr/bin/mysql"

Just append the mysql command to the ssh command to run it in one go, like this:
#!/usr/bin/expect -f
spawn /usr/bin/ssh -t root#10.0.0.2 /usr/bin/mysql databasename -e "the query"
expect "password: "
sleep 1
send "password\r"
I'm not very much into expect, but I'm expecting that your attempt in the mysql line isn't actually valid syntax for expect to run a command.
Additionally:
You should use SSH keys for passwordless login instead of having a root password hardcoded in a script.
Consider running MySQL remotely e.g. mysql -h 10.0.0.2 -e "the query", or
Use port forwarding in SSH to connect to MySQL securely, e.g. run ssh -L 3307:localhost:3306 root#10.0.0.2 in the background and then connect to TCP port 3307 on localhost mysql -h 127.0.0.1 -P 3307.

It sounds like /usr/bin/mysql is not the the path to the mysql binary on that remote server. You could use just mysql instead, assuming that the binary is somewhere in that remote server's PATH. Otherwise you will have to go and find out where the binary is actually located and alter the absolute path accordingly.

Related

Nested SQL Statement within MYSQL within SSH from bash script

I have the unfortunate situation, that I don't have the permission to access the MYSQL database from outside the server. But SSH is possible. Therefore I try to run a simple SQL statement from a bash file, that creates a SSH connection, connects to the MYSQL DB and run the SQL statement.
The syntax is pretty straight forward but I'm not able to use them combined in one bash file, but on the command line each individual is working
that the snippets I'm using:
1) establish the SSH connection:
$:sshpass -p my_password ssh my_user#my_server
2) connect to the MYSQL DB:
my_server>mysql -h rdbms -u db_user -D db_name -p db_password
3) run the SQL statement
mysql>SELECT * FROM table
... as said. all good when running on command line.
But when I combine them into a bash file:
#!/usr/bin/
sshpass -p my_password ssh my_user#my_server
mysql -h rdbms -u db_user -D db_name -p db_password
SELECT * FROM table
It stops right after the first line (establishing the SSH connection). Any ideas how I can combine these?
To run a command on a remote server via ssh, you need to list the command as arguments on the same command-line.
For example:
sshpass -p my_password ssh my_user#my_server date
That will run date on the remote server, and return the output of that command.
You can run the mysql client this way too. Just put the mysql command on the same command-line, as arguments to your ssh.
sshpass -p my_password ssh my_user#my_server mysql ...arguments...
You can use \ at the end of a line to continue a long command on the following line. It works as if you had written the full command on one very long line, but it's easier to post in Stack Overflow so readers don't have to scroll horizontally to read it. :-)
Also note that the remote command must be in quotes so it appears like a single argument to ssh. When it runs on the remote server, it will be expanded to multiple arguments.
sshpass -p my_password ssh my_user#my_server \
"mysql ...arguments..."
The mysql client has an option -e that you can use to execute an SQL statement.
sshpass -p my_password ssh my_user#my_server \
"mysql -h rdbms -u db_user -D db_name -pdb_password -e 'SELECT * FROM table'"
A couple of tips about the password:
There must be no space between -p and the password. If you use -p with a space after it, you will be prompted for the password interactively. The word following the space is not taken as the password unless you stick it against the -p.
I don't like to put passwords in plaintext on the command-line. It's not safe to do that, because anyone who can access your shell history can view the password. It's better to use an option file or a login file. But you'll have to put these on the remote server where the mysql client runs.

xmalloc: cannot allocate 16 bytes copying mysql database from 1 remote to another

I have 2 remote servers behind bastion servers, and I am trying to clone 1 MySQL database to another. I have a script on one bastion server sending data to another script on the other bastion server, and it appears to be running out of memory. The database is about 2.7G and these servers have 2G RAM. It appears that it is loading the entire database into memory, but I'm not sure why. Is there something in these scripts that is loading the entire db into memory? Here are the scripts:
migrateToRemote.sh (on bastion 1)
#!/bin/bash
ssh -i ~/.ssh/key.pem ubuntu#<ipaddress> "mysqldump -h <db host> -u <db user> -p<db password> <orig db name>" | ssh -i ~/.ssh/key.pem ubuntu#<ipaddress> "/home/ubuntu/forwardDbMigration.sh"
forwardDbMigration.sh (on bastion 2)
#!/bin/bash
ssh -i ~/.ssh/key.pem ubuntu#<ip address> "mysql -h <db host> -u <db user> -p<db password> <new db name>" < $(< /dev/stdin)
mysql ... < $(< /dev/stdin)
I don't think this does what you think it does. The $( ) substitution in bash is not just I/O redirection. It runs a command.
Your usage reads /dev/stdin, and then tries to execute that content as a command. That's probably where it ran out of memory, trying to form a command that is 2.7GB long.
Here's a demo of what I mean:
echo date | $(</dev/stdin)
Tue Nov 19 07:34:14 PST 2019
This is reading the string "date" from /dev/stdin and then executing the command date. The output is not the string "date" — it's the result of executing date, because it's enclosed in $( ).
Another demo:
echo "hello world" | $(</dev/stdin)
-bash: hello: command not found
See? It's trying to execute "hello world" as a command after reading it from stdin.
You don't want to execute the content of your mysqldump, it is not a series of shell commands. You just want to pass that content as the input to mysql.
If you want forwardDbMigration.sh to pass its stdin to mysql, I think you only need to do this:
ssh -i ~/.ssh/key.pem ubuntu#<ip address> "mysql -h <db host> -u <db user> -p<db password> <new db name>"
I'm also not sure why your forwardDbMigration.sh contains an ssh command at all, because you are already ssh'ing to the bastion host to run it.

Bash script for interactive ssh and mysql commands

I'm studying MySQL, and every time I have to
Enter ssh XXX#XXX command, and enter my password to the school server.
Enter mysql -u XXX -p command, and enter MySQL password.
I want to create a Bash script for performing the steps above automatically.
I can accomplish the first step with this code:
#!/usr/bin/expect -f
set address xxx.com
set password xxx
set timeout 10
spawn ssh xxx#$address
expect { "*yes/no" { send "yes\r"; exp_continue} "*password:" { send "$password\r" } }
send clear\r
interact
But I don't know how to automatically input the next command (mysql -u xxx -p) and the password.
How can I do this?
You don't need such a complex script to just enter the MySQL console on remote machine. Use the features of the ssh tool:
ssh -tt user#host -- mysql -uuser -ppassword
The -t option forces pseudo-terminal allocation. Multiple -t force tty allocation, even if ssh has no local tty (see man ssh). Note the use of -p option. There must be no spaces between -p and password (see the manual for mysql).
Or even connect via mysql directly, if the MySQL host is accessible from your local machine:
mysql -hhost -uuser -p
Don't forget to adjust the shebang:
#!/bin/bash -
Use my.cnf to store your password securly like ssh keys.
https://easyengine.io/tutorials/mysql/mycnf-preference/
Same way ssh is also possible through ssh -i parameter and passing the private key path of the remote host.
Best of luck!

Expect scripting: remote database backup automation

I'm looking for a kind of remote database backup automation.
Then, I came across a scripting language which commonly used for administrative tasks, "Expect scripting" and I believe it could serve my purpose very well.
what I'd like to do is I want to perform login to a remote server using the following bash script from my local linux box. (supposed everything has been set properly, SSH authentication via generated key pair, so no password is required)
For the most important part, I'd like to send a mysqldump command to perform backup for my database on that server.
#!/usr/bin/expect
set login "root"
set addr "192.168.1.1"
spawn ssh $login#$addr
expect "#"
send "cd /tmp\r"
expect "#"
send "mysqldump -u root -ppassword my_database > my_database.sql\r"
expect "#"
send "exit\r"
The only problem I found here was after the line send "mysqldump -u root....... ".
It was never waiting until the process to finish, but immediately exit the shell with 'send "exit\r"' command line.
what do I do to make it waits until mysqldump command finish and log off the SSH properly?
I don't know the answer to your question: add exp_internal 1 to the top of the program to see what's going on.
However, since you have ssh keys set up, you don't really need expect at all:
ssh $login#$addr 'cd /tmp && mysqldump -u root -ppassword my_database > my_database.sql'

Making an alias for SSH MySQL login using ENDSSH heredoc

I want to make an alias that is kept in my bashrc file to log into a remote MySQL db via SSH.
Assume that I can't add/alter any files on the remote machine that I'm SSHing into. Here's the relevant code.
function ssh_mysql {
echo "SSHing to $server"
ssh -t -t $suser#$server <<ENDSSH
eval "mysql -h "$host" -u $user -p $pass $db"
ENDSSH
}
alias wt_mysql=ssh_mysql
The Problem: Entering 'wt_mysql' into the terminal as an alias SSHs and logs into MySQL fine.. but when trying to enter any command/query/etc at the MySQL prompt, none of what I've submitted is executed/run. Including the 'exit' command. I have to ctrl C to get back to my local terminal. although its a bit out of my understanding I believe the problem is related to this topic, Terminating SSH session executed by bash script
How can I make sure that mysql and any subsequent commands are executed remotely?
Thanks!
I don't understand why you're using eval (or why you're passing the -t switch twice).
I would expect this ssh command to do what you want:
ssh -t $suser#$server "mysql -h '$host' -u $user -p $pass $db"