├── .gitmodules
├── LICENSE
├── README.md
├── build_scheduler.sh
├── config.toml
├── doc
├── _images
│ └── Percona_Logo_Color.png
├── proxysql_galera_checker.md
└── release-notes
│ ├── proxysql-admin_v1.3.0.md
│ ├── proxysql-admin_v1.3.2a.md
│ ├── proxysql-admin_v1.3.5.md
│ └── proxysql-admin_v1.3.6.md
├── percona-scheduler-admin
├── proxysql-admin
├── proxysql-admin-common
├── proxysql-admin.cnf
├── proxysql-common
├── proxysql-login-file
├── proxysql-logrotate
├── proxysql-status
├── tests
├── bad-login-file.clear.cnf
├── bad-login-file.cnf
├── bad-login-file2.clear.cnf
├── bad-login-file2.cnf
├── disable_proxysql.bats
├── generic-test.bats
├── login-file.clear.cnf
├── login-file.cnf
├── login-file2.clear.cnf
├── login-file2.cnf
├── proxysql-admin-testsuite.bats
├── proxysql-admin-testsuite.sh
├── scheduler-admin-testsuite.bats
├── scheduler-args.bats
├── setup_workdir.sh
├── test-common.bash
└── testsuite.toml
└── tools
├── enable_scheduler
├── mysql_exec
├── proxysql_exec
└── run_galera_checker
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "percona-scheduler"]
2 | path = percona-scheduler
3 | url = https://github.com/percona/pxc_scheduler_handler
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Percona's build for ProxySQL with Admin tools
3 |
4 | 
5 |
6 | ## ProxySQL information
7 |
8 | For information on ProxySQL, see [the ProxySQL Documentation](https://proxysql.com/documentation/), or review [the ProxySQL GitHub repository](https://github.com/sysown/proxysql).
9 |
10 | ## Percona's build for ProxySQL information
11 |
12 | The Percona's build for ProxySQL has the following tools:
13 |
14 | - [ProxySQL Admin](#proxysql-admin)
15 | - [ProxySQL Status](#proxysql-status)
16 | - [Percona Scheduler Admin](#percona-scheduler-admin)
17 |
18 | For more information about Percona's build of ProxySQL and the ProxySQL Admin tools, see the [Percona build of ProxySQL and ProxySQL Admin Utilities documentation](https://docs.percona.com/proxysql/index.html).
19 |
20 | The documentation source is in the [proxysql-admin-tool-doc repository](https://github.com/percona/proxysql-admin-tool-doc).
21 |
22 | ## Installation
23 |
24 | You can install Percona's build of ProxySQL and the ProxySQL Admin utilities with either of the following methods:
25 |
26 | - [Use the Percona repository](https://docs.percona.com/proxysql/where-to-download-proxysql.html)
27 |
28 | - [Build from source code](https://github.com/percona/proxysql-admin-tool)
29 |
30 | ## Submit a Bug report or feature request
31 |
32 | If you find a bug in any of the ProxySQL tools, [you can submit a report to the project's Jira tracker](https://jira.percona.com/projects/PSQLADM).
33 |
34 | As a general rule of thumb, please try to create a bug report that has the following qualities:
35 |
36 | - Reproducible - include the steps on how to reproduce the issue
37 |
38 | - Specific - include as much detail as possible, such as which version, environment, etc.
39 |
40 | - Unique - do not duplicate existing tickets
41 |
42 | - Scoped to a single issue - only one issue per report
43 |
44 | ## Contact
45 |
46 | [You can reach us by using the Percona Community Forum](https://forums.percona.com/c/polyglot-projects/proxysql)
47 |
48 | We encourage contributions and are always looking for new members that are as dedicated to serving the community as we are.
49 |
--------------------------------------------------------------------------------
/build_scheduler.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # This script will assist with building the pxc_scheduler_handler
3 | # Version 2.0
4 | ###############################################################################################
5 |
6 | # This program is copyright 2016-2020 Percona LLC and/or its affiliates.
7 | #
8 | # THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
9 | # WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
10 | # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11 | #
12 | # This program is free software; you can redistribute it and/or modify it under
13 | # the terms of the GNU General Public License as published by the Free Software
14 | # Foundation, version 2 or later
15 | #
16 | # You should have received a copy of the GNU General Public License version 2
17 | # along with this program; if not, write to the Free Software Foundation, Inc.,
18 | # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19 |
20 | # shellcheck disable=SC1094,SC2181,SC1091
21 |
22 | source ./proxysql-common || exit
23 |
24 | if [ ! -d percona-scheduler ]; then
25 | git submodule update --init
26 | fi
27 |
28 | pushd percona-scheduler || exit
29 |
30 | if [[ ! -e $(command -v go 2> /dev/null) ]]; then
31 | error "" "go packages not found. Please install golang package."
32 | exit 1
33 | fi
34 |
35 | go mod tidy
36 | go build -v -a -ldflags "-X main.pxcSchedulerHandlerVersion=${PROXYSQL_ADMIN_VERSION}" -o pxc_scheduler_handler
37 |
38 | if [ $? -ne 0 ]; then
39 | error "" "go build process failed with errors. Exiting.."
40 | exit 1
41 | fi
42 |
43 | popd || exit
44 |
45 | cp percona-scheduler/pxc_scheduler_handler .
46 | echo -e "Build was successful. The binary can be found in ./pxc_scheduler_handler"
47 |
48 | echo -e
49 | ./pxc_scheduler_handler --version
50 |
--------------------------------------------------------------------------------
/config.toml:
--------------------------------------------------------------------------------
1 | # For the detailed manual, see
2 | # https://github.com/percona/pxc_scheduler_handler#how-to-configure-pxc-scheduler-handler
3 | #
4 |
5 | [pxccluster]
6 | activeFailover = 1
7 | failBack = false
8 | checkTimeOut = 2000
9 | mainSegment = 0
10 | sslClient = "client-cert.pem"
11 | sslKey = "client-key.pem"
12 | sslCa = "ca.pem"
13 | sslCertificatePath = "/opt/cert/ssl_test"
14 | hgW = 100
15 | hgR = 101
16 | configHgRange =8000
17 | maintenanceHgRange =9000
18 |
19 | # --------------------------------
20 | # Set to true if there is a single writer node. If this is set,
21 | # then maxNumWriters is assumed to be 1.
22 | #
23 | # Allowable values: true,false
24 | # Default: false
25 | #
26 | singlePrimary = true
27 |
28 | # --------------------------------
29 | # Set to the number of writer nodes desired.
30 | #
31 | # The value of this is assumed to be 1 if singlePrimary is true.
32 | #
33 | # If this is set to a value from 1 to 100, then the query rules
34 | # are setup for a distinct writer hostgroup (writes are sent to the
35 | # writer hostgroup and read are sent to the reader hostgroup).
36 | #
37 | # If this is set to a value > 100, then all queries (writes and reads)
38 | # are sent to the writer hostgroup. This is assumed to be a
39 | # load-balancing scenario, where all nodes are equivalent and accept
40 | # both reads and writes.
41 | #
42 | # Default: (none)
43 | #
44 | maxNumWriters = 1
45 | writerIsAlsoReader = 1
46 | retryUp = 0
47 | retryDown = 2
48 | clusterId = 10
49 |
50 | # Controls the primary settings during failover.
51 | # More details at https://github.com/percona/pxc_scheduler_handler#persist-primary-values
52 | #
53 | # Allowed values:
54 | #
55 | # 0 Disable
56 | # 1 Persist only write settings
57 | # 2 Persist both read and write settings
58 | persistPrimarySettings=0
59 |
60 |
61 |
62 | # == proxysql ===================================================
63 | # The proxysql section is for ProxySQL-specific information.
64 | #
65 | # These settings will be read and used whenever the scheduler is run.
66 | #
67 | [proxysql]
68 | port = 6032
69 | host = "127.0.0.1"
70 | user = ""
71 | password = ""
72 | clustered = false
73 | lockfilepath ="/var/run/pxc_scheduler_handler"
74 | respectManualOfflineSoft=false
75 |
76 |
77 |
78 | #== global ======================================================
79 | # The global section are for variables that are not ProxySQL or
80 | # cluster specific.
81 | #
82 | # These settings will be read and used whenever the scheduler is run.
83 | #
84 | [global]
85 | debug = true
86 |
87 | # stdout: output is redirected to proxysql logs
88 | # file: output is written to the file pointed by logFile. When setting to
89 | # 'file', ensure that the user proxysql:proxysql has the appropriate
90 | # permissions to write to this location.
91 | logTarget = "stdout" #stdout | file
92 |
93 | # Defines the log level to be used.
94 | # Allowed options are [error,warning,info,debug]
95 | logLevel = "info"
96 | logFile = "/var/log/pxc_scheduler_handler/pscheduler.log"
97 |
98 | # Should be set to false if we are pxc_scheduler_handler through percona-scheduler-admin.
99 | daemonize = false
100 | daemonInterval = 2000
101 |
102 | # boolean variable which enables reporting of statistics.
103 | performance = true
104 |
105 | # Not used currently
106 | OS = "na"
107 |
108 | # Time in seconds after which the file lock is considered expired [local instance lock]
109 | lockFileTimeout = 60 #seconds
110 |
111 | # Time in seconds after which the cluster lock is considered expired
112 | lockClusterTimeout = 600 #seconds
113 |
114 |
115 |
116 | #== setup =======================================================
117 | # These variables are used only upon Setup
118 | # Changing these variables after setup will not affect operation
119 | #
120 | [setup]
121 |
122 | # --------------------------------
123 | # The clusterAppUser is the ProxySQL user account that should be
124 | # used by clients to access the cluster.
125 | #
126 | # Uncomment the following options (clusterAppUser and clusterAppUserPassword)
127 | # to enable the setting of the clusterAppUser for this cluster.
128 | #
129 | #clusterAppUser="proxysql_user"
130 | #clusterAppUserPassword="passw0rd"
131 |
132 | # --------------------------------
133 | # The monitorUser is used by ProxySQL to access the servers and
134 | # check the connections.
135 | #
136 | monitorUser="monitor"
137 | monitorUserPassword="monitor"
138 |
139 | # --------------------------------
140 | # The clusterXXX information is used to setup the cluster for
141 | # use by ProxySQL.
142 | #
143 | clusterHost=""
144 | clusterPort=3306
145 | clusterUser="admin"
146 | clusterUserPassword="admin"
147 |
148 | # --------------------------------
149 | # ProxySQL will use SSL to connect to the backend servers
150 | #
151 | useSSL=0
152 |
153 | # --------------------------------
154 | # Max number of connections from ProxySQL to the backend servers.
155 | #
156 | maxConnections=1000
157 |
158 | # --------------------------------
159 | # Defines how frequently (in milliseconds) the scheduler must be run
160 | #
161 | nodeCheckInterval=2000
162 |
--------------------------------------------------------------------------------
/doc/_images/Percona_Logo_Color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/percona/proxysql-admin-tool/c642b6ff3f48f1625fb4b18f1dd4cfe19729a849/doc/_images/Percona_Logo_Color.png
--------------------------------------------------------------------------------
/doc/proxysql_galera_checker.md:
--------------------------------------------------------------------------------
1 | # proxysql_galera_checker usage info.
2 |
3 | `proxysql_galera_checker` script will check Percona XtraDB Cluster desynced nodes, and temporarily deactivate them. Currently, this script is developed to work with proxysql-admin [script](https://github.com/percona/proxysql-admin-tool/blob/v2.0/README.md)
4 |
5 | This script will also call `proxysql_node_monitor` script. Monitor script will check cluster node membership, and re-configure ProxySQL if cluster membership changes occur.
6 |
7 | eg: If any node goes out from cluster this script will mark as `OFFLINE_HARD` in proxysql database. When it comes back it will mark the node as `ONLINE`.
8 |
9 | The galera checker script will be added in ProxySQL [scheduler](https://github.com/sysown/proxysql/blob/master/doc/scheduler.md) table if you use `proxysql-admin` script.
10 |
11 | Galera checker usage
12 | ```
13 | Usage: proxysql_galera_checker [hostgroup_id read] [number writers] [writers are readers 0|1] [log_file]
14 |
15 | - HOSTGROUP WRITERS (required) (0..) The hostgroup_id that contains nodes that will server 'writes'
16 | - HOSTGROUP READERS (optional) (0..) The hostgroup_id that contains nodes that will server 'reads'
17 | - NUMBER WRITERS (optional) (0..) Maximum number of write hostgroup_id node that can be marked ONLINE
18 | When 0 (default), all nodes can be marked ONLINE
19 | - WRITERS ARE READERS (optional) (0|1) When 1 (default), ONLINE nodes in write hostgroup_id will prefer not
20 | to be ONLINE in read hostgroup_id
21 | - LOG_FILE (optional) file logfile where node state checks & changes are written to (verbose)
22 |
23 | - LOG_FILE (optional) file logfile where node state checks & changes are written to (verbose)
24 |
25 |
26 | Notes about the mysql_servers in ProxySQL:
27 |
28 | - WEIGHT Hosts with a higher weight will be prefered to be put ONLINE
29 | - NODE STATUS * Nodes that are in status OFFLINE_HARD will not be checked nor will their status be changed
30 | * SHUNNED nodes are not to be used with Galera based systems, they will be checked and status
31 | will be changed to either ONLINE or OFFLINE_SOFT.
32 | ```
33 |
34 | You can configure these parameter in scheduler table with custom configuration as follows:
35 | ```
36 | arg1: HOSTGROUP WRITERS
37 | arg2: HOSTGROUP READERS
38 | arg3: NUMBER WRITERS
39 | arg4: WRITERS ARE READERS
40 | arg5: LOG_FILE
41 | ```
42 | scheduler table entry.
43 | ```
44 | mysql> select * from scheduler\G
45 | *************************** 1. row ***************************
46 | id: 11
47 | active: 1
48 | interval_ms: 5000
49 | filename: /bin/proxysql_galera_checker
50 | arg1: 10
51 | arg2: 11
52 | arg3: 1
53 | arg4: 1
54 | arg5: /var/lib/proxysql/cluster_one_proxysql_galera_check.log
55 | comment: cluster_one
56 | ```
57 |
58 | You can also use galera checker script with custom PXC proxysql configurations. But there are some limitations to this configuration.
59 |
--------------------------------------------------------------------------------
/doc/release-notes/proxysql-admin_v1.3.0.md:
--------------------------------------------------------------------------------
1 | # proxysql-admin v1.3.0 , v1.3.0a, v1.3.0b
2 |
3 | ## proxysql-admin v1.3.0b
4 |
5 | Release date : Nov 17, 2016
6 |
7 | ### Usability improvement
8 |
9 | * Added document updates for single write mode
10 | * Packaging: Added version number
11 |
12 | ### New features
13 |
14 | * Added PXC Maintenance Mode support
15 | * Percona Xtradb Cluster implemented a maintenance mode to reduce the abrupt failure of workload while the node is taken down.
16 | With this new change in PXC, ProxySQL galera checker willl continue to probe the state of individual node by checking for pxc_maint_mode (in addition to existing wsrep_local_state).
17 | If ProxySQL detects pxc_maint_mode = SHUTDOWN|MAINTENANCE then it marks the node as OFFLINE_SOFT. This will avoid creation of new connections (or workload) on said node.
18 |
19 | ## proxysql-admin v1.3.0a
20 |
21 | Release date : Oct 20, 2016
22 |
23 | ### New features
24 |
25 | * Added singlewrite mode in proxysql-admin
26 | * Added proxysql-admin logrotate support
27 |
28 | ### Bug fixes
29 |
30 | * FIXED BLD-524 - proxysql galera check log file warning messages for credentials
31 | * Removed hardcoded hostgroup id from proxysql-admin script [#1](../../../../issues/1)
32 |
--------------------------------------------------------------------------------
/doc/release-notes/proxysql-admin_v1.3.2a.md:
--------------------------------------------------------------------------------
1 | # proxysql-admin v1.3.2a
2 |
3 | Release date : Jan 12, 2017
4 |
5 | ### Usability improvement
6 |
7 | * Changed proxysql-admin default mode from loadbal to singlewrite
8 | * Modified proxysql-admion script to read configuration file by default.
9 | * Improved proxysql-admin dsn connection error message.
10 | * Changed PXC default port to 3306 in configuration file.
11 | * Resolved mismatch between command line options and EXPORT variables.
12 | * Added network restriction to ProxySQL users in PXC #16
13 | * Renamed following parameter options
14 | * --proxysql-user to --proxysql-username
15 | * --cluster-user to --cluster-username
16 | * --monitor-user to --monitor-username
17 | * --galera-check-interval to --node-check-interval
18 | * --proxysql-host to --proxysql-hostname
19 | * --cluster-host to --cluster-hostname
20 | * Repalaced following parameter options
21 | * --pxc-app-write-user to --cluster-app-username
22 | * --pxc-app-write-password to --cluster-app-password
23 | * Reomoved following parameter options
24 | * --pxc-app-read-user
25 | * --pxc-app-read-password
26 |
27 |
28 |
29 | ### New features
30 |
31 | * Modified proxysql-admin script to create single user for handling read write transactions. proxysql will manage traffic automatically and split read and write operations with the help of mysql query rule and hostgroups.
32 |
33 | All SELECT operations (except 'SELECT .. FOR UPDATE') will go to read nodes and all other transactions will go to writer node.
34 | * Added __--quick-demo__ to setup dummy proxysql configuration
35 |
36 | ### Bug fixes
37 |
38 | * Fixed .mylogin.cnf issue. Now proxysql-admin user configuration will not override with .mylogin.cnf variables. [#14](../../../../issues/14)
39 | * Fixed BLD-600
40 |
--------------------------------------------------------------------------------
/doc/release-notes/proxysql-admin_v1.3.5.md:
--------------------------------------------------------------------------------
1 | # proxysql-admin v1.3.5
2 |
3 | Release date : Apr 14, 2017
4 |
5 | ### Usability improvement
6 |
7 | * Merged upstream proxysql_galera_checker.sh changes to proxysql_galera_checker.
8 | * Added proxysql_node_monitor inside proxysql_galera_checker script to avoid scheduler table conflict.
9 |
10 | Currently we have two different entry in scheduler table to check PXC node status (proxysql_node_monitor and proxysql_galera_checker ).
11 | These two scripts are independent but it uses same mysql_servers table to change the PXC node status. Sometime these scripts will run together and update mysql_servers table. As per proxysql, scheduler entries should not interfere with each other.
12 | To overcome this issue proxysql_galera_checker script should call proxysql_node_monitor script to check node monitoring independently.
13 |
14 | * Added hostgroup info and date in proxysql node monitoring log.
15 |
--------------------------------------------------------------------------------
/doc/release-notes/proxysql-admin_v1.3.6.md:
--------------------------------------------------------------------------------
1 | # proxysql-admin v1.3.6
2 |
3 | Release date : May 12, 2017
4 |
5 | ### Usability improvement
6 |
7 | * Improved proxysql-admin mysql connection error message.
8 | * Made --write-node optional with singlewrite mode.
9 | * Added notes in /etc/proxysql-admin.cnf for each of the parameters.
10 | * Added writer node sanity check with wsrep_incoming_addresses
11 |
12 | ### Bug fixes
13 |
14 | * Fixed PQA-145 : proxysql-admin --quick-demo mode does not set auto-configure
15 |
16 |
--------------------------------------------------------------------------------
/proxysql-admin-common:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # This script contains functions common to proxysql-admin related scripts.
3 | # (currently only Percona XtraDB cluster in combination with ProxySQL is supported)
4 | # Version 2.0
5 | ###############################################################################################
6 |
7 | # This program is copyright 2016-2022 Percona LLC and/or its affiliates.
8 | #
9 | # THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
10 | # WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
11 | # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12 | #
13 | # This program is free software; you can redistribute it and/or modify it under
14 | # the terms of the GNU General Public License as published by the Free Software
15 | # Foundation, version 2 or later
16 | #
17 | # You should have received a copy of the GNU General Public License version 2
18 | # along with this program; if not, write to the Free Software Foundation, Inc.,
19 | # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20 |
21 | # shellcheck disable=SC2181
22 |
23 | #-------------------------------------------------------------------------------
24 | #
25 | # Step 1 : Bash internal configuration
26 | #
27 |
28 |
29 | #-------------------------------------------------------------------------------
30 | #
31 | # Step 2 : Global variables
32 | #
33 |
34 |
35 | #-------------------------------------------------------------------------------
36 | #
37 | # Step 3 : Helper functions
38 | #
39 |
40 |
41 | # Executes a SQL query with the (fully) specified server
42 | #
43 | # Globals:
44 | # DEBUG
45 | # TIMEOUT
46 | #
47 | # Arguments:
48 | # 1: lineno
49 | # 2: the name of the user
50 | # 3: the user's password
51 | # 4: the hostname of the server
52 | # 5: the port used to connect to the server
53 | # 6: the query to be run
54 | # 7: (optional) arguments to the mysql client
55 | # 8: (optional) additional options, space separated
56 | # Available options:
57 | # "hide_output"
58 | # This will not show the output of the query when DEBUG is set.
59 | # Used to stop the display of sensitve information (such as passwords)
60 | # from being displayed when debugging.
61 | #
62 | function exec_sql() {
63 | local lineno=$1
64 | local user=$2
65 | local password=$3
66 | local hostname=$4
67 | local port=$5
68 | local query=$6
69 | local args=""
70 | local more_options=""
71 | local retvalue
72 | local retoutput
73 | local default_auth=""
74 | local defaults=""
75 |
76 | if [[ $# -ge 7 ]]; then
77 | args=$7
78 | fi
79 |
80 | if [[ $# -ge 8 ]]; then
81 | more_options=$8
82 | fi
83 |
84 | debug "$lineno" "exec_sql : $user@$hostname:$port ==> $query"
85 |
86 | if [[ $MYSQL_CLIENT_VERSION == "8.0" ]]; then
87 | default_auth="default-auth=mysql_native_password"
88 | fi
89 |
90 | defaults=$(printf '[client]\nuser=%s\npassword="%s"\nhost=%s\nport=%s\nconnect-timeout=%s\n%s' \
91 | "${user}" \
92 | "${password}" \
93 | "${hostname}" \
94 | "${port}" \
95 | "${TIMEOUT}" \
96 | "${default_auth}"
97 | )
98 |
99 | # shellcheck disable=SC2086
100 | if [[ $USE_STDIN_FOR_CREDENTIALS -eq 1 ]]; then
101 | retoutput=$(printf "%s" "${defaults}" | mysql --defaults-file=/dev/stdin --protocol=tcp --unbuffered --batch --silent ${args} -e "$query")
102 | retvalue=$?
103 | else
104 | retoutput=$(mysql --defaults-file=<(echo "${defaults}") --protocol=tcp --unbuffered --batch --silent ${args} -e "$query")
105 | retvalue=$?
106 | fi
107 |
108 | if [[ $DEBUG -eq 1 ]]; then
109 | local number_of_newlines=0
110 | local dbgoutput=$retoutput
111 |
112 | if [[ " $more_options " =~ [[:space:]]hide_output[[:space:]] ]]; then
113 | dbgoutput="**** data hidden ****"
114 | fi
115 |
116 | if [[ -n $dbgoutput ]]; then
117 | number_of_newlines=$(printf "%s" "${dbgoutput}" | wc -l)
118 | fi
119 |
120 | if [[ $retvalue -ne 0 ]]; then
121 | debug "" "--> query failed $retvalue"
122 | elif [[ -z $dbgoutput ]]; then
123 | debug "" "--> query returned $retvalue : "
124 | elif [[ ${number_of_newlines} -eq 0 ]]; then
125 | debug "" "--> query returned $retvalue : ${dbgoutput}"
126 | else
127 | debug "" "--> query returned $retvalue : "
128 | printf "%s\n" "${dbgoutput}" | while IFS= read -r line; do
129 | debug "" "----> $line"
130 | done
131 | fi
132 | fi
133 |
134 | printf "%s" "${retoutput}"
135 | return $retvalue
136 | }
137 |
138 |
139 | # Executes a SQL query on proxysql
140 | #
141 | # Globals:
142 | # PROXYSQL_USERNAME
143 | # PROXYSQL_PASSWORD
144 | # PROXYSQL_HOSTNAME
145 | # PROXYSQL_PORT
146 | #
147 | # Arguments:
148 | # 1: lineno
149 | # 2: The SQL query
150 | # 3: (optional) Additional arguments to the mysql client for the query
151 | # 4: (optional) more options, see exec_sql
152 | #
153 | function proxysql_exec() {
154 | local lineno=$1
155 | local query=$2
156 | local args=""
157 | local more_options=""
158 |
159 | if [[ $# -ge 3 ]]; then
160 | args=$3
161 | fi
162 |
163 | if [[ -z $args ]]; then
164 | args="--skip-column_names"
165 | fi
166 |
167 | if [[ $# -ge 4 ]]; then
168 | more_options=$4
169 | fi
170 |
171 | exec_sql "$lineno" "$PROXYSQL_USERNAME" "$PROXYSQL_PASSWORD" \
172 | "$PROXYSQL_HOSTNAME" "$PROXYSQL_PORT" \
173 | "$query" "$args" "$more_options"
174 |
175 | return $?
176 | }
177 |
178 |
179 | # Executes a SQL query on a specific node in the cluster
180 | #
181 | # Globals:
182 | # CLUSTER_USERNAME
183 | # CLUSTER_PASSWORD
184 | #
185 | # Arguments:
186 | # 1: lineno
187 | # 2: cluster host
188 | # 3: cluster port
189 | # 4: The SQL query
190 | # 5: Additional arguments to the mysql client for the query
191 | # 6: (optional) more options, see exec_sql
192 | #
193 | function cluster_exec() {
194 | local lineno=$1
195 | local cluster_host=$2
196 | local cluster_port=$3
197 | local query=$4
198 | local args=""
199 | local more_options=""
200 |
201 | if [[ $# -ge 5 ]]; then
202 | args=$5
203 | fi
204 |
205 | if [[ $# -ge 6 ]]; then
206 | more_options=$6
207 | fi
208 |
209 | exec_sql "$lineno" "$CLUSTER_USERNAME" "$CLUSTER_PASSWORD" \
210 | "$cluster_host" "$cluster_port" \
211 | "$query" "$args" "$more_options"
212 |
213 | return $?
214 | }
215 |
216 |
217 | # Executes a SQL query on the CLUSTER_HOSTNAME/CLUSTER_PORT
218 | # specified in the config file.
219 | #
220 | # Globals:
221 | # CLUSTER_USERNAME
222 | # CLUSTER_PASSWORD
223 | # CLUSTER_HOSTNAME
224 | # CLUSTER_PORT
225 | #
226 | # Arguments:
227 | # 1: lineno
228 | # 2: The SQL query
229 | # 3: Additional arguments to the mysql client for the query
230 | # 4: (optional) more options, see exec_sql
231 | #
232 | function mysql_exec() {
233 | local lineno=$1
234 | local query=$2
235 | local args=""
236 | local more_options=""
237 |
238 | if [[ $# -ge 3 ]]; then
239 | args=$3
240 | fi
241 |
242 | if [[ $# -ge 4 ]]; then
243 | more_options=$4
244 | fi
245 |
246 | cluster_exec "$lineno" "$CLUSTER_HOSTNAME" "$CLUSTER_PORT" \
247 | "$query" "$args" "$more_options"
248 |
249 | return $?
250 | }
251 |
252 |
253 | # Executes a SQL query on a cluster ndde with the monitor credentials
254 | #
255 | # Globals:
256 | # CLUSTER_HOSTNAME
257 | # CLUSTER_PORT
258 | #
259 | # Arguments:
260 | # 1: lineno
261 | # 2: The monitor username
262 | # 3: The monitor password
263 | # 4: Additional arguments to the mysql client for the query
264 | # 5: The SQL query
265 | # 6: (optional) more options, see exec_sql
266 | #
267 | function monitor_exec() {
268 | local lineno=$1
269 | local user=$2
270 | local password=$3
271 | local args=$4
272 | local query=$5
273 | local more_options=""
274 |
275 | if [[ $# -ge 6 ]]; then
276 | more_options=$7
277 | fi
278 |
279 | exec_sql "$lineno" "$user" "$password" \
280 | "$CLUSTER_HOSTNAME" "$CLUSTER_PORT" \
281 | "$query" "$args" "$more_options"
282 |
283 | return $?
284 | }
285 |
286 |
287 | # This will move the configuration from memory to the runtime (load)
288 | # and from memory to disk (save)
289 | #
290 | # Globals:
291 | # None
292 | #
293 | # Arguments:
294 | # 1: the proxysql data that is being loaded and saved
295 | # (for example "MYSQL USERS" or "MYSQL SERVERS").
296 | # 2: the lineno where this function was invoked
297 | # 3: (optional) call "SAVE $1 FROM RUNTIME" after
298 | # loading data to runtime. This is done for
299 | # MYSQL USERS to load the encrypted version of the
300 | # password field.
301 | #
302 | # This function will exit the program if an error occurs while
303 | # loaded to runtime or saving to disk.
304 | #
305 | function proxysql_load_to_runtime_save_to_disk() {
306 | local data_type=$1
307 | local lineno=$2
308 | local reload_from_runtime=0
309 |
310 | if [[ $# -ge 3 ]]; then
311 | reload_from_runtime=$3
312 | fi
313 |
314 | proxysql_exec "$LINENO" "LOAD ${data_type} TO RUNTIME"
315 | check_cmd $? "$lineno" "Failed to load the ${data_type} configuration to runtime."\
316 | "\n-- Please check the ProxySQL configuration and status."
317 | debug "$lineno" "Loaded ${data_type} to runtime"
318 |
319 | if [[ $reload_from_runtime -eq 1 ]]; then
320 | # This has a specific purpose for the MYSQL USERS
321 | # This will cause the password field to be loaded with the encrypted version
322 | # of the password field
323 | proxysql_exec "$LINENO" "SAVE ${data_type} FROM RUNTIME"
324 | check_cmd $? "$lineno" "Failed to load the ${data_type} configuration from the runtime."\
325 | "\n-- Please check the ProxySQL configuration and status."
326 | debug "$lineno" "Saved ${data_type} from runtime"
327 | fi
328 |
329 | proxysql_exec "$LINENO" "SAVE ${data_type} TO DISK;"
330 | check_cmd $? "$lineno" "Failed to save the ${data_type} configuration to disk."\
331 | "\n-- Please check the ProxySQL configuration and status."
332 | debug "$lineno" "Saved ${data_type} to disk"
333 | }
334 |
335 |
336 | # Update mysql server version details in proxysql db
337 | # Globals:
338 | # WRITER_HOSTGROUP_ID
339 | # CLUSTER_HOSTNAME (overwrites)
340 | # CLUSTER_PORT (overwrites)
341 | #
342 | # Arguments:
343 | # None
344 | function update_mysql_version()
345 | {
346 | local cluster_node
347 |
348 | # Find a cluster node that belongs to the cluster with $WRITER_HOSTGROUP_ID
349 | cluster_node=$(find_cluster_node "$WRITER_HOSTGROUP_ID")
350 | check_cmd $? "$LINENO" "Could not find a primary cluster node"
351 |
352 | # Reset the central cluster node (so that calls to mysql_exec) will
353 | # work with this new node, rather than the node in the config file
354 | CLUSTER_HOSTNAME=$(echo -e "$cluster_node" | cut -f1)
355 | CLUSTER_PORT=$(echo -e "$cluster_node" | cut -f2)
356 | cluster_connection_check
357 |
358 | proxysql_mysql_version_string=$(proxysql_exec "$LINENO" "select variable_value from global_variables where variable_name like 'mysql-server_version'")
359 | check_cmd $? "$LINENO" "Failed to select the mysql-server_version variables from ProxySQL."\
360 | "\n-- Please check the ProxySQL connection parameters and status."
361 | mysql_version_string=$(mysql_exec "$LINENO" "SELECT VERSION();" | tail -1 | cut -d'-' -f1 )
362 | check_cmd $? "$LINENO" "Failed to select the mysql version info from Cluster node."\
363 | "\n-- Please check the PXC connection parameters and status."
364 | if [[ $proxysql_mysql_version_string != "$mysql_version_string" ]]; then
365 | proxysql_exec "$LINENO" \
366 | "UPDATE global_variables
367 | SET variable_value='$mysql_version_string'
368 | WHERE variable_name='mysql-server_version';"
369 | check_cmd $? "$LINENO" "Failed to set the mysql-server_version variables in ProxySQL."\
370 | "\n-- Please check the ProxySQL connection parameters and status."
371 | echo "ProxySQL MySQL version changed to $mysql_version_string"
372 | proxysql_load_to_runtime_save_to_disk "MYSQL VARIABLES" $LINENO
373 | fi
374 | }
375 |
376 | # Adds an application user to ProxySQL
377 | #
378 | # Globals:
379 | # WRITER_HOSTGROUP_ID
380 | # CLUSTER_HOSTNAME (overwrites)
381 | # CLUSTER_PORT (overwrites)
382 | #
383 | # Arguments:
384 | # None
385 | #
386 | function adduser(){
387 | debug "$LINENO" "adduser ()"
388 |
389 | local cluster_node
390 |
391 | # Find a cluster node that belongs to the cluster with $WRITER_HOSTGROUP_ID
392 | cluster_node=$(find_cluster_node "$WRITER_HOSTGROUP_ID")
393 | check_cmd $? "$LINENO" "Could not find a primary cluster node"
394 |
395 | # Reset the central cluster node (so that calls to mysql_exec) will
396 | # work with this new node, rather than the node in the config file
397 | CLUSTER_HOSTNAME=$(echo -e "$cluster_node" | cut -f1)
398 | CLUSTER_PORT=$(echo -e "$cluster_node" | cut -f2)
399 | cluster_connection_check
400 |
401 | local cluster_app_write_username
402 | local cluster_app_write_password
403 | local safe_cluster_app_write_username
404 | local safe_cluster_app_write_password
405 |
406 | echo -e "\nAdding PXC application user to the ProxySQL database"
407 | echo -n "Enter the PXC application user name: "
408 | read -r cluster_app_write_username
409 | while [[ -z "$cluster_app_write_username" ]]
410 | do
411 | echo -n "No input entered. Enter the PXC application user name: "
412 | read -r cluster_app_write_username
413 | done
414 | safe_cluster_app_write_username=${cluster_app_write_username//\'/\'\'}
415 |
416 | read -r -s -p "Enter the PXC application user password: " cluster_app_write_password
417 | while [[ -z "$cluster_app_write_password" ]]
418 | do
419 | read -r -s -p "No input entered. Enter the PXC application user password: " cluster_app_write_password
420 | done
421 | safe_cluster_app_write_password=${cluster_app_write_password//\'/\'\'}
422 |
423 | # check to see if the user already exists
424 | local check_user
425 | local check_cluster_user
426 |
427 | check_user=$(proxysql_exec "$LINENO" \
428 | "SELECT username
429 | FROM mysql_users
430 | WHERE username='$safe_cluster_app_write_username'")
431 | check_cmd $? "$LINENO" "Could not retrieve the user from ProxySQL."\
432 | "\n-- Check the ProxySQL connection parameters and status."
433 | if [[ -n "$check_user" ]]; then
434 | error "$LINENO" "The application user '$cluster_app_write_username' already exists in ProxySQL."
435 | exit 1
436 | fi
437 |
438 | check_cluster_user=$(mysql_exec "$LINENO" "SELECT user,host FROM mysql.user where user='$safe_cluster_app_write_username'")
439 | check_cmd $? "$LINENO" "Could not retrieve the user from PXC."\
440 | "\n-- Check the PXC connection parameters and status."
441 | if [[ -z "$check_cluster_user" ]]; then
442 | local check_param
443 | echo -e "\n\n"
444 | read -r -p "The application user '$cluster_app_write_username' does not exist in PXC. Would you like to proceed [y/n] ? " check_param
445 | case $check_param in
446 | y|Y)
447 | proxysql_exec "$LINENO" \
448 | "INSERT INTO mysql_users
449 | (username,password,active,default_hostgroup)
450 | VALUES
451 | ('$safe_cluster_app_write_username','$safe_cluster_app_write_password',1,$WRITER_HOSTGROUP_ID);"
452 | check_cmd $? "$LINENO" "Failed to add the PXC application user: '$cluster_app_write_username' to ProxySQL."\
453 | "\n-- Please check the ProxySQL connection parameters and status."
454 | echo -e "\nPlease create the user ${BD}$cluster_app_write_username${NBD} in PXC to access the application through ProxySQL"
455 | ;;
456 | n|N)
457 | exit 0
458 | ;;
459 | *)
460 | error "" "Please type [y/n]!"
461 | exit 1
462 | ;;
463 | esac
464 | else
465 | proxysql_exec "$LINENO" \
466 | "INSERT INTO mysql_users
467 | (username,password,active,default_hostgroup)
468 | values
469 | ('$safe_cluster_app_write_username','$safe_cluster_app_write_password',1,$WRITER_HOSTGROUP_ID);"
470 | check_cmd $? "$LINENO" "Failed to add the PXC application user: '$cluster_app_write_username' to ProxySQL."\
471 | "\n-- Please check the ProxySQL connection parameters and status."
472 | fi
473 |
474 | proxysql_load_to_runtime_save_to_disk "MYSQL USERS" "$LINENO" "1"
475 | }
476 |
477 | # Check to see if the cluster is in mysql_galera_hostgroups
478 | #
479 | # Globals:
480 | # None
481 | #
482 | # Arguments:
483 | # Parameter 1 : the writer hostgroup id
484 | #
485 | function cluster_in_proxysql_check() {
486 | local write_hg=$1
487 |
488 | # As scheduler does not use the mysql_galera_hostgroups table,
489 | # skip this check when scheduler is active
490 | local is_scheduler_active
491 | is_scheduler_active=$(proxysql_exec "$LINENO" \
492 | "SELECT active
493 | FROM runtime_scheduler
494 | WHERE comment like '% hgW:${write_hg}%'")
495 |
496 |
497 | if [[ $is_scheduler_active -eq 1 ]]; then
498 | return
499 | fi
500 |
501 | # Check to see if mysql_galera_hostgroups already has an
502 | # entry for the worker hostgroup
503 | local hostgroup_in_use
504 | hostgroup_in_use=$(proxysql_exec "$LINENO" \
505 | "SELECT count(*)
506 | FROM mysql_galera_hostgroups
507 | WHERE
508 | writer_hostgroup = $write_hg")
509 | check_cmd $? "$LINENO" "Galera hostgroup retrieval failed."\
510 | "\n-- Please check the ProxySQL connection parameters and status."
511 |
512 | # If there are no hostgroups with this writer hostgroup id
513 | # then return failure
514 | if [[ $hostgroup_in_use -eq 0 ]]; then
515 | error "$LINENO" "The cluster (with writer hostgroup:$WRITER_HOSTGROUP_ID) has not been configured in ProxySQL"
516 | exit 1
517 | fi
518 | }
519 |
520 | # Synchronizes the users between ProxySQL and PXC
521 | #
522 | # This function was created to auto sync all the existing users already
523 | # in MySQL to proxySQL's mysql_users table. As there is not much point
524 | # in having users in ProxySQL that don't exist in MySQL, this function
525 | # will delete any users from ProxySQL that were not found in MySQL.
526 | #
527 | # Going forward you can add/remove application users in MySQL then
528 | # rerun proxysql-admin with the --syncusers switch to replicate the changes
529 | # to ProxySQL.
530 | #
531 | # LIMITATIONS: Will not work properly in cases where the same user name
532 | # exists in MySQL with several hosts and different passwords.
533 | # This will cause ProxySQL to throw a "UNIQUE constraint failed"
534 | # error message.
535 | #
536 | # Globals:
537 | # WRITER_HOSTGROUP_ID
538 | # SYNCUSERS
539 | # CLUSTER_HOSTNAME (overwrites)
540 | # CLUSTER_PORT (overwrites)
541 | # SINGLE_SERVER
542 | #
543 | # Arguments:
544 | # None
545 | #
546 | function syncusers() {
547 | debug "$LINENO" "syncusers ()"
548 |
549 | local mysql_version
550 | local password_field
551 | local changes_made=0
552 |
553 | # If a single server has been specified with --server, use that server
554 | # and skip the cluster check (it may be a standalone node)
555 | if [[ -n $SINGLE_SERVER ]]; then
556 | local ws_address
557 |
558 | ws_address=$(separate_ip_port_from_address "$SINGLE_SERVER")
559 | CLUSTER_HOSTNAME=$(echo "$ws_address" | cut -d' ' -f1)
560 | CLUSTER_PORT=$(echo "$ws_address" | cut -d' ' -f2)
561 |
562 | echo -e "\nSyncing user accounts from server(${CLUSTER_HOSTNAME}:${CLUSTER_PORT}) to ProxySQL"
563 |
564 | else
565 | cluster_in_proxysql_check "${WRITER_HOSTGROUP_ID}"
566 |
567 | local cluster_node
568 |
569 | # Get current MySQL users, filter out header row and mysql.sys user
570 | # Find a cluster node that belongs to the cluster with $WRITER_HOSTGROUP_ID
571 | cluster_node=$(find_cluster_node "$WRITER_HOSTGROUP_ID")
572 | check_cmd $? "$LINENO" "Could not find a primary cluster node"
573 |
574 | # Reset the central cluster node (so that calls to mysql_exec) will
575 | # work with this new node, rather than the node in the config file
576 | CLUSTER_HOSTNAME=$(echo -e "$cluster_node" | cut -f1)
577 | CLUSTER_PORT=$(echo -e "$cluster_node" | cut -f2)
578 |
579 | echo -e "\nSyncing user accounts from PXC(${CLUSTER_HOSTNAME}:${CLUSTER_PORT}) to ProxySQL"
580 |
581 | fi
582 |
583 | # Check that we can connect to CLUSTER_HOSTNAME:CLUSTER_PORT
584 | cluster_connection_check
585 |
586 | mysql_version=$(mysql_exec "$LINENO" "SELECT VERSION();" | tail -1 | cut -d'.' -f1,2 )
587 | check_cmd $? "$LINENO" "Could not connect to the server."\
588 | "\n-- Please check the server connection parameters and status."
589 |
590 | case $mysql_version in
591 | 5.5 | 5.6)
592 | password_field="Password"
593 | ;;
594 | 5.7 | 8.0 | 8.4)
595 | password_field="authentication_string"
596 | ;;
597 | 10.0 | 10.1 | 10.2 | 10.3 | 10.4 | 10.5 | 10.6 | 10.11)
598 | password_field="Password"
599 | ;;
600 | *)
601 | error "$LINENO" "Unexpected database server version: ${mysql_version}"\
602 | "\n-- This version of proxysql-admin needs to be updated."
603 | exit 1
604 | ;;
605 | esac
606 |
607 | # Filter out the internal system users
608 | mysql_users=$(mysql_exec "$LINENO" "SELECT User,HEX(${password_field}) FROM mysql.user where ${password_field}!=''" "" "hide_output" |
609 | grep -E -v "^(mysql.sys|mysql.session|mysql.infoschema|mysql.pxc)" |
610 | sort |
611 | uniq )
612 | check_cmd $? "$LINENO" "Failed to load the user list from the server."\
613 | "\n-- Please check the server connection parameters and status."
614 |
615 | # Checking whether user is part of proxysql admin user list
616 | # Get current ProxySQL users and filter out header row
617 | proxysql_users=$(get_proxysql_users)
618 |
619 | # TEST FOR USERS THAT EXIST IN MYSQL BUT NOT IN PROXYSQL HERE AND ADD
620 |
621 | # Escape all backslashes here, because the read will evaluate
622 | # the escaped chars
623 | mysql_users=${mysql_users//\\/\\\\}
624 |
625 | # Declare associative arrays
626 | declare -A mysql_users_full_hash # Hash of MySQL users
627 | declare -A proxysql_users_full_hash # Hash of ProxySQL users
628 | local username password
629 |
630 | # Populate MySQL users hash
631 | while read -r mysql_user; do
632 | if [[ -z $mysql_user ]]; then
633 | continue
634 | fi
635 |
636 | # Add MySQL user to hash
637 | username=$(echo "$mysql_user" | cut -f1)
638 | password=$(echo "$mysql_user" | cut -f2)
639 | mysql_users_full_hash["${username}"]="$password"
640 |
641 | done < <(printf "%s\n" "${mysql_users}")
642 |
643 | # Populate ProxySQL users hash
644 | while read -r proxysql_user; do
645 | if [[ -z $proxysql_user ]]; then
646 | continue
647 | fi
648 |
649 | # Extract ProxySQL username
650 | username=$(echo "$proxysql_user" | cut -f1)
651 | password=$(echo "$proxysql_user" | cut -f2)
652 |
653 | # Add ProxySQL user to hash
654 | proxysql_users_full_hash["${username}"]="$password"
655 |
656 | done < <(printf "%s\n" "${proxysql_users}")
657 |
658 | unset username
659 | unset password
660 |
661 | # Disable nounset to be able to search in the associative array
662 | set +o nounset
663 |
664 | # Check MySQL users against ProxySQL
665 | for user in "${!mysql_users_full_hash[@]}"; do
666 |
667 | username=${user}
668 | password="${mysql_users_full_hash[${username}]}"
669 |
670 | # Since we're using single quotes within the SQL statement, only need
671 | # to escape the single quotes for SQL
672 | password=${password//\'/\'\'}
673 |
674 | debug "$LINENO" "Processing MySQL user: '${username}'"
675 |
676 | # Check if the user exists in ProxySQL
677 | if [[ -n ${proxysql_users_full_hash[${username}]} ]]; then
678 |
679 | # Perform an exact match for the user and password
680 | if [[ "${proxysql_users_full_hash[${username}]}" == "${mysql_users_full_hash[${username}]}" ]]; then
681 | debug "$LINENO" "MySQL user: '${username}' already exists in ProxySQL, continuing"
682 | # User already exists in ProxySQL, we may skip this user
683 | continue
684 |
685 | else
686 |
687 | # If the same user exists in ProxySQL, but with a different password,
688 | # then remove all such users from ProxySQL
689 |
690 | echo "Removing existing user from ProxySQL: ${username}"
691 | proxysql_exec "$LINENO" "DELETE FROM mysql_users WHERE username='${username}' and default_hostgroup=$WRITER_HOSTGROUP_ID"
692 | check_cmd $? "$LINENO" "Failed to delete the user (${username}) from ProxySQL database."\
693 | "\n-- Please check the ProxySQL connection parameters and status."
694 | proxysql_exec "$LINENO" "DELETE FROM mysql_query_rules WHERE username='${username}' and destination_hostgroup in($WRITER_HOSTGROUP_ID,$READER_HOSTGROUP_ID)"
695 | check_cmd $? "$LINENO" "Failed to delete the query rule for user (${username}) from ProxySQL database."\
696 | "\n-- Please check the ProxySQL connection parameters and status."
697 | changes_made=1
698 | fi
699 | fi
700 |
701 | # Check for ProxySQL admin user
702 | local is_proxysql_admin_user
703 | is_proxysql_admin_user=$(proxysql_admin_user_check "${username}")
704 | if [[ $is_proxysql_admin_user -eq 1 ]]; then
705 | echo -e "\nNote : '${username}' is in proxysql admin user list, this user cannot be added to ProxySQL"\
706 | "\n-- (For more info, see https://github.com/sysown/proxysql/issues/709)"
707 | else
708 | # Verify that the user does not exist in ProxySQL
709 | check_user=$(proxysql_exec "$LINENO" "SELECT username from mysql_users where username='${username}'")
710 | if [[ -z $check_user ]]; then
711 | # It is confirmed that the user does not exist in ProxySQL, let's add it
712 | echo "Adding user to ProxySQL: ${username}"
713 | proxysql_exec "$LINENO" \
714 | "INSERT INTO mysql_users
715 | (username, password, active, default_hostgroup)
716 | VALUES
717 | ('${username}', UNHEX('${password}'), 1, $WRITER_HOSTGROUP_ID)"
718 | check_cmd $? "$LINENO" "Failed to add the user (${username}) from PXC to ProxySQL database."\
719 | "\n-- Please check the ProxySQL connection parameters and status."
720 | if [[ $ADD_QUERY_RULE -eq 1 ]];then
721 | add_query_rule "${username}"
722 | fi
723 | changes_made=1
724 | else
725 | echo "Cannot add the user (${username}). The user (${username}) already exists in ProxySQL database with different hostgroup."
726 | check_user=""
727 | fi
728 | fi
729 | done # End of for loop
730 |
731 | # Remove users from ProxySQL that do not exist in MySQL
732 | if [[ $SYNCUSERS -eq 1 ]]; then
733 |
734 | # Get all proxysql users
735 | proxysql_users=$(get_proxysql_users)
736 |
737 | # Unset the hash
738 | declare -A proxysql_users_full_hash
739 |
740 | # Populate ProxySQL users hash
741 | while read -r proxysql_user; do
742 | if [[ -z $proxysql_user ]]; then
743 | continue
744 | fi
745 |
746 | # Extract ProxySQL username
747 | username=$(echo "$proxysql_user" | cut -f1)
748 | password=$(echo "$proxysql_user" | cut -f2)
749 |
750 | # Add ProxySQL user to hash
751 | proxysql_users_full_hash["${username}"]="$password"
752 |
753 | done < <(printf "%s\n" "${proxysql_users}")
754 |
755 | # Check ProxySQL users against MySQL
756 | for username in "${!proxysql_users_full_hash[@]}"; do
757 | debug "$LINENO" "Processing ProxySQL user(for removal):${username}"
758 |
759 | if [[ -z ${mysql_users_full_hash["${username}"]} ]]; then
760 | # Delete the ProxySQL user
761 | echo -e "\nRemoving (non-MySQL) user from ProxySQL: ${username}"
762 | proxysql_exec "$LINENO" "DELETE FROM mysql_users WHERE username='${username}' and default_hostgroup=$WRITER_HOSTGROUP_ID"
763 | check_cmd $? "$LINENO" "Failed to delete the user (${username}) from ProxySQL database."\
764 | "\n-- Please check the ProxySQL connection parameters and status."
765 | proxysql_exec "$LINENO" "DELETE FROM mysql_query_rules WHERE username='${username}' and destination_hostgroup in($WRITER_HOSTGROUP_ID,$READER_HOSTGROUP_ID)"
766 | check_cmd $? "$LINENO" "Failed to delete the query rule for user (${username}) from ProxySQL database."\
767 | "\n-- Please check the ProxySQL connection parameters and status."
768 | changes_made=1
769 | fi
770 | done
771 | fi
772 |
773 | # Save the configuration
774 | if [[ $changes_made -eq 1 ]]; then
775 | proxysql_load_to_runtime_save_to_disk "MYSQL USERS" $LINENO
776 | proxysql_load_to_runtime_save_to_disk "MYSQL QUERY RULES" $LINENO
777 | fi
778 |
779 | # Re-enable nounset
780 | set -o nounset
781 | }
782 |
783 | # Returns a list of users from the ProxySQL database
784 | #
785 | # Globals:
786 | # WRITER_HOSTGROUP_ID
787 | #
788 | # Arguments:
789 | # None
790 | #
791 | function get_proxysql_users() {
792 | local proxysql_users
793 | proxysql_users=$(proxysql_exec "$LINENO" \
794 | "SELECT username,HEX(password)
795 | FROM mysql_users
796 | WHERE password!='' AND default_hostgroup=$WRITER_HOSTGROUP_ID" "" "hide_output")
797 | check_cmd $? "$LINENO" "Failed to load user list from ProxySQL database."\
798 | "\n-- Please check the ProxySQL connection parameters and status."
799 | proxysql_users=$(echo "$proxysql_users" |
800 | sort |
801 | uniq )
802 | printf "%s" "$proxysql_users"
803 | }
804 |
805 | # Checks if a user is a ProxySQL admin user
806 | #
807 | # Globals:
808 | # None
809 | #
810 | # Arguments:
811 | # 1: the name of the use to be checked
812 | #
813 | # Outputs (to stdout):
814 | # 1 if the user is a proxysql admin user
815 | # 0 if the user is not a proxysql admin user
816 | #
817 | function proxysql_admin_user_check(){
818 | local userchk=$1
819 | local proxysql_admin_users
820 | local is_proxysql_admin_user
821 |
822 | mapfile -t proxysql_admin_users < <(proxysql_exec "$LINENO" \
823 | "select variable_value
824 | from global_variables
825 | where variable_name like 'admin-%_credentials'" |
826 | sed 's/;/\n/g'|
827 | cut -d':' -f1 |
828 | grep -v variable_value)
829 | # shellcheck disable=SC2199
830 | if [[ " ${proxysql_admin_users[@]} " =~ [[:space:]]${userchk}[[:space:]] ]]; then
831 | is_proxysql_admin_user=1
832 | else
833 | is_proxysql_admin_user=0
834 | fi
835 | printf "%s" "$is_proxysql_admin_user"
836 | }
837 |
838 |
839 | # Returns success if the native scheduler is in use.
840 | # Returns success(0) if the native proxysql scheduler is in use.
841 | # Else returns failure(1)
842 | #
843 | # In this case, the native scheduler is used if entries are
844 | # found in mysql_galera_hostgroups, mysql_group_replication_hostgroups,
845 | # or mysql_replication_hostgroups.
846 | #
847 | # Globals:
848 | # None
849 | #
850 | # Arguments:
851 | # Parameter 1: line number
852 | #
853 | # Returns:
854 | # 0 (success) the native scheduler is being used
855 | # 1 (failure) the native scheduler is not being used
856 | # 255 (failure) error, unable to connect to proxysql
857 | #
858 | function is_native_scheduler_in_use()
859 | {
860 | local lineno=$1
861 | local count
862 |
863 | count=$(proxysql_exec "$LINENO" \
864 | "SELECT COUNT(*)
865 | FROM runtime_mysql_group_replication_hostgroups
866 | WHERE active=1")
867 | [[ $? -ne 0 ]] && return 255
868 | [[ $count -gt 0 ]] && return 0
869 |
870 | count=$(proxysql_exec "$LINENO" \
871 | "SELECT COUNT(*)
872 | FROM runtime_mysql_galera_hostgroups
873 | WHERE active=1")
874 | [[ $? -ne 0 ]] && return 255
875 | [[ $count -gt 0 ]] && return 0
876 |
877 | count=$(proxysql_exec "$LINENO" \
878 | "SELECT COUNT(*)
879 | FROM runtime_mysql_replication_hostgroups")
880 | [[ $? -ne 0 ]] && return 255
881 | [[ $count -gt 0 ]] && return 0
882 |
883 | return 1
884 | }
885 |
886 | function is_go_scheduler_in_use()
887 | {
888 | local lineno=$1
889 | local count
890 |
891 | count=$(proxysql_exec "$LINENO" \
892 | "SELECT COUNT(*)
893 | FROM runtime_scheduler
894 | WHERE active=1 AND
895 | filename LIKE '%pxc_scheduler_handler'")
896 | [[ $? -ne 0 ]] && return 255
897 | [[ $count -gt 0 ]] && return 0
898 | return 1
899 | }
900 |
901 | function is_other_scheduler_in_use()
902 | {
903 | local lineno=$1
904 | local count
905 |
906 | count=$(proxysql_exec "$LINENO" \
907 | "SELECT COUNT(*)
908 | FROM runtime_scheduler
909 | WHERE active=1 AND
910 | filename NOT LIKE '%pxc_scheduler_handler'")
911 | [[ $? -ne 0 ]] && return 255
912 | [[ $count -gt 0 ]] && return 0
913 | return 1
914 | }
915 |
916 |
917 | function native_scheduler_capability_check()
918 | {
919 | local lineno=$1
920 | if is_go_scheduler_in_use "${lineno}"; then
921 | # TODO: better error messages
922 | error "${lineno}" "Unable to setup the native ProxySQL scheduler." \
923 | "\n---- The Percona go scheduler is currently in use" \
924 | "\n---- and must be removed."
925 | return 1;
926 | fi
927 |
928 | if is_other_scheduler_in_use "${lineno}"; then
929 | # TODO: better error messages
930 | error "${lineno}" "Unable to setup the native ProxySQL scheduler." \
931 | "\n---- Another scheduler is currently in use" \
932 | "\n---- and must be removed."
933 | return 1;
934 | fi
935 | return 0;
936 | }
937 |
938 | function go_scheduler_capability_check()
939 | {
940 | local lineno=$1
941 | if is_native_scheduler_in_use "${lineno}"; then
942 | # TODO: better error messages
943 | error "${lineno}" "Unable to setup the Percona go scheduler." \
944 | "\n---- The ProxySQL native scheduler is in use" \
945 | "\n---- and must be removed."
946 | return 1;
947 | fi
948 |
949 | if is_other_scheduler_in_use "${lineno}"; then
950 | # TODO: better error messages
951 | error "${lineno}" "Unable to setup the Percona go scheduler." \
952 | "\n---- Another scheduler is in use" \
953 | "\n---- and must be removed."
954 | return 1;
955 | fi
956 |
957 | return 0;
958 | }
959 |
--------------------------------------------------------------------------------
/proxysql-admin.cnf:
--------------------------------------------------------------------------------
1 |
2 | export PROXYSQL_DATADIR='/var/lib/proxysql'
3 |
4 | # --------------------------------
5 | # encrypted login credentials file options
6 | #
7 | #export LOGIN_FILE='/path/to/loginfile'
8 | #export LOGIN_PASSWORD_FILE='/path/to/loginfile/password'
9 |
10 | # --------------------------------
11 | # proxysql admin interface credentials.
12 | #
13 | export PROXYSQL_USERNAME='admin'
14 | export PROXYSQL_PASSWORD='admin'
15 | export PROXYSQL_HOSTNAME='localhost'
16 | export PROXYSQL_PORT='6032'
17 |
18 | # --------------------------------
19 | # PXC admin credentials for connecting to pxc-cluster-node.
20 | #
21 | export CLUSTER_USERNAME='admin'
22 | export CLUSTER_PASSWORD='admin'
23 | export CLUSTER_HOSTNAME='localhost'
24 | export CLUSTER_PORT='3306'
25 |
26 | # --------------------------------
27 | # proxysql monitoring user. proxysql admin script will create
28 | # this user in pxc to monitor pxc-nodes.
29 | #
30 | export MONITOR_USERNAME='monitor'
31 | export MONITOR_PASSWORD='monitor'
32 |
33 | # --------------------------------
34 | # Application user to connect to pxc-node through proxysql
35 | #
36 | export CLUSTER_APP_USERNAME='proxysql_user'
37 | export CLUSTER_APP_PASSWORD='passw0rd'
38 |
39 | # --------------------------------
40 | # ProxySQL hostgroup IDs
41 | #
42 | export WRITER_HOSTGROUP_ID='10'
43 | export READER_HOSTGROUP_ID='11'
44 | export BACKUP_WRITER_HOSTGROUP_ID='12'
45 | export OFFLINE_HOSTGROUP_ID='13'
46 |
47 | # --------------------------------
48 | # ProxySQL read/write configuration mode.
49 | #
50 | export MODE='singlewrite'
51 |
52 | # --------------------------------
53 | # max_connections default (used only when INSERTing a new mysql_servers entry)
54 | #
55 | export MAX_CONNECTIONS='1000'
56 |
57 | # --------------------------------
58 | # Determines the maximum number of writesets a node can have queued
59 | # before the node is SHUNNED to avoid stale reads.
60 | #
61 | export MAX_TRANSACTIONS_BEHIND=100
62 |
63 | # --------------------------------
64 | # Connections to the backend servers (from ProxySQL) will use SSL
65 | #
66 | export USE_SSL='no'
67 |
68 | # --------------------------------
69 | # Determines if a node should be added to the reader hostgroup if it has
70 | # been promoted to the writer hostgroup.
71 | # If set to 'yes', then all writers (including backup-writers) are added to
72 | # the read hostgroup.
73 | # If set to 'no', then none of the writers (including backup-writers) are added.
74 | # If set to 'backup', then only the backup-writers will be added to
75 | # the read hostgroup.
76 | #
77 | export WRITERS_ARE_READERS='backup'
78 |
--------------------------------------------------------------------------------
/proxysql-common:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # This script contains functions common to all proxysql-related scripts.
3 | # (currently only Percona XtraDB cluster in combination with ProxySQL is supported)
4 | # Version 2.0
5 | ###############################################################################################
6 |
7 | # This program is copyright 2016-2020 Percona LLC and/or its affiliates.
8 | #
9 | # THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
10 | # WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
11 | # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12 | #
13 | # This program is free software; you can redistribute it and/or modify it under
14 | # the terms of the GNU General Public License as published by the Free Software
15 | # Foundation, version 2 or later
16 | #
17 | # You should have received a copy of the GNU General Public License version 2
18 | # along with this program; if not, write to the Free Software Foundation, Inc.,
19 | # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20 |
21 | #-------------------------------------------------------------------------------
22 | #
23 | # Step 1 : Bash internal configuration
24 | #
25 |
26 | #bash prompt internal configuration
27 | declare BD=""
28 | declare NBD=""
29 | declare RED=""
30 | declare NRED=""
31 |
32 | # Test if stdout and stderr are open to a terminal
33 | if [[ -t 1 ]]; then
34 | BD=$(tput bold)
35 | NBD=$(tput sgr0)
36 | fi
37 | if [[ -t 2 ]]; then
38 | RED=$(tput setaf 1)
39 | NRED=$(tput sgr0)
40 | fi
41 |
42 | #-------------------------------------------------------------------------------
43 | #
44 | # Step 2 : Global variables
45 | #
46 |
47 | #
48 | # Script parameters/constants
49 | #
50 | readonly PROXYSQL_ADMIN_VERSION="2.7.3"
51 |
52 | # The minimum required openssl version
53 | readonly REQUIRED_OPENSSL_VERSION="1.1.1"
54 |
55 | # The name of the openssl binary packaged with proxysql-admin
56 | readonly PROXYSQL_ADMIN_OPENSSL_NAME="proxysql-admin-openssl"
57 |
58 | declare -i DEBUG=0
59 |
60 | declare PROXYSQL_USERNAME=""
61 | declare PROXYSQL_PASSWORD=""
62 | declare PROXYSQL_PORT=""
63 | declare PROXYSQL_HOSTNAME=""
64 |
65 | declare CLUSTER_USERNAME=""
66 | declare CLUSTER_PASSWORD=""
67 | declare CLUSTER_HOSTNAME=""
68 | declare CLUSTER_PORT=""
69 |
70 | declare CLUSTER_APP_USERNAME=""
71 | declare CLUSTER_APP_PASSWORD=""
72 |
73 | declare MONITOR_USERNAME=""
74 | declare MONITOR_PASSWORD=""
75 |
76 | #-------------------------------------------------------------------------------
77 | #
78 | # Step 3 : Helper functions
79 | #
80 |
81 | function error() {
82 | local lineno=$1
83 | shift
84 | if [[ -n "$lineno" ]]; then
85 | printf "${BD}ERROR${NBD} (line:$lineno) : ${*//%/%%}\n" 1>&2
86 | else
87 | printf "${BD}ERROR${NBD} : ${*//%/%%}\n" 1>&2
88 | fi
89 | }
90 |
91 | function warning() {
92 | local lineno=$1
93 | shift
94 | if [[ -n "$lineno" ]]; then
95 | printf "${BD}WARNING${NBD} (line:$lineno) : ${*//%/%%}\n" 1>&2
96 | else
97 | printf "${BD}WARNING${NBD}: ${*//%/%%}\n" 1>&2
98 | fi
99 | }
100 |
101 | function debug() {
102 | if [[ $DEBUG -eq 1 ]]; then
103 | local lineno=$1
104 | shift
105 | if [[ -n "$lineno" ]]; then
106 | printf "${RED}${BD}debug (line:$lineno) : ${*//%/%%}${NBD}${NRED}\n" 1>&2
107 | else
108 | printf "${RED}debug: ${*//%/%%}${NRED}\n" 1>&2
109 | fi
110 | fi
111 | }
112 |
113 | function dump_arguments() {
114 | local arg_list=""
115 | for arg do
116 | arg_list+=" '$arg'"
117 | done
118 | echo $arg_list
119 | }
120 |
121 |
122 | # Checks the return value of the most recent command
123 | #
124 | # Globals:
125 | # None
126 | #
127 | # Arguments:
128 | # 1: the error code of the most recent command
129 | # 2: the lineno where the error occurred
130 | # 3: the error message if the error code is non-zero
131 | #
132 | # Exits the script if the retcode is non-zero.
133 | #
134 | function check_cmd() {
135 | local retcode=$1
136 | local lineno=$2
137 | shift 2
138 |
139 | if [[ ${retcode} -ne 0 ]]; then
140 | error "$lineno" $*
141 | exit 1
142 | fi
143 | }
144 |
145 |
146 | # Check the permissions for a file or directory
147 | #
148 | # Globals:
149 | # None
150 | #
151 | # Arguments:
152 | # 1: the bash test to be applied to the file
153 | # 2: the lineno where this call is invoked (used for errors)
154 | # 3: the path to the file
155 | # 4: (optional) description of the path (mostly used for existence checks)
156 | #
157 | # Exits the script if the permissions test fails.
158 | #
159 | function check_permission() {
160 | local permission=$1
161 | local lineno=$2
162 | local path_to_check=$3
163 | local description=""
164 | if [[ $# -gt 3 ]]; then
165 | description="$4"
166 | fi
167 |
168 | # shellcheck disable=SC1009,SC1073,SC1072
169 | if [ ! $permission "$path_to_check" ] ; then
170 | if [[ $permission == "-r" ]]; then
171 | error "$lineno" "You do not have READ permission for: $path_to_check"
172 | elif [[ $permission == "-w" ]]; then
173 | error "$lineno" "You do not have WRITE permission for: $path_to_check"
174 | elif [[ $permission == "-x" ]]; then
175 | error "$lineno" "You do not have EXECUTE permission for: $path_to_check"
176 | elif [[ $permission == "-e" ]]; then
177 | if [[ -n $description ]]; then
178 | error "$lineno" "Could not find the $description: $path_to_check"
179 | else
180 | error "$lineno" "Could not find: $path_to_check"
181 | fi
182 | elif [[ $permission == "-d" ]]; then
183 | if [[ -n $description ]]; then
184 | error "$lineno" "Could not find the $description: $path_to_check"
185 | else
186 | error "$lineno" "Could not find the directory: $path_to_check"
187 | fi
188 | elif [[ $permission == "-f" ]]; then
189 | if [[ -n $description ]]; then
190 | error "$lineno" "Could not find the $description: $path_to_check"
191 | else
192 | error "$lineno" "Could not find the file: $path_to_check"
193 | fi
194 | else
195 | error "$lineno" "You do not have the correct permissions for: $path_to_check"
196 | fi
197 | exit 1
198 | fi
199 | }
200 |
201 |
202 | # Separates the IP address from the port in a network address
203 | # Works for IPv4 and IPv6
204 | #
205 | # Globals:
206 | # None
207 | #
208 | # Params:
209 | # 1. The network address to be parsed
210 | #
211 | # Outputs:
212 | # A string with a space separating the IP address from the port
213 | #
214 | function separate_ip_port_from_address()
215 | {
216 | #
217 | # Break address string into host:port/path parts
218 | #
219 | local address=$1
220 |
221 | # Has to have at least one ':' to separate the port from the ip address
222 | if [[ $address =~ : ]]; then
223 | ip_addr=${address%:*}
224 | port=${address##*:}
225 | else
226 | ip_addr=$address
227 | port=""
228 | fi
229 |
230 | # Remove any braces that surround the ip address portion
231 | ip_addr=${ip_addr#\[}
232 | ip_addr=${ip_addr%\]}
233 |
234 | echo "${ip_addr} ${port}"
235 | }
236 |
237 |
238 | # Combines the IP address and port into a network address
239 | # Works for IPv4 and IPv6
240 | # (If the IP address is IPv6, the IP portion will have brackets)
241 | #
242 | # Globals:
243 | # None
244 | #
245 | # Params:
246 | # 1: The IP address portion
247 | # 2: The port
248 | #
249 | # Outputs:
250 | # A string containing the full network address
251 | #
252 | function combine_ip_port_into_address()
253 | {
254 | local ip_addr=$1
255 | local port=$2
256 | local addr
257 |
258 | if [[ ! $ip_addr =~ \[.*\] && $ip_addr =~ .*:.* ]] ; then
259 | # If there are no brackets and it does have a ':', then add the brackets
260 | # because this is an unbracketed IPv6 address
261 | addr="[${ip_addr}]:${port}"
262 | else
263 | addr="${ip_addr}:${port}"
264 | fi
265 | echo "$addr"
266 | }
267 |
268 |
269 | # Tests if a string is an integer
270 | # (checks if made up of digits with an optional minus sign)
271 | #
272 | # Arguments
273 | # Parameter 1: the string to be tested
274 | #
275 | # Returns
276 | # 0 : if the string is an integer
277 | # 1 : if the string is not like an integer
278 | #
279 | function is_integer()
280 | {
281 | if [ "$1" -eq "$1" ] 2>/dev/null; then
282 | return 0
283 | else
284 | return 1
285 | fi
286 | }
287 |
288 |
289 | # Returns the version string in a standardized format
290 | # Input "1.2.3" => echoes "010203"
291 | # Wrongly formatted values => echoes "000000"
292 | #
293 | # Globals:
294 | # None
295 | #
296 | # Arguments:
297 | # Parameter 1: a version string
298 | # like "5.1.12"
299 | # anything after the major.minor.revision is ignored
300 | # Outputs:
301 | # A string that can be used directly with string comparisons.
302 | # So, the string "5.1.12" is transformed into "050112"
303 | # Note that individual version numbers can only go up to 99.
304 | #
305 | function normalize_version()
306 | {
307 | local major=0
308 | local minor=0
309 | local patch=0
310 |
311 | # Only parses purely numeric version numbers, 1.2.3
312 | # Everything after the first three values are ignored
313 | if [[ $1 =~ ^([0-9]+)\.([0-9]+)\.?([0-9]*)([^ ])* ]]; then
314 | major=${BASH_REMATCH[1]}
315 | minor=${BASH_REMATCH[2]}
316 | patch=${BASH_REMATCH[3]}
317 | fi
318 |
319 | printf %02d%02d%02d $major $minor $patch
320 | }
321 |
322 |
323 | # Compares two version strings
324 | # The version strings passed in will be normalized to a
325 | # string-comparable version.
326 | #
327 | # Globals:
328 | # None
329 | #
330 | # Arguments:
331 | # Parameter 1: The left-side of the comparison (for example: "5.7.25")
332 | # Parameter 2: the comparison operation
333 | # '>', '>=', '=', '==', '<', '<=', "!="
334 | # Parameter 3: The right-side of the comparison (for example: "5.7.24")
335 | #
336 | # Returns:
337 | # Returns 0 (success) if param1 op param2
338 | # Returns 1 (failure) otherwise
339 | #
340 | function compare_versions()
341 | {
342 | local version_1="$1"
343 | local op=$2
344 | local version_2="$3"
345 |
346 | if [[ -z $version_1 || -z $version_2 ]]; then
347 | error "$LINENO" "Missing version string in comparison"
348 | echo -e "-- left-side:$version_1 operation:$op right-side:$version_2"
349 | return 1
350 | fi
351 |
352 | version_1="$( normalize_version "$version_1" )"
353 | version_2="$( normalize_version "$version_2" )"
354 |
355 | if [[ ! " = == > >= < <= != " =~ " $op " ]]; then
356 | error "$LINENO" "Unknown operation : $op"
357 | echo -e "-- Must be one of : = == > >= < <="
358 | return 1
359 | fi
360 |
361 | [[ $op == "<" && $version_1 < $version_2 ]] && return 0
362 | [[ $op == "<=" && ! $version_1 > $version_2 ]] && return 0
363 | [[ $op == "=" && $version_1 == $version_2 ]] && return 0
364 | [[ $op == "==" && $version_1 == $version_2 ]] && return 0
365 | [[ $op == ">" && $version_1 > $version_2 ]] && return 0
366 | [[ $op == ">=" && ! $version_1 < $version_2 ]] && return 0
367 | [[ $op == "!=" && $version_1 != $version_2 ]] && return 0
368 |
369 | return 1
370 | }
371 |
372 |
373 | # Outputs the version string (major.minor) for the path passed in
374 | #
375 | # Globals
376 | # None
377 | #
378 | # Arguments
379 | # Parameter 1 : Path to the client
380 | #
381 | # Outputs
382 | # The version number (major.minor). The version numbers are not
383 | # normalized, so they cannot be directly compared.
384 | #
385 | function get_mysql_version()
386 | {
387 |
388 | local mysql_path=$1
389 | local version_string
390 | version_string=$(${mysql_path} --version)
391 |
392 | if echo "$version_string" | grep -qe "[[:space:]]5\.5\."; then
393 | echo "5.5"
394 | elif echo "$version_string" | grep -qe "[[:space:]]5\.6\."; then
395 | echo "5.6"
396 | elif echo "$version_string" | grep -qe "[[:space:]]5\.7\."; then
397 | echo "5.7"
398 | elif echo "$version_string" | grep -qe "[[:space:]]8\.0\."; then
399 | echo "8.0"
400 | elif echo "$version_string" | grep -qe "[[:space:]]8\.4\."; then
401 | echo "8.4"
402 | elif echo "$version_string" | grep -qe "[[:space:]]10\.0\."; then
403 | echo "10.0"
404 | elif echo "$version_string" | grep -qe "[[:space:]]10\.1\."; then
405 | echo "10.1"
406 | elif echo "$version_string" | grep -qe "[[:space:]]10\.2\."; then
407 | echo "10.2"
408 | elif echo "$version_string" | grep -qe "[[:space:]]10\.3\."; then
409 | echo "10.3"
410 | elif echo "$version_string" | grep -qe "[[:space:]]10\.4\."; then
411 | echo "10.4"
412 | elif echo "$version_string" | grep -qe "[[:space:]]10\.5\."; then
413 | echo "10.5"
414 | elif echo "$version_string" | grep -qe "[[:space:]]10\.6\."; then
415 | echo "10.6"
416 | elif echo "$version_string" | grep -qe "[[:space:]]10\.11\."; then
417 | echo "10.11"
418 | else
419 | echo "$version_string"
420 | return 1
421 | fi
422 | return 0
423 | }
424 |
425 |
426 | # Looks for a version of OpenSSL 1.1.1
427 | # This could be openssl, openssl11, or the proxysql-admin-openssl binary.
428 | #
429 | # Globals:
430 | # REQUIRED_OPENSSL_VERSION
431 | # PROXYSQL_ADMIN_OPENSSL_NAME
432 | #
433 | # Arguments:
434 | # Parameter 1: the lineno where this function was called
435 | #
436 | # Returns 0 if a binary was found (with version 1.1.1+)
437 | # and writes the path to the binary to stdout
438 | # Returns 1 otherwise (and prints out its own error message)
439 | #
440 | function find_openssl_binary()
441 | {
442 | local lineno=$1
443 | local path_to_openssl
444 | local openssl_executable=""
445 | local value
446 | local openssl_version
447 |
448 | # Check for the proper version of the executable
449 | path_to_openssl=$(which openssl 2> /dev/null)
450 | if [[ $? -eq 0 && -n ${path_to_openssl} && -e ${path_to_openssl} ]]; then
451 |
452 | # We found a possible binary, check the version
453 | value=$(${path_to_openssl} version)
454 | openssl_version=$(expr match "$value" '.*[ \t]\+\([0-9]\+\.[0-9]\+\.[0-9]\+\)[^0-9].*')
455 |
456 | # Extract the version from version string
457 | if compare_versions "${openssl_version}" ">=" "$REQUIRED_OPENSSL_VERSION"; then
458 | openssl_executable=${path_to_openssl}
459 | fi
460 | fi
461 |
462 | # If we haven't found an acceptable openssl, look for openssl11
463 | if [[ -z $openssl_executable ]]; then
464 | # Check for openssl 1.1 executable (if installed alongside 1.0)
465 | openssl_executable=$(which openssl11 2> /dev/null)
466 | fi
467 |
468 | # If we haven't found openssl/openssl11 look for our own binary
469 | if [[ -z $openssl_executable ]]; then
470 | openssl_executable=$(which "$(dirname $0)/${PROXYSQL_ADMIN_OPENSSL_NAME}" 2> /dev/null)
471 | fi
472 |
473 | if [[ -z $openssl_executable ]]; then
474 | error "$lineno" "Could not find a v${REQUIRED_OPENSSL_VERSION}+ OpenSSL executable in the path." \
475 | "\n-- Please check that OpenSSL v${REQUIRED_OPENSSL_VERSION} or greater is installed and in the path."
476 | return 1
477 | fi
478 |
479 | # Verify the openssl versions
480 | value=$(${openssl_executable} version)
481 |
482 | # Extract the version from version string
483 | openssl_version=$(expr match "$value" '.*[ \t]\+\([0-9]\+\.[0-9]\+\.[0-9]\+\)[^0-9].*')
484 |
485 | if compare_versions "$openssl_version" "<" "$REQUIRED_OPENSSL_VERSION"; then
486 | error "$lineno" "Could not find OpenSSL with the required version. required:${REQUIRED_OPENSSL_VERSION} found:${openssl_version}" \
487 | "\n-- Please check that OpenSSL v${REQUIRED_OPENSSL_VERSION} or greater is installed and in the path."
488 | return 1
489 | fi
490 |
491 | debug "$LINENO" "Found openssl executable:${openssl_executable} ${openssl_version}"
492 |
493 | printf "%s" "${openssl_executable}"
494 | return 0
495 | }
496 |
497 | # Retrieves/unencrypts the login information from the login-file
498 | #
499 | # Globals:
500 | # REQUIRED_OPENSSL_VERSION
501 | # PROXYSQL_ADMIN_OPENSSL_NAME
502 | #
503 | # Arguments:
504 | # Parameter 1 : the path to the login-file
505 | # Parameter 2 : the key for the login-file
506 | #
507 | # Outputs:
508 | # Echoes the data (unencrypted) from the file
509 | #
510 | # Returns:
511 | # 1 (failure) if the openssl command failed
512 | # 0 (success) the openssl command succeeded and the contents of
513 | # the file is sent to output
514 | #
515 | function get_login_file_data()
516 | {
517 | local file_path="$1"
518 | local file_key="$2"
519 | local reval=""
520 | local encrypted_data=""
521 | local file_version file_iterations file_method file_data
522 | local value
523 | local openssl_executable=""
524 |
525 | if [[ -z $file_path || -z $file_key ]]; then
526 | error "$LINENO" "Missing file location(--login-file) or file key(--login-password or --login-password-file)"
527 | return 1
528 | fi
529 |
530 | # Check for the proper version of the executable
531 | openssl_executable=$(find_openssl_binary "$LINENO")
532 | if [[ $? -ne 0 ]]; then
533 | return 1
534 | fi
535 |
536 | if [[ ! -r $file_path ]]; then
537 | error "$LINENO" "Could not read from the login-file: $file_path"
538 | return 1
539 | fi
540 |
541 | debug "$LINENO" "Found openssl executable: $openssl_executable"
542 | debug "$LINENO" "Using the encrypted login-file:$file_path for credentials"
543 |
544 | # Get the file contents
545 | file_data=$(cat "$file_path")
546 |
547 | # Extract file parameters
548 | file_version=$(extract_value "$file_data" "version")
549 | if [[ -z $file_version ]]; then
550 | error "$LINENO" "Could not find the version information in the file: $file_path"
551 | return 1
552 | fi
553 | if [[ $file_version != "1" ]]; then
554 | error "$LINENO" "Unsupported login-file version: $file_version"
555 | return 1
556 | fi
557 |
558 | file_method=$(extract_value "$file_data" "encrypt_method")
559 | if [[ -z $file_method ]]; then
560 | error "$LINENO" "Could not find the encryption method in the file: $file_path"
561 | return 1
562 | fi
563 | if [[ $file_method != "openssl-pbkdf2-aes-256-cbc" ]]; then
564 | error "$LINENO" "Unsupported encryption method: $file_method"
565 | return 1
566 | fi
567 |
568 | file_iterations=$(extract_value "$file_data" "iterations")
569 | encrypted_data=$(extract_value "$file_data" "encrypted_data")
570 | if [[ -z $file_iterations || -z $encrypted_data ]]; then
571 | error "$LINENO" "Could not find the iteration count in the file: $file_path"
572 | return 1
573 | fi
574 |
575 | # Decrypt the data
576 | reval=$(${openssl_executable} enc -d -aes-256-cbc -pbkdf2 -iter "$file_iterations" -salt \
577 | -in <(printf "%s" "$encrypted_data") -A -base64 -pass file:<(printf "%s" "$file_key") 2>/dev/null)
578 | if [[ $? -ne 0 ]]; then
579 | error "$LINENO" "Decryption of data in login-file failed: $file_path"
580 | return 1
581 | fi
582 | printf "%s" "${reval}"
583 | }
584 |
585 |
586 | # Extracts the value from a "name=value" line
587 | #
588 | # Globals:
589 | # None
590 | #
591 | # Arguments:
592 | # Parameter 1 : the data (captured from the login file)
593 | # Parameter 2 : the name of the variable to be extracted
594 | #
595 | # Output:
596 | # Echoes the value portion
597 | #
598 | # Returns:
599 | # 1 (failure) if there is no line using the name
600 | # 0 (success) if the name exists in the file
601 | #
602 | function extract_value()
603 | {
604 | local data=$1
605 | local name=$2
606 | local reval=""
607 | local processed_data
608 |
609 | # normalize the variable name by replacing all '_' with '-'
610 | name=${name//_/-}
611 |
612 | # This will normalize the variable name side of the strings
613 | processed_data=$(printf "%s" "$data" | awk -F= '{st=index($0,"="); cur=$0; if ($1 ~ /_/) { gsub(/_/,"-",$1);} if (st != 0) { print $1"="substr(cur,st+1) } else { print cur }}')
614 |
615 | # Check to see if the variable name is used in the login-file data
616 | printf "%s" "$processed_data" | grep -q "^[ \t]*$name="
617 | if [[ $? -ne 0 ]]; then
618 | return 1
619 | fi
620 |
621 | # Get the named variable from the login-file data
622 | reval=$(printf "%s" "$processed_data" | grep -- "^[ \t]*$name=" | cut -d= -f2- | tail -1)
623 |
624 | printf "%s" "${reval}"
625 | return 0
626 | }
627 |
628 |
629 | # Loads the credentials from the login-file
630 | # This will also verify the OpenSSL version and set the path to the executable.
631 | #
632 | # Globals:
633 | # PROXYSQL_USERNAME (sets the value)
634 | # PROXYSQL_PASSWORD (sets the value)
635 | # PROXYSQL_HOSTNAME (sets the value)
636 | # PROXYSQL_PORT (sets the value)
637 | # CLUSTER_USERNAME (sets the value)
638 | # CLUSTER_PASSWORD (sets the value)
639 | # CLUSTER_HOSTNAME (sets the value)
640 | # CLUSTER_PORT (sets the value)
641 | # MONITOR_USERNAME (sets the value)
642 | # MONITOR_PASSWORD (sets the value)
643 | # CLUSTER_APP_USERNAME (sets the value)
644 | # CLUSTER_APP_PASSWORD (sets the value)
645 | #
646 | # Parameters:
647 | # Argument 1 : lineno this function was called from
648 | # Argument 2 : the path to the login-file
649 | # Argument 3 : the key for the login file
650 | #
651 | function load_login_file()
652 | {
653 | local lineno="$1"
654 | local login_file_path="$2"
655 | local login_key="$3"
656 | local data value
657 |
658 | data=$(get_login_file_data "${login_file_path}" "${login_key}")
659 | if [[ $? -ne 0 ]]; then
660 | return 1
661 | fi
662 |
663 | value=$(extract_value "$data" "proxysql.user")
664 | [[ $? -eq 0 ]] && PROXYSQL_USERNAME="$value" && debug "$LINENO" "Using login-file:proxysql.user";
665 |
666 | value=$(extract_value "$data" "proxysql.password")
667 | [[ $? -eq 0 ]] && PROXYSQL_PASSWORD="$value" && debug "$LINENO" "Using login-file:proxysql.password";
668 |
669 | value=$(extract_value "$data" "proxysql.host")
670 | [[ $? -eq 0 ]] && PROXYSQL_HOSTNAME="$value" && debug "$LINENO" "Using login-file:proxysql.host";
671 |
672 | value=$(extract_value "$data" "proxysql.port")
673 | [[ $? -eq 0 ]] && PROXYSQL_PORT="$value" && debug "$LINENO" "Using login-file:proxysql.port";
674 |
675 | value=$(extract_value "$data" "cluster.user")
676 | [[ $? -eq 0 ]] && CLUSTER_USERNAME="$value" && debug "$LINENO" "Using login-file:cluster.user";
677 |
678 | value=$(extract_value "$data" "cluster.password")
679 | [[ $? -eq 0 ]] && CLUSTER_PASSWORD="$value" && debug "$LINENO" "Using login-file:cluster.password";
680 |
681 | value=$(extract_value "$data" "cluster.host")
682 | [[ $? -eq 0 ]] && CLUSTER_HOSTNAME="$value" && debug "$LINENO" "Using login-file:cluster.host";
683 |
684 | value=$(extract_value "$data" "cluster.port")
685 | [[ $? -eq 0 ]] && CLUSTER_PORT="$value" && debug "$LINENO" "Using login-file:cluster.port";
686 |
687 |
688 | value=$(extract_value "$data" "monitor.user")
689 | [[ $? -eq 0 ]] && MONITOR_USERNAME="$value" && debug "$LINENO" "Using login-file:monitor.user";
690 |
691 | value=$(extract_value "$data" "monitor.password")
692 | [[ $? -eq 0 ]] && MONITOR_PASSWORD="$value" && debug "$LINENO" "Using login-file:monitor.password";
693 |
694 |
695 | value=$(extract_value "$data" "cluster-app.user")
696 | [[ $? -eq 0 ]] && CLUSTER_APP_USERNAME="$value" && debug "$LINENO" "Using login-file:cluster-app.user";
697 |
698 | value=$(extract_value "$data" "cluster-app.password")
699 | [[ $? -eq 0 ]] && CLUSTER_APP_PASSWORD="$value" && debug "$LINENO" "Using login-file:cluster-app.password";
700 |
701 | return 0
702 | }
703 |
704 |
705 | # Writes/Encrypts the login information and writes it out to a file
706 | #
707 | # Globals:
708 | # REQUIRED_OPENSSL_VERSION
709 | # PROXYSQL_ADMIN_OPENSSL_NAME
710 | #
711 | # Arguments:
712 | # Parameter 1 : path to the file with the unencrypted data
713 | # Parameter 2 : the password
714 | # Parameter 3 : the destination file (will be overwritten)
715 | #
716 | # Outputs:
717 | # Echoes the data (unencrypted) from the file
718 | #
719 | # Returns:
720 | # 1 (failure) if the openssl command failed
721 | # 0 (success) the openssl command succeeded and the contents of
722 | # the file is sent to output
723 | #
724 | function write_login_file()
725 | {
726 | local input_file_path="$1"
727 | local file_key="$2"
728 | local output_file_path="$3"
729 | local value
730 | local openssl_executable=""
731 |
732 | local reval=""
733 | local encrypted_data=""
734 | local file_version file_iterations file_method
735 |
736 | # Verify the openssl versions
737 | openssl_executable=$(find_openssl_binary "$LINENO")
738 | if [[ $? -ne 0 ]]; then
739 | return 1
740 | fi
741 |
742 | debug "$LINENO" "Found openssl executable: $openssl_executable"
743 | debug "$LINENO" "Writing to output file: $OUTFILE"
744 |
745 | # Setup encryption parameters
746 | file_iterations=100000
747 |
748 | # Encrypt the data
749 | reval=$(${openssl_executable} enc -aes-256-cbc -pbkdf2 -iter "$file_iterations" -salt \
750 | -in <(cat ${input_file_path}) -A -base64 -pass file:<(printf "%s" "$file_key") 2>/dev/null)
751 | if [[ $? -ne 0 ]]; then
752 | error "$LINENO" "Encryption of input data failed: $input_file_path"
753 | return 1
754 | fi
755 |
756 | # Write out the file
757 | printf "# Created $(date)\n" > ${OUTFILE}
758 | printf "version=%s\n" "1" >> ${OUTFILE}
759 | printf "encrypt_method=%s\n" "openssl-pbkdf2-aes-256-cbc" >> ${OUTFILE}
760 | printf "iterations=%s\n" "${file_iterations}" >> ${OUTFILE}
761 | printf "encrypted_data=%s\n" "${reval}" >> ${OUTFILE}
762 |
763 | return 0
764 | }
765 |
--------------------------------------------------------------------------------
/proxysql-login-file:
--------------------------------------------------------------------------------
1 | #!/bin/bash -u
2 | # This script will assist with creating (encrypting) the login file
3 | # Version 2.0
4 | ###############################################################################################
5 |
6 | # This program is copyright 2016-2020 Percona LLC and/or its affiliates.
7 | #
8 | # THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
9 | # WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
10 | # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11 | #
12 | # This program is free software; you can redistribute it and/or modify it under
13 | # the terms of the GNU General Public License as published by the Free Software
14 | # Foundation, version 2 or later
15 | #
16 | # You should have received a copy of the GNU General Public License version 2
17 | # along with this program; if not, write to the Free Software Foundation, Inc.,
18 | # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19 |
20 | # shellcheck disable=SC2046,SC2181,SC1091
21 |
22 | # Include the common functions
23 | . $(dirname "${BASH_SOURCE[0]}")/proxysql-common
24 |
25 | # The file used as input (unencrypted)
26 | declare INFILE="/dev/stdin"
27 |
28 | # The destination file
29 | declare OUTFILE="/dev/stdout"
30 |
31 | # The password used to generate the key for the login-file
32 | declare LOGIN_PASSWORD=""
33 |
34 | # The file that contains the key for the login-file
35 | declare LOGIN_PASSWORD_FILE=""
36 |
37 | # What this script is trying to, either "encrypt" or "decrypt"
38 | declare OPERATION="encrypt"
39 |
40 | function usage()
41 | {
42 | local path=$0
43 | cat << EOF
44 | Usage example:
45 | $ ${path##*/} [options]
46 |
47 | This script is used to create the encrypted login-file.
48 |
49 | Options:
50 | -h,--help : Prints out this help text.
51 | -v,--version : Prints out the script name and version
52 |
53 | --in= : The source file that will be encrypted.
54 | (default: stdin)
55 | --out= : The destination file that will contain the
56 | encrypted data and metadata information.
57 | (default: stdout)
58 |
59 | --password= : The key used to decrypt the encrypted login-file.
60 | This cannot be used with --login-password-file.
61 | --password-file= : Read the key from a file using the .
62 | This cannot be used with --login-password
63 |
64 | --decrypt : Decrypts the login-file data. --in is now the
65 | path to the encrypted login-file and --out is
66 | used for the unencrypted data.
67 | EOF
68 | }
69 |
70 |
71 | #
72 | # Prints out the script version
73 | #
74 | # Globals:
75 | # PROXYSQL_ADMIN_VERSION
76 | #
77 | # Parameters:
78 | # None
79 | #
80 | function version()
81 | {
82 | local path=$0
83 | printf "%s version %s\n" "${path##*/}" "${PROXYSQL_ADMIN_VERSION}"
84 | }
85 |
86 |
87 |
88 | function parse_args()
89 | {
90 | local go_out=""
91 |
92 | # TODO: kennt, what happens if we don't have a functional getopt()?
93 | # Check if we have a functional getopt(1)
94 | if ! getopt --test; then
95 | go_out="$(getopt --options=hv --longoptions=decrypt,debug,version,in:,out:,password:,password-file:,help \
96 | --name="$(basename "$0")" -- "$@")"
97 | if [[ $? -ne 0 ]]; then
98 | # no place to send output
99 | echo "Script error: getopt() failed" >&2
100 | exit 1
101 | fi
102 | eval set -- "$go_out"
103 | fi
104 |
105 | while [[ $# -gt 0 ]];
106 | do
107 | arg="$1"
108 | case "$arg" in
109 | -- )
110 | shift
111 | break;;
112 | --in )
113 | INFILE="$2"
114 | check_permission -e "$LINENO" "$INFILE" "input login-file"
115 | check_permission -r "$LINENO" "$INFILE" "input login-file"
116 | debug "$LINENO" "--in specified, using : $INFILE"
117 | shift 2
118 | ;;
119 | --out )
120 | OUTFILE="$2"
121 | debug "$LINENO" "--out specified, using : $OUTFILE"
122 | shift 2
123 | ;;
124 | --password)
125 | if [[ -n $LOGIN_PASSWORD_FILE ]]; then
126 | error "$LINENO" "--password cannot be used with --password-file"
127 | exit 1
128 | fi
129 | LOGIN_PASSWORD="$2"
130 | shift 2
131 | ;;
132 | --password-file)
133 | if [[ -n $LOGIN_PASSWORD ]]; then
134 | error "$LINENO" "--password-file cannot be used with --password"
135 | exit 1
136 | fi
137 | LOGIN_PASSWORD_FILE="$2"
138 | shift 2
139 | ;;
140 | --decrypt )
141 | OPERATION="decrypt"
142 | shift
143 | ;;
144 | --debug )
145 | # shellcheck disable=SC2034
146 | DEBUG=1
147 | shift 1
148 | ;;
149 | -v | --version)
150 | version
151 | exit 0
152 | ;;
153 | -h | --help )
154 | usage
155 | exit 0
156 | ;;
157 | esac
158 | done
159 |
160 | # Get the password
161 | if [[ -n $LOGIN_PASSWORD_FILE ]]; then
162 | if [[ ! -r $LOGIN_PASSWORD_FILE ]]; then
163 | error "$LINENO" "Cannot read from the password file: $LOGIN_PASSWORD_FILE"
164 | exit 1
165 | fi
166 | LOGIN_PASSWORD=$(cat "$LOGIN_PASSWORD_FILE")
167 | if [[ -z $LOGIN_PASSWORD ]]; then
168 | error "$LINENO" "Did not find any data in the password file: $LOGIN_PASSWORD_FILE"
169 | exit 1
170 | fi
171 | fi
172 | if [[ -z $LOGIN_PASSWORD ]]; then
173 | read -r -s -p "Enter the password:" LOGIN_PASSWORD
174 | echo
175 | fi
176 | }
177 |
178 |
179 | function main()
180 | {
181 | local data=""
182 | if [[ ${OPERATION} == "decrypt" ]]; then
183 | data=$(get_login_file_data "${INFILE}" "${LOGIN_PASSWORD}")
184 | if [[ $? -ne 0 ]]; then
185 | exit 1
186 | fi
187 | echo -e "$data" > "${OUTFILE}"
188 | else
189 | write_login_file "${INFILE}" "${LOGIN_PASSWORD}" "$OUTFILE"
190 | if [[ $? -ne 0 ]]; then
191 | exit 1
192 | fi
193 | fi
194 | }
195 |
196 |
197 | #
198 | # Execute the script
199 | #
200 | parse_args "$@"
201 | main
202 |
--------------------------------------------------------------------------------
/proxysql-logrotate:
--------------------------------------------------------------------------------
1 |
2 | /var/lib/proxysql/*.log {
3 | missingok
4 | daily
5 | notifempty
6 | compress
7 | create 0600 proxysql proxysql
8 | rotate 15
9 | postrotate
10 | . /etc/proxysql-admin.cnf
11 | /usr/bin/printf "%s\n" "[client]" "user=${PROXYSQL_USERNAME}" "password=${PROXYSQL_PASSWORD}" "host=${PROXYSQL_HOSTNAME}" "port=${PROXYSQL_PORT}" | /usr/bin/mysql --defaults-file=/dev/stdin --protocol=tcp -Nse "PROXYSQL FLUSH LOGS"
12 | endscript
13 | }
14 |
--------------------------------------------------------------------------------
/proxysql-status:
--------------------------------------------------------------------------------
1 | #!/bin/bash -u
2 | # This script will assist with configuring ProxySQL
3 | # by querying the ProxySQL tables
4 | # Version 2.0
5 | ###############################################################################################
6 |
7 | # This program is copyright 2016-2020 Percona LLC and/or its affiliates.
8 | #
9 | # THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
10 | # WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
11 | # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12 | #
13 | # This program is free software; you can redistribute it and/or modify it under
14 | # the terms of the GNU General Public License as published by the Free Software
15 | # Foundation, version 2 or later
16 | #
17 | # You should have received a copy of the GNU General Public License version 2
18 | # along with this program; if not, write to the Free Software Foundation, Inc.,
19 | # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20 |
21 | # shellcheck disable=SC2046,SC2181,SC1091
22 |
23 | # Include the common functions
24 | . $(dirname "${BASH_SOURCE[0]}")/proxysql-common
25 |
26 | # Global variables
27 | declare USER=""
28 | declare PASSWORD=""
29 | declare HOST=""
30 | declare PORT=""
31 | declare RUNTIME_OPTION=""
32 | declare DUMP_ALL=1
33 | declare DUMP_MAIN=0
34 | declare DUMP_STATS=0
35 | declare DUMP_MONITOR=0
36 | declare DUMP_FILES=0
37 | declare TABLE_FILTER=""
38 | declare DUMP_STATS_RESET_TABLE=0
39 |
40 | # The login-file is the path to an encrypted file that
41 | # contains the credentials for proxysql, PXC cluster,
42 | # monitor, and cluster-app logins.
43 | declare LOGIN_FILE=""
44 | declare LOGIN_PASSWORD=""
45 | declare LOGIN_PASSWORD_FILE=""
46 |
47 | # Set this to 1 if the default user credentials from my.cnf
48 | # are being used, set to 0 if the default my.cnf user credentials
49 | # are not being used (default)
50 | declare CREDENTIALS_FROM_CLIENT_CONFIG=0
51 |
52 | #
53 | # If set to 1, then calls to MySQL/ProxySQL via the MySQL client
54 | # will have credentials passed via stdin rather than using bash
55 | # process substitution.
56 | #
57 | declare USE_STDIN_FOR_CREDENTIALS=0
58 |
59 |
60 | function usage() {
61 | local path=$0
62 | cat << EOF
63 | Usage example:
64 | $ ${path##*/} [options] [ ]
65 |
66 | Options:
67 | --files : display contents of proxysql-admin related files
68 | --main : display main tables (both on-disk and runtime)
69 | --monitor : display monitor tables
70 | --runtime : display runtime-related data
71 | (implies --main)
72 | --stats : display stats tables
73 | --table= : display only tables that contain the table name
74 | (note: this is a case-sensitive match)
75 | --with-stats-reset : display _reset tables, by default _reset tables
76 | will not be queried.
77 |
78 | --login-file=
79 | : Read login credentials from an encrypted file.
80 | If the --login-password or --login-password-file
81 | options are not specified, then the user
82 | will be prompted for the password.
83 | (command line options override any login file values)
84 | --login-password=
85 | : The key used to decrypt the encrypted login-file.
86 | This cannot be used with --login-password-file.
87 | --login-password-file=
88 | : Read the key from a file using the .
89 | This cannot be used with --login-password
90 | --use-stdin-for-credentials
91 | : If set, then the MySQL client will use stdin to send
92 | credentials to the client (instead of process
93 | substitution).
94 | (default: process substitution is used)
95 |
96 | The default is to display all tables and files.
97 |
98 | If no credentials are specified (on the command line or via a login-file) then:
99 | 1. The default MySQL client credentials are used (usually found
100 | in ~/.my.cnf), if they connect to a ProxySQL instance).
101 | 2. If the default MySQL client credentials do not exist, or do not connect
102 | to a ProxySQL instance, then the credentials in /etc/proxysql-admin.cnf
103 | are used.
104 |
105 | EOF
106 | }
107 |
108 |
109 | #
110 | # Prints out the script version
111 | #
112 | # Globals:
113 | # PROXYSQL_ADMIN_VERSION
114 | #
115 | # Parameters:
116 | # None
117 | #
118 | function version()
119 | {
120 | local path=$0
121 | printf "%s version %s\n" "${path##*/}" "${PROXYSQL_ADMIN_VERSION}"
122 | }
123 |
124 |
125 | #
126 | # Executes an SQL query
127 | #
128 | # Globals:
129 | # USER
130 | # PASSWORD
131 | # HOST
132 | # PORT
133 | # LOGIN_PATH
134 | #
135 | # Arguments:
136 | # 1: arguments to be passed to mysql
137 | # 2: the query
138 | #
139 | function mysql_exec() {
140 | local args=$1
141 | local query=$2
142 | local retvalue
143 | local retoutput
144 | local defaults=""
145 | local default_auth=""
146 |
147 | # shellcheck disable=SC2086
148 | if [[ $CREDENTIALS_FROM_CLIENT_CONFIG -eq 0 ]]; then
149 | defaults=$(printf '[client]\nuser=%s\npassword="%s"\nhost=%s\nport=%s\n%s' \
150 | "${USER}" \
151 | "${PASSWORD}" \
152 | "${HOST}" \
153 | "${PORT}" \
154 | "${default_auth}"
155 | )
156 |
157 | if [[ $USE_STDIN_FOR_CREDENTIALS -eq 1 ]]; then
158 | retoutput=$(printf "%s" "${defaults}" | mysql --defaults-file=/dev/stdin --protocol=tcp --unbuffered --batch --silent ${args} -e "$query")
159 | retvalue=$?
160 | else
161 | retoutput=$(mysql --defaults-file=<(echo "${defaults}") --protocol=tcp --unbuffered --batch --silent ${args} -e "$query")
162 | retvalue=$?
163 | fi
164 | else
165 | retoutput=$(mysql ${args} -e "${query}")
166 | retvalue=$?
167 | fi
168 |
169 | if [[ -n $retoutput ]]; then
170 | printf "%s\n" "${retoutput}"
171 | fi
172 | return $retvalue
173 | }
174 |
175 |
176 | function parse_args() {
177 | local go_out=""
178 |
179 | # TODO: kennt, what happens if we don't have a functional getopt()?
180 | # Check if we have a functional getopt(1)
181 | if ! getopt --test; then
182 | go_out="$(getopt --options=hv --longoptions=runtime,main,stats,monitor,files,table:,with-stats-reset,login-file:,login-password:,login-password-file:,use-stdin-for-credentials,version,help \
183 | --name="$(basename "$0")" -- "$@")"
184 | check_cmd $? "$LINENO" "Script error: getopt() failed with arguments: $*"
185 | eval set -- "$go_out"
186 | fi
187 |
188 | while [[ $# -gt 0 ]];
189 | do
190 | arg="$1"
191 | case "$arg" in
192 | -- )
193 | shift
194 | break;;
195 | --runtime )
196 | shift
197 | RUNTIME_OPTION=" LIKE 'runtime_%'"
198 | DUMP_ALL=0
199 | DUMP_MAIN=1
200 | ;;
201 | --main )
202 | shift
203 | DUMP_ALL=0
204 | DUMP_MAIN=1
205 | ;;
206 | --stats )
207 | shift
208 | DUMP_ALL=0
209 | DUMP_STATS=1
210 | ;;
211 | --monitor )
212 | shift
213 | DUMP_ALL=0
214 | DUMP_MONITOR=1
215 | ;;
216 | --files )
217 | shift
218 | DUMP_ALL=0
219 | DUMP_FILES=1
220 | ;;
221 | --table )
222 | TABLE_FILTER=$2
223 | shift 2
224 | ;;
225 | --with-stats-reset )
226 | shift
227 | DUMP_STATS_RESET_TABLE=1
228 | ;;
229 | --login-file)
230 | LOGIN_FILE="$2"
231 | check_permission -e "$LINENO" "$LOGIN_FILE" "login-file"
232 | check_permission -r "$LINENO" "$LOGIN_FILE" "login-file"
233 | debug "$LINENO" "--login-file specified, using : $LOGIN_FILE"
234 | shift 2
235 | ;;
236 | --login-password)
237 | if [[ -n $LOGIN_PASSWORD_FILE ]]; then
238 | error "$LINENO" "--login-password cannot be used with --login-password-file"
239 | exit 1
240 | fi
241 | LOGIN_PASSWORD="$2"
242 | shift 2
243 | ;;
244 | --login-password-file)
245 | if [[ -n $LOGIN_PASSWORD ]]; then
246 | error "$LINENO" "--login-password-file cannot be used with --login-password"
247 | exit 1
248 | fi
249 | LOGIN_PASSWORD_FILE="$2"
250 | shift 2
251 | ;;
252 | --use-stdin-for-credentials )
253 | USE_STDIN_FOR_CREDENTIALS=1
254 | shift
255 | ;;
256 | -v | --version )
257 | version
258 | exit 0
259 | ;;
260 | -h | --help )
261 | usage
262 | exit 0
263 | ;;
264 | esac
265 | done
266 |
267 | if [[ $# -eq 0 && -z $LOGIN_FILE ]]; then
268 | # If no credentials have been provided, try the default
269 | # mysql client credentials
270 |
271 | mysql -e "SHOW tables" 2>/dev/null | grep -q "runtime_proxysql_servers"
272 | if [[ $? -eq 0 ]]; then
273 | echo -e "Connecting to ProxySQL with the default MySQL client credentials"
274 | echo -e "Usually found in ~/.my.cnf"
275 | CREDENTIALS_FROM_CLIENT_CONFIG=1
276 | fi
277 | fi
278 |
279 | if [[ $CREDENTIALS_FROM_CLIENT_CONFIG -eq 0 ]]; then
280 |
281 | # Load the data if the login-file has been set
282 | # Run this before the command-line parsing, so that the command-line
283 | # options can override the login path settings
284 | if [[ -n $LOGIN_FILE ]]; then
285 |
286 | # Check for key
287 | if [[ -n $LOGIN_PASSWORD_FILE ]]; then
288 | #if [[ ! -e $LOGIN_PASSWORD_FILE ]]; then
289 | # error "$LINENO" "Cannot read from the login-password file: $LOGIN_PASSWORD_FILE"
290 | # exit 1
291 | #fi
292 | LOGIN_PASSWORD=$(cat "$LOGIN_PASSWORD_FILE")
293 | if [[ -z $LOGIN_PASSWORD ]]; then
294 | error "$LINENO" "Did not find any data in the login-password file: $LOGIN_PASSWORD_FILE"
295 | exit 1
296 | fi
297 | fi
298 | if [[ -z $LOGIN_PASSWORD ]]; then
299 | read -r -s -p "Enter the login-file password:" LOGIN_PASSWORD
300 | echo
301 | fi
302 |
303 | # Extract the information
304 | load_login_file "$LINENO" "$LOGIN_FILE" "$LOGIN_PASSWORD"
305 | if [[ $? -ne 0 ]]; then
306 | error "$LINENO" "Cannot read the credentials from the login-file"
307 | exit 1
308 | fi
309 |
310 | [[ -n $PROXYSQL_USERNAME ]] && USER=$PROXYSQL_USERNAME;
311 | [[ -n $PROXYSQL_PASSWORD ]] && PASSWORD=$PROXYSQL_PASSWORD;
312 | [[ -n $PROXYSQL_HOSTNAME ]] && HOST=$PROXYSQL_HOSTNAME;
313 | [[ -n $PROXYSQL_PORT ]] && PORT=$PROXYSQL_PORT;
314 |
315 | elif [[ $# -eq 0 ]]; then
316 | # When no arguments are passed try to read from /etc/proxysql-admin.cnf
317 | if [[ ! -r /etc/proxysql-admin.cnf ]]; then
318 | error $LINENO "Cannot find /etc/proxysql-admin.cnf to read the credentials." \
319 | "\nYou can either consider creating the cnf file or pass the credentials through command-line in the format "
320 | exit 1
321 | else
322 | source /etc/proxysql-admin.cnf
323 | USER=$PROXYSQL_USERNAME
324 | PASSWORD=$PROXYSQL_PASSWORD
325 | HOST=$PROXYSQL_HOSTNAME
326 | PORT=$PROXYSQL_PORT
327 | fi
328 |
329 | elif [[ $# -ne 4 ]]; then
330 | error "$LINENO" "Incorrect usage: Please use the format "
331 | usage
332 | exit 1
333 | else
334 | [[ -n ${1+} ]] && USER=$1
335 | [[ -n ${2+} ]] && PASSWORD=$2
336 | [[ -n ${3+} ]] && HOST=$3
337 | [[ -n ${4+} ]] && PORT=$4
338 | fi
339 |
340 |
341 | if [[ -z $USER || -z $PASSWORD || -z $HOST || -z $PORT ]]; then
342 |
343 | error "$LINENO" "One of the user, password, host, or port parameterd is missing."
344 | exit 1
345 | fi
346 | fi
347 |
348 | }
349 |
350 |
351 | parse_args "$@"
352 |
353 | # Run a test to see if we can connect
354 | TABLES=$(mysql_exec -BN "SELECT 1" >/dev/null)
355 | if [[ $? -ne 0 ]]; then
356 | error "$LINENO" "Cannot connect to the server at $HOST:$PORT"
357 | echo -e "Please check that the address is correct and the server is online"
358 | exit 1
359 | fi
360 |
361 | if [[ $DUMP_ALL -eq 1 || $DUMP_MAIN -eq 1 ]]; then
362 | echo "............ DUMPING MAIN DATABASE ............"
363 | TABLES=$(mysql_exec -BN "SHOW TABLES $RUNTIME_OPTION" 2>/dev/null)
364 | for table in $TABLES
365 | do
366 | if [[ -n $TABLE_FILTER && $table != *${TABLE_FILTER}* ]]; then
367 | continue
368 | fi
369 | echo "***** DUMPING $table *****"
370 | mysql_exec -t "SELECT * FROM $table"
371 | echo "***** END OF DUMPING $table *****"
372 | echo ""
373 | done
374 | echo "............ END OF DUMPING MAIN DATABASE ............"
375 | echo ""
376 | fi
377 |
378 | if [[ $DUMP_ALL -eq 1 || $DUMP_STATS -eq 1 ]]; then
379 | echo "............ DUMPING STATS DATABASE ............"
380 | TABLES=$(mysql_exec -BN "SHOW TABLES FROM stats" 2> /dev/null)
381 | for table in $TABLES
382 | do
383 | if [[ -n $TABLE_FILTER && $table != *${TABLE_FILTER}* ]]; then
384 | continue
385 | fi
386 | # Dump _reset tables only if we specify option --with-stats-reset
387 | if [[ $DUMP_STATS_RESET_TABLE -eq 0 ]]; then
388 | if echo "$table" | grep -q "_reset$"; then
389 | continue
390 | fi
391 | fi
392 | echo "***** DUMPING stats.$table *****"
393 | mysql_exec "-t --database=stats" "SELECT * FROM $table" 2> /dev/null
394 | echo "***** END OF DUMPING stats.$table *****"
395 | echo ""
396 | done
397 | echo "............ END OF DUMPING STATS DATABASE ............"
398 | echo ""
399 | fi
400 |
401 | if [[ $DUMP_ALL -eq 1 || $DUMP_MONITOR -eq 1 ]]; then
402 | echo "............ DUMPING MONITOR DATABASE ............"
403 | TABLES=$(mysql_exec -BN "SHOW TABLES FROM monitor" 2> /dev/null)
404 | for table in $TABLES
405 | do
406 | if [[ -n $TABLE_FILTER && $table != *${TABLE_FILTER}* ]]; then
407 | continue
408 | fi
409 | echo "***** DUMPING monitor.$table *****"
410 | mysql_exec "-t --database=monitor" "SELECT * FROM $table" 2> /dev/null
411 | echo "***** END OF DUMPING monitor.$table *****"
412 | echo ""
413 | done
414 | echo "............ END OF DUMPING MONITOR DATABASE ............"
415 | echo ""
416 | fi
417 |
418 | if [[ $DUMP_ALL -eq 1 || $DUMP_FILES -eq 1 ]]; then
419 | if [[ -z $TABLE_FILTER ]]; then
420 | if [[ -r "/var/lib/proxysql/host_priority.conf" ]]; then
421 | echo "............ DUMPING HOST PRIORITY FILE ............"
422 | cat /var/lib/proxysql/host_priority.conf 2>&1
423 | echo "............ END OF DUMPING HOST PRIORITY FILE ............"
424 | else
425 | echo "/var/lib/proxysql/host_priority.conf not found or not readble by you!"
426 | fi
427 | echo ""
428 | if [[ -r "/etc/proxysql-admin.cnf" ]]; then
429 | echo "............ DUMPING PROXYSQL ADMIN CNF FILE ............"
430 | cat /etc/proxysql-admin.cnf 2>&1
431 | echo "............ END OF DUMPING PROXYSQL ADMIN CNF FILE ............"
432 | else
433 | echo "/etc/proxysql-admin.cnf not found or not readble by you!"
434 | fi
435 | echo ""
436 | if [[ -r "/etc/config.toml" ]]; then
437 | echo "............ DUMPING PERCONA SCHEDULER ADMIN CNF FILE ............"
438 | cat /etc/config.toml 2>&1
439 | echo "............ END OF DUMPING PERCONA SCHEDULER ADMIN CNF FILE ............"
440 | else
441 | echo "/etc/config.toml not found or not readble by you!"
442 | fi
443 | echo ""
444 | fi
445 | fi
446 |
--------------------------------------------------------------------------------
/tests/bad-login-file.clear.cnf:
--------------------------------------------------------------------------------
1 |
2 | # --------------------------------
3 | # proxysql admin interface credentials.
4 | proxysql.user=admin
5 | proxysql.password=xxxxx
6 | proxysql.host=localhost
7 | proxysql.port=6032
8 |
9 | # --------------------------------
10 | # PXC admin credentials for connecting to pxc-cluster-node.
11 | cluster.user=admin
12 | cluster.password=xxxxx
13 | cluster.host=localhost
14 | cluster.port=4110
15 |
16 | # --------------------------------
17 | # proxysql monitoring user. proxysql admin script will create
18 | # this user in pxc to monitor pxc-nodes.
19 | monitor.user=monitor
20 | monitor.password=xxxx
21 |
22 | # --------------------------------
23 | # Application user to connect to pxc-node through proxysql
24 | cluster-app.user=cluster_one
25 | cluster-app.password=xxxx
26 |
27 |
28 |
--------------------------------------------------------------------------------
/tests/bad-login-file.cnf:
--------------------------------------------------------------------------------
1 | # Created Wed Sep 30 06:32:46 PDT 2020
2 | version=1
3 | encrypt_method=openssl-pbkdf2-aes-256-cbc
4 | iterations=100000
5 | encrypted_data=U2FsdGVkX19YHF55Dcsz4mgVmN49w073+u+sHJbO6w/5bMyZIlrhmUd3/OR51HrVueF2WTdBSR7znTiYpe4Wr9mW5FlXPZzgNk36f5ULKM/dvT9LqpHNlmiFuQqMOjRMXTSwzOxAiobXEn7WewNwXSvrir9H/qnBO5fQjCwowPnvlOYbaAlPXKQU2zsn++z6+Po820uJTqyvMXBzCeBFhcatTsfdNBEMMj4hxtzolu5/pttZz2dqC7XO93ZL0hK+ImldIMCNDkzuS8QLFhXt+Jw47G+WOUz3UFkMx3OHwAYcgFrjaB6YJhMm62skugCwVePXf22DMD9bsrChJmLwZdQsNUnLi5H0u1y4RwO4Mk8pakjwqH1lxGsWosQfLHrGOlHzi4Ta3wVQSnZP9nUgriDJrl1JsYbocBQ23FztFzH8NVux0vs+3BBYMrPQC8ebfcGFESkNUkGu+T0PG5UNhM1wRFNoM43zgCBKizkhicnTZ30LeOV2oR8jb0OmhYwiJd+CKQPPIUjqqCiXA9Pb9b980+O0TO+EkTNTb8ZAEqnH3ZAQczYUPhhfP6x+ar/1POOzda6UIf0h8q0p6dG5RpuVV+3EP+ibI3K88wnkIm8XKRnRoQetFniDNpLfHyd04fao6MIusOTNg5AEGpd26rmAwYvrHii9WZuOe71K7NK/tXq4+QrDw8TRuCrxPx3oC+1Hc5fxM+0ObcLgZ0stAFtNlsFFfOmQwmNkOdLOdlN0wnMpcuRTV5SKwaPxG99846kd97om5jJkyu8z6OfPvza/aCvqeMYyeXbTschMVLRsmggQ0xsKAo9JwNXu6aZnWvDXFn1gqPtL/Wo9Zve9g/N/t5oLQvhMgyZI3cE+vvfiqI7jto301Vf6lc05KdAGDM8Bo7+1IdE5kI8qGNnzNQrklIZoG8q8WdeUAaqMPhw=
6 |
--------------------------------------------------------------------------------
/tests/bad-login-file2.clear.cnf:
--------------------------------------------------------------------------------
1 |
2 | # --------------------------------
3 | # proxysql admin interface credentials.
4 | proxysql.user=admin
5 | proxysql.password=xxxxx
6 | proxysql.host=localhost
7 | proxysql.port=6032
8 |
9 | # --------------------------------
10 | # PXC admin credentials for connecting to pxc-cluster-node.
11 | cluster.user=admin
12 | cluster.password=xxxxx
13 | cluster.host=localhost
14 | cluster.port=4210
15 |
16 | # --------------------------------
17 | # proxysql monitoring user. proxysql admin script will create
18 | # this user in pxc to monitor pxc-nodes.
19 | monitor.user=monitor
20 | monitor.password=xxxx
21 |
22 | # --------------------------------
23 | # Application user to connect to pxc-node through proxysql
24 | cluster-app.user=cluster_two
25 | cluster-app.password=xxxx
26 |
27 |
28 |
--------------------------------------------------------------------------------
/tests/bad-login-file2.cnf:
--------------------------------------------------------------------------------
1 | # Created Wed Sep 30 06:32:35 PDT 2020
2 | version=1
3 | encrypt_method=openssl-pbkdf2-aes-256-cbc
4 | iterations=100000
5 | encrypted_data=U2FsdGVkX19wMUVJ9D0RrDTmUAcN2BMhRYpK18CdSFDM0vsCCE+yYzuL8FBV3mHrVEMBw8fJHDLkGKmpMvHUReSo8zdU3++7IBA3vcaVPEHUkmMQs/JUeGIhROMjgcAcO3QHpelhbSD2tVn9p+fbkQyGhSQ7gNbZwutL/TLGDKZT5f/z+Vjd0nWNx5TOIzbAjOF4OjygKKQ7Na/wxl+sb+vYIj6UypaeWtJY3k1O9ODlEolc7ZiKC4lKJbsN3OqP4Ik0jjQmjkuhnwPj5jQZ3M30/WzxZMDQTjVfMsSM9IgEeyEOBFATIETbvrGKu712PGRFMRCwnRzbbhZsfQAcXm2VT6lRIUFvtn+VDi1umtKU4BVjJowB0rM4i1Y00JVLsaLAb+IfA6PMwSAMmcxYtaJch+9Kfw74hDx5aCefccZZg0kCRg+XAbRWB7OSPGvYvz/nOp83ti7ZDzpGvM1SSXyrEquTMD0FOw7p3BvByR7I6Qf4bVSHZuhTz931OSi6Hy16jxR81B0+nng4vb7orUWS128GNsxSugO16r//4zR7L3MCfNxpUAAP9hNK6KNh9iQNwqjWF40xblmL4DjhzQrN+Y1e4u1QMCnpdh0lmcaPU9H/D+ag8ntWDNj5oiyE0+M6zjy0X8FCnqJi/WEn3P0MBH3+2n1d5F1Ka1qB2u5YUL7Qg7ljv9J0eXY9Gmq2yhOrCBGAlcjLRduK+RmgoZf+gyIZxR1opJ4onshZ+99b5QVywYIeddiSMvknFe4CTuXEYIIVWOmet7Bhhurb2NfLUsYG105p4Fp8vqRHzZNFaveJoduF1+BL33v56hzuoZDJNJWEnfyBrZY2TzNAKXWX2jpuDq796EOFWZh57XhXT1vhlQc1QyxabQGSEDYKLP1fTX5cIT6RwmsTv/HOeo6kuEwf4ZEIvnqIVVIpv+U=
6 |
--------------------------------------------------------------------------------
/tests/disable_proxysql.bats:
--------------------------------------------------------------------------------
1 | ## proxysql-admin setup tests
2 | #
3 |
4 | #
5 | # Variable initialization
6 | #
7 | source /etc/proxysql-admin.cnf
8 | PXC_BASEDIR=$WORKDIR/pxc-bin
9 | PROXYSQL_BASEDIR=$WORKDIR/proxysql-bin
10 |
11 | # Declare some GLOBALS
12 | # These are used to return data from get_node_data()
13 | load test-common
14 |
15 | WSREP_CLUSTER_NAME=$(cluster_exec "select @@wsrep_cluster_name" 2> /dev/null)
16 |
17 | @test "run proxysql-admin -d ($WSREP_CLUSTER_NAME)" {
18 | run sudo PATH=$WORKDIR:$PATH $WORKDIR/proxysql-admin -d
19 | echo "$output" >&2
20 | [ "$status" -eq 0 ]
21 | }
22 |
23 |
24 |
--------------------------------------------------------------------------------
/tests/generic-test.bats:
--------------------------------------------------------------------------------
1 | ## Generic bats tests
2 |
3 | #
4 | # Variable initialization
5 | #
6 | source /etc/proxysql-admin.cnf
7 | PXC_BASEDIR=$WORKDIR/pxc-bin
8 | PROXYSQL_BASEDIR=$WORKDIR/proxysql-bin
9 |
10 | @test "run proxysql-admin under root privileges" {
11 | if [[ $(id -u) -ne 0 ]] ; then
12 | skip "Skipping this test, because you are NOT running under root"
13 | fi
14 | run $WORKDIR/proxysql-admin
15 | echo "$output" >&2
16 | [ "$status" -eq 1 ]
17 | [ "${lines[0]}" = "Usage: proxysql-admin [ options ]" ]
18 | }
19 |
20 | @test "run proxysql-admin without any arguments" {
21 | run sudo $WORKDIR/proxysql-admin
22 | echo "$output" >&2
23 | [ "$status" -eq 1 ]
24 | [ "${lines[0]}" = "Usage: proxysql-admin [ options ]" ]
25 | }
26 |
27 | @test "run proxysql-admin --help" {
28 | run sudo $WORKDIR/proxysql-admin --help
29 | echo "$output" >&2
30 | [ "$status" -eq 0 ]
31 | [ "${lines[0]}" = "Usage: proxysql-admin [ options ]" ]
32 | }
33 |
34 | @test "run proxysql-admin with wrong option" {
35 | run sudo $WORKDIR/proxysql-admin test
36 | echo "$output" >&2
37 | [ "$status" -eq 1 ]
38 | }
39 |
40 | @test "run proxysql-admin --config-file without parameters" {
41 | run sudo $WORKDIR/proxysql-admin --config-file
42 | echo "$output" >&2
43 | [ "$status" -eq 1 ]
44 | }
45 |
46 | @test "run proxysql-admin check default configuration file" {
47 | run ls /etc/proxysql-admin.cnf
48 | echo "$output" >&2
49 | [ "$status" -eq 0 ]
50 | [ "${lines[0]}" == "/etc/proxysql-admin.cnf" ]
51 | }
52 |
53 | @test "run proxysql-admin --proxysql-username without parameters" {
54 | run sudo $WORKDIR/proxysql-admin --proxysql-username
55 | echo "$output" >&2
56 | [ "$status" -eq 1 ]
57 | }
58 |
59 | @test "run proxysql-admin --proxysql-port without parameters" {
60 | run sudo $WORKDIR/proxysql-admin --proxysql-port
61 | echo "$output" >&2
62 | [ "$status" -eq 1 ]
63 | }
64 |
65 | @test "run proxysql-admin --proxysql-hostname without parameters" {
66 | run sudo $WORKDIR/proxysql-admin --proxysql-hostname
67 | echo "$output" >&2
68 | [ "$status" -eq 1 ]
69 | }
70 |
71 | @test "run proxysql-admin --cluster-username without parameters" {
72 | run sudo $WORKDIR/proxysql-admin --cluster-username
73 | echo "$output" >&2
74 | [ "$status" -eq 1 ]
75 | }
76 |
77 | @test "run proxysql-admin --cluster-port without parameters" {
78 | run sudo $WORKDIR/proxysql-admin --cluster-port
79 | echo "$output" >&2
80 | [ "$status" -eq 1 ]
81 | }
82 |
83 | @test "run proxysql-admin --cluster-hostname without parameters" {
84 | run sudo $WORKDIR/proxysql-admin --cluster-hostname
85 | echo "$output" >&2
86 | [ "$status" -eq 1 ]
87 | }
88 |
89 | @test "run proxysql-admin --cluster-app-username without parameters" {
90 | run sudo $WORKDIR/proxysql-admin --cluster-app-username
91 | echo "$output" >&2
92 | [ "$status" -eq 1 ]
93 | }
94 |
95 | @test "run proxysql-admin --monitor-username without parameters" {
96 | run sudo $WORKDIR/proxysql-admin --monitor-username
97 | echo "$output" >&2
98 | [ "$status" -eq 1 ]
99 | }
100 |
101 | @test "run proxysql-admin --mode without parameters" {
102 | run sudo $WORKDIR/proxysql-admin --mode
103 | echo "$output" >&2
104 | [ "$status" -eq 1 ]
105 | }
106 |
107 | @test "run proxysql-admin --mode check wrong option" {
108 | run sudo $WORKDIR/proxysql-admin --mode=foo
109 | echo "$output" >&2
110 | [ "$status" -eq 1 ]
111 | [ "${lines[0]}" == "ERROR : Invalid --mode passed: 'foo'" ]
112 | }
113 |
114 | @test "run proxysql-admin --write-node without parameters" {
115 | run sudo $WORKDIR/proxysql-admin --write-node
116 | echo "$output" >&2
117 | [ "$status" -eq 1 ]
118 | [[ "${lines[0]}" =~ .*--write-node.* ]]
119 | }
120 |
121 | @test "run proxysql-admin --write-node with missing port" {
122 | run sudo $WORKDIR/proxysql-admin --write-node=1.1.1.1,2.2.2.2:44 --disable
123 | echo "$output" >&2
124 | [ "$status" -eq 1 ]
125 | [[ "${lines[0]}" =~ ERROR.*--write-node.*expects.* ]]
126 |
127 | run sudo $WORKDIR/proxysql-admin --write-node=[1:1:1:1],[2:2:2:2]:44 --disable
128 | echo "$output" >&2
129 | [ "$status" -eq 1 ]
130 | [[ "${lines[0]}" =~ ERROR.*--write-node.*expects.* ]]
131 | }
132 |
133 | @test "run proxysql-admin --server without parameters" {
134 | run sudo $WORKDIR/proxysql-admin --server
135 | echo "$output" >&2
136 | [ "$status" -eq 1 ]
137 | [[ "${lines[0]}" =~ .*--server.* ]]
138 | }
139 |
140 | @test "run proxysql-admin --server with missing port" {
141 | run sudo $WORKDIR/proxysql-admin --server=1.1.1.1 --syncusers
142 | echo "$output" >&2
143 | [ "$status" -eq 1 ]
144 | [[ "${lines[0]}" =~ ERROR.*--server.*expected.* ]]
145 |
146 | run sudo $WORKDIR/proxysql-admin --server=[1:1:1:1] --syncusers
147 | echo "$output" >&2
148 | [ "$status" -eq 1 ]
149 | [[ "${lines[0]}" =~ ERROR.*--server.*expected.* ]]
150 | }
151 |
152 | @test "run proxysql-admin --server with unsupported commands" {
153 | run sudo $WORKDIR/proxysql-admin --server=1.1.1.1 --disable
154 | echo "$output" >&2
155 | [ "$status" -eq 1 ]
156 | [[ "${lines[0]}" =~ ERROR.*--server.*can.only.be.used.* ]]
157 |
158 | run sudo $WORKDIR/proxysql-admin --server=[1:1:1:1] --update-cluster
159 | echo "$output" >&2
160 | [ "$status" -eq 1 ]
161 | [[ "${lines[0]}" =~ ERROR.*--server.*can.only.be.used.* ]]
162 | }
163 |
164 | @test 'run proxysql-admin --max-connections with empty parameters' {
165 | run sudo $WORKDIR/proxysql-admin --max-connections
166 | echo "$output" >&2
167 | [ "$status" -eq 1 ]
168 | }
169 |
170 | @test 'run proxysql-admin --max-connections without parameters' {
171 | run sudo $WORKDIR/proxysql-admin --max-connections=
172 | echo "$output" >&2
173 | [ "$status" -eq 1 ]
174 | }
175 |
176 | @test 'run proxysql-admin --max-connections with non-number parameter' {
177 | run sudo $WORKDIR/proxysql-admin --max-connections=abc
178 | echo "$output" >&2
179 | [ "$status" -eq 1 ]
180 | }
181 |
182 | @test 'run proxysql-admin --max-connections with negative values' {
183 | run sudo $WORKDIR/proxysql-admin --max-connections=-1
184 | echo "$output" >&2
185 | [ "$status" -eq 1 ]
186 | }
187 |
188 | @test 'run proxysql-admin --login-file with nonexistent file' {
189 | run sudo $WORKDIR/proxysql-admin --login-file=dummy.file.should.not.exist.cnf
190 | echo "$output" >&2
191 | [ "$status" -eq 1 ]
192 | }
193 |
194 | @test 'run proxysql-admin --login-file with nonexistent --login-password-file' {
195 | run sudo $WORKDIR/proxysql-admin --login-file=login-file.cnf --login-password-file=dummy.file.should.not.exist.cnf
196 | echo "$output" >&2
197 | [ "$status" -eq 1 ]
198 | }
199 |
200 | @test "run proxysql-admin --version check" {
201 | admin_version=$(sudo $WORKDIR/proxysql-admin -v | grep --extended-regexp -oe '[1-9]\.[0-9]\.[0-9]+')
202 | proxysql_version=$(sudo $PROXYSQL_BASEDIR/usr/bin/proxysql --help | grep --extended-regexp -oe '[1-9]\.[0-9]\.[0-9]+')
203 | echo "proxysql_version:$proxysql_version admin_version:$admin_version" >&2
204 | [ "${proxysql_version}" = "${admin_version}" ]
205 | }
206 |
--------------------------------------------------------------------------------
/tests/login-file.clear.cnf:
--------------------------------------------------------------------------------
1 |
2 | # --------------------------------
3 | # proxysql admin interface credentials.
4 | proxysql.user=admin
5 | proxysql.password=admin
6 | proxysql.host=localhost
7 | proxysql.port=6032
8 |
9 | # --------------------------------
10 | # PXC admin credentials for connecting to pxc-cluster-node.
11 | cluster.user=admin
12 | cluster.password=admin
13 | cluster.host=localhost
14 | cluster.port=4110
15 |
16 | # --------------------------------
17 | # proxysql monitoring user. proxysql admin script will create
18 | # this user in pxc to monitor pxc-nodes.
19 | monitor.user=monitor
20 | monitor.password=monitor
21 |
22 | # --------------------------------
23 | # Application user to connect to pxc-node through proxysql
24 | cluster-app.user=cluster_one
25 | cluster-app.password=passw0rd
26 |
27 |
28 |
--------------------------------------------------------------------------------
/tests/login-file.cnf:
--------------------------------------------------------------------------------
1 | # Created Wed Sep 30 06:32:57 PDT 2020
2 | version=1
3 | encrypt_method=openssl-pbkdf2-aes-256-cbc
4 | iterations=100000
5 | encrypted_data=U2FsdGVkX19fwq5TWk7CWKQLG3I0gvlaiNhC+XvT1T/SacrRr2oeiheIjm4IkRSDPMjv4CvRz8xDa+JR1aIogH8MzbBrgIrvP5rOO3XB1sPUWeeJzIopHKhdm4ISlxwlLjyXq2V9rM7x3AryvL2sAq9bBHWhYio39/emdANiDXXOUGMWeNsNIk4yc6TRFwJEZ9IZ/vbvvK5ZhuS78f0xlz80Yg8ieegkqxWk09s8zieg/kJ14KW6Goyk9L4Fncn50lsB1Juph3DXbHFP+7N4Wn2m94NYdkRn69/r1MFMEfl1BYNCfCQe2zdUjqyY5CmSatrjRFi+uRdqY/tie3pK4yebX8yVu1gxDd4/qeik0/QL3rvGyrgT6HCpL6/s3Bc93asnaRx/dxAmMEGegm8iKWfvLEuGAn1lUZJg0Pu60QZdQBXx+EQq42qCaivQU2f0G50d4S3LjN0fYScxY8Z6PfumXV5O1xHUQIyg0uqDcnI9jh7JHVXeDE0vAAbEm2QemvTefls4bvb42VxVC4MX1FRwkm0asUEBK4KbZ2c7XcAgIszqX83XzWC+G1ezFAVyO6eDIVJLAHG3IiwzxhHwji4naAOkGvQbzSZi3VeoaLuJ8wae0RgmRKd1Xai/0pC9L34LsEJxOw3n6Y9whLjWET18wedJYee28ss/tPRqCka/KTDl43toOKLpHLGsqaapfBrN0JItXYohghDIGV28Nex6nyOR+o7XXWvH1Ex0EGjWTLJHwBu8DL4S7VI+11YzAvWyxl/cASedSepYvqQ6+x1ZcIIsfY3WAaJ6rsSRM9tSVvw8925EdE/xTAVgrjsg7DsTOmOxtSMOfUgDwKsMfQiWy/mt88aSwdSKJYiGOIAFoSmlXCvgV021T3gI+B/0TFi40M6eFPnTSnjNla0xMSrrzAplOvGp4Kap7L3LjH8=
6 |
--------------------------------------------------------------------------------
/tests/login-file2.clear.cnf:
--------------------------------------------------------------------------------
1 |
2 | # --------------------------------
3 | # proxysql admin interface credentials.
4 | proxysql.user=admin
5 | proxysql.password=admin
6 | proxysql.host=localhost
7 | proxysql.port=6032
8 |
9 | # --------------------------------
10 | # PXC admin credentials for connecting to pxc-cluster-node.
11 | cluster.user=admin
12 | cluster.password=admin
13 | cluster.host=localhost
14 | cluster.port=4210
15 |
16 | # --------------------------------
17 | # proxysql monitoring user. proxysql admin script will create
18 | # this user in pxc to monitor pxc-nodes.
19 | monitor.user=monitor
20 | monitor.password=monitor
21 |
22 | # --------------------------------
23 | # Application user to connect to pxc-node through proxysql
24 | cluster-app.user=cluster_two
25 | cluster-app.password=passw0rd
26 |
27 |
28 |
--------------------------------------------------------------------------------
/tests/login-file2.cnf:
--------------------------------------------------------------------------------
1 | # Created Wed Sep 30 06:33:08 PDT 2020
2 | version=1
3 | encrypt_method=openssl-pbkdf2-aes-256-cbc
4 | iterations=100000
5 | encrypted_data=U2FsdGVkX19EwylQLNtVvXMggcujuiLnETNscBx7OB9k0l/YUQSOIWoAaP2Bg29E6abK6FB0fb2jYD8RLrxkGriqEHtcoA+sfaPPpVbuiJ8m+m7S9L0on/UDBLbJVxhkg7AmMQ66h+Cg4oIhSyUD7k076T2/HHMRDHvjOKvwuNmgQpukIYhYlpzhNVZ1woTmdPzfrwB/SYu5bLKEMctafG4N96jmY34WFyVU0t/ZINgbxsaRFDZdz8aqfShSE/CHkV/+2biDm1GTikaC+s/FQmu4uW/ERRuXTcPApNAGsmlOWnkXJUkhAaBrU0pS8G13HIVXOJCkAsD58O5Z8R8A3K9wBwGzNZPq7BoVlF22ehLJgkHUmAwr1Oj1k2HHfFvc1wfJvzwXBPmaBMy2IIOU/nklgRUKwNt/b0UZPAKzEDJbOxa0rxbqgoRPiH42F+mv9sBGGbxHpM6GOckz/TUc4i1sY2LR+R7IHHMCoSMlJMMmVIHsh+Ke4zJWMugkfoQG1odZ/AwJISZt+uLQUGt83byNpMQGFVgSG3L9f1v53OH5Q2O+U74bJg/aco55+eyyR57udDD5kI8ozLBH9XSJISLSYJ10NwLRlqZG8ooHYys53B5Ld1rjKMbacairCDrD2P0DKXHHXV9St/8QnukV9uRKc3/1Bm1BMRcUzG51tZie9a5yvEjgD59LDr7yYnuaC070k6AtWt2rCXxRjpCl5YifWb6Tfm5MJ/myiLttodLMFJiYofMthd51FfR0dTEs+bOS2Ya6B3cInp8/tbzWB3ZfUHS8HC67rtnWwwIBWIQDfPGez9qBgSokdgXOx+rD98VfctL97qfYkGBNA/OGct1sJ44BH/W46SYC+bXNHtVeF0gbA4CktQS8U3uRtp80Zft5LSUTCp7Oc6D5I/9toeSm6gSNqr9zRqHkeaEB5oA=
6 |
--------------------------------------------------------------------------------
/tests/scheduler-args.bats:
--------------------------------------------------------------------------------
1 | ## Test of go-scheduler argument handling
2 |
3 | #
4 | # Variable initialization
5 | #
6 | source /etc/proxysql-admin.cnf
7 | PXC_BASEDIR=$WORKDIR/pxc-bin
8 | PROXYSQL_BASEDIR=$WORKDIR/proxysql-bin
9 |
10 | @test "run percona-scheduler-admin under root privileges" {
11 | if [[ $(id -u) -ne 0 ]] ; then
12 | skip "Skipping this test, because you are NOT running under root"
13 | fi
14 | run $WORKDIR/percona-scheduler-admin
15 | echo "$output" >&2
16 | [ "$status" -eq 1 ]
17 | [ "${lines[0]}" = "Usage: percona-scheduler-admin [ options ]" ]
18 | }
19 |
20 | @test "run percona-scheduler-admin without any arguments" {
21 | run sudo $WORKDIR/percona-scheduler-admin
22 | echo "$output" >&2
23 | [ "$status" -eq 1 ]
24 | [ "${lines[0]}" = "Usage: percona-scheduler-admin [ options ]" ]
25 | }
26 |
27 | @test "run percona-scheduler-admin --help" {
28 | run sudo $WORKDIR/percona-scheduler-admin --help
29 | echo "$output" >&2
30 | [ "$status" -eq 0 ]
31 | [ "${lines[0]}" = "Usage: percona-scheduler-admin [ options ]" ]
32 | }
33 |
34 | @test "run percona-scheduler-admin with wrong option" {
35 | run sudo $WORKDIR/percona-scheduler-admin test
36 | echo "$output" >&2
37 | [ "$status" -eq 2 ]
38 | }
39 |
40 | @test "run percona-scheduler-admin --config-file without parameters" {
41 | run sudo $WORKDIR/percona-scheduler-admin --config-file
42 | echo "$output" >&2
43 | [ "$status" -eq 1 ]
44 | }
45 |
46 | @test "run percona-scheduler-admin --config-file with incorrect filename" {
47 | run sudo $WORKDIR/percona-scheduler-admin --config-file=$SCRIPTDIR/missing_file.txt
48 | echo "$output" >&2
49 | [ "$status" -eq 2 ]
50 | }
51 |
52 | @test "run percona-scheduler-admin --proxysql-username without parameters" {
53 | run sudo $WORKDIR/percona-scheduler-admin --config-file=testsuite.toml --proxysql-username
54 | echo "$output" >&2
55 | [ "$status" -eq 1 ]
56 | }
57 |
58 | @test "run percona-scheduler-admin --proxysql-port without parameters" {
59 | run sudo $WORKDIR/percona-scheduler-admin --config-file=testsuite.toml --proxysql-port
60 | echo "$output" >&2
61 | [ "$status" -eq 1 ]
62 | }
63 |
64 | @test "run percona-scheduler-admin --proxysql-hostname without parameters" {
65 | run sudo $WORKDIR/percona-scheduler-admin --config-file=testsuite.toml --proxysql-hostname
66 | echo "$output" >&2
67 | [ "$status" -eq 1 ]
68 | }
69 |
70 | @test "run percona-scheduler-admin --cluster-username without parameters" {
71 | run sudo $WORKDIR/percona-scheduler-admin --config-file=testsuite.toml --cluster-username
72 | echo "$output" >&2
73 | [ "$status" -eq 1 ]
74 | }
75 |
76 | @test "run percona-scheduler-admin --cluster-port without parameters" {
77 | run sudo $WORKDIR/percona-scheduler-admin --config-file=testsuite.toml --cluster-port
78 | echo "$output" >&2
79 | [ "$status" -eq 1 ]
80 | }
81 |
82 | @test "run percona-scheduler-admin --cluster-hostname without parameters" {
83 | run sudo $WORKDIR/percona-scheduler-admin --config-file=testsuite.toml --cluster-hostname
84 | echo "$output" >&2
85 | [ "$status" -eq 1 ]
86 | }
87 |
88 | @test "run percona-scheduler-admin --cluster-app-username without parameters" {
89 | run sudo $WORKDIR/percona-scheduler-admin --config-file=testsuite.toml --cluster-app-username
90 | echo "$output" >&2
91 | [ "$status" -eq 1 ]
92 | }
93 |
94 | @test "run percona-scheduler-admin --monitor-username without parameters" {
95 | run sudo $WORKDIR/percona-scheduler-admin --config-file=testsuite.toml --monitor-username
96 | echo "$output" >&2
97 | [ "$status" -eq 1 ]
98 | }
99 |
100 | @test "run percona-scheduler-admin --write-node without parameters" {
101 | run sudo $WORKDIR/percona-scheduler-admin --config-file=testsuite.toml --write-node
102 | echo "$output" >&2
103 | [ "$status" -eq 1 ]
104 | [[ "${lines[0]}" =~ .*--write-node.* ]]
105 | }
106 |
107 | @test "run percona-scheduler-admin --write-node with missing port" {
108 | run sudo PATH=$PATH $WORKDIR/percona-scheduler-admin --config-file=testsuite.toml --write-node=1.1.1.1,2.2.2.2:44 --disable
109 | echo "$output" >&2
110 | [ "$status" -eq 1 ]
111 | [[ "${lines[0]}" =~ ERROR.*--write-node.*expects.* ]]
112 |
113 | run sudo PATH=$PATH $WORKDIR/percona-scheduler-admin --config-file=testsuite.toml --write-node=[1:1:1:1],[2:2:2:2]:44 --disable
114 | echo "$output" >&2
115 | [ "$status" -eq 1 ]
116 | [[ "${lines[0]}" =~ ERROR.*--write-node.*expects.* ]]
117 | }
118 |
119 | @test "run percona-scheduler-admin --version check" {
120 | admin_version=$(sudo $WORKDIR/percona-scheduler-admin -v | head -1 | grep --extended-regexp -oe '[1-9]\.[0-9]\.[0-9]+')
121 | scheduler_version=$(sudo $WORKDIR/percona-scheduler-admin -v | head -1 | grep --extended-regexp -oe '[1-9]\.[0-9]\.[0-9]+')
122 | proxysql_version=$(sudo $PROXYSQL_BASEDIR/usr/bin/proxysql --help | grep --extended-regexp -oe '[1-9]\.[0-9]\.[0-9]+')
123 | echo "proxysql_version:$proxysql_version admin_version:$admin_version scheduler_version:$scheduler_version" >&2
124 |
125 | # All the versions should be the same
126 | [ "${proxysql_version}" = "${admin_version}" ]
127 | [ "${admin_version}" = "${scheduler_version}" ]
128 | }
129 |
130 | # Mutually exclusive options
131 | @test "run percona-scheduler-admin --auto-assign-weights, write-node and --update-write-weight options" {
132 | run sudo PATH=$PATH $WORKDIR/percona-scheduler-admin --config-file=testsuite.toml --auto-assign-weights --write-node=1.1.1.1,2.2.2.2:44
133 | echo "$output" >&2
134 | [ "$status" -eq 1 ]
135 | [[ "${lines[0]}" =~ ERROR.*options.are.mutually.exclusive.* ]]
136 |
137 | run sudo PATH=$PATH $WORKDIR/percona-scheduler-admin --config-file=testsuite.toml --write-node=2.2.2.2:44 --update-write-weight="[::1]:4130,2000"
138 | echo "$output" >&2
139 | [ "$status" -eq 1 ]
140 | [[ "${lines[0]}" =~ ERROR.*options.are.mutually.exclusive.* ]]
141 |
142 | run sudo PATH=$PATH $WORKDIR/percona-scheduler-admin --config-file=testsuite.toml --update-write-weight="[::1]:4130,2000" --auto-assign-weights
143 | echo "$output" >&2
144 | [ "$status" -eq 1 ]
145 | [[ "${lines[0]}" =~ ERROR.*options.are.mutually.exclusive.* ]]
146 | }
147 |
148 | # Malformed address in --update-write-weight
149 | @test "run percona-scheduler-admin --update-write-weight" {
150 | run sudo PATH=$PATH $WORKDIR/percona-scheduler-admin --config-file=testsuite.toml --update-write-weight="[::1]:4130av,20s00"
151 | echo "$output" >&2
152 | [ "$status" -eq 1 ]
153 | [[ "${lines[0]}" =~ ERROR.*expected.address.in.format.* ]]
154 |
155 | run sudo PATH=$PATH $WORKDIR/percona-scheduler-admin --config-file=testsuite.toml --update-write-weight="[::1]:4130,20s00"
156 | echo "$output" >&2
157 | [ "$status" -eq 1 ]
158 | [[ "${lines[0]}" =~ ERROR.*Weight.in.--update-write-weight.requires.a.number.* ]]
159 | }
160 |
--------------------------------------------------------------------------------
/tests/setup_workdir.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Created by Mohit Joshi, Percona LLC
3 | # Creation date: 15-April-2021
4 | #
5 | # The script is used for creating the workdir which must be passed to proxysql-admin-testsuite.sh
6 | # for testing the proxysql-admin functionality
7 |
8 | # Create Helper Functions
9 |
10 | help() {
11 | cat << EOF
12 | Usage:
13 | ./setup_workdir.sh /path/where/the/workdir/should/be/created skip_download
14 | eg.
15 | 1) ./setup_workdir.sh ~/workdir1 1 => skips the download of PXC
16 | 2) ./setup_workdir.sh /tmp/workdir2 0
17 | 3) ./setup_workdir.sh workdir3
18 |
19 |
20 | Note: The script will exit if there exists a directory by the same name
21 | EOF
22 | }
23 |
24 | enable_repo() {
25 | # parameters are:
26 | local repo_name=$1
27 | local repo_type=$2
28 |
29 | # Assuming percona-release utility is installed on the machine
30 | sudo percona-release enable "$repo_name" "$repo_type"
31 | }
32 |
33 | install_package() {
34 | # parameters are stored in array varible:
35 | local -a pkg_name_arr=("$@")
36 |
37 | if [ -f /usr/bin/yum ]; then
38 | for file in "${pkg_name_arr[@]}"; do
39 | sudo yum install -y "$file"
40 | done
41 | elif [ -f /usr/bin/apt ]; then
42 | for file in "${pkg_name_arr[@]}"; do
43 | sudo apt-get update -y
44 | sudo apt-get install -y "$file"
45 | done
46 | fi
47 | }
48 |
49 | # Call the helper function if no argument is passed
50 | if [[ $# -eq 0 ]]; then
51 | help
52 | exit 1
53 | fi
54 |
55 | # Check if Proxysql is installed
56 | echo "Looking for proxysql package installed on the machine"
57 | if [[ ! -e $(which proxysql) ]];then
58 | echo "...ProxySQL not found"
59 | echo "Installing proxysql2 package"
60 | enable_repo proxysql testing
61 | install_package proxysql2
62 | echo "...ProxySQL installed successfully"
63 | PROXYSQL=$(which proxysql)
64 | else
65 | PROXYSQL=$(which proxysql)
66 | echo "...ProxySQL found at $PROXYSQL"
67 | fi
68 |
69 | # Ensure we have read permission on ProxySQL configuration file
70 | sudo chmod 644 /etc/proxysql*.cnf
71 |
72 | # Check if mysql client is installed
73 | echo "Looking for mysql client installed on the machine"
74 | if [[ ! -e $(which mysql) ]]; then
75 | echo "...mysql client not found"
76 | echo "Installing latest mysql client"
77 | enable_repo pxc-80 release
78 | install_package percona-xtradb-cluster-client
79 | echo "...mysql client install successfully"
80 | else
81 | echo "...mysql client found at $(which mysql)"
82 | fi
83 |
84 | WORKDIR=$1
85 | SKIP_DOWNLOAD=$2
86 | SKIP_DOWNLOAD=${SKIP_DOWNLOAD:=0}
87 | VERSION="8.4"
88 |
89 |
90 | # Fetch PXC versions
91 | if [[ $VERSION == "8.0" ]]; then
92 |
93 | LATEST_VERSION=$(git ls-remote --refs --sort='version:refname' --tags https://github.com/percona/percona-xtradb-cluster | \
94 | grep 'Percona-XtraDB-Cluster-8.0' | tail -n1 | cut -d '/' -f3 | cut -d '-' -f4)
95 | VERSION_SUFFIX=$(git ls-remote --refs --sort='version:refname' --tags https://github.com/percona/percona-xtradb-cluster | \
96 | grep 'Percona-XtraDB-Cluster-8.0' | tail -n1 | cut -d '/' -f3 | cut -d '-' -f5)
97 | elif [[ $VERSION == "8.4" ]]; then
98 | LATEST_VERSION=$(git ls-remote --refs --sort='version:refname' --tags https://github.com/percona/percona-xtradb-cluster | \
99 | grep 'Percona-XtraDB-Cluster-8.4' | tail -n1 | cut -d '/' -f3 | cut -d '-' -f4)
100 | VERSION_SUFFIX=$(git ls-remote --refs --sort='version:refname' --tags https://github.com/percona/percona-xtradb-cluster | \
101 | grep 'Percona-XtraDB-Cluster-8.4' | tail -n1 | cut -d '/' -f3 | cut -d '-' -f5)
102 | fi
103 |
104 | if [ -d "$WORKDIR" ]; then
105 | echo "Directory with the provided name already exist."
106 | echo "Exiting..."
107 | exit 1
108 | else
109 | mkdir -p "$WORKDIR" "$WORKDIR"/proxysql-2.0/usr/bin "$WORKDIR"/proxysql-2.0/etc
110 | if [ -d "$WORKDIR" ]; then
111 | echo "...Work Directory created successfully";
112 | fi
113 | fi
114 |
115 | echo "Looking for ProxySQL Admin Base directory";
116 | SCRIPT=$(readlink -f "$0")
117 | SCRIPTPATH=$(dirname "$SCRIPT")
118 | PROXYSQL_ADMIN_BASEDIR=$(realpath "$SCRIPTPATH"/../)
119 |
120 | if [ -f "$PROXYSQL_ADMIN_BASEDIR"/proxysql-admin ]; then
121 | echo "...ProxySQL Base Directory found at $PROXYSQL_ADMIN_BASEDIR"
122 | else
123 | echo "...ProxySQL Base Directory not found. Exiting!"
124 | exit 1
125 | fi
126 |
127 | echo "Looking for Percona Scheduler Handler";
128 | if [ -f "$PROXYSQL_ADMIN_BASEDIR"/pxc_scheduler_handler ]; then
129 | echo "...Percona Scheduler binary found at $PROXYSQL_ADMIN_BASEDIR/pxc_scheduler_handler"
130 | else
131 | echo "...Not found. Building percona scheduler"
132 | pushd "$PROXYSQL_ADMIN_BASEDIR" > /dev/null || exit
133 | bash build_scheduler.sh > /dev/null 2>&1
134 | popd > /dev/null || exit
135 | fi
136 |
137 | echo "Creating Symbolic links"
138 | ln -s "$PROXYSQL" "$WORKDIR"/proxysql-2.0/usr/bin
139 | ln -s "$PROXYSQL_ADMIN_BASEDIR"/proxysql-admin.cnf "$WORKDIR"/proxysql-2.0/etc
140 | for file in proxysql-admin proxysql-common proxysql-admin-common percona-scheduler-admin proxysql-login-file pxc_scheduler_handler
141 | do
142 | ln -s "$PROXYSQL_ADMIN_BASEDIR"/$file "$WORKDIR"
143 | done;
144 |
145 |
146 | echo "...Symbolic links created successfully"
147 |
148 |
149 | echo "Copying config files required for the test"
150 | cp $PROXYSQL_ADMIN_BASEDIR/tests/testsuite.toml $WORKDIR
151 | echo "...Copying done"
152 |
153 | if [[ ! $SKIP_DOWNLOAD -eq 1 ]];then
154 | echo "Fetching the PXC tarball packages"
155 | if [[ $VERSION == "8.0" ]]; then
156 | wget -O $WORKDIR/Percona-XtraDB-Cluster_${LATEST_VERSION}_Linux.x86_64.glibc2.35-minimal.tar.gz http://downloads.percona.com/downloads/Percona-XtraDB-Cluster-80/Percona-XtraDB-Cluster-${LATEST_VERSION}/binary/tarball/Percona-XtraDB-Cluster_${LATEST_VERSION}-${VERSION_SUFFIX}_Linux.x86_64.glibc2.35-minimal.tar.gz
157 | elif [[ $VERSION == "8.4" ]]; then
158 | wget -O $WORKDIR/Percona-XtraDB-Cluster_${LATEST_VERSION}_Linux.x86_64.glibc2.35-minimal.tar.gz http://downloads.percona.com/downloads/Percona-XtraDB-Cluster-84/Percona-XtraDB-Cluster-${LATEST_VERSION}/binary/tarball/Percona-XtraDB-Cluster_${LATEST_VERSION}-${VERSION_SUFFIX}_Linux.x86_64.glibc2.35-minimal.tar.gz
159 | fi
160 | echo "...Successful"
161 | fi
162 |
163 | echo "The workdir is ready for use located at: $WORKDIR"
164 | echo "Run: $PROXYSQL_ADMIN_BASEDIR/tests/proxysql-admin-testsuite.sh $WORKDIR"
165 |
166 |
--------------------------------------------------------------------------------
/tests/test-common.bash:
--------------------------------------------------------------------------------
1 | # Common helper file for bats test script
2 |
3 | # The minimum required openssl version
4 | readonly REQUIRED_OPENSSL_VERSION="1.1.1"
5 |
6 | # The name of the openssl binary packaged with proxysql-admin
7 | readonly PROXYSQL_ADMIN_OPENSSL_NAME="proxysql-admin-openssl"
8 |
9 | declare DEBUG_SQL_QUERY=0
10 |
11 |
12 | function exec_sql() {
13 | local user=$1
14 | local password=$2
15 | local hostname=$3
16 | local port=$4
17 | local query=$5
18 | local args="--skip-column_names"
19 | local retvalue
20 | local retoutput
21 |
22 | if [[ $# -ge 6 ]]; then
23 | args=$6
24 | fi
25 |
26 | if [[ $DEBUG_SQL_QUERY -eq 1 ]]; then
27 | echo "exec_sql : $user@$hostname:$port $password ==> $query" >&2
28 | fi
29 |
30 | retoutput=$(printf "[client]\nuser=${user}\npassword=\"${password}\"\nhost=${hostname}\nport=${port}" \
31 | | $PXC_BASEDIR/bin/mysql --defaults-file=/dev/stdin --protocol=tcp \
32 | --unbuffered --batch --silent ${args} -e "${query}")
33 | retvalue=$?
34 |
35 | if [[ $DEBUG_SQL_QUERY -eq 1 ]]; then
36 | local number_of_newlines=0
37 | local dbgoutput=$retoutput
38 |
39 | if [[ -n $retoutput ]]; then
40 | number_of_newlines=$(printf "%s" "${dbgoutput}" | wc -l)
41 | fi
42 |
43 | if [[ $retvalue -ne 0 ]]; then
44 | echo "--> query failed $retvalue" >&2
45 | elif [[ -z $dbgoutput ]]; then
46 | echo "--> query returned $retvalue : " >&2
47 | elif [[ ${number_of_newlines} -eq 0 ]]; then
48 | echo "--> query returned $retvalue : ${dbgoutput}" >&2
49 | else
50 | echo "--> query returned $retvalue : " >&2
51 | printf "%s\n" "${dbgoutput}" | while IFS= read -r line; do
52 | echo "----> $line" >&2
53 | done
54 | fi
55 | fi
56 |
57 |
58 | printf "%s" "${retoutput}"
59 | return $retvalue
60 | }
61 |
62 | function proxysql_exec() {
63 | local query=$1
64 | local args=""
65 |
66 | if [[ $# -ge 2 ]]; then
67 | args=$2
68 | fi
69 |
70 | exec_sql "$PROXYSQL_USERNAME" "$PROXYSQL_PASSWORD" \
71 | "$PROXYSQL_HOSTNAME" "$PROXYSQL_PORT" \
72 | "$query" "$args"
73 |
74 | return $?
75 | }
76 |
77 | function cluster_exec() {
78 | local query=$1
79 | local args=""
80 |
81 | if [[ $# -ge 2 ]]; then
82 | args=$2
83 | fi
84 |
85 | exec_sql "$CLUSTER_USERNAME" "$CLUSTER_PASSWORD" \
86 | "$CLUSTER_HOSTNAME" "$CLUSTER_PORT" \
87 | "$query" "$args"
88 |
89 | return $?
90 | }
91 |
92 | function mysql_exec() {
93 | local hostname=$1
94 | local port=$2
95 | local query=$3
96 | local args=""
97 |
98 | if [[ $# -ge 4 ]]; then
99 | args=$4
100 | fi
101 |
102 | exec_sql "$CLUSTER_USERNAME" "$CLUSTER_PASSWORD" \
103 | "$hostname" "$port" \
104 | "$query" "$args"
105 |
106 | return $?
107 | }
108 |
109 |
110 | # Returns information about the nodes in the hostgroup
111 | #
112 | # Globals:
113 | # HOSTS
114 | # PORTS
115 | # STATUS
116 | # COMMENTS
117 | # HOSTGROUPS
118 | # WEIGHTS
119 | # MAX_CONNECTIONS
120 | #
121 | # Arguments:
122 | # 1: hostgroup
123 | #
124 | function get_node_data() {
125 | local hostgroup=$1
126 | local query=""
127 | local data
128 |
129 | HOSTS=()
130 | PORTS=()
131 | STATUS=()
132 | COMMENTS=()
133 | HOSTGROUPS=()
134 | WEIGHTS=()
135 | MAX_CONNECTIONS=()
136 |
137 | if [[ -n $hostgroup ]]; then
138 | if [[ $hostgroup =~ ',' ]]; then
139 | query+="hostgroup_id IN ($hostgroup)"
140 | else
141 | query+="hostgroup_id=$hostgroup"
142 | fi
143 | fi
144 |
145 | data=$(proxysql_exec "SELECT hostname,port,status,comment,hostgroup_id,weight,max_connections
146 | FROM runtime_mysql_servers
147 | WHERE $query and STATUS != 'SHUNNED'
148 | ORDER BY status,hostname,port,hostgroup_id")
149 | local rc=$?
150 |
151 | if [[ $rc -ne 0 ]]; then
152 | return $rc
153 | fi
154 |
155 | while read line; do
156 | HOSTS+=($(echo -e "$line" | cut -f1))
157 | PORTS+=($(echo -e "$line" | cut -f2))
158 | STATUS+=($(echo -e "$line" | cut -f3))
159 | COMMENTS+=($(echo -e "$line" | cut -f4))
160 | HOSTGROUPS+=($(echo -e "$line" | cut -f5))
161 | WEIGHTS+=($(echo -e "$line" | cut -f6))
162 | MAX_CONNECTIONS+=($(echo -e "$line" | cut -f7))
163 | done< <(printf "%s\n" "$data")
164 | }
165 |
166 | function retrieve_reader_info() {
167 | get_node_data $READER_HOSTGROUP_ID
168 | read_host=("${HOSTS[@]}")
169 | read_port=("${PORTS[@]}")
170 | read_status=("${STATUS[@]}")
171 | read_comment=("${COMMENTS[@]}")
172 | read_hostgroup=("${HOSTGROUPS[@]}")
173 | read_weight=("${WEIGHTS[@]}")
174 | read_max_connections=("${MAX_CONNECTIONS[@]}")
175 | }
176 |
177 | function retrieve_writer_info() {
178 | local hg_id=$1
179 | get_node_data $hg_id
180 | write_host=("${HOSTS[@]}")
181 | write_port=("${PORTS[@]}")
182 | write_status=("${STATUS[@]}")
183 | write_comment=("${COMMENTS[@]}")
184 | write_hostgroup=("${HOSTGROUPS[@]}")
185 | write_weight=("${WEIGHTS[@]}")
186 | write_max_connections=("${MAX_CONNECTIONS[@]}")
187 | }
188 |
189 |
190 | function retrieve_slave_info() {
191 | local data=""
192 |
193 | local HOSTGROUPS=()
194 | local HOSTS=()
195 | local PORTS=()
196 | local STATUS=()
197 | local COMMENTS=()
198 |
199 | data=$(proxysql_exec "SELECT
200 | hostgroup_id,hostname,port,status,comment
201 | FROM runtime_mysql_servers
202 | WHERE hostgroup_id in ($ALL_HOSTGROUPS)
203 | AND comment = 'SLAVEREAD'
204 | ORDER BY hostgroup_id,hostname,port,status")
205 | local rc=$?
206 | if [[ $rc -ne 0 ]]; then
207 | return $rc
208 | fi
209 |
210 | while read line; do
211 | HOSTGROUPS+=($(echo -e "$line" | cut -f1))
212 | HOSTS+=($(echo -e "$line" | cut -f2))
213 | PORTS+=($(echo -e "$line" | cut -f3))
214 | STATUS+=($(echo -e "$line" | cut -f4))
215 | COMMENTS+=($(echo -e "$line" | cut -f5))
216 | done< <(printf "$data\n")
217 |
218 | slave_hostgroup=("${HOSTGROUPS[@]}")
219 | slave_host=("${HOSTS[@]}")
220 | slave_port=("${PORTS[@]}")
221 | slave_status=("${STATUS[@]}")
222 | slave_comment=("${COMMENTS[@]}")
223 | }
224 |
225 | # Queries the node for it's slave status and returns the
226 | # data in a a string with four fields:
227 | # master_host:slave_io_running:slave_sql_running:seconds_behind_master
228 | # This is to get around the lack of associative array support in
229 | # the distros.
230 | #
231 | # Globals:
232 | # slave_status
233 | #
234 | # Arguments:
235 | # 1: host address
236 | # 2: port
237 | #
238 | function retrieve_slavenode_status() {
239 | local host=$1
240 | local port=$2
241 | local status
242 |
243 | status=$(mysql_exec "${host}" "${port}" 'SHOW SLAVE STATUS\G' "--silent" | sed 's/ //g')
244 |
245 | result=""
246 | result+=$(echo "$status" | grep "^Master_Host:" | cut -d: -f2-)
247 | result+="\t"
248 | result+=$(echo "$status" | grep "^Slave_IO_Running:" | cut -d: -f2)
249 | result+="\t"
250 | result+=$(echo "$status" | grep "^Slave_SQL_Running:" | cut -d: -f2)
251 | result+="\t"
252 | result+=$(echo "$status" | grep "^Seconds_Behind_Master:" | cut -d: -f2)
253 |
254 | echo "$result"
255 | }
256 |
257 |
258 | function wait_for_server_start() {
259 | local socket=$1
260 | local cluster_size=$2
261 |
262 | for X in $( seq 0 30 ); do
263 | sleep 1
264 | if ${PXC_BASEDIR}/bin/mysqladmin -uroot -S${socket} ping > /dev/null 2>&1; then
265 | # Check the WSREP_READY status
266 | ready_status=$(${PXC_BASEDIR}/bin/mysql -uroot -$${socket} -Ns -e "show status like 'wsrep_ready'")
267 | if [[ -n $ready_status ]]; then
268 | ready_status=$(echo "$ready_status" | awk '{ print $2 }')
269 | if [[ $ready_status == "ON" ]]; then
270 | size=$(${PXC_BASEDIR}/bin/mysql -uroot -$${socket} -Ns -e "show status like 'wsrep_cluster_size'")
271 | if [[ -n $size ]]; then
272 | size=$(echo "$size" | awk '{ print $2 }')
273 | if [[ $size -eq $cluster_size ]]; then
274 | break
275 | fi
276 | fi
277 | fi
278 | fi
279 |
280 | fi
281 | done
282 | }
283 |
284 | function wait_for_server_shutdown() {
285 | local socket=$1
286 | local cluster_size=$2
287 |
288 | for X in $( seq 0 30 ); do
289 | sleep 1
290 | if ! ${PXC_BASEDIR}/bin/mysqladmin -uroot -S${socket} ping > /dev/null 2>&1; then
291 | return 0
292 | fi
293 | done
294 | return 1
295 | }
296 |
297 |
298 |
299 | function restart_server() {
300 | local restart_cmd=$1
301 | local restart_user=$2
302 | local bootstrap=""
303 | local pxc_datadir
304 | local options=""
305 |
306 | if [[ $# -ge 3 ]]; then
307 | bootstrap=$3
308 | fi
309 |
310 | local new_start_cmd=$restart_cmd
311 |
312 | if [[ $bootstrap == "bootstrap" ]]; then
313 | if echo "$restart_cmd" | grep -q -v "\-\-wsrep-new-cluster"; then
314 | # There is no --wsrep-new-cluster, so add it to the command line
315 | options+=" --wsrep-new-cluster "
316 | fi
317 |
318 | # Extract the datadir
319 | pxc_datadir=$(echo $restart_cmd | grep -o "\-\-datadir=[^ ]*")
320 | pxc_datadir=$(echo "$pxc_datadir" | cut -d'=' -f2)
321 |
322 | # Update the grastate.dat file to ensure that the node can bootstrap
323 | # Ensure that safe_to_bootstrap is set to 1
324 | sed -i "s/^safe_to_bootstrap:[ \t]0/safe_to_bootstrap: 1/" "${pxc_datadir}/grastate.dat"
325 | else
326 | new_start_cmd=$(echo "$new_start_cmd" | sed "s/\-\-wsrep-new-cluster//g")
327 | fi
328 |
329 | if [[ ! $new_start_cmd =~ --user=$restart_user ]]; then
330 | options+="--user=$restart_user"
331 | fi
332 | nohup $new_start_cmd $options 3>&- &>/dev/null &
333 | }
334 |
335 | function dump_nodes() {
336 | local lineno=$1
337 | local msg=$2
338 | echo "$lineno Dumping server info : $msg" >&2
339 | proxysql_exec "SELECT
340 | hostgroup_id,hostname,port,status,comment,weight
341 | FROM mysql_servers
342 | WHERE hostgroup_id IN ($ALL_HOSTGROUPS)
343 | ORDER BY hostgroup_id,status,hostname,port" >&2
344 | echo "" >&2
345 | }
346 |
347 | function dump_runtime_nodes() {
348 | local lineno=$1
349 | local msg=$2
350 | echo "$lineno Dumping runtime server info : $msg" >&2
351 | proxysql_exec "SELECT hostgroup_id,hostname,port,status,comment,weight
352 | FROM runtime_mysql_servers
353 | WHERE hostgroup_id IN ($ALL_HOSTGROUPS)
354 | ORDER BY hostgroup_id,status,hostname,port" >&2
355 | echo "" >&2
356 | }
357 |
358 | function require_pxc_maint_mode() {
359 | if [[ $MYSQL_VERSION =~ ^5.5 || $MYSQL_VERSION =~ ^5.6 ]]; then
360 | skip "requires pxc_maint_mode"
361 | fi
362 | }
363 |
364 |
365 |
366 | # Returns the version string in a standardized format
367 | # Input "1.2.3" => echoes "010203"
368 | # Wrongly formatted values => echoes "000000"
369 | #
370 | # Globals:
371 | # None
372 | #
373 | # Arguments:
374 | # Parameter 1: a version string
375 | # like "5.1.12"
376 | # anything after the major.minor.revision is ignored
377 | # Outputs:
378 | # A string that can be used directly with string comparisons.
379 | # So, the string "5.1.12" is transformed into "050112"
380 | # Note that individual version numbers can only go up to 99.
381 | #
382 | function normalize_version()
383 | {
384 | local major=0
385 | local minor=0
386 | local patch=0
387 |
388 | # Only parses purely numeric version numbers, 1.2.3
389 | # Everything after the first three values are ignored
390 | if [[ $1 =~ ^([0-9]+)\.([0-9]+)\.?([0-9]*)([^ ])* ]]; then
391 | major=${BASH_REMATCH[1]}
392 | minor=${BASH_REMATCH[2]}
393 | patch=${BASH_REMATCH[3]}
394 | fi
395 |
396 | printf %02d%02d%02d $major $minor $patch
397 | }
398 |
399 |
400 | # Compares two version strings
401 | # The version strings passed in will be normalized to a
402 | # string-comparable version.
403 | #
404 | # Globals:
405 | # None
406 | #
407 | # Arguments:
408 | # Parameter 1: The left-side of the comparison (for example: "5.7.25")
409 | # Parameter 2: the comparison operation
410 | # '>', '>=', '=', '==', '<', '<=', "!="
411 | # Parameter 3: The right-side of the comparison (for example: "5.7.24")
412 | #
413 | # Returns:
414 | # Returns 0 (success) if param1 op param2
415 | # Returns 1 (failure) otherwise
416 | #
417 | function compare_versions()
418 | {
419 | local version_1="$1"
420 | local op=$2
421 | local version_2="$3"
422 |
423 | if [[ -z $version_1 || -z $version_2 ]]; then
424 | echo "$LINENO : Missing version string in comparison" >&2
425 | echo -e "-- left-side:$version_1 operation:$op right-side:$version_2" >&2
426 | return 1
427 | fi
428 |
429 | version_1="$( normalize_version "$version_1" )"
430 | version_2="$( normalize_version "$version_2" )"
431 |
432 | if [[ ! " = == > >= < <= != " =~ " $op " ]]; then
433 | echo "$LINENO : Unknown operation : $op" >&2
434 | echo -e "-- Must be one of : = == > >= < <=" >&2
435 | return 1
436 | fi
437 |
438 | [[ $op == "<" && $version_1 < $version_2 ]] && return 0
439 | [[ $op == "<=" && ! $version_1 > $version_2 ]] && return 0
440 | [[ $op == "=" && $version_1 == $version_2 ]] && return 0
441 | [[ $op == "==" && $version_1 == $version_2 ]] && return 0
442 | [[ $op == ">" && $version_1 > $version_2 ]] && return 0
443 | [[ $op == ">=" && ! $version_1 < $version_2 ]] && return 0
444 | [[ $op == "!=" && $version_1 != $version_2 ]] && return 0
445 |
446 | return 1
447 | }
448 |
449 |
450 |
451 | # Looks for a version of OpenSSL 1.1.1
452 | # This could be openssl, openssl11, or the proxysql-admin-openssl binary.
453 | #
454 | # Globals:
455 | # REQUIRED_OPENSSL_VERSION
456 | # PROXYSQL_ADMIN_OPENSSL_NAME
457 | #
458 | # Arguments:
459 | # Parameter 1: the lineno where this function was called
460 | #
461 | # Returns 0 if a binary was found (with version 1.1.1+)
462 | # and writes the path to the binary to stdout
463 | # Returns 1 otherwise (and prints out its own error message)
464 | #
465 | function find_openssl_binary()
466 | {
467 | local lineno=$1
468 | local path_to_openssl
469 | local openssl_executable=""
470 | local value
471 | local openssl_version
472 |
473 | # Check for the proper version of the executable
474 | path_to_openssl=$(which openssl 2> /dev/null)
475 | if [[ $? -eq 0 && -n ${path_to_openssl} && -e ${path_to_openssl} ]]; then
476 |
477 | # We found a possible binary, check the version
478 | value=$(${path_to_openssl} version)
479 | openssl_version=$(expr match "$value" '.*[ \t]\+\([0-9]\+\.[0-9]\+\.[0-9]\+\)[^0-9].*')
480 |
481 | # Extract the version from version string
482 | if compare_versions "${openssl_version}" ">=" "$REQUIRED_OPENSSL_VERSION"; then
483 | openssl_executable=${path_to_openssl}
484 | fi
485 | fi
486 |
487 | # If we haven't found an acceptable openssl, look for openssl11
488 | if [[ -z $openssl_executable ]]; then
489 | # Check for openssl 1.1 executable (if installed alongside 1.0)
490 | openssl_executable=$(which openssl11 2> /dev/null)
491 | fi
492 |
493 | # If we haven't found openssl/openssl11 look for our own binary
494 | if [[ -z $openssl_executable ]]; then
495 | openssl_executable=$(which "${WORKDIR}/${PROXYSQL_ADMIN_OPENSSL_NAME}" 2> /dev/null)
496 | fi
497 |
498 | if [[ -z $openssl_executable ]]; then
499 | echo -e "$LINENO : Could not find a v${REQUIRED_OPENSSL_VERSION}+ OpenSSL executable in the path." \
500 | "\n-- Please check that OpenSSL v${REQUIRED_OPENSSL_VERSION} or greater is installed and in the path." >&2
501 | return 1
502 | fi
503 |
504 | # Verify the openssl versions
505 | value=$(${openssl_executable} version)
506 |
507 | # Extract the version from version string
508 | openssl_version=$(expr match "$value" '.*[ \t]\+\([0-9]\+\.[0-9]\+\.[0-9]\+\)[^0-9].*')
509 |
510 | if compare_versions "$openssl_version" "<" "$REQUIRED_OPENSSL_VERSION"; then
511 | echo -e "$LINENO : Could not find OpenSSL with the required version. required:${REQUIRED_OPENSSL_VERSION} found:${openssl_version}" \
512 | "\n-- Please check that OpenSSL v${REQUIRED_OPENSSL_VERSION} or greater is installed and in the path." >& 2
513 | return 1
514 | fi
515 |
516 | echo "$LINENO : Found openssl executable:${openssl_executable} ${openssl_version}" >&2
517 |
518 | printf "%s" "${openssl_executable}"
519 | return 0
520 | }
521 |
--------------------------------------------------------------------------------
/tests/testsuite.toml:
--------------------------------------------------------------------------------
1 |
2 | [pxccluster]
3 | activeFailover = 1
4 | failBack = false
5 | checkTimeOut = 2000
6 | # debug = 1 //Deprecated: this is redundant and not in use
7 | mainSegment = 0
8 | sslClient = "client-cert.pem"
9 | sslKey = "client-key.pem"
10 | sslCa = "ca.pem"
11 | sslCertificatePath = "/opt/cert/ssl_test"
12 | hgW = 100
13 | hgR = 101
14 | configHgRange =8000
15 | maintenanceHgRange =9000
16 | #bckHgW = 8100 #deprecated
17 | #bckHgR = 8101 #deprecated
18 |
19 | # --------------------------------
20 | # Set to true if there is a single writer node. If this is set,
21 | # then maxNumWriters is assumed to be 1.
22 | #
23 | # Allowable values: true,false
24 | # Default: true
25 | #
26 | singlePrimary = true
27 |
28 | # --------------------------------
29 | # Set to the number of writer nodes desired.
30 | #
31 | # The value of this is assumed to be 1 if singlePrimary is true.
32 | #
33 | # If this is set to a value from 1 to 100, then the query rules
34 | # are setup for a distinct writer hostgroup (writes are sent to the
35 | # writer hostgroup and read are sent to the reader hostgroup).
36 | #
37 | # If this is set to a value > 100, then all queries (writes and reads)
38 | # are sent to the writer hostgroup. This is assumed to be a
39 | # load-balancing scenario, where all nodes are equivalent and accept
40 | # both reads and writes.
41 | #
42 | # Default: (none)
43 | #
44 |
45 | maxNumWriters = 1
46 |
47 | writerIsAlsoReader = 1
48 |
49 | retryUp = 0
50 | retryDown = 2
51 | clusterId = 10
52 | persistPrimarySettings=0 #0 disable| 1 only persist Write settings | 2 persist Read and Write settings
53 |
54 | # == proxysql ===================================================
55 | # The proxysql section is for ProxySQL-specific information.
56 | #
57 | # These settings will be read and used whenever the scheduler is run.
58 | #
59 | [proxysql]
60 | port = 6032
61 | host = "127.0.0.1"
62 | user = "admin"
63 | password = "admin"
64 | clustered = false
65 | respectManualOfflineSoft=false
66 | lockfilepath = "/tmp/"
67 |
68 | #== global ======================================================
69 | # The global section are for variables that are not ProxySQL or
70 | # cluster specific.
71 | #
72 | # These settings will be read and used whenever the scheduler is run.
73 | #
74 | [global]
75 | debug = true
76 |
77 | #?? Should we just have logFile, what advantage does logTarget have?
78 | logLevel = "debug"
79 | logTarget = "file" #stdout | file
80 | logFile = "/tmp/pscheduler.log"
81 |
82 | #?? Should we use the development for these two
83 | daemonize = false
84 | daemonInterval = 2000
85 | performance = true
86 |
87 | # Not used currently
88 | OS = "na"
89 |
90 | #?? Make common lockfileTimeout -> lockFileTimeout
91 | lockfiletimeout = 60 #seconds
92 | lockclustertimeout = 600 #120 # seconds
93 |
94 |
95 | #== setup =======================================================
96 | # These variables are used only upon Setup
97 | # Changing these variables after setup will not affect operation
98 | #
99 | [setup]
100 |
101 | # --------------------------------
102 | # The clusterAppUser is the ProxySQL user account that should be
103 | # used by clients to access the cluster.
104 | #
105 | # Uncomment the following options (clusterAppUser and clusterAppUserPassword)
106 | # to enable the setting of the clusterAppUser for this cluster.
107 | #
108 | #clusterAppUser="proxysql_user"
109 | #clusterAppUserPassword="passw0rd"
110 |
111 | # --------------------------------
112 | # The monitorUser is used by ProxySQL to access the servers and
113 | # check the connections.
114 | #
115 | monitorUser="monitor"
116 | monitorUserPassword="monitor"
117 |
118 | # --------------------------------
119 | # The clusterXXX information is used to setup the cluster for
120 | # use by ProxySQL.
121 | #
122 | clusterHost="localhost"
123 | clusterPort=4110
124 | clusterUser="admin"
125 | clusterUserPassword="admin"
126 |
127 | # --------------------------------
128 | # ProxySQL will use SSL to connect to the backend servers
129 | #
130 | useSSL=0
131 |
132 | # --------------------------------
133 | # Max number of connections from ProxySQL to the backend servers.
134 | #
135 | maxConnections=1000
136 |
137 | nodeCheckInterval=2000
138 |
--------------------------------------------------------------------------------
/tools/enable_scheduler:
--------------------------------------------------------------------------------
1 | #!/bin/bash -u
2 |
3 | # Turn off shell globbing (because we do SQL querying below)
4 | set -o noglob
5 |
6 | function usage() {
7 | local path=$0
8 | cat << EOF
9 | Usage example:
10 | $ ${path##*/} [options]
11 |
12 | This tool is used to enable/disable the specified scheduler that matches the write-hg.
13 |
14 | Options:
15 | --write-hg= : the write hostgroup (specifies the scheduler to be enabled/disabled)
16 | --enable : activate the scheduler (default)
17 | --disable : deactivate the scheduler
18 | --user= : specify the user name
19 | --password= : specify the user password
20 | --host= : specify host address
21 | --port= : specify host port
22 | --query-options= : mysql client command line options, (example: "--silent -N")
23 |
24 | Examples:
25 | ${path##*/} --enable --write-hg=10
26 |
27 | The default is to use the ProxySQL credentials in /etc/proxysql-admin.cnf.
28 |
29 | EOF
30 | }
31 |
32 | #
33 | # Executes an SQL query
34 | #
35 | # Globals:
36 | # USER
37 | # PASSWORD
38 | # HOST
39 | # PORT
40 | #
41 | # Arguments:
42 | # 1: arguments to be passed to mysql
43 | # 2: the query
44 | #
45 | function exec_sql() {
46 | local args=$1
47 | local query=$2
48 | local retvalue
49 | local retoutput
50 |
51 | retoutput=$(printf "[client]\nuser=${USER}\npassword=\"${PASSWORD}\"\nhost=${HOST}\nport=${PORT}" \
52 | | mysql --defaults-file=/dev/stdin --protocol=tcp \
53 | ${args} -e "${query}")
54 | retvalue=$?
55 |
56 | printf "${retoutput//%/%%}"
57 | return $retvalue
58 | }
59 |
60 |
61 | declare USER=""
62 | declare PASSWORD=""
63 | declare HOST=""
64 | declare PORT=""
65 | declare WRITE_HG=""
66 | declare ENABLE=1
67 |
68 | function parse_args() {
69 | local param value
70 | local positional_params=""
71 |
72 | while [[ $# -gt 0 && "$1" != "" ]]; do
73 | param=`echo $1 | awk -F= '{print $1}'`
74 | value=`echo $1 | awk -F= '{print $2}'`
75 |
76 | # Assume that all options start with a '-'
77 | # otherwise treat as a positional parameter
78 | if [[ ! $param =~ ^- ]]; then
79 | positional_params+="$1 "
80 | shift
81 | continue
82 | fi
83 | case $param in
84 | -h | --help)
85 | usage
86 | exit
87 | ;;
88 | --user)
89 | USER=$value
90 | ;;
91 | --password)
92 | PASSWORD=$value
93 | ;;
94 | --host)
95 | HOST=$value
96 | ;;
97 | --port)
98 | PORT=$value
99 | ;;
100 | --write-hg)
101 | WRITE_HG=$value
102 | ;;
103 | --enable)
104 | ENABLE=1
105 | ;;
106 | --disable)
107 | ENABLE=0
108 | ;;
109 | *)
110 | echo "ERROR: unknown parameter \"$param\""
111 | usage
112 | exit 1
113 | ;;
114 | esac
115 | shift
116 | done
117 | }
118 |
119 |
120 | if [[ -r /etc/proxysql-admin.cnf ]]; then
121 | source /etc/proxysql-admin.cnf
122 | USER=$PROXYSQL_USERNAME
123 | PASSWORD=$PROXYSQL_PASSWORD
124 | HOST=$PROXYSQL_HOSTNAME
125 | PORT=$PROXYSQL_PORT
126 | fi
127 |
128 | parse_args "$@"
129 | if [[ -z $WRITE_HG ]]; then
130 | echo "Error: Must specify a write hostgroup"
131 | exit 1
132 | fi
133 |
134 | exec_sql "" "UPDATE scheduler SET active=$ENABLE WHERE ARG1 LIKE '% --write-hg=$WRITE_HG %'; LOAD scheduler TO RUNTIME"
135 | if [[ $? -ne 0 ]]; then
136 | echo "scheduler update failed"
137 | exit 1
138 | fi
139 |
140 | value=$(exec_sql "-Ns" "SELECT active FROM scheduler WHERE ARG1 LIKE '% --write-hg=$WRITE_HG %'")
141 | echo " scheduler active value for write hostgroup $WRITE_HG : $value"
142 | value=$(exec_sql "-Ns" "SELECT active FROM runtime_scheduler WHERE ARG1 LIKE '% --write-hg=$WRITE_HG %'")
143 | echo "runtime scheduler active value for write hostgroup $WRITE_HG : $value"
144 |
--------------------------------------------------------------------------------
/tools/mysql_exec:
--------------------------------------------------------------------------------
1 | #!/bin/bash -u
2 |
3 | # Turn off shell globbing (because we do SQL querying below)
4 | set -o noglob
5 |
6 | function usage() {
7 | local path=$0
8 | cat << EOF
9 | Usage example:
10 | $ ${path##*/} [options]
11 |
12 | This tool executes a query on the PXC cluster.
13 |
14 | Options:
15 | --user= : specify the user name (default:root)
16 | --password= : specify the user password
17 | --host= : specify host address
18 | --port= : specify host port
19 | --socket= : path to the socket file (default:/tmp/cluster_one1.sock)
20 | --query-options= : mysql client command line options, (example: "--silent -N")
21 |
22 | If the host and port are specified, the socket file is ignored.
23 |
24 | Examples:
25 | ${path##*/} --query-options="--table" "select * from table_name"
26 |
27 | The default is to connect using the PXC cluster sockets utilizing the default
28 | PXC root user credentials.
29 |
30 | EOF
31 | }
32 |
33 | #
34 | # Executes an SQL query
35 | #
36 | # Globals:
37 | # USER
38 | # PASSWORD
39 | # HOST
40 | # PORT
41 | #
42 | # Arguments:
43 | # 1: arguments to be passed to mysql
44 | # 2: the query
45 | #
46 | function exec_sql() {
47 | local args=$1
48 | local query=$2
49 | local retvalue
50 | local retoutput
51 |
52 | if [[ -n $HOST && -n $PORT ]]; then
53 | retoutput=$(printf "[client]\nuser=${USER}\npassword=\"${PASSWORD}\"\nhost=${HOST}\nport=${PORT}" \
54 | | mysql --defaults-file=/dev/stdin --protocol=tcp \
55 | ${args} -e "${query}")
56 | elif [[ -n $SOCKET ]]; then
57 | if [[ ! -e $SOCKET ]]; then
58 | echo "Error: Could not find socket file: $SOCKET"
59 | exit 1
60 | fi
61 | retoutput=$(printf "[client]\nuser=${USER}\npassword=\"${PASSWORD}\"\n" \
62 | | mysql --defaults-file=/dev/stdin --socket=$SOCKET --user=$USER \
63 | ${args} -e "${query}")
64 | else
65 | echo "Error: requires a socket or host/port to be specified"
66 | exit 1
67 | fi
68 | retvalue=$?
69 |
70 | printf "${retoutput//%/%%}"
71 | return $retvalue
72 | }
73 |
74 |
75 | declare USER="root"
76 | declare PASSWORD=""
77 | declare HOST=""
78 | declare PORT=""
79 | declare QUERY_OPTIONS=""
80 | declare QUERY=""
81 | declare SOCKET="/tmp/cluster_one1.sock"
82 |
83 | function parse_args() {
84 | local param value
85 | local positional_params=""
86 |
87 | while [[ $# -gt 0 && "$1" != "" ]]; do
88 | param=`echo $1 | awk -F= '{print $1}'`
89 | value=`echo $1 | awk -F= '{print $2}'`
90 |
91 | # Assume that all options start with a '-'
92 | # otherwise treat as a positional parameter
93 | if [[ ! $param =~ ^- ]]; then
94 | positional_params+="$1 "
95 | shift
96 | continue
97 | fi
98 | case $param in
99 | -h | --help)
100 | usage
101 | exit
102 | ;;
103 | --user)
104 | USER=$value
105 | ;;
106 | --password)
107 | PASSWORD=$value
108 | ;;
109 | --host)
110 | HOST=$value
111 | ;;
112 | --port)
113 | PORT=$value
114 | ;;
115 | --socket)
116 | SOCKET=$value
117 | ;;
118 | --query-options)
119 | QUERY_OPTIONS=$value
120 | ;;
121 | *)
122 | echo "ERROR: unknown parameter \"$param\""
123 | usage
124 | exit 1
125 | ;;
126 | esac
127 | shift
128 | done
129 |
130 | # handle positional parameters (we only expect one)
131 | QUERY=$positional_params
132 | }
133 |
134 | parse_args "$@"
135 |
136 | if [[ -z $QUERY ]]; then
137 | echo "Error, no query specified (nothing to run)"
138 | exit 1
139 | fi
140 |
141 | exec_sql "$QUERY_OPTIONS" "$QUERY"
142 |
--------------------------------------------------------------------------------
/tools/proxysql_exec:
--------------------------------------------------------------------------------
1 | #!/bin/bash -u
2 |
3 | # Turn off shell globbing (because we do SQL querying below)
4 | set -o noglob
5 |
6 | function usage() {
7 | local path=$0
8 | cat << EOF
9 | Usage example:
10 | $ ${path##*/} [options]
11 |
12 | This tool executes a query on ProxySQL.
13 |
14 | Options:
15 | --user= : specify the user name
16 | --password= : specify the user password
17 | --host= : specify host address
18 | --port= : specify host port
19 | --query-options= : mysql client command line options, (example: "--silent -N")
20 |
21 | Examples:
22 | ${path##*/} --query-options="--table" "select * from mysql_servers"
23 |
24 | The default is to use the ProxySQL credentials in /etc/proxysql-admin.cnf.
25 |
26 | EOF
27 | }
28 |
29 | #
30 | # Executes an SQL query
31 | #
32 | # Globals:
33 | # USER
34 | # PASSWORD
35 | # HOST
36 | # PORT
37 | #
38 | # Arguments:
39 | # 1: arguments to be passed to mysql
40 | # 2: the query
41 | #
42 | function exec_sql() {
43 | local args=$1
44 | local query=$2
45 | local retvalue
46 | local retoutput
47 |
48 | retoutput=$(printf "[client]\nuser=${USER}\npassword=\"${PASSWORD}\"\nhost=${HOST}\nport=${PORT}" \
49 | | mysql --defaults-file=/dev/stdin --protocol=tcp \
50 | ${args} -e "${query}")
51 | retvalue=$?
52 |
53 | printf "${retoutput//%/%%}"
54 | return $retvalue
55 | }
56 |
57 |
58 | declare USER=""
59 | declare PASSWORD=""
60 | declare HOST=""
61 | declare PORT=""
62 | declare QUERY_OPTIONS=""
63 | declare QUERY=""
64 |
65 | function parse_args() {
66 | local param value
67 | local positional_params=""
68 |
69 | while [[ $# -gt 0 && "$1" != "" ]]; do
70 | param=`echo $1 | awk -F= '{print $1}'`
71 | value=`echo $1 | awk -F= '{print $2}'`
72 |
73 | # Assume that all options start with a '-'
74 | # otherwise treat as a positional parameter
75 | if [[ ! $param =~ ^- ]]; then
76 | positional_params+="$1 "
77 | shift
78 | continue
79 | fi
80 | case $param in
81 | -h | --help)
82 | usage
83 | exit
84 | ;;
85 | --user)
86 | USER=$value
87 | ;;
88 | --password)
89 | PASSWORD=$value
90 | ;;
91 | --host)
92 | HOST=$value
93 | ;;
94 | --port)
95 | PORT=$value
96 | ;;
97 | --query-options)
98 | QUERY_OPTIONS=$value
99 | ;;
100 | *)
101 | echo "ERROR: unknown parameter \"$param\""
102 | usage
103 | exit 1
104 | ;;
105 | esac
106 | shift
107 | done
108 |
109 | # handle positional parameters (we only expect one)
110 | QUERY=$positional_params
111 | }
112 |
113 |
114 | if [[ -r /etc/proxysql-admin.cnf ]]; then
115 | source /etc/proxysql-admin.cnf
116 | USER=$PROXYSQL_USERNAME
117 | PASSWORD=$PROXYSQL_PASSWORD
118 | HOST=$PROXYSQL_HOSTNAME
119 | PORT=$PROXYSQL_PORT
120 | fi
121 |
122 | parse_args "$@"
123 |
124 | if [[ -z $QUERY ]]; then
125 | echo "Error, no query specified (nothing to run)"
126 | exit 1
127 | fi
128 |
129 | echo "Query : $QUERY"
130 | exec_sql "$QUERY_OPTIONS" "$QUERY"
131 | echo
132 |
--------------------------------------------------------------------------------
/tools/run_galera_checker:
--------------------------------------------------------------------------------
1 | #!/bin/bash -u
2 |
3 | # Turn off shell globbing (because we do SQL querying below)
4 | set -o noglob
5 |
6 | function usage() {
7 | local path=$0
8 | cat << EOF
9 | Usage example:
10 | $ ${path##*/} [options]
11 |
12 | Options:
13 | --write-hg= : The scheduler for this WRITE hostgroup
14 | will be invoked.
15 | --debug : Enable DEBUG
16 | --log= : Use this path for the log file instead
17 | of the one used by the scheduler.
18 | --node-monitor-log= : Sets the output of the node monitor
19 | to this path.
20 |
21 | The options below are used when querying ProxySQL. If unspecified, the
22 | values in /etc/proxysql-admin.cnf are used.
23 | --user= : specify the user name
24 | --password= : specify the user password
25 | --host= : specify host address
26 | --port= : specify host port
27 |
28 | EOF
29 | }
30 |
31 | #
32 | # Executes an SQL query
33 | #
34 | # Globals:
35 | # USER
36 | # PASSWORD
37 | # HOST
38 | # PORT
39 | #
40 | # Arguments:
41 | # 1: arguments to be passed to mysql
42 | # 2: the query
43 | #
44 | function exec_sql() {
45 | local args=$1
46 | local query=$2
47 | local retvalue
48 | local retoutput
49 |
50 | retoutput=$(printf "[client]\nuser=${USER}\npassword=\"${PASSWORD}\"\nhost=${HOST}\nport=${PORT}" \
51 | | mysql --defaults-file=/dev/stdin --protocol=tcp \
52 | ${args} -e "${query}")
53 | retvalue=$?
54 |
55 | printf "%s" "${retoutput//%/%%}"
56 | return $retvalue
57 | }
58 |
59 |
60 | declare DEBUG=0
61 | declare LOG_FILE=""
62 | declare NODE_MONITOR_LOG=""
63 | declare WRITE_HG=""
64 |
65 | declare USER=""
66 | declare PASSWORD=""
67 | declare HOST=""
68 | declare PORT=""
69 |
70 | function parse_args() {
71 | local param value
72 | local positional_params=""
73 |
74 | while [[ $# -gt 0 && "$1" != "" ]]; do
75 | param=`echo $1 | awk -F= '{print $1}'`
76 | value=`echo $1 | awk -F= '{print $2}'`
77 |
78 | # Assume that all options start with a '-'
79 | # otherwise treat as a positional parameter
80 | if [[ ! $param =~ ^- ]]; then
81 | positional_params+="$1 "
82 | shift
83 | continue
84 | fi
85 | case $param in
86 | -h | --help)
87 | usage
88 | exit
89 | ;;
90 | --user)
91 | USER=$value
92 | ;;
93 | --password)
94 | PASSWORD=$value
95 | ;;
96 | --host)
97 | HOST=$value
98 | ;;
99 | --port)
100 | PORT=$value
101 | ;;
102 | --write-hg)
103 | if [[ -z $value ]]; then
104 | echo "Error: no value provided with --write-hg"
105 | exit 1
106 | fi
107 | WRITE_HG=$value
108 | ;;
109 | --debug)
110 | DEBUG=1
111 | ;;
112 | --log)
113 | if [[ -z $value ]]; then
114 | echo "Error: no value provided with --log"
115 | exit 1
116 | fi
117 | LOG_FILE=$value
118 | ;;
119 | --node-monitor-log )
120 | NODE_MONITOR_LOG=$value
121 | if [[ -z $value ]]; then
122 | echo "Error: no value provided with --node-monitor-log"
123 | exit 1
124 | fi
125 | ;;
126 | *)
127 | echo "ERROR: unknown parameter \"$param\""
128 | usage
129 | exit 1
130 | ;;
131 | esac
132 | shift
133 | done
134 |
135 | # handle positional parameters (we only expect one)
136 | QUERY=$positional_params
137 | }
138 |
139 |
140 | if [[ -r /etc/proxysql-admin.cnf ]]; then
141 | source /etc/proxysql-admin.cnf
142 | USER=$PROXYSQL_USERNAME
143 | PASSWORD=$PROXYSQL_PASSWORD
144 | HOST=$PROXYSQL_HOSTNAME
145 | PORT=$PROXYSQL_PORT
146 | fi
147 |
148 | parse_args "$@"
149 |
150 | if [[ -z $WRITE_HG ]]; then
151 | echo "Error: A WRITE hostgroup is required (--write-hg=)"
152 | exit 1
153 | fi
154 |
155 | # Retrieve the scheduler information for this write hostgroup
156 | scheduler_id=$(exec_sql "-Ns" "SELECT id FROM scheduler WHERE arg1 like '% --write-hg=$WRITE_HOSTGROUP_ID %' OR arg1 like '% -w $WRITE_HOSTGROUP_ID %'")
157 | if [[ -z $scheduler_id ]]; then
158 | echo "Error: Could not retrieve the scheduler for write hostgroup: $WRITE_HG"
159 | exit 1
160 | fi
161 |
162 | galera_checker=$(exec_sql "-Ns" "SELECT filename FROM scheduler WHERE id=$scheduler_id")
163 | galera_checker_args=$(exec_sql "-Ns" "SELECT arg1 FROM scheduler WHERE id=$scheduler_id")
164 | if [[ -z $galera_checker || -z $galera_checker_args ]]; then
165 | echo "Could not retrieve the galera checker information"
166 | exit 1
167 | fi
168 |
169 | if [[ $DEBUG -ne 0 ]]; then
170 | if [[ ! " $galera_checker_args " =~ [[:space:]]--debug[[:space:]] ]]; then
171 | galera_checker_args+=" --debug"
172 | fi
173 | fi
174 |
175 | if [[ -n $LOG_FILE ]]; then
176 | # Replace the existing log file option
177 | # Remove any existing --log=XXX option
178 | galera_checker_args=$(echo "$galera_checker_args" | sed 's/--log=[^ ]*//g')
179 |
180 | # Append on the --log option
181 | galera_checker_args+=" --log=$LOG_FILE"
182 | fi
183 |
184 | if [[ -n $NODE_MONITOR_LOG ]]; then
185 | galera_checker_args=$(echo "$galera_checker_args" | sed 's/--node-monitor-log=[^ ]*//g')
186 |
187 | # Append on the --node-monitor-log option
188 | galera_checker_args+=" --node-monitor-log=$NODE_MONITOR_LOG"
189 | fi
190 |
191 | # TODO: kennt, should support --log-text also
192 |
193 | # Execute the galera checker statement
194 | ${galera_checker} "${galera_checker_args}"
195 |
--------------------------------------------------------------------------------