Portail Infra : CMDB, générateur certificats & mapper VLAN switch
Ajouts : - Snapshots serveur de la base CMDB (auto + manuel, restauration) - Import/Export CSV de l'inventaire Préparation partage public : - Données réelles (cmdb.db, snapshots, certs/clés privées) exclues via .gitignore - Suppression des infos en dur (proxy, VLAN, configs switch exemples) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
commit
bfc88f4afc
24 changed files with 13551 additions and 0 deletions
20
.gitignore
vendored
Normal file
20
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# === Données réelles — gardées en local, jamais publiées ===
|
||||
# Base CMDB (inventaire + mot de passe bind LDAP)
|
||||
CMDB/cmdb.db
|
||||
CMDB/cmdb.db.ver
|
||||
CMDB/cmdb.db.tmp
|
||||
# Snapshots horodatés de la base (copies des données réelles)
|
||||
CMDB/snapshots/
|
||||
|
||||
# Certificats générés (contiennent des clés privées)
|
||||
GENERATEUR_CERTIFICATES/LISTS_ALL_CERT/
|
||||
|
||||
# === Environnement / build ===
|
||||
.venv/
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
|
||||
# === Divers ===
|
||||
.DS_Store
|
||||
*.swp
|
||||
1
.python-version
Normal file
1
.python-version
Normal file
|
|
@ -0,0 +1 @@
|
|||
3.13
|
||||
BIN
CMDB/__pycache__/cmdb_server.cpython-313.pyc
Normal file
BIN
CMDB/__pycache__/cmdb_server.cpython-313.pyc
Normal file
Binary file not shown.
BIN
CMDB/__pycache__/cmdb_server.cpython-314.pyc
Normal file
BIN
CMDB/__pycache__/cmdb_server.cpython-314.pyc
Normal file
Binary file not shown.
4055
CMDB/cmdb.html
Normal file
4055
CMDB/cmdb.html
Normal file
File diff suppressed because it is too large
Load diff
482
CMDB/cmdb_server.py
Normal file
482
CMDB/cmdb_server.py
Normal file
|
|
@ -0,0 +1,482 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Serveur CMDB : sert cmdb.html, la base partagée et la recherche AD.
|
||||
|
||||
Remplace `python -m http.server` ET le connecteur séparé :
|
||||
pip install ldap3
|
||||
python3 cmdb_server.py # http://0.0.0.0:8000
|
||||
python3 cmdb_server.py 8080 # port custom
|
||||
|
||||
Endpoints :
|
||||
GET /db → base SQLite (bytes) + entête X-DB-Version
|
||||
GET /db/version → {"version": n} (poll léger)
|
||||
POST /db → écrit la base ; entête X-Base-Version pour la
|
||||
concurrence optimiste (409 si obsolète)
|
||||
POST /ldap/search → recherche annuaire (config envoyée par la page)
|
||||
|
||||
La base est un vrai fichier `cmdb.db` partagé : plusieurs personnes
|
||||
peuvent l'utiliser en même temps, avec détection de conflit.
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import ssl
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
|
||||
from urllib.parse import urlparse, parse_qs
|
||||
|
||||
PORT = int(sys.argv[1]) if len(sys.argv) > 1 else 8000
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
DB_PATH = os.path.join(HERE, 'cmdb.db')
|
||||
VER_PATH = DB_PATH + '.ver'
|
||||
DB_LOCK = threading.Lock()
|
||||
|
||||
|
||||
def db_version():
|
||||
try:
|
||||
with open(VER_PATH) as f:
|
||||
return int(f.read().strip() or 0)
|
||||
except (OSError, ValueError):
|
||||
return 1 if os.path.exists(DB_PATH) else 0
|
||||
|
||||
|
||||
def db_bytes():
|
||||
try:
|
||||
with open(DB_PATH, 'rb') as f:
|
||||
return f.read()
|
||||
except OSError:
|
||||
return b''
|
||||
|
||||
|
||||
def db_write(data):
|
||||
"""Écrit la base atomiquement et incrémente la version. Renvoie la version."""
|
||||
with DB_LOCK:
|
||||
ver = db_version() + 1
|
||||
tmp = DB_PATH + '.tmp'
|
||||
with open(tmp, 'wb') as f:
|
||||
f.write(data)
|
||||
os.replace(tmp, DB_PATH)
|
||||
with open(VER_PATH, 'w') as f:
|
||||
f.write(str(ver))
|
||||
return ver
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Snapshots : copies horodatées de la base dans snapshots/.
|
||||
# - « auto » : créées après une écriture, au plus 1/heure, rétention 72.
|
||||
# - « manuel » : créées à la demande (bouton), rétention 100, label libre.
|
||||
# Restaurer un snapshot crée d'abord un snapshot de sécurité de l'état courant.
|
||||
# ---------------------------------------------------------------------------
|
||||
SNAP_DIR = os.path.join(HERE, 'snapshots')
|
||||
# nom : cmdb-<AAAAMMJJ>-<HHMMSS>-v<version>[-<label>].db (pas de '/' possible → pas de traversal)
|
||||
SNAP_RE = re.compile(r'^cmdb-(\d{8})-(\d{6})-v(\d+)(?:-([A-Za-z0-9_.-]+))?\.db$')
|
||||
AUTO_MIN_INTERVAL = 3600 # s : au plus un snapshot auto par heure
|
||||
AUTO_KEEP = 72 # rétention snapshots auto (~3 jours horaires)
|
||||
MANUAL_KEEP = 100 # rétention snapshots manuels
|
||||
|
||||
|
||||
def _sanitize_label(label):
|
||||
label = re.sub(r'[^A-Za-z0-9_.-]+', '-', (label or '').strip()).strip('-')
|
||||
return label[:40]
|
||||
|
||||
|
||||
def _parse_snap(name):
|
||||
"""Valide un nom de snapshot et renvoie sa méta, ou None si invalide."""
|
||||
name = os.path.basename(name or '')
|
||||
m = SNAP_RE.match(name)
|
||||
if not m:
|
||||
return None
|
||||
return {'name': name, 'date': m.group(1), 'time': m.group(2),
|
||||
'version': int(m.group(3)), 'label': m.group(4) or '',
|
||||
'auto': m.group(4) == 'auto'}
|
||||
|
||||
|
||||
def list_snapshots():
|
||||
"""Liste les snapshots existants, plus récents d'abord."""
|
||||
out = []
|
||||
try:
|
||||
entries = os.listdir(SNAP_DIR)
|
||||
except OSError:
|
||||
return out
|
||||
for n in entries:
|
||||
meta = _parse_snap(n)
|
||||
if not meta:
|
||||
continue
|
||||
try:
|
||||
st = os.stat(os.path.join(SNAP_DIR, n))
|
||||
except OSError:
|
||||
continue
|
||||
meta['size'] = st.st_size
|
||||
meta['mtime'] = int(st.st_mtime * 1000)
|
||||
out.append(meta)
|
||||
out.sort(key=lambda s: s['mtime'], reverse=True)
|
||||
return out
|
||||
|
||||
|
||||
def _prune(auto, keep):
|
||||
for s in [s for s in list_snapshots() if s['auto'] == auto][keep:]:
|
||||
try:
|
||||
os.remove(os.path.join(SNAP_DIR, s['name']))
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
def create_snapshot(label='manual', auto=False):
|
||||
"""Copie la base courante dans snapshots/. Renvoie la méta, ou None si base vide."""
|
||||
with DB_LOCK:
|
||||
data = db_bytes()
|
||||
if not data:
|
||||
return None
|
||||
ver = db_version()
|
||||
os.makedirs(SNAP_DIR, exist_ok=True)
|
||||
lbl = 'auto' if auto else (_sanitize_label(label) or 'manual')
|
||||
name = 'cmdb-%s-v%d-%s.db' % (time.strftime('%Y%m%d-%H%M%S'), ver, lbl)
|
||||
path = os.path.join(SNAP_DIR, name)
|
||||
tmp = path + '.tmp'
|
||||
with open(tmp, 'wb') as f:
|
||||
f.write(data)
|
||||
os.replace(tmp, path)
|
||||
_prune(auto, AUTO_KEEP if auto else MANUAL_KEEP)
|
||||
return _parse_snap(name)
|
||||
|
||||
|
||||
def _maybe_auto_snapshot():
|
||||
"""Snapshot auto si le dernier date de plus d'AUTO_MIN_INTERVAL. Jamais dans DB_LOCK."""
|
||||
autos = [s for s in list_snapshots() if s['auto']]
|
||||
if autos and (time.time() - autos[0]['mtime'] / 1000) < AUTO_MIN_INTERVAL:
|
||||
return
|
||||
try:
|
||||
create_snapshot(auto=True)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
def db_write_and_snapshot(data):
|
||||
"""Écrit la base puis déclenche un snapshot auto (throttlé). Renvoie la version."""
|
||||
ver = db_write(data)
|
||||
_maybe_auto_snapshot()
|
||||
return ver
|
||||
|
||||
|
||||
def snapshot_bytes(name):
|
||||
"""Contenu d'un snapshot. Lève si nom invalide ou fichier absent."""
|
||||
meta = _parse_snap(name)
|
||||
if not meta:
|
||||
raise ValueError('nom de snapshot invalide')
|
||||
with open(os.path.join(SNAP_DIR, meta['name']), 'rb') as f:
|
||||
return f.read()
|
||||
|
||||
|
||||
def delete_snapshot(name):
|
||||
meta = _parse_snap(name)
|
||||
if not meta:
|
||||
raise ValueError('nom de snapshot invalide')
|
||||
path = os.path.join(SNAP_DIR, meta['name'])
|
||||
if os.path.isfile(path):
|
||||
os.remove(path)
|
||||
|
||||
|
||||
def restore_snapshot(name):
|
||||
"""Remplace la base courante par le snapshot `name`.
|
||||
|
||||
Crée d'abord un snapshot de sécurité de l'état courant. Renvoie la nouvelle version.
|
||||
"""
|
||||
meta = _parse_snap(name)
|
||||
if not meta:
|
||||
raise ValueError('nom de snapshot invalide')
|
||||
path = os.path.join(SNAP_DIR, meta['name'])
|
||||
if not os.path.isfile(path):
|
||||
raise FileNotFoundError('snapshot introuvable')
|
||||
with open(path, 'rb') as f:
|
||||
data = f.read()
|
||||
create_snapshot(label='pre-restore') # filet de sécurité avant écrasement
|
||||
return db_write(data)
|
||||
|
||||
try:
|
||||
from ldap3 import Server, Connection, Tls, SUBTREE, ALL_ATTRIBUTES
|
||||
from ldap3.utils.conv import escape_filter_chars
|
||||
HAS_LDAP = True
|
||||
except ImportError:
|
||||
HAS_LDAP = False
|
||||
|
||||
|
||||
def _cn_of(dn):
|
||||
if not dn:
|
||||
return ''
|
||||
head = dn.split(',')[0]
|
||||
return head.split('=', 1)[1] if '=' in head else head
|
||||
|
||||
|
||||
def ldap_connect(cfg):
|
||||
"""Ouvre et bind une connexion LDAP selon la config de la page."""
|
||||
use_ssl = cfg.get('method') == 'ssl'
|
||||
tls = Tls(validate=ssl.CERT_REQUIRED if cfg.get('verify_certificates') else ssl.CERT_NONE)
|
||||
srv = Server(cfg['host'], port=int(cfg.get('port') or (636 if use_ssl else 389)),
|
||||
use_ssl=use_ssl, tls=tls, get_info=None, connect_timeout=8)
|
||||
conn = Connection(srv, user=cfg.get('bind_dn') or None,
|
||||
password=cfg.get('bind_password') or None,
|
||||
auto_referrals=False, receive_timeout=15)
|
||||
if cfg.get('method') == 'start_tls':
|
||||
conn.open()
|
||||
conn.start_tls()
|
||||
if not conn.bind():
|
||||
raise RuntimeError('Bind LDAP refusé : %s' % conn.result)
|
||||
return conn
|
||||
|
||||
|
||||
def ldap_computer(cfg, query):
|
||||
"""Cherche un poste (objectClass=computer) par nom/dNSHostName."""
|
||||
conn = ldap_connect(cfg)
|
||||
q = escape_filter_chars((query or '').strip().rstrip('$'))
|
||||
flt = ('(&(objectClass=computer)(|(cn=*%s*)(name=*%s*)(dNSHostName=*%s*)'
|
||||
'(sAMAccountName=*%s*)))' % (q, q, q, q))
|
||||
base = cfg.get('base') or ''
|
||||
ok = conn.search(base, flt, SUBTREE, attributes=ALL_ATTRIBUTES, size_limit=5)
|
||||
res = conn.result or {}
|
||||
if not ok and res.get('result') not in (0, 4):
|
||||
raise RuntimeError('Recherche LDAP échouée : %s' % (res.get('description') or res))
|
||||
out = []
|
||||
for e in conn.entries:
|
||||
d = e.entry_attributes_as_dict
|
||||
|
||||
def val(k):
|
||||
for kk in d:
|
||||
if kk.lower() == k.lower():
|
||||
v = d[kk]
|
||||
if isinstance(v, list):
|
||||
v = v[0] if v else ''
|
||||
return str(v) if v else ''
|
||||
return ''
|
||||
|
||||
def vals(k):
|
||||
for kk in d:
|
||||
if kk.lower() == k.lower():
|
||||
v = d[kk]
|
||||
return [str(x) for x in (v if isinstance(v, list) else [v]) if x]
|
||||
return []
|
||||
|
||||
uac = val('userAccountControl')
|
||||
enabled = (not (int(uac) & 2)) if uac.isdigit() else None
|
||||
out.append({
|
||||
'name': val('cn') or val('name'),
|
||||
'dns': val('dNSHostName'),
|
||||
'os': val('operatingSystem'),
|
||||
'os_version': val('operatingSystemVersion'),
|
||||
'description': val('description'),
|
||||
'location': val('location'),
|
||||
'managed_by': _cn_of(val('managedBy')),
|
||||
'when_created': val('whenCreated')[:8],
|
||||
'enabled': enabled,
|
||||
'groups': [_cn_of(x) for x in vals('memberOf')][:20],
|
||||
})
|
||||
return out
|
||||
|
||||
|
||||
def ldap_search(cfg, query, limit=25):
|
||||
"""Recherche d'utilisateurs dans l'AD selon la config de la page.
|
||||
|
||||
Cherche par username, nom, prénom, nom affiché ou mail.
|
||||
Lève une exception explicite si le bind ou la recherche échoue
|
||||
(sinon un problème de config renverrait « aucun résultat » en silence).
|
||||
"""
|
||||
conn = ldap_connect(cfg)
|
||||
|
||||
uid = cfg.get('uid') or 'userPrincipalName'
|
||||
raw = cfg.get('filter') or ''
|
||||
if raw:
|
||||
flt = raw.replace('{query}', escape_filter_chars(query))
|
||||
else:
|
||||
# recherche prioritairement sur displayName, multi-mots (ET) → "jean dupont"
|
||||
# et "dupont jean" fonctionnent tous les deux, quel que soit l'ordre.
|
||||
search_attrs = ['displayName', 'cn', 'sAMAccountName', 'givenName', 'sn',
|
||||
'userPrincipalName', 'mail']
|
||||
tokens = [escape_filter_chars(t) for t in query.split() if t] or ['']
|
||||
parts = []
|
||||
for t in tokens:
|
||||
ors = ''.join('(%s=*%s*)' % (a, t) for a in search_attrs)
|
||||
parts.append('(|%s)' % ors)
|
||||
flt = '(&%s)' % ''.join(parts) if len(parts) > 1 else parts[0]
|
||||
# personnes uniquement, compatible AD + OpenLDAP
|
||||
person = ('(|(objectClass=user)(objectClass=inetOrgPerson)'
|
||||
'(objectClass=organizationalPerson)(objectClass=person))')
|
||||
base = cfg.get('base') or ''
|
||||
|
||||
ok = conn.search(base, '(&%s%s)' % (person, flt), SUBTREE,
|
||||
attributes=ALL_ATTRIBUTES, size_limit=limit)
|
||||
res = conn.result or {}
|
||||
# 0 = success, 4 = sizeLimitExceeded (résultats partiels OK)
|
||||
if not ok and res.get('result') not in (0, 4):
|
||||
raise RuntimeError('Recherche LDAP échouée : %s (base=%s)'
|
||||
% (res.get('description') or res, base or '∅'))
|
||||
|
||||
def val(d, k):
|
||||
# accès insensible à la casse, première valeur
|
||||
for kk in d:
|
||||
if kk.lower() == k.lower():
|
||||
v = d[kk]
|
||||
if isinstance(v, list):
|
||||
v = v[0] if v else ''
|
||||
return str(v) if v else ''
|
||||
return ''
|
||||
|
||||
def vals(d, k):
|
||||
for kk in d:
|
||||
if kk.lower() == k.lower():
|
||||
v = d[kk]
|
||||
return [str(x) for x in (v if isinstance(v, list) else [v]) if x]
|
||||
return []
|
||||
|
||||
def cn_of(dn):
|
||||
# "CN=Jean Dupont,OU=..." -> "Jean Dupont"
|
||||
if not dn:
|
||||
return ''
|
||||
head = dn.split(',')[0]
|
||||
return head.split('=', 1)[1] if '=' in head else head
|
||||
|
||||
out, seen = [], set()
|
||||
for e in conn.entries:
|
||||
d = e.entry_attributes_as_dict
|
||||
name = val(d, 'displayName') or val(d, 'cn') \
|
||||
or (val(d, 'givenName') + ' ' + val(d, 'sn')).strip()
|
||||
username = val(d, 'sAMAccountName') or val(d, uid) or val(d, 'userPrincipalName')
|
||||
key = (name, username)
|
||||
if not (name or username) or key in seen:
|
||||
continue
|
||||
seen.add(key)
|
||||
uac = val(d, 'userAccountControl')
|
||||
enabled = (not (int(uac) & 2)) if uac.isdigit() else None
|
||||
out.append({
|
||||
'displayName': name or username,
|
||||
'username': username,
|
||||
'mail': val(d, 'mail'),
|
||||
'title': val(d, 'title'),
|
||||
'department': val(d, 'department'),
|
||||
'company': val(d, 'company'),
|
||||
'office': val(d, 'physicalDeliveryOfficeName'),
|
||||
'phone': val(d, 'telephoneNumber'),
|
||||
'mobile': val(d, 'mobile') or val(d, 'ipPhone'),
|
||||
'manager': cn_of(val(d, 'manager')),
|
||||
'description': val(d, 'description'),
|
||||
'employee_id': val(d, 'employeeID') or val(d, 'employeeNumber'),
|
||||
'division': val(d, 'division'),
|
||||
'city': val(d, 'l'),
|
||||
'country': val(d, 'co') or val(d, 'c'),
|
||||
'enabled': enabled,
|
||||
'groups': [cn_of(x) for x in vals(d, 'memberOf')][:15],
|
||||
})
|
||||
out.sort(key=lambda u: u['displayName'].lower())
|
||||
return out
|
||||
|
||||
|
||||
class Handler(SimpleHTTPRequestHandler):
|
||||
def log_message(self, *args):
|
||||
pass
|
||||
|
||||
def _json(self, code, payload):
|
||||
body = json.dumps(payload).encode()
|
||||
self.send_response(code)
|
||||
self.send_header('Content-Type', 'application/json')
|
||||
self.send_header('Content-Length', str(len(body)))
|
||||
self.end_headers()
|
||||
self.wfile.write(body)
|
||||
|
||||
def _send_db(self, code, data, version):
|
||||
self.send_response(code)
|
||||
self.send_header('Content-Type', 'application/octet-stream')
|
||||
self.send_header('X-DB-Version', str(version))
|
||||
self.send_header('Cache-Control', 'no-store')
|
||||
self.send_header('Content-Length', str(len(data)))
|
||||
self.end_headers()
|
||||
if data:
|
||||
self.wfile.write(data)
|
||||
|
||||
def _send_download(self, data, filename):
|
||||
self.send_response(200)
|
||||
self.send_header('Content-Type', 'application/octet-stream')
|
||||
self.send_header('Content-Disposition', 'attachment; filename="%s"' % filename)
|
||||
self.send_header('Cache-Control', 'no-store')
|
||||
self.send_header('Content-Length', str(len(data)))
|
||||
self.end_headers()
|
||||
self.wfile.write(data)
|
||||
|
||||
def do_GET(self):
|
||||
if self.path == '/db':
|
||||
with DB_LOCK:
|
||||
return self._send_db(200, db_bytes(), db_version())
|
||||
if self.path == '/db/version':
|
||||
return self._json(200, {'version': db_version()})
|
||||
if self.path == '/db/snapshots':
|
||||
return self._json(200, {'snapshots': list_snapshots()})
|
||||
if self.path.startswith('/db/snapshot?'):
|
||||
name = (parse_qs(urlparse(self.path).query).get('name') or [''])[0]
|
||||
try:
|
||||
data = snapshot_bytes(name)
|
||||
except (ValueError, OSError):
|
||||
return self._json(404, {'error': 'snapshot introuvable'})
|
||||
return self._send_download(data, os.path.basename(name))
|
||||
if self.path in ('/', '/index.html'):
|
||||
self.path = '/cmdb.html'
|
||||
return super().do_GET()
|
||||
|
||||
def do_POST(self):
|
||||
if self.path == '/db':
|
||||
data = self.rfile.read(int(self.headers.get('Content-Length', 0)))
|
||||
base = int(self.headers.get('X-Base-Version', '0') or 0)
|
||||
cur = db_version()
|
||||
if base != cur: # quelqu'un a écrit entre-temps
|
||||
return self._send_db(409, db_bytes(), cur)
|
||||
ver = db_write_and_snapshot(data)
|
||||
return self._send_db(200, b'', ver)
|
||||
if self.path in ('/db/snapshot', '/db/snapshot/delete', '/db/restore'):
|
||||
try:
|
||||
body = json.loads(self.rfile.read(int(self.headers.get('Content-Length', 0)) or 0) or b'{}')
|
||||
except ValueError:
|
||||
body = {}
|
||||
if self.path == '/db/snapshot':
|
||||
meta = create_snapshot(label=body.get('label') or 'manual')
|
||||
if not meta:
|
||||
return self._json(400, {'error': 'base vide — rien à sauvegarder'})
|
||||
return self._json(200, meta)
|
||||
if self.path == '/db/snapshot/delete':
|
||||
try:
|
||||
delete_snapshot(body.get('name') or '')
|
||||
except (ValueError, OSError):
|
||||
return self._json(400, {'error': 'nom de snapshot invalide'})
|
||||
return self._json(200, {'ok': True})
|
||||
# /db/restore
|
||||
try:
|
||||
restore_snapshot(body.get('name') or '')
|
||||
except (ValueError, FileNotFoundError):
|
||||
return self._json(404, {'error': 'snapshot introuvable'})
|
||||
with DB_LOCK:
|
||||
return self._send_db(200, db_bytes(), db_version())
|
||||
if self.path == '/ldap/computer':
|
||||
if not HAS_LDAP:
|
||||
return self._json(500, {'error': "module ldap3 manquant — pip install ldap3"})
|
||||
try:
|
||||
body = json.loads(self.rfile.read(int(self.headers.get('Content-Length', 0))))
|
||||
result = ldap_computer(body.get('config') or {}, (body.get('query') or '').strip())
|
||||
return self._json(200, result)
|
||||
except Exception as ex:
|
||||
return self._json(500, {'error': str(ex)})
|
||||
if self.path != '/ldap/search':
|
||||
return self._json(404, {'error': 'not found'})
|
||||
if not HAS_LDAP:
|
||||
return self._json(500, {'error': "module ldap3 manquant — pip install ldap3"})
|
||||
try:
|
||||
body = json.loads(self.rfile.read(int(self.headers.get('Content-Length', 0))))
|
||||
limit = int(body.get('limit') or 25)
|
||||
result = ldap_search(body.get('config') or {}, (body.get('query') or '').strip(), limit)
|
||||
self._json(200, result)
|
||||
except Exception as ex: # renvoyé tel quel à la page
|
||||
self._json(500, {'error': str(ex)})
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
if not HAS_LDAP:
|
||||
print("⚠ ldap3 absent : la recherche AD renverra une erreur (pip install ldap3)")
|
||||
print('CMDB : http://127.0.0.1:%d (Ctrl+C pour arrêter)' % PORT)
|
||||
ThreadingHTTPServer(('0.0.0.0', PORT), Handler).serve_forever()
|
||||
3535
CMDB/preferences.html
Normal file
3535
CMDB/preferences.html
Normal file
File diff suppressed because it is too large
Load diff
9
CMDB/pyproject.toml
Normal file
9
CMDB/pyproject.toml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
[project]
|
||||
name = "cmdb"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
dependencies = [
|
||||
"ldap3>=2.9.1",
|
||||
]
|
||||
174
GENERATEUR_CERTIFICATES/cert_server.py
Normal file
174
GENERATEUR_CERTIFICATES/cert_server.py
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Serveur du Générateur de Certificats SSL.
|
||||
|
||||
Remplace `python -m http.server` : sert les pages ET écrit les certificats
|
||||
sur le disque dans GENERATEUR_CERTIFICATES/LISTS_ALL_CERT/ (créé au besoin),
|
||||
sans aucune sélection de dossier côté navigateur.
|
||||
|
||||
Usage :
|
||||
python3 cert_server.py # http://127.0.0.1:8000/GENERATEUR_CERTIFICATES/dashboard.html
|
||||
python3 cert_server.py 8080 # port custom
|
||||
|
||||
Sert la RACINE du projet (parent), donc les 3 apps + le switcher fonctionnent.
|
||||
"""
|
||||
import sys, os, json, base64, shutil, re
|
||||
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
|
||||
|
||||
PORT = int(sys.argv[1]) if len(sys.argv) > 1 else 8000
|
||||
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) # .../GENERATEUR_CERTIFICATES
|
||||
ROOT = os.path.dirname(SCRIPT_DIR) # racine projet
|
||||
WORK = os.path.join(SCRIPT_DIR, 'LISTS_ALL_CERT') # dossier de travail (disque)
|
||||
ARCH = os.path.join(WORK, 'archives')
|
||||
|
||||
SAFE = re.compile(r'^[A-Za-z0-9._@\- ]+$') # noms de dossier/fichier autorisés
|
||||
|
||||
def safe_name(n):
|
||||
n = (n or '').strip()
|
||||
if not n or n in ('.', '..') or '/' in n or '\\' in n or not SAFE.match(n):
|
||||
raise ValueError('nom invalide: %r' % n)
|
||||
return n
|
||||
|
||||
def ensure_work():
|
||||
os.makedirs(WORK, exist_ok=True)
|
||||
|
||||
class Handler(SimpleHTTPRequestHandler):
|
||||
def _json(self, obj, code=200):
|
||||
body = json.dumps(obj).encode('utf-8')
|
||||
self.send_response(code)
|
||||
self.send_header('Content-Type', 'application/json')
|
||||
self.send_header('Content-Length', str(len(body)))
|
||||
self.send_header('Cache-Control', 'no-store')
|
||||
self.end_headers()
|
||||
self.wfile.write(body)
|
||||
|
||||
def _err(self, msg, code=400):
|
||||
self._json({'ok': False, 'error': str(msg)}, code)
|
||||
|
||||
def _body(self):
|
||||
n = int(self.headers.get('Content-Length', 0))
|
||||
return json.loads(self.rfile.read(n) or b'{}')
|
||||
|
||||
def _api(self):
|
||||
p = self.path.split('?', 1)[0]
|
||||
return p.split('/api/', 1)[1] if '/api/' in p else None
|
||||
|
||||
# ---------- GET : API list/ping, sinon fichiers statiques ----------
|
||||
def do_GET(self):
|
||||
api = self._api()
|
||||
if api == 'ping':
|
||||
return self._json({'ok': True, 'workdir': 'LISTS_ALL_CERT'})
|
||||
if api == 'list':
|
||||
return self._json(self.list_all())
|
||||
return super().do_GET()
|
||||
|
||||
def do_POST(self):
|
||||
api = self._api()
|
||||
try:
|
||||
if api == 'write': return self.write_text()
|
||||
if api == 'write_bin': return self.write_bin()
|
||||
if api == 'delete': return self.delete_dir()
|
||||
if api == 'delete_file': return self.delete_file()
|
||||
if api == 'delete_archives': return self.delete_archives()
|
||||
except Exception as e:
|
||||
return self._err(e, 500)
|
||||
self._err('route inconnue: %s' % self.path, 404)
|
||||
|
||||
# ---------- implémentations ----------
|
||||
def list_all(self):
|
||||
ensure_work()
|
||||
certs, archives = [], []
|
||||
for entry in sorted(os.listdir(WORK)):
|
||||
full = os.path.join(WORK, entry)
|
||||
if entry == 'archives':
|
||||
if os.path.isdir(full):
|
||||
for a in sorted(os.listdir(full)):
|
||||
af = os.path.join(full, a)
|
||||
if os.path.isfile(af):
|
||||
st = os.stat(af)
|
||||
archives.append({'name': a, 'size': st.st_size,
|
||||
'mtime': int(st.st_mtime * 1000)})
|
||||
continue
|
||||
if not os.path.isdir(full):
|
||||
continue
|
||||
files, date = [], 0
|
||||
for fn in sorted(os.listdir(full)):
|
||||
ff = os.path.join(full, fn)
|
||||
if not os.path.isfile(ff):
|
||||
continue
|
||||
st = os.stat(ff)
|
||||
m = int(st.st_mtime * 1000)
|
||||
date = max(date, m)
|
||||
files.append({'name': fn, 'ext': (fn.rsplit('.', 1)[-1] if '.' in fn else '').lower(),
|
||||
'size': st.st_size, 'mtime': m})
|
||||
if files:
|
||||
certs.append({'dir': entry, 'files': files, 'date': date})
|
||||
archives.sort(key=lambda a: -a['mtime'])
|
||||
certs.sort(key=lambda c: -c['date'])
|
||||
return {'ok': True, 'certs': certs, 'archives': archives}
|
||||
|
||||
def write_text(self):
|
||||
d = self._body()
|
||||
dname = safe_name(d['dir'])
|
||||
target = os.path.join(WORK, dname)
|
||||
os.makedirs(target, exist_ok=True)
|
||||
for fname, content in (d.get('files') or {}).items():
|
||||
fn = safe_name(fname)
|
||||
with open(os.path.join(target, fn), 'w', encoding='utf-8', newline='') as f:
|
||||
f.write(content)
|
||||
self._json({'ok': True, 'path': 'LISTS_ALL_CERT/%s/' % dname})
|
||||
|
||||
def write_bin(self):
|
||||
d = self._body()
|
||||
# path = "archives/<fichier>.zip" OU "<dir>/<fichier>"
|
||||
parts = [safe_name(x) for x in d['path'].split('/') if x != '']
|
||||
if not parts:
|
||||
raise ValueError('path vide')
|
||||
target = os.path.join(WORK, *parts)
|
||||
os.makedirs(os.path.dirname(target), exist_ok=True)
|
||||
with open(target, 'wb') as f:
|
||||
f.write(base64.b64decode(d['b64']))
|
||||
self._json({'ok': True, 'path': 'LISTS_ALL_CERT/%s' % '/'.join(parts)})
|
||||
|
||||
def delete_dir(self):
|
||||
d = self._body()
|
||||
dname = safe_name(d['dir'])
|
||||
target = os.path.join(WORK, dname)
|
||||
if os.path.isdir(target):
|
||||
shutil.rmtree(target)
|
||||
if d.get('archives'):
|
||||
self._rm_archives(dname)
|
||||
self._json({'ok': True})
|
||||
|
||||
def delete_file(self):
|
||||
d = self._body()
|
||||
target = os.path.join(WORK, safe_name(d['dir']), safe_name(d['name']))
|
||||
if os.path.isfile(target):
|
||||
os.remove(target)
|
||||
self._json({'ok': True})
|
||||
|
||||
def delete_archives(self):
|
||||
d = self._body()
|
||||
self._rm_archives(safe_name(d['dir']))
|
||||
self._json({'ok': True})
|
||||
|
||||
def _rm_archives(self, dname):
|
||||
low = dname.lower()
|
||||
if os.path.isdir(ARCH):
|
||||
for a in os.listdir(ARCH):
|
||||
if low in a.lower():
|
||||
try: os.remove(os.path.join(ARCH, a))
|
||||
except OSError: pass
|
||||
|
||||
def log_message(self, *a):
|
||||
pass # silencieux
|
||||
|
||||
if __name__ == '__main__':
|
||||
ensure_work()
|
||||
os.chdir(ROOT)
|
||||
url = 'http://127.0.0.1:%d/GENERATEUR_CERTIFICATES/dashboard.html' % PORT
|
||||
print('Générateur Certificats : %s' % url)
|
||||
print('Dossier disque : %s (créé automatiquement)' % WORK)
|
||||
print('Ctrl+C pour arrêter.')
|
||||
ThreadingHTTPServer(('0.0.0.0', PORT), Handler).serve_forever()
|
||||
1286
GENERATEUR_CERTIFICATES/dashboard.html
Normal file
1286
GENERATEUR_CERTIFICATES/dashboard.html
Normal file
File diff suppressed because it is too large
Load diff
2
GENERATEUR_CERTIFICATES/vendor/forge.min.js
vendored
Normal file
2
GENERATEUR_CERTIFICATES/vendor/forge.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
13
GENERATEUR_CERTIFICATES/vendor/jszip.min.js
vendored
Normal file
13
GENERATEUR_CERTIFICATES/vendor/jszip.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
48
GENERATEUR_SWITCH/couleurs.txt
Normal file
48
GENERATEUR_SWITCH/couleurs.txt
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#26d953 (vert)
|
||||
#2dd4bf (turquoise)
|
||||
#22c55e (vert vif)
|
||||
#4ade80 (vert clair)
|
||||
#06b6d4 (cyan)
|
||||
#38bdf8 (bleu ciel)
|
||||
#3b82f6 (bleu)
|
||||
#6366f1 (indigo)
|
||||
#8b5cf6 (violet)
|
||||
#a855f7 (violet vif)
|
||||
#d946ef (fuchsia)
|
||||
#d926c7 (rose magenta)
|
||||
#ec4899 (rose)
|
||||
#f43f5e (rose/rouge)
|
||||
#ef4444 (rouge)
|
||||
#f97316 (orange)
|
||||
#fb923c (orange clair)
|
||||
#facc15 (jaune)
|
||||
#eab308 (jaune foncé)
|
||||
#84cc16 (vert citron)
|
||||
|
||||
====== NOT USED ======
|
||||
|
||||
#38bdf8 (bleu ciel)
|
||||
#3b82f6 (bleu)
|
||||
#a855f7 (violet vif)
|
||||
#d946ef (fuchsia)
|
||||
#d926c7 (rose magenta)
|
||||
#ef4444 (rouge)
|
||||
#84cc16 (vert citron)
|
||||
|
||||
|
||||
IA
|
||||
|
||||
Probleme 1 : Quand un switch fait 24 ou 54 port (fibre) , la taille tu tableau n'est pas automatiquement mis a jours.
|
||||
Probleme 2 : Les numeros des interface ne sont pas centrer dans le rectancle (1,2,3,...) c'est le padding top de la div qui doit etre a 0 ou 1px.
|
||||
Probleme 3 : Quand j'ajoute les vlan, nom et couleur il ne s'update pas dans la Database. les couleur ne sont pas aleatoir (touours la meme, et rester dasn les meme ton de couleur)
|
||||
Probleme 4 : Il faut que je puisse utiliser l'application juste avec le html sans ouvrir un serveur html
|
||||
Probleme 5 : Attention important ! Si et seulement si les switch sont stacker : Exemple : GigabitEthernet1/X/X et GigabitEthernet2/X/X il faut afficher 2 tableaux des 2 switchs stacker l'un en dessous de l'autre et le deuxième tableau reprend a partir de GigabitEthernet2/X/X, avec copier de un tableau 1 ou 2 mais pas les 2.
|
||||
|
||||
New Feature 1 : Ajoute des boutons = "Copier l'image" et "Telecharger l'image" pour télécharger ou copier l'image du tableau comme sur le site (une image png).
|
||||
|
||||
|
||||
|
||||
|
||||
Probleme 5 : Le tableau, si il est trop grand pour voir la suite doit etre derouler sur l'horizontal, est ce que c'est possible que ca largeur s'auto adapte a la largeur de la page pour pas que on est a scroll.
|
||||
New Feature 2 : Ajoute les fibre Ten-GigabitEthernet avec comme pour les interface a l'interieur une information rapide de la fibre. (toujours dans le tableau, peut toujours etre copier coller dans excel. Choisi toi meme la facon de les presenter mais a droites des dernieres interface)
|
||||
New Feature 3: Met les modification de vlan dans un collapse depliant fermer par defaut.
|
||||
2561
GENERATEUR_SWITCH/switch_vlan_mapper.html
Normal file
2561
GENERATEUR_SWITCH/switch_vlan_mapper.html
Normal file
File diff suppressed because it is too large
Load diff
11
GENERATEUR_SWITCH/vlan_database.js
Normal file
11
GENERATEUR_SWITCH/vlan_database.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// Fichier de base de données VLAN - À charger dans le HTML
|
||||
// Placer ce fichier dans le même dossier que switch_vlan_mapper.html
|
||||
// Format : <id> = <nom> = <couleur hex> (exemple générique, à adapter)
|
||||
|
||||
const VLAN_DATABASE_FILE = `10 = MGMT = #6366f1
|
||||
20 = SERVERS = #22c55e
|
||||
30 = USERS = #06b6d4
|
||||
40 = VOICE = #2dd4bf
|
||||
50 = DMZ = #8b5cf6
|
||||
99 = GUEST = #f97316
|
||||
`;
|
||||
BIN
__pycache__/server.cpython-314.pyc
Normal file
BIN
__pycache__/server.cpython-314.pyc
Normal file
Binary file not shown.
335
conf_switch.exemple
Normal file
335
conf_switch.exemple
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
|
||||
|
||||
|
||||
**********************************************************
|
||||
|
||||
Use is restricted to authorized users
|
||||
who must comply with the Electronic Communications Policy.
|
||||
Usage is monitored; unauthorized use will be prosecuted.
|
||||
|
||||
**********************************************************
|
||||
|
||||
**********************************************************
|
||||
|
||||
Connected to 5130-INV-1714 GEMALTO on MEYREUIL (FRANCE)
|
||||
|
||||
Use is restricted to authorized users
|
||||
who must comply with the Electronic Communications Policy.
|
||||
Usage is monitored; unauthorized use will be prosecuted.
|
||||
|
||||
**********************************************************
|
||||
|
||||
|
||||
|
||||
******************************************************************************
|
||||
* Copyright (c) 2010-2019 Hewlett Packard Enterprise Development LP *
|
||||
* Without the owner's prior written consent, *
|
||||
* no decompiling or reverse-engineering shall be allowed. *
|
||||
******************************************************************************
|
||||
|
||||
<5130-INV-1714>display current-configuration interface
|
||||
#
|
||||
interface NULL0
|
||||
#
|
||||
interface Vlan-interface17
|
||||
description SW_MGMT
|
||||
ip address 10.0.0.2 255.255.255.0
|
||||
#
|
||||
interface GigabitEthernet1/0/1
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/2
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/3
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/4
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/5
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/6
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/7
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/8
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/9
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/10
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/11
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/12
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/13
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/14
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/15
|
||||
port access vlan 16
|
||||
duplex full
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/16
|
||||
port access vlan 16
|
||||
duplex full
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/17
|
||||
port access vlan 16
|
||||
duplex full
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/18
|
||||
port access vlan 16
|
||||
speed 1000
|
||||
duplex full
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/19
|
||||
port access vlan 16
|
||||
duplex full
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/20
|
||||
port access vlan 16
|
||||
duplex full
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/21
|
||||
port access vlan 16
|
||||
duplex full
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/22
|
||||
port access vlan 16
|
||||
duplex full
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/23
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/24
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/25
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/26
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/27
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/28
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/29
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/30
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/31
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/32
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/33
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/34
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/35
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/36
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/37
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/38
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/39
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/40
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/41
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/42
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/43
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/44
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/45
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/46
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/47
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/48
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface Ten-GigabitEthernet1/0/49
|
||||
description *** Uplink TRUNK_TO_CORE ***
|
||||
port link-type trunk
|
||||
port trunk permit vlan all
|
||||
#
|
||||
interface Ten-GigabitEthernet1/0/50
|
||||
description ###TRUNK_TO_COREXXXX###
|
||||
port link-type trunk
|
||||
port trunk permit vlan all
|
||||
stp instance 0 cost 120
|
||||
#
|
||||
interface Ten-GigabitEthernet1/0/51
|
||||
#
|
||||
interface Ten-GigabitEthernet1/0/52
|
||||
#
|
||||
return
|
||||
<5130-INV-1714>
|
||||
686
conf_switch_stack.exemple
Normal file
686
conf_switch_stack.exemple
Normal file
|
|
@ -0,0 +1,686 @@
|
|||
|
||||
|
||||
|
||||
**********************************************************
|
||||
|
||||
Use is restricted to authorized users
|
||||
who must comply with the Electronic Communications Policy.
|
||||
Usage is monitored; unauthorized use will be prosecuted.
|
||||
|
||||
**********************************************************
|
||||
|
||||
**********************************************************
|
||||
|
||||
Connected to 5130-INV-1714 GEMALTO on MEYREUIL (FRANCE)
|
||||
|
||||
Use is restricted to authorized users
|
||||
who must comply with the Electronic Communications Policy.
|
||||
Usage is monitored; unauthorized use will be prosecuted.
|
||||
|
||||
**********************************************************
|
||||
|
||||
|
||||
|
||||
******************************************************************************
|
||||
* Copyright (c) 2010-2019 Hewlett Packard Enterprise Development LP *
|
||||
* Without the owner's prior written consent, *
|
||||
* no decompiling or reverse-engineering shall be allowed. *
|
||||
******************************************************************************
|
||||
|
||||
<5130-INV-1714>display current-configuration interface
|
||||
#
|
||||
interface NULL0
|
||||
#
|
||||
interface Vlan-interface17
|
||||
description SW_MGMT
|
||||
ip address 10.0.0.2 255.255.255.0
|
||||
#
|
||||
interface GigabitEthernet1/0/1
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/2
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/3
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/4
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/5
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/6
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/7
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/8
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/9
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/10
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/11
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/12
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/13
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/14
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/15
|
||||
port access vlan 16
|
||||
duplex full
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/16
|
||||
port access vlan 16
|
||||
duplex full
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet1/0/17
|
||||
port access vlan 16
|
||||
duplex full
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/18
|
||||
port access vlan 16
|
||||
speed 1000
|
||||
duplex full
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/19
|
||||
port access vlan 16
|
||||
duplex full
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/20
|
||||
port access vlan 16
|
||||
duplex full
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/21
|
||||
port access vlan 16
|
||||
duplex full
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/22
|
||||
port access vlan 16
|
||||
duplex full
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/23
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/24
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/25
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/26
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/27
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/28
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/29
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/30
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/31
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/32
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/33
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/34
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/35
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/36
|
||||
port access vlan 18
|
||||
#
|
||||
interface GigabitEthernet1/0/37
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/38
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/39
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/40
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/41
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/42
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/43
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/44
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/45
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/46
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/47
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet1/0/48
|
||||
description ** ULAB **
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface Ten-GigabitEthernet1/0/49
|
||||
description *** Uplink TRUNK_TO_CORE ***
|
||||
port link-type trunk
|
||||
port trunk permit vlan all
|
||||
#
|
||||
interface Ten-GigabitEthernet1/0/50
|
||||
description ###TRUNK_TO_COREXXXX###
|
||||
port link-type trunk
|
||||
port trunk permit vlan all
|
||||
stp instance 0 cost 120
|
||||
#
|
||||
interface Ten-GigabitEthernet1/0/51
|
||||
#
|
||||
interface Ten-GigabitEthernet1/0/52
|
||||
#
|
||||
interface GigabitEthernet2/0/1
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/2
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/3
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/4
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/5
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/6
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/7
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/8
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/9
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/10
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/11
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/12
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/13
|
||||
port access vlan 16
|
||||
duplex full
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/14
|
||||
port access vlan 16
|
||||
duplex full
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/15
|
||||
port access vlan 16
|
||||
duplex full
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/16
|
||||
port access vlan 16
|
||||
duplex full
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/17
|
||||
port access vlan 16
|
||||
duplex full
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/18
|
||||
port access vlan 16
|
||||
duplex full
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/19
|
||||
port access vlan 16
|
||||
duplex full
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/20
|
||||
port access vlan 16
|
||||
duplex full
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/21
|
||||
port access vlan 16
|
||||
duplex full
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/22
|
||||
port access vlan 16
|
||||
duplex full
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/23
|
||||
port access vlan 16
|
||||
duplex full
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/24
|
||||
port access vlan 16
|
||||
duplex full
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/25
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/26
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/27
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/28
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/29
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/30
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/31
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/32
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/33
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/34
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/35
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/36
|
||||
stp edged-port
|
||||
undo lldp enable
|
||||
undo dot1x handshake
|
||||
dot1x mandatory-domain example_radius
|
||||
undo dot1x multicast-trigger
|
||||
dot1x re-authenticate
|
||||
port-security port-mode userlogin-secure
|
||||
#
|
||||
interface GigabitEthernet2/0/37
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/38
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/39
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/40
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/41
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/42
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/43
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/44
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/45
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/46
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/47
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface GigabitEthernet2/0/48
|
||||
port access vlan 18
|
||||
undo lldp enable
|
||||
#
|
||||
interface Ten-GigabitEthernet2/0/49
|
||||
description *** Uplink TRUNK_TO_CORE ***
|
||||
port link-type trunk
|
||||
port trunk permit vlan all
|
||||
#
|
||||
interface Ten-GigabitEthernet2/0/50
|
||||
description ###TRUNK_TO_COREXXXX###
|
||||
port link-type trunk
|
||||
port trunk permit vlan all
|
||||
stp instance 0 cost 120
|
||||
#
|
||||
interface Ten-GigabitEthernet2/0/51
|
||||
#
|
||||
interface Ten-GigabitEthernet2/0/52
|
||||
#
|
||||
return
|
||||
<5130-INV-STACK>
|
||||
11
index.html
Normal file
11
index.html
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="refresh" content="0; url=CMDB/cmdb.html">
|
||||
<title>CMDB</title>
|
||||
</head>
|
||||
<body>
|
||||
<a href="CMDB/cmdb.html">Redirection vers la CMDB…</a>
|
||||
</body>
|
||||
</html>
|
||||
5
mise.toml
Normal file
5
mise.toml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
[tasks.run]
|
||||
description = "Run server"
|
||||
run = '''
|
||||
uv run server.py
|
||||
'''
|
||||
11
proxy.sh
Normal file
11
proxy.sh
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# Renseignez l'URL de votre proxy d'entreprise (host:port).
|
||||
PROXY_URL="http://PROXY_HOST:PROXY_PORT/"
|
||||
|
||||
export http_proxy="$PROXY_URL"
|
||||
export https_proxy="$PROXY_URL"
|
||||
export ftp_proxy="$PROXY_URL"
|
||||
|
||||
# For curl
|
||||
export HTTP_PROXY="$PROXY_URL"
|
||||
export HTTPS_PROXY="$PROXY_URL"
|
||||
export FTP_PROXY="$PROXY_URL"
|
||||
9
pyproject.toml
Normal file
9
pyproject.toml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
[project]
|
||||
name = "version2"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
dependencies = [
|
||||
"ldap3>=2.9.1",
|
||||
]
|
||||
262
server.py
Normal file
262
server.py
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Serveur unifié du portail Infra (CMDB + Certificats + Switch).
|
||||
|
||||
Un seul serveur, lancé à la racine du projet :
|
||||
|
||||
python3 server.py # http://127.0.0.1:8000 → CMDB
|
||||
python3 server.py 8080 # port custom
|
||||
|
||||
- http://127.0.0.1:8000/ → redirige vers la CMDB
|
||||
- CMDB : base partagée cmdb.db sourcée automatiquement (/db, versionnée)
|
||||
- Générateur de certificats : écrit sur le disque dans
|
||||
GENERATEUR_CERTIFICATES/LISTS_ALL_CERT/ (créé au besoin), aucun prompt
|
||||
- Sert les 3 applications + le switcher (liens relatifs OK)
|
||||
- Recherche AD/LDAP de la CMDB conservée (nécessite `pip install ldap3`)
|
||||
"""
|
||||
import sys, os, json, base64, shutil, re, threading
|
||||
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
|
||||
from urllib.parse import urlparse, parse_qs
|
||||
|
||||
PORT = int(sys.argv[1]) if len(sys.argv) > 1 else 8000
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__)) # racine projet
|
||||
CMDB_DIR = os.path.join(HERE, 'CMDB')
|
||||
CERT_DIR = os.path.join(HERE, 'GENERATEUR_CERTIFICATES')
|
||||
WORK = os.path.join(CERT_DIR, 'LISTS_ALL_CERT') # dossier de travail certs (disque)
|
||||
ARCH = os.path.join(WORK, 'archives')
|
||||
|
||||
# réutilise la logique CMDB existante (base partagée cmdb.db + LDAP)
|
||||
sys.path.insert(0, CMDB_DIR)
|
||||
import cmdb_server as C # ne démarre rien (guarded __main__)
|
||||
|
||||
SAFE = re.compile(r'^[A-Za-z0-9._@\- ]+$')
|
||||
|
||||
def safe_name(n):
|
||||
n = (n or '').strip()
|
||||
if not n or n in ('.', '..') or '/' in n or '\\' in n or not SAFE.match(n):
|
||||
raise ValueError('nom invalide: %r' % n)
|
||||
return n
|
||||
|
||||
def ensure_work():
|
||||
os.makedirs(WORK, exist_ok=True)
|
||||
|
||||
|
||||
class Handler(SimpleHTTPRequestHandler):
|
||||
def log_message(self, *a):
|
||||
pass
|
||||
|
||||
# ---------- helpers ----------
|
||||
def _json(self, obj, code=200):
|
||||
body = json.dumps(obj).encode('utf-8')
|
||||
self.send_response(code)
|
||||
self.send_header('Content-Type', 'application/json')
|
||||
self.send_header('Content-Length', str(len(body)))
|
||||
self.send_header('Cache-Control', 'no-store')
|
||||
self.end_headers()
|
||||
self.wfile.write(body)
|
||||
|
||||
def _err(self, msg, code=400):
|
||||
self._json({'ok': False, 'error': str(msg)}, code)
|
||||
|
||||
def _send_db(self, code, data, version):
|
||||
self.send_response(code)
|
||||
self.send_header('Content-Type', 'application/octet-stream')
|
||||
self.send_header('X-DB-Version', str(version))
|
||||
self.send_header('Cache-Control', 'no-store')
|
||||
self.send_header('Content-Length', str(len(data)))
|
||||
self.end_headers()
|
||||
if data:
|
||||
self.wfile.write(data)
|
||||
|
||||
def _send_download(self, data, filename):
|
||||
self.send_response(200)
|
||||
self.send_header('Content-Type', 'application/octet-stream')
|
||||
self.send_header('Content-Disposition', 'attachment; filename="%s"' % filename)
|
||||
self.send_header('Cache-Control', 'no-store')
|
||||
self.send_header('Content-Length', str(len(data)))
|
||||
self.end_headers()
|
||||
self.wfile.write(data)
|
||||
|
||||
def _body(self):
|
||||
n = int(self.headers.get('Content-Length', 0))
|
||||
return json.loads(self.rfile.read(n) or b'{}')
|
||||
|
||||
def _cert_api(self):
|
||||
p = self.path.split('?', 1)[0]
|
||||
if '/GENERATEUR_CERTIFICATES/api/' in p:
|
||||
return p.split('/api/', 1)[1]
|
||||
return None
|
||||
|
||||
# ---------- GET ----------
|
||||
def do_GET(self):
|
||||
# racine → CMDB
|
||||
if self.path in ('/', '/index.html'):
|
||||
self.send_response(302)
|
||||
self.send_header('Location', '/CMDB/cmdb.html')
|
||||
self.end_headers()
|
||||
return
|
||||
# base CMDB partagée
|
||||
if self.path == '/db':
|
||||
with C.DB_LOCK:
|
||||
return self._send_db(200, C.db_bytes(), C.db_version())
|
||||
if self.path == '/db/version':
|
||||
return self._json({'version': C.db_version()})
|
||||
if self.path == '/db/snapshots':
|
||||
return self._json({'snapshots': C.list_snapshots()})
|
||||
if self.path.startswith('/db/snapshot?'):
|
||||
name = (parse_qs(urlparse(self.path).query).get('name') or [''])[0]
|
||||
try:
|
||||
data = C.snapshot_bytes(name)
|
||||
except (ValueError, OSError):
|
||||
return self._json({'error': 'snapshot introuvable'}, 404)
|
||||
return self._send_download(data, os.path.basename(name))
|
||||
# API certs (lecture)
|
||||
api = self._cert_api()
|
||||
if api == 'ping':
|
||||
return self._json({'ok': True, 'workdir': 'LISTS_ALL_CERT'})
|
||||
if api == 'list':
|
||||
return self._json(self.cert_list())
|
||||
return super().do_GET()
|
||||
|
||||
# ---------- POST ----------
|
||||
def do_POST(self):
|
||||
# base CMDB
|
||||
if self.path == '/db':
|
||||
data = self.rfile.read(int(self.headers.get('Content-Length', 0)))
|
||||
base = int(self.headers.get('X-Base-Version', '0') or 0)
|
||||
cur = C.db_version()
|
||||
if base != cur:
|
||||
return self._send_db(409, C.db_bytes(), cur)
|
||||
return self._send_db(200, b'', C.db_write_and_snapshot(data))
|
||||
# snapshots CMDB (création / suppression / restauration)
|
||||
if self.path in ('/db/snapshot', '/db/snapshot/delete', '/db/restore'):
|
||||
body = self._body()
|
||||
if self.path == '/db/snapshot':
|
||||
meta = C.create_snapshot(label=body.get('label') or 'manual')
|
||||
if not meta:
|
||||
return self._json({'error': 'base vide — rien à sauvegarder'}, 400)
|
||||
return self._json(meta)
|
||||
if self.path == '/db/snapshot/delete':
|
||||
try:
|
||||
C.delete_snapshot(body.get('name') or '')
|
||||
except (ValueError, OSError):
|
||||
return self._json({'error': 'nom de snapshot invalide'}, 400)
|
||||
return self._json({'ok': True})
|
||||
try:
|
||||
C.restore_snapshot(body.get('name') or '')
|
||||
except (ValueError, FileNotFoundError):
|
||||
return self._json({'error': 'snapshot introuvable'}, 404)
|
||||
with C.DB_LOCK:
|
||||
return self._send_db(200, C.db_bytes(), C.db_version())
|
||||
# LDAP (délégué à cmdb_server)
|
||||
if self.path in ('/ldap/search', '/ldap/computer'):
|
||||
if not C.HAS_LDAP:
|
||||
return self._json({'error': "module ldap3 manquant — pip install ldap3"}, 500)
|
||||
try:
|
||||
body = json.loads(self.rfile.read(int(self.headers.get('Content-Length', 0))))
|
||||
fn = C.ldap_computer if self.path == '/ldap/computer' else C.ldap_search
|
||||
if self.path == '/ldap/search':
|
||||
return self._json(fn(body.get('config') or {}, (body.get('query') or '').strip(),
|
||||
int(body.get('limit') or 25)))
|
||||
return self._json(fn(body.get('config') or {}, (body.get('query') or '').strip()))
|
||||
except Exception as ex:
|
||||
return self._json({'error': str(ex)}, 500)
|
||||
# API certs (écriture)
|
||||
api = self._cert_api()
|
||||
try:
|
||||
if api == 'write': return self.cert_write_text()
|
||||
if api == 'write_bin': return self.cert_write_bin()
|
||||
if api == 'delete': return self.cert_delete_dir()
|
||||
if api == 'delete_archives': return self.cert_delete_archives()
|
||||
except Exception as e:
|
||||
return self._err(e, 500)
|
||||
self._err('route inconnue: %s' % self.path, 404)
|
||||
|
||||
# ---------- certificats (disque réel) ----------
|
||||
def cert_list(self):
|
||||
ensure_work()
|
||||
certs, archives = [], []
|
||||
for entry in sorted(os.listdir(WORK)):
|
||||
full = os.path.join(WORK, entry)
|
||||
if entry == 'archives':
|
||||
if os.path.isdir(full):
|
||||
for a in sorted(os.listdir(full)):
|
||||
af = os.path.join(full, a)
|
||||
if os.path.isfile(af):
|
||||
st = os.stat(af)
|
||||
archives.append({'name': a, 'size': st.st_size,
|
||||
'mtime': int(st.st_mtime * 1000)})
|
||||
continue
|
||||
if not os.path.isdir(full):
|
||||
continue
|
||||
files, date = [], 0
|
||||
for fn in sorted(os.listdir(full)):
|
||||
ff = os.path.join(full, fn)
|
||||
if not os.path.isfile(ff):
|
||||
continue
|
||||
st = os.stat(ff)
|
||||
m = int(st.st_mtime * 1000)
|
||||
date = max(date, m)
|
||||
files.append({'name': fn, 'ext': (fn.rsplit('.', 1)[-1] if '.' in fn else '').lower(),
|
||||
'size': st.st_size, 'mtime': m})
|
||||
if files:
|
||||
certs.append({'dir': entry, 'files': files, 'date': date})
|
||||
archives.sort(key=lambda a: -a['mtime'])
|
||||
certs.sort(key=lambda c: -c['date'])
|
||||
return {'ok': True, 'certs': certs, 'archives': archives}
|
||||
|
||||
def cert_write_text(self):
|
||||
d = self._body()
|
||||
dname = safe_name(d['dir'])
|
||||
target = os.path.join(WORK, dname)
|
||||
os.makedirs(target, exist_ok=True)
|
||||
for fname, content in (d.get('files') or {}).items():
|
||||
with open(os.path.join(target, safe_name(fname)), 'w', encoding='utf-8', newline='') as f:
|
||||
f.write(content)
|
||||
self._json({'ok': True, 'path': 'LISTS_ALL_CERT/%s/' % dname})
|
||||
|
||||
def cert_write_bin(self):
|
||||
d = self._body()
|
||||
parts = [safe_name(x) for x in d['path'].split('/') if x != '']
|
||||
if not parts:
|
||||
raise ValueError('path vide')
|
||||
target = os.path.join(WORK, *parts)
|
||||
os.makedirs(os.path.dirname(target), exist_ok=True)
|
||||
with open(target, 'wb') as f:
|
||||
f.write(base64.b64decode(d['b64']))
|
||||
self._json({'ok': True, 'path': 'LISTS_ALL_CERT/%s' % '/'.join(parts)})
|
||||
|
||||
def cert_delete_dir(self):
|
||||
d = self._body()
|
||||
dname = safe_name(d['dir'])
|
||||
target = os.path.join(WORK, dname)
|
||||
if os.path.isdir(target):
|
||||
shutil.rmtree(target)
|
||||
if d.get('archives'):
|
||||
self._rm_archives(dname)
|
||||
self._json({'ok': True})
|
||||
|
||||
def cert_delete_archives(self):
|
||||
self._rm_archives(safe_name(self._body()['dir']))
|
||||
self._json({'ok': True})
|
||||
|
||||
def _rm_archives(self, dname):
|
||||
low = dname.lower()
|
||||
if os.path.isdir(ARCH):
|
||||
for a in os.listdir(ARCH):
|
||||
if low in a.lower():
|
||||
try: os.remove(os.path.join(ARCH, a))
|
||||
except OSError: pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
ensure_work()
|
||||
os.chdir(HERE)
|
||||
if not C.HAS_LDAP:
|
||||
print("⚠ ldap3 absent : recherche AD de la CMDB désactivée (pip install ldap3)")
|
||||
print('Portail Infra : http://127.0.0.1:%d → CMDB' % PORT)
|
||||
print('CMDB base : %s' % C.DB_PATH)
|
||||
print('Certificats : %s (créé automatiquement)' % WORK)
|
||||
print('Ctrl+C pour arrêter.')
|
||||
ThreadingHTTPServer(('0.0.0.0', PORT), Handler).serve_forever()
|
||||
35
uv.lock
generated
Normal file
35
uv.lock
generated
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.13"
|
||||
|
||||
[[package]]
|
||||
name = "ldap3"
|
||||
version = "2.9.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pyasn1" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/43/ac/96bd5464e3edbc61595d0d69989f5d9969ae411866427b2500a8e5b812c0/ldap3-2.9.1.tar.gz", hash = "sha256:f3e7fc4718e3f09dda568b57100095e0ce58633bcabbed8667ce3f8fbaa4229f", size = 398830, upload-time = "2021-07-18T06:34:21.786Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/4e/f6/71d6ec9f18da0b2201287ce9db6afb1a1f637dedb3f0703409558981c723/ldap3-2.9.1-py2.py3-none-any.whl", hash = "sha256:5869596fc4948797020d3f03b7939da938778a0f9e2009f7a072ccf92b8e8d70", size = 432192, upload-time = "2021-07-18T06:34:12.905Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyasn1"
|
||||
version = "0.6.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5c/5f/6583902b6f79b399c9c40674ac384fd9cd77805f9e6205075f828ef11fb2/pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf", size = 148685, upload-time = "2026-03-17T01:06:53.382Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde", size = 83997, upload-time = "2026-03-17T01:06:52.036Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "version2"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "ldap3" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [{ name = "ldap3", specifier = ">=2.9.1" }]
|
||||
Loading…
Add table
Add a link
Reference in a new issue