55from models_library .docker import DockerGenericTag
66from types_aiobotocore_ec2 import EC2Client
77from types_aiobotocore_ec2 .literals import InstanceStateNameType , InstanceTypeType
8- from types_aiobotocore_ec2 .type_defs import FilterTypeDef , InstanceTypeDef , TagTypeDef
8+ from types_aiobotocore_ec2 .type_defs import (
9+ FilterTypeDef ,
10+ InstanceTypeDef ,
11+ ReservationTypeDef ,
12+ TagTypeDef ,
13+ )
914
1015
1116async def assert_autoscaled_computational_ec2_instances (
@@ -72,6 +77,7 @@ async def assert_autoscaled_dynamic_warm_pools_ec2_instances(
7277 expected_additional_tag_keys : list [str ],
7378 expected_pre_pulled_images : list [DockerGenericTag ] | None ,
7479 instance_filters : Sequence [FilterTypeDef ] | None ,
80+ check_reservation_index : int | None = None ,
7581) -> list [InstanceTypeDef ]:
7682 return await assert_ec2_instances (
7783 ec2_client ,
@@ -88,9 +94,80 @@ async def assert_autoscaled_dynamic_warm_pools_ec2_instances(
8894 expected_pre_pulled_images = expected_pre_pulled_images ,
8995 expected_user_data = [],
9096 instance_filters = instance_filters ,
97+ check_reservation_index = check_reservation_index ,
9198 )
9299
93100
101+ async def _assert_reservation (
102+ ec2_client : EC2Client ,
103+ reservation : ReservationTypeDef ,
104+ * ,
105+ expected_num_instances : int ,
106+ expected_instance_type : InstanceTypeType ,
107+ expected_instance_state : InstanceStateNameType ,
108+ expected_instance_tag_keys : list [str ],
109+ expected_user_data : list [str ],
110+ expected_pre_pulled_images : list [DockerGenericTag ] | None ,
111+ ) -> list [InstanceTypeDef ]:
112+ list_instances : list [InstanceTypeDef ] = []
113+ assert "Instances" in reservation
114+ assert (
115+ len (reservation ["Instances" ]) == expected_num_instances
116+ ), f"expected { expected_num_instances } , found { len (reservation ['Instances' ])} "
117+ for instance in reservation ["Instances" ]:
118+ assert "InstanceType" in instance
119+ assert instance ["InstanceType" ] == expected_instance_type
120+ assert "Tags" in instance
121+ assert instance ["Tags" ]
122+ expected_tag_keys = {
123+ * expected_instance_tag_keys ,
124+ "io.simcore.autoscaling.version" ,
125+ "Name" ,
126+ }
127+ instance_tag_keys = {tag ["Key" ] for tag in instance ["Tags" ] if "Key" in tag }
128+ assert instance_tag_keys == expected_tag_keys
129+
130+ if expected_pre_pulled_images is None :
131+ assert "io.simcore.autoscaling.pre_pulled_images" not in instance_tag_keys
132+ else :
133+ assert "io.simcore.autoscaling.pre_pulled_images" in instance_tag_keys
134+
135+ def _by_pre_pull_image (ec2_tag : TagTypeDef ) -> bool :
136+ assert "Key" in ec2_tag
137+ return ec2_tag ["Key" ] == "io.simcore.autoscaling.pre_pulled_images"
138+
139+ instance_pre_pulled_images_aws_tag = next (
140+ iter (filter (_by_pre_pull_image , instance ["Tags" ]))
141+ )
142+ assert "Value" in instance_pre_pulled_images_aws_tag
143+ assert (
144+ instance_pre_pulled_images_aws_tag ["Value" ]
145+ == f"{ json_dumps (expected_pre_pulled_images )} "
146+ )
147+
148+ assert "PrivateDnsName" in instance
149+ instance_private_dns_name = instance ["PrivateDnsName" ]
150+ if expected_instance_state not in ["terminated" ]:
151+ # NOTE: moto behaves here differently than AWS by still returning an IP which does not really make sense
152+ assert instance_private_dns_name .endswith (".ec2.internal" )
153+ assert "State" in instance
154+ state = instance ["State" ]
155+ assert "Name" in state
156+ assert state ["Name" ] == expected_instance_state
157+
158+ assert "InstanceId" in instance
159+ user_data = await ec2_client .describe_instance_attribute (
160+ Attribute = "userData" , InstanceId = instance ["InstanceId" ]
161+ )
162+ assert "UserData" in user_data
163+ assert "Value" in user_data ["UserData" ]
164+ user_data = base64 .b64decode (user_data ["UserData" ]["Value" ]).decode ()
165+ for user_data_string in expected_user_data :
166+ assert user_data .count (user_data_string ) == 1
167+ list_instances .append (instance )
168+ return list_instances
169+
170+
94171async def assert_ec2_instances (
95172 ec2_client : EC2Client ,
96173 * ,
@@ -102,66 +179,35 @@ async def assert_ec2_instances(
102179 expected_user_data : list [str ],
103180 expected_pre_pulled_images : list [DockerGenericTag ] | None = None ,
104181 instance_filters : Sequence [FilterTypeDef ] | None = None ,
182+ check_reservation_index : int | None = None ,
105183) -> list [InstanceTypeDef ]:
106- list_instances : list [InstanceTypeDef ] = []
107184 all_instances = await ec2_client .describe_instances (Filters = instance_filters or [])
108185 assert len (all_instances ["Reservations" ]) == expected_num_reservations
186+ if check_reservation_index is not None :
187+ assert check_reservation_index < len (all_instances ["Reservations" ])
188+ reservation = all_instances ["Reservations" ][check_reservation_index ]
189+ return await _assert_reservation (
190+ ec2_client ,
191+ reservation ,
192+ expected_num_instances = expected_num_instances ,
193+ expected_instance_type = expected_instance_type ,
194+ expected_instance_state = expected_instance_state ,
195+ expected_instance_tag_keys = expected_instance_tag_keys ,
196+ expected_user_data = expected_user_data ,
197+ expected_pre_pulled_images = expected_pre_pulled_images ,
198+ )
199+ list_instances : list [InstanceTypeDef ] = []
109200 for reservation in all_instances ["Reservations" ]:
110- assert "Instances" in reservation
111- assert (
112- len (reservation ["Instances" ]) == expected_num_instances
113- ), f"expected { expected_num_instances } , found { len (reservation ['Instances' ])} "
114- for instance in reservation ["Instances" ]:
115- assert "InstanceType" in instance
116- assert instance ["InstanceType" ] == expected_instance_type
117- assert "Tags" in instance
118- assert instance ["Tags" ]
119- expected_tag_keys = {
120- * expected_instance_tag_keys ,
121- "io.simcore.autoscaling.version" ,
122- "Name" ,
123- }
124- instance_tag_keys = {tag ["Key" ] for tag in instance ["Tags" ] if "Key" in tag }
125- assert instance_tag_keys == expected_tag_keys
126-
127- if expected_pre_pulled_images is None :
128- assert (
129- "io.simcore.autoscaling.pre_pulled_images" not in instance_tag_keys
130- )
131- else :
132- assert "io.simcore.autoscaling.pre_pulled_images" in instance_tag_keys
133-
134- def _by_pre_pull_image (ec2_tag : TagTypeDef ) -> bool :
135- assert "Key" in ec2_tag
136- return ec2_tag ["Key" ] == "io.simcore.autoscaling.pre_pulled_images"
137-
138- instance_pre_pulled_images_aws_tag = next (
139- iter (filter (_by_pre_pull_image , instance ["Tags" ]))
140- )
141- assert "Value" in instance_pre_pulled_images_aws_tag
142- assert (
143- instance_pre_pulled_images_aws_tag ["Value" ]
144- == f"{ json_dumps (expected_pre_pulled_images )} "
145- )
146-
147- assert "PrivateDnsName" in instance
148- instance_private_dns_name = instance ["PrivateDnsName" ]
149- if expected_instance_state not in ["terminated" ]:
150- # NOTE: moto behaves here differently than AWS by still returning an IP which does not really make sense
151- assert instance_private_dns_name .endswith (".ec2.internal" )
152- assert "State" in instance
153- state = instance ["State" ]
154- assert "Name" in state
155- assert state ["Name" ] == expected_instance_state
156-
157- assert "InstanceId" in instance
158- user_data = await ec2_client .describe_instance_attribute (
159- Attribute = "userData" , InstanceId = instance ["InstanceId" ]
201+ list_instances .extend (
202+ await _assert_reservation (
203+ ec2_client ,
204+ reservation ,
205+ expected_num_instances = expected_num_instances ,
206+ expected_instance_type = expected_instance_type ,
207+ expected_instance_state = expected_instance_state ,
208+ expected_instance_tag_keys = expected_instance_tag_keys ,
209+ expected_user_data = expected_user_data ,
210+ expected_pre_pulled_images = expected_pre_pulled_images ,
160211 )
161- assert "UserData" in user_data
162- assert "Value" in user_data ["UserData" ]
163- user_data = base64 .b64decode (user_data ["UserData" ]["Value" ]).decode ()
164- for user_data_string in expected_user_data :
165- assert user_data .count (user_data_string ) == 1
166- list_instances .append (instance )
212+ )
167213 return list_instances
0 commit comments