software packages and deploying
This commit is contained in:
+81
-1
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user