updated player deployment for digiserver

This commit is contained in:
ske087
2026-06-07 23:40:50 +03:00
parent b97372f74d
commit f674330b93
30 changed files with 3459 additions and 201 deletions
+128
View File
@@ -3,6 +3,7 @@ from flask import Blueprint, request, jsonify, current_app
from functools import wraps
from datetime import datetime, timedelta
import secrets
import hashlib
import bcrypt
from typing import Optional, Dict, List
@@ -860,6 +861,133 @@ def receive_edited_media():
return jsonify({'error': 'Internal server error'}), 500
# ──────────────────────────────────────────────────────────────────────────────
# SSH/Deployment Endpoints - For player provisioning and code deployment
# ──────────────────────────────────────────────────────────────────────────────
@api_bp.route('/deploy/test-ssh', methods=['POST'])
@rate_limit(max_requests=30, window=60)
def test_ssh_connection():
"""Test SSH connection to a remote host.
Request JSON:
hostname: Target hostname or IP (required)
username: SSH username (required)
password: SSH password (required)
port: SSH port (default: 22)
Returns:
JSON with connection test result
"""
try:
from app.utils.ssh_deploy import test_ssh_connection as test_ssh
data = request.get_json()
if not data:
return jsonify({'error': 'No data provided'}), 400
hostname = data.get('hostname', '').strip()
username = data.get('username', '').strip()
password = data.get('password', '').strip()
port = data.get('port', 22)
# Validation
if not hostname or not username or not password:
return jsonify({'error': 'hostname, username, and password are required'}), 400
# Test connection
result = test_ssh(hostname, username, password, port)
log_action('info', f'SSH test for {username}@{hostname}: {result["message"]}')
return jsonify(result), 200 if result['success'] else 400
except Exception as e:
log_action('error', f'Error testing SSH connection: {str(e)}')
return jsonify({
'success': False,
'error': str(e),
'message': f'SSH test error: {str(e)}'
}), 500
@api_bp.route('/deploy/player', methods=['POST'])
@rate_limit(max_requests=20, window=60)
def deploy_player():
"""Deploy player code to a remote host via SSH.
Request JSON:
hostname: Target hostname or IP (required)
username: SSH username (required)
password: SSH password (required)
player_name: Name for the player instance (required)
port: SSH port (default: 22)
deploy_path: Deployment path on remote host (default: /home/[user]/kiwy-signage)
repo_url: Git repository URL (default: official Kiwy-Signage repo)
Returns:
JSON with deployment status and step details
"""
try:
from app.utils.ssh_deploy import deploy_player_to_host
data = request.get_json()
if not data:
return jsonify({'error': 'No data provided'}), 400
hostname = data.get('hostname', '').strip()
username = data.get('username', '').strip()
password = data.get('password', '').strip()
player_name = data.get('player_name', '').strip()
port = data.get('port', 22)
deploy_path = data.get('deploy_path', None) # Will default to /home/[user]/kiwy-signage
repo_url = data.get('repo_url', 'https://gitea.moto-adv.com/ske087/Kiwy-Signage.git').strip()
# Validation
if not hostname or not username or not password:
return jsonify({'error': 'hostname, username, and password are required'}), 400
if not player_name:
return jsonify({'error': 'player_name is required'}), 400
# Get server URL for player configuration
# Use X-Forwarded-Proto and X-Forwarded-Host for proxy, fall back to request host
scheme = request.headers.get('X-Forwarded-Proto', request.scheme)
host = request.headers.get('X-Forwarded-Host', request.host)
server_url = f"{scheme}://{host}/digiserver"
# Get or generate API key for the player
# For now, use a hash of player_name and hostname as a simple key
import hashlib
api_key = hashlib.sha256(f'{player_name}:{hostname}'.encode()).hexdigest()[:32]
# Execute deployment
result = deploy_player_to_host(
hostname=hostname,
username=username,
password=password,
player_name=player_name,
repo_url=repo_url,
deploy_path=deploy_path, # Will use /home/[user]/kiwy-signage if None
port=port,
server_url=server_url,
server_api_key=api_key
)
log_action('info', f'Player deployment for {player_name} on {hostname}: success={result["success"]}')
return jsonify(result), 200 if result['success'] else 400
except Exception as e:
log_action('error', f'Error deploying player: {str(e)}')
return jsonify({
'success': False,
'error': str(e),
'message': f'Deployment error: {str(e)}',
'steps': []
}), 500
@api_bp.errorhandler(404)
def api_not_found(error):
"""Handle 404 errors in API."""