Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix a bug related to user update failed in case of proxysql cluster #84

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

MaxFedotov
Copy link
Contributor

let's suppose that you have a proxysql cluster which had 2 nodes configured like this:

class { 'proxysql':
     mysql_servers    => [ 
       { 
         'db1' => { 
           'port' => 3306, 
           'hostgroup_id' => 1, 
         } 
       },
       { 
         'db2' => { 
           'hostgroup_id' => 2, 
         } 
       },
     ],
     cluster_name => 'test',
     mysql_users      => [ 
       { 
         'app' => { 
           'password' => '*92C74DFBDA5D60ABD41EFD7EB0DAE389F4646ABB', 
           'default_hostgroup' => 1, 
         } 
       },
       { 
         'ro'  => { 
           'password' => mysql_password('MyReadOnlyUserPassword'), 
           'default_hostgroup' => 2, 
         } 
       },
     ]
}

on the first node you will get

Admin> select * from mysql_users;
+----------+-------------------------------------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+
| username | password                                  | active | use_ssl | default_hostgroup | default_schema | schema_locked | transaction_persistent | fast_forward | backend | frontend | max_connections |
+----------+-------------------------------------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+
| app      | *D45AE3CFCDF725E7B8E1AD008208F2B890DE8CA9 | 1      | 0       | 1                 |                | 0             | 0                      | 0            | 1       | 1        | 10000           |
| ro       | *26EBF0470CAD1F87FBF1DD6B3F20F97D7EEC3C42 | 1      | 0       | 2                 |                | 0             | 1                      | 0            | 1       | 1        | 10000           |
+----------+-------------------------------------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+
2 rows in set (0.00 sec)

but on the second node users get duplicated - you will have separate users for frontend and backend (see sysown/proxysql#1580)

Admin> select * from mysql_users;
+----------+-------------------------------------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+
| username | password                                  | active | use_ssl | default_hostgroup | default_schema | schema_locked | transaction_persistent | fast_forward | backend | frontend | max_connections |
+----------+-------------------------------------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+
| app      | *D45AE3CFCDF725E7B8E1AD008208F2B890DE8CA9 | 1      | 0       | 1                 |                | 0             | 0                      | 0            | 0       | 1        | 10000           |
| ro       | *26EBF0470CAD1F87FBF1DD6B3F20F97D7EEC3C42 | 1      | 0       | 2                 |                | 0             | 1                      | 0            | 0       | 1        | 10000           |
| app      | *D45AE3CFCDF725E7B8E1AD008208F2B890DE8CA9 | 1      | 0       | 1                 |                | 0             | 0                      | 0            | 1       | 0        | 10000           |
| ro       | *26EBF0470CAD1F87FBF1DD6B3F20F97D7EEC3C42 | 1      | 0       | 2                 |                | 0             | 1                      | 0            | 1       | 0        | 10000           |
+----------+-------------------------------------------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+
4 rows in set (0.00 sec)

if you will now change user configuration on the second node (where you have duplicated users), for example add

     mysql_users      => [ 
       { 
         'app' => { 
           'password' => '*92C74DFBDA5D60ABD41EFD7EB0DAE389F4646ABB', 
           'default_hostgroup' => 1, 
           ' transaction_persistent' => 0
         } 
       },

you will get following error:

Error: /Stage[main]/Proxysql::Configure/Proxy_mysql_user[app]: Could not evaluate: Execution of '/usr/bin/mysql --defaults-extra-file=/root/.my.cnf -e UPDATE mysql_users SET `frontend` = '1' WHERE username = 'app'' returned 1: ERROR 1045 (#2800) at line 1: UNIQUE constraint failed: mysql_users.username, mysql_users.frontend
Error: /Stage[main]/Proxysql::Configure/Proxy_mysql_user[ro]: Could not evaluate: Execution of '/usr/bin/mysql --defaults-extra-file=/root/.my.cnf -e UPDATE mysql_users SET `transaction_persistent` = '0', `frontend` = '1' WHERE username = 'ro'' returned 1: ERROR 1045 (#2800) at line 1: UNIQUE constraint failed: mysql_users.username, mysql_users.frontend

this is becase in Proxysql primary key is not username, but username+backend. And as we have default value for this column defined in proxysql_user resource

backend = @resource.value(:backend) || 1
frontend = @resource.value(:frontend) || 1

, puppet tries to upgrade each of users to change to defaults values and got constraint violation.

This pull request fixes this issue. It removes default values from frontend and backend columns (because they already have defaults defined in proxysql database), so this value won't be updated every puppet run if it is not explicitly configured.

@@ -80,13 +80,11 @@ def initialize(*args)

newproperty(:backend) do
desc 'Backend or not.'
defaultto 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Defaults in resource properties in the type are almost always wrong.

max_connections = @resource.value(:max_connections) || 10_000

query = 'INSERT INTO mysql_users (`username`, `password`, `active`, `use_ssl`, `default_hostgroup`, `default_schema`, '
query << ' `schema_locked`, `transaction_persistent`, `fast_forward`, `backend`, `frontend`, `max_connections`) '
query << ' `schema_locked`, `transaction_persistent`, `fast_forward`, '
query << ' `backend`,' if defined?(backend).nil?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not following this. Won't the variable always be defined? and return local-variable (a String which won't be nil)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only if you will define it in your manifest. Else as it don't have default values this would be skipped

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

each user defined in puppet should just create 2 entries in the proxysql config, one backend and one frontend user... These settings currently do not mean anything in the upstream product but they are designed this way to add some functionality to them in the future...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's OK. But the problem is with constraint violation, which i've described in first post. That's really make some problems with cluster deployments

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then I would assume you need a GROUP BY username statement here and change this line to SELECT password, active, use_ssl, default_hostgroup, default_schema, schema_locked, transaction_persistent, fast_forward, MAX(backend) as backend, MAX(frontend) as frontend, max_connections FROM mysql_users WHERE username = '#{name}' GROUP BY username

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the insert and update statements need to update both entries when making changes:
with a WHERE username = '<blah>' AND backend = 0 and a WHERE username = '<blah>' AND backend = 1 to keep both records up-to-date...

Copy link
Contributor Author

@MaxFedotov MaxFedotov Jul 10, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with adding GROUP BY and MAX statements to query. But i don't understand the need to have inserting or updating both entries. Right now, as this fields are not used, no one will specify them in user hash, so basically a user with default values will be inserted (frontend = 1, backend = 1). Then as update also do not specify if this user is frontend or backend - both will be updated. Isn't it correct behavior for current situation?

@bastelfreak bastelfreak added needs-feedback Further information is requested bug Something isn't working labels Mar 5, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working needs-feedback Further information is requested
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants