Browse Source

Basic protoype

- Set/get Creole values by their names
- Handles multi values and master/slaves
- Basic playbook with module instanciation
William Petit 1 month ago
parent
commit
3185f8a46c
9 changed files with 173 additions and 140 deletions
  1. 2
    0
      .gitignore
  2. 9
    28
      Makefile
  3. 34
    2
      README.md
  4. 0
    20
      misc/ansible-eole/Dockerfile
  5. 0
    1
      misc/ansible-eole/bashrc
  6. 0
    39
      misc/eole-2.6.2/Dockerfile
  7. 0
    3
      misc/eole-2.6.2/eole.list
  8. 79
    0
      playbook-sample.yml
  9. 49
    47
      src/eole_config.py

+ 2
- 0
.gitignore View File

@@ -0,0 +1,2 @@
1
+/inventory
2
+*.retry

+ 9
- 28
Makefile View File

@@ -1,29 +1,10 @@
1
-eole-2.6.2:
2
-	docker build \
3
-		--build-arg HTTP_PROXY=$(HTTP_PROXY) \
4
-		--build-arg HTTPS_PROXY=$(HTTPS_PROXY) \
5
-		--build-arg http_proxy=$(http_proxy) \
6
-		--build-arg https_proxy=$(https_proxy) \
7
-		-t eolebase-2.6.2:latest \
8
-		./misc/eole-2.6.2
1
+DESTDIR := ./
2
+install:
3
+	install -d $(DESTDIR)usr/share/ansible/plugins/modules
4
+	install src/eole_config.py $(DESTDIR)usr/share/ansible/plugins/modules
5
+	
6
+link-dev:
7
+	mkdir -p "$(HOME)/.ansible/plugins/modules"
8
+	ln -s "$(PWD)/src" "$(HOME)/.ansible/plugins/modules/eole"
9 9
 
10
-ansible-eole: eole-2.6.2
11
-	docker build \
12
-		--build-arg HTTP_PROXY=$(HTTP_PROXY) \
13
-		--build-arg HTTPS_PROXY=$(HTTPS_PROXY) \
14
-		--build-arg http_proxy=$(http_proxy) \
15
-		--build-arg https_proxy=$(https_proxy) \
16
-		-t ansible-eole:latest \
17
-		./misc/ansible-eole
18
-
19
-dev-env:
20
-	docker run \
21
-		-it \
22
-		--rm \
23
-		-v "$(PWD)/src/eole_config.py:/ansible/lib/ansible/modules/system/eole_config.py:ro" \
24
-		-v "$(PWD)/testdata:/testdata:ro" \
25
-		--network host \
26
-		--name ansible-creole-dev-env \
27
-		ansible-eole
28
-
29
-.PHONY: eole-2.6.2 ansible-eole
10
+.PHONY: link-locally install

+ 34
- 2
README.md View File

@@ -1,9 +1,41 @@
1 1
 # Ansible - EOLE
2 2
 
3
-Module Ansible permettant de configurer une distribution EOLE
3
+Module Ansible permettant de manipuler les valeurs de configuration Creole d'un module EOLE.
4
+
5
+**Stabilité** expérimental
6
+
7
+## Démonstration
8
+
9
+[![asciicast](https://asciinema.org/a/3PyxG4M43cXW0wiUQlgkt3pwQ.svg)](https://asciinema.org/a/3PyxG4M43cXW0wiUQlgkt3pwQ)
10
+
11
+Voir le fichier [`playbook-sample.yml`](./playbook-sample.yml) pour plus de détails.
12
+
13
+## Utilisation
14
+
15
+```shell
16
+# Récupérer les sources du projet
17
+git clone https://forge.cadoles.com/wpetit/ansible-eole.git
18
+cd ansible-eole
19
+
20
+# Exposer le module à Ansible
21
+# Voir la section ressources pour plus d'informations sur les modules locaux.
22
+make link-dev
23
+
24
+# Créer un fichier d'inventaire simple
25
+cat > inventory <<EOF
26
+[all]
27
+<ip_machine> ansible_user=root
28
+EOF
29
+
30
+# Utiliser le playbook d'exemple avec le fichier d'inventaire
31
+ansible-playbook -i inventory playbook-sample.yml
32
+```
4 33
 
5 34
 ## Ressources
6 35
 
7 36
 - [Développement de modules Ansible](https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_general.html)
37
+- [Ajout des modules/plugins locaux à Ansible](https://docs.ansible.com/ansible/latest/dev_guide/developing_locally.html)
38
+
39
+## Licence
8 40
 
9
-/usr/lib/python2.7/dist-packages/tiramisu/config.py
41
+GPL-3.0

+ 0
- 20
misc/ansible-eole/Dockerfile View File

@@ -1,20 +0,0 @@
1
-FROM eolebase-2.6.2:latest
2
-
3
-ARG HTTP_PROXY=
4
-ARG HTTPS_PROXY=
5
-ARG http_proxy=
6
-ARG https_proxy=
7
-ARG DEBIAN_FRONTEND=noninteractive
8
-
9
-RUN apt-get update -y &&\
10
-    apt-get install -y build-essential libssl-dev libffi-dev python-dev python-pip git &&\
11
-    rm -rf /var/lib/apt/lists/*
12
-
13
-RUN git clone https://github.com/ansible/ansible.git &&\
14
-    cd ansible &&\
15
-    pip install wheel &&\
16
-    pip install -r requirements.txt    
17
-
18
-COPY bashrc /root/.bashrc
19
-
20
-WORKDIR ansible

+ 0
- 1
misc/ansible-eole/bashrc View File

@@ -1 +0,0 @@
1
-. hacking/env-setup

+ 0
- 39
misc/eole-2.6.2/Dockerfile View File

@@ -1,39 +0,0 @@
1
-FROM ubuntu:16.04
2
-
3
-ARG HTTP_PROXY=
4
-ARG HTTPS_PROXY=
5
-ARG http_proxy=
6
-ARG https_proxy=
7
-ENV DEBIAN_FRONTEND=noninteractive
8
-
9
-# systemd/docker compatibility configuration
10
-# See https://developers.redhat.com/blog/2016/09/13/running-systemd-in-a-non-privileged-container/
11
-ENV container=docker
12
-STOPSIGNAL SIGRTMIN+3
13
-
14
-RUN apt-get update -y && apt-get install -y locales wget keyboard-configuration
15
-RUN locale-gen --purge fr_FR.UTF-8
16
-
17
-ENV LC_ALL=fr_FR.UTF-8
18
-ENV LANG=french
19
-
20
-# Install apt-show-versions
21
-# See https://askubuntu.com/questions/916199/install-apt-show-versions-inside-an-ubuntu-docker-container
22
-RUN rm /etc/apt/apt.conf.d/docker-gzip-indexes &&\
23
-  apt-get purge apt-show-versions &&\
24
-  rm /var/lib/apt/lists/*lz4 &&\
25
-  apt-get -o Acquire::GzipIndexes=false update &&\
26
-  apt-get install -y apt-show-versions
27
-
28
-# Configure then install EOLE packages
29
-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 -
30
-COPY eole.list /etc/apt/sources.list.d/eole.list
31
-RUN apt-get update -y &&\
32
-  apt-get install -y --force-yes eole-server eole-exim-pkg &&\
33
-  rm -rf /var/lib/apt/lists/*
34
-
35
-ENV DEBIAN_FRONTEND=text
36
-
37
-ENTRYPOINT []
38
-
39
-CMD ["/bin/bash"]

+ 0
- 3
misc/eole-2.6.2/eole.list View File

@@ -1,3 +0,0 @@
1
-deb http://eole.ac-dijon.fr/eole eole-2.6.2 main cloud
2
-deb http://eole.ac-dijon.fr/eole eole-2.6.2-security main cloud
3
-deb http://eole.ac-dijon.fr/eole eole-2.6.2-updates main cloud

+ 79
- 0
playbook-sample.yml View File

@@ -0,0 +1,79 @@
1
+- name: Exemple de playbook Ansible pour le déploiement de module EOLE
2
+  hosts: all
3
+  tasks:
4
+
5
+    - name: Mise à jour des valeurs de configuration Creole
6
+      # On utilise le module Ansible "eole_config" implémenté
7
+      # par ce projet
8
+      eole_config:
9
+        name: "{{ item.name }}"
10
+        value: "{{ item.value | to_json }}"
11
+      # On définie ici l'ensemble des valeurs de configuration nécessaires
12
+      # à l'instanciation d'un module eolebase.
13
+      with_items:
14
+        - name: ip_ssh_eth0
15
+          value: [ 0.0.0.0 ]
16
+        - name: netmask_ssh_eth0
17
+          value: [ 0.0.0.0 ]
18
+        - name: ip_admin_eth0
19
+          value: [ 0.0.0.0 ]
20
+        - name: netmask_admin_eth0
21
+          value: [ 0.0.0.0 ]
22
+        - name: nom_machine
23
+          value: ansible-eole
24
+        - name: nom_domaine_local
25
+          value: ansible-eole
26
+        # Dans les 3 entrées suivantes, on utilise les données récoltées
27
+        # dans les "facts" Ansible pour définir l'adresse IP de la carte
28
+        # eth0, l'adresse IP de la passerelle et les serveurs DNS.
29
+        - name: adresse_ip_eth0
30
+          value: '{{ ansible_default_ipv4.address }}'
31
+        - name: adresse_ip_gw
32
+          value: '{{ ansible_default_ipv4.gateway }}'
33
+        - name: adresse_ip_dns
34
+          value: '{{ ansible_dns.nameservers }}'
35
+        - name: nom_academie
36
+          value: ac-ansible
37
+        - name: exim_relay_smtp
38
+          value: 127.0.0.1
39
+        - name: numero_etab
40
+          value: '000Test'
41
+        - name: libelle_etab
42
+          value: Ansible EOLE
43
+    
44
+    # Le paquet python-pexpect est nécessaire
45
+    # à l'utilisation du module Ansible "expect"
46
+    - name: Installation de pexpect
47
+      package:
48
+        name: python-pexpect
49
+        state: present
50
+    
51
+    # On récupère l'état du module (instancié ou non)
52
+    - name: On vérifie l'état du module
53
+      eole_config:
54
+        name: module_instancie
55
+      register: module_instancie
56
+    
57
+    # On instancie le module si celui ci ne l'est pas déjà
58
+    - name: Instancier le module EOLE
59
+      when: module_instancie.value != 'oui'
60
+      expect:
61
+        command: /usr/bin/instance
62
+        # Attention, les mots de passe sont en clairs dans le playbook !
63
+        # Il serait préférable d'utiliser le mécanisme ansible_vault ici.
64
+        responses:
65
+          "Nouveau mot de passe:":
66
+            - "NotSoSecret;21"
67
+            - "NotSoSecret;21"
68
+          "Confirmation du mot de passe:":
69
+            - "NotSoSecret;21"
70
+            - "NotSoSecret;21"
71
+          '\[non\]':
72
+            - non
73
+          '\[oui\]':
74
+            - non
75
+        timeout: 600
76
+    
77
+    # On reconfigure le module
78
+    - name: Reconfigurer le module EOLE
79
+      command: /usr/bin/reconfigure

+ 49
- 47
src/eole_config.py View File

@@ -8,30 +8,30 @@ ANSIBLE_METADATA = {
8 8
 
9 9
 DOCUMENTATION = '''
10 10
 ---
11
-module: creole
11
+module: eole_config
12 12
 
13
-short_description: This is my sample module
13
+short_description: EOLE configuration values management
14 14
 
15 15
 version_added: "2.4"
16 16
 
17 17
 description:
18
-    - "This is my longer description explaining my sample module"
18
+    - This module provides facilities to read/update EOLE configuration values.
19 19
 
20 20
 options:
21 21
     name:
22 22
         description:
23
-            - This is the message to send to the sample module
23
+            - The name of the configuration variable, as seen in "CreoleGet --list"
24 24
         required: true
25
-    new:
25
+    value:
26 26
         description:
27
-            - Control to demo if the result of this module is changed or not
27
+            - If set, update the configuration variable with this value
28 28
         required: false
29 29
 
30 30
 extends_documentation_fragment:
31 31
     - azure
32 32
 
33 33
 author:
34
-    - Your Name (@yourhandle)
34
+    - William Petit
35 35
 '''
36 36
 
37 37
 EXAMPLES = '''
@@ -53,15 +53,13 @@ EXAMPLES = '''
53 53
 '''
54 54
 
55 55
 RETURN = '''
56
-original_message:
57
-    description: The original name param that was passed in
58
-    type: str
59
-message:
56
+name:
60 57
     description: The output message that the sample module generates
61 58
 '''
62 59
 
63 60
 from ansible.module_utils.basic import AnsibleModule
64 61
 from creole.loader import creole_loader, config_save_values
62
+import json
65 63
 
66 64
 def run_module():
67 65
 
@@ -71,13 +69,13 @@ def run_module():
71 69
         value=dict(type='json', required=False),
72 70
         load_extra=dict(type='bool', required=False, default=True),
73 71
         check_mandatory=dict(type='bool', required=False, default=False),
74
-        reload_config=dict(type='bool', required=False, default=False),
72
+        reload_config=dict(type='bool', required=False, default=True)
75 73
     )
76 74
 
77 75
     result = dict(
78 76
         changed=False,
79
-        original_message='',
80
-        message=''
77
+        path='',
78
+        name=''
81 79
     )
82 80
 
83 81
     module = AnsibleModule(
@@ -86,44 +84,48 @@ def run_module():
86 84
     )
87 85
 
88 86
     update_value = not module.params['value'] is None
89
-    c = creole_loader(rw=update_value, load_extra=module.params['load_extra'])
90
-    
91
-    path = c.creole.find_first(byname=module.params['name'], type_='path')
92
-    value = getattr(c, path)
93
-
94
-    result['state'] = dict(
95
-        name=module.params['name'],
96
-        value=value
97
-    )
98 87
 
99
-    if update_value:
100
-        setattr(c, path, module.params['value'])
101
-        if not module.check_mode:
102
-            try:
103
-                config_save_values(
104
-                    c, 'creole', 
105
-                    check_mandatory=module.params['check_mandatory'],
106
-                    reload_config=module.params['reload_config']
107
-                )
108
-                result['changed'] = True
109
-            except e:
110
-                module.fail_json(msg=str(e), **result)
111
-    else:
88
+    try:
89
+        c = creole_loader(rw=update_value, load_extra=module.params['load_extra'])
90
+        path = c.creole.find_first(byname=module.params['name'], type_='path')
112 91
         value = getattr(c, path)
92
+    except Exception as ex:
93
+        module.fail_json(msg=ex.message, **result)
94
+
95
+    result['name'] = module.params['name']
96
+    try:
97
+        result['value'] = json.loads(json.dumps(value))
98
+    except TypeError:
99
+        result['value'] = value
100
+
101
+    result['path'] = path
102
+
103
+    try:
104
+        if update_value:
105
+
106
+            new_value = module.params['value']
107
+
108
+            if isinstance(new_value, str): 
109
+                new_value = unicode(new_value)
110
+
111
+            new_value = json.loads(new_value)
112
+
113
+            if value != new_value:
114
+
115
+                setattr(c, path, new_value)
116
+                value = getattr(c, path)
113 117
 
114
-    # use whatever logic you need to determine whether or not this module
115
-    # made any modifications to your target
116
-    # if module.params['new']:
117
-    #     result['changed'] = True
118
+                if not module.check_mode:
119
+                    config_save_values(
120
+                        c, 'creole', 
121
+                        check_mandatory=module.params['check_mandatory'],
122
+                        reload_config=module.params['reload_config']
123
+                    )
124
+                    result['changed'] = True
118 125
 
119
-    # during the execution of the module, if there is an exception or a
120
-    # conditional state that effectively causes a failure, run
121
-    # AnsibleModule.fail_json() to pass in the message and the result
122
-    # if module.params['name'] == 'fail me':
123
-    #     module.fail_json(msg='You requested this to fail', **result)
126
+    except Exception as ex:
127
+        module.fail_json(msg=ex.message, **result)
124 128
 
125
-    # in the event of a successful module execution, you will want to
126
-    # simple AnsibleModule.exit_json(), passing the key/value results
127 129
     module.exit_json(**result)
128 130
 
129 131
 def main():