@@ -285,17 +285,26 @@ class ComposeService(object):
285285 ("x-network" , dict ),
286286 ]
287287
288+ ecs_plugin_aws_keys = [
289+ ("x-aws-role" , dict ),
290+ ("x-aws-policies" , list ),
291+ ("x-aws-autoscaling" , dict ),
292+ ("x-aws-pull_credentials" , str ),
293+ ]
294+
288295 def __init__ (self , name , definition , volumes = None , secrets = None ):
289296 if not isinstance (definition , dict ):
290297 raise TypeError (
291298 "The definition of a service must be" , dict , "got" , type (definition )
292299 )
293300 if not all (
294- key in [title [0 ] for title in self .keys ] for key in list (definition .keys ())
301+ key in [title [0 ] for title in self .ecs_plugin_aws_keys + self .keys ]
302+ for key in list (definition .keys ())
295303 ):
296304 raise KeyError (
297305 "Only valid keys for a service definition are" ,
298306 sorted ([key [0 ] for key in self .keys ]),
307+ sorted ([key [0 ] for key in self .ecs_plugin_aws_keys ]),
299308 "Got" ,
300309 sorted (list (definition .keys ())),
301310 )
@@ -322,6 +331,8 @@ def __init__(self, name, definition, volumes=None, secrets=None):
322331 self .x_iam = set_else_none ("x-iam" , self .definition )
323332 self .x_logging = {"RetentionInDays" : 14 , "CreateLogGroup" : True }
324333
334+ self .import_x_aws_settings ()
335+
325336 self .replicas = 1
326337 self .container = None
327338 self .volumes = []
@@ -399,6 +410,57 @@ def set_container_definition(self):
399410 )
400411 self .container_parameters .update ({self .image_param .title : self .image })
401412
413+ def merge_x_aws_role (self , key ):
414+ """
415+ Method to update the service definition with the x-aws-role information if NOT defined in the composex
416+ definition.
417+
418+ :param str key:
419+ """
420+ policy_def = {
421+ "PolicyName" : "ImportedFromXAWSRole" ,
422+ "PolicyDocument" : self .definition [key ],
423+ }
424+ if not self .x_iam :
425+ self .x_iam = {"Policies" : [policy_def ]}
426+ LOG .info (f"Added { key } definition" )
427+ elif self .x_iam and keyisset ("Policies" , self .x_iam ):
428+ self .x_iam ["Policies" ].append (policy_def )
429+ LOG .info (f"Merged { key } to existing definition" )
430+
431+ def merge_x_policies (self , key ):
432+ """
433+ Method to merge policies
434+
435+ :param str key:
436+ """
437+ if not self .x_iam :
438+ self .x_iam = {"ManagedPolicyArns" : self .definition [key ]}
439+ LOG .info (f"Added { key } definition" )
440+ elif self .x_iam and keyisset ("ManagedPolicyArns" , self .x_iam ):
441+ self .x_iam ["ManagedPolicyArns" ] += self .definition [key ]
442+ LOG .info (f"Merged { key } definition" )
443+
444+ def import_x_aws_settings (self ):
445+ aws_keys = [
446+ ("x-aws-role" , dict , self .merge_x_aws_role ),
447+ ("x-aws-policies" , list , self .merge_x_policies ),
448+ ("x-aws-autoscaling" , dict , None ),
449+ ("x-aws-pull_credentials" , str , None ),
450+ ]
451+ for setting in aws_keys :
452+ if keyisset (setting [0 ], self .definition ) and not isinstance (
453+ self .definition [setting [0 ]], setting [1 ]
454+ ):
455+ raise TypeError (
456+ f"{ setting [0 ]} is of type" ,
457+ type (self .definition [setting [0 ]]),
458+ "Expected" ,
459+ setting [1 ],
460+ )
461+ elif keyisset (setting [0 ], self .definition ) and setting [2 ]:
462+ setting [2 ](setting [0 ])
463+
402464 def define_logging (self ):
403465 """
404466 Method to define logging properties
@@ -686,18 +748,22 @@ def add_policies(config, key, new_policies):
686748 if f"PolicyGenerated{ count } " not in existing_policy_names
687749 else f"PolicyGenerated{ count + len (existing_policy_names )} "
688750 )
689- name = generated_name if not keyisset ("name" , policy ) else policy ["name" ]
751+ name = (
752+ generated_name
753+ if not keyisset ("PolicyName" , policy )
754+ else policy ["PolicyName" ]
755+ )
690756 if name in existing_policy_names :
691757 return
692- if not keyisset ("document " , policy ):
758+ if not keyisset ("PolicyDocument " , policy ):
693759 raise KeyError ("You must set the policy document for the policy" )
694760 if (
695- keyisset ("Version" , policy ["document " ])
696- and not isinstance (policy ["document " ]["Version" ], str )
697- or not keyisset ("Version" , policy ["document " ])
761+ keyisset ("Version" , policy ["PolicyDocument " ])
762+ and not isinstance (policy ["PolicyDocument " ]["Version" ], str )
763+ or not keyisset ("Version" , policy ["PolicyDocument " ])
698764 ):
699- policy ["document " ]["Version" ] = "2012-10-17"
700- policy_object = Policy (PolicyName = name , PolicyDocument = policy ["document " ])
765+ policy ["PolicyDocument " ]["Version" ] = "2012-10-17"
766+ policy_object = Policy (PolicyName = name , PolicyDocument = policy ["PolicyDocument " ])
701767 existing_policies .append (policy_object )
702768
703769
@@ -723,7 +789,11 @@ def __init__(self, services, family_name):
723789 self .ignored_services = []
724790 self .name = family_name
725791 self .logical_name = re .sub (r"[^a-zA-Z0-9]+" , "" , family_name )
726- self .iam = {"boundary" : None , "managed_policies" : [], "policies" : []}
792+ self .iam = {
793+ "PermissionsBoundary" : None ,
794+ "ManagedPolicyArns" : [],
795+ "Policies" : [],
796+ }
727797 self .template = None
728798 self .use_xray = None
729799 self .stack = None
@@ -766,7 +836,7 @@ def set_xray(self):
766836 "resources" : {"limits" : {"cpus" : 0.03125 , "memory" : "256M" }},
767837 },
768838 "x-iam" : {
769- "managed_policies " : [
839+ "ManagedPolicyArns " : [
770840 "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
771841 ]
772842 },
@@ -874,9 +944,9 @@ def sort_iam_settings(self, key, setting):
874944
875945 def handle_iam (self ):
876946 valid_keys = [
877- ("managed_policies " , list , None ),
878- ("policies " , list , add_policies ),
879- ("boundary " , (str , Sub ), handle_iam_boundary ),
947+ ("ManagedPolicyArns " , list , None ),
948+ ("Policies " , list , add_policies ),
949+ ("PermissionsBoundary " , (str , Sub ), handle_iam_boundary ),
880950 ]
881951 iam_settings = [service .x_iam for service in self .services if service .x_iam ]
882952 for setting in iam_settings :
@@ -885,7 +955,7 @@ def handle_iam(self):
885955 self .set_secrets_access ()
886956
887957 def handle_permission_boundary (self , prop_key ):
888- if keyisset ("boundary " , self .iam ) and self .template :
958+ if keyisset ("PermissionsBoundary " , self .iam ) and self .template :
889959 if EXEC_ROLE_T in self .template .resources :
890960 add_role_boundaries (
891961 self .template .resources [EXEC_ROLE_T ], self .iam [prop_key ]
@@ -943,17 +1013,17 @@ def assign_policies(self, role_name=None):
9431013 role = self .template .resources [role_name ]
9441014 props = [
9451015 (
946- "managed_policies " ,
1016+ "ManagedPolicyArns " ,
9471017 "ManagedPolicyArns" ,
9481018 list ,
9491019 self .assign_iam_managed_policies ,
9501020 ),
951- ("policies " , "Policies" , list , self .assign_iam_policies ),
952- ("boundary " , "PermissionsBoundary" , (str , Sub ), None ),
1021+ ("Policies " , "Policies" , list , self .assign_iam_policies ),
1022+ ("PermissionsBoundary " , "PermissionsBoundary" , (str , Sub ), None ),
9531023 ]
9541024 for prop in props :
9551025 if keyisset (prop [0 ], self .iam ) and isinstance (self .iam [prop [0 ]], prop [2 ]):
956- if prop [0 ] == "boundary " :
1026+ if prop [0 ] == "PermissionsBoundary " :
9571027 self .handle_permission_boundary (prop [0 ])
9581028 elif prop [3 ]:
9591029 prop [3 ](role , prop )
0 commit comments