You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写幂等性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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 08:50:09