Le Blog Utux

HTTP 200 GET /

Ansible filter by Azure tag

Rédigé par uTux Aucun commentaire

It took me some time to figure out how to use Azure tags as a filter for Ansible. Well it's not that hard, azure_rm.py will automatically generate groups based on tags with this pattern:

  • Tag: role:webserver
  • Becomes group: role_webserver

Yes, that's the trick, ":" becomes "_". Let's say you want to run a playbook only on machines tagged with role:webserver, just use the following command:

$ ansible-playbook -i azure_rm.py playbook.yml --limit role_webserver

Ansible Jinja loop all groups except

Rédigé par uTux Aucun commentaire

I want to generate a /usr/local/etc/backuppc/hosts with all hosts from the ansible inventory, but exclude a group.

Inventory:

[dbservers]
db1
db2
db3

[DisableBackup]
db3

hosts.j2:

# {{ ansible_managed }}

{% for hosts in groups['all'] | difference(groups['DisableBackup']) %}
{{ hosts }}
{% endfor %}

tasks/generate_hosts.yml:

  - name: Generate hosts file
    template:
      src: hosts.j2
      dest: "{{ backuppc__confdir }}/hosts"
      owner: "{{ backuppc__user }}"
      group: "{{ backuppc__group }}"
      mode: 0644
      force: yes

Run:

ansible-playbook -i inventory install_backuppc.yml

Result:

cat /usr/local/etc/backuppc/hosts
# Ansible managed
db1
db2

Source.

Ansible: récupérer les clés SSH depuis BitBucket

Rédigé par uTux Aucun commentaire

Je m'attaque aux API REST et en particulier celle de BitBucket pour y récupérer mes clés SSH que je déploie ensuite sur mes serveurs, le tout avec Ansible. Voilà un petit bout de code sur lequel j'ai passé une bonne soirée car autant c'est facile d'interroger l'API, autant ça l'est un peu moins de faire rentrer les bons champs dans des variables ;)

Pré requis:

  • Sur votre compte BitBucket
  • Settings > App passwords
  • Créez un password avec l'autorisation Account / read.

Allons-y (à mettre dans votre tasks/main.yml par exemple):

---

  - name: GET authorized_keys from REST API
    uri:
      url: "{{ authorized_keys.api_url }}"
      method: "{{ authorized_keys.api_method }}"
      user: "{{ authorized_keys.api_user }}"
      password: "{{ authorized_keys.api_password }}"
      force_basic_auth: "{{ authorized_keys.api_force_basic }}"
    register: authorized_keys__json_response
    delegate_to: localhost
    run_once: True
    # Delegate to localhost and run 1 time because
    # we don't need to query the API from each remote host

  - name: Set Keys as a Var
    set_fact:
      authorized_keys__keys: "{{ authorized_keys__json_response.json | json_query('values[*].key') }}"
    delegate_to: localhost
    run_once: True
    # Extract the fields 'key' in a variable

  - name: Concatenate Keys
    set_fact:
      authorized_keys__keys_concatenate: "{{ authorized_keys__keys | join('\n') }}"
    delegate_to: localhost
    run_once: True
    # Ansible authorized_keys module with 'exclusive' option requires all keys in one batch
    # separated by a newline \n

La variable authorized_keys__keys contient la liste des clés publiques. La variable authorized_keys__keys_concatenate n'est pas une liste mais un champ contenant toutes les clés séparées par un retour à la ligne et elle est utile si vous souhaitez utiliser le module authorized_keys avec exclusive: yes car ce dernier ne marche pas bien avec une liste, il faut donc lui fournir 1 seul "batch".

Complétez ensuite vos variables, par exemple:

# group_vars/all/vars.yml

authorized_keys:
  api_user: john
  api_url: "https://api.bitbucket.org/2.0/users/john/ssh-keys"
  api_method: GET
  api_force_basic: yes
  api_password: password créé dans l'interface bitbucket

Bien sûr en vrai on mettra le password dans un vault ;)

Et voilà, vous pouvez utiliser authorized_keys__keys ou authorized_keys__keys_concatenate pour la suite!

Ansible: loop, subelements, dictionnary

Rédigé par uTux Aucun commentaire

Article pense-bête. J'écris un petit rôle pour configurer firewalld, en gros je veux spécifier quelles interfaces et quels services il faut ajouter dans les zones. Mon idée c'est de définir tout ça dans un dictionnaire dans le playbook, et ensuite de récupérer les élements et sous-élements dans le rôle.

Voici ce que ça donne:

# install.yml

- hosts: nas

  roles:
    - nfs-server
    - firewalld

  vars:
    firewalld_zones:
      - zone: internal
        interfaces:
          - eth0
        services:
          - mountd
          - nfs
          - rpc-bind
  - name: Define zones for interfaces
    firewalld:
      zone: "{{ item.0.zone }}"
      permanent: true
      immediate: true
      interface: "{{ item.1 }}"
      state: enabled
    with_subelements:
      - "{{ firewalld_zones }}"
      - interfaces

  - name: Allow services for zones
    firewalld:
      zone: "{{ item.0.zone }}"
      permanent: true
      immediate: true
      service: "{{ item.1 }}"
      state: enabled
    with_subelements:
      - "{{ firewalld_zones }}"
      - services

Mouais. C'est quand même loin d'être clair ou évident. Mais c'est le seul moyen que j'ai trouvé pour le moment. Si quelqu'un connaît une méthode plus propre/lisible je suis preneur.

Le rolling release c'est pas toujours bien (pour ansible)

Rédigé par uTux Aucun commentaire

Il y a des gens qui préfèrent les distributions stable telles que debian et il y en a d'autres qui, au contraire, veulent du rolling release. Sur serveur j'ai toujours privilégié la stabilité, donc debian mais je n'ai pas toujours le choix.

Mon NAS tourne sous FreeNAS, et ayant besoin d'étendre ses possibilités j'ai ajouté quelques jails qui offrent donc du FreeBSD quasi upstream. Or FreeBSD a une base stable mais la plupart des ports/packages non. J'ai fait la configuration avec Ansible pour pouvoir tout réinstaller facilement sans me poser de question (voir Docker, Ansible, NixOS : le savoir (re)faire). Et justement le cas s'est présenté, suite au passage au chiffrement des disques j'ai du backuper/restaurer toutes les données et recréer mes jails. Le problème est qu'Ansible n'a pas pu jouer les playbook à cause de cet aspect rolling release qui fait que le comportement ou les fichiers de conf des logiciels à installer a changé. Je pense notamment à unbound, je parse le /usr/local/etc/unbound.conf à la recherche d'une ligne "listen 0.0.0.0" que je créé si elle n'existe pas. Or depuis peu elle est présente dans une autre contexte, cela induit donc mon playbook en erreur. Ce n'est pas trop grave, il m'a fallu moins de 1h pour tout corriger et tout installer.

J'étudie la possibilité de remplacer ces jails FreeBSD par des machines virtuelles debian, car FreeNAS supporte la virtualisation avec bhyve. Une grande stabilité est nécessaire pour orchestrer et automatiser les choses proprement.

Fil RSS des articles de ce mot clé