Skip to content

Commit 9057637

Browse files
mysql_info - add table count to the databases returned values (#691)
* Add tables count per database * Add integrations tests * Deduplicate tests between main and new task file
1 parent d613fa1 commit 9057637

File tree

4 files changed

+207
-121
lines changed

4 files changed

+207
-121
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
---
2+
minor_changes:
3+
- mysql_info - adds the count of tables for each database to the returned values. It is possible to exclude this new field using the ``db_table_count`` exclusion filter. (https://github.com/ansible-collections/community.mysql/pull/691)

plugins/modules/mysql_info.py

Lines changed: 40 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
exclude_fields:
3636
description:
3737
- List of fields which are not needed to collect.
38-
- "Supports elements: C(db_size). Unsupported elements will be ignored."
38+
- "Supports elements: C(db_size), C(db_table_count). Unsupported elements will be ignored."
3939
type: list
4040
elements: str
4141
version_added: '0.1.0'
@@ -204,13 +204,19 @@
204204
returned: if not excluded by filter
205205
type: dict
206206
sample:
207-
- { "mysql": { "size": 656594 }, "information_schema": { "size": 73728 } }
207+
- { "mysql": { "size": 656594, "tables": 31 }, "information_schema": { "size": 73728, "tables": 79 } }
208208
contains:
209209
size:
210210
description: Database size in bytes.
211211
returned: if not excluded by filter
212212
type: dict
213213
sample: { 'size': 656594 }
214+
tables:
215+
description: Count of tables and views in that database.
216+
returned: if not excluded by filter
217+
type: dict
218+
sample: { 'tables': 12 }
219+
version_added: '3.11.0'
214220
settings:
215221
description: Global settings (variables) information.
216222
returned: if not excluded by filter
@@ -656,40 +662,39 @@ def __get_users_info(self):
656662

657663
def __get_databases(self, exclude_fields, return_empty_dbs):
658664
"""Get info about databases."""
659-
if not exclude_fields:
660-
query = ('SELECT table_schema AS "name", '
661-
'SUM(data_length + index_length) AS "size" '
662-
'FROM information_schema.TABLES GROUP BY table_schema')
663-
else:
664-
if 'db_size' in exclude_fields:
665-
query = ('SELECT table_schema AS "name" '
666-
'FROM information_schema.TABLES GROUP BY table_schema')
667-
668-
res = self.__exec_sql(query)
669-
670-
if res:
671-
for db in res:
672-
self.info['databases'][db['name']] = {}
673-
674-
if not exclude_fields or 'db_size' not in exclude_fields:
675-
if db['size'] is None:
676-
db['size'] = 0
677-
678-
self.info['databases'][db['name']]['size'] = int(db['size'])
679-
680-
# If empty dbs are not needed in the returned dict, exit from the method
681-
if not return_empty_dbs:
682-
return None
683-
684-
# Add info about empty databases (issue #65727):
685-
res = self.__exec_sql('SHOW DATABASES')
686-
if res:
687-
for db in res:
688-
if db['Database'] not in self.info['databases']:
689-
self.info['databases'][db['Database']] = {}
690665

691-
if not exclude_fields or 'db_size' not in exclude_fields:
692-
self.info['databases'][db['Database']]['size'] = 0
666+
def is_field_included(field_name):
667+
return not exclude_fields or 'db_{}'.format(field_name) not in exclude_fields
668+
669+
def create_db_info(db_data):
670+
info = {}
671+
if is_field_included('size'):
672+
info['size'] = int(db_data.get('size', 0) or 0)
673+
if is_field_included('table_count'):
674+
info['tables'] = int(db_data.get('tables', 0) or 0)
675+
return info
676+
677+
# Build the main query
678+
query_parts = ['SELECT table_schema AS "name"']
679+
if is_field_included('size'):
680+
query_parts.append('SUM(data_length + index_length) AS "size"')
681+
if is_field_included('table_count'):
682+
query_parts.append('COUNT(table_name) as "tables"')
683+
684+
query = "{} FROM information_schema.TABLES GROUP BY table_schema".format(", ".join(query_parts))
685+
686+
# Get and process databases with tables
687+
databases = self.__exec_sql(query) or []
688+
for db in databases:
689+
self.info['databases'][db['name']] = create_db_info(db)
690+
691+
# Handle empty databases if requested
692+
if return_empty_dbs:
693+
empty_databases = self.__exec_sql('SHOW DATABASES') or []
694+
for db in empty_databases:
695+
db_name = db['Database']
696+
if db_name not in self.info['databases']:
697+
self.info['databases'][db_name] = create_db_info({})
693698

694699
def __exec_sql(self, query, ddl=False):
695700
"""Execute SQL.
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
---
2+
3+
- module_defaults:
4+
community.mysql.mysql_db: &mysql_defaults
5+
login_user: "{{ mysql_user }}"
6+
login_password: "{{ mysql_password }}"
7+
login_host: "{{ mysql_host }}"
8+
login_port: "{{ mysql_primary_port }}"
9+
community.mysql.mysql_query: *mysql_defaults
10+
community.mysql.mysql_info: *mysql_defaults
11+
community.mysql.mysql_user: *mysql_defaults
12+
13+
block:
14+
15+
# ================================ Prepare ==============================
16+
- name: Mysql_info databases | Prepare | Create databases
17+
community.mysql.mysql_db:
18+
name:
19+
- db_tables_count_empty
20+
- db_tables_count_1
21+
- db_tables_count_2
22+
- db_only_views # https://github.com/ansible-Getions/community.mysql/issues/204
23+
state: present
24+
25+
- name: Mysql_info databases | Prepare | Create tables
26+
community.mysql.mysql_query:
27+
query:
28+
- >-
29+
CREATE TABLE IF NOT EXISTS db_tables_count_1.t1
30+
(id int, name varchar(9))
31+
- >-
32+
CREATE TABLE IF NOT EXISTS db_tables_count_2.t1
33+
(id int, name1 varchar(9))
34+
- >-
35+
CREATE TABLE IF NOT EXISTS db_tables_count_2.t2
36+
(id int, name1 varchar(9))
37+
- >-
38+
CREATE VIEW db_only_views.v_today (today) AS SELECT CURRENT_DATE
39+
40+
# ================================== Tests ==============================
41+
42+
- name: Mysql_info databases | Get all non-empty databases fields
43+
community.mysql.mysql_info:
44+
filter:
45+
- databases
46+
register: result
47+
failed_when:
48+
- >
49+
result.databases['db_tables_count_1'].size != 16384 or
50+
result.databases['db_tables_count_1'].tables != 1 or
51+
result.databases['db_tables_count_2'].size != 32768 or
52+
result.databases['db_tables_count_2'].tables != 2 or
53+
result.databases['db_only_views'].size != 0 or
54+
result.databases['db_only_views'].tables != 1 or
55+
'db_tables_count_empty' in result.databases | dict2items
56+
| map(attribute='key')
57+
58+
- name: Mysql_info databases | Get all dbs fields except db_size
59+
community.mysql.mysql_info:
60+
filter:
61+
- databases
62+
exclude_fields:
63+
- db_size
64+
register: result
65+
failed_when:
66+
- >
67+
result.databases['db_tables_count_1'].size is defined or
68+
result.databases['db_tables_count_1'].tables != 1 or
69+
result.databases['db_tables_count_2'].size is defined or
70+
result.databases['db_tables_count_2'].tables != 2 or
71+
result.databases['db_only_views'].size is defined or
72+
result.databases['db_only_views'].tables != 1 or
73+
'db_tables_count_empty' in result.databases | dict2items
74+
| map(attribute='key')
75+
76+
# 'unsupported' element is passed to check that an unsupported value
77+
# won't break anything (will be ignored regarding to the module's
78+
# documentation).
79+
- name: Mysql_info databases | Get all dbs fields with unsupported value
80+
community.mysql.mysql_info:
81+
filter:
82+
- databases
83+
exclude_fields:
84+
- db_size
85+
- unsupported
86+
register: result
87+
failed_when:
88+
- >
89+
result.databases['db_tables_count_1'].size is defined or
90+
result.databases['db_tables_count_1'].tables != 1 or
91+
result.databases['db_tables_count_2'].size is defined or
92+
result.databases['db_tables_count_2'].tables != 2 or
93+
result.databases['db_only_views'].size is defined or
94+
result.databases['db_only_views'].tables != 1 or
95+
'db_tables_count_empty' in result.databases | dict2items
96+
| map(attribute='key')
97+
98+
- name: Mysql_info databases | Get all dbs fields except tables
99+
community.mysql.mysql_info:
100+
filter:
101+
- databases
102+
exclude_fields:
103+
- db_table_count
104+
register: result
105+
failed_when:
106+
- >
107+
result.databases['db_tables_count_1'].size != 16384 or
108+
result.databases['db_tables_count_1'].tables is defined or
109+
result.databases['db_tables_count_2'].size != 32768 or
110+
result.databases['db_tables_count_2'].tables is defined or
111+
result.databases['db_only_views'].size != 0 or
112+
result.databases['db_only_views'].tables is defined or
113+
'db_tables_count_empty' in result.databases | dict2items
114+
| map(attribute='key')
115+
116+
- name: Mysql_info databases | Get all dbs even empty ones
117+
community.mysql.mysql_info:
118+
filter:
119+
- databases
120+
return_empty_dbs: true
121+
register: result
122+
failed_when:
123+
- >
124+
result.databases['db_tables_count_1'].size != 16384 or
125+
result.databases['db_tables_count_1'].tables != 1 or
126+
result.databases['db_tables_count_2'].size != 32768 or
127+
result.databases['db_tables_count_2'].tables != 2 or
128+
result.databases['db_only_views'].size != 0 or
129+
result.databases['db_only_views'].tables != 1 or
130+
result.databases['db_tables_count_empty'].size != 0 or
131+
result.databases['db_tables_count_empty'].tables != 0
132+
133+
- name: Mysql_info databases | Get all dbs even empty ones without size
134+
community.mysql.mysql_info:
135+
filter:
136+
- databases
137+
exclude_fields:
138+
- db_size
139+
return_empty_dbs: true
140+
register: result
141+
failed_when:
142+
- >
143+
result.databases['db_tables_count_1'].size is defined or
144+
result.databases['db_tables_count_1'].tables != 1 or
145+
result.databases['db_tables_count_2'].size is defined or
146+
result.databases['db_tables_count_2'].tables != 2 or
147+
result.databases['db_only_views'].size is defined or
148+
result.databases['db_only_views'].tables != 1 or
149+
result.databases['db_tables_count_empty'].size is defined or
150+
result.databases['db_tables_count_empty'].tables != 0
151+
152+
# ================================== Cleanup ============================
153+
154+
- name: Mysql_info databases | Cleanup databases
155+
community.mysql.mysql_db:
156+
name:
157+
- db_tables_count_empty
158+
- db_tables_count_1
159+
- db_tables_count_2
160+
- db_only_views
161+
state: absent

tests/integration/targets/test_mysql_info/tasks/main.yml

Lines changed: 3 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -132,94 +132,11 @@
132132
- result.global_status is not defined
133133
- result.users is not defined
134134

135-
# Test exclude_fields: db_size
136-
# 'unsupported' element is passed to check that an unsupported value
137-
# won't break anything (will be ignored regarding to the module's documentation).
138-
- name: Collect info about databases excluding their sizes
139-
mysql_info:
140-
<<: *mysql_params
141-
filter:
142-
- databases
143-
exclude_fields:
144-
- db_size
145-
- unsupported
146-
register: result
147-
148-
- assert:
149-
that:
150-
- result is not changed
151-
- result.databases != {}
152-
- result.databases.mysql == {}
153-
154-
########################################################
155-
# Issue #65727, empty databases must be in returned dict
156-
#
157-
- name: Create empty database acme
158-
mysql_db:
159-
<<: *mysql_params
160-
name: acme
161-
162-
- name: Collect info about databases
163-
mysql_info:
164-
<<: *mysql_params
165-
filter:
166-
- databases
167-
return_empty_dbs: true
168-
register: result
169-
170-
# Check acme is in returned dict
171-
- assert:
172-
that:
173-
- result is not changed
174-
- result.databases.acme.size == 0
175-
- result.databases.mysql != {}
176-
177-
- name: Collect info about databases excluding their sizes
178-
mysql_info:
179-
<<: *mysql_params
180-
filter:
181-
- databases
182-
exclude_fields:
183-
- db_size
184-
return_empty_dbs: true
185-
register: result
186-
187-
# Check acme is in returned dict
188-
- assert:
189-
that:
190-
- result is not changed
191-
- result.databases.acme == {}
192-
- result.databases.mysql == {}
193-
194-
- name: Remove acme database
195-
mysql_db:
196-
<<: *mysql_params
197-
name: acme
198-
state: absent
199-
200135
- include_tasks: issue-28.yml
201136

202-
# https://github.com/ansible-collections/community.mysql/issues/204
203-
- name: Create database containing only views
204-
mysql_db:
205-
<<: *mysql_params
206-
name: allviews
207-
208-
- name: Create view
209-
mysql_query:
210-
<<: *mysql_params
211-
login_db: allviews
212-
query: 'CREATE VIEW v_today (today) AS SELECT CURRENT_DATE'
213-
214-
- name: Fetch info
215-
mysql_info:
216-
<<: *mysql_params
217-
register: result
218-
219-
- name: Check
220-
assert:
221-
that:
222-
- result.databases.allviews.size == 0
137+
- name: Import tasks file to tests tables count in database filter
138+
ansible.builtin.import_tasks:
139+
file: filter_databases.yml
223140

224141
- name: Import tasks file to tests users_info filter
225142
ansible.builtin.import_tasks:

0 commit comments

Comments
 (0)