Repository: aws-cloudformation/cfn-lint

Issue:
ECS Task definition container log driver enum does not include "sumologic"
Our team uses the somologic log driver in container definitions. It appears that when validation was added sub properties, "sumologic" was not included in the enum used to validate LogDriver types. This change seems to have been introduced in issue #3763. 

Here's an example of where we are using the sumologic log driver. 

```yaml
TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      TaskRoleArn: !Ref TaskRole
      ExecutionRoleArn: !GetAtt ExecutionRole.Arn
      ContainerDefinitions:
        - Name: nginx
          Essential: true
          Image: !Sub  <accountId>.dkr.ecr.${AWS::Region}.amazonaws.com/<imageName>:latest
          Memory: 16
          PortMappings:
            - ContainerPort: 443
          Links:
            - app
          LogConfiguration:
            LogDriver: sumologic
            Options:
              sumo-url: !GetAtt SumoUrl.Value
              sumo-source-category: !Sub ${Environment}/${ProjectName}/access
```

When we execute cfn-lint the following error is returned.

```
E3030 'sumologic' is not one of ['awsfirelens', 'awslogs', 'fluentd', 'gelf', 'journald', 'json-file', 'splunk', 'syslog']
ci/service.template:234:13
```

Is resolving this just a matter of extending the enum to include "sumologic" log driver? If so, I can contribute this and submit a PR.

Discussion:
@kddejong: Looking into this.  When I look at the [API docs](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_LogConfiguration.html) or [CFN docs](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_LogConfiguration.html) they don't list sumologic. Trying to find a more complete list then or what I'm missing.@kddejong: [This](https://github.com/aws/amazon-ecs-agent/blob/0f876b5372c9ecb15228f607f11d2c4be629d364/agent/dockerclient/logging_drivers.go#L18-L30) looks like its the complete list and we are taking this value from [boto](https://github.com/boto/botocore/blob/3ff30ef929da20bc83a1f21d1bd3ab6e408648fe/botocore/data/ecs/2014-11-13/service-2.json#L3554-L3566). @kddejong: Are you using External or EC2 launch types or compatibilities?@fidelperez: I'm not sure what you mean by launch type but we deploy to ECS on ec2. @kddejong: Yea, slight typo there.  Either way the LogDriver when using EC2 and EXTERNAL should work. I have updated our definition and logic to remove this error for you.@fidelperez: Thanks so much for the quick response. 

Solution patch:
diff --git a/scripts/boto/update_schemas_from_boto.py b/scripts/boto/update_schemas_from_boto.py
index 829cd3f62..4cfea803b 100755
--- a/scripts/boto/update_schemas_from_boto.py
+++ b/scripts/boto/update_schemas_from_boto.py
@@ -29,7 +29,8 @@ case_insensitive_services = [
 ]
 
 exceptions = {
-    "ses": ["/definitions/EventDestination/properties/MatchingEventTypes/items"]
+    "ses": ["/definitions/EventDestination/properties/MatchingEventTypes/items"],
+    "ecs": ["/definitions/LogConfiguration/properties/LogDriver"],
 }
 
 
diff --git a/src/cfnlint/data/schemas/extensions/aws_ecs_taskdefinition/fargate_properties.json b/src/cfnlint/data/schemas/extensions/aws_ecs_taskdefinition/fargate_properties.json
index f0326beeb..94885935c 100644
--- a/src/cfnlint/data/schemas/extensions/aws_ecs_taskdefinition/fargate_properties.json
+++ b/src/cfnlint/data/schemas/extensions/aws_ecs_taskdefinition/fargate_properties.json
@@ -16,54 +16,119 @@
   ]
  },
  "then": {
-  "if": {
-   "properties": {
-    "Cpu": {
-     "type": [
-      "string",
-      "integer"
+  "allOf": [
+   {
+    "if": {
+     "properties": {
+      "NetworkMode": {
+       "type": "string"
+      }
+     },
+     "required": [
+      "NetworkMode"
+     ]
+    },
+    "required": [
+     "NetworkMode"
+    ],
+    "then": {
+     "properties": {
+      "NetworkMode": {
+       "enum": [
+        "awsvpc"
+       ],
+       "type": "string"
+      }
+     },
+     "required": [
+      "NetworkMode"
      ]
     }
    },
-   "required": [
-    "Cpu"
-   ]
-  },
-  "not": {
-   "required": [
-    "PlacementConstraints"
-   ]
-  },
-  "required": [
-   "Cpu",
-   "Memory"
-  ],
-  "then": {
-   "properties": {
-    "Cpu": {
-     "else": {
-      "pattern": "^(\\.25|\\.5|1|2|4|8|16)\\s*(?i)vCpu$"
-     },
-     "if": {
-      "pattern": "^\\d+$",
-      "type": [
-       "integer",
-       "string"
-      ]
+   {
+    "properties": {
+     "ContainerDefinitions": {
+      "items": {
+       "properties": {
+        "LogConfiguration": {
+         "if": {
+          "properties": {
+           "LogDriver": {
+            "type": "string"
+           }
+          },
+          "required": [
+           "LogDriver"
+          ]
+         },
+         "then": {
+          "properties": {
+           "LogDriver": {
+            "enum": [
+             "awslogs",
+             "splunk",
+             "awsfirelens"
+            ]
+           }
+          }
+         }
+        }
+       }
+      }
+     }
+    }
+   },
+   {
+    "if": {
+     "properties": {
+      "Cpu": {
+       "type": [
+        "string",
+        "integer"
+       ]
+      }
      },
-     "then": {
-      "enum": [
-       "256",
-       "512",
-       "1024",
-       "2048",
-       "4096",
-       "8192",
-       "16384"
-      ]
+     "required": [
+      "Cpu"
+     ]
+    },
+    "not": {
+     "required": [
+      "PlacementConstraints"
+     ]
+    },
+    "required": [
+     "Cpu",
+     "Memory"
+    ],
+    "then": {
+     "properties": {
+      "Cpu": {
+       "else": {
+        "pattern": "^(\\.25|\\.5|1|2|4|8|16)\\s*(?i)vCpu$"
+       },
+       "if": {
+        "pattern": "^\\d+$",
+        "type": [
+         "integer",
+         "string"
+        ]
+       },
+       "then": {
+        "enum": [
+         "256",
+         "512",
+         "1024",
+         "2048",
+         "4096",
+         "8192",
+         "16384"
+        ]
+       }
+      }
      }
     }
    }
-  }
+  ]
  }
 }
diff --git a/src/cfnlint/data/schemas/patches/extensions/all/aws_ecs_service/boto.json b/src/cfnlint/data/schemas/patches/extensions/all/aws_ecs_service/boto.json
index e6ad41c27..fd1d715ee 100644
--- a/src/cfnlint/data/schemas/patches/extensions/all/aws_ecs_service/boto.json
+++ b/src/cfnlint/data/schemas/patches/extensions/all/aws_ecs_service/boto.json
@@ -9,20 +9,6 @@
   "path": "/definitions/Tag/properties/Value/pattern",
   "value": "^([\\p{L}\\p{Z}\\p{N}_.:/=+\\-@]*)$"
  },
- {
-  "op": "add",
-  "path": "/definitions/LogConfiguration/properties/LogDriver/enum",
-  "value": [
-   "awsfirelens",
-   "awslogs",
-   "fluentd",
-   "gelf",
-   "journald",
-   "json-file",
-   "splunk",
-   "syslog"
-  ]
- },
  {
   "op": "add",
   "path": "/definitions/EBSTagSpecification/properties/ResourceType/enum",
diff --git a/src/cfnlint/data/schemas/patches/extensions/all/aws_ecs_taskdefinition/boto.json b/src/cfnlint/data/schemas/patches/extensions/all/aws_ecs_taskdefinition/boto.json
index fb8d335eb..f0973d86f 100644
--- a/src/cfnlint/data/schemas/patches/extensions/all/aws_ecs_taskdefinition/boto.json
+++ b/src/cfnlint/data/schemas/patches/extensions/all/aws_ecs_taskdefinition/boto.json
@@ -71,20 +71,6 @@
    "stack"
   ]
  },
- {
-  "op": "add",
-  "path": "/definitions/LogConfiguration/properties/LogDriver/enum",
-  "value": [
-   "awsfirelens",
-   "awslogs",
-   "fluentd",
-   "gelf",
-   "journald",
-   "json-file",
-   "splunk",
-   "syslog"
-  ]
- },
  {
   "op": "add",
   "path": "/definitions/ResourceRequirement/properties/Type/enum",
diff --git a/src/cfnlint/data/schemas/providers/eu_central_1/aws-ecs-service.json b/src/cfnlint/data/schemas/providers/eu_central_1/aws-ecs-service.json
index 39c164ea6..706515640 100644
--- a/src/cfnlint/data/schemas/providers/eu_central_1/aws-ecs-service.json
+++ b/src/cfnlint/data/schemas/providers/eu_central_1/aws-ecs-service.json
@@ -174,16 +174,6 @@
    "additionalProperties": false,
    "properties": {
     "LogDriver": {
-     "enum": [
-      "awsfirelens",
-      "awslogs",
-      "fluentd",
-      "gelf",
-      "journald",
-      "json-file",
-      "splunk",
-      "syslog"
-     ],
      "type": "string"
     },
     "Options": {
diff --git a/src/cfnlint/data/schemas/providers/us_east_1/aws-ecs-taskdefinition.json b/src/cfnlint/data/schemas/providers/us_east_1/aws-ecs-taskdefinition.json
index 8b9f47336..2db10e86b 100644
--- a/src/cfnlint/data/schemas/providers/us_east_1/aws-ecs-taskdefinition.json
+++ b/src/cfnlint/data/schemas/providers/us_east_1/aws-ecs-taskdefinition.json
@@ -581,16 +581,6 @@
    "additionalProperties": false,
    "properties": {
     "LogDriver": {
-     "enum": [
-      "awsfirelens",
-      "awslogs",
-      "fluentd",
-      "gelf",
-      "journald",
-      "json-file",
-      "splunk",
-      "syslog"
-     ],
      "type": "string"
     },
     "Options": {
diff --git a/src/cfnlint/data/schemas/providers/us_west_2/aws-ecs-service.json b/src/cfnlint/data/schemas/providers/us_west_2/aws-ecs-service.json
index 39c164ea6..706515640 100644
--- a/src/cfnlint/data/schemas/providers/us_west_2/aws-ecs-service.json
+++ b/src/cfnlint/data/schemas/providers/us_west_2/aws-ecs-service.json
@@ -174,16 +174,6 @@
    "additionalProperties": false,
    "properties": {
     "LogDriver": {
-     "enum": [
-      "awsfirelens",
-      "awslogs",
-      "fluentd",
-      "gelf",
-      "journald",
-      "json-file",
-      "splunk",
-      "syslog"
-     ],
      "type": "string"
     },
     "Options": {


Test patch:
diff --git a/test/unit/rules/resources/ecs/test_ecs_task_fargate_properties.py b/test/unit/rules/resources/ecs/test_ecs_task_fargate_properties.py
index b2935bd6b..8d557e623 100644
--- a/test/unit/rules/resources/ecs/test_ecs_task_fargate_properties.py
+++ b/test/unit/rules/resources/ecs/test_ecs_task_fargate_properties.py
@@ -22,6 +22,7 @@ def rule():
     [
         (
             {
+                "NetworkMode": "awsvpc",
                 "RequiresCompatibilities": ["FARGATE"],
                 "Cpu": 256,
                 "Memory": "512",
@@ -30,6 +31,7 @@ def rule():
         ),
         (
             {
+                "NetworkMode": "awsvpc",
                 "RequiresCompatibilities": ["FARGATE"],
                 "Cpu": ".25     vCpU",
                 "Memory": "512",
@@ -38,6 +40,7 @@ def rule():
         ),
         (
             {
+                "NetworkMode": "awsvpc",
                 "RequiresCompatibilities": ["FARGATE"],
                 "Cpu": 16384,
             },
@@ -47,12 +50,13 @@ def rule():
                     rule=TaskFargateProperties(),
                     path=deque([]),
                     validator="required",
-                    schema_path=deque(["then", "required"]),
+                    schema_path=deque(["then", "allOf", 2, "required"]),
                 )
             ],
         ),
         (
             {
+                "NetworkMode": "awsvpc",
                 "RequiresCompatibilities": ["FARGATE"],
                 "Memory": "512",
             },
@@ -62,12 +66,13 @@ def rule():
                     rule=TaskFargateProperties(),
                     path=deque([]),
                     validator="required",
-                    schema_path=deque(["then", "required"]),
+                    schema_path=deque(["then", "allOf", 2, "required"]),
                 )
             ],
         ),
         (
             {
+                "NetworkMode": "awsvpc",
                 "RequiresCompatibilities": ["FARGATE"],
                 "Memory": "512",
                 "Cpu": 256,
@@ -79,12 +84,13 @@ def rule():
                     rule=TaskFargateProperties(),
                     path=deque(["PlacementConstraints"]),
                     validator="not",
-                    schema_path=deque(["then", "not"]),
+                    schema_path=deque(["then", "allOf", 2, "not"]),
                 )
             ],
         ),
         (
             {
+                "NetworkMode": "awsvpc",
                 "RequiresCompatibilities": ["FARGATE"],
                 "Cpu": {"Ref": "MyParameter"},
                 "Memory": "512",
@@ -93,6 +99,7 @@ def rule():
         ),
         (
             {
+                "NetworkMode": "awsvpc",
                 "RequiresCompatibilities": ["FARGATE"],
                 "Cpu": 128,
                 "Memory": "512",
@@ -107,7 +114,128 @@ def rule():
                     path=deque(["Cpu"]),
                     validator="enum",
                     schema_path=deque(
-                        ["then", "then", "properties", "Cpu", "then", "enum"]
+                        [
+                            "then",
+                            "allOf",
+                            2,
+                            "then",
+                            "properties",
+                            "Cpu",
+                            "then",
+                            "enum",
+                        ]
+                    ),
+                )
+            ],
+        ),
+        (
+            {
+                "RequiresCompatibilities": ["FARGATE"],
+                "Cpu": 256,
+                "Memory": "512",
+                "NetworkMode": {"Ref": "MyParameter"},
+            },
+            [],
+        ),
+        (
+            {
+                "RequiresCompatibilities": ["FARGATE"],
+                "Cpu": 256,
+                "Memory": "512",
+            },
+            [
+                ValidationError(
+                    ("'NetworkMode' is a required property"),
+                    rule=TaskFargateProperties(),
+                    path=deque([]),
+                    validator="required",
+                    schema_path=deque(["then", "allOf", 0, "required"]),
+                )
+            ],
+        ),
+        (
+            {
+                "RequiresCompatibilities": ["FARGATE"],
+                "Cpu": 256,
+                "Memory": "512",
+                "NetworkMode": "awsvpc",
+                "ContainerDefinitions": [
+                    {
+                        "LogConfiguration": {
+                            "LogDriver": "awslogs",
+                            "Options": {
+                                "awslogs-group": "log-group",
+                                "awslogs-region": "us-east-1",
+                                "awslogs-stream-prefix": "ecs",
+                            },
+                        }
+                    }
+                ],
+            },
+            [],
+        ),
+        (
+            {
+                "RequiresCompatibilities": ["FARGATE"],
+                "Cpu": 256,
+                "Memory": "512",
+                "NetworkMode": "awsvpc",
+                "ContainerDefinitions": [
+                    {
+                        "LogConfiguration": {
+                            "LogDriver": {"Ref": "MyParameter"},
+                            "Options": {
+                                "awslogs-group": "log-group",
+                                "awslogs-region": "us-east-1",
+                                "awslogs-stream-prefix": "ecs",
+                            },
+                        }
+                    }
+                ],
+            },
+            [],
+        ),
+        (
+            {
+                "RequiresCompatibilities": ["FARGATE"],
+                "Cpu": 256,
+                "Memory": "512",
+                "NetworkMode": "awsvpc",
+                "ContainerDefinitions": [
+                    {
+                        "LogConfiguration": {
+                            "LogDriver": "sumologic",
+                            "Options": {
+                                "sumo-url": "aurl",
+                                "sumo-source-category": "access",
+                            },
+                        }
+                    }
+                ],
+            },
+            [
+                ValidationError(
+                    ("'sumologic' is not one of ['awslogs', 'splunk', 'awsfirelens']"),
+                    rule=TaskFargateProperties(),
+                    path=deque(
+                        ["ContainerDefinitions", 0, "LogConfiguration", "LogDriver"]
+                    ),
+                    validator="enum",
+                    schema_path=deque(
+                        [
+                            "then",
+                            "allOf",
+                            1,
+                            "properties",
+                            "ContainerDefinitions",
+                            "items",
+                            "properties",
+                            "LogConfiguration",
+                            "then",
+                            "properties",
+                            "LogDriver",
+                            "enum",
+                        ]
                     ),
                 )
             ],