diff --git a/apps/challenges/aws_utils.py b/apps/challenges/aws_utils.py index 716e858594..7d5e581a1c 100644 --- a/apps/challenges/aws_utils.py +++ b/apps/challenges/aws_utils.py @@ -524,9 +524,38 @@ def stop_ec2_instance(challenge): } +def describe_ec2_instance(challenge): + """ + Describe the EC2 instance associated with a challenge. + + Args: + challenge (Challenge): The challenge for which the EC2 instance description is needed. + + Returns: + dict: A dictionary containing the status and message of the operation. + """ + target_instance_id = challenge.ec2_instance_id + try: + ec2 = get_boto3_client("ec2", aws_keys) + response = ec2.describe_instances(InstanceIds=[target_instance_id]) + + instances = [ + instance + for reservation in response["Reservations"] + for instance in reservation["Instances"] + ] + instance = instances[0] + return {"message": instance} + except Exception as e: + logger.exception(e) + return { + "error": e.response, + } + + def start_ec2_instance(challenge): """ - Start the EC2 instance instance associated with a challenge. + Start the EC2 instance associated with a challenge. Args: challenge (Challenge): The challenge for which the EC2 instance needs to be started. diff --git a/apps/challenges/urls.py b/apps/challenges/urls.py index 1c15bdd31b..cb1e4f7d55 100644 --- a/apps/challenges/urls.py +++ b/apps/challenges/urls.py @@ -201,6 +201,11 @@ views.manage_ec2_instance, name="manage_ec2_instance", ), + url( + r"^(?P[0-9]+)/get_ec2_instance_details/$", + views.get_ec2_instance_details, + name="get_ec2_instance_details", + ), url( r"^phases/(?P[0-9]+)/get_annotation_file_presigned_url/$", views.get_annotation_file_presigned_url, diff --git a/apps/challenges/views.py b/apps/challenges/views.py index 5b292e7e2f..429dbd862c 100644 --- a/apps/challenges/views.py +++ b/apps/challenges/views.py @@ -137,6 +137,7 @@ restart_workers, start_ec2_instance, stop_ec2_instance, + describe_ec2_instance, get_logs_from_cloudwatch, get_log_group_name, scale_resources, @@ -3346,6 +3347,48 @@ def manage_worker(request, challenge_pk, action): return Response(response_data, status=status.HTTP_200_OK) +@api_view(["GET"]) +@throttle_classes([UserRateThrottle]) +@permission_classes((permissions.IsAuthenticated, HasVerifiedEmail)) +@authentication_classes((JWTAuthentication, ExpiringTokenAuthentication)) +def get_ec2_instance_details(request, challenge_pk): + if not request.user.is_staff: + response_data = { + "error": "Sorry, you are not authorized for access worker operations." + } + return Response(response_data, status=status.HTTP_400_BAD_REQUEST) + + challenge = get_challenge_model(challenge_pk) + + if not challenge.uses_ec2_worker: + response_data = { + "error": "Challenge does not use EC2 worker instance." + } + return Response(response_data, status=status.HTTP_400_BAD_REQUEST) + + response = describe_ec2_instance(challenge) + if response: + if "error" not in response: + status_code = status.HTTP_200_OK + response_data = { + "message": response["message"], + "action": "Success", + } + else: + status_code = status.HTTP_400_BAD_REQUEST + response_data = { + "message": response["error"], + "action": "Failure", + } + else: + status_code = status.HTTP_500_INTERNAL_SERVER_ERROR + response_data = { + "message": "No Response", + "action": "Failure", + } + return Response(response_data, status=status_code) + + @api_view(["PUT"]) @throttle_classes([UserRateThrottle]) @permission_classes((permissions.IsAuthenticated, HasVerifiedEmail))