|
28 | 28 | EC2InstanceType, |
29 | 29 | Resources, |
30 | 30 | ) |
| 31 | +from common_library.json_serialization import json_dumps |
31 | 32 | from deepdiff import DeepDiff |
32 | 33 | from faker import Faker |
33 | 34 | from fakeredis.aioredis import FakeRedis |
34 | 35 | from fastapi import FastAPI |
35 | | -from models_library.docker import DockerLabelKey, StandardSimcoreDockerLabels |
| 36 | +from models_library.docker import ( |
| 37 | + DockerGenericTag, |
| 38 | + DockerLabelKey, |
| 39 | + StandardSimcoreDockerLabels, |
| 40 | +) |
36 | 41 | from models_library.generated_models.docker_rest_api import Availability |
37 | 42 | from models_library.generated_models.docker_rest_api import Node as DockerNode |
38 | 43 | from models_library.generated_models.docker_rest_api import ( |
|
57 | 62 | ) |
58 | 63 | from settings_library.rabbit import RabbitSettings |
59 | 64 | from settings_library.ssm import SSMSettings |
| 65 | +from simcore_service_autoscaling.constants import PRE_PULLED_IMAGES_EC2_TAG_KEY |
60 | 66 | from simcore_service_autoscaling.core.application import create_app |
61 | 67 | from simcore_service_autoscaling.core.settings import ( |
62 | 68 | AUTOSCALING_ENV_PREFIX, |
|
71 | 77 | DaskTaskResources, |
72 | 78 | ) |
73 | 79 | from simcore_service_autoscaling.modules import auto_scaling_core |
| 80 | +from simcore_service_autoscaling.modules.auto_scaling_mode_dynamic import ( |
| 81 | + DynamicAutoscaling, |
| 82 | +) |
74 | 83 | from simcore_service_autoscaling.modules.docker import AutoscalingDocker |
75 | 84 | from simcore_service_autoscaling.modules.ec2 import SimcoreEC2API |
| 85 | +from simcore_service_autoscaling.utils.buffer_machines_pool_core import ( |
| 86 | + get_deactivated_buffer_ec2_tags, |
| 87 | +) |
76 | 88 | from simcore_service_autoscaling.utils.utils_docker import ( |
77 | 89 | _OSPARC_SERVICE_READY_LABEL_KEY, |
78 | 90 | _OSPARC_SERVICES_READY_DATETIME_LABEL_KEY, |
|
81 | 93 | from tenacity.retry import retry_if_exception_type |
82 | 94 | from tenacity.stop import stop_after_delay |
83 | 95 | from tenacity.wait import wait_fixed |
84 | | -from types_aiobotocore_ec2.literals import InstanceTypeType |
| 96 | +from types_aiobotocore_ec2 import EC2Client |
| 97 | +from types_aiobotocore_ec2.literals import InstanceStateNameType, InstanceTypeType |
| 98 | +from types_aiobotocore_ec2.type_defs import TagTypeDef |
85 | 99 |
|
86 | 100 | pytest_plugins = [ |
87 | 101 | "pytest_simcore.aws_server", |
@@ -1042,3 +1056,93 @@ async def _( |
1042 | 1056 | autospec=True, |
1043 | 1057 | side_effect=_, |
1044 | 1058 | ) |
| 1059 | + |
| 1060 | + |
| 1061 | +@pytest.fixture |
| 1062 | +async def create_buffer_machines( |
| 1063 | + ec2_client: EC2Client, |
| 1064 | + aws_ami_id: str, |
| 1065 | + app_settings: ApplicationSettings, |
| 1066 | + initialized_app: FastAPI, |
| 1067 | +) -> Callable[ |
| 1068 | + [int, InstanceTypeType, InstanceStateNameType, list[DockerGenericTag]], |
| 1069 | + Awaitable[list[str]], |
| 1070 | +]: |
| 1071 | + async def _do( |
| 1072 | + num: int, |
| 1073 | + instance_type: InstanceTypeType, |
| 1074 | + instance_state_name: InstanceStateNameType, |
| 1075 | + pre_pull_images: list[DockerGenericTag], |
| 1076 | + ) -> list[str]: |
| 1077 | + assert app_settings.AUTOSCALING_EC2_INSTANCES |
| 1078 | + |
| 1079 | + assert instance_state_name in [ |
| 1080 | + "running", |
| 1081 | + "stopped", |
| 1082 | + ], "only 'running' and 'stopped' are supported for testing" |
| 1083 | + |
| 1084 | + resource_tags: list[TagTypeDef] = [ |
| 1085 | + {"Key": tag_key, "Value": tag_value} |
| 1086 | + for tag_key, tag_value in get_deactivated_buffer_ec2_tags( |
| 1087 | + initialized_app, DynamicAutoscaling() |
| 1088 | + ).items() |
| 1089 | + ] |
| 1090 | + if pre_pull_images is not None and instance_state_name == "stopped": |
| 1091 | + resource_tags.append( |
| 1092 | + { |
| 1093 | + "Key": PRE_PULLED_IMAGES_EC2_TAG_KEY, |
| 1094 | + "Value": f"{json_dumps(pre_pull_images)}", |
| 1095 | + } |
| 1096 | + ) |
| 1097 | + with log_context( |
| 1098 | + logging.INFO, f"creating {num} buffer machines of {instance_type}" |
| 1099 | + ): |
| 1100 | + instances = await ec2_client.run_instances( |
| 1101 | + ImageId=aws_ami_id, |
| 1102 | + MaxCount=num, |
| 1103 | + MinCount=num, |
| 1104 | + InstanceType=instance_type, |
| 1105 | + KeyName=app_settings.AUTOSCALING_EC2_INSTANCES.EC2_INSTANCES_KEY_NAME, |
| 1106 | + SecurityGroupIds=app_settings.AUTOSCALING_EC2_INSTANCES.EC2_INSTANCES_SECURITY_GROUP_IDS, |
| 1107 | + SubnetId=app_settings.AUTOSCALING_EC2_INSTANCES.EC2_INSTANCES_SUBNET_ID, |
| 1108 | + IamInstanceProfile={ |
| 1109 | + "Arn": app_settings.AUTOSCALING_EC2_INSTANCES.EC2_INSTANCES_ATTACHED_IAM_PROFILE |
| 1110 | + }, |
| 1111 | + TagSpecifications=[ |
| 1112 | + {"ResourceType": "instance", "Tags": resource_tags}, |
| 1113 | + {"ResourceType": "volume", "Tags": resource_tags}, |
| 1114 | + {"ResourceType": "network-interface", "Tags": resource_tags}, |
| 1115 | + ], |
| 1116 | + UserData="echo 'I am pytest'", |
| 1117 | + ) |
| 1118 | + instance_ids = [ |
| 1119 | + i["InstanceId"] for i in instances["Instances"] if "InstanceId" in i |
| 1120 | + ] |
| 1121 | + |
| 1122 | + waiter = ec2_client.get_waiter("instance_exists") |
| 1123 | + await waiter.wait(InstanceIds=instance_ids) |
| 1124 | + instances = await ec2_client.describe_instances(InstanceIds=instance_ids) |
| 1125 | + assert "Reservations" in instances |
| 1126 | + assert instances["Reservations"] |
| 1127 | + assert "Instances" in instances["Reservations"][0] |
| 1128 | + assert len(instances["Reservations"][0]["Instances"]) == num |
| 1129 | + for instance in instances["Reservations"][0]["Instances"]: |
| 1130 | + assert "State" in instance |
| 1131 | + assert "Name" in instance["State"] |
| 1132 | + assert instance["State"]["Name"] == "running" |
| 1133 | + |
| 1134 | + if instance_state_name == "stopped": |
| 1135 | + await ec2_client.stop_instances(InstanceIds=instance_ids) |
| 1136 | + instances = await ec2_client.describe_instances(InstanceIds=instance_ids) |
| 1137 | + assert "Reservations" in instances |
| 1138 | + assert instances["Reservations"] |
| 1139 | + assert "Instances" in instances["Reservations"][0] |
| 1140 | + assert len(instances["Reservations"][0]["Instances"]) == num |
| 1141 | + for instance in instances["Reservations"][0]["Instances"]: |
| 1142 | + assert "State" in instance |
| 1143 | + assert "Name" in instance["State"] |
| 1144 | + assert instance["State"]["Name"] == "stopped" |
| 1145 | + |
| 1146 | + return instance_ids |
| 1147 | + |
| 1148 | + return _do |
0 commit comments