Files
sql/init_metabase.py
2025-09-19 10:02:52 +02:00

194 lines
5.9 KiB
Python
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import requests
import time
import sys
BASE_URL = "http://metabase:3000"
ADMIN = {
"first_name": "Emmanuel",
"last_name": "Medina",
"email": "emmanuel.medina@univ-lorraine.fr",
"password": "!ChangeMe!"
}
DB = {
"engine": "postgres",
"name": "ventdest",
"is_on_demand": False,
"is_full_sync": True,
"is_sample": False,
"details": {
"host": "database",
"port": 5432,
"dbname": "sql",
"user": "sql",
"password": "!ChangeMe!",
"ssl": False
}
}
def wait_for_metabase(timeout=300):
print("⏳ Attente de Metabase...")
start = time.time()
while time.time() - start < timeout:
try:
r = requests.get(f"{BASE_URL}/api/health", timeout=2)
if r.ok:
print("✅ Metabase est prêt")
return True
except requests.RequestException:
pass
time.sleep(2)
print("❌ Timeout en attendant Metabase")
return False
def get_setup_token():
r = requests.get(f"{BASE_URL}/api/session/properties")
r.raise_for_status()
return r.json().get("setup-token")
def run_setup(token):
payload = {
"token": token,
"user": ADMIN,
"prefs": {"site_name": "IUT", "site_locale": "fr"}
}
r = requests.post(f"{BASE_URL}/api/setup", json=payload)
if r.status_code == 400 and "already" in r.text.lower():
return login(ADMIN["email"], ADMIN["password"])
r.raise_for_status()
return r.json()["id"]
def login(email, password):
r = requests.post(f"{BASE_URL}/api/session",
json={"username": email, "password": password})
r.raise_for_status()
return r.json()["id"]
def database_exists(session_id, name):
headers = {"X-Metabase-Session": session_id}
r = requests.get(f"{BASE_URL}/api/database", headers=headers)
r.raise_for_status()
for db in r.json():
if db["name"].lower() == name.lower():
return db["id"]
return None
def add_database(session_id, db_config):
db_id = database_exists(session_id, db_config["name"])
if db_id:
print(f" Base '{db_config['name']}' existe déjà (id={db_id})")
return db_id
headers = {"X-Metabase-Session": session_id}
r = requests.post(f"{BASE_URL}/api/database",
headers=headers, json=db_config)
r.raise_for_status()
db_id = r.json()["id"]
print(f"🗄️ Base '{db_config['name']}' ajoutée (id={db_id})")
return db_id
def get_or_create_collection(session_id, name, parent_id=None):
headers = {"X-Metabase-Session": session_id}
r = requests.get(f"{BASE_URL}/api/collection", headers=headers)
r.raise_for_status()
for coll in r.json():
if coll["name"].lower() == name.lower():
print(f" Collection '{name}' existe déjà (id={coll['id']})")
return coll["id"]
payload = {"name": name, "color": "#509EE3"}
if parent_id:
payload["parent_id"] = parent_id
r = requests.post(f"{BASE_URL}/api/collection",
headers=headers, json=payload)
r.raise_for_status()
print(f"📁 Collection '{name}' créée (id={r.json()['id']})")
return r.json()["id"]
def get_or_create_question(session_id, name, db_id, sql, collection_id):
headers = {"X-Metabase-Session": session_id}
r = requests.get(f"{BASE_URL}/api/card", headers=headers)
r.raise_for_status()
for q in r.json():
if q["name"].lower() == name.lower():
print(f" Question '{name}' existe déjà (id={q['id']})")
return q["id"]
payload = {
"name": name,
"dataset_query": {
"database": db_id,
"type": "native",
"native": {"query": sql}
},
"display": "table",
"collection_id": collection_id
}
r = requests.post(f"{BASE_URL}/api/card",
headers=headers, json=payload)
r.raise_for_status()
print(f"❓ Question '{name}' créée (id={r.json()['id']})")
return r.json()["id"]
def get_or_create_dashboard(session_id, name, collection_id):
headers = {"X-Metabase-Session": session_id}
r = requests.get(f"{BASE_URL}/api/dashboard", headers=headers)
r.raise_for_status()
for d in r.json():
if d["name"].lower() == name.lower():
print(f" Dashboard '{name}' existe déjà (id={d['id']})")
return d["id"]
payload = {"name": name, "collection_id": collection_id}
r = requests.post(f"{BASE_URL}/api/dashboard",
headers=headers, json=payload)
r.raise_for_status()
print(f"📊 Dashboard '{name}' créé (id={r.json()['id']})")
return r.json()["id"]
def add_question_to_dashboard(session_id, dashboard_id, card_id):
headers = {"X-Metabase-Session": session_id}
payload = {"cardId": card_id}
r = requests.post(f"{BASE_URL}/api/dashboard/{dashboard_id}/cards",
headers=headers, json=payload)
if r.status_code == 400 and "already" in r.text.lower():
print(f" Question {card_id} déjà liée au dashboard {dashboard_id}")
return
r.raise_for_status()
print(f" Question {card_id} ajoutée au dashboard {dashboard_id}")
if __name__ == "__main__":
if not wait_for_metabase():
sys.exit(1)
token = get_setup_token()
session = run_setup(token)
db_id = add_database(session, DB)
coll_id = get_or_create_collection(session, "IUT Dashboard")
# Exemple : une question SQL
q1 = get_or_create_question(
session,
"Nombre de lignes",
db_id,
"SELECT COUNT(*) AS total FROM information_schema.tables;",
coll_id
)
# Exemple : un dashboard
dash_id = get_or_create_dashboard(session, "Vue d'ensemble", coll_id)
add_question_to_dashboard(session, dash_id, q1)
print("🎉 Initialisation Metabase terminée avec dashboards/questions")