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 (
@@ -43,6 +48,7 @@ async def assert_autoscaled_dynamic_ec2_instances(
4348 expected_additional_tag_keys : list [str ],
4449 instance_filters : Sequence [FilterTypeDef ] | None ,
4550 expected_user_data : list [str ] | None = None ,
51+ check_reservation_index : int | None = None ,
4652) -> list [InstanceTypeDef ]:
4753 if expected_user_data is None :
4854 expected_user_data = ["docker swarm join" ]
@@ -59,6 +65,7 @@ async def assert_autoscaled_dynamic_ec2_instances(
5965 ],
6066 expected_user_data = expected_user_data ,
6167 instance_filters = instance_filters ,
68+ check_reservation_index = check_reservation_index ,
6269 )
6370
6471
@@ -72,6 +79,7 @@ async def assert_autoscaled_dynamic_warm_pools_ec2_instances(
7279 expected_additional_tag_keys : list [str ],
7380 expected_pre_pulled_images : list [DockerGenericTag ] | None ,
7481 instance_filters : Sequence [FilterTypeDef ] | None ,
82+ check_reservation_index : int | None = None ,
7583) -> list [InstanceTypeDef ]:
7684 return await assert_ec2_instances (
7785 ec2_client ,
@@ -88,9 +96,80 @@ async def assert_autoscaled_dynamic_warm_pools_ec2_instances(
8896 expected_pre_pulled_images = expected_pre_pulled_images ,
8997 expected_user_data = [],
9098 instance_filters = instance_filters ,
99+ check_reservation_index = check_reservation_index ,
91100 )
92101
93102
103+ async def _assert_reservation (
104+ ec2_client : EC2Client ,
105+ reservation : ReservationTypeDef ,
106+ * ,
107+ expected_num_instances : int ,
108+ expected_instance_type : InstanceTypeType ,
109+ expected_instance_state : InstanceStateNameType ,
110+ expected_instance_tag_keys : list [str ],
111+ expected_user_data : list [str ],
112+ expected_pre_pulled_images : list [DockerGenericTag ] | None ,
113+ ) -> list [InstanceTypeDef ]:
114+ list_instances : list [InstanceTypeDef ] = []
115+ assert "Instances" in reservation
116+ assert (
117+ len (reservation ["Instances" ]) == expected_num_instances
118+ ), f"expected { expected_num_instances } , found { len (reservation ['Instances' ])} "
119+ for instance in reservation ["Instances" ]:
120+ assert "InstanceType" in instance
121+ assert instance ["InstanceType" ] == expected_instance_type
122+ assert "Tags" in instance
123+ assert instance ["Tags" ]
124+ expected_tag_keys = {
125+ * expected_instance_tag_keys ,
126+ "io.simcore.autoscaling.version" ,
127+ "Name" ,
128+ }
129+ instance_tag_keys = {tag ["Key" ] for tag in instance ["Tags" ] if "Key" in tag }
130+ assert instance_tag_keys == expected_tag_keys
131+
132+ if expected_pre_pulled_images is None :
133+ assert "io.simcore.autoscaling.pre_pulled_images" not in instance_tag_keys
134+ else :
135+ assert "io.simcore.autoscaling.pre_pulled_images" in instance_tag_keys
136+
137+ def _by_pre_pull_image (ec2_tag : TagTypeDef ) -> bool :
138+ assert "Key" in ec2_tag
139+ return ec2_tag ["Key" ] == "io.simcore.autoscaling.pre_pulled_images"
140+
141+ instance_pre_pulled_images_aws_tag = next (
142+ iter (filter (_by_pre_pull_image , instance ["Tags" ]))
143+ )
144+ assert "Value" in instance_pre_pulled_images_aws_tag
145+ assert (
146+ instance_pre_pulled_images_aws_tag ["Value" ]
147+ == f"{ json_dumps (expected_pre_pulled_images )} "
148+ )
149+
150+ assert "PrivateDnsName" in instance
151+ instance_private_dns_name = instance ["PrivateDnsName" ]
152+ if expected_instance_state not in ["terminated" ]:
153+ # NOTE: moto behaves here differently than AWS by still returning an IP which does not really make sense
154+ assert instance_private_dns_name .endswith (".ec2.internal" )
155+ assert "State" in instance
156+ state = instance ["State" ]
157+ assert "Name" in state
158+ assert state ["Name" ] == expected_instance_state
159+
160+ assert "InstanceId" in instance
161+ user_data = await ec2_client .describe_instance_attribute (
162+ Attribute = "userData" , InstanceId = instance ["InstanceId" ]
163+ )
164+ assert "UserData" in user_data
165+ assert "Value" in user_data ["UserData" ]
166+ user_data = base64 .b64decode (user_data ["UserData" ]["Value" ]).decode ()
167+ for user_data_string in expected_user_data :
168+ assert user_data .count (user_data_string ) == 1
169+ list_instances .append (instance )
170+ return list_instances
171+
172+
94173async def assert_ec2_instances (
95174 ec2_client : EC2Client ,
96175 * ,
@@ -102,66 +181,35 @@ async def assert_ec2_instances(
102181 expected_user_data : list [str ],
103182 expected_pre_pulled_images : list [DockerGenericTag ] | None = None ,
104183 instance_filters : Sequence [FilterTypeDef ] | None = None ,
184+ check_reservation_index : int | None = None ,
105185) -> list [InstanceTypeDef ]:
106- list_instances : list [InstanceTypeDef ] = []
107186 all_instances = await ec2_client .describe_instances (Filters = instance_filters or [])
108187 assert len (all_instances ["Reservations" ]) == expected_num_reservations
188+ if check_reservation_index is not None :
189+ assert check_reservation_index < len (all_instances ["Reservations" ])
190+ reservation = all_instances ["Reservations" ][check_reservation_index ]
191+ return await _assert_reservation (
192+ ec2_client ,
193+ reservation ,
194+ expected_num_instances = expected_num_instances ,
195+ expected_instance_type = expected_instance_type ,
196+ expected_instance_state = expected_instance_state ,
197+ expected_instance_tag_keys = expected_instance_tag_keys ,
198+ expected_user_data = expected_user_data ,
199+ expected_pre_pulled_images = expected_pre_pulled_images ,
200+ )
201+ list_instances : list [InstanceTypeDef ] = []
109202 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" ]
203+ list_instances .extend (
204+ await _assert_reservation (
205+ ec2_client ,
206+ reservation ,
207+ expected_num_instances = expected_num_instances ,
208+ expected_instance_type = expected_instance_type ,
209+ expected_instance_state = expected_instance_state ,
210+ expected_instance_tag_keys = expected_instance_tag_keys ,
211+ expected_user_data = expected_user_data ,
212+ expected_pre_pulled_images = expected_pre_pulled_images ,
160213 )
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 )
214+ )
167215 return list_instances
0 commit comments