如何编写幂等性Ansible代码创建MySQL用户避免重复创建
问题
我用Ansible脚本创建管理数据库的MySQL用户,当前通过随机方式生成用户名和密码:
- set_fact: wp_db_user: "{{ lookup('password', '/dev/null length=10 chars=ascii_letters') }}"
- set_fact: wp_db_password: "{{ lookup('password', '/dev/null length=20 chars=ascii_letters,hexdigits') }}"
并通过以下代码创建用户:
- name: Create mysql user community.mysql.mysql_user: login_user: root login_unix_socket: /var/run/mysqld/mysqld.sock name: "{{ wp_db_user }}" password: "{{ wp_db_password }}" priv: "{{ wp_db_name }}.*:ALL"
首次执行正常,但重复执行同一远程服务器时,每次都会生成新用户,请问如何避免重复创建不同用户?
解决方案
方法1:基于主机唯一标识生成固定用户名+本地存储密码
核心思路是用目标主机的唯一标识(比如主机名)生成固定用户名,同时把密码存储到本地文件,避免每次执行重新生成。
# 利用主机名哈希生成固定后缀的用户名,同一主机每次执行结果一致 - set_fact: wp_db_user: "wp_admin_{{ ansible_hostname | hash('md5') | truncate(8, True, '') }}" # 密码存储到本地文件,第一次生成后后续执行直接读取文件内容 - set_fact: wp_db_password: "{{ lookup('password', '~/mysql_creds/{{ ansible_hostname }}_wp.pass length=20 chars=ascii_letters,hexdigits') }}" - name: Ensure mysql user exists community.mysql.mysql_user: login_user: root login_unix_socket: /var/run/mysqld/mysqld.sock name: "{{ wp_db_user }}" password: "{{ wp_db_password }}" priv: "{{ wp_db_name }}.*:ALL" state: present # 用户已存在时不会重复创建,仅确保权限正确
方法2:先查询MySQL是否存在目标用户
先检查目标主机的MySQL中是否已有对应数据库的全权限用户,存在则复用,不存在再生成新用户。
# 查询是否已有对应数据库的管理员用户 - name: Check existing wp db admin user community.mysql.mysql_query: login_user: root login_unix_socket: /var/run/mysqld/mysqld.sock query: "SELECT user FROM mysql.user u JOIN mysql.db d ON u.user = d.user WHERE d.Db = '{{ wp_db_name }}' AND d.Privilege = 'ALL PRIVILEGES'" register: existing_user # 仅当无匹配用户时生成新的用户名和密码 - set_fact: wp_db_user: "{{ lookup('password', '/dev/null length=10 chars=ascii_letters') }}" when: existing_user.rowcount == 0 - set_fact: wp_db_password: "{{ lookup('password', '/dev/null length=20 chars=ascii_letters,hexdigits') }}" when: existing_user.rowcount == 0 # 创建或确认用户存在:已有用户则直接复用,无则创建 - name: Manage mysql user community.mysql.mysql_user: login_user: root login_unix_socket: /var/run/mysqld/mysqld.sock name: "{{ wp_db_user | default(existing_user.rows[0][0]) }}" password: "{{ wp_db_password | default(omit) }}" # 已有用户时不修改密码 priv: "{{ wp_db_name }}.*:ALL" state: present
方法3:将凭据存储在目标主机本地
在目标主机上保存生成的用户名和密码文件,每次执行优先读取文件内容,不存在再生成并写入。
# 尝试读取目标主机上的凭据文件 - name: Read existing wp credentials from target host slurp: src: /etc/wp_db_creds.txt register: saved_creds ignore_errors: true # 解析已存储的凭据 - set_fact: wp_db_user: "{{ (saved_creds.content | b64decode).split('\n')[0] }}" wp_db_password: "{{ (saved_creds.content | b64decode).split('\n')[1] }}" when: saved_creds is succeeded # 无凭据文件时生成新的用户名和密码 - set_fact: wp_db_user: "{{ lookup('password', '/dev/null length=10 chars=ascii_letters') }}" when: saved_creds is failed - set_fact: wp_db_password: "{{ lookup('password', '/dev/null length=20 chars=ascii_letters,hexdigits') }}" when: saved_creds is failed # 将新凭据写入目标主机文件(仅当文件不存在时) - name: Save wp credentials to target host copy: content: | {{ wp_db_user }} {{ wp_db_password }} dest: /etc/wp_db_creds.txt mode: '0600' # 限制文件权限,避免泄露 when: saved_creds is failed # 确保用户存在 - name: Manage mysql user community.mysql.mysql_user: login_user: root login_unix_socket: /var/run/mysqld/mysqld.sock name: "{{ wp_db_user }}" password: "{{ wp_db_password }}" priv: "{{ wp_db_name }}.*:ALL" state: present
内容的提问来源于stack exchange,提问作者Roberto Jobet
相关产品推荐
相关产品推荐

