How to make a program that can open mysql - mysql

I'm developing an InSpec control that runs CIS compliance commands.
While working on MySQL, I'm stuck here:
Execute the following SQL statement to determine the value of datadir:
show variables where variable_name = 'datadir';
I need to extract the output from the above command and reuse it in the next command:
ls -l <THE OUTPUT OF THE PREVIOUS COMMAND>/.. | egrep "^d[r|w|x]{3}------\s*.\s*mysql\s*mysql\s*\d*.*mysql"
The problem is that the first command is an SQL Request and the second command is a terminal command.
How can I put both of them (after getting the output of the first command and put it in the second one) in an InSpec control like the following:
control "mysql1" do
impact 1.0
title "Use dedicated Least Privileged Account for MySQL Daemon/Service"
desc "May reduce the impact of a MySQL-born vulnerability"
describe command ('ps -ef |e grep "^mysql.*$"') do
its('stdout') { should match ''}
end
end
Thank you for your help #Matt
I've read your answer and found it really helpful, except the last block of code : Does
egrep "^d[r|w|x]{3}------\s*.\s*mysql\s*mysql\s*\d*.*mysql"
mean
it { expect(subject).to_not be_owned_by 'mysql' }
it { expect(subject).to_not be_grouped_into 'mysql' }
it { expect(subject).to_not be_executable_by 'mysql' }
?
Plus I did try all of the blocks you wrote previously and none of them did work.. And yes, I'm using linux 16.04

You can extract the output of the SQL request with the following method:
command('mysql -u <user> -p -e "show variables where variable_name = \'datadir\'"').stdout.split(' ')
The mysql -u <user> -p -e part is necessary to execute the SQL query from a Linux command. If you are using Window, you will probably need to make use of sqlcmd instead. This allows the SQL query to execute successfully with the command method.
The reason the command method works here is because it is a custom RSpec type (implicitly therefore also a class constructor in the sense that Ruby has constructors) that will execute locally or remotely on the tested system. The .stdout method is a member of the class to capture the stdout of the command. .split will ensure the output variables are stored in a whitespace-delimited array.
Now we can use it in the next command like so:
# store array of variables
variables = command('mysql -u <user> -p -e "show variables where variable_name = \'datadir\'"').stdout.split(' ')
# use array in command
variables.each do |variable|
describe command("ls -l #{variable}/.. | egrep \"^d[r|w|x]{3}------\s*.\s*mysql\s*mysql\s*\d*.*mysql\"") do
its('stdout') { should match ''}
end
end
Above we iterate through the array of variables captured in the SQL query and test it in the describe command() RSpec test. A better way to execute this test would be to test the stdout of the command in the matcher and not the egrep. Doing that and cleaning up the match method:
# store array of variables
variables = command('mysql -u <user> -p -e "show variables where variable_name = \'datadir\'"').stdout.split(' ')
# use array in command
variables.each do |variable|
describe command("ls -l #{variable}/..") do
its('stdout') { should_not match(/^d[r|w|x]{3}------\s*.\s*mysql\s*mysql\s*\d*.*mysql/)}
end
end
Updating to non-deprecated RSpec matchers and fixing the invoking of the stdout method as a string instead of a symbol we arrive at:
# store array of variables
variables = command('mysql -u <user> -p -e "show variables where variable_name = \'datadir\'"').stdout.split(' ')
# use array in command
variables.each do |variable|
describe command("ls -l #{variable}/..") do
its(:stdout) { is_expected.to_not match(/^d[r|w|x]{3}------\s*.\s*mysql\s*mysql\s*\d*.*mysql/)}
end
end
Another improvement we can make is to use a better suited file type and the permissions matchers instead of raw commands. This helps for platform-independent testing:
# store array of variables
variables = command('mysql -u <user> -p -e "show variables where variable_name = \'datadir\'"').stdout.split(' ')
# use array in file type
variables.each do |variable|
describe file("#{variable}/..") do
# check permissions
it { expect(subject).to_not be_owned_by 'mysql' }
it { expect(subject).to_not be_grouped_into 'mysql' }
it { expect(subject).to_not be_executable_by 'mysql' }
end
end
I understand there was a good bit here to implement the functionality you are looking for and many fixes and improvements as well, so be sure to examine the code and explanations closely to understand everything I did here.

Related

Why is this bash variable blank when taking output from mysql?

I am trying to take the output from a MySQL query in bash and use it in a bash variable, but it keeps coming up blank when used in the script, but works perfectly from the terminal. What's wrong here?
I've tried changing the way the statement is written and changing the name of the variable just in case it was somehow reserved. I've also done a significant amount of searching but it turns out if you but 'bash', 'blank', and 'variable' in the search it usually comes up with some version of how to test for blank variables which I already know how to do.
tempo=$(mysql -u "$dbuser" -p"$dbpass" -D "$database" -t -s -r -N -B -e "select user from example where user='$temp' > 0;")
printf "the output should be: $tempo" # This is a test statement
The end result should be that the $tempo variable should either contain a user name from the database or be blank if there isn't one.
I think there is some error with your sql statement at user = '$temp' > 0.
But to get the result from MySql you have to redirect the standard error (stderr) to the standard output (stdout), you should use 2>&1.
Most probably you will run into MySql error but try running this on terminal.
tempo=$((mysql -u "$dbuser" -p"$dbpass" -D "$database" -t -s -r -N -B -e "select user from example where user='$temp' > 0;") 2>&1)
The solution was to echo the result of the sql query like this:
tempo=$(echo $(mysql -u "$dbuser" -p"$dbpass" -D "$database" -s -N -B -e "select user from example where user='$username' > 0;"))
Now I'm left with logic issues but I think I can handle that.

connect to mysql db and execute query and export result to variable - bash script

I want to connect to mysql databse and execute some queries and export its result to a varibale, and do all of these need to be done entirely by bash script
I have a snippet code but does not work.
#!/bin/bash
BASEDIR=$(dirname $0)
cd $BASEDIR
mysqlUser=n_userdb
mysqlPass=d2FVR0NA3
mysqlDb=n_datadb
result=$(mysql -u $mysqlUser -p$mysqlPass -D $mysqlDb -e "select * from confs limit 1")
echo "${result}" >> a.txt
whats the problem ?
The issue was resolved in the chat by using the correct password.
If you further want to get only the data, use mysql with -NB (or --skip-column-names and --batch).
Also, the script needs to quote the variable expansions, or there will be issues with usernames/passwords containing characters that are special to the shell. Additionally, uppercase variable names are usually reserved for system variables.
#!/bin/sh
basedir=$(dirname "$0")
mysqlUser='n_userdb'
mysqlPass='d2FVR0NA3'
mysqlDb='n_datadb'
cd "$basedir" &&
mysql -NB -u "$mysqlUser" -p"$mysqlPass" -D "$mysqlDb" \
-e 'select * from confs limit 1' >a.txt 2>a-err.txt
Ideally though, you'd use a my.cnf file to configure the username and password.
See e.g.
MySQL Utilities - ~/.my.cnf option file
mysql .my.cnf not reading credentials properly?
Do this:
result=$(mysql -u $mysqlUser -p$mysqlPass -D $mysqlDb -e "select * from confs limit 1" | grep '^\|' | tail -1)
The $() statement of Bash has trouble handling variables which contain multiple lines so the above hack greps only the interesting part: the data

script for MySQL with user and password entered as a parameter

As another post (Script for MySQL backup to multiple files), I received help to create a Powershell script that creates backup of MySQL databases and generates multiple files, one for each database. As can be seen, the script makes a pipeline between a command mysql and mysqldump.
My intention now is to eliminate the user information and password directly in the script. As another link (How to perform a mysqldump without a password prompt?), I created the my.cnf configuration file MYSQL_HOME, passing the information on [mysqldump], and used the flag --defaults-extra-file. The problem is that this flag does not work for mysql.exe, so could not use this solution.
To avoid leaving the user and password information directly in the script, I used another post (How to handle command-line arguments in PowerShell), which shows how to configure parameters input into Powershell scripts. With that, my script looked like this:
param (
[string]$username = $(throw "-username is required."),
[string]$password = $(Read-Host "Input password, please" )
)
$BACKUPDATE = Get-Date -UFormat "%Y-%m-%d_%H%M%S"
$BKPFOLDER='E:\bkp'
$MYSQL_HOME="C:\MYSQL"
Set-Location "$MYSQL_HOME\bin"
& .\mysql.exe -N -s -r -u $username -p$password -e 'show databases' | % {
& .\mysqldump.exe -u $username -p$password --single-transaction $_ |
Out-File "$BKPFOLDER\${_}_$BACKUPDATE.sql" -Encoding Ascii
}
When I run the following command:
test.ps1 -username bkpuser -password mypass
I get the following message:
ERROR 1045 (28000): Access denied for user 'bkpuser'#'localhost' (using password: YES)
But there is no access permission problem, because if I replace the values โ€‹โ€‹of $usename and $password to call the mysql and mysqldump by correct values โ€‹โ€‹(excluding the parameter), the command works.
What should I change?
PowerShell's parser can't determine where commandline argument ends and vairable name starts. You can see this clearly in ISE, because $password should be red, but it's blue:
Just add space between -p and $password or use "=": --user=$username --password=$password

scala system call to mysql fails

I have a shell script
mysql --local-infile=1 -h myhost -P myport -u me < ./loader_file.sql
When I run this directly in command line, it works great. data gets loaded into the database.
but inside a scala code
val myScript = "mysql --local-infile=1 -h myhost -P myport -u me" #< "loader_file.sql"
myScript !
I get a error message saying the mysql commands in my shell, such as "use" and "load" are not found. Obviously, shell is interpreting the loader_file.sql as bash command rather then mysql commands.
But if I incorporate the whole string as one command
val myScript = "mysql --local-infile=1 -h myhost -P myport -u me < loader_file.sql"
Then I get a mysql dump with all its valid options. Apparently, mysql thinks I am feeding it illegal input parameters.
Anyone knows how to fix this?
Here's what you need to do it from scala code:
import scala.sys.process._
val cmd = Seq("bash","-c","mysql --local-infile=1 -h myhost -P myport -u me < loader_file.sql")
for( line <- cmd.lineStream_! ){
printf("%s\n",line)
}
That should work under linux, OSX, cygwin, or similar (sounds like you have one of those environments, since bash is present).
There are lots of variations on this particular theme, allowing you to set the default working directory, specify environment variables, separately process STDOUT and STDERR streams, and capture the return value, etc.
Here's a version that does everything except specify environment variables:
import scala.sys.process._
val cmd = Seq("bash","-c","command with args, blah, blah, blah")
val proc = Process( cmd, new java.io.File(".") )
val exitValue = proc ! ProcessLogger (
(out) => System.out.printf("stdout:%s\n",out)
,
(err) => System.err.printf("stderr:%s\n",err)
)
printf("exit value: %d\n",exitValue)
The documentation for scala.sys.process is pretty good, although it assumes a linux-type environment. A shell command line will sometimes work without being wrapped with Seq("bash","-c", ...), but it isn't as portable (Windows java doesn't pass your command line to bash, for example).

replacing sqlplus commands with mysql commands

i am trying to rewrite a script that is written in c-shell script to that uses sql plus command to get information from an oracle database but i am replacing it with mysql and i would like to replace all sqlplus syntax with mysql syntax. I am asking all the c-shell gurus to explain to me what this command means
set SQLPLUS=${ORACLE_HOME}/bin/sqlplus
set REPORT=${MYBD_HOME}/Scripts/report.sql
so somewhere along the line i invoke the sql plus command using the follwing
${SQLPLUS} ${MYDBUSER} # &{REPORT}
i am able to say i undertand what the right hand values mean ({ORACLE_HOME}/bin/sqlplus) is the path to where my sqplus command is located and thus i need it to invoke the command and the {REPORT=$(MYBD_HOME}/Scripts.report.sql) is the path where my sql script that is to be ran by invoking the sqplus command resides correct?
what i dont understand is what the set command is initializing this to. is SQLPLUS a variable so i dont have to type the path when i try to put it in my .csh script?
If so then all i need to do to run this script on a mysql database is simply set the SQLPLUS(problably change it to MYSQL) to point to the path where my msql exec is right
set MYSQL=${MYSQL_HOME}/bin/mysql
then just invoke mysql and run the sql statement
${MYSQL}${MYDBUSER}#${REPORT}
is this what i need to do ro tun the same .tsch script to get data from a mysql table?
You'll need something like this:
${MYSQL} -u $username -p$password -D $database < ${REPORT}
(The username and password are passed in differently to the mysql executable than they are passed to SQLPlus. You'll need to parse out the username and the password from ${MYDBUSER}. Likely, that contains a string such as "scott/tiger". The equivalent on the mysql command line client would be "-u scott -ptiger -D scott".
That # (at sign) is a SQLPlus thing; it tells SQLPLus to read input from the specified filename. The equivalent in mysql would be the source command, e.g.
${MYSQL} -u $username -p$password <_EOD!
use $database
source ${REPORT}
_EOD!
Also, your report.sql file likely includes spool and other SQLPLus specific commands. The mysql command line client is NOT ANYWHERE near as powerful a reporting tool as SQLPlus is.
Addendum:
Q: what exactly does the spool do?
The SQLPlus spool command directs output to a file. It's frequently used to create a log file from a SQLPLus session, and is also useful for creating report files.
set trimspool on
spool /tmp/file.lis
select 'foo' as foo from dual;
spool off
Q: Why can't i set the user name and passowrd to a variable and use that?
You could set a variable, the end result of the command line sent to the OS would be the same.
set MYDBUSER="-u username -ppassword -D database"
${MYSQL} ${MYDBUSER} <${REPORT}
Q:Seems like mysql is more verbose than sqlplus.
The mysql command line client takes unix-style options. These are equivalent:
mysql -u myusername -pmypassword -D mydatabase
mysql --user=myusername --password=mypassword --database=mydatabase