|
@@ -0,0 +1,198 @@
|
|
|
|
|
+#!/usr/bin/env python3
|
|
|
|
|
+"""
|
|
|
|
|
+Generate DBeaver data-sources.json from sdm status --json output
|
|
|
|
|
+Organizes PostgreSQL connections by customer folders
|
|
|
|
|
+Excludes readonly connections, includes activate connections
|
|
|
|
|
+"""
|
|
|
|
|
+
|
|
|
|
|
+import subprocess
|
|
|
|
|
+import json
|
|
|
|
|
+import re
|
|
|
|
|
+import uuid
|
|
|
|
|
+import os
|
|
|
|
|
+from collections import defaultdict
|
|
|
|
|
+
|
|
|
|
|
+def run_sdm_status():
|
|
|
|
|
+ try:
|
|
|
|
|
+ result = subprocess.run(['sdm', 'status', '--json'], capture_output=True, text=True)
|
|
|
|
|
+ if result.returncode != 0:
|
|
|
|
|
+ print(f"Error running sdm status: {result.stderr}")
|
|
|
|
|
+ return None
|
|
|
|
|
+ return json.loads(result.stdout)
|
|
|
|
|
+ except FileNotFoundError:
|
|
|
|
|
+ print("Error: sdm command not found")
|
|
|
|
|
+ return None
|
|
|
|
|
+ except json.JSONDecodeError as e:
|
|
|
|
|
+ print(f"Error parsing JSON: {e}")
|
|
|
|
|
+ return None
|
|
|
|
|
+
|
|
|
|
|
+def parse_postgres_connections(sdm_data):
|
|
|
|
|
+ connections = []
|
|
|
|
|
+
|
|
|
|
|
+ for item in sdm_data:
|
|
|
|
|
+ if item.get('type') == 'postgres':
|
|
|
|
|
+ name = item.get('name', '')
|
|
|
|
|
+ address = item.get('address', '')
|
|
|
|
|
+
|
|
|
|
|
+ if 'readonly' in name:
|
|
|
|
|
+ continue
|
|
|
|
|
+
|
|
|
|
|
+ if ':' in address:
|
|
|
|
|
+ addr, port = address.split(':')
|
|
|
|
|
+ port = int(port)
|
|
|
|
|
+ else:
|
|
|
|
|
+ continue
|
|
|
|
|
+
|
|
|
|
|
+ env_info = parse_connection_name(name)
|
|
|
|
|
+ if env_info:
|
|
|
|
|
+ connections.append({
|
|
|
|
|
+ 'name': name,
|
|
|
|
|
+ 'addr': addr,
|
|
|
|
|
+ 'port': port,
|
|
|
|
|
+ 'environment': env_info['environment'],
|
|
|
|
|
+ 'customer': env_info['customer'],
|
|
|
|
|
+ 'stage': env_info['stage']
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ return connections
|
|
|
|
|
+
|
|
|
|
|
+def parse_connection_name(name):
|
|
|
|
|
+ pattern = r'oc-([^-]+)-([^-]+)-.*'
|
|
|
|
|
+ match = re.match(pattern, name)
|
|
|
|
|
+
|
|
|
|
|
+ if not match:
|
|
|
|
|
+ return None
|
|
|
|
|
+
|
|
|
|
|
+ environment = match.group(1)
|
|
|
|
|
+ customer = match.group(2)
|
|
|
|
|
+
|
|
|
|
|
+ if environment in ['dev', 'nextrc', 'nextrc2']:
|
|
|
|
|
+ stage = 'internal'
|
|
|
|
|
+ elif environment in ['stage', 'stage2', 'uat']:
|
|
|
|
|
+ stage = 'stage'
|
|
|
|
|
+ elif environment in ['prod', 'prod2']:
|
|
|
|
|
+ stage = 'production'
|
|
|
|
|
+ else:
|
|
|
|
|
+ stage = 'unknown'
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ 'environment': environment,
|
|
|
|
|
+ 'customer': customer,
|
|
|
|
|
+ 'stage': stage
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+def create_dbeaver_connection(conn, connection_id):
|
|
|
|
|
+ if conn['customer'] == 'internal' or conn['customer'].startswith('feature'):
|
|
|
|
|
+ folder = 'internal'
|
|
|
|
|
+ elif conn['stage'] == 'stage':
|
|
|
|
|
+ folder = conn['customer']
|
|
|
|
|
+ elif conn['stage'] == 'production':
|
|
|
|
|
+ folder = conn['customer']
|
|
|
|
|
+ else:
|
|
|
|
|
+ folder = 'other'
|
|
|
|
|
+
|
|
|
|
|
+ display_name = conn['name'].replace('oc-', '').replace('-rds', '').replace('-activate', '')
|
|
|
|
|
+
|
|
|
|
|
+ if 'activate' in conn['name']:
|
|
|
|
|
+ display_name = f"activate-{display_name}"
|
|
|
|
|
+
|
|
|
|
|
+ if 'activate' in conn['name']:
|
|
|
|
|
+ default_db = "postgres"
|
|
|
|
|
+ db_url = f"jdbc:postgresql://{conn['addr']}:{conn['port']}/postgres"
|
|
|
|
|
+ else:
|
|
|
|
|
+ default_db = "member_dossier"
|
|
|
|
|
+ db_url = f"jdbc:postgresql://{conn['addr']}:{conn['port']}/member_dossier"
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ "provider": "postgresql",
|
|
|
|
|
+ "driver": "postgres-jdbc",
|
|
|
|
|
+ "name": display_name,
|
|
|
|
|
+ "save-password": True,
|
|
|
|
|
+ "folder": folder,
|
|
|
|
|
+ "configuration": {
|
|
|
|
|
+ "host": conn['addr'],
|
|
|
|
|
+ "port": str(conn['port']),
|
|
|
|
|
+ "database": default_db,
|
|
|
|
|
+ "url": db_url,
|
|
|
|
|
+ "configurationType": "MANUAL",
|
|
|
|
|
+ "home": "/bin",
|
|
|
|
|
+ "type": conn['environment'],
|
|
|
|
|
+ "closeIdleConnection": False,
|
|
|
|
|
+ "provider-properties": {
|
|
|
|
|
+ "@dbeaver-show-non-default-db@": "true",
|
|
|
|
|
+ "@dbeaver-show-template-db@": "true",
|
|
|
|
|
+ "@dbeaver-show-unavailable-db@": "true",
|
|
|
|
|
+ "show-database-statistics": "false",
|
|
|
|
|
+ "@dbeaver-read-all-data-types-db@": "false",
|
|
|
|
|
+ "@dbeaver-use-prepared-statements-db@": "false",
|
|
|
|
|
+ "postgresql.dd.plain.string": "false",
|
|
|
|
|
+ "postgresql.dd.tag.string": "false"
|
|
|
|
|
+ },
|
|
|
|
|
+ "auth-model": "native"
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+def group_connections(connections):
|
|
|
|
|
+ folders = defaultdict(list)
|
|
|
|
|
+
|
|
|
|
|
+ for conn in connections:
|
|
|
|
|
+ if conn['customer'] == 'internal' or conn['customer'].startswith('feature'):
|
|
|
|
|
+ folder = 'internal'
|
|
|
|
|
+ elif conn['stage'] == 'stage':
|
|
|
|
|
+ folder = conn['customer']
|
|
|
|
|
+ elif conn['stage'] == 'production':
|
|
|
|
|
+ folder = conn['customer']
|
|
|
|
|
+ else:
|
|
|
|
|
+ folder = 'other'
|
|
|
|
|
+
|
|
|
|
|
+ folders[folder].append(conn)
|
|
|
|
|
+
|
|
|
|
|
+ return folders
|
|
|
|
|
+
|
|
|
|
|
+def generate_dbeaver_config(connections):
|
|
|
|
|
+ folders = group_connections(connections)
|
|
|
|
|
+
|
|
|
|
|
+ folders_config = {}
|
|
|
|
|
+ for folder_name in folders.keys():
|
|
|
|
|
+ folders_config[folder_name] = {}
|
|
|
|
|
+
|
|
|
|
|
+ connections_config = {}
|
|
|
|
|
+
|
|
|
|
|
+ for conn in connections:
|
|
|
|
|
+ connection_id = f"postgres-jdbc-{uuid.uuid4().hex[:8]}-{uuid.uuid4().hex[:8]}"
|
|
|
|
|
+ conn_config = create_dbeaver_connection(conn, connection_id)
|
|
|
|
|
+ connections_config[connection_id] = conn_config
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ "folders": folders_config,
|
|
|
|
|
+ "connections": connections_config
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+def main():
|
|
|
|
|
+ print("Generating DBeaver data-sources.json from sdm status --json...")
|
|
|
|
|
+
|
|
|
|
|
+ sdm_data = run_sdm_status()
|
|
|
|
|
+ if not sdm_data:
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ connections = parse_postgres_connections(sdm_data)
|
|
|
|
|
+ print(f"Found {len(connections)} PostgreSQL connections")
|
|
|
|
|
+
|
|
|
|
|
+ folders = group_connections(connections)
|
|
|
|
|
+
|
|
|
|
|
+ for folder_name, conns in folders.items():
|
|
|
|
|
+ print(f" {folder_name}: {len(conns)} connections")
|
|
|
|
|
+
|
|
|
|
|
+ dbeaver_config = generate_dbeaver_config(connections)
|
|
|
|
|
+
|
|
|
|
|
+ output_file = os.path.expanduser('~/.local/share/DBeaverData/workspace6/Stuzo/.dbeaver/data-sources.json')
|
|
|
|
|
+ try:
|
|
|
|
|
+ with open(output_file, 'w') as f:
|
|
|
|
|
+ json.dump(dbeaver_config, f, indent='\t')
|
|
|
|
|
+ print(f"✅ Successfully generated {output_file}")
|
|
|
|
|
+ print("📝 Note: You may need to restart DBeaver to see the new connections")
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ print(f"❌ Error writing file: {e}")
|
|
|
|
|
+
|
|
|
|
|
+if __name__ == '__main__':
|
|
|
|
|
+ main()
|