diff --git a/apps/pusher_app_prem/.DS_Store b/apps/pusher_app_prem/.DS_Store
deleted file mode 100644
index 7e30b28c..00000000
Binary files a/apps/pusher_app_prem/.DS_Store and /dev/null differ
diff --git a/apps/pusher_app_prem/appserver/static/git_pusher.js b/apps/pusher_app_prem/appserver/static/git_pusher.js
deleted file mode 100755
index a8533d92..00000000
--- a/apps/pusher_app_prem/appserver/static/git_pusher.js
+++ /dev/null
@@ -1,557 +0,0 @@
-// ============================================
-// CHARGER LES DASHBOARDS DYNAMIQUEMENT
-// ============================================
-
-// Charger les applications
-function loadAvailableApps() {
- console.log("loadAvailableApps called");
-
- const apiUrl = '/en-US/splunkd/__raw/services/apps/local?output_mode=json&count=0';
-
- fetch(apiUrl)
- .then(response => {
- if (!response.ok) {
- throw new Error('HTTP ' + response.status);
- }
- return response.json();
- })
- .then(data => {
- console.log("Apps Response: Found " + (data.entry ? data.entry.length : 0) + " apps");
-
- if (data.entry && data.entry.length > 0) {
- const apps = data.entry
- .filter(item => {
- // Filtrer les apps système
- const isHidden = item.content && item.content.is_visible === 0;
- const appName = item.name;
- // Exclure les apps système
- const systemApps = ['launcher', 'splunk_monitoring_console', 'introspection'];
- return !isHidden && !systemApps.includes(appName);
- })
- .map(item => ({
- id: item.name,
- name: item.content.label || item.name,
- description: item.content.description || ''
- }))
- .sort((a, b) => a.name.localeCompare(b.name));
-
- console.log("Filtered apps: " + apps.length);
- populateAppsList(apps);
- } else {
- console.warn("No apps found");
- showAppsEmpty();
- }
- })
- .catch(error => {
- console.error("API Error:", error);
- showAppsEmpty();
- });
-}
-
-function populateAppsList(apps) {
- console.log("populateAppsList called with", apps.length, "apps");
-
- const container = document.getElementById('dashboard-list');
-
- if (!container) {
- console.error("dashboard-list container not found");
- return;
- }
-
- if (!apps || apps.length === 0) {
- showAppsEmpty();
- return;
- }
-
- let html = '
';
-
- apps.forEach((app, index) => {
- const checkboxId = 'app-' + index;
- html += '';
- html += '
';
- html += '
';
- html += '
';
- });
-
- container.innerHTML = html;
- console.log('Successfully populated ' + apps.length + ' apps');
-
- // Ajouter les event listeners
- addCheckboxListeners();
-}
-
-function addCheckboxListeners() {
- console.log("addCheckboxListeners called");
-
- const selectAllCheckbox = document.getElementById('select-all');
- if (selectAllCheckbox) {
- selectAllCheckbox.addEventListener('change', function() {
- toggleSelectAll(this);
- });
- }
-
- const appCheckboxes = document.querySelectorAll('#dashboard-list input[type="checkbox"][data-app]');
- appCheckboxes.forEach(checkbox => {
- checkbox.addEventListener('change', function() {
- console.log("App checkbox changed");
- });
- });
-}
-
-function showAppsEmpty() {
- const container = document.getElementById('dashboard-list');
- if (container) {
- container.innerHTML = 'No apps found
';
- }
- console.log("Displayed empty state");
-}
-
-// Attendre que le DOM soit chargé
-function initScript() {
- console.log("initScript called");
-
- // Charger les applications
- loadAvailableApps();
-
- // Charger les credentials sauvegardés
- loadSavedCredentials();
-
- // Attacher les event listeners au bouton
- const pushBtn = document.getElementById('push-btn');
- if (pushBtn) {
- console.log("Push button found, attaching listener");
- pushBtn.addEventListener('click', function(e) {
- e.preventDefault();
- console.log("Push button clicked!");
- pushDashboards();
- });
- } else {
- console.warn("Push button not found");
- }
-
- // Attacher l'event listener pour sauvegarder les credentials
- const saveCheckbox = document.getElementById('save-credentials');
- if (saveCheckbox) {
- saveCheckbox.addEventListener('change', function() {
- if (this.checked) {
- saveCredentials();
- } else {
- clearSavedCredentials();
- }
- });
- }
-}
-
-function loadSavedCredentials() {
- console.log("Loading saved credentials...");
-
- try {
- const savedUrl = getCookie('git_pusher_url');
- const savedToken = getCookie('git_pusher_token');
- const savedBranch = getCookie('git_pusher_branch');
-
- if (savedUrl) {
- document.getElementById('git-url').value = decodeURIComponent(savedUrl);
- console.log("Loaded saved URL from cookie");
- }
-
- if (savedToken) {
- document.getElementById('git-token').value = decodeURIComponent(savedToken);
- console.log("Loaded saved token from cookie");
- }
-
- if (savedBranch) {
- document.getElementById('git-branch').value = decodeURIComponent(savedBranch);
- }
-
- if (savedUrl && savedToken) {
- document.getElementById('save-credentials').checked = true;
- }
- } catch (e) {
- console.warn("Could not load saved credentials:", e);
- }
-}
-
-function saveCredentials() {
- console.log("Saving credentials...");
-
- try {
- const gitUrl = document.getElementById('git-url').value;
- const gitToken = document.getElementById('git-token').value;
- const gitBranch = document.getElementById('git-branch').value;
-
- if (gitUrl && gitToken) {
- setCookie('git_pusher_url', gitUrl, 30);
- setCookie('git_pusher_token', gitToken, 30);
- setCookie('git_pusher_branch', gitBranch, 30);
- console.log("Credentials saved to cookies");
- showSuccess("Credentials saved locally");
- } else {
- showError("Please fill in URL and Token before saving");
- }
- } catch (e) {
- console.error("Error saving credentials:", e);
- showError("Could not save credentials");
- }
-}
-
-function clearSavedCredentials() {
- console.log("Clearing saved credentials...");
-
- try {
- deleteCookie('git_pusher_url');
- deleteCookie('git_pusher_token');
- deleteCookie('git_pusher_branch');
- console.log("Credentials cleared from cookies");
- showSuccess("Credentials cleared");
- } catch (e) {
- console.error("Error clearing credentials:", e);
- }
-}
-
-// Fonctions utilitaires pour les cookies
-function setCookie(name, value, days) {
- const d = new Date();
- d.setTime(d.getTime() + (days * 24 * 60 * 60 * 1000));
- const expires = "expires=" + d.toUTCString();
- document.cookie = name + "=" + encodeURIComponent(value) + ";" + expires + ";path=/";
- console.log("Cookie set: " + name);
-}
-
-function getCookie(name) {
- const nameEQ = name + "=";
- const ca = document.cookie.split(';');
- for (let i = 0; i < ca.length; i++) {
- let c = ca[i].trim();
- if (c.indexOf(nameEQ) === 0) {
- return c.substring(nameEQ.length);
- }
- }
- return "";
-}
-
-function deleteCookie(name) {
- setCookie(name, "", -1);
- console.log("Cookie deleted: " + name);
-}
-
-if (document.readyState === 'loading') {
- document.addEventListener('DOMContentLoaded', function() {
- console.log("DOM Ready - Initializing script...");
- setTimeout(function() {
- initScript();
- }, 1000);
- });
-} else {
- console.log("DOM already ready - Initializing script...");
- setTimeout(function() {
- initScript();
- }, 1000);
-}
-
-function getFormKeyValue() {
- try {
- // Chercher dans les meta tags du DOM
- const metaTag = document.querySelector('meta[name="splunk_form_key"]');
- if (metaTag) {
- return metaTag.getAttribute('content');
- }
-
- // Chercher dans les cookies
- const cookies = document.cookie.split(';');
- for (let cookie of cookies) {
- const [name, value] = cookie.trim().split('=');
- if (name === 'splunk_form_key') {
- return decodeURIComponent(value);
- }
- }
-
- console.warn("Could not find form key, proceeding without it");
- return '';
- } catch (e) {
- console.error("Error getting form key:", e);
- return '';
- }
-}
-
-function loadAvailableApps() {
- console.log("loadAvailableApps called");
-
- const apiUrl = '/en-US/splunkd/__raw/services/apps/local?output_mode=json&count=0';
-
- fetch(apiUrl)
- .then(response => {
- if (!response.ok) {
- throw new Error('HTTP ' + response.status);
- }
- return response.json();
- })
- .then(data => {
- console.log("Apps Response: Found " + (data.entry ? data.entry.length : 0) + " apps");
-
- if (data.entry && data.entry.length > 0) {
- const apps = data.entry
- .filter(item => {
- // Filtrer les apps système
- const isHidden = item.content && item.content.is_visible === 0;
- const appName = item.name;
- // Exclure les apps système
- const systemApps = ['launcher', 'splunk_monitoring_console', 'introspection'];
- return !isHidden && !systemApps.includes(appName);
- })
- .map(item => ({
- id: item.name,
- name: item.content.label || item.name,
- description: item.content.description || ''
- }))
- .sort((a, b) => a.name.localeCompare(b.name));
-
- console.log("Filtered apps: " + apps.length);
- populateAppsList(apps);
- } else {
- console.warn("No apps found");
- showAppsEmpty();
- }
- })
- .catch(error => {
- console.error("API Error:", error);
- showAppsEmpty();
- });
-}
-
-function populateAppsList(apps) {
- console.log("populateAppsList called with", apps.length, "apps");
-
- const container = document.getElementById('dashboard-list');
-
- if (!container) {
- console.error("dashboard-list container not found");
- return;
- }
-
- if (!apps || apps.length === 0) {
- showAppsEmpty();
- return;
- }
-
- let html = '';
- html += '';
- html += '';
- html += '
';
-
- apps.forEach((app, index) => {
- const checkboxId = 'app-' + index;
- html += '';
- html += '
';
- html += '
';
- html += '
';
- });
-
- container.innerHTML = html;
- console.log('Successfully populated ' + apps.length + ' apps');
-}
-
-function showAppsEmpty() {
- const container = document.getElementById('dashboard-list');
- if (container) {
- container.innerHTML = 'No apps found
';
- }
- console.log("Displayed empty state");
-}
-
-function toggleSelectAll(checkbox) {
- const checkboxes = document.querySelectorAll('#dashboard-list input[type="checkbox"][data-app]');
- checkboxes.forEach(cb => cb.checked = checkbox.checked);
-}
-
-// ============================================
-// POUSSER LES DASHBOARDS VERS GIT
-// ============================================
-
-function pushDashboards() {
- console.log("pushDashboards called");
-
- const gitUrl = document.getElementById('git-url').value;
- const gitBranch = document.getElementById('git-branch').value;
- const gitToken = document.getElementById('git-token').value;
- const commitMessage = document.getElementById('commit-message').value;
-
- console.log("Git URL:", gitUrl);
- console.log("Git Branch:", gitBranch);
- console.log("Commit Message:", commitMessage);
-
- const checkboxes = document.querySelectorAll('#dashboard-list input[type="checkbox"]:not(#select-all):checked');
- const selectedApps = Array.from(checkboxes).map(cb => ({
- id: cb.value,
- name: cb.getAttribute('data-name')
- }));
-
- console.log("Selected apps:", selectedApps);
-
- // Validation
- if (!gitUrl.trim()) {
- console.warn("Validation failed: No Git URL");
- showError('Please enter a Git repository URL');
- return;
- }
-
- if (!gitToken.trim()) {
- console.warn("Validation failed: No Git token");
- showError('Please enter your Git token or password');
- return;
- }
-
- if (!commitMessage.trim()) {
- console.warn("Validation failed: No commit message");
- showError('Please enter a commit message');
- return;
- }
-
- if (selectedApps.length === 0) {
- console.warn("Validation failed: No apps selected");
- showError('Please select at least one application');
- return;
- }
-
- console.log("Validation passed, showing loading state...");
-
- // Afficher le loading
- document.getElementById('loading').style.display = 'block';
- document.getElementById('success-msg').style.display = 'none';
- document.getElementById('error-msg').style.display = 'none';
- document.getElementById('push-btn').disabled = true;
-
- // Sauvegarder les credentials si la case est cochée
- if (document.getElementById('save-credentials').checked) {
- try {
- setCookie('git_pusher_url', gitUrl, 30);
- setCookie('git_pusher_token', gitToken, 30);
- setCookie('git_pusher_branch', gitBranch, 30);
- console.log("Credentials auto-saved to cookies");
- } catch (e) {
- console.warn("Could not auto-save credentials:", e);
- }
- }
-
- // Préparer les données - passer les apps au lieu des dashboards
- const payload = {
- git_url: gitUrl,
- git_branch: gitBranch,
- git_token: gitToken,
- apps: selectedApps,
- commit_message: commitMessage,
- timestamp: new Date().toISOString(),
- user: getCurrentUser()
- };
-
- console.log("Payload prepared:", payload);
-
- // Appeler le script Python via serveur
- callPushScript(payload);
-}
-
-function callPushScript(payload) {
- console.log("callPushScript called");
- console.log("Payload:", payload);
-
- // Construire l'URL vers le serveur Python sur le port 9999 en HTTP
- const hostname = window.location.hostname;
- const baseUrl = `http://${hostname}:9999`;
-
- const url = new URL('/push', baseUrl);
-
- // Ajouter les paramètres en query string
- url.searchParams.append('git_url', payload.git_url);
- url.searchParams.append('git_branch', payload.git_branch);
- url.searchParams.append('git_token', payload.git_token);
- url.searchParams.append('commit_message', payload.commit_message);
-
- // Encoder correctement les apps en JSON
- const appsJson = JSON.stringify(payload.apps);
- console.log("Apps JSON:", appsJson);
- url.searchParams.append('apps', appsJson);
-
- url.searchParams.append('user', payload.user);
-
- console.log("Calling:", url.toString());
-
- fetch(url.toString(), {
- method: 'POST',
- mode: 'no-cors'
- })
- .then(response => {
- // Avec no-cors, on ne peut pas lire response.json()
- // Donc on suppose que si la requête arrive au serveur, c'est bon
- console.log("Request sent successfully");
- document.getElementById('loading').style.display = 'none';
- document.getElementById('push-btn').disabled = false;
- showSuccess('Push request sent! Check server logs for details.');
- resetForm();
- return;
- })
- .catch(error => {
- console.error('Fetch error:', error);
- document.getElementById('loading').style.display = 'none';
- document.getElementById('push-btn').disabled = false;
- showError('Network error: ' + error.message);
- });
-}
-
-function getCurrentUser() {
- try {
- // Essayer plusieurs méthodes
- if (Splunk && Splunk.util && typeof Splunk.util.getCurrentUser === 'function') {
- return Splunk.util.getCurrentUser();
- }
-
- // Fallback: chercher dans le DOM ou retourner 'unknown'
- return 'unknown_user';
- } catch (e) {
- console.warn("Could not get current user:", e);
- return 'unknown_user';
- }
-}
-
-function showSuccess(message) {
- const successMsg = document.getElementById('success-msg');
- document.getElementById('success-text').textContent = message;
- successMsg.style.display = 'block';
- setTimeout(() => {
- successMsg.style.display = 'none';
- }, 5000);
-}
-
-function showError(message) {
- const errorMsg = document.getElementById('error-msg');
- document.getElementById('error-text').textContent = 'X ' + message;
- errorMsg.style.display = 'block';
-}
-
-function resetForm(showConfirm = false) {
- document.getElementById('git-url').value = '';
- document.getElementById('git-branch').value = 'main';
- document.getElementById('git-token').value = '';
- document.getElementById('commit-message').value = '';
- document.querySelectorAll('#dashboard-list input[type="checkbox"]').forEach(cb => cb.checked = false);
-
- // Demander si l'utilisateur veut aussi effacer les credentials sauvegardés
- // SEULEMENT si showConfirm = true (c'est-à-dire si l'utilisateur a cliqué sur Reset)
- if (showConfirm && document.getElementById('save-credentials').checked) {
- const confirmClear = confirm('Do you want to clear saved credentials?');
- if (confirmClear) {
- clearSavedCredentials();
- document.getElementById('save-credentials').checked = false;
- }
- }
-}
\ No newline at end of file
diff --git a/apps/pusher_app_prem/bin/README b/apps/pusher_app_prem/bin/README
deleted file mode 100755
index 9a70db09..00000000
--- a/apps/pusher_app_prem/bin/README
+++ /dev/null
@@ -1 +0,0 @@
-This is where you put any scripts you want to add to this app.
diff --git a/apps/pusher_app_prem/bin/git_pusher.pid b/apps/pusher_app_prem/bin/git_pusher.pid
deleted file mode 100755
index 81d2a971..00000000
--- a/apps/pusher_app_prem/bin/git_pusher.pid
+++ /dev/null
@@ -1 +0,0 @@
-919562
diff --git a/apps/pusher_app_prem/bin/git_pusher.py b/apps/pusher_app_prem/bin/git_pusher.py
deleted file mode 100755
index 6f0c0ceb..00000000
--- a/apps/pusher_app_prem/bin/git_pusher.py
+++ /dev/null
@@ -1,340 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-import sys
-import os
-import json
-import logging
-import tempfile
-import shutil
-import subprocess
-from datetime import datetime
-from http.server import HTTPServer, BaseHTTPRequestHandler
-from urllib.parse import parse_qs, urlparse
-
-# Configuration du logging
-log_dir = '/opt/splunk/var/log/splunk'
-os.makedirs(log_dir, exist_ok=True)
-
-logging.basicConfig(
- level=logging.INFO,
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
- handlers=[
- logging.FileHandler(os.path.join(log_dir, 'git_pusher.log')),
- logging.StreamHandler()
- ]
-)
-logger = logging.getLogger('git_pusher')
-
-
-class GitPusherRequestHandler(BaseHTTPRequestHandler):
- """Handler pour les requêtes HTTP"""
-
- def do_OPTIONS(self):
- """Traiter les requêtes OPTIONS (CORS preflight)"""
- self.send_response(200)
- self.send_header('Access-Control-Allow-Origin', '*')
- self.send_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')
- self.send_header('Access-Control-Allow-Headers', 'Content-Type')
- self.end_headers()
-
- def do_POST(self):
- """Traiter les requêtes POST"""
- # Envoyer les headers CORS EN PREMIER
- self.send_response(200)
- self.send_header('Content-type', 'application/json')
- self.send_header('Access-Control-Allow-Origin', '*')
- self.send_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')
- self.send_header('Access-Control-Allow-Headers', 'Content-Type')
- self.end_headers()
-
- try:
- logger.info(f"POST request to {self.path}")
-
- # Parser l'URL et les paramètres
- parsed_url = urlparse(self.path)
- query_params = parse_qs(parsed_url.query)
-
- logger.info(f"Query params keys: {list(query_params.keys())}")
-
- # Extraire les paramètres
- git_url = query_params.get('git_url', [''])[0]
- git_branch = query_params.get('git_branch', ['main'])[0]
- git_token = query_params.get('git_token', [''])[0]
- commit_message = query_params.get('commit_message', [''])[0]
-
- # Accepter soit 'apps' soit 'dashboards'
- apps_json = query_params.get('apps', query_params.get('dashboards', ['[]']))[0]
- user = query_params.get('user', ['unknown'])[0]
-
- logger.info(f"Parameters received: git_url={git_url}, branch={git_branch}, user={user}")
- logger.info(f"Raw apps_json: '{apps_json}'")
-
- # Parser les apps
- try:
- # parse_qs décode déjà, mais au cas où
- if isinstance(apps_json, str):
- apps = json.loads(apps_json)
- else:
- apps = apps_json
- except (json.JSONDecodeError, TypeError) as e:
- logger.error(f"JSON parse error: {e} - trying to parse: {apps_json}")
- apps = []
-
- logger.info(f"Parsed apps: {len(apps)} items - {apps}")
-
- # Valider
- if not git_url or not git_token or not commit_message or not apps:
- logger.warning(f"Validation failed: git_url={bool(git_url)}, git_token={bool(git_token)}, commit_message={bool(commit_message)}, apps={len(apps)}")
- response = {
- 'status': 'error',
- 'message': 'Missing required parameters'
- }
- self.wfile.write(json.dumps(response).encode())
- return
-
- # Créer un répertoire temporaire
- temp_dir = tempfile.mkdtemp(prefix='splunk_git_')
- logger.info(f"Created temp directory: {temp_dir}")
-
- try:
- # Préparer l'URL Git avec le token
- git_url_with_token = self.prepare_git_url(git_url, git_token)
-
- logger.info(f"Git URL prepared (token inserted)")
- logger.debug(f"Git URL with token: {git_url_with_token}")
- logger.info("Cloning repository...")
- self.clone_repository(temp_dir, git_url_with_token, git_branch)
-
- # Récupérer TOUTES les applications (dossiers complets)
- logger.info("Fetching applications from Splunk...")
- dashboard_contents = self.fetch_apps_directories(apps)
-
- # Créer le dossier apps
- apps_dir = os.path.join(temp_dir, 'apps')
- os.makedirs(apps_dir, exist_ok=True)
-
- # Copier les applications
- logger.info("Copying applications to repository...")
- for app_data in dashboard_contents:
- app_name = app_data['name']
- app_path = app_data['path']
- dest_path = os.path.join(apps_dir, app_name)
-
- if os.path.exists(app_path):
- logger.info(f"Copying app {app_name} from {app_path}")
- # Supprimer le dossier s'il existe déjà
- if os.path.exists(dest_path):
- logger.info(f"Removing existing app directory: {dest_path}")
- shutil.rmtree(dest_path)
- # Copier le dossier
- shutil.copytree(app_path, dest_path)
- logger.info(f"Copied app: {app_name}")
- else:
- logger.warning(f"App path not found: {app_path}")
-
- # Configurer git
- logger.info("Configuring git...")
- subprocess.run(['git', 'config', 'user.email', 'splunk@splunk.local'],
- cwd=temp_dir, capture_output=True)
- subprocess.run(['git', 'config', 'user.name', 'Splunk Git Pusher'],
- cwd=temp_dir, capture_output=True)
-
- # Commit et push
- logger.info("Adding files...")
- subprocess.run(['git', 'add', '-A'], cwd=temp_dir, capture_output=True)
-
- full_message = f"{commit_message}\n\nPushed by: {user}\nTimestamp: {datetime.now().isoformat()}"
- logger.info("Committing...")
- result = subprocess.run(['git', 'commit', '-m', full_message],
- cwd=temp_dir, capture_output=True, text=True)
-
- if result.returncode != 0:
- logger.warning(f"Commit may have failed or had no changes: {result.stderr}")
-
- logger.info("Pushing...")
- result = subprocess.run(['git', 'push', 'origin', git_branch],
- cwd=temp_dir, capture_output=True, text=True, timeout=60)
-
- if result.returncode != 0:
- raise Exception(f"Push failed: {result.stderr}")
-
- logger.info("Push successful!")
- response = {
- 'status': 'success',
- 'message': f'Successfully pushed {len(dashboard_contents)} dashboards from {len(apps)} application(s) to Git',
- 'dashboards_pushed': len(dashboard_contents)
- }
- self.wfile.write(json.dumps(response).encode())
-
- finally:
- logger.info(f"Cleaning up {temp_dir}")
- shutil.rmtree(temp_dir, ignore_errors=True)
-
- except Exception as e:
- logger.error(f"Error: {str(e)}", exc_info=True)
- response = {
- 'status': 'error',
- 'message': f'Error: {str(e)}'
- }
- self.wfile.write(json.dumps(response).encode())
-
- def log_message(self, format, *args):
- """Éviter les logs HTTP par défaut"""
- logger.debug(format % args)
-
- @staticmethod
- def prepare_git_url(git_url, token):
- """Préparer l'URL Git avec le token inséré"""
- logger.info(f"Preparing git URL with token")
-
- # Si l'URL contient déjà un token (format: https://user:token@host/repo)
- # on le remplace
- if '@' in git_url:
- # Extraire la partie sans le token
- protocol = git_url.split('://')[0]
- rest = git_url.split('://', 1)[1]
- host_and_path = rest.split('@', 1)[1] if '@' in rest else rest
- return f"{protocol}://{token}@{host_and_path}"
-
- # Si l'URL est juste https://host/repo (sans credentials)
- if git_url.startswith('https://') or git_url.startswith('http://'):
- protocol = git_url.split('://')[0]
- host_and_path = git_url.split('://', 1)[1]
- # Insérer le token au format user:token@host ou juste token@host
- return f"{protocol}://{token}@{host_and_path}"
-
- return git_url
-
- @staticmethod
- def clone_repository(dest_dir, git_url, branch):
- """Cloner le repository"""
- try:
- cmd = ['git', 'clone', '--depth', '1', '--branch', branch, git_url, dest_dir]
- result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
-
- if result.returncode != 0:
- raise Exception(f"Clone failed: {result.stderr}")
-
- logger.info("Repository cloned successfully")
- except subprocess.TimeoutExpired:
- raise Exception("Git clone operation timed out")
- except FileNotFoundError:
- raise Exception("Git is not installed on this system")
-
- @staticmethod
- def fetch_apps_directories(apps):
- """Récupérer les dossiers complets des applications"""
- logger.info(f"Fetching directories for {len(apps)} applications")
-
- splunk_home = '/opt/splunk'
- apps_base_path = os.path.join(splunk_home, 'etc', 'apps')
-
- app_directories = []
-
- for app in apps:
- app_id = app.get('id') or app.get('app_id')
- app_path = os.path.join(apps_base_path, app_id)
-
- logger.info(f"Checking app directory: {app_path}")
-
- if os.path.isdir(app_path):
- app_directories.append({
- 'name': app_id,
- 'path': app_path,
- 'size': sum(os.path.getsize(os.path.join(dirpath, filename))
- for dirpath, dirnames, filenames in os.walk(app_path)
- for filename in filenames)
- })
- logger.info(f"Found app: {app_id} at {app_path}")
- else:
- logger.warning(f"App directory not found: {app_path}")
-
- logger.info(f"Successfully found {len(app_directories)} application directories")
- return app_directories
- """Récupérer TOUS les dashboards de chaque application"""
- logger.info(f"Fetching dashboards from {len(apps)} applications")
-
- import urllib.request
- import urllib.error
- import ssl
- import base64
-
- # Ignorer les certificats SSL auto-signés
- ssl_context = ssl.create_default_context()
- ssl_context.check_hostname = False
- ssl_context.verify_mode = ssl.CERT_NONE
-
- dashboard_contents = []
-
- # Lire le fichier de configuration Splunk pour obtenir les credentials
- # Ou utiliser des credentials par défaut
- splunk_username = os.environ.get('SPLUNK_USERNAME', 'admin')
- splunk_password = os.environ.get('SPLUNK_PASSWORD', 'changeme')
-
- # Créer l'authentification Basic
- credentials = base64.b64encode(f"{splunk_username}:{splunk_password}".encode()).decode()
-
- for app in apps:
- app_id = app.get('id') or app.get('app_id')
- logger.info(f"Fetching all dashboards from app: {app_id}")
-
- try:
- # Récupérer la liste de TOUS les dashboards de cette app
- api_url = f"https://127.0.0.1:8089/servicesNS/-/{app_id}/data/ui/views?output_mode=json&count=0"
-
- logger.debug(f"API URL: {api_url}")
-
- req = urllib.request.Request(api_url)
- req.add_header('Authorization', f'Basic {credentials}')
-
- with urllib.request.urlopen(req, timeout=15, context=ssl_context) as response:
- api_data = json.loads(response.read().decode('utf-8'))
-
- if 'entry' in api_data and len(api_data['entry']) > 0:
- for entry in api_data['entry']:
- try:
- dashboard_id = entry.get('name')
- content = entry.get('content', {})
-
- # eai:data contient le XML complet du dashboard
- dashboard_xml = content.get('eai:data', '')
-
- if dashboard_xml:
- dashboard_contents.append({
- 'id': f"{app_id}_{dashboard_id}",
- 'app': app_id,
- 'content': dashboard_xml,
- 'name': dashboard_id
- })
- logger.debug(f"Fetched: {dashboard_id} from {app_id}")
- except Exception as e:
- logger.error(f"Error processing dashboard entry: {str(e)}")
-
- logger.info(f"Found {len([d for d in dashboard_contents if d['app'] == app_id])} dashboards in {app_id}")
- else:
- logger.warning(f"No dashboards found in app {app_id}")
-
- except urllib.error.HTTPError as e:
- logger.error(f"HTTP {e.code} when fetching app {app_id}: {e.reason}")
- except urllib.error.URLError as e:
- logger.error(f"Cannot reach Splunk API for app {app_id}: {e.reason}")
- except Exception as e:
- logger.error(f"Error fetching dashboards from {app_id}: {str(e)}")
-
- logger.info(f"Successfully fetched {len(dashboard_contents)} dashboards total")
- return dashboard_contents
-
-
-def start_server(port=9999):
- """Démarrer le serveur HTTP"""
- server = HTTPServer(('0.0.0.0', port), GitPusherRequestHandler)
- logger.info(f"Git Pusher server listening on 0.0.0.0:{port} (HTTP)")
- server.serve_forever()
-
-
-if __name__ == '__main__':
- # Démarrer le serveur en background
- port = 9999
- logger.info(f"Starting Git Pusher on port {port}")
- start_server(port)
\ No newline at end of file
diff --git a/apps/pusher_app_prem/bin/start_git_pusher.sh b/apps/pusher_app_prem/bin/start_git_pusher.sh
deleted file mode 100755
index 951e1a0e..00000000
--- a/apps/pusher_app_prem/bin/start_git_pusher.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/bash
-export SPLUNK_USERNAME=admin
-export SPLUNK_PASSWORD='2312Jocpam!?'
-python3 /opt/splunk/etc/apps/pusher_app/bin/git_pusher.py > /opt/splunk/var/log/splunk/git_pusher_startup.log 2>&1 &
-echo $! > /opt/splunk/etc/apps/pusher_app/bin/git_pusher.pid
\ No newline at end of file
diff --git a/apps/pusher_app_prem/certs/server.crt b/apps/pusher_app_prem/certs/server.crt
deleted file mode 100755
index 11fa39a7..00000000
--- a/apps/pusher_app_prem/certs/server.crt
+++ /dev/null
@@ -1,19 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDCTCCAfGgAwIBAgIUCuKo8SLloS5cjBOR04+X6ayZ40cwDQYJKoZIhvcNAQEL
-BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI2MDEyMzIyMTIxOFoXDTI3MDEy
-MzIyMTIxOFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
-AAOCAQ8AMIIBCgKCAQEAs0vF6sFTseKgZC1nZ6CVZdw45yk1Ni0W9Mc24KZ9NKCJ
-rP0tHy0hs6mME/sq8DV1fh0YtqIvBCxcKEE84/cVXmUfZF9JRXO95734+JGPmo07
-zpiu7p3r4WyIWmCXX5VB0UkMEXsPQmonqG1Kwtz+R1cfgis2lUk+xsC2zSjER8l4
-2UODjHvtD25usgxKjpwPrCuZt43miArnVnwfB8OLbAqpwQeYIf18bPt/TrnQsdgd
-ZZiQdE6UTaJ5xhqztwpYJO9pvZA24Bi3bGNfBciITds5RCGY2wQo8yxbeJsidTuW
-7Z64DK9t33oVnB2PqlP6hVGD5Agthsv9ehRPxdd3MwIDAQABo1MwUTAdBgNVHQ4E
-FgQUy0dni+ogqC7YuvfD/Pn0AuebsXQwHwYDVR0jBBgwFoAUy0dni+ogqC7YuvfD
-/Pn0AuebsXQwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAlyxg
-vR15lsYp4TxJPi1WPzLZl1e6ewTl8GhyE1saxS8LRtyTyr8sa9EFRLQ0OIsqYrUw
-zZi7FIDoDPZDKpd0/+U94UKlhUuPUyufQwl5vNu0A+SEpwKeznUMaj4Y98tHvVGd
-1SCndZBWn/v2U4nXqHoTd6Y0xEOga0jUEsUMBckNC236BTo88Zk65/oa9Gncyb27
-9vGVCbmPyzE70H4KFoVtxkoZrKywn+0ajHhgH5gqZNRPWpe6i8xTbMAeIXkCjmWL
-LmOA7MkjeQBBEWewu4vMOXsvf+gCtxUj5owsAcOQlZ3g72Sng4MeMjuVx4ZRVxX9
-fj+vCP9EFI8rX48tjQ==
------END CERTIFICATE-----
diff --git a/apps/pusher_app_prem/certs/server.key b/apps/pusher_app_prem/certs/server.key
deleted file mode 100755
index 8b790585..00000000
--- a/apps/pusher_app_prem/certs/server.key
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAQCzS8XqwVOx4qBk
-LWdnoJVl3DjnKTU2LRb0xzbgpn00oIms/S0fLSGzqYwT+yrwNXV+HRi2oi8ELFwo
-QTzj9xVeZR9kX0lFc73nvfj4kY+ajTvOmK7unevhbIhaYJdflUHRSQwRew9Caieo
-bUrC3P5HVx+CKzaVST7GwLbNKMRHyXjZQ4OMe+0Pbm6yDEqOnA+sK5m3jeaICudW
-fB8Hw4tsCqnBB5gh/Xxs+39OudCx2B1lmJB0TpRNonnGGrO3Clgk72m9kDbgGLds
-Y18FyIhN2zlEIZjbBCjzLFt4myJ1O5btnrgMr23fehWcHY+qU/qFUYPkCC2Gy/16
-FE/F13czAgMBAAECggEAMrEMrvej0xpQ4KHZp3nGY3sk9242JjAPWntsb42CvrtY
-0XjvJe5bpfEcspWDqVBj/Jj7YL9v7Y0hLRxsu8Mi3oJWoskx7RnxKjES0CxPXpHp
-w9p1Mu+hPiWyU2MVySdo6WPuro6NXOiod70WswtKNR9TwDi5gPGpdwYLaOvKusSp
-Rncm0m0H3IBhgVA691X0AUIomAW3Wmh+5If1XHfjrNHTB8cjcNf6koPMkCqHCEZ9
-wtINxOJior+gGkjMXaDszqzNlicVBXFEFjaXWcp38xAif1uimpqKsRzZEF6RAUzi
-H7cI3aF2dXG3C9l6Byi7OSgd8X4JUnE0dlCpC7qweQKBgQDgvoavo8G0kYruCUIQ
-6vcSs1YBByOkl6yZBCZWk10NgRpU1wyu9zmlvEwNVlUfALs5eoLxnhe8Wklq0ckQ
-r/Rl+r/lj/MZUFn49TgUCsUOIi/G7nWQG0bPo4bCB2QXsAiKdY+KZeC56620uyom
-1VY+nS3y8O4EP0YHX0qHFfmIZwKBgQDMOywO0DSrZMDyvmbwL0ISzHRcNpRn0jk7
-pEtzM/VOx+v0O93E+5OygzmXlBKjF0MwMXBidf8IZu4xO8qWqAM4EP2DD0cpoS1Z
-WiHHkc5NZhjgeG6C4XaCXR++7CuY25VKKe01yz/+j51linDD8OAibKUspkjVufEN
-R/AT0GFLVQKBgBxMYTEkcXOHD/NA/yyaKVoVcrLWb0p+PqFVwG4OSB03MFWWbmZp
-gry3pOvY/wbUVL68CljaCysQQ0ZL/AE55pAgrqD9KyL41xtd5R3A7WcGLvXheLQY
-eyYR9RnhTF0fMTQd8WD/yvgeENU86+XP3vgrWmnIpG+sd+jdusifn7fpAn9QkwfO
-0FX3SMjW/EegewSWZhOCTgY+77Gk1izuRpGBg16T/QqBrL+Yri0KoGC593OKj/bG
-4ca8id9vjSdgSOj8NbfO/TgWNICvv9+T3PKHlsA5z0nKWSloRVVA/ew1YmyD1gbA
-MnAM/pwac4QJyf6jljmUZAZYTAPOOZN+PbglAoGBAJ9cOGDgT+BCOoNc0T1GJDAk
-xOR8d+tD+j4JH5IVxB51DXjJOZxw9U3XhNH1OcE0x3fRzKJOtlQLxP6fHYVtMVFq
-VpeekmTtJ9OfMg68ELOlf7ykA3GhMJ3FarM6e8+X+KliGf6ND4HBMb112FlMgIi6
-yYi7sfSL53Dzp1Q2DxXV
------END PRIVATE KEY-----
diff --git a/apps/pusher_app_prem/default/app.conf b/apps/pusher_app_prem/default/app.conf
deleted file mode 100755
index a01a048d..00000000
--- a/apps/pusher_app_prem/default/app.conf
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# Splunk app configuration file
-#
-
-[install]
-is_configured = 0
-
-[ui]
-is_visible = true
-label = Pusher Premium
-
-[launcher]
-author =
-description =
-version = 1.0.0
-
diff --git a/apps/pusher_app_prem/default/data/ui/nav/default.xml b/apps/pusher_app_prem/default/data/ui/nav/default.xml
deleted file mode 100755
index 8e98eadb..00000000
--- a/apps/pusher_app_prem/default/data/ui/nav/default.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
diff --git a/apps/pusher_app_prem/default/data/ui/views/README b/apps/pusher_app_prem/default/data/ui/views/README
deleted file mode 100755
index 6cf74f0b..00000000
--- a/apps/pusher_app_prem/default/data/ui/views/README
+++ /dev/null
@@ -1 +0,0 @@
-Add all the views that your app needs in this directory
diff --git a/apps/pusher_app_prem/local/app.conf b/apps/pusher_app_prem/local/app.conf
deleted file mode 100755
index 78666a91..00000000
--- a/apps/pusher_app_prem/local/app.conf
+++ /dev/null
@@ -1,3 +0,0 @@
-[ui]
-
-[launcher]
diff --git a/apps/pusher_app_prem/local/data/ui/views/git_pusher_-_deploy_applications.xml b/apps/pusher_app_prem/local/data/ui/views/git_pusher_-_deploy_applications.xml
deleted file mode 100644
index 15b0b86d..00000000
--- a/apps/pusher_app_prem/local/data/ui/views/git_pusher_-_deploy_applications.xml
+++ /dev/null
@@ -1,484 +0,0 @@
-
-
-
- Modern interface to push Splunk applications to Git repository
-
-
- | rest /services/apps/local | search disabled=0 | fields name, label, description | sort label
- -4h@h
- now
-
-
-
-
-
-
-
-
-
-
-
- ✨ Configure your Git settings below and select the applications you want to deploy to your repository
-
-
-
-
-
-
⚙️ Configuration
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
📦 Applications
-
-
-
-
-
Loading applications...
-
-
-
-
-
-
-
-
Deploying applications to Git... Please wait
-
-
-
- ✅ Applications successfully deployed to Git!
-
-
-
- ❌ Error occurred while deploying applications
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/apps/pusher_app_prem/local/data/ui/views/git_pusher_-_push_applications_to_git.xml b/apps/pusher_app_prem/local/data/ui/views/git_pusher_-_push_applications_to_git.xml
deleted file mode 100644
index eca8b17e..00000000
--- a/apps/pusher_app_prem/local/data/ui/views/git_pusher_-_push_applications_to_git.xml
+++ /dev/null
@@ -1,256 +0,0 @@
-
-
-
- Push Splunk applications to Git repository
-
-
- | rest /services/apps/local | search disabled=0 | fields name, label, description | sort label
- -4h@h
- now
-
-
-
- Configuration & Application Selection
-
-
-
-
-
- ℹ️ Configure your Git settings and select the applications you want to push to your repository.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Pushing applications to Git...
-
-
-
- ✓ Applications successfully pushed to Git!
-
-
-
- ✗ Error occurred while pushing applications
-
-
-
-
-
-
-
- Push History
-
-
- index=_internal source=*git_pusher* action=push_attempt | table _time, user, apps, commit_message, status, error_msg | reverse | rename _time as "Timestamp", user as "User", apps as "Applications", commit_message as "Message", status as "Status", error_msg as "Error" | head 20
- -30d@d
- now
-
-
-
- {"success": "#28a745", "error": "#dc3545", "pending": "#ffc107"}
-
-
-
-
-
\ No newline at end of file
diff --git a/apps/pusher_app_prem/local/data/ui/views/git_pusher_-_push_dashboards_to_git.xml b/apps/pusher_app_prem/local/data/ui/views/git_pusher_-_push_dashboards_to_git.xml
deleted file mode 100644
index 79d34cc9..00000000
--- a/apps/pusher_app_prem/local/data/ui/views/git_pusher_-_push_dashboards_to_git.xml
+++ /dev/null
@@ -1,254 +0,0 @@
-
-
- Push Splunk dashboards to Git repository
-
-
-
- | rest /services/data/ui/views | search title!="" | fields label, id, eai:acl.app | rename label as "Dashboard Name", id as "dashboard_id", "eai:acl.app" as "app" | sort "Dashboard Name"
- -4h@h
- now
-
-
-
-
- Configuration & Dashboard Selection
-
-
-
-
-
- ℹ️ Configure your Git settings and select the dashboards you want to push to your repository.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Pushing dashboards to Git...
-
-
-
- ✓ Dashboards successfully pushed to Git!
-
-
-
- ✗ Error occurred while pushing dashboards
-
-
-
-
-
-
-
-
- Push History
-
-
- index=_internal source=*git_pusher* action=push_attempt | table _time, user, dashboards, commit_message, status, error_msg | reverse | rename _time as "Timestamp", user as "User", dashboards as "Dashboards", commit_message as "Message", status as "Status", error_msg as "Error" | head 20
- -30d@d
- now
-
-
-
- {"success": "#28a745", "error": "#dc3545", "pending": "#ffc107"}
-
-
-
-
-
-
\ No newline at end of file
diff --git a/apps/pusher_app_prem/metadata/default.meta b/apps/pusher_app_prem/metadata/default.meta
deleted file mode 100755
index b77b8cb9..00000000
--- a/apps/pusher_app_prem/metadata/default.meta
+++ /dev/null
@@ -1,35 +0,0 @@
-
-# Application-level permissions
-
-[]
-access = read : [ * ], write : [ admin, power ]
-
-### EVENT TYPES
-
-[eventtypes]
-export = system
-
-
-### PROPS
-
-[props]
-export = system
-
-
-### TRANSFORMS
-
-[transforms]
-export = system
-
-
-### LOOKUPS
-
-[lookups]
-export = system
-
-
-### VIEWSTATES: even normal users should be able to create shared viewstates
-
-[viewstates]
-access = read : [ * ], write : [ * ]
-export = system
diff --git a/apps/pusher_app_prem/metadata/local.meta b/apps/pusher_app_prem/metadata/local.meta
deleted file mode 100644
index a2a6d1a5..00000000
--- a/apps/pusher_app_prem/metadata/local.meta
+++ /dev/null
@@ -1,26 +0,0 @@
-[app/ui]
-version = 10.0.2
-modtime = 1769115948.043388000
-
-[app/launcher]
-version = 10.0.2
-modtime = 1769115948.046389000
-
-[views/git_pusher_-_push_dashboards_to_git]
-access = read : [ admin ], write : [ admin ]
-export = system
-owner = admin
-version = 10.0.2
-modtime = 1769276443.812957000
-
-[views/git_pusher_-_push_applications_to_git]
-owner = admin
-version = 10.0.2
-modtime = 1769361925.808816000
-
-[views/git_pusher_-_deploy_applications]
-access = read : [ * ], write : [ * ]
-export = none
-owner = admin
-version = 10.0.2
-modtime = 1769368785.414181000