Since 2 weeks, I'm working on MySQL deployment and stuff with Ansible. I have to install MySQL on a LV.
Before MySQL deployment, Ansible script creates /var/lib/mysql, LV and mount it on /var/lib/mysql. Then, it create MySQL user and MySQL group to set 0700 right on MySQL directory. When it done, Ansible deploy MySQL 5.7.
Part of my Ansible code :
- name: "Group : mysql"
group:
name: "mysql"
state: "present"
tags:
- User mysql
- name: "user : mysql"
user:
name: "mysql"
shell: "mysql"
group: "mysql"
createhome: "no"
append: "True"
state: "present"
tags:
- User
- name: "Set rights on mysql dir "
file:
path: "/var/lib/mysql"
owner: "mysql"
group: "mysql"
mode: 0700
tags:
- mysql dir rights
- name: "mysql root password"
debconf:
name: "mysql-server"
question: "mysql-server/root_password"
value: "{{ password_root_mysql }}"
vtype: "password"
when: password_root_mysql is defined
tags:
- Install
- name: "mysql root password confirmation"
debconf:
name: "mysql-server"
question: "mysql-server/root_password_again"
value: "{{ password_root_mysql }}"
vtype: "password"
when: password_root_mysql is defined
tags:
- Install mysql
- name: "Install : MySQL Server"
apt:
update_cache: "True"
name: "mysql-server"
install_recommends: "True"
tags:
- Install mysql
notify:
- stop mysql
- name: "Copie du template root.cnf.j2 vers root/.my.cnf "
template:
src: "{{ mysql_template_rootcnf }}"
dest: "~/.my.cnf"
owner: "root"
mode: "0600"
tags:
- Install mysql
So when I try to install mysql-server without any LV and directory settings, it works. But when I prepare directory MySQL with good rights, installation doesn't work, whether manual or automatic deployment.
Any ideas ?
Ubuntu 16.04 with MYSQL 5.7.
Ansible v2.7
Ok, I've found the problem, Lost+Found directory in /var/lib/mysql (lv mounted on it) is considerated like a database, mysql doesn't like it. In my code, ive just added :
- name: "Remove lost+found from {{ mysql_dir }}"
file:
path: "{{ mysql_dir }}/lost+found"
state: absent
Related
Hope y'all are enjoying the holidays. I am attempting an automated installation of wordpress on my Linux VM using ansible. To that end, I have written this ansible piece of code that tries to mimic the official ubuntu guide.
Here is the code:
- name: "Installing wordpress dependencies"
hosts: all
become: True
gather_facts: True
vars:
get_installer: 'curl -sS https://getcomposer.org/installer -o /tmp/composer-setup.php || /bin/true'
get_signature: 'curl -sS https://composer.github.io/installer.sig'
tasks:
- name: "Update repository"
apt:
update_cache: "yes"
- name: "Installing requirements"
apt:
name:
- "curl"
- "php"
- "php-cli"
- "gnupg"
- "unzip"
- "mysql-server"
- "php-fpm"
- "php-mysql"
- "apache2"
- "ghostscript"
- "libapache2-mod-php"
- "php-bcmath"
- "php-curl"
- "php-imagick"
- "php-intl"
- "php-json"
- "php-mbstring"
- "php-xml"
- "php-zip"
state: present
- name: Populate service facts
ansible.builtin.service_facts:
- name: Print service facts
ansible.builtin.debug:
var: ansible_facts.services
- name: "stopping nginx if running"
service:
name: nginx
state: stopped
when: "'nginx' in ansible_facts.services"
- name: "remove nginx if installed"
apt:
name:
- "nginx"
state: absent
- name: stop Mysql
service:
name: mysql
state: stopped
when: "'mysql' in ansible_facts.services"
- name: stop apache2
service:
name: apache2
state: stopped
when: "'apache2' in ansible_facts.services"
- name: Installing wordpress through source
hosts: all
become: True
gather_facts: False
vars:
wprootdir: "/srv/www/wordpress"
tasks:
- name: checking if wp src dir exists
stat:
path: "{{ wprootdir }}"
register: dir_details
- name: delete existing wordpress source files
become_user: www-data
no_log: True
file:
#path: "{{ item.path }}"
#recurse: True
path: "{{ wprootdir }}"
state: absent
#with_items: "{{ path_list.files }}"
- name: creating /var/www for wordpress source
file:
#path: "'{{ wp-root-dir }}' + 'wordpress'"
path: "/srv/www/wordpress"
recurse: yes
state: directory
owner: www-data
mode: '0755'
- name: downloading and extracting wordpress source
shell:
cmd: "curl https://wordpress.org/latest.tar.gz | sudo -u www-data tar zx -C /srv/www"
register: status
- fail:
msg: "Unable to download or extract wordpress source"
when: (status.rc != 0)
- name: Configuring apache for wordpress
hosts: all
become: True
gather_facts: False
vars:
wprootdir: "/srv/www/wordpress"
wpconffile: "/etc/apache2/sites-available/wordpress.conf"
tasks:
- name: deleting the file if it exists
file:
path: "{{ wpconffile }}"
state: absent
- name: creating wordpress conf file
file:
path: "{{ wpconffile }}"
state: touch
owner: www-data
- name: populating wordpress conf file
template:
src: apache2.j2
dest: "{{ wpconffile }}"
- name: enabling the site
shell:
cmd: "a2ensite wordpress"
- name: enable URL rewriting
shell:
cmd: "a2enmod rewrite"
- name: disable default "it works" site
shell:
cmd: "a2dissite 000-default"
- name: restart apache2
service:
name: apache2
state: reloaded
- name: Configuring database
hosts: all
become: True
gather_facts: True
#gather_facts: yes
vars:
mysql_port: 3306
mysql_socket: /var/run/mysqld/mysqld.sock
mysql_superuser: root
mysql_superuser_home: "{% if mysql_superuser == 'root' %}/root{% else %}/home/{{ mysql_superuser }}{% endif %}"
mysql_superuser_password: SuperUserPwd
mysql_wordpress_password: WordpressPwd
http_port: 80
tasks:
- name: Installing PyMySql through pip
pip:
name: PyMySql
state: present
- name: ensure mysql is running and starts on boot
service:
name: mysql
state: started
enabled: True
- name: Removes anonymous user account for localhost
community.mysql.mysql_user:
name: ''
state: absent
login_user: root
login_password: ""
login_unix_socket: "{{ mysql_socket }}"
when: ansible_local.mysqlinfo is undefined
- name: adding a password for root user
mysql_user:
# Update the superuser to have all grants and a password
name: "{{ mysql_superuser }}"
host: localhost
password: "{{ mysql_superuser_password }}"
priv: "*.*:ALL,GRANT"
# Login *as root* to perform this change, even though you might
# be altering the root user itself
login_user: root
login_password: ""
login_port: "{{ mysql_port }}"
login_host: localhost
login_unix_socket: "{{ mysql_socket }}"
# As a good measure,have ansible check whether an implicit login
# is possible first
check_implicit_admin: yes
when: ansible_local.mysqlinfo is undefined
- name: "Create custom fact directory"
file:
path: "/etc/ansible/facts.d"
state: "directory"
recurse: yes
when: ansible_local.mysqlinfo is undefined
- name: "record mysql info in custom fact"
template:
src: mysqlinfo.j2
dest: /etc/ansible/facts.d/mysqlinfo.fact
mode: 0644
when: ansible_local.mysqlinfo is undefined
- name: "re-run setup to use custom facts"
setup:
filter: ansible_local
when: ansible_local.mysqlinfo is undefined
- debug:
msg:
- "mysqlinfo is {{ ansible_local.mysqlinfo }}"
when: ansible_local.mysqlinfo is defined
#- name: Create system-wide mysql configuration file
#template:
#src: mysql_sys.cnf.j2
#dest: /etc/my.cnf
#- name: Create mysql configuration file for `{{ mysql_superuser }}`
#template:
#src: mysql_superuser.cnf.j2
#dest: "{{ mysql_superuser_home }}/.my.cnf"
- name: create database wordpress
mysql_db:
db: wordpress
state: present
login_user: "{{ ansible_local.mysqlinfo.mysql_superuser }}"
login_password: "{{ ansible_local.mysqlinfo.mysql_superuser_password }}"
login_unix_socket: "{{ mysql_socket }}"
when: ansible_local.mysqlinfo is defined
- name: Create database user 'wordpress' with all database privileges
community.mysql.mysql_user:
name: wordpress
password: "{{ mysql_wordpress_password }}"
login_user: "{{ ansible_local.mysqlinfo.mysql_superuser }}"
login_password: "{{ ansible_local.mysqlinfo.mysql_superuser_password }}"
priv: '*.*:ALL'
state: present
when: ansible_local.mysqlinfo is defined
- name: Flush privileges
mysql_query:
login_db: wordpress
login_user: "{{ ansible_local.mysqlinfo.mysql_superuser }}"
login_password: "{{ ansible_local.mysqlinfo.mysql_superuser_password }}"
login_unix_socket: "{{ mysql_socket }}"
query: FLUSH PRIVILEGES
# UFW Configuration
- name: "UFW - Allow HTTP on port {{ http_port }}"
ufw:
rule: allow
port: "{{ http_port }}"
proto: tcp
notify:
- Restart Mysql
tags: [ system ]
handlers:
- name: Restart Mysql
service:
name: mysql
state: restarted
- name: Restart Apache2
service:
name: apache2
state: restarted
- name: Configuring wordpress to connect to the database
hosts: all
gather_facts: False
become: true
vars:
wpconfigfile: "/srv/www/wordpress/wp-config.php"
tasks:
- name: copy sample config to wp-config.php
#become_user: www-data
copy:
remote_src: yes
src: /srv/www/wordpress/wp-config-sample.php
dest: "{{ wpconfigfile }}"
owner: www-data
- name: "re-run setup to use custom facts"
setup:
filter: ansible_local
- name: set database credentials in the config file
become: false
#become_user: www-data
#become_method: "su"
# multiple commands are run like this whereas with
# single command one can use a cmd paramater
# since this is technically *not* a list passed to /bin/sh
# we do not need a list here. Instead it is a series of
# commands being passed to /bin/sh
#shell: |
# apparently, passing this list directly doesn't seem to work
# what works is this loop
command: "{{ item }}"
with_items:
- "sudo -u www-data sed -i s/database_name_here/wordpress/ {{ wpconfigfile }}"
- "sudo -u www-data sed -i s/username_here/wordpress/ {{ wpconfigfile }}"
- "sudo -u www-data sed -i s/password_here/{{ ansible_local.mysqlinfo.mysql_wordpress_password }}/ {{ wpconfigfile }}"
- name: get random secret keys
uri:
url: https://api.wordpress.org/secret-key/1.1/salt/
return_content: yes
body_format: json
register: wordpress_keys
- debug:
var: wordpress_keys.content
- name: delete existing bak file
file:
path: "{{ wpconfigfile }}.bak"
state: absent
- name: run script to remove key placeholders
become_user: www-data
script:
chdir: /srv/www/wordpress/
cmd: replacelines.py
executable: /usr/bin/python3
environment: /srv/www/wordpress/
- name: update config file
become_user: www-data
copy:
remote_src: yes
src: "{{ wpconfigfile }}.bak"
dest: "{{ wpconfigfile }}"
- blockinfile:
path: "{{ wpconfigfile }}"
marker: // {mark} ANSIBLE MANAGED BLOCK
# having this separator here was giving me issues
#block: |
block:
"{{ wordpress_keys.content }}"
handlers:
- name: Restart Mysql
service:
name: mysql
state: restarted
- name: Restart Apache2
service:
name: apache2
state: restarted
Associated jinja2 template files are here:
Apache2 template:
<VirtualHost *:80>
Servername {{ ansible_hostname }}
DocumentRoot "{{ wprootdir }}"
<Directory "{{ wprootdir }}">
Options FollowSymLinks
AllowOverride Limit Options FileInfo
DirectoryIndex index.php
Require all granted
</Directory>
<Directory "{{ wprootdir }}/wp-content">
Options FollowSymLinks
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
mysqlinfo template
{
"mysql_port": "{{ mysql_port }}",
"mysql_socket": "{{ mysql_socket }}",
"mysql_superuser": "{{ mysql_superuser }}",
"mysql_superuser_password": "{{ mysql_superuser_password }}",
"mysql_wordpress_password": "{{ mysql_wordpress_password }}"
}
replacelines.py script:
import re
with open("wp-config.php", "r") as wpconfig, open("wp-config.php.bak", "w") as wpconfigbak:
for line in wpconfig:
found = re.search(r'AUTH_KEY|SECURE_AUTH_KEY|LOGGED_IN_KEY|NONCE_KEY|AUTH_SALT|SECURE_AUTH_SALT|LOGGED_IN_SALT|NONCE_SALT', line.strip());
if (not found):
wpconfigbak.write(line)
else:
continue
inventory file:
[local]
localhost ansible_connection=local
With this playbook I am able to see the wordpress landing page when I open 'localhost:80/' on my Linux machine. However I am unable to get to the wordpress dashboard. I run the playbook like so: ansible-playbook -i inventory SetupWordpress.yaml
To save time, you may use my github repo:
git clone -b WIP git#github.com:redbilledpanda/DevOpsScripts.git
cd DevOpsScripts && ansible-playbook -i inventory SetupWordpress.yaml
After the playbook completes, I go to http://localhost:80 and I am presented with the installer:
I fill in the details:
Apparently, it succeeds:
When I try logging in, I don't see the dashboard. Instead, I never go past the login screen (it doesn't say incorrect credentials or anything though):
I am at a loss as to what am I doing wrong. Keen to hear from you folks.
UPDATE1: If I skip the part where I generate the wordpress 'salts'/keys it works. I can see the dashboard etc. With these salts however, it just won't get to the wordpress admin dashboard.
Using a minimal sample config file wpconfig.file
<?php
/**
* The base configuration for WordPress
* ...
* Authentication unique keys and salts.
*
* Change these to different unique phrases! You can generate these using
* the {#link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service}.
*
* You can change these at any point in time to invalidate all existing cookies.
* This will force all users to have to log in again.
* ...
*/
and a minimal example playbook
---
- hosts: localhost
become: false
gather_facts: false
tasks:
- name: Get random secret keys
uri:
url: https://api.wordpress.org/secret-key/1.1/salt/
return_content: yes
body_format: json
register: wordpress_keys
- name: Show keys
debug:
var: wordpress_keys.content
- name: Write keys to config
blockinfile:
path: wpconfig.file
marker: // {mark} ANSIBLE MANAGED BLOCK
block:
"{{ wordpress_keys.content }}"
it results into the expected and probably correct output.
TASK [Show keys] ************************************************************************************************
ok: [localhost] =>
wordpress_keys.content: |-
define('AUTH_KEY', '...');
define('SECURE_AUTH_KEY', '...');
define('LOGGED_IN_KEY', '...');
define('NONCE_KEY', '...');
define('AUTH_SALT', '...');
define('SECURE_AUTH_SALT', '...');
define('LOGGED_IN_SALT', '...');
define('NONCE_SALT', '...');
<?php
/**
* The base configuration for WordPress
* ...
* Authentication unique keys and salts.
*
* Change these to different unique phrases! You can generate these using
* the {#link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service}.
*
* You can change these at any point in time to invalidate all existing cookies.
* This will force all users to have to log in again.
* ...
*/
// BEGIN ANSIBLE MANAGED BLOCK
define('AUTH_KEY', '...');
define('SECURE_AUTH_KEY', '...');
define('LOGGED_IN_KEY', '...');
define('NONCE_KEY', '...');
define('AUTH_SALT', '...');
define('SECURE_AUTH_SALT', '...');
define('LOGGED_IN_SALT', '...');
define('NONCE_SALT', '...');
// END ANSIBLE MANAGED BLOCK
Summary
Your current question and description seems not to be focused on the necessary part but on everything not so related around
On Ansible tasks I am not able to (re-)produce an issue
The part deals with configuration for a 3rd party web service or PHP only
According this it seems not to be related to Ansible at all
The problem domain seems to be Wordpress and PHP setup and configuration only, namely the config file
For further troubleshooting you may try to template module – Template a file out to a target host, the config file including keys generated define('AUTH_KEY', '{{ lookup('password', '/dev/null chars=ascii_letters length=64') }}');
Check with Browser in Incognito Mode because of invalidated cookies
Therefore it is also not about programming at all
An other site on Stack like serverfault.com, superuser.com, devops.staexchange.com or wordpress.stackexchange.com might fit better for your question
-regenerate the security keys
-Make sure the keys are entered correctly in the wp-config file of your WordPress installation.
Which of the following library versions work well with Airflow 2.2.3 ?
Tried few options but none worked. Fails when initializing db
solution: downgrading no result
pip install Flask==1.0.4
pip3 install marshmallow-sqlalchemy==0.17.1
solution: no result
pip3 install marshmallow-sqlalchemy==0.17.1
pip3 install SQLAlchemy==1.3.23
pip3 install flask-sqlalchemy
errors:
flask-appbuilder 3.4.3 requires marshmallow-sqlalchemy<0.27.0,>=0.22.0, but you'll have marshmallow-sqlalchemy 0.17.1 which is incompatible.
apache-airflow 2.2.3 requires flask<2.0,>=1.1.0, but you'll have flask 1.0.4 which is incompatible.
apache-airflow 2.2.3 requires werkzeug>=1.0.1,~=1.0, but you'll have werkzeug 0.16.0 which is incompatible.
higher versions when used produuce different error.
- name: "pip : ensure correct werkzeug package present"
pip:
name: "werkzeug"
version: "{{ airflow_werkzeug_version | default('0.16.0') }}"
state: present
virtualenv: "{{ airflow_venv_path }}"
virtualenv_command: "{{ airflow_venv_cmd }}"
environment:
AIRFLOW_GPL_UNIDECODE: "yes"
SLUGIFY_USES_TEXT_UNIDECODE: "yes"
become: true
become_user: "{{ airflow_username }}"
- name: "venv - ensure python sqlalchemy dependencies "
pip:
name: "Flask-SQLAlchemy"
version: "2.4.4"
state: present
virtualenv: "{{ airflow_venv_path }}"
virtualenv_command: "{{ airflow_venv_cmd }}"
environment:
AIRFLOW_GPL_UNIDECODE: "yes"
SLUGIFY_USES_TEXT_UNIDECODE: "yes"
become: true
become_user: "{{ airflow_username }}"
- name: "venv - ensure python sqlalchemy dependencies "
pip:
name: "SQLAlchemy"
version: "1.3.23"
state: present
virtualenv: "{{ airflow_venv_path }}"
virtualenv_command: "{{ airflow_venv_cmd }}"
environment:
AIRFLOW_GPL_UNIDECODE: "yes"
SLUGIFY_USES_TEXT_UNIDECODE: "yes"
become: true
become_user: "{{ airflow_username }}"
- name: "venv - ensure python sqlalchemy dependencies "
pip:
name: "wtforms"
version: "2.3.3"
state: present
virtualenv: "{{ airflow_venv_path }}"
virtualenv_command: "{{ airflow_venv_cmd }}"
environment:
AIRFLOW_GPL_UNIDECODE: "yes"
SLUGIFY_USES_TEXT_UNIDECODE: "yes"
become: true
become_user: "{{ airflow_username }}"
Look at constraint files. You do not have to think about the right versions of dependencies as long as you use golden set of constraints which are generated by Airflow maintainers with every release.
See Airflow documentation about this:
https://airflow.apache.org/docs/apache-airflow/stable/installation/installing-from-pypi.html
You should use constraints when you install airflow - this way the right versions will be automatically found and installed by PIP.
But you can also - if you want manually set those dependencies or even automate version retrieval. For example here you have the set of "golden" constraints for Airflow 2.2.2 and Python 3.7:
https://raw.githubusercontent.com/apache/airflow/constraints-2.2.3/constraints-3.7.txt
I try to setup a MySQL DB with Ansible, however, I have trouble with changing the initial root password.
- name: Get temporary root password from install log
shell: cat /var/log/mysqld.log | grep "temporary password" | grep -oE '[^ ]+$'
register: tmp_root_password
- name: Set new password from temporary password
shell: 'mysql -e \"ALTER USER root IDENTIFIED BY("{{ mysql_root_password }}");\" --connect-expired-password -uroot -p"{{ tmp_root_password.stdout }}"'
Fails with the following error:
fatal: [mysqlhost.mydomain]: FAILED! => {"changed": true, "cmd": "mysql -e \\\"ALTER USER root IDENTIFIED BY(\" MyNewPassword\");\\\" --connect-expired-password -uroot -p\"MyTmpPassword\"", "delta": "0:00:00.003081", "end": "2021-11-28 08:40:52.000198", "msg": "non-zero return code", "rc": 1, "start": "2021-11-28 08:40:51.997117", "stderr": "/bin/sh: -c: line 0: syntax error near unexpected token `('\n/bin/sh: -c: line 0: `mysql -e \\\"ALTER USER root IDENTIFIED BY(\" MyNewPassword\");\\\" --connect-expired-password -uroot -p\"MyTmpPassword\"'", "stderr_lines": ["/bin/sh: -c: line 0: syntax error near unexpected token `('", "/bin/sh: -c: line 0: `mysql -e \\\"ALTER USER root IDENTIFIED BY(\" MyNewPassword\");\\\" --connect-expired-password -uroot -p\"MyTmpPassword\"'"], "stdout": "", "stdout_lines": []}
I've tried to set the root password based on the below guide, as well, without any luck.
https://docs.ansible.com/ansible/latest/collections/community/mysql/mysql_user_module.html#ansible-collections-community-mysql-mysql-user-module
Thanks!
The following is based the Ansible role I created for mysql/percona and is idempotent.
This is the playbook you could use, taken from the repo described above.
This sets the 'debian-sys-main' user as a root user of the database.
This also assumes you build MySQL for the first time, and not while already being active/installed.
---
- name: root | stat to check whether /root/.my.cnf exists
stat:
path: /root/.my.cnf
register: cnf_file
- block:
- name: root | place temporary cnf file
template:
src: temp_cnf.j2
dest: /etc/my.cnf
mode: '0644'
- name: root | start mysql to add the debian-sys-maint user
systemd:
name: mysql
state: started
enabled: true
- name: root | get temp root password
shell: >-
grep 'temporary password' /var/log/mysqld.log |
awk '{print $NF}' | tail -n 1
register: temp_root_pw
no_log: true
- name: root | set root password
shell: >-
mysqladmin -u root
--password="{{ temp_root_pw.stdout }}"
password "{{ mysql_root_password }}"
no_log: true
- name: root | set debian-sys-maint user and password
mysql_user:
name: debian-sys-maint
password: "{{ mysql_system_password }}"
priv: '*.*:ALL,GRANT'
update_password: always
state: present
login_unix_socket: /var/run/mysqld/mysqld.sock
login_user: root
login_password: "{{ mysql_root_password }}"
no_log: true
- name: root | copy root.cnf
template:
src: root.cnf.j2
dest: /etc/mysql/root.cnf
mode: '0600'
owner: root
group: root
- name: root | make symlink of file for root db access
file:
state: link
src: /etc/mysql/root.cnf
path: /root/.my.cnf
- name: root | delete anonymous connections
mysql_user:
name: ""
host_all: true
state: absent
no_log: true
- name: root | secure root user
mysql_user:
name: root
host: "{{ item }}"
no_log: true
loop:
- ::1
- 127.0.0.1
- localhost
- name: root | ensure test database is removed
mysql_db:
name: test
login_user: root
state: absent
- name: root | stop mysql again
systemd:
name: mysql
state: stopped
enabled: true
- name: root | remove mysqld log file
file:
path: /var/log/mysqld.log
state: absent
when: not cnf_file.stat.exists
The temp_cnf.j2:
[client]
socket=/var/run/mysqld/mysqld.sock
[mysqld]
server-id=1
datadir=/var/lib/mysql
socket=/var/run/mysqld/mysqld.sock
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
And the root.cnf.j2
{{ ansible_managed | comment }}
# This file is symlinked to /root/.my.cnf to use passwordless login for the root user
[client]
socket = {{ mysqld.socket }}
user = debian-sys-maint
password = {{ percona_system_password }}
[mysql_upgrade]
socket = {{ mysqld.socket }}
user = debian-sys-maint
password = {{ percona_system_password }}
Some vars:
mysql_root_password: my_password
mysql_system_password: my_password
mysqld:
socket: /var/run/mysqld/mysqld.sock
Should work for CentOS 8, Rocky Linux and Oracle Linux as well.
Regarding the initial question for RHEL 7 and MySQL Server 8.0.21, I've found the following approach working in the mentioned environment.
- name: Delete all anonymous SQL user accounts
mysql_user:
user: ""
host_all: yes
state: absent
- name: Remove the SQL test database
mysql_db:
db: test
state: absent
- name: Change root user password on first run
mysql_user:
login_user: root
login_password: ''
name: root
password: "{{ SQL_ROOT_PASSWORD }}"
priv: "*.*:ALL,GRANT"
host: "{{ item }}"
with_items:
- "{{ ansible_hostname }}"
- "127.0.0.1"
- "::1"
- "localhost"
I want to deploy a MySql database server with these configurations.
This is my playbook to deploy MySql :
- name: "Inclure le fichier : install_utilitaires_mysql.yaml"
include: install_utilitaires_mysql.yaml
when: ansible_os_family == "Debian"
- name: "Telechargement d'un package .deb pour ajouter le repo mysql"
get_url:
url: https://dev.mysql.com/get/mysql-apt-config_0.8.15-1_all.deb
dest: /tmp
when: ansible_os_family == "Debian"
- name: "Installation du package .deb"
apt:
deb: /tmp/mysql-apt-config_0.8.15-1_all.deb
when: ansible_os_family == "Debian"
- name: "Mise a jour des sources list : apt update"
apt:
update_cache: yes
when: ansible_os_family == "Debian"
- name: "Installation de MySql"
apt:
name: mysql-server
state: latest
when: ansible_os_family == "Debian"
- name: "Demarrer le service MySql"
service:
name: mysql
state: started
enabled: yes
when: ansible_os_family == "Debian"
- name: "Voir la variable mysql_username"
debug:
msg: "{{ mysql_username }}"
when: ansible_os_family == "Debian"
- name: "Création du user : {{ mysql_username }}"
mysql_user:
name: "{{ mysql_username }}"
password: "{{ mysql_password }}"
priv: '*.*:ALL'
state: present
when: ansible_os_family == "Debian"
But when I execute this playbook with the ansible-playbook -i hosts playbook.yaml --vault-password-file password command, I will get this error :
TASK [Création du user : {{ mysql_username }}] ********************************************************************************************************************************************************************
skipping: [192.168.1.41]
[WARNING]: Module did not set no_log for update_password
fatal: [192.168.1.37]: FAILED! => {"changed": false, "msg": "unable to connect to database, check login_user and login_password are correct or /root/.my.cnf has the credentials. Exception message: (1698, u\"Access denied for user 'root'#'localhost'\")"}
Why can ansible not connect to MySQL while mysql -u root works perfectly fine?
I found this solution but I don't understand how it works:
- name: Example using login_unix_socket to connect to server
mysql_user:
name: root
password: root
login_unix_socket: /var/run/mysqld/mysqld.sock
when: ansible_os_family == "Debian"
First food for thought
I found this code
---
- name: "Inclure le fichier : install_utilitaires_mysql.yaml"
include: install_utilitaires_mysql.yaml
when: ansible_os_family == "Debian"
- name: "Telechargement d'un package .deb pour ajouter le repo mysql"
get_url:
url: https://dev.mysql.com/get/mysql-apt-config_0.8.15-1_all.deb
dest: /tmp
when: ansible_os_family == "Debian"
- name: "Installation du package .deb"
apt:
deb: /tmp/mysql-apt-config_0.8.15-1_all.deb
when: ansible_os_family == "Debian"
- name: "Mise a jour des sources list : apt update"
apt:
update_cache: yes
when: ansible_os_family == "Debian"
- name: "Installation de MySql"
apt:
name: mysql-server
state: latest
when: ansible_os_family == "Debian"
- name: "Demarrer le service MySql"
service:
name: mysql
state: started
enabled: yes
when: ansible_os_family == "Debian"
- name: "Envoi du template .my.cnf dans ~"
template:
src: root_cnf.j2
dest: ~/.my.cnf
owner: root
mode: 0600
when: ansible_os_family == "Debian"
- name: "Redemarrer le service MySql"
service:
name: mysql
state: restarted
enabled: yes
when: ansible_os_family == "Debian"
- name: "Création du user : {{ mysql_username }}"
mysql_user:
login_user: root
login_password: root
name: "{{ mysql_username }}"
password: "{{ mysql_password }}"
priv: '*.*:ALL'
state: present
when: ansible_os_family == "Debian"
But when I executed this ansible-playbook -i hosts playbook.yaml --vault-password-file password command I get this error:
TASK [Création du user : {{ mysql_username }}] ********************************************************************************************************************************************************************
skipping: [192.168.43.102]
[WARNING]: Module did not set no_log for update_password
fatal: [192.168.43.182]: FAILED! => {"changed": false, "msg": "unable to connect to database, check login_user and login_password are correct or /********/.my.cnf has the credentials. Exception message: (1698, u\"Access denied for user '********'#'localhost'\")"}
Question : Why does running my playbook result in this error?
Knowing that the root_cnf.j2 jinja2 file contains this configuration :
[client]
user=root
password=root
As you wrote, you need to use login_unix_socket: /var/run/mysqld/mysqld.sock (replace the path to the socket if necessary) as the password-less login is only available using the socket, not using the network.
See this post on dba.stackexchange.com.
It is basically a security feature, so you do not accidentally expose a password-less access to a database on the internet.
What you want to do is first
- name: Set password for root user
mysql_user:
name: "root"
password: "{{ mysql_password }}"
priv: '*.*:ALL,GRANT'
host: 'localhost'
login_unix_socket: /var/run/mysqld/mysqld.sock
state: present
which will set a password for root. After that the login for root via the network will be enabled.
Afterwards, you want to do something like this:
- name: Save root password in .my.cnf
template:
src: root_cnf.j2
dest: /root/.my.cnf
owner: root
mode: '0600'
With the template being this:
[client]
user=root
password={{ mysql_root_password }}
This will put your password in /root/.my.cnf so you are able to just use mysql on the machine without providing credentials (ansible will pick that up).
Then you can add users with this:
- name: "Create mysql user {{ mysql_username }}"
mysql_user:
name: "{{ mysql_username }}"
password: "{{ mysql_password }}"
priv: '*.*:ALL'
which is what you want, I guess.
I am a saltstack newbie and mysql newbie too... :-/ was trying to install my-sql on Ubuntu 14. I am getting following error
I use the following sls file
mysql_package:
pkg.installed:
- name: mysql-server
mysql_conf:
file.managed:
- name: /etc/my.cnf
- source: salt://mysql/files/my.cnf
- user: root
- group: root
- mode: 0644
- require:
- pkg: mysql_package
mysql_service:
service:
- name: mysqld
- running
- enable: True
- require:
- pkg: mysql_conf
- watch:
- pkg: mysql_conf
# required packages start
server_pkgs:
pkg:
- installed
- pkgs:
- python-dev
- refresh: True
mysql_python_pkgs:
pkg.installed:
- pkgs:
- libmysqlclient-dev
- mysql-client
- python-mysqldb
- require:
- pkg: server_pkgs
python-pip:
pkg:
- installed
- refresh: False
mysql:
pip.installed:
- require:
- pkg: python-pip
- pkg: mysql_python_pkg
# required package end
stg_databases:
mysql_database.present:
- name: stagingdb
- require:
- pkg: mysql
- service: mysql_service
first_db_user:
mysql_user.present:
- name: stg-admin
- password: "pass4admin"
- host: '%'
- connection_charset: utf8
- saltenv:
- LC_ALL: "en_US.utf8"
- require:
- mysql_database: stg_databases
create_first_table:
mysql_query.run:
- database: stagingdb
- query: "create table first_table(id INT NOT NULL AUTO_INCREMENT, name VARCHAR(100) NOT NULL, PRIMARY KEY ( id ));"
- output: "/tmp/create_first_table.txt"
- require:
- mysql_database: stg_databases
first_table_grants:
mysql_grants.present:
- grant: all privileges
- database: stagingdb.*
- user: stg-admin
- host: '%'
- require:
- mysql_user: first_db_user
And using following conf file
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
symbolic-links=0
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
Came across following link MySQL - ERROR 1045 - Access denied , thats not what i want to do...
Guessing there is a relation between user defined in my.cnf and in sls file, which i am not getting correct ?
Where there any errors when you ran this state?
Also if you run:
salt-call -ldebug state.sls <state file>
That will give you a lot of useful information as to what salt is exactly running. Is the root user still available? Can you login and see if that user was actually created?
This is obvious Mysql GRANT issues that you don't need to debug. It means you make some mistake of GRANTING the user. Just check the doc : https://docs.saltstack.com/en/latest/ref/states/all/salt.states.mysql_user.html
mysql_user.present DOES NOT grant a user. you need mysql_grants.present together with mysql_user.present. The confusing part : mysql_grants.present doesn't set password; mysql_user.present set password but doesn't grant DB rights.
first_db_user:
mysql_user.present:
- name: stg-admin
- password: "pass4admin"
- host: '%'
- connection_charset: utf8
- saltenv:
- LC_ALL: "en_US.utf8"
- require:
- mysql_database: stg_databases
grant_my_first_db_user:
mysql_grants.present:
- grant: select,insert,update
- database: stagingdb
- user: stg-admin
- host: localhost
And saltstack mysql formula confirm this.
https://github.com/saltstack-formulas/mysql-formula/blob/master/mysql/salt-user.sls