From 3f3dba87592c47d50554ac6cd9491d2f16ec6646 Mon Sep 17 00:00:00 2001 From: Kobe Date: Sun, 15 Jun 2025 13:17:44 +0200 Subject: [PATCH] checking portainer connection --- app/routes/admin_api.py | 107 ++++++++++++++++++++++++ routes/__pycache__/main.cpython-313.pyc | Bin 90844 -> 90929 bytes routes/main.py | 6 +- templates/main/launch_progress.html | 98 ++++++++++++++++++++-- 4 files changed, 204 insertions(+), 7 deletions(-) create mode 100644 app/routes/admin_api.py diff --git a/app/routes/admin_api.py b/app/routes/admin_api.py new file mode 100644 index 0000000..6473c9a --- /dev/null +++ b/app/routes/admin_api.py @@ -0,0 +1,107 @@ +from flask import request, jsonify, current_app +from flask_login import login_required +import os +from datetime import datetime +from app.utils.gitea_api import GiteaAPI +from app.models.gitea_settings import GiteaSettings + +@admin_api.route('/test-git-connection', methods=['POST']) +@login_required +def test_git_connection(): + try: + data = request.get_json() + if not data: + return jsonify({'success': False, 'error': 'No data provided'}), 400 + + required_fields = ['gitea_url', 'username', 'api_token', 'repo_name'] + for field in required_fields: + if field not in data: + return jsonify({'success': False, 'error': f'Missing required field: {field}'}), 400 + + # Test the connection using the provided credentials + gitea = GiteaAPI( + url=data['gitea_url'], + token=data['api_token'] + ) + + # Try to get repository information + repo = gitea.get_repo(data['username'], data['repo_name']) + if not repo: + return jsonify({'success': False, 'error': 'Repository not found'}), 404 + + return jsonify({ + 'success': True, + 'message': 'Successfully connected to Gitea', + 'data': { + 'repo_name': repo.name, + 'description': repo.description, + 'default_branch': repo.default_branch, + 'created_at': repo.created_at, + 'updated_at': repo.updated_at + } + }) + + except Exception as e: + return jsonify({'success': False, 'error': str(e)}), 500 + +@admin_api.route('/check-docker-compose', methods=['POST']) +@login_required +def check_docker_compose(): + try: + data = request.get_json() + if not data: + return jsonify({'success': False, 'error': 'No data provided'}), 400 + + required_fields = ['repository', 'branch'] + for field in required_fields: + if field not in data: + return jsonify({'success': False, 'error': f'Missing required field: {field}'}), 400 + + # Get Gitea settings from database + gitea_settings = GiteaSettings.query.first() + if not gitea_settings: + return jsonify({'success': False, 'error': 'Gitea settings not configured'}), 400 + + # Initialize Gitea API + gitea = GiteaAPI( + url=gitea_settings.server_url, + token=gitea_settings.api_token + ) + + # Split repository into owner and repo name + owner, repo_name = data['repository'].split('/') + + # Get the docker-compose.yml file content + try: + file_content = gitea.get_file_content( + owner=owner, + repo=repo_name, + filepath='docker-compose.yml', + ref=data['branch'] + ) + except Exception as e: + return jsonify({'success': False, 'error': f'Failed to get docker-compose.yml: {str(e)}'}), 404 + + # Save the file content to a temporary location + temp_dir = os.path.join(current_app.config['UPLOAD_FOLDER'], 'temp') + os.makedirs(temp_dir, exist_ok=True) + + file_path = os.path.join(temp_dir, f'docker-compose-{owner}-{repo_name}.yml') + with open(file_path, 'w') as f: + f.write(file_content) + + # Get file stats + file_stats = os.stat(file_path) + + return jsonify({ + 'success': True, + 'message': 'Successfully found and downloaded docker-compose.yml', + 'data': { + 'file_path': file_path, + 'size': file_stats.st_size, + 'last_modified': datetime.fromtimestamp(file_stats.st_mtime).isoformat() + } + }) + + except Exception as e: + return jsonify({'success': False, 'error': str(e)}), 500 \ No newline at end of file diff --git a/routes/__pycache__/main.cpython-313.pyc b/routes/__pycache__/main.cpython-313.pyc index caa229eaa4b5cba01d7eb2c195ea3b281d1c8713..094ed887c6b8e455db511d84931daac616d35990 100644 GIT binary patch delta 274 zcmca}ly&1VR=&@?yj%=GP_oi5W4UZ2-&Q`xO@Ul&KoMae{wy-N@u>M^-!(jw9lDgK z8w4>HOcs7FtER*d%wft1(#OD%#~2M#3I@TPp$wsn!CaQiDh!(3)3*jOsxTGZnSL#Z zQJ$Bn=q^xA(H$V6$u)Uho62;>U`7#ECLmv7x@9n<6JzaU{z{F>JJO}6?+40g%IaR1 zHNPZle!;@$vaIg~4yh;nau?*SZs=IuFmU?F$|T^z_<@0m(}i*SgJ8yQOl1_(5j-&v?dLOq?-NjNC=GKvw_& D=QK&< delta 184 zcmdmZjP=e@R=&@?yj%=G@UYT1 `; stepsContainer.appendChild(proxyStep); + + // Add Portainer connection check step (now last) + const portainerStep = document.createElement('div'); + portainerStep.className = 'step-item'; + portainerStep.innerHTML = ` +
+
+
Checking Portainer Connection
+

Verifying connection to Portainer...

+
+ `; + stepsContainer.appendChild(portainerStep); } async function startLaunch(data) { @@ -234,7 +246,7 @@ async function startLaunch(data) { } // Update the step to show success - const dnsStep = document.querySelector('.step-item'); + const dnsStep = document.querySelectorAll('.step-item')[0]; dnsStep.classList.remove('active'); dnsStep.classList.add('completed'); @@ -294,7 +306,7 @@ async function startLaunch(data) { nginxStep.classList.add('completed'); nginxStep.querySelector('.step-status').textContent = 'Successfully connected to NGINX Proxy Manager'; - // Step 3: Generate SSL Certificate (moved up) + // Step 3: Generate SSL Certificate await updateStep(3, 'Generating SSL Certificate', 'Setting up secure HTTPS connection...'); const sslResult = await generateSSLCertificate(data.webAddresses); @@ -302,7 +314,7 @@ async function startLaunch(data) { throw new Error(sslResult.error || 'Failed to generate SSL certificate'); } - // Step 4: Create Proxy Host (moved down) + // Step 4: Create Proxy Host await updateStep(4, 'Creating Proxy Host', 'Setting up NGINX proxy host configuration...'); const proxyResult = await createProxyHost(data.webAddresses, data.port, sslResult.data.certificate.id); @@ -310,6 +322,20 @@ async function startLaunch(data) { throw new Error(proxyResult.error || 'Failed to create proxy host'); } + // Step 5: Check Portainer connection + await updateStep(5, 'Checking Portainer Connection', 'Verifying connection to Portainer...'); + const portainerResult = await checkPortainerConnection(); + + if (!portainerResult.success) { + throw new Error(portainerResult.error || 'Failed to connect to Portainer'); + } + + // Update the step to show success + const portainerStep = document.querySelectorAll('.step-item')[4]; + portainerStep.classList.remove('active'); + portainerStep.classList.add('completed'); + portainerStep.querySelector('.step-status').textContent = 'Successfully connected to Portainer'; + } catch (error) { showError(error.message); } @@ -391,6 +417,66 @@ async function checkNginxConnection() { } } +async function checkPortainerConnection() { + try { + // Get CSRF token from meta tag + const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content'); + + // Get Portainer settings from the template + const portainerSettings = { + url: '{{ portainer_settings.url if portainer_settings else "" }}', + api_key: '{{ portainer_settings.api_key if portainer_settings else "" }}' + }; + + // Debug log the raw template values + console.log('Raw template values:', { + url: '{{ portainer_settings.url if portainer_settings else "" }}', + api_key: '{{ portainer_settings.api_key if portainer_settings else "" }}' + }); + + // Debug log the settings (without API key) + console.log('Portainer Settings:', { + url: portainerSettings.url, + hasApiKey: !!portainerSettings.api_key + }); + + // Check if any required field is missing + if (!portainerSettings.url || !portainerSettings.api_key) { + console.error('Missing Portainer settings:', portainerSettings); + return { + success: false, + error: 'Portainer settings are not configured. Please configure Portainer settings in the admin panel.' + }; + } + + const testResponse = await fetch('/api/admin/test-portainer-connection', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-Token': csrfToken + }, + body: JSON.stringify(portainerSettings) + }); + + if (!testResponse.ok) { + const error = await testResponse.json(); + console.error('Portainer connection error:', error); + return { + success: false, + error: error.error || 'Failed to connect to Portainer' + }; + } + + return { success: true }; + } catch (error) { + console.error('Error checking Portainer connection:', error); + return { + success: false, + error: error.message || 'Error checking Portainer connection' + }; + } +} + function updateStatus(step, message, type = 'info', details = '') { const statusElement = document.getElementById(`${step}Status`); const detailsElement = document.getElementById(`${step}Details`); @@ -508,7 +594,7 @@ async function createProxyHost(domains, port, sslCertificateId) { forward_host: '192.168.68.124', forward_port: parseInt(port), ssl_forced: true, - caching_enabled: false, + caching_enabled: true, block_exploits: true, allow_websocket_upgrade: true, http2_support: true,