+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""Script de génération automatique de fichier ~/.ssh/config
+
+TODO : mettre une option pour append le ssh des bornes
+"""
+
+import sys
+import re
+sys.path.append('/usr/scripts/')
+
+import lc_ldap.shortcuts
+import lc_ldap.objets
+
+#: Fichier à inclure au début
+static_before_file = "./static_before"
+
+#: Fichier à inclure à la fin
+static_after_file = "./static_after"
+
+#: regexp pour exclure certains "serveurs"
+black_regex = re.compile('^((bigbrother|hugebrother|littlebrother|tinybrother|imprimante|vigile(--?\d[a-z])?|bat[abcghijmopk]-\d|minigiga|multiprise-v6|chu|pika|kvm|pulsar|nols2?).adm.crans.org|ftp.federez.net|ns1.crans.ens-cachan.fr)$')
+
+#: Proxy pour contacter le VLAN adm
+adm_proxy = u"sable.crans.org"
+
+#: Login pour se connecter sur les serveurs Cr@ns
+login_crans = u"legallic"
+
+#: À afficher avant les serveurs Cr@ns
+crans_header = u"""
+# +-------------------+
+# | Serveurs du Cr@ns |
+# +-------------------+
+# Accessible aux apprentis
+# sauf zamok et ssh2, accessibles à tous les adhérents
+
+"""
+
+#: À afficher avant les serveurs adm
+crans_adm_header = u"""
+# +-------------------------+
+# | Serveurs Cr@ns adm-only |
+# +-------------------------+
+# Accessibles aux apprentis, mais ne sont que sur le VLAN adm
+# d'où la ProxyCommand
+# fy et fz ne sont accessibles qu'aux nounous
+
+"""
+
+def blacklisted(key, aliases):
+ """Répond True si le serveur ne doit pas apparaître dans le fichier de conf."""
+ for a in aliases:
+ if black_regex.match(a):
+ return True
+ return False
+
+def cache_servers(servs):
+ import json
+ json.dump(servs, open("plouf.json", "w"))
+
+def load_servers():
+ import json
+ return json.load(open("plouf.json"))
+
+def get_servers(help=None):
+ """Récupère la liste des serveurs dans la base LDAP."""
+ if help is None:
+ c = lc_ldap.shortcuts.lc_ldap_readonly(user=u"legallic")
+
+ l = c.allMachines()
+ l = [m for m in l if isinstance(m, lc_ldap.objets.machineCrans)]
+ else:
+ l = help
+
+ hosts = {}
+ for m in l:
+ host = m["host"][0].value
+ h = host.replace(".crans.org", "")
+ if hosts.has_key(h):
+ print (u"Doublon : clé %s had %r and wants %r" % (h, hosts[h], [host] + [a.value for a in m["hostAlias"]])).encode("utf-8")
+ else:
+ hosts[h] = [host] + [a.value for a in m["hostAlias"]]
+ return hosts
+
+def output(key, aliases, use_adm_proxy=False):
+ """ Renvoie le block de conf pour un host.
+ Traite particulièrment : ssh2, les ilo, la ferme"""
+ # On teste si le serveur est dans la ferme
+ ferme = any([a.endswith(u".ferme.crans.org") for a in aliases])
+ shorts = list(set([a.replace(".crans.org", "") for a in aliases]))
+ if ferme:
+ shorts.append(a.split(".", 1)[0])
+ shorts.sort()
+ if key in shorts:
+ shorts.remove(key)
+ out = u"Host %s\n" % (u" ".join([key] + shorts + aliases))
+ if key=="ssh2":
+ out += u" # Un serveur ssh qui n'est qu'un nat vers 138.231.136.1:22\n"
+ out += u" # pour passer à travers les blocages de ports (443 = https)\n"
+ out += u" HostName 138.231.136.2\n"
+ out += u" Port 443\n"
+ out += u" User %s\n" % login_crans
+ out += u" ForwardAgent yes\n"
+ out += u"\n"
+ return out
+ hostname = u"%s.crans.org" % (key)
+ out += u" HostName %s\n" % (hostname)
+ out += u" User %s\n" % login_crans
+ if not key in ["apprentis", "batk-0"]:
+ out += u" ForwardAgent yes\n"
+ if use_adm_proxy:
+ out += u" ProxyCommand ssh %s -W %%h:%%p\n" % (adm_proxy)
+ if key.endswith("-ilo.adm"):
+ out += u" HostKeyAlgorithms ssh-rsa\n"
+ out += u"\n"
+ return out
+
+def compute_ssh_config(servers):
+ """Affiche le ssh_config à partir de la liste de serveurs."""
+ # Un serveur "plouf.adm.crans.org" est adm-only si aucune clé "plouf", "plouf.ferme" n'existe
+ keys = servers.keys()
+ adm_only = {k : aliases for k, aliases in servers.items() if all([not k.replace(".adm", zone) in keys
+ for zone in [".ferme", ""]])}
+ # On veut pouvoir utiliser babar et pas seulement babar.adm
+ for k in adm_only.keys():
+ newk = k.replace(".adm", "")
+ if not newk in adm_only[k]:
+ adm_only[k] = [k.replace(".adm", "")] + adm_only[k]
+ for a in adm_only.keys():
+ del servers[a]
+ s = crans_header
+ keys = servers.keys()
+ keys.sort()
+ for h in keys:
+ s += output(h, servers[h])
+ s += crans_adm_header
+ keys = adm_only.keys()
+ keys.sort()
+ for h in keys:
+ s += output(h, adm_only[h], use_adm_proxy=True)
+ return s
+
+if __name__ == '__main__':
+ try:
+ servers = load_servers()
+ except:
+ servers = get_servers()
+ cache_servers(servers)
+ servers = {h:aliases for h, aliases in servers.iteritems() if not blacklisted(h, aliases)}
+ out = compute_ssh_config(servers)
+ before = open(static_before_file).read().decode("utf-8")
+ after = open(static_after_file).read().decode("utf-8")
+ print (before + out + after).encode("utf-8")