
    Vh                     $   d dl mZmZmZ eZdZdZdZd dl	m
Z
 d dlmZmZmZmZ d dlmZmZmZmZmZmZ d dlmZ d d	lmZ dd
Z G d d      Z G d d      Z G d d      Z G d d      Z G d d      Z  G d d      Z!d Z"e#dk(  r e"        yy)    )absolute_importdivisionprint_functionu  
---
module: mysql_role

short_description: Adds, removes, or updates a MySQL or MariaDB role

description:
   - Adds, removes, or updates a MySQL or MariaDB role.
   - Roles are supported since MySQL 8.0.0 and MariaDB 10.0.5.

version_added: '2.2.0'

options:
  name:
    description:
      - Name of the role to add or remove.
    type: str
    required: true

  admin:
    description:
      - Supported by B(MariaDB).
      - Name of the admin user of the role (the I(login_user), by default).
    type: str

  priv:
    description:
      - "MySQL privileges string in the format: C(db.table:priv1,priv2)."
      - "You can specify multiple privileges by separating each one using
        a forward slash: C(db.table:priv/db.table:priv)."
      - The format is based on MySQL C(GRANT) statement.
      - Database and table names can be quoted, MySQL-style.
      - If column privileges are used, the C(priv1,priv2) part must be
        exactly as returned by a C(SHOW GRANT) statement. If not followed,
        the module will always report changes. It includes grouping columns
        by permission (C(SELECT(col1,col2)) instead of C(SELECT(col1),SELECT(col2))).
      - Can be passed as a dictionary (see the examples).
      - Supports GRANTs for procedures and functions
        (see the examples for the M(community.mysql.mysql_user) module).
    type: raw

  append_privs:
    description:
      - Append the privileges defined by the I(priv) option to the existing ones
        for this role instead of overwriting them. Mutually exclusive with I(subtract_privs).
    type: bool
    default: false

  subtract_privs:
    description:
      - Revoke the privileges defined by the I(priv) option and keep other existing privileges.
        If set, invalid privileges in I(priv) are ignored.
        Mutually exclusive with I(append_privs).
    version_added: '3.2.0'
    type: bool
    default: false

  members:
    description:
      - List of members of the role.
      - For users, use the format C(username@hostname).
        Always specify the hostname part explicitly.
      - For roles, use the format C(rolename).
      - Mutually exclusive with I(admin).
    type: list
    elements: str

  append_members:
    description:
      - Add members defined by the I(members) option to the existing ones
        for this role instead of overwriting them.
      - Mutually exclusive with the I(detach_members) and I(admin) option.
    type: bool
    default: false

  detach_members:
    description:
      - Detaches members defined by the I(members) option from the role
        instead of overwriting all the current members.
      - Mutually exclusive with the I(append_members) and I(admin) option.
    type: bool
    default: false

  set_default_role_all:
    description:
      - Is not supported by MariaDB and is silently ignored when working with MariaDB.
      - If C(yes), runs B(SET DEFAULT ROLE ALL TO) each of the I(members) when changed.
      - If you want to avoid this behavior, set this option to C(no) explicitly.
    type: bool
    default: true

  state:
    description:
      - If C(present) and the role does not exist, creates the role.
      - If C(present) and the role exists, does nothing or updates its attributes.
      - If C(absent), removes the role.
    type: str
    choices: [ absent, present ]
    default: present

  check_implicit_admin:
    description:
      - Check if mysql allows login as root/nopassword before trying supplied credentials.
      - If success, passed I(login_user)/I(login_password) will be ignored.
    type: bool
    default: false

  members_must_exist:
    description:
      - When C(yes), the module fails if any user in I(members) does not exist.
      - When C(no), users in I(members) which don't exist are simply skipped.
    type: bool
    default: true

  column_case_sensitive:
    description:
      - The default is C(false).
      - When C(true), the module will not uppercase the field in the privileges.
      - When C(false), the field names will be upper-cased. This was the default before this
        feature was introduced but since MySQL/MariaDB is case sensitive you should set this
        to C(true) in most cases.
    type: bool
    version_added: '3.8.0'

notes:
  - Roles are supported since MySQL 8.0.0 and MariaDB 10.0.5.
  - Pay attention that the module runs C(SET DEFAULT ROLE ALL TO)
    all the I(members) passed by default when the state has changed.
    If you want to avoid this behavior, set I(set_default_role_all) to C(no).

attributes:
  check_mode:
    support: full

seealso:
  - module: community.mysql.mysql_user
  - name: MySQL role reference
    description: Complete reference of the MySQL role documentation.
    link: https://dev.mysql.com/doc/refman/8.0/en/create-role.html

author:
  - Andrew Klychkov (@Andersson007)
  - Felix Hamme (@betanummeric)
  - kmarse (@kmarse)
  - Laurent Indermühle (@laurent-indermuehle)

extends_documentation_fragment:
  - community.mysql.mysql
al  
# If you encounter the "Please explicitly state intended protocol" error,
# use the login_unix_socket argument, for example, login_unix_socket: /run/mysqld/mysqld.sock

# Example of a .my.cnf file content for setting a root password
# [client]
# user=root
# password=n<_665{vS43y
#
# Example of a privileges dictionary passed through the priv option
# priv:
#   'mydb.*': 'INSERT,UPDATE'
#   'anotherdb.*': 'SELECT'
#   'yetanotherdb.*': 'ALL'
#
# You can also use the string format like in the community.mysql.mysql_user module, for example
# mydb.*:INSERT,UPDATE/anotherdb.*:SELECT/yetanotherdb.*:ALL
#
# For more examples on how to specify privileges, refer to the community.mysql.mysql_user module

# Create a role developers with all database privileges
# and add alice and bob as members.
# The statement 'SET DEFAULT ROLE ALL' to them will be run.
- name: Create role developers, add members
  community.mysql.mysql_role:
    name: developers
    state: present
    priv: '*.*:ALL'
    members:
    - 'alice@%'
    - 'bob@%'

- name: Same as above but do not run SET DEFAULT ROLE ALL TO each member
  community.mysql.mysql_role:
    name: developers
    state: present
    priv: '*.*:ALL'
    members:
    - 'alice@%'
    - 'bob@%'
    set_default_role_all: false

# Assuming that the role developers exists,
# add john to the current members
- name: Add members to an existing role
  community.mysql.mysql_role:
    name: developers
    state: present
    append_members: true
    members:
    - 'joe@localhost'

# Create role readers with the SELECT privilege
# on all tables in the fiction database
- name: Create role developers, add members
  community.mysql.mysql_role:
    name: readers
    state: present
    priv: 'fiction.*:SELECT'

# Assuming that the role readers exists,
# add the UPDATE privilege to the role on all tables in the fiction database
- name: Create role developers, add members
  community.mysql.mysql_role:
    name: readers
    state: present
    priv: 'fiction.*:UPDATE'
    append_privs: true

- name: Create role with the 'SELECT' and 'UPDATE' privileges in db1 and db2
  community.mysql.mysql_role:
    state: present
    name: foo
    priv:
      'db1.*': 'SELECT,UPDATE'
      'db2.*': 'SELECT,UPDATE'

- name: Remove joe from readers
  community.mysql.mysql_role:
    state: present
    name: readers
    members:
    - 'joe@localhost'
    detach_members: true

- name: Remove the role readers if exists
  community.mysql.mysql_role:
    state: absent
    name: readers

- name: Example of using login_unix_socket to connect to the server
  community.mysql.mysql_role:
    name: readers
    state: present
    login_unix_socket: /var/run/mysqld/mysqld.sock

# Pay attention that the admin cannot be changed later
# and will be ignored if a role currently exists.
# To change members, you need to run a separate task using the admin
# of the role as the login_user.
- name: On MariaDB, create the role readers with alice as its admin
  community.mysql.mysql_role:
    state: present
    name: readers
    admin: 'alice@%'

- name: Create the role business, add the role marketing to members
  community.mysql.mysql_role:
    state: present
    name: business
    members:
    - marketing

- name: Ensure the role foo does not have the DELETE privilege
  community.mysql.mysql_role:
    state: present
    name: foo
    subtract_privs: true
    priv:
      'db1.*': DELETE

- name: Add some members to a role and skip not-existent users
  community.mysql.mysql_role:
    state: present
    name: foo
    append_members: true
    members_must_exist: false
    members:
    - 'existing_user@localhost'
    - 'not_existing_user@localhost'

- name: Detach some members from a role and ignore not-existent users
  community.mysql.mysql_role:
    state: present
    name: foo
    detach_members: true
    members_must_exist: false
    members:
    - 'existing_user@localhost'
    - 'not_existing_user@localhost'
#)AnsibleModule)mysql_connectmysql_drivermysql_driver_fail_msgmysql_common_argument_spec)convert_priv_dict_to_strget_user_implementationget_modeuser_modprivileges_grantprivileges_unpack)	to_native)	iteritemsc                    g }|D ]  }	 |j                  d      }|d   dk(  r| j                  d       t        |      dk(  r0|s|j                  |d   df       n>|j                  |d   df       n't        |      dk(  r|j                  |d   |d   f        |S # t        $ r.}d	|d
t        |      d}| j                  |       Y d}~d}~ww xY w)a  Normalize passed user names.

    Example of transformation:
    ['user0'] => [('user0', '')] / ['user0'] => [('user0', '%')]
    ['user0@host0'] => [('user0', 'host0')]

    Args:
        module (AnsibleModule): Object of the AnsibleModule class.
        users (list): List of user names.
        is_mariadb (bool): Flag indicating we are working with MariaDB

    Returns:
        list: List of tuples like [('user0', ''), ('user0', 'host0')].
    @r    zMember's name cannot be empty.msg   %   z&Error occured while parsing the name "z": z=. It must be in the format "username" or "username@hostname" N)split	fail_jsonlenappend	Exceptionr   )moduleusers
is_mariadbnormalized_usersusertmper   s           n/home/dcms/DCMS/lib/python3.12/site-packages/ansible_collections/community/mysql/plugins/modules/mysql_role.pynormalize_usersr)   C  s      &	&**S/C1v|  %E F3x1}!$++SVSM:$++SVRL9SQ ''QQ(89&,   	& .29Q<AC %%		&s   BB	C&$CCc                   F    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zy)DbServera  Class to fetch information from a database.

    Args:
        module (AnsibleModule): Object of the AnsibleModule class.
        cursor (cursor): Cursor object of a database Python connector.

    Attributes:
        module (AnsibleModule): Object of the AnsibleModule class.
        cursor (cursor): Cursor object of a database Python connector.
        role_impl (library): Corresponding library depending
            on a server type (MariaDB or MySQL)
        mariadb (bool): True if MariaDB, False otherwise.
        roles_supported (bool): True if roles are supported, False otherwise.
        users (set): Set of users existing in a DB in the form (username, hostname).
    c                    || _         || _        | j                         | _        | j                  j	                         | _        | j                  j                  | j                        | _        t        | j                               | _
        y N)r!   cursorget_implementation	role_implr#   mariadbsupports_rolesroles_supportedset_DbServer__get_usersr"   )selfr!   r.   s      r(   __init__zDbServer.__init__}  sd    002~~002#~~<<T[[I))+,
    c                     | j                   S )zyGet info whether a DB server is a MariaDB instance.

        Returns:
            self.mariadb: Attribute value.
        )r1   r6   s    r(   r#   zDbServer.is_mariadb  s     ||r8   c                     | j                   S )zzGet info whether a DB server supports roles.

        Returns:
            self.roles_supported: Attribute value.
        )r3   r:   s    r(   r2   zDbServer.supports_roles  s     ###r8   c                     | j                   j                  d       d| j                   j                         d   j                         v rddlmc mc mc mc m	c m
c m} |S ddlmc mc mc mc m	c mc m} |S )zGet a current server implementation depending on its type.

        Returns:
            library: Depending on a server type (MySQL or MariaDB).
        zSELECT VERSION()r1   r   N)r.   executefetchonelowerUansible_collections.community.mysql.plugins.module_utils.implementations.mariadb.role	communitymysqlpluginsmodule_utilsimplementationsr1   roleSansible_collections.community.mysql.plugins.module_utils.implementations.mysql.role)r6   r0   s     r(   r/   zDbServer.get_implementation  s]     	./,,.q17799uuu  tssr8   c                     |D ]<  }|| j                   vsd|d   d|d   d}| j                  j                  |       > y)zCheck if users exist in a database.

        Args:
            users (list): List of tuples (username, hostname) to check.
        zUser / role `r   z` with host `r   z` does not existr   N)r"   r!   r   )r6   r"   r%   r   s       r(   check_users_in_dbzDbServer.check_users_in_db  sI      	/D4::%JNq'SWXYSZ[%%#%.	/r8   c              #   @   K   |D ]  }|| j                   v s|  y wr-   r"   )r6   r"   r%   s      r(   filter_existing_userszDbServer.filter_existing_users  s&      	Dtzz!
	s   c                 l    | j                   j                  d       | j                   j                         S )z\Get users.

        Returns:
            list: List of tuples (username, hostname).
        z!SELECT User, Host FROM mysql.userr.   r=   fetchallr:   s    r(   __get_userszDbServer.__get_users  s*     	?@{{##%%r8   c                     | j                   S )z|Get set of tuples (username, hostname) existing in a DB.

        Returns:
            self.users: Attribute value.
        rK   r:   s    r(   	get_userszDbServer.get_users  s     zzr8   c                     |r| j                   j                  d||f       n| j                   j                  d|f       | j                   j                         S )zGet grants.

        Args:
            user (str): User name
            host (str): Host name

        Returns:
            list: List of tuples like [(grant1,), (grant2,), ... ].
        zSHOW GRANTS FOR %s@%szSHOW GRANTS FOR %srN   )r6   r%   hosts      r(   
get_grantszDbServer.get_grants  sJ     KK 7$FKK 4tg>{{##%%r8   N)__name__
__module____qualname____doc__r7   r#   r2   r/   rI   rL   r5   rR   rU    r8   r(   r+   r+   m  s4    -$	/
&&r8   r+   c                   0    e Zd ZdZd Zd Zd Zd ZddZy)	MySQLQueryBuilderzClass to build and return queries specific to MySQL.

    Args:
        name (str): Role name.
        host (str): Role host.

    Attributes:
        name (str): Role name.
        host (str): Role host.
    c                      || _         || _        y r-   namerT   )r6   r_   rT   s      r(   r7   zMySQLQueryBuilder.__init__  s    		r8   c                 6    d| j                   | j                  ffS )zReturn a query to check if a role with self.name and self.host exists in a database.

        Returns:
            tuple: (query_string, tuple_containing_parameters).
        z=SELECT count(*) FROM mysql.user WHERE user = %s AND host = %sr^   r:   s    r(   role_existszMySQLQueryBuilder.role_exists  s#     OQUQZQZ\`\e\ePfffr8   c                     |d   r"d| j                   | j                  |d   |d   ffS d| j                   | j                  |d   ffS )zReturn a query to grant a role to a user or a role.

        Args:
            user (tuple): User / role to grant the role to in the form (username, hostname).

        Returns:
            tuple: (query_string, tuple_containing_parameters).
        r   zGRANT %s@%s TO %s@%sr   zGRANT %s@%s TO %sr^   r6   r%   s     r(   
role_grantzMySQLQueryBuilder.role_grant  sN     7)DIItyy$q'4PQ7+SSS&DIItAw(GGGr8   c                     |d   r"d| j                   | j                  |d   |d   ffS d| j                   | j                  |d   ffS )Return a query to revoke a role from a user or role.

        Args:
            user (tuple): User / role to revoke the role from in the form (username, hostname).

        Returns:
            tuple: (query_string, tuple_containing_parameters).
        r   zREVOKE %s@%s FROM %s@%sr   zREVOKE %s@%s FROM %sr^   rc   s     r(   role_revokezMySQLQueryBuilder.role_revoke  sN     7,tyy$))T!WdSTg.VVV)DIItyy$q'+JJJr8   Nc                      d| j                   ffS )a  Return a query to create a role.

        Args:
            admin (tuple): Admin user in the form (username, hostname).
                Because it is not supported by MySQL, we ignore it.

        Returns:
            tuple: (query_string, tuple_containing_parameters).
        CREATE ROLE %sr_   r6   admins     r(   role_createzMySQLQueryBuilder.role_create
  s      $))--r8   r-   	rV   rW   rX   rY   r7   ra   rd   rg   rm   rZ   r8   r(   r\   r\     s#    	gHK
.r8   r\   c                   0    e Zd ZdZd Zd Zd Zd ZddZy)	MariaDBQueryBuilderzClass to build and return queries specific to MariaDB.

    Args:
        name (str): Role name.

    Attributes:
        name (str): Role name.
    c                     || _         y r-   rj   )r6   r_   s     r(   r7   zMariaDBQueryBuilder.__init__   s	    	r8   c                      d| j                   ffS )zReturn a query to check if a role with self.name exists in a database.

        Returns:
            tuple: (query_string, tuple_containing_parameters).
        zBSELECT count(*) FROM mysql.user WHERE user = %s AND is_role  = 'Y'rj   r:   s    r(   ra   zMariaDBQueryBuilder.role_exists#  s     TVZV_V_Uaaar8   c                 `    |d   rd| j                   |d   |d   ffS d| j                   |d   ffS )zReturn a query to grant a role to a user or role.

        Args:
            user (tuple): User / role to grant the role to in the form (username, hostname).

        Returns:
            tuple: (query_string, tuple_containing_parameters).
        r   zGRANT %s TO %s@%sr   zGRANT %s TO %srj   rc   s     r(   rd   zMariaDBQueryBuilder.role_grant+  sA     7&DGT!W(EEE#diia%999r8   c                 `    |d   rd| j                   |d   |d   ffS d| j                   |d   ffS )rf   r   zREVOKE %s FROM %s@%sr   zREVOKE %s FROM %srj   rc   s     r(   rg   zMariaDBQueryBuilder.role_revoke9  sA     7)DIItAwQ+HHH&DG(<<<r8   Nc                     |sd| j                   ffS |d   rd| j                   |d   |d   ffS d| j                   |d   ffS )zReturn a query to create a role.

        Args:
            admin (tuple): Admin user in the form (username, hostname).

        Returns:
            tuple: (query_string, tuple_containing_parameters).
        ri   r   zCREATE ROLE %s WITH ADMIN %s@%sr   zCREATE ROLE %s WITH ADMIN %srj   rk   s     r(   rm   zMariaDBQueryBuilder.role_createG  sV     #dii\1184tyy%(ERSH6UUU1DIIuQx3HHHr8   r-   rn   rZ   r8   r(   rp   rp     s"    b:=Ir8   rp   c                   (    e Zd ZdZd Zd Zd Zd Zy)MySQLRoleImpla  Class to work with MySQL role implementation.

    Args:
        module (AnsibleModule): Object of the AnsibleModule class.
        cursor (cursor): Cursor object of a database Python connector.
        name (str): Role name.
        host (str): Role host.

    Attributes:
        module (AnsibleModule): Object of the AnsibleModule class.
        cursor (cursor): Cursor object of a database Python connector.
        name (str): Role name.
        host (str): Role host.
    c                 <    || _         || _        || _        || _        y r-   )r!   r.   r_   rT   )r6   r!   r.   r_   rT   s        r(   r7   zMySQLRoleImpl.__init__h  s    		r8   c                     |d   r%| j                   j                  d|d   |d   f       y| j                   j                  d|d   f       y)zRun 'SET DEFAULT ROLE ALL TO' a user.

        Args:
            user (tuple): User / role to run the command against in the form (username, hostname).
        r   zSET DEFAULT ROLE ALL TO %s@%sr   zSET DEFAULT ROLE ALL TO %sN)r.   r=   rc   s     r(   set_default_role_allz"MySQLRoleImpl.set_default_role_alln  sI     7KK ?$q'4PQ7ASTKK <tAwjIr8   c                      y)zYGet a current admin of a role.

        Not supported by MySQL, so ignored here.
        NrZ   r:   s    r(   	get_adminzMySQLRoleImpl.get_adminy  s    
 	r8   c                      y)zSet an admin of a role.

        Not supported by MySQL, so ignored here.

        TODO: Implement the feature if this gets supported.

        Args:
            admin (tuple): Admin user of the role in the form (username, hostname).
        NrZ   rk   s     r(   	set_adminzMySQLRoleImpl.set_admin  s     	r8   NrV   rW   rX   rY   r7   rz   r|   r~   rZ   r8   r(   rw   rw   Y  s    	J
r8   rw   c                   (    e Zd ZdZd Zd Zd Zd Zy)MariaDBRoleImpla  Class to work with MariaDB role implementation.

    Args:
        module (AnsibleModule): Object of the AnsibleModule class.
        cursor (cursor): Cursor object of a database Python connector.
        name (str): Role name.

    Attributes:
        module (AnsibleModule): Object of the AnsibleModule class.
        cursor (cursor): Cursor object of a database Python connector.
        name (str): Role name.
    c                 .    || _         || _        || _        y r-   )r!   r.   r_   )r6   r!   r.   r_   s       r(   r7   zMariaDBRoleImpl.__init__  s    	r8   c                      y)zRun 'SET DEFAULT ROLE ALL TO' a user.

        The command is not supported by MariaDB, ignored.

        Args:
            user (tuple): User / role to run the command against in the form (username, hostname).
        NrZ   rc   s     r(   rz   z$MariaDBRoleImpl.set_default_role_all  s     	r8   c                     d}| j                   j                  || j                  f       | j                   j                         S )znGet a current admin of a role.

        Returns:
            tuple: Of the form (username, hostname).
        zQSELECT User, Host FROM mysql.roles_mapping WHERE Role = %s and Admin_option = 'Y')r.   r=   r_   r>   )r6   querys     r(   r|   zMariaDBRoleImpl.get_admin  s8    : 	EDII<0{{##%%r8   c                     |d   }|d   }| j                         }||f|k7  r+d|d   d|d   d}| j                  j                  |       yy)zSet an admin of a role.

        TODO: Implement changing when ALTER ROLE statement to
            change role's admin gets supported.

        Args:
            admin (tuple): Admin user of the role in the form (username, hostname).
        r   r   z6The "admin" option value and the current roles admin (r   zZ) don not match. Ignored. To change the admin, you need to drop and create the role again.N)r|   r!   warn)r6   rl   
admin_user
admin_hostcurrent_adminr   s         r(   r~   zMariaDBRoleImpl.set_admin  sa     1X
1X
(
#}4 %2!$4mA6FHC KKS! 5r8   Nr   rZ   r8   r(   r   r     s    

&"r8   r   c                   b    e Zd ZdZd Zd Z	 	 ddZddZ	 	 ddZddZ	ddZ
	 	 	 	 dd	Zd
 Zy)Rolea  Class to work with MySQL role objects.

    Args:
        module (AnsibleModule): Object of the AnsibleModule class.
        cursor (cursor): Cursor object of a database Python connector.
        name (str): Role name.
        server (DbServer): Object of the DbServer class.

    Attributes:
        module (AnsibleModule): Object of the AnsibleModule class.
        cursor (cursor): Cursor object of a database Python connector.
        name (str): Role name.
        server (DbServer): Object of the DbServer class.
        host (str): Role's host.
        full_name (str): Role's full name.
        exists (bool): Indicates if a role exists or not.
        members (set): Set of current role's members.
    c                    || _         || _        || _        || _        | j                  j	                         | _        | j                  rft        | j                        | _        t        | j                   | j                  | j                        | _        d| j                  z  | _	        d| _
        nd| _
        t        | j                  | j                        | _        t        | j                   | j                  | j                  | j                        | _        d| j                  d| j                  d| _	        | j                         | _        t               | _        | j                  r| j#                         | _        y y )Nz`%s`r   r   `z`@`)r!   r.   r_   serverr#   rp   	q_builderr   r0   	full_namerT   r\   rw   _Role__role_existsexistsr4   members_Role__get_members)r6   r!   r.   r_   r   s        r(   r7   zRole.__init__  s   	++002??0;DN,T[[$++tyyQDN#dii/DNDIDI.tyy$))DDN*4;;TYYPTPYPYZDN,0IItyyADN((*u;;--/DL r8   c                      | j                   j                  | j                  j                           | j                   j	                         d   dkD  S )zsCheck if a role exists.

        Returns:
            bool: True if the role exists, False if it does not.
        r   )r.   r=   r   ra   r>   r:   s    r(   __role_existszRole.__role_exists  sB     	T^^779:{{##%a(1,,r8   c           
      P   |r| j                   syy | j                  j                  | j                  j	                  |        |r| j                  ||       |rMt        |      D ]?  \  }}t        | j                  | j                  | j                  ||d| j                         A y)a  Add a role.

        Args:
            users (list): Role members.
            privs (str): String containing privileges.
            check_mode (bool): If True, just checks and does nothing.
            admin (tuple): Role's admin. Contains (username, hostname).
            set_default_role_all (bool): If True, runs SET DEFAULT ROLE ALL TO each member.

        Returns:
            bool: True if the state has changed, False if has not.
        TF)rz   N)tls_requires
maria_role)r   r.   r=   r   rm   update_membersr   r   r_   rT   r#   )r6   r"   privs
check_moderl   rz   db_tableprivs           r(   addzRole.add  s     ;;T^^77>?<PQ"+E"2 =$ dii!)4d,0OO==
 r8   c                     | j                   sy|r| j                   ry| j                  j                  d| j                  f       y)zDrop a role.

        Args:
            check_mode (bool): If True, just checks and does nothing.

        Returns:
            bool: True if the state has changed, False if has not.
        FTzDROP ROLE %s)r   r.   r=   r_   )r6   r   s     r(   dropz	Role.drop  s7     {{$++NTYYL9r8   c                 J   |syd}|D ]f  }|| j                   vs|r y | j                  j                  | j                  j	                  |        |r| j
                  j                  |       d}h |r|S | j                   D ]  }||vs|dk7  s| j                  ||      }! |S )a  Add users to a role.

        Args:
            users (list): Role members.
            check_mode (bool): If True, just checks and does nothing.
            append_members (bool): If True, adds new members passed through users
                not touching current members.
            set_default_role_all (bool): If True, runs SET DEFAULT ROLE ALL TO each member.

        Returns:
            bool: True if the state has changed, False if has not.
        FT)root	localhost)r   r.   r=   r   rd   r0   rz   _Role__remove_member)r6   r"   r   append_membersrz   changedr%   s          r(   r   zRole.update_members0  s      
	D4<<'###T^^%>%>t%DE'NN77=
	 NLL 	AD5 T-B%B..tZ@	A r8   c                 `    |syd}|D ]#  }|| j                   v s| j                  ||      }% |S )zRemove members from a role.

        Args:
            users (list): Role members.
            check_mode (bool): If True, just checks and does nothing.

        Returns:
            bool: True if the state has changed, False if has not.
        F)r   r   )r6   r"   r   r   r%   s        r(   remove_memberszRole.remove_membersW  sE      	ADt||#..tZ@	A r8   c                 n    |ry | j                   j                  | j                  j                  |        y)a  Remove a member from a role.

        Args:
            user (str): Role member to remove.
            check_mode (bool): If True, just returns True and does nothing.

        Returns:
            bool: True if the state has changed, False if has not.
        T)r.   r=   r   rg   )r6   r%   r   s      r(   __remove_memberzRole.__remove_memberk  s0     T^^77=>r8   c
                    d}
d}|r+|r| j                  ||      }n| j                  ||||	      }|r|t        di d| j                  d| j                  d| j
                  ddd	dd
dddddddddd|d|d|ddddd| j                  ddddddd| j                  }|d   }
|r| j                  j                  |       |
xs |}
|
S )aJ  Update a role.

        Update a role if needed.

        Todo: Implement changing of role's admin when ALTER ROLE statement
            to do that gets supported.

        Args:
            users (list): Role members.
            privs (str): String containing privileges.
            check_mode (bool): If True, just checks and does nothing.
            append_privs (bool): If True, adds new privileges passed through privs
                not touching current privileges.
            subtract_privs (bool): If True, revoke the privileges passed through privs
                not touching other existing privileges.
            append_members (bool): If True, adds new members passed through users
                not touching current members.
            detach_members (bool): If True, removes members passed through users from a role.
            admin (tuple): Role's admin. Contains (username, hostname).
            set_default_role_all (bool): If True, runs SET DEFAULT ROLE ALL TO each member.

        Returns:
            bool: True if the state has changed, False if has not.
        F)r   )r   r   rz   r.   r%   rT   host_allNpassword	encryptedpluginplugin_auth_stringplugin_hash_stringsaltnew_privappend_privssubtract_privs
attributesr   r!   password_expirepassword_expire_intervalrF   Tr   r   rZ   )
r   r   r   r.   r_   rT   r!   r#   r0   r~   )r6   r"   r   r   r   r   r   detach_membersrl   rz   r   members_changedresults                r(   updatezRole.update|  sr   8 "&"5"5e
"5"S #'"5"5e
ESK_ #6 #a  dT[[ dtyy dtyy d'+d6:dFJdSWd15dJNdUYd (-d <Hd Ygd *.	d =A	d JN	d gk	d
 8<d
 CGd
 TXSbSbdF Y'GNN$$U+,_r8   c                     | j                   r(| j                  j                  d| j                  f       n'| j                  j                  d| j                  f       t	        | j                  j                               S )zPGet current role's members.

        Returns:
            set: Members.
        z:select user, host from mysql.roles_mapping where role = %szRselect TO_USER as user, TO_HOST as host from mysql.role_edges where FROM_USER = %s)r#   r.   r=   r_   r4   rO   r:   s    r(   __get_memberszRole.__get_members  sp     ??KK \_c_h_h^jkKK tw{  xA  xA  wC  D4;;'')**r8   N)FFTF)FFFFFFT)rV   rW   rX   rY   r7   r   r   r   r   r   r   r   r   rZ   r8   r(   r   r     sW    $00- 9>!%@$ FK,0%N(" /42749156p
+r8   r   c                  ~
   t               } | j                  t        dd      t        ddddg      t        d      t        d      t        d	d
      t        d	d
      t        dd      t        d	d
      t        d	d
      t        d	d
      t        d	d      t        d	d      t        d	d              t        | dd      }|j                  d   }|j                  d   }|j                  d   }|j                  d   }|j                  d   }|j                  d   }|j                  d   }|j                  d   }	|j                  d   }
|j                  d   }|j                  |j                  d         }|j                  d   }|j                  d   }|j                  d   }|j                  d   }|j                  d    }|j                  d!   }|j                  d"   }d#}|j                  d$   }|j                  d%   }|j                  d&   }|r6t        |t        t        f      s d't        |      z  }|j                  |(       |rt        |t              rt        |      }t        |j                  t        (       |d
}|j                  d)       d }	 |r	 t        |d*d#|
|||||	|d+      \  }}|st        ||||
|||||	|d+      \  }}d
}t#        |      }|	 t%        |      }	 t'        ||| .      }t)        ||      }|j+                         sd0}|j                  |(       |rD|j-                         s|j                  d1(       t/        ||g      d2   }|j1                  |g       |rIt/        |||j-                               }|r|j1                  |       nt3        |j5                  |            }t7        ||||      } 	 |dk(  rX| j8                  s(|rd }|rd }| j;                  |||j<                  ||      }nD| j                  |||j<                  ||||||	      }n |dk(  r| j?                  |j<                        }|jA                  |3       y # t        $ r Y w xY w# t        $ r,}|j                  d,|
d-t!        |      (       Y d }~d }~ww xY w# t        $ r&}|j                  t!        |      (       Y d }~d }~ww xY w# t        $ r)}|j                  d/t!        |      z  (       Y d }~d }~ww xY w# t        $ r%}|j                  t!        |      (       Y d }~d }~ww xY w)4NstrT)typerequiredpresentabsent)r   defaultchoices)r   rawboolF)r   r   list)r   elements)r_   staterl   r   r   r   r   r   r   check_implicit_adminrz   members_must_existcolumn_case_sensitive))r   r   )rl   r   )rl   r   )rl   r   )r   r   )argument_specsupports_check_modemutually_exclusive
login_userlogin_passwordr_   r   rl   r   r   connect_timeoutconfig_filer   r   r   r   r   client_cert
client_keyca_certcheck_hostnamer   rz   r   r   z:The "priv" parameter must be str or dict but %s was passedr   zOption column_case_sensitive is not provided. The default is now false, so the column's name will be uppercased. The default will be changed to true in community.mysql 4.0.0.r   )r   r   
autocommitzRunable to connect to database, check login_user and login_password are correct or z) has the credentials. Exception message: )ensure_usagezInvalid privileges string: %szZRoles are not supported by the server. Minimal versions are MySQL 8.0.0 or MariaDB 10.0.5.z1The "admin" option can be used only with MariaDB.r   )r   )!r   r   dictr   paramsboolean
isinstancer   r   r   r   r	   r
   r   r   r    r   r   r   r   r+   r2   r#   r)   rI   r   rL   r   r   r   r   r   	exit_json)!r   r!   r   r   r_   r   rl   r   r   r   r   r   r   r   r   r   ssl_certssl_keyssl_car   dbrz   r   r   r   r.   db_connr'   r   implmoder   rF   s!                                    r(   mainr     sl   .0Mut,y8Y:OPuvu57&5177!vu=!vt<VT:"=   # 

F |,J]]#34N== DMM'"EMM'"E== D!==)?@mm$56O--.K==0L^^FMM2B$CDNmmI&G]]#34N]]#34N}}]+HmmL)G]]9%F]]#34N	B!==)?@';<"MM*ABJtc4[1#%)$Z0S!
4&'-23 $ % T 	U FT"/K08'62@O?M;?	#A +FJ,77,2B;I7;	=OFG G"6*D	/F#D	Q$T41FYgUghD ff%F   "ES!  "!TU03  %)!&'63D3D3FG$$W-677@AG f-D+I;;!D!"G((7D&2C2CU#79 ++gtV5F5FVd&4ne&:< hii 1 12G
 W%]    T 9DYq\S 	T 	TT  	/1..	/
  	Q!@9Q<!OPP	Q\  +Yq\**+s   Q/ Q 8Q/ #R' /S A=T 	Q,(Q/ +Q,,Q/ /	R$8!RR$'	S0SS	T"TT	T<T77T<__main__Nr   )$
__future__r   r   r   r   __metaclass__DOCUMENTATIONEXAMPLESRETURNansible.module_utils.basicr   >ansible_collections.community.mysql.plugins.module_utils.mysqlr   r	   r
   r   =ansible_collections.community.mysql.plugins.module_utils.userr   r   r   r   r   r   ansible.module_utils._textr   ansible.module_utils.sixr   r)   r+   r\   rp   rw   r   r   r   rV   rZ   r8   r(   <module>r      s    A @TlL\ 
 4   1 .'Tg& g&T=. =.@?I ?ID1 1h:" :"zt+ t+n]&@ zF r8   