software packages and deploying

This commit is contained in:
2026-09-10 21:54:55 +02:00
parent 0fb18ae4f7
commit 4567df7ebb
73 changed files with 3088 additions and 6 deletions
+81 -1
View File
@@ -16,6 +16,7 @@ from .config import load_config
from .database import SessionLocal
from .models import Asset, SoftwareJob, JobEvent, JobDefinition
from .job_state import sync_asset_job_state
from .software_packages import build_deployment_user_script, load_package_manifest, package_payload_files
_DISPATCH_SLOT_LOCK = threading.Lock()
@@ -376,6 +377,22 @@ def _definition_execution_artifacts(db, platform: str, callback_url: str, job_id
def _job_execution_artifacts(db, platform: str, callback_url: str, job_id: int, asset: Asset, definition_id: int | None = None) -> tuple[str, str, bool]:
job = db.get(SoftwareJob, job_id)
if job and job.job_type == 'software_deployment':
if platform != 'windows':
raise RuntimeError('Softwarepakete werden derzeit nur fuer Windows-Assets unterstuetzt.')
manifest = load_package_manifest(job.package_id)
user_script = build_deployment_user_script(manifest, job.action)
script = _runtime_wrap_script('powershell', user_script)
script = _replace_job_placeholders(
script,
asset,
callback_url,
job_id,
job.parameters if isinstance(job.parameters, dict) else {},
)
return script, 'powershell', True
configured=_definition_execution_artifacts(db,platform,callback_url,job_id,asset,definition_id)
if configured[0]:
return configured
@@ -383,7 +400,7 @@ def _job_execution_artifacts(db, platform: str, callback_url: str, job_id: int,
return windows_inventory(callback_url, job_id), 'powershell', True
if platform in {'linux','macos'}:
return unix_python_payload(platform, callback_url, job_id), 'python', True
raise HTTPException(400, 'Für dieses Betriebssystem ist kein sicherer MeshCtrl-Handler verfügbar.')
raise HTTPException(400, 'Fuer dieses Betriebssystem ist kein sicherer MeshCtrl-Handler verfuegbar.')
def _script_extension(interpreter: str) -> str:
@@ -551,6 +568,12 @@ def execute_job(job_id: int, token: str, callback_base: str) -> None:
if not password: raise RuntimeError(f'MeshCentral-Passwortvariable {password_env} ist nicht gesetzt.')
timeout=max(30,int(cfg.get('timeout_seconds') or 600))
job_parameters = job.parameters if isinstance(job.parameters, dict) else {}
try:
execution_timeout_seconds = int(job_parameters.get('_execution_timeout_seconds') or 0)
except (TypeError, ValueError):
execution_timeout_seconds = 0
if execution_timeout_seconds > 0:
timeout = max(timeout, min(execution_timeout_seconds + 180, 86400))
diagnostics=[
'--- File dispatcher diagnostics ---',
f'Dispatch interval configured: {dispatch_delay_seconds:g} seconds',
@@ -575,6 +598,14 @@ def execute_job(job_id: int, token: str, callback_base: str) -> None:
f'Definition interpreter: {job_parameters.get("definition_interpreter") or interpreter}',
f'Definition source type: {job_parameters.get("definition_source_type") or "-"}',
]
elif job.job_type == 'software_deployment':
diagnostics += [
f'Deployment action: {job.action}',
f'Deployment product: {job_parameters.get("product_name") or "-"}',
f'Deployment version: {job_parameters.get("product_version") or "-"}',
f'Installer type: {job_parameters.get("installer_type") or "-"}',
f'Execution timeout: {execution_timeout_seconds or timeout} seconds',
]
if upload_required:
suffix=_script_extension(interpreter)
@@ -607,6 +638,55 @@ def execute_job(job_id: int, token: str, callback_base: str) -> None:
combined='\n\n'.join(((item.stdout or '')+'\n'+(item.stderr or '')).strip() for item in upload_results if ((item.stdout or '')+(item.stderr or '')).strip())
raise RuntimeError(f'MeshCentral-Dateiupload fehlgeschlagen nach 2 Versuchen: {combined.strip()}')
if job.job_type == 'software_deployment':
payload_files = package_payload_files(job.package_id, job.action)
diagnostics += [f'Package payload files: {len(payload_files)}']
for package_file in payload_files:
remote_package_file = remote_dir + '\\' + package_file.name
package_uploads = []
package_uploaded = _upload_script(cfg, asset, password, str(package_file), remote_dir, timeout)
package_uploads.append(package_uploaded)
diagnostics += [
f'--- Package upload {package_file.name} attempt 1 stdout ---', package_uploaded.stdout or '',
f'--- Package upload {package_file.name} attempt 1 stderr ---', package_uploaded.stderr or '',
f'Package upload {package_file.name} attempt 1 return code: {package_uploaded.returncode}',
]
package_text = (package_uploaded.stdout or '') + '\n' + (package_uploaded.stderr or '')
package_ok = package_uploaded.returncode == 0 and 'Upload done' in package_text and 'Upload error' not in package_text
if not package_ok:
package_repair = _prepare_remote_directory(
cfg,
asset,
password,
job.platform,
remote_dir,
min(timeout, 120),
remote_package_file,
)
diagnostics += [
f'--- Package upload {package_file.name} repair stdout ---', package_repair.stdout or '',
f'--- Package upload {package_file.name} repair stderr ---', package_repair.stderr or '',
f'Package upload {package_file.name} repair return code: {package_repair.returncode}',
]
package_uploaded = _upload_script(cfg, asset, password, str(package_file), remote_dir, timeout)
package_uploads.append(package_uploaded)
diagnostics += [
f'--- Package upload {package_file.name} attempt 2 stdout ---', package_uploaded.stdout or '',
f'--- Package upload {package_file.name} attempt 2 stderr ---', package_uploaded.stderr or '',
f'Package upload {package_file.name} attempt 2 return code: {package_uploaded.returncode}',
]
package_text = (package_uploaded.stdout or '') + '\n' + (package_uploaded.stderr or '')
package_ok = package_uploaded.returncode == 0 and 'Upload done' in package_text and 'Upload error' not in package_text
if not package_ok:
combined = '\n\n'.join(
((item.stdout or '') + '\n' + (item.stderr or '')).strip()
for item in package_uploads
if ((item.stdout or '') + (item.stderr or '')).strip()
)
raise RuntimeError(
f'MeshCentral-Paketdateiupload fehlgeschlagen fuer {package_file.name}: {combined.strip()}'
)
diagnostics += [f'Remote execution shell: {launch_shell}',f'Remote execution command: {launch_command}',f'MeshCtrl PowerShell mode: False']
started=datetime.utcnow()
result=_launch_uploaded_script(cfg,asset,password,job.platform,interpreter,remote_file,timeout)