mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge pull request #43625 from gtmanfred/2017.7
results and columns are lists for mysql returns
This commit is contained in:
commit
ed7eeaaafb
4 changed files with 155 additions and 6 deletions
|
@ -687,11 +687,20 @@ def file_query(database, file_name, **connection_args):
|
|||
|
||||
.. versionadded:: 2017.7.0
|
||||
|
||||
database
|
||||
|
||||
database to run script inside
|
||||
|
||||
file_name
|
||||
|
||||
File name of the script. This can be on the minion, or a file that is reachable by the fileserver
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' mysql.file_query mydb file_name=/tmp/sqlfile.sql
|
||||
salt '*' mysql.file_query mydb file_name=salt://sqlfile.sql
|
||||
|
||||
Return data:
|
||||
|
||||
|
@ -700,6 +709,9 @@ def file_query(database, file_name, **connection_args):
|
|||
{'query time': {'human': '39.0ms', 'raw': '0.03899'}, 'rows affected': 1L}
|
||||
|
||||
'''
|
||||
if any(file_name.startswith(proto) for proto in ('salt://', 'http://', 'https://', 'swift://', 's3://')):
|
||||
file_name = __salt__['cp.cache_file'](file_name)
|
||||
|
||||
if os.path.exists(file_name):
|
||||
with salt.utils.fopen(file_name, 'r') as ifile:
|
||||
contents = ifile.read()
|
||||
|
@ -708,7 +720,7 @@ def file_query(database, file_name, **connection_args):
|
|||
return False
|
||||
|
||||
query_string = ""
|
||||
ret = {'rows returned': 0, 'columns': 0, 'results': 0, 'rows affected': 0, 'query time': {'raw': 0}}
|
||||
ret = {'rows returned': 0, 'columns': [], 'results': [], 'rows affected': 0, 'query time': {'raw': 0}}
|
||||
for line in contents.splitlines():
|
||||
if re.match(r'--', line): # ignore sql comments
|
||||
continue
|
||||
|
@ -728,16 +740,16 @@ def file_query(database, file_name, **connection_args):
|
|||
if 'rows returned' in query_result:
|
||||
ret['rows returned'] += query_result['rows returned']
|
||||
if 'columns' in query_result:
|
||||
ret['columns'] += query_result['columns']
|
||||
ret['columns'].append(query_result['columns'])
|
||||
if 'results' in query_result:
|
||||
ret['results'] += query_result['results']
|
||||
ret['results'].append(query_result['results'])
|
||||
if 'rows affected' in query_result:
|
||||
ret['rows affected'] += query_result['rows affected']
|
||||
ret['query time']['human'] = str(round(float(ret['query time']['raw']), 2)) + 's'
|
||||
ret['query time']['raw'] = round(float(ret['query time']['raw']), 5)
|
||||
|
||||
# Remove empty keys in ret
|
||||
ret = dict((k, v) for k, v in six.iteritems(ret) if v)
|
||||
ret = {k: v for k, v in six.iteritems(ret) if v}
|
||||
|
||||
return ret
|
||||
|
||||
|
|
7
tests/integration/files/file/base/mysql/select_query.sql
Normal file
7
tests/integration/files/file/base/mysql/select_query.sql
Normal file
|
@ -0,0 +1,7 @@
|
|||
CREATE TABLE test_select (a INT);
|
||||
insert into test_select values (1);
|
||||
insert into test_select values (3);
|
||||
insert into test_select values (4);
|
||||
insert into test_select values (5);
|
||||
update test_select set a=2 where a=1;
|
||||
select * from test_select;
|
3
tests/integration/files/file/base/mysql/update_query.sql
Normal file
3
tests/integration/files/file/base/mysql/update_query.sql
Normal file
|
@ -0,0 +1,3 @@
|
|||
CREATE TABLE test_update (a INT);
|
||||
insert into test_update values (1);
|
||||
update test_update set a=2 where a=1;
|
|
@ -1280,6 +1280,7 @@ class MysqlModuleUserGrantTest(ModuleCase, SaltReturnAssertsMixin):
|
|||
testdb1 = 'tes.t\'"saltdb'
|
||||
testdb2 = 't_st `(:=salt%b)'
|
||||
testdb3 = 'test `(:=salteeb)'
|
||||
test_file_query_db = 'test_query'
|
||||
table1 = 'foo'
|
||||
table2 = "foo `\'%_bar"
|
||||
users = {
|
||||
|
@ -1391,13 +1392,19 @@ class MysqlModuleUserGrantTest(ModuleCase, SaltReturnAssertsMixin):
|
|||
name=self.testdb1,
|
||||
connection_user=self.user,
|
||||
connection_pass=self.password,
|
||||
)
|
||||
)
|
||||
self.run_function(
|
||||
'mysql.db_remove',
|
||||
name=self.testdb2,
|
||||
connection_user=self.user,
|
||||
connection_pass=self.password,
|
||||
)
|
||||
)
|
||||
self.run_function(
|
||||
'mysql.db_remove',
|
||||
name=self.test_file_query_db,
|
||||
connection_user=self.user,
|
||||
connection_pass=self.password,
|
||||
)
|
||||
|
||||
def _userCreation(self,
|
||||
uname,
|
||||
|
@ -1627,3 +1634,123 @@ class MysqlModuleUserGrantTest(ModuleCase, SaltReturnAssertsMixin):
|
|||
"GRANT USAGE ON *.* TO ''@'localhost'",
|
||||
"GRANT DELETE ON `test ``(:=salteeb)`.* TO ''@'localhost'"
|
||||
])
|
||||
|
||||
|
||||
@skipIf(
|
||||
NO_MYSQL,
|
||||
'Please install MySQL bindings and a MySQL Server before running'
|
||||
'MySQL integration tests.'
|
||||
)
|
||||
class MysqlModuleFileQueryTest(ModuleCase, SaltReturnAssertsMixin):
|
||||
'''
|
||||
Test file query module
|
||||
'''
|
||||
|
||||
user = 'root'
|
||||
password = 'poney'
|
||||
testdb = 'test_file_query'
|
||||
|
||||
@destructiveTest
|
||||
def setUp(self):
|
||||
'''
|
||||
Test presence of MySQL server, enforce a root password, create users
|
||||
'''
|
||||
super(MysqlModuleFileQueryTest, self).setUp()
|
||||
NO_MYSQL_SERVER = True
|
||||
# now ensure we know the mysql root password
|
||||
# one of theses two at least should work
|
||||
ret1 = self.run_state(
|
||||
'cmd.run',
|
||||
name='mysqladmin --host="localhost" -u '
|
||||
+ self.user
|
||||
+ ' flush-privileges password "'
|
||||
+ self.password
|
||||
+ '"'
|
||||
)
|
||||
ret2 = self.run_state(
|
||||
'cmd.run',
|
||||
name='mysqladmin --host="localhost" -u '
|
||||
+ self.user
|
||||
+ ' --password="'
|
||||
+ self.password
|
||||
+ '" flush-privileges password "'
|
||||
+ self.password
|
||||
+ '"'
|
||||
)
|
||||
key, value = ret2.popitem()
|
||||
if value['result']:
|
||||
NO_MYSQL_SERVER = False
|
||||
else:
|
||||
self.skipTest('No MySQL Server running, or no root access on it.')
|
||||
# Create some users and a test db
|
||||
self.run_function(
|
||||
'mysql.db_create',
|
||||
name=self.testdb,
|
||||
connection_user=self.user,
|
||||
connection_pass=self.password,
|
||||
connection_db='mysql',
|
||||
)
|
||||
|
||||
@destructiveTest
|
||||
def tearDown(self):
|
||||
'''
|
||||
Removes created users and db
|
||||
'''
|
||||
self.run_function(
|
||||
'mysql.db_remove',
|
||||
name=self.testdb,
|
||||
connection_user=self.user,
|
||||
connection_pass=self.password,
|
||||
connection_db='mysql',
|
||||
)
|
||||
|
||||
@destructiveTest
|
||||
def test_update_file_query(self):
|
||||
'''
|
||||
Test query without any output
|
||||
'''
|
||||
ret = self.run_function(
|
||||
'mysql.file_query',
|
||||
database=self.testdb,
|
||||
file_name='salt://mysql/update_query.sql',
|
||||
character_set='utf8',
|
||||
collate='utf8_general_ci',
|
||||
connection_user=self.user,
|
||||
connection_pass=self.password
|
||||
)
|
||||
self.assertTrue('query time' in ret)
|
||||
ret.pop('query time')
|
||||
self.assertEqual(ret, {'rows affected': 2})
|
||||
|
||||
@destructiveTest
|
||||
def test_select_file_query(self):
|
||||
'''
|
||||
Test query with table output
|
||||
'''
|
||||
ret = self.run_function(
|
||||
'mysql.file_query',
|
||||
database=self.testdb,
|
||||
file_name='salt://mysql/select_query.sql',
|
||||
character_set='utf8',
|
||||
collate='utf8_general_ci',
|
||||
connection_user=self.user,
|
||||
connection_pass=self.password
|
||||
)
|
||||
expected = {
|
||||
'rows affected': 5,
|
||||
'rows returned': 4,
|
||||
'results': [
|
||||
[
|
||||
['2'],
|
||||
['3'],
|
||||
['4'],
|
||||
['5']
|
||||
]
|
||||
],
|
||||
'columns': [
|
||||
['a']
|
||||
],
|
||||
}
|
||||
self.assertTrue('query time' in ret)
|
||||
ret.pop('query time')
|
||||
self.assertEqual(ret, expected)
|
||||
|
|
Loading…
Add table
Reference in a new issue