@@ -94,22 +94,20 @@ def list_task_def_family(self) -> dict:
9494 @Command ()
9595 def find_def (self ,
9696 name : args .NAME ):
97- """Find a ECS task definition by name.
97+ """Find the latest version of an ECS task definition by family name.
9898
9999 Args:
100- name: The name of the ECS task definition to find.
100+ name: The family name of the ECS task definition to find.
101101
102102 Returns:
103- task_definition: The ECS task definition object .
103+ task_definition: The latest version of that ECS task definition in the family .
104104
105105 Raises:
106106 DuploError: If the ECS task definition could not be found.
107107 """
108108 name = self .prefixed_name (name )
109- svcFam = self .find_service_family (name )
110- family = svcFam ["TaskDefFamily" ]
111- tdf = self .find_task_def_family (family )
112- arn = tdf ["VersionArns" ][- 1 ]
109+ task_definition_family = self .find_task_def_family (name )
110+ arn = task_definition_family ["VersionArns" ][- 1 ]
113111 return self .find_def_by_arn (arn )
114112
115113 @Command ()
@@ -199,14 +197,16 @@ def update_image(self,
199197 container_image : args .CONTAINER_IMAGE = None ) -> dict :
200198 """Update Image
201199
202- Update the image for an ECS task definition and service container if one exists.
200+ Creates a new task definition version cloning the latest existing version in the family except for image arguments
201+
202+ If task family is used by an ECS service, method also updates the service to use that newly created definition version
203203
204204 Usage: Basic CLI Use
205205 ```sh
206- duploctl ecs update_image <service- name> <service -image>
206+ duploctl ecs update_image <task-definition-family- name> <new -image>
207207 ```
208208 ```sh
209- duploctl ecs update_image <service- name> --container-image <container-name> <container-image>
209+ duploctl ecs update_image <task-definition-family- name> --container-image <container-name> <new- container-image>
210210 ```
211211
212212 Example: Update image and wait
@@ -217,15 +217,15 @@ def update_image(self,
217217 ```
218218
219219 Args:
220- name: The name of the ECS service to update.
220+ name: The name of the ECS task definition family to update.
221221 image: The new image to use for the container.
222222 container-image: A list of key-value pairs to set as container image.
223223
224224 Returns:
225225 dict: A dictionary containing a message about the update status.
226226
227227 Raises:
228- DuploError: If the ECS service could not be updated.
228+ DuploError: If the ECS task definition family could not be updated.
229229 """
230230 name = self .prefixed_name (name )
231231 tdf = self .find_def (name )
@@ -255,12 +255,22 @@ def update_image(self,
255255 }
256256
257257 def __ecs_task_def_body (self , task_def ):
258- containers = [
259- self .__ecs_container_update_body (c )
260- for c in task_def .get ("ContainerDefinitions" , [])
261- ]
258+ def sanitize_container_definition (containerDefinition ):
259+ if containerDefinition .get ("Cpu" ) == 0 :
260+ del containerDefinition ["Cpu" ]
261+ if containerDefinition .get ("Memory" ) == 0 :
262+ del containerDefinition ["Memory" ]
263+ if containerDefinition .get ("MemoryReservation" ) == 0 :
264+ del containerDefinition ["MemoryReservation" ]
265+ if containerDefinition .get ("StartTimeout" ) == 0 :
266+ del containerDefinition ["StartTimeout" ]
267+ if containerDefinition .get ("StopTimeout" ) == 0 :
268+ del containerDefinition ["StopTimeout" ]
269+ return containerDefinition
270+
271+ containers = list (map (sanitize_container_definition , task_def .get ("ContainerDefinitions" , [])))
262272
263- def sanitize_efs_port_if_needed (v ):
273+ def sanitize_volume (v ):
264274 if "EfsVolumeConfiguration" in v and "TransitEncryptionPort" in v ["EfsVolumeConfiguration" ] and v ["EfsVolumeConfiguration" ]["TransitEncryptionPort" ] == 0 :
265275 del v ["EfsVolumeConfiguration" ]["TransitEncryptionPort" ]
266276 return v
@@ -272,44 +282,28 @@ def sanitize_efs_port_if_needed(v):
272282 "ContainerDefinitions" : containers ,
273283 "RuntimePlatform" : task_def .get ("RuntimePlatform" , {}),
274284 "RequiresCompatibilities" : task_def .get ("RequiresCompatibilities" , []),
275- "Volumes" : list (map (sanitize_efs_port_if_needed , task_def .get ("Volumes" , []))),
285+ "Volumes" : list (map (sanitize_volume , task_def .get ("Volumes" , []))),
276286 }
277287 if task_def .get ("Cpu" ) not in (None , 0 ):
278288 result ["Cpu" ] = task_def ["Cpu" ]
279289 if task_def .get ("Memory" ) not in (None , 0 ):
280290 result ["Memory" ] = task_def ["Memory" ]
281291 if task_def .get ("MemoryReservation" ) not in (None , 0 ):
282292 result ["MemoryReservation" ] = task_def ["MemoryReservation" ]
283- return result
284-
293+ if "EphemeralStorage" in task_def :
294+ result ["EphemeralStorage" ] = task_def ["EphemeralStorage" ]
295+ if "ExecutionRoleArn" in task_def :
296+ result ["ExecutionRoleArn" ] = task_def ["ExecutionRoleArn" ]
297+ if "IpcMode" in task_def :
298+ result ["IpcMode" ] = task_def ["IpcMode" ]
299+ if "PlacementConstraints" in task_def :
300+ result ["PlacementConstraints" ] = task_def ["PlacementConstraints" ]
301+ if "ProxyConfiguration" in task_def :
302+ result ["ProxyConfiguration" ] = task_def ["ProxyConfiguration" ]
303+ if "TaskRoleArn" in task_def :
304+ result ["TaskRoleArn" ] = task_def ["TaskRoleArn" ]
285305
286- def __ecs_container_update_body (self , container_def ):
287- update_body = {
288- "Essential" : container_def .get ("Essential" ),
289- "Image" : container_def .get ("Image" ) ,
290- "Name" : container_def .get ("Name" ) ,
291- "PortMappings" : container_def .get ("PortMappings" , []) ,
292- "Environment" : container_def .get ("Environment" , {}) ,
293- "Command" : container_def .get ("Command" , {}) ,
294- "Secrets" : container_def .get ("Secrets" , {}) ,
295- "EnvironmentFiles" : container_def .get ("EnvironmentFiles" , {})
296- }
297-
298- # Add LogConfiguration only if it exists in container_def
299- if "LogConfiguration" in container_def :
300- update_body ["LogConfiguration" ] = container_def ["LogConfiguration" ]
301- # Add FirelensConfiguration only if it exists in container_def
302- if "FirelensConfiguration" in container_def :
303- update_body ["FirelensConfiguration" ] = container_def ["FirelensConfiguration" ]
304- if container_def .get ("Cpu" ) not in (None , 0 ):
305- update_body ["Cpu" ] = container_def ["Cpu" ]
306- if container_def .get ("Memory" ) not in (None , 0 ):
307- update_body ["Memory" ] = container_def ["Memory" ]
308- if container_def .get ("MemoryReservation" ) not in (None , 0 ):
309- update_body ["MemoryReservation" ] = container_def ["MemoryReservation" ]
310- if container_def .get ("RepositoryCredentials" ) not in (None , 0 ):
311- update_body ["RepositoryCredentials" ] = container_def ["RepositoryCredentials" ]
312- return update_body
306+ return result
313307
314308 @Command ()
315309 def list_tasks (self ,
@@ -338,13 +332,13 @@ def list_tasks(self,
338332 def run_task (self ,
339333 name : args .NAME ,
340334 replicas : args .REPLICAS ) -> dict :
341- """Run a task for an ECS service ."
335+ """Run a task from an ECS task definition family's latest definition version ."
342336
343337 Execute a task based on some definition.
344338
345339 Usage: Basic CLI Use
346340 ```sh
347- duploctl ecs run_task <service -name> <replicas>
341+ duploctl ecs run_task <task-definition-family -name> <replicas>
348342 ```
349343
350344 Example: Wait for task to complete
@@ -355,7 +349,7 @@ def run_task(self,
355349 ```
356350
357351 Args:
358- name: The name of the ECS service to run the task for .
352+ name: The name of the ECS task definition family the task will be spawned from .
359353 replicas: The number of replicas to run.
360354
361355 Returns:
0 commit comments