47 votes

Ansible idempotent MySQL installation Playbook

Je veux installer un serveur MySQL sur AWS, à l'aide de Ansible pour la gestion de la configuration. Je suis à l'aide de la valeur par défaut AMI de Amazon (ami-3275ee5b), qui utilise yum pour la gestion des paquets.

Lorsque le Playbook ci-dessous est exécutée, tout va bien. Mais quand je le lance pour une deuxième fois, la tâche Configure the root credentials d'échec, parce que l'ancien mot de passe de MySQL ne correspondent plus, depuis qu'il a été mis à jour la dernière fois que j'ai couru ce Playbook.

Cela rend le Playbook non la quantité, qui, je n'aime pas. Je veux être en mesure d'exécuter le Playbook autant de fois que je veux.

- hosts: staging_mysql
  user: ec2-user
  sudo: yes

  tasks:
    - name: Install MySQL
      action: yum name=$item
      with_items:
        - MySQL-python
        - mysql
        - mysql-server

    - name: Start the MySQL service
      action: service name=mysqld state=started

    - name: Configure the root credentials
      action: command mysqladmin -u root -p $mysql_root_password

Quelle serait la meilleure façon de résoudre ce problème, ce qui signifie faire le Playbook idempotent? Merci à l'avance!

37voto

Lorin Hochstein Points 11816

J'ai posté à ce sujet sur coderwall, mais je vais reproduire dennisjac de l'amélioration dans les commentaires de mon post original.

L'astuce pour le faire idempotently est de savoir que la mysql_user module vous permettra de charger un ~/.mon.cnf fichier si il en trouve un.

J'ai d'abord changer le mot de passe, puis copiez un .mon.cnf fichier avec le mot de passe des informations d'identification. Lorsque vous essayez d'exécuter une seconde fois, le myqsl_user ansible module trouverez la .mon.cnf et utiliser le nouveau mot de passe.

- hosts: staging_mysql
  user: ec2-user
  sudo: yes

  tasks:
    - name: Install MySQL
      action: yum name={{ item }}
      with_items:
        - MySQL-python
        - mysql
        - mysql-server

    - name: Start the MySQL service
      action: service name=mysqld state=started

    # 'localhost' needs to be the last item for idempotency, see
    # http://ansible.cc/docs/modules.html#mysql-user
    - name: update mysql root password for all root accounts
      mysql_user: name=root host={{ item }} password={{ mysql_root_password }} priv=*.*:ALL,GRANT
      with_items:
        - "{{ ansible_hostname }}"
        - 127.0.0.1
        - ::1
        - localhost

    - name: copy .my.cnf file with root password credentials
      template: src=templates/root/.my.cnf dest=/root/.my.cnf owner=root mode=0600

L' .mon.cnf modèle ressemble à ceci:

[client]
user=root
password={{ mysql_root_password }}

Edit: Ajout de privilèges comme recommandé par Dhananjay Nene dans les commentaires, et a changé la variable d'interpolation à utiliser des accolades à la place du signe de dollar.

33voto

Voles Points 2019

Ansible version pour une sécurité de l'installation de MySQL.

mysql_secure_installation.yml

- hosts: staging_mysql
  user: ec2-user
  sudo: yes

  tasks:
    - name: Install MySQL
      action: yum name=$item
      with_items:
        - MySQL-python
        - mysql
        - mysql-server

    - name: Start the MySQL service
      action: service name=mysqld state=started

    # 'localhost' needs to be the last item for idempotency, see
    # http://ansible.cc/docs/modules.html#mysql-user
    - name: update mysql root password for all root accounts
      mysql_user: name=root host=$item password=$mysql_root_password
      with_items:
        - $ansible_hostname
        - 127.0.0.1
        - ::1
        - localhost

    - name: copy .my.cnf file with root password credentials
      template: src=templates/root/my.cnf.j2 dest=/root/.my.cnf owner=root mode=0600

    - name: delete anonymous MySQL server user for $server_hostname
      action: mysql_user user="" host="$server_hostname" state="absent"

    - name: delete anonymous MySQL server user for localhost
      action: mysql_user user="" state="absent"

    - name: remove the MySQL test database
      action: mysql_db db=test state=absent

modèles/root/my.cnf.j2

[client]
user=root
password={{ mysql_root_password }}

Références

5voto

mahemoff Points 4879

Pour ajouter à la réponse à la question précédente, je ne voulais pas d'un manuel étape avant l'exécution de la commande, c'est à dire je veux lancer un nouveau serveur et il suffit d'exécuter la playbook sans avoir à modifier manuellement le mot de passe root première fois. Je ne crois pas {{ mysql_password }} va travailler la première fois, lorsque le mot de passe root est nulle, parce que mysql_password encore être défini quelque part (sauf si vous voulez la remplacer par -e).

J'ai donc ajouté une règle pour le faire, ce qui est ignorée si elle échoue. C'est en plus, et apparaît avant, les autres commandes ici.

- 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

5voto

Dhananjay Nene Points 506

C'est une solution alternative à celle proposée par @LorinHochStein

L'un de mes contraintes était de veiller à ce qu'aucun des mots de passe sont stockés dans des fichiers de texte brut n'importe où sur le serveur. Ainsi .mon.cnf n'était pas une proposition pratique

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

Et dans le fichier vars

current_password: foobar
new_password: "{{ current_password }}"

Lorsqu'il n'est pas de changer le mot de passe mysql exécuter ansible playbook sur la ligne de commande comme d'habitude.

Quand changer le mot de passe mysql, ajoutez le code suivant à la ligne de commande. De le spécifier sur la ligne de commande permet le jeu de paramètres sur la ligne de commande de prendre la priorité sur celui par défaut dans le fichier vars.

$ ansible-playbook ........ --extra-vars "new_password=buzzz"

Après l'exécution de la commande de changement de la rva fichier comme suit

current_password=buzzz
new_password={{ current_password }}

3voto

oblalex Points 221

Eh bien, c'est venu un peu compliqué. J'ai passé une journée entière sur ce et est venu avec la solution indiquée ci-dessous. Le point clé est de savoir comment Ansible installe le serveur MySQL. À partir de la documentation de mysql_user module (dernière remarque de la page):

MySQL server installs with default login_user of ‘root' and no password. To secure this user as part of an idempotent playbook, you must create at least two tasks: the first must change the root user's password, without providing any login_user/login_password details. The second must drop a ~/.my.cnf file containing the new root credentials. Subsequent runs of the playbook will then succeed by reading the new credentials from the file.

Que le problème avec vide ou null mot de passe a été une grosse surprise.

Rôle:

---

- name: Install MySQL packages
  sudo: yes
  yum: name={{ item }} state=present
  with_items:
    - mysql
    - mysql-server
    - MySQL-python


- name: Start MySQL service
  sudo: yes
  service: name=mysqld state=started enabled=true


- name: Update MySQL root password for root account
  sudo: yes
  mysql_user: name=root password={{ db_root_password }} priv=*.*:ALL,GRANT


- name: Create .my.cnf file with root password credentials
  sudo: yes
  template: src=.my.cnf.j2 dest=/root/.my.cnf owner=root group=root mode=0600
  notify:
  - restart mysql


- name: Create a database
  sudo: yes
  mysql_db: name={{ db_name }}
            collation=utf8_general_ci
            encoding=utf8
            state=present


- name: Create a database user
  sudo: yes
  mysql_user: name={{ db_user }}
              password={{ db_user_password }}
              priv="{{ db_name }}.*:ALL"
              host=localhost
              state=present

Gestionnaire:

---

- name: restart mysql
  service: name=mysqld state=restarted

.mon.cnf.j2:

[client]
user=root
password={{ db_root_password }}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X