diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..315ad74 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/inventory +*.retry \ No newline at end of file diff --git a/Makefile b/Makefile index d13c490..861cf56 100644 --- a/Makefile +++ b/Makefile @@ -1,29 +1,10 @@ -eole-2.6.2: - docker build \ - --build-arg HTTP_PROXY=$(HTTP_PROXY) \ - --build-arg HTTPS_PROXY=$(HTTPS_PROXY) \ - --build-arg http_proxy=$(http_proxy) \ - --build-arg https_proxy=$(https_proxy) \ - -t eolebase-2.6.2:latest \ - ./misc/eole-2.6.2 +DESTDIR := ./ +install: + install -d $(DESTDIR)usr/share/ansible/plugins/modules + install src/eole_config.py $(DESTDIR)usr/share/ansible/plugins/modules + +link-dev: + mkdir -p "$(HOME)/.ansible/plugins/modules" + ln -s "$(PWD)/src" "$(HOME)/.ansible/plugins/modules/eole" -ansible-eole: eole-2.6.2 - docker build \ - --build-arg HTTP_PROXY=$(HTTP_PROXY) \ - --build-arg HTTPS_PROXY=$(HTTPS_PROXY) \ - --build-arg http_proxy=$(http_proxy) \ - --build-arg https_proxy=$(https_proxy) \ - -t ansible-eole:latest \ - ./misc/ansible-eole - -dev-env: - docker run \ - -it \ - --rm \ - -v "$(PWD)/src/eole_config.py:/ansible/lib/ansible/modules/system/eole_config.py:ro" \ - -v "$(PWD)/testdata:/testdata:ro" \ - --network host \ - --name ansible-creole-dev-env \ - ansible-eole - -.PHONY: eole-2.6.2 ansible-eole \ No newline at end of file +.PHONY: link-locally install \ No newline at end of file diff --git a/README.md b/README.md index 03ce067..6e1ccf4 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,41 @@ # Ansible - EOLE -Module Ansible permettant de configurer une distribution EOLE +Module Ansible permettant de manipuler les valeurs de configuration Creole d'un module EOLE. + +**Stabilité** expérimental + +## Démonstration + +[![asciicast](https://asciinema.org/a/3PyxG4M43cXW0wiUQlgkt3pwQ.svg)](https://asciinema.org/a/3PyxG4M43cXW0wiUQlgkt3pwQ) + +Voir le fichier [`playbook-sample.yml`](./playbook-sample.yml) pour plus de détails. + +## Utilisation + +```shell +# Récupérer les sources du projet +git clone https://forge.cadoles.com/wpetit/ansible-eole.git +cd ansible-eole + +# Exposer le module à Ansible +# Voir la section ressources pour plus d'informations sur les modules locaux. +make link-dev + +# Créer un fichier d'inventaire simple +cat > inventory < ansible_user=root +EOF + +# Utiliser le playbook d'exemple avec le fichier d'inventaire +ansible-playbook -i inventory playbook-sample.yml +``` ## Ressources - [Développement de modules Ansible](https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_general.html) +- [Ajout des modules/plugins locaux à Ansible](https://docs.ansible.com/ansible/latest/dev_guide/developing_locally.html) -/usr/lib/python2.7/dist-packages/tiramisu/config.py \ No newline at end of file +## Licence + +GPL-3.0 \ No newline at end of file diff --git a/misc/ansible-eole/Dockerfile b/misc/ansible-eole/Dockerfile deleted file mode 100644 index ee895e7..0000000 --- a/misc/ansible-eole/Dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -FROM eolebase-2.6.2:latest - -ARG HTTP_PROXY= -ARG HTTPS_PROXY= -ARG http_proxy= -ARG https_proxy= -ARG DEBIAN_FRONTEND=noninteractive - -RUN apt-get update -y &&\ - apt-get install -y build-essential libssl-dev libffi-dev python-dev python-pip git &&\ - rm -rf /var/lib/apt/lists/* - -RUN git clone https://github.com/ansible/ansible.git &&\ - cd ansible &&\ - pip install wheel &&\ - pip install -r requirements.txt - -COPY bashrc /root/.bashrc - -WORKDIR ansible \ No newline at end of file diff --git a/misc/ansible-eole/bashrc b/misc/ansible-eole/bashrc deleted file mode 100644 index 794ff28..0000000 --- a/misc/ansible-eole/bashrc +++ /dev/null @@ -1 +0,0 @@ -. hacking/env-setup \ No newline at end of file diff --git a/misc/eole-2.6.2/Dockerfile b/misc/eole-2.6.2/Dockerfile deleted file mode 100644 index 3681fc3..0000000 --- a/misc/eole-2.6.2/Dockerfile +++ /dev/null @@ -1,39 +0,0 @@ -FROM ubuntu:16.04 - -ARG HTTP_PROXY= -ARG HTTPS_PROXY= -ARG http_proxy= -ARG https_proxy= -ENV DEBIAN_FRONTEND=noninteractive - -# systemd/docker compatibility configuration -# See https://developers.redhat.com/blog/2016/09/13/running-systemd-in-a-non-privileged-container/ -ENV container=docker -STOPSIGNAL SIGRTMIN+3 - -RUN apt-get update -y && apt-get install -y locales wget keyboard-configuration -RUN locale-gen --purge fr_FR.UTF-8 - -ENV LC_ALL=fr_FR.UTF-8 -ENV LANG=french - -# Install apt-show-versions -# See https://askubuntu.com/questions/916199/install-apt-show-versions-inside-an-ubuntu-docker-container -RUN rm /etc/apt/apt.conf.d/docker-gzip-indexes &&\ - apt-get purge apt-show-versions &&\ - rm /var/lib/apt/lists/*lz4 &&\ - apt-get -o Acquire::GzipIndexes=false update &&\ - apt-get install -y apt-show-versions - -# Configure then install EOLE packages -RUN wget -q -O - "http://eole.ac-dijon.fr/eole/project/eole-2.6-repository.key" | apt-key --keyring /etc/apt/trusted.gpg.d/eole-archive-keyring.gpg add - -COPY eole.list /etc/apt/sources.list.d/eole.list -RUN apt-get update -y &&\ - apt-get install -y --force-yes eole-server eole-exim-pkg &&\ - rm -rf /var/lib/apt/lists/* - -ENV DEBIAN_FRONTEND=text - -ENTRYPOINT [] - -CMD ["/bin/bash"] \ No newline at end of file diff --git a/misc/eole-2.6.2/eole.list b/misc/eole-2.6.2/eole.list deleted file mode 100644 index f5456a2..0000000 --- a/misc/eole-2.6.2/eole.list +++ /dev/null @@ -1,3 +0,0 @@ -deb http://eole.ac-dijon.fr/eole eole-2.6.2 main cloud -deb http://eole.ac-dijon.fr/eole eole-2.6.2-security main cloud -deb http://eole.ac-dijon.fr/eole eole-2.6.2-updates main cloud \ No newline at end of file diff --git a/playbook-sample.yml b/playbook-sample.yml new file mode 100644 index 0000000..468fb53 --- /dev/null +++ b/playbook-sample.yml @@ -0,0 +1,79 @@ +- name: Exemple de playbook Ansible pour le déploiement de module EOLE + hosts: all + tasks: + + - name: Mise à jour des valeurs de configuration Creole + # On utilise le module Ansible "eole_config" implémenté + # par ce projet + eole_config: + name: "{{ item.name }}" + value: "{{ item.value | to_json }}" + # On définie ici l'ensemble des valeurs de configuration nécessaires + # à l'instanciation d'un module eolebase. + with_items: + - name: ip_ssh_eth0 + value: [ 0.0.0.0 ] + - name: netmask_ssh_eth0 + value: [ 0.0.0.0 ] + - name: ip_admin_eth0 + value: [ 0.0.0.0 ] + - name: netmask_admin_eth0 + value: [ 0.0.0.0 ] + - name: nom_machine + value: ansible-eole + - name: nom_domaine_local + value: ansible-eole + # Dans les 3 entrées suivantes, on utilise les données récoltées + # dans les "facts" Ansible pour définir l'adresse IP de la carte + # eth0, l'adresse IP de la passerelle et les serveurs DNS. + - name: adresse_ip_eth0 + value: '{{ ansible_default_ipv4.address }}' + - name: adresse_ip_gw + value: '{{ ansible_default_ipv4.gateway }}' + - name: adresse_ip_dns + value: '{{ ansible_dns.nameservers }}' + - name: nom_academie + value: ac-ansible + - name: exim_relay_smtp + value: 127.0.0.1 + - name: numero_etab + value: '000Test' + - name: libelle_etab + value: Ansible EOLE + + # Le paquet python-pexpect est nécessaire + # à l'utilisation du module Ansible "expect" + - name: Installation de pexpect + package: + name: python-pexpect + state: present + + # On récupère l'état du module (instancié ou non) + - name: On vérifie l'état du module + eole_config: + name: module_instancie + register: module_instancie + + # On instancie le module si celui ci ne l'est pas déjà + - name: Instancier le module EOLE + when: module_instancie.value != 'oui' + expect: + command: /usr/bin/instance + # Attention, les mots de passe sont en clairs dans le playbook ! + # Il serait préférable d'utiliser le mécanisme ansible_vault ici. + responses: + "Nouveau mot de passe:": + - "NotSoSecret;21" + - "NotSoSecret;21" + "Confirmation du mot de passe:": + - "NotSoSecret;21" + - "NotSoSecret;21" + '\[non\]': + - non + '\[oui\]': + - non + timeout: 600 + + # On reconfigure le module + - name: Reconfigurer le module EOLE + command: /usr/bin/reconfigure diff --git a/src/eole_config.py b/src/eole_config.py index 9c5c88f..8e1e373 100644 --- a/src/eole_config.py +++ b/src/eole_config.py @@ -8,30 +8,30 @@ ANSIBLE_METADATA = { DOCUMENTATION = ''' --- -module: creole +module: eole_config -short_description: This is my sample module +short_description: EOLE configuration values management version_added: "2.4" description: - - "This is my longer description explaining my sample module" + - This module provides facilities to read/update EOLE configuration values. options: name: description: - - This is the message to send to the sample module + - The name of the configuration variable, as seen in "CreoleGet --list" required: true - new: + value: description: - - Control to demo if the result of this module is changed or not + - If set, update the configuration variable with this value required: false extends_documentation_fragment: - azure author: - - Your Name (@yourhandle) + - William Petit ''' EXAMPLES = ''' @@ -53,15 +53,13 @@ EXAMPLES = ''' ''' RETURN = ''' -original_message: - description: The original name param that was passed in - type: str -message: +name: description: The output message that the sample module generates ''' from ansible.module_utils.basic import AnsibleModule from creole.loader import creole_loader, config_save_values +import json def run_module(): @@ -71,13 +69,13 @@ def run_module(): value=dict(type='json', required=False), load_extra=dict(type='bool', required=False, default=True), check_mandatory=dict(type='bool', required=False, default=False), - reload_config=dict(type='bool', required=False, default=False), + reload_config=dict(type='bool', required=False, default=True) ) result = dict( changed=False, - original_message='', - message='' + path='', + name='' ) module = AnsibleModule( @@ -86,44 +84,48 @@ def run_module(): ) update_value = not module.params['value'] is None - c = creole_loader(rw=update_value, load_extra=module.params['load_extra']) - - path = c.creole.find_first(byname=module.params['name'], type_='path') - value = getattr(c, path) - result['state'] = dict( - name=module.params['name'], - value=value - ) - - if update_value: - setattr(c, path, module.params['value']) - if not module.check_mode: - try: - config_save_values( - c, 'creole', - check_mandatory=module.params['check_mandatory'], - reload_config=module.params['reload_config'] - ) - result['changed'] = True - except e: - module.fail_json(msg=str(e), **result) - else: + try: + c = creole_loader(rw=update_value, load_extra=module.params['load_extra']) + path = c.creole.find_first(byname=module.params['name'], type_='path') value = getattr(c, path) + except Exception as ex: + module.fail_json(msg=ex.message, **result) - # use whatever logic you need to determine whether or not this module - # made any modifications to your target - # if module.params['new']: - # result['changed'] = True + result['name'] = module.params['name'] + try: + result['value'] = json.loads(json.dumps(value)) + except TypeError: + result['value'] = value - # during the execution of the module, if there is an exception or a - # conditional state that effectively causes a failure, run - # AnsibleModule.fail_json() to pass in the message and the result - # if module.params['name'] == 'fail me': - # module.fail_json(msg='You requested this to fail', **result) + result['path'] = path + + try: + if update_value: + + new_value = module.params['value'] + + if isinstance(new_value, str): + new_value = unicode(new_value) + + new_value = json.loads(new_value) + + if value != new_value: + + setattr(c, path, new_value) + value = getattr(c, path) + + if not module.check_mode: + config_save_values( + c, 'creole', + check_mandatory=module.params['check_mandatory'], + reload_config=module.params['reload_config'] + ) + result['changed'] = True + + except Exception as ex: + module.fail_json(msg=ex.message, **result) - # in the event of a successful module execution, you will want to - # simple AnsibleModule.exit_json(), passing the key/value results module.exit_json(**result) def main():