|
9 | 9 |
|
10 | 10 | if TYPE_CHECKING: |
11 | 11 | from ecs_composex.ecs.ecs_family import ComposeFamily |
| 12 | + from ecs_composex.compose.compose_services import ComposeService |
12 | 13 | from ecs_composex.common.settings import ComposeXSettings |
13 | 14 | from ecs_composex.common.stacks import ComposeXStack |
| 15 | + from ecs_composex.ecs_ingress.ecs_ingress_stack import XStack as EcsIngressStack |
14 | 16 |
|
15 | 17 | from json import dumps |
16 | 18 |
|
|
21 | 23 | from ecs_composex.cloudmap.cloudmap_params import RES_KEY as CLOUDMAP_KEY |
22 | 24 | from ecs_composex.common.cfn_params import Parameter |
23 | 25 | from ecs_composex.common.logging import LOG |
24 | | -from ecs_composex.common.troposphere_tools import add_parameters |
| 26 | +from ecs_composex.common.troposphere_tools import add_parameters, add_resource |
25 | 27 | from ecs_composex.ecs.ecs_params import SERVICE_NAME |
26 | 28 | from ecs_composex.ingress_settings import Ingress |
27 | 29 | from ecs_composex.vpc.vpc_params import SG_ID_TYPE |
@@ -142,120 +144,82 @@ def merge_family_services_networking(family: ComposeFamily) -> dict: |
142 | 144 | return network_config |
143 | 145 |
|
144 | 146 |
|
145 | | -def add_independent_rules( |
146 | | - dst_family: ComposeFamily, service_name: str, root_stack: ComposeXStack |
147 | | -) -> None: |
148 | | - """ |
149 | | - Adds security groups rules in the root stack as both services need to be created (with their SG) |
150 | | - before the ingress rule can be defined. |
151 | | -
|
152 | | - :param dst_family: |
153 | | - :param service_name: |
154 | | - :param root_stack: |
155 | | - :return: |
156 | | - """ |
157 | | - src_service_stack = root_stack.stack_template.resources[service_name] |
158 | | - for port in dst_family.service_networking.ports: |
159 | | - target_port = set_else_none( |
160 | | - "published", port, alt_value=set_else_none("target", port, None) |
161 | | - ) |
162 | | - if target_port is None: |
163 | | - raise ValueError( |
164 | | - "Wrong port definition value for security group ingress", port |
165 | | - ) |
166 | | - ingress_rule = SecurityGroupIngress( |
167 | | - f"From{src_service_stack.title}To{dst_family.logical_name}On{target_port}", |
168 | | - FromPort=target_port, |
169 | | - ToPort=target_port, |
170 | | - IpProtocol=port["protocol"], |
171 | | - Description=Sub( |
172 | | - f"From {src_service_stack.title} to {dst_family.logical_name}" |
173 | | - f" on port {target_port}/{port['protocol']}" |
174 | | - ), |
175 | | - GroupId=GetAtt( |
176 | | - dst_family.stack.title, |
177 | | - f"Outputs.{dst_family.logical_name}GroupId", |
178 | | - ), |
179 | | - SourceSecurityGroupId=GetAtt( |
180 | | - src_service_stack.title, |
181 | | - f"Outputs.{src_service_stack.title}GroupId", |
182 | | - ), |
183 | | - SourceSecurityGroupOwnerId=Ref(AWS_ACCOUNT_ID), |
184 | | - ) |
185 | | - if ingress_rule.title not in root_stack.stack_template.resources: |
186 | | - root_stack.stack_template.add_resource(ingress_rule) |
187 | | - |
188 | | - |
189 | | -def add_dependant_ingress_rules( |
190 | | - dst_family: ComposeFamily, dst_family_sg_param: Parameter, src_family: ComposeFamily |
191 | | -) -> None: |
192 | | - for port in dst_family.service_networking.ports: |
193 | | - target_port = set_else_none( |
194 | | - "published", port, alt_value=set_else_none("target", port, None) |
195 | | - ) |
196 | | - if target_port is None: |
197 | | - raise ValueError( |
198 | | - "Wrong port definition value for security group ingress", port |
199 | | - ) |
200 | | - common_args = { |
201 | | - "FromPort": target_port, |
202 | | - "ToPort": target_port, |
203 | | - "IpProtocol": port["protocol"], |
204 | | - "SourceSecurityGroupOwnerId": Ref(AWS_ACCOUNT_ID), |
205 | | - "Description": Sub( |
206 | | - f"From ${{{SERVICE_NAME.title}}} to {dst_family.stack.title} on port {target_port}" |
207 | | - ), |
208 | | - } |
209 | | - src_family.template.add_resource( |
210 | | - SecurityGroupIngress( |
211 | | - f"From{src_family.logical_name}To{dst_family.stack.title}On{target_port}", |
212 | | - SourceSecurityGroupId=GetAtt( |
213 | | - src_family.service_networking.security_group, "GroupId" |
214 | | - ), |
215 | | - GroupId=Ref(dst_family_sg_param), |
216 | | - **common_args, |
217 | | - ) |
218 | | - ) |
219 | | - |
220 | | - |
221 | 147 | def set_compose_services_ingress( |
222 | | - root_stack, dst_family: ComposeFamily, families: list, settings: ComposeXSettings |
| 148 | + dst_family: ComposeFamily, |
| 149 | + families_sg_stack: EcsIngressStack, |
| 150 | + settings: ComposeXSettings, |
223 | 151 | ) -> None: |
224 | 152 | """ |
225 | 153 | Function to crate SG Ingress between two families / services. |
226 | 154 | Presently, the ingress rules are set after all services have been created |
227 | | -
|
228 | | - :param ecs_composex.common.stacks.ComposeXStack root_stack: |
229 | | - :param ecs_composex.ecs.ecs_family.ComposeFamily dst_family: |
230 | | - :param list families: The list of family names. |
231 | | - :param ecs_composex.common.settings.ComposeXSettings settings: |
232 | 155 | """ |
233 | | - for service in dst_family.service_networking.ingress.services: |
234 | | - service_name = service["Name"] |
235 | | - if service_name not in families: |
236 | | - raise KeyError( |
237 | | - f"The service {service_name} is not among the services created together. Valid services are", |
238 | | - families, |
| 156 | + target_family_services: list[ComposeService] = [] |
| 157 | + for _target_service_def in dst_family.service_networking.ingress.services: |
| 158 | + service_name = _target_service_def["Name"] |
| 159 | + for _service in settings.services: |
| 160 | + if service_name != _service.name: |
| 161 | + continue |
| 162 | + if _service.family == dst_family: |
| 163 | + continue |
| 164 | + target_family_services.append(_service) |
| 165 | + add_service_to_service_ingress_rules( |
| 166 | + dst_family, target_family_services, families_sg_stack |
| 167 | + ) |
| 168 | + |
| 169 | + |
| 170 | +def add_service_to_service_ingress_rules( |
| 171 | + dst_family: ComposeFamily, |
| 172 | + target_family_services: list[ComposeService], |
| 173 | + families_sg_stack: EcsIngressStack, |
| 174 | +): |
| 175 | + """ |
| 176 | + For each identified service that wants to access the `dst_family` services |
| 177 | + For each port of the `dst_family` |
| 178 | + Create an SG Ingress rule that allows service-to-service communication |
| 179 | + """ |
| 180 | + for _service in target_family_services: |
| 181 | + if families_sg_stack.title not in _service.family.stack.DependsOn: |
| 182 | + _service.family.stack.DependsOn.append(families_sg_stack.title) |
| 183 | + for _service_port_def in dst_family.service_networking.ports: |
| 184 | + target_port = set_else_none( |
| 185 | + "target", |
| 186 | + _service_port_def, |
| 187 | + set_else_none("published", _service_port_def, None), |
239 | 188 | ) |
240 | | - if not keypresent("DependsOn", service): |
241 | | - add_independent_rules(dst_family, service_name, root_stack) |
242 | | - else: |
243 | | - src_family = settings.families[service_name] |
244 | | - if dst_family.stack.title not in src_family.stack.DependsOn: |
245 | | - src_family.stack.DependsOn.append(dst_family.stack.title) |
246 | | - dst_family_sg_param = Parameter( |
247 | | - f"{dst_family.stack.title}GroupId", Type=SG_ID_TYPE |
| 189 | + if target_port is None: |
| 190 | + raise ValueError( |
| 191 | + "Wrong port definition value for security group ingress", |
| 192 | + _service_port_def, |
| 193 | + ) |
| 194 | + common_args = { |
| 195 | + "FromPort": target_port, |
| 196 | + "ToPort": target_port, |
| 197 | + "IpProtocol": _service_port_def["protocol"], |
| 198 | + "SourceSecurityGroupOwnerId": Ref(AWS_ACCOUNT_ID), |
| 199 | + "Description": Sub( |
| 200 | + f"From ${_service.family.name} to {dst_family.name} " |
| 201 | + f"on port {target_port}/{_service_port_def['protocol']}" |
| 202 | + ), |
| 203 | + } |
| 204 | + ingress_title: str = ( |
| 205 | + f"From{_service.family.logical_name}To{dst_family.logical_name}" |
| 206 | + f"On{target_port}{_service_port_def['protocol'].title()}" |
248 | 207 | ) |
249 | | - add_parameters(src_family.template, [dst_family_sg_param]) |
250 | | - src_family.stack.Parameters.update( |
251 | | - { |
252 | | - dst_family_sg_param.title: GetAtt( |
253 | | - dst_family.stack.title, |
254 | | - f"Outputs.{dst_family.logical_name}GroupId", |
| 208 | + add_resource( |
| 209 | + families_sg_stack.stack_template, |
| 210 | + SecurityGroupIngress( |
| 211 | + ingress_title, |
| 212 | + SourceSecurityGroupId=GetAtt( |
| 213 | + _service.family.service_networking.inter_services_sg.cfn_resource, |
| 214 | + "GroupId", |
255 | 215 | ), |
256 | | - } |
| 216 | + GroupId=GetAtt( |
| 217 | + dst_family.service_networking.inter_services_sg.cfn_resource, |
| 218 | + "GroupId", |
| 219 | + ), |
| 220 | + **common_args, |
| 221 | + ), |
257 | 222 | ) |
258 | | - add_dependant_ingress_rules(dst_family, dst_family_sg_param, src_family) |
259 | 223 |
|
260 | 224 |
|
261 | 225 | def handle_str_cloudmap_config( |
|
0 commit comments