Connect to mysql with Ruby but without Rails - mysql

I am using my old script, which used to work just fine, but now I'm receiving following error:
Error while connecting to the database.
Can't connect to MySQL server on 'some.remote.host.com' (65)
I can't figure out what the real error is, my connect data is surely correct, because I can login to PhPMyadmin with the given username and password.
Here is my code:
# encoding: UTF-8
require 'mysql2'
require 'csv'
def initialize_data
puts "Initializing database, username, password and host..."
#database = "database_name"
#username = "database_user"
#password = "my_secret_password"
#host = "remote.host.com"
end
def connect
puts "Trying to connect to the database."
begin
#client = Mysql2::Client.new(host: #host, username: #username, password: #password, database: #database)
rescue => e
puts "Error while connecting to the database."
puts e.message
end
end
I wasn't able to find any info on this 65 error. Rescuing with e.message does not help at all.
Can someone point me at least in what direction to dig? I'm struggling with this simple script second day in a row now. Is there any way to receive more detailed error messages? Like Rails' error.full_messages.each

You can look up MySQL error codes with perror:
$ perror 65
OS error code 65: No route to host
That might mean the MySQL server is on a network you can't currently reach. If so, you haven't reached the point where the username and password matters. An easy way to test if the problem is with your code or with accessing the database is to use the command-line tool. If you can't reach the database from the command line you are running Ruby from, the problem isn't your code.
Another test would be to run MySQL locally. (Or run your script on the same machine as the MySQL database, if possible.) If the script works as expected, check to see if there's been a recent change in network or database configuration.

Related

What's the proper connection string to MySQL db for ActiveRecord on TravisCI?

Here is one of my problematic builds:
https://travis-ci.org/RailsEventStore/rails_event_store_active_record/jobs/268876871
Here is the error:
Mysql2::Error:
Access denied for user 'travis'#'%'
to database 'rails_event_store_active_record'
and here is a list of connection strings that I tried
DATABASE_URL=mysql2://travis:#127.0.0.1/rails_event_store_active_record?pool=5
DATABASE_URL=mysql2://travis#127.0.0.1/rails_event_store_active_record?pool=5
DATABASE_URL=mysql2://travis#localhost/rails_event_store_active_record?pool=5
This is how I create the DB:
before_script:
- mysql -e 'CREATE DATABASE rails_event_store_active_record;'
And the code responsible for connecting:
ENV['DATABASE_URL'] ||= "postgres://localhost/rails_event_store_active_record?pool=5"
RSpec.configure do |config|
config.failure_color = :magenta
config.around(:each) do |example|
ActiveRecord::Base.establish_connection(ENV['DATABASE_URL'])
Everything works fine when I test my gem with Postgresql but it fails for Mysql.
https://docs.travis-ci.com/user/database-setup/#MySQL - documents how to connect to MySQL DB and I am not sure what I am doing wrong right now.
I just tried one more option and it worked. Apparently I had to use root user instead of travis despite what the documentation says...
DATABASE_URL=mysql2://root:#127.0.0.1/rails_event_store_active_record?pool=5

catch mysql STDOUT error from ruby system method or backticks `` system execution (Chef)

This question kind of involves many things and i don't know from where to make a workaround. I found a solution, but i think it is a nasty one.
i have this LWRP that installs mysql and as the last step i update the password if it is provided and it is not defined before:
ruby_block "Changing password for root" do
block do
if !(root_password.nil? || system("\"#{installation_path}\\bin\\mysql.exe\" -u root -p#{root_password} --execute \"exit\""))
# In order to allow the service to completely start and then change the passowrd
#
sleep 30
change_pass_str = "\"#{installation_path}\\bin\\mysql.exe\" -u root --execute \"UPDATE mysql.user SET Password=PASSWORD('#{root_password}') WHERE User='root';FLUSH PRIVILEGES;\""
password_set_result = system(change_pass_str)
else
puts !password_set_result ? "Password wasn't changed since root already have a password defined. Maybe there's still data from a previous installation." : "Password has been set!"
`dir`
end
end
end
when this resource is executed in chef it prints or throws or STDOUT or i don't know how to call it, the next lines:
ERROR 1045 (28000): Access denied for user 'root'#'localhost' (using password: Yes)
that line is not captured if i execute the mysql call with `` (backticks), i mean, something like this:
irb(main):002:0> response = `mysql.exe -u root -pdevtest --execute \"exit\"`
ERROR 1045 (28000): Access denied for user 'root'#'localhost' (using password: YES)
=> ""
irb(main):003:0> puts response
=> ""
only returns "", instead of returning the error string itself.
the thing is that when i later (in the recipe cookbook that implements mysql installation and does other stuff with subversion) execute subversion resource with action :export (i think it would fail with any other action), it fails telling that it returns exit status 1, but it doesn't is the exit status that mysql throw.
if i add a dir system call (as you can see in the ruby block), subversion resource passes without any problem as the dir system call (i think) resets the exit status to 0.
The dir system call, i guess is a really nasty way to work around this, that's why i'm asking for your help, how do avoid mysql to throw (or STDOUT) that thing, or how do i catch it or reset the exit status?
A lot of things here.
First I would bet the ERROR from mysql is sent to stderr and not stdout, it is why its not captured, you may redirect it to stdout with the classic 2&>1 redirection to capture the error.
The exit status is the last command status, mysql had an error and so set its exit status to something different from 0.
All in all, you should avoid system call in chef recipe and use Mixin::ShellOut instead wich give you more control over what you run.

mysql-proxy not running lua script

I know there are many mysql-proxy questions on SO, however I have read through many of them and none seem to solve my problem. I am simply trying to get mysql-proxy up and running, with the eventual purpose of rewriting some queries that go through the proxy. I am using ubuntu 14.04, I have mysql-proxy version 0.8.1, and mysql version 5.5.37. To start mysql-proxy I run the following line on the command line
sudo mysql-proxy --defaults-file=mysql-proxy.cnf
where the file mysql-proxy.cnf looks like the following:
[mysql-proxy]
log-file= /var/log/mysql/proxy-error.log
log-level= debug
admin-lua-script= /usr/lib/mysql-proxy/lua/admin.lua
proxy-lua-script= /path/to/lua/script/example.lua
admin-username = myusername
admin-password = mypassword
proxy-skip-profiling = true
proxy-address = localhost:4040
proxy-backend-addresses = localhost:3306
plugins = proxy,admin
My example.lua script is very simple, and meant only to verify that the mysql-proxy query is being altered. example.lua is pasted below
-- first_example.lua
function read_query(packet)
if string.byte(packet) == proxy.COM_QUERY then
print("Hello world! Seen the query: " .. string.sub(packet, 2))
end
end
Since I don't run this with the --daemon flag, when I run that line above in the command line it just loops indefinitely, which is expected.
Finally, in separate terminal session, I run the following on the command line and enter my password in order to connect with the proxy
mysql -u myusername -p -h localhost -P 4040
I then select a database to use, and run a simple SELECT query on one of the tables. Based on multiple articles/tutorials I've read on mysql-proxy, my first console session, the one that ran mysql-proxy, should print out some data based on the example.lua file. However this does not happen, in fact nothing happens.
I'm not sure if the following bit of information makes any difference, but in my "my.cnf" mysql configuration file, I have these couple of lines
bind-address = 255.255.255.255
#bind-address = 127.0.0.1
where I have replaced my actual ip address with 255.255.255.255 because I do not want to display my ip address publicly.
Please, I have been trying to figure this out for several days, and no amount of new lua scripts, or changing the host:port parameters in the mysql-proxy.cnf file have solved anything. I

Ruby: How do I return a MySQL query up an SSH tunnel?

//update: when feeding mysql passwords, -ppassword works. -p password does -not- work. Problem solved.//
We have hundreds of databases on our work servers, and I'd like to write a ruby script that automates the process of creating duplicate versions of them on my local machine for development purposes.
I've been trying to use net-ssh to create the tunnel, but (host, user, pass, etc. are censored for obvious reasons):
require 'net/ssh'
HOST = 'xxx'
USER = 'yyy'
PASS = 'ppp'
Net::SSH.start( HOST, USER, :password => PASS ) do|ssh|
puts "inside ssh tunnel"
puts ssh.exec!('ruby -v')
puts ssh.exec!('mysql -u zzz -p pswrd -h c3 will_il_raw -e "select * from deeds limit 1"')
end
results in the output:
inside ssh tunnel
ruby 1.8.7 (2010-08-16 patchlevel 302) [x86_64-linux]
followed by an indefinite hang. Interestingly, if I ssh into the same computer via the console, 'ruby -v' returns 1.9.3. If I enter that mysql query there, it successfully returns one line of the named table.
I assume the solution has something to do with port forwarding, but here my limited knowledge begins to fail me utterly.
The machine running the mysql server is not the same machine as I am accessing it from, which is not, in turn, the machine I am actually sitting at. I need to connect the dots and apparently have no idea how to go about this properly.
Any protips would be much appreciated.
In MySQL syntax, when feeding a password using -p[password], there is no space between -p and the password.
Because the script's version of the syntax had a space, the result of the query was a prompt requesting the password, which caused the hang on the far end of the SSH tunnel.

Ruby SSH MySQL Sequel (or DataMapper) remote connection with keys using Net::SSH gem

How would I connect to my VPS based MySQL database remotely (from a cloud based app) using the Ruby Net::SSH or Net::SSH::Gateway gems and key, not password, authentication?
And then connect to the database with Sequel or DataMapper. I'm assuming that after I manage to get the SSH connection working, I would just setup a Sequel/DM connection to 'sql_user#localhost:3306/database'.
I did locate a couple of similar question here, but they all use password authentication, not keys, and only demonstrate executing raw commands to query the database.
UPDATE: I just cannot seem to get this (Net::SSH with key manager) to work.
UPDATE2: Alright I have managed to get authorization when logging in from a computer that has authorized keys stored in the users local .ssh folder, with the following (port is my custom SQL port on the VPS):
sql_gate = Net::SSH::Gateway.new('192.xxx.xxx.xx','sqluser', port: 26000)
However, I will not be able to create a .ssh folder in the app's VM, so I need to somehow pass the path and filename (I will be creating a public key just for SQL access for specified user) as an option ... but haven't been able to figure out how.
UPDATE: Just need to figure out DataMapper access now. Current code being tested (remote_user_sql is my Ubuntu user, sql_user is the MySQL database user with localhost/127.0.0.1 privileges):
require 'net/ssh/gateway'
require 'data_mapper'
require 'dm-mysql-adapter'
class User
include DataMapp......
.
.
end
ssh_gate = Net::SSH::Gateway.new('192.n.n.n','remote_user_sql', {port: 25000, keys: ["sql_rsa"], keys_only: true})
port = ssh_gate.open('localhost',3306,3307)
child = fork do
DataMapper.setup(:default, {
adapter: 'mysql',
database: 'sql_test',
username: 'sql_user',
password: 'passwd',
host: 'localhost',
port: port})
DataMapper.auto_upgrade!
exit
end
puts "child: #{child}"
Process.wait
ssh_gate.close(port)
My solution, in two parts:
Well I have figured how to make the Net::SSH::Gateway gem using a specified keyfile, and then connect to the VPS through ssh via a port other than 22:
Part 1: Net::SSH::Gateway key authentication
First you must generate the keyfiles you want to use, copy the .pub to the remove server and append it to the ~/.ssh/authorized_keys file (cat sql_rsa.pub >> authorized_keys), and then make sure user_sql (the user I created on the VPS to be used only for this purpose) has been added to AllowUsers list in sshd_config. Make note of port used for ssh (25000 for this example) and use the following code to establish the connection:
ssh_gate = Net::SSH::Gateway.new('192.n.n.n','user_sql', {port: 25000, keys: ["sql_rsa"], keys_only: true})
That will read the keyfile sql_rsa in the same directory as script file, then create a new ssh gateway for 'user_sql'#'192.n.n.n' on port 25000.
I can successfully execute raw shell commands on the remove VPS with:
ssh_gate.exec("ls -la")
To close:
ssh_gate.shutdown!
Unfortunately I am still having problems using DataMapper (do-mysql-adapter) to use the gateway. I will update this answer if I figure that part out, but at least the first half of the problem has been solved.
These are the errors that DataMapper::Logger has reported:
When 127.0.0.1 was used:
Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) (code: 2002, sql state: HY000, query: , uri: )
When localhost was used:
Access denied for user 'user_sql'#'localhost' (using password: YES) (code: 1045, sql state: 28000, query: , uri: )
When the VPS hostname was used:
Unknown MySQL server host 'hostname' (25) (code: 2005, sql state: HY000, query: , uri: )
UPDATE (No success yet): So far the only way I can access the remote MySQL database is by using Net::SSH::Gateway to establish a gateway, and then use the .sshmethod to open a new Net::SSH connection over that gateway, like so:
ssh_gate.ssh('192.n.n.n','user_sql',{port: 25000, keys: ["sql_rsa"], keys_only: true}) do |ssh|
ssh.exec("mysql -u sql_user -p'passwd' -h localhost -P 3306 -e 'SELECT DATABASE();'")
end
In other words, I can only execute SQL commands using the mysql command line. I cannot figure out how to get Sequel or DataMapper to use the gateway to connect.
Part 2: DataMapper/Sequel/mysql2 connection through Net::SSH::Gateway
Make sure your MySQL server is bound to 127.0.0.1 in /etc/mysql/my.cnf, setup your connection - DataMapper example:
DataMapper.setup(:default, {
adapter: 'mysql',
database: 'DATABASE',
username: 'username',
password: 'passwd',
host: '127.0.0.1',
port: 3307}) # local port being forwarded via Net::SSH:Gateway
Followed by any class table definitions and DataMapper.finalize if required. Note that DataMapper doesn't actually connect to the remote MySQL server until either an auto_upgrade!, auto_migrate!, or query is executed, so no need to create the forwarded port yet.
Then create a new Net::SSH::Gateway, and then whenever you need DataMapper/Sequel to access the remote database, just open a port for the process, like so:
port = ssh_gate.open('127.0.0.1',3306,3307)
child = fork do
DataMapper.auto_upgrade! # DM call that accesses MySQL server
exit
end
Process.wait
ssh_gate.close(port)
You may want to put the Net::SSH::Gateway/.open code in a begin..ensure..end block, ensure'ing the port closure and gateway shutdown.
I had to use a fork and Process.wait to establish the connection, without it the method just hangs.