]> gitweb.pimeys.fr Git - scripts-20-100.git/blob - ssh/generate_config.py
ae730c39f01b721007551a2f44d5defa89d91faa
[scripts-20-100.git] / ssh / generate_config.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 """Script de génération automatique de fichier ~/.ssh/config
5
6 TODO : mettre une option pour append le ssh des bornes
7 """
8
9 import sys
10 import re
11 sys.path.append('/usr/scripts/')
12
13 import lc_ldap.shortcuts
14 import lc_ldap.objets
15
16 #: Fichier à inclure au début
17 static_before_file = "./static_before"
18
19 #: Fichier à inclure à la fin
20 static_after_file = "./static_after"
21
22 #: regexp pour exclure certains "serveurs"
23 black_regex = re.compile(r'^((bigbrother|hugebrother|littlebrother|tinybrother|imprimante|vigile(--?\d[a-z])?|bat[abcghijmopkv]-\d|minigiga|multiprise-v6|chu|pika|kvm|pulsar|nols2?)\.adm\.crans\.org|ftp\.federez\.net|ns1\.crans\.ens-cachan\.fr)$')
24
25 #: Proxy pour contacter le VLAN adm
26 adm_proxy = u"sable.crans.org"
27
28 #: Login pour se connecter sur les serveurs Cr@ns
29 login_crans = u"loginCr@ns"
30
31 #: À afficher avant les serveurs Cr@ns
32 crans_header = u"""
33 # +-------------------+
34 # | Serveurs du Cr@ns |
35 # +-------------------+
36 # Accessible aux apprentis
37 # sauf zamok et ssh2, accessibles à tous les adhérents
38
39 """
40
41 #: À afficher avant les serveurs adm
42 crans_adm_header = u"""
43 # +-------------------------+
44 # | Serveurs Cr@ns adm-only |
45 # +-------------------------+
46 # Accessibles aux apprentis, mais ne sont que sur le VLAN adm
47 # d'où la ProxyCommand
48
49 """
50
51 def blacklisted(key, aliases):
52 """Répond True si le serveur ne doit pas apparaître dans le fichier de conf."""
53 for a in aliases:
54 if black_regex.match(a):
55 return True
56 return False
57
58 def cache_servers(servs):
59 import json
60 json.dump(servs, open("plouf.json", "w"))
61
62 def load_servers():
63 import json
64 return json.load(open("plouf.json"))
65
66 def get_servers(help=None):
67 """Récupère la liste des serveurs dans la base LDAP."""
68 if help is None:
69 c = lc_ldap.shortcuts.lc_ldap_readonly(user=u"legallic")
70
71 l = c.allMachines()
72 l = [m for m in l if isinstance(m, lc_ldap.objets.machineCrans)]
73 else:
74 l = help
75
76 hosts = {}
77 for m in l:
78 host = m["host"][0].value
79 h = host.replace(".crans.org", "")
80 if hosts.has_key(h):
81 print (u"Doublon : clé %s had %r and wants %r" % (h, hosts[h], [host] + [a.value for a in m["hostAlias"]])).encode("utf-8")
82 else:
83 hosts[h] = [host] + [a.value for a in m["hostAlias"]]
84 return hosts
85
86 def output(key, aliases, use_adm_proxy=False):
87 """ Renvoie le block de conf pour un host.
88 Traite particulièrment : ssh2, les ilo, la ferme"""
89 # On teste si le serveur est dans la ferme
90 ferme = any([a.endswith(u".ferme.crans.org") for a in aliases])
91 shorts = list(set([a.replace(".crans.org", "") for a in aliases]))
92 if ferme:
93 shorts.append(a.split(".", 1)[0])
94 shorts.sort()
95 if key in shorts:
96 shorts.remove(key)
97 out = u"Host %s\n" % (u" ".join([key] + shorts + aliases))
98 if key=="ssh2":
99 out += u" # Un serveur ssh qui n'est qu'un nat vers 138.231.136.1:22\n"
100 out += u" # pour passer à travers les blocages de ports (443 = https)\n"
101 out += u" HostName 138.231.136.2\n"
102 out += u" Port 443\n"
103 out += u" User %s\n" % login_crans
104 out += u" ForwardAgent yes\n"
105 out += u"\n"
106 return out
107 hostname = u"%s.crans.org" % (key)
108 out += u" HostName %s\n" % (hostname)
109 out += u" User %s\n" % login_crans
110 if not key in ["apprentis", "batk-0"]:
111 out += u" ForwardAgent yes\n"
112 if use_adm_proxy:
113 out += u" ProxyCommand ssh %s -W %%h:%%p\n" % (adm_proxy)
114 if key.endswith("-ilo.adm"):
115 out += u" HostKeyAlgorithms ssh-rsa\n"
116 out += u"\n"
117 return out
118
119 def compute_ssh_config(servers):
120 """Affiche le ssh_config à partir de la liste de serveurs."""
121 # Un serveur "plouf.adm.crans.org" est adm-only si aucune clé "plouf", "plouf.ferme" n'existe
122 keys = servers.keys()
123 adm_only = {k : aliases for k, aliases in servers.items() if all([not k.replace(".adm", zone) in keys
124 for zone in [".ferme", ""]])}
125 # On veut pouvoir utiliser babar et pas seulement babar.adm
126 for k in adm_only.keys():
127 newk = k.replace(".adm", "")
128 if not newk in adm_only[k]:
129 adm_only[k] = [k.replace(".adm", "")] + adm_only[k]
130 for a in adm_only.keys():
131 del servers[a]
132 s = crans_header
133 keys = servers.keys()
134 keys.sort()
135 for h in keys:
136 s += output(h, servers[h])
137 s += crans_adm_header
138 keys = adm_only.keys()
139 keys.sort()
140 for h in keys:
141 s += output(h, adm_only[h], use_adm_proxy=True)
142 return s
143
144 if __name__ == '__main__':
145 try:
146 servers = load_servers()
147 except:
148 servers = get_servers()
149 cache_servers(servers)
150 servers = {h:aliases for h, aliases in servers.iteritems() if not blacklisted(h, aliases)}
151 out = compute_ssh_config(servers)
152 before = open(static_before_file).read().decode("utf-8")
153 after = open(static_after_file).read().decode("utf-8")
154 print (before + out + after).encode("utf-8")