# Copyright (c) 2019, JINGROW # For license information, please see license.txt from __future__ import annotations import ipaddress import jingrow from jcloude.agent import Agent from jcloude.jcloude.pagetype.agent_job.agent_job import handle_polled_job from jcloude.utils import log_error def check_ip_version(remote_addr: str): try: return ipaddress.ip_interface(remote_addr).version except ValueError: return None def validate_server_request(remote_addr: str): version = check_ip_version(remote_addr) if version == 4: server = jingrow.get_value("Server", {"ip": remote_addr}) elif version == 6: # Added this here, however fc does not support ipv6 remote_addr = f"{remote_addr.split('::')[0]}::" server = jingrow.get_value("Server", {"ipv6": remote_addr}) else: server = None return server def verify_job_id(server: str, job_id: str): return jingrow.get_value("Agent Job", {"server": server, "job_id": job_id}) def handle_job_updates(server: str, job_identifier: str): server_info = jingrow.get_value( "Server", {"name": server}, fieldname=[ "use_for_build", "use_agent_job_callbacks", ], as_dict=True, ) if not server_info.use_for_build: return current_user = jingrow.session.user try: jingrow.set_user("Administrator") job_id = job_identifier agent = Agent(server, "Server") jcloude_settings_use_callbacks = jingrow.get_value( "Jcloude Settings", fieldname=["use_agent_job_callbacks"] ) if not jcloude_settings_use_callbacks or not server_info.use_agent_job_callbacks: return # For some reason output is not returned when job returns from rq callback polled_job = agent.get_job_status(job_id) job = jingrow.get_value( "Agent Job", fieldname=[ "name", "job_id", "status", "callback_failure_count", "job_type", ], filters={"job_id": job_id}, as_dict=True, ) callback = jingrow.get_pg( { "pagetype": "Agent Job Callback", "job_name": job.job_type, "agent_job": polled_job["agent_job_id"], "status": polled_job["status"], } ) callback.insert() handle_polled_job(polled_job=polled_job, job=job) except Exception as e: log_error("Failed to process agent job callback", data=e) raise finally: jingrow.set_user(current_user) @jingrow.whitelist(allow_guest=True) def callback(job_id: str): """ Handle job updates sent from agent. This api should ideally only be hit from a build server. """ remote_addr = jingrow.request.environ["HTTP_X_FORWARDED_FOR"] server = validate_server_request(remote_addr) # Request origin not authorized to update job status. if not server: jingrow.throw("Not permitted", jingrow.ValidationError) job = verify_job_id(server, job_id) if not job: jingrow.throw("Invalid Job Id", jingrow.ValidationError) jingrow.enqueue(handle_job_updates, server=server, job_identifier=job_id)