I want to setup a MySQL server on AWS, using Ansible for the configuration management.
I am using the default AMI from Amazon (ami-3275ee5b), which uses yum
For ansible 1.3+ :
- name: ensure mysql local root password is zwx123
mysql_user: check_implicit_admin=True login_user=root login_password="zwx123" name=root password="zwx123" state=present
We have spent a lot of time on this issue. For MySQL 5.7 and above we concluded it is easier to simply ignore the root account, and set permissions on a regular MySQL user.
unix_socket
auth plugin conflicts with the standard auth pluginunix_socket
plugin is almost impossibleIf you abandon idempotency, then you can get it to work fine. However, since the ansible value proposition is that idempotency is possible, we find that developers waste time with the wrong assumption.
The mere existence of a hack option like check_implicit_admin
starts to hint to us that deterministic MySQL setup is not that easy. If it's actually deterministic, there should be no "check", there should only be "do".
This is an alternative solution to the one proposed by @LorinHochStein
One of my constraints was to ensure that no passwords are stored in plain text files anywhere on the server. Thus .my.cnf was not a practical proposition
Solution :
- name: update mysql root password for all root accounts from local servers
mysql_user: login_user=root
login_password={{ current_password }}
name=root
host=$item
password={{ new_password }}
priv=*.*:ALL,GRANT
with_items:
- $ansible_hostname
- 127.0.0.1
- ::1
- localhost
And in the vars file
current_password: foobar
new_password: "{{ current_password }}"
When not changing the mysql password run ansible playbook on command line as usual.
When changing the mysql password, add the following to the command line. Specifying it on the commandline allows the parameter set on the command line to take precedence over the one defaulted to in the vars file.
$ ansible-playbook ........ --extra-vars "new_password=buzzz"
After running the command change the vars file as follows
current_password=buzzz
new_password={{ current_password }}
Adding to the previous answers, I didn't want a manual step before running the command, ie I want to spin up a new server and just run the playbook without having to manually change the root password first time. I don't believe {{ mysql_password }} will work the first time, when root password is null, because mysql_password still has to be defined somewhere (unless you want to override it with -e).
So I added a rule to do that, which is ignored if it fails. This is in addition to, and appears before, any of the other commands here.
- name: Change root user password on first run
mysql_user: login_user=root
login_password=''
name=root
password={{ mysql_root_password }}
priv=*.*:ALL,GRANT
host={{ item }}
with_items:
- $ansible_hostname
- 127.0.0.1
- ::1
- localhost
ignore_errors: true
The following will Work (Insert my.cnf in between 2 mysql_user calls)
- name: 'Install MySQL'
yum: name={{ item }} state=present
with_items:
- MySQL-python
- mysql
- mysql-server
notify:
- restart-mysql
- name: 'Start Mysql Service'
action: service name=mysqld state=started enabled=yes
- name: 'Update Mysql Root Password'
mysql_user: name=root host=localhost password={{ mysql_root_password }} state=present
- name: 'Copy Conf file with root password credentials'
template: src=../templates/my.cnf.j2 dest=/root/.my.cnf owner=root mode=0600
- name: 'Update Rest-Mysql Root Password'
mysql_user: name=root host={{ item }} password={{ mysql_root_password }} state=present
with_items:
- "{{ ansible_hostname }}"
- "{{ ansible_eth0.ipv4.address }}"
- 127.0.0.1
- ::1
- name: 'Delete anonymous MySQL server user from server'
mysql_user: name="" host={{ ansible_hostname }} state="absent"