Merge branch 'clean-up' into 'newinfra'

Clean up

See merge request nounous/ansible!143
certbot_on_virtu
_pollion 2020-12-30 13:16:08 +01:00
commit 80604fc232
11 changed files with 342 additions and 263 deletions

View File

@ -0,0 +1,177 @@
#!/usr/bin/env python3
# Copyright: (c) 2019, Alexandre Iooss <erdnaxe@crans.org>
#
# GNU General Public License v3.0+
import re
import urllib.error
import urllib.parse
import urllib.request
import difflib
from ansible.errors import AnsibleError
from ansible.plugins.action import ActionBase
from ansible.utils.display import Display
from ansible.module_utils._text import to_native
display = Display()
class ActionModule(ActionBase):
TRANSFERS_FILES = False
_VALID_ARGS = frozenset(('url', 'user', 'password', 'content', 'revision_comment'))
def login(self, url, user, password):
"""
Log in and return session cookie or None if failed
:param url: random wiki url (not root page)
:param user: wiki user
:param password: user's password
:return: session cookie
"""
# Send a HTTP POST request
data = urllib.parse.urlencode({
'action': 'login',
'login': 'Connexion',
'name': user,
'password': password
}).encode()
req = urllib.request.Request(url, data)
try:
response = urllib.request.urlopen(req)
cookie = response.getheader('set-cookie')
except urllib.error.HTTPError as e:
# If 404, then also return header
cookie = e.getheader('set-cookie')
# Check that authentication worked
if not cookie:
raise AnsibleError(to_native('server did not return a session cookie'))
return cookie
def craft_request(self, suffix):
"""
Crafts a function that takes an url and a cookie,
and returns the content of the requested page with given action suffix.
"""
def f(url, cookie):
req = urllib.request.Request(url + suffix)
req.add_header("Cookie", cookie)
content = urllib.request.urlopen(req).read().decode('utf-8')
return content
return f
def edit_ticket(self, url, cookie):
"""
Return edition ticket of url
:param url: page to edit
:param cookie: session cookie
:return: edit ticket
"""
# Send request with session cookie
content = self.craft_request("?action=edit&editor=text")(url, cookie)
# Search for ticket
search = re.search('name=\"ticket\" value=\"([^\"]*)\"', content)
if not search:
raise AnsibleError(to_native('no edit ticket was found'))
return search.group(1)
def edit(self, url, user, password, content, revision_comment, cookie):
"""
Edit a MoinMoin wiki page
:param url: page to edit
:param user: wiki user
:param password: user's password
:param content: content to place on this page
:param revision_comment: revision comment
"""
# Connect and get edit ticket
ticket = self.edit_ticket(url, cookie)
# Create request and send
data = {
'button_save': 'Enregistrer les modifications',
'category': '',
'comment': revision_comment.encode("utf-8"),
'savetext': content.encode("utf-8"),
'action': 'edit',
'ticket': ticket
}
req = urllib.request.Request(url, urllib.parse.urlencode(data).encode())
req.add_header("Cookie", cookie)
urllib.request.urlopen(req)
def run(self, tmp=None, task_vars=None):
"""
The run method is the main Action Plugin driver. All work is done from within this method.
tmp: Temporary directory. Sometimes an action plugin sets up
a temporary directory and then calls another module. This parameter
allows us to reuse the same directory for both.
task_vars: The variables (host vars, group vars, config vars, etc) associated with this task.
Note that while this will contain Ansible facts from the host, they should be used
with caution as a user running Ansible can disable their collection. If you want
make sure that your Action Plugin always has access to the ones it needs, you may
want to consider running the setup module directly in the run the method and getting
the Ansible facts that way.
The strategy plugin which manages running tasks on instances uses an ansible.vars.manager
VariableManager instance to retrieve this context specific dict of variables.
"""
if task_vars is None:
task_vars = dict()
result = super(ActionModule, self).run(tmp, task_vars)
del tmp
url = self._task.args.get("url")
user = self._task.args.get("user")
password = self._task.args.get("password")
content = self._task.args.get("content")
revision_comment = self._task.args.get("revision_comment")
cookie = self.login(url, user, password)
try:
raw = self.craft_request("?action=raw")(url, cookie)
except urllib.error.HTTPError: # We will create the page.
raw = ""
diff = difflib.unified_diff(raw.splitlines(), content.splitlines(), fromfile="old", tofile="new", lineterm="")
i=0
# Display any change
for line in diff:
i+=1
if line.startswith("-"):
display.display(line, "red")
elif line.startswith("+"):
display.display(line, "green")
elif line.startswith("@"):
display.display(line, "yellow")
else:
display.display(line)
# Do apply the change if not in check mode
if not self._play_context.check_mode:
self.edit(url, user, password, content, revision_comment, cookie)
result['changed']=i>0
self._supports_check_mode = True
self._supports_async = False
return result

View File

@ -5,13 +5,13 @@
- import_playbook: plays/mail.yml
- import_playbook: plays/nfs.yml
#- import_playbook: plays/logs.yml
#- import_playbook: plays/backup.yml
- import_playbook: plays/network-interfaces.yml
#- import_playbook: plays/logs.yml TODO: rsyncd
- import_playbook: plays/backup.yml
# - import_playbook: plays/network-interfaces.yml TODO: check this paybook
- import_playbook: plays/monitoring.yml
# Services that only apply to a subset of server
- import_playbook: plays/cas.yml
# - import_playbook: plays/cas.yml
- import_playbook: plays/dhcp.yml
- import_playbook: plays/dns.yml
- import_playbook: plays/etherpad.yml

222
hosts
View File

@ -1,70 +1,59 @@
# Crans servers inventory
# How to name your server ?
# > We name servers according to location, then type.
# > Then we regroup everything in global geographic and type groups.
# [framadate]
# voyager.adm.crans.org
#
# [dhcp]
# dhcp.adm.crans.org
# odlyd.adm.crans.org
#
# [keepalived]
# gulp.adm.crans.org
# odlyd.adm.crans.org
# eap.adm.crans.org
# radius.adm.crans.org
# frontdaur.adm.crans.org
# bakdaur.adm.crans.org
#
# [test_vm]
# re2o-test.adm.crans.org
[dovecot]
owl.adm.crans.org
[backups]
zephir.adm.crans.org
[certbot]
gitzly.adm.crans.org
[certbot:children]
radius # We use certbot to manage LE certificates
reverseproxy
dovecot
[nginx_rtmp]
fluxx.adm.crans.org
[reverseproxy]
hodaur.adm.crans.org
[roundcube]
roundcube-srv.adm.crans.org
[ethercalc]
ethercalc-srv.adm.crans.org
[horde]
horde.adm.crans.org
[radius]
routeur-sam.adm.crans.org
[re2o]
re2o-newinfra.adm.crans.org
routeur-sam.adm.crans.org
[baie]
cameron.adm.crans.org
tealc.adm.crans.org
[bdd]
tealc.adm.crans.org
[virtu]
sam.adm.crans.org
daniel.adm.crans.org
jack.adm.crans.org
[certbot:children]
dovecot
git
radius # We use certbot to manage LE certificates
reverseproxy
[dhcp:children]
routeurs_vm
[dns_auth_master]
silice.adm.crans.org
[dns_authoritative:children]
dns_auth_master
freebox
ovh_physical
[dns_recursive:children]
routeurs_vm
[dovecot]
owl.adm.crans.org
[ethercalc]
ethercalc-srv.adm.crans.org
[framadate]
voyager.adm.crans.org
[freebox]
boeing.adm.crans.org
titanic.adm.crans.org
[git]
gitzly.adm.crans.org
[horde]
horde.adm.crans.org
[irc]
irc.adm.crans.org
[keepalived:children]
routeurs_vm
[ldap_server]
tealc.adm.crans.org
@ -72,55 +61,98 @@ sam.adm.crans.org
daniel.adm.crans.org
jack.adm.crans.org
[keepalived]
[monitoring]
monitoring.adm.crans.org
[nginx]
charybde.adm.crans.org
[nginx_rtmp]
fluxx.adm.crans.org
[nginx:children]
reverseproxy
[postfix]
mailman.adm.crans.org
redisdead.adm.crans.org
zamok.adm.crans.org
[postfix:children]
freebox
ovh_physical
[radius:children]
routeurs_vm
[re2o]
re2o-newinfra.adm.crans.org
[re2o:children]
radius
[reverseproxy]
hodaur.adm.crans.org
[roundcube]
roundcube-srv.adm.crans.org
[routeurs_vm]
routeur-daniel.adm.crans.org
routeur-jack.adm.crans.org
routeur-sam.adm.crans.org
#routeur-daniel.adm.crans.org
[dhcp]
routeur-sam.adm.crans.org
#routeur-daniel.adm.crans.org
[crans_routeurs:children]
dhcp
keepalived
[crans_physical]
cameron.adm.crans.org
tealc.adm.crans.org
sam.adm.crans.org
[virtu]
daniel.adm.crans.org
jack.adm.crans.org
#gulp.adm.crans.org
zephir.adm.crans.org
sam.adm.crans.org
[crans_routeurs:children]
# dhcp TODO: Really needed ?
# keepalived
routeurs_vm
[crans_physical]
charybde.adm.crans.org
omnomnom.adm.crans.org
zamok.adm.crans.org
[crans_physical:children]
backups
baie
virtu
[crans_vm]
owl.adm.crans.org
codichotomie.adm.crans.org
voyager.adm.crans.org
#silice.adm.crans.org
routeur-sam.adm.crans.org
#routeur-daniel.adm.crans.org
#belenios.adm.crans.org
#re2o-ldap.adm.crans.org
bigbluebutton.adm.crans.org
#boeing.adm.crans.org
#casouley.adm.crans.org
codichotomie.adm.crans.org
#ethercalc-srv.adm.crans.org
fluxx.adm.crans.org
gitlab-ci.adm.crans.org
gitzly.adm.crans.org
hodaur.adm.crans.org
monitoring.adm.crans.org
#boeing.adm.crans.org
fluxx.adm.crans.org
#unifi.adm.crans.org
#pastemoisa.adm.crans.org
#casouley.adm.crans.org
horde.adm.crans.org
irc.adm.crans.org
jitsi.adm.crans.org
kenobi.adm.crans.org
kiwi.adm.crans.org
kiwijuice.adm.crans.org
tracker.adm.crans.org
jitsi.adm.crans.org
#ethercalc-srv.adm.crans.org
kenobi.adm.crans.org
roundcube.adm.crans.org
horde.adm.crans.org
bigbluebutton.adm.crans.org
monitoring.adm.crans.org
owl.adm.crans.org
owncloud.adm.crans.org
#re2o-ldap.adm.crans.org
redisdead.adm.crans.org
roundcube.adm.crans.org
#silice.adm.crans.org
titanic.adm.crans.org
tracker.adm.crans.org
voyager.adm.crans.org
#unifi.adm.crans.org
[crans_vm:children]
routeurs_vm
[ovh_physical]
sputnik.adm.crans.org
@ -129,7 +161,6 @@ sputnik.adm.crans.org
[crans_server:children]
crans_physical
crans_vm
crans_routeurs
# everything at crans
[crans:children]
@ -147,7 +178,6 @@ ovh_physical
# every virtual machine
[vm:children]
crans_vm
crans_routeurs
# every server
[server:children]

View File

@ -1,12 +1,12 @@
#!/usr/bin/env ansible-playbook
---
# Deploy recursive DNS cache server
- hosts: routeur-sam.adm.crans.org,routeur-daniel.adm.crans.org
- hosts: dns_recursive
roles:
- bind-recursive
# Deploy authoritative DNS server
- hosts: silice.adm.crans.org,sputnik.adm.crans.org,boeing.adm.crans.org
- hosts: dns_authoritative
vars:
certbot_dns_secret: "{{ vault_certbot_dns_secret }}"
certbot_adm_dns_secret: "{{ vault_certbot_adm_dns_secret }}"
@ -18,7 +18,7 @@
roles:
- bind-authoritative
- hosts: silice.adm.crans.org
- hosts: dns_auth_master
vars:
re2o:
server: re2o.adm.crans.org

View File

@ -6,7 +6,7 @@
# All other servers uses nullmailer to send local mail to Crans SMTP.
# Redirect local mail to mailserver
- hosts: crans_server,!redisdead.adm.crans.org,!soyouz.adm.crans.org,!titanic.adm.crans.org,!boeing.adm.crans.org,!sputnik.adm.crans.org,!zamok.adm.crans.org,!mailman.adm.crans.org
- hosts: crans_server,!postfix
vars:
mail_root: root@crans.org
mail_smtp_server: smtp.adm.crans.org

View File

@ -1,7 +1,7 @@
#!/usr/bin/env ansible-playbook
---
# Deploy Prometheus and Grafana on monitoring server
- hosts: monitoring.adm.crans.org
- hosts: monitoring
vars:
# Prometheus targets.json
prometheus:
@ -64,13 +64,13 @@
# Monitor all hosts
- hosts: server,test_vm
- hosts: server
vars:
adm_ipv4: "{{ query('ldap', 'ip', ansible_hostname, 'adm') | ipv4 | first }}"
roles: ["prometheus-node-exporter"]
# Export nginx metrics
- hosts: charybde.adm.crans.org,hodaur.adm.crans.org
- hosts: nginx
vars:
adm_ipv4: "{{ query('ldap', 'ip', ansible_hostname, 'adm') | ipv4 | first }}"
roles: ["prometheus-nginx-exporter"]

View File

@ -20,9 +20,7 @@
insertafter: '127.0.0.1 localhost'
when: check_mirror.found == 0
- hosts: tealc.adm.crans.org
- hosts: baie
roles:
- baie
@ -75,7 +73,7 @@
roles:
- openssh
- hosts: server
- hosts: crans_vm
tasks:
- name: Remove cloud-init
apt:

View File

@ -32,7 +32,6 @@ EXAMPLES = '''
'''
import dmidecode
import json
from ansible.module_utils.basic import AnsibleModule
@ -48,16 +47,30 @@ def decode_dict(data):
def run_module():
module = AnsibleModule(
argument_spec = {}
argument_spec = {},
supports_check_mode=True,
)
dmi_data = decode_dict({
'bios': dmidecode.bios(),
'processor': dmidecode.processor(),
'system': dmidecode.system(),
'memory': dmidecode.memory(),
'slot': dmidecode.slot(),
})
module.exit_json(changed=True, ansible_facts=dmi_data)
try:
import dmidecode
dmi_data = decode_dict({
'bios': dmidecode.bios(),
'processor': dmidecode.processor(),
'system': dmidecode.system(),
'memory': dmidecode.memory(),
'slot': dmidecode.slot(),
})
except ImportError:
dmi_data = {
'bios': dict(),
'processor': dict(),
'system': dict(),
'memory': dict(),
'slot': dict(),
}
module.exit_json(changed=False, ansible_facts=dmi_data)
def main():

View File

@ -1,139 +0,0 @@
#!/usr/bin/env python3
# Copyright: (c) 2019, Alexandre Iooss <erdnaxe@crans.org>
# GNU General Public License v3.0+
"""
This module simulate the edition of a MoinMoin wiki page
Example:
moinmoin_page:
url: https://wiki.crans.org/WikiErdnaxe
user: WikiErdnaxe
password: HoTuNeMeConnaisPas
content: "{{ lookup('template', 'mapage.j2') }}"
revision_comment: Bip bip
"""
import re
import urllib.error
import urllib.parse
import urllib.request
from ansible.module_utils.basic import AnsibleModule
def login(url, user, password):
"""
Log in and return session cookie or None if failed
:param url: random wiki url (not root page)
:param user: wiki user
:param password: user's password
:return: session cookie
"""
# Send a HTTP POST request
data = urllib.parse.urlencode({
'action': 'login',
'login': 'Connexion',
'name': user,
'password': password
}).encode()
req = urllib.request.Request(url, data)
try:
response = urllib.request.urlopen(req)
cookie = response.getheader('set-cookie')
except urllib.error.HTTPError as e:
# If 404, then also return header
cookie = e.getheader('set-cookie')
# Check that authentication worked
assert cookie, 'server did not return a session cookie'
return cookie
def edit_ticket(url, cookie):
"""
Return edition ticket of url
:param url: page to edit
:param cookie: session cookie
:return: edit ticket
"""
# Send request with session cookie
suffix = "?action=edit&editor=text"
req = urllib.request.Request(url + suffix)
req.add_header("Cookie", cookie)
content = urllib.request.urlopen(req).read().decode('utf-8')
# Search for ticket
search = re.search('name=\"ticket\" value=\"([^\"]*)\"', content)
assert search, 'no edit ticket was found'
return search.group(1)
def edit(url, user, password, content, revision_comment):
"""
Edit a MoinMoin wiki page
:param url: page to edit
:param user: wiki user
:param password: user's password
:param content: content to place on this page
:param revision_comment: revision comment
"""
# Connect and get edit ticket
cookie = login(url, user, password)
ticket = edit_ticket(url, cookie)
# Create request and send
data = {
'button_save': 'Enregistrer les modifications',
'category': '',
'comment': revision_comment.encode("utf-8"),
'savetext': content.encode("utf-8"),
'action': 'edit',
'ticket': ticket
}
req = urllib.request.Request(url, urllib.parse.urlencode(data).encode())
req.add_header("Cookie", cookie)
urllib.request.urlopen(req)
def run_module():
# Define arguments that should be passed
module_args = {
'url': {'type': 'str', 'required': True},
'user': {'type': 'str', 'required': True},
'password': {'type': 'str', 'required': True},
'content': {'type': 'str', 'required': True},
'revision_comment': {'type': 'str', 'required': True},
}
# Define arguments that are returned
result = {
'changed': False,
}
# Our AnsibleModule
module = AnsibleModule(
argument_spec=module_args,
supports_check_mode=True
)
# TODO: get current wiki page and compare
result['changed'] = True
# If not is check mode and page need to change, then update page
if not module.check_mode and result['changed']:
edit(**module.params)
module.exit_json(**result)
def main():
run_module()
if __name__ == '__main__':
main()

View File

@ -8,7 +8,7 @@
until: apt_result is succeeded
- name: get dmidecode facts
dmidecode: {}
dmidecode_facts: {}
- name: get ssh fingerprints
sshfp: {}

View File

@ -56,7 +56,7 @@ et {{ (ansible_memory_mb.swap.total/1024)|round(1) }} GiB de SWAP.
== Caractéristiques logicielles ==
'''Système d'exploitation''' :
{{ ansible_lsb.description }}
{{ ansible_distribution }} {{ ansible_distribution_major_version }} ({{ ansible_distribution_release }})
'''Noyau''' :
{{ ansible_kernel }}