Repository: aws-cloudformation/cfn-lint

Issue:
Incorrect parameter type message for Number parameters
Receiving the error:

```
E2530 Type for Parameter should be Integer, MinValue should be at least 128, and MaxValue equal or less than 1536 at Parameters/MemorySize/Type
cloudformation/ec2/management/templates/instance-scheduler.yaml:20:5
```

The block of cloudformation it is complaining about it:

```
MemorySize:
    Type: Number
    AllowedValues:
      - 128
      - 384
      - 512
      - 640
      - 768
      - 896
      - 1024
      - 1152
      - 1280
      - 1408
      - 1536
    Default: 128
    Description: Size of the Lambda function running the scheduler, increase size when
      processing large numbers of instances
```

There is no parameter type of Integer so I don't where this error is coming from?


Discussion:
I'm almost done with this one.

Resolving patch:
diff --git a/src/cfnlint/rules/parameters/LambdaMemorySize.py b/src/cfnlint/rules/parameters/LambdaMemorySize.py
--- a/src/cfnlint/rules/parameters/LambdaMemorySize.py
+++ b/src/cfnlint/rules/parameters/LambdaMemorySize.py
@@ -26,9 +26,6 @@ class LambdaMemorySize(CloudFormationLintRule):
                   ' should have a min and max size that matches Lambda constraints'
     tags = ['base', 'parameters', 'lambda']
 
-    min_memory = 128
-    max_memory = 3008
-
     def __init__(self):
         """Init"""
         resource_type_specs = [
@@ -45,19 +42,17 @@ def check_lambda_memory_size_ref(self, value, path, parameters, resources):
 
         if value in parameters:
             parameter = parameters.get(value)
-            min_value = parameter.get('MinValue', 0)
-            max_value = parameter.get('MaxValue', 999999)
-            if min_value < self.min_memory or max_value > self.max_memory:
-                param_path = ['Parameters', value, 'Type']
-                message = 'Type for Parameter should be Integer, MinValue should be ' \
-                          'at least {0}, and MaxValue equal or less than {1} at {0}'
+            min_value = parameter.get('MinValue')
+            max_value = parameter.get('MaxValue')
+            allowed_values = parameter.get('AllowedValues')
+            if (not min_value or not max_value) and (not allowed_values):
+                param_path = ['Parameters', value]
+                message = 'Lambda Memory Size parameters should use MinValue, MaxValue ' \
+                          'or AllowedValues at {0}'
                 matches.append(
                     RuleMatch(
                         param_path,
-                        message.format(
-                            self.min_memory,
-                            self.max_memory,
-                            ('/'.join(param_path)))))
+                        message.format(('/'.join(param_path)))))
 
         return matches
 
diff --git a/src/cfnlint/rules/resources/lmbd/FunctionMemorySize.py b/src/cfnlint/rules/resources/lmbd/FunctionMemorySize.py
--- a/src/cfnlint/rules/resources/lmbd/FunctionMemorySize.py
+++ b/src/cfnlint/rules/resources/lmbd/FunctionMemorySize.py
@@ -14,6 +14,7 @@
   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 """
+import six
 from cfnlint import CloudFormationLintRule
 from cfnlint import RuleMatch
 
@@ -56,6 +57,13 @@ def check_value(self, value, path):
 
         return matches
 
+    def check_memory_size_value(self, value):
+        """ Check the memory size value"""
+        if value < self.min_memory or value > self.max_memory:
+            return False
+
+        return True
+
     def check_ref(self, value, path, parameters, resources):
         """ Check Memory Size Ref """
 
@@ -71,6 +79,46 @@ def check_ref(self, value, path, parameters, resources):
                 message = 'Type for Parameter should be Number at {0}'
                 matches.append(RuleMatch(param_path, message.format(('/'.join(param_path)))))
 
+            min_value = parameter.get('MinValue')
+            max_value = parameter.get('MaxValue')
+            allowed_values = parameter.get('AllowedValues')
+            if isinstance(allowed_values, list):
+                for allowed_value in allowed_values:
+                    if isinstance(allowed_value, six.integer_types):
+                        if not self.check_memory_size_value(allowed_value):
+                            param_path = ['Parameters', value, 'AllowedValues']
+                            message = 'AllowedValues should be between {0} and {1} at {2}'
+                            matches.append(
+                                RuleMatch(
+                                    param_path,
+                                    message.format(
+                                        self.min_memory,
+                                        self.max_memory,
+                                        ('/'.join(param_path)))))
+            else:
+                if min_value:
+                    if not self.check_memory_size_value(min_value):
+                        param_path = ['Parameters', value, 'MinValue']
+                        message = 'MinValue should be greater than {0} and equal or less than {1} at {2}'
+                        matches.append(
+                            RuleMatch(
+                                param_path,
+                                message.format(
+                                    self.min_memory,
+                                    self.max_memory,
+                                    ('/'.join(param_path)))))
+                if max_value:
+                    if not self.check_memory_size_value(max_value):
+                        param_path = ['Parameters', value, 'MaxValue']
+                        message = 'MaxValue should be greater than {0} and equal or less than {1} at {2}'
+                        matches.append(
+                            RuleMatch(
+                                param_path,
+                                message.format(
+                                    self.min_memory,
+                                    self.max_memory,
+                                    ('/'.join(param_path)))))
+
         return matches
 
     def match(self, cfn):


Test patch:
diff --git a/test/rules/parameters/test_lambda_memory_size.py b/test/rules/parameters/test_lambda_memory_size.py
--- a/test/rules/parameters/test_lambda_memory_size.py
+++ b/test/rules/parameters/test_lambda_memory_size.py
@@ -31,4 +31,4 @@ def test_file_positive(self):
 
     def test_file_negative(self):
         """Test failure"""
-        self.helper_file_negative('templates/bad/resources_lambda.yaml', 1)
+        self.helper_file_negative('templates/bad/resources_lambda.yaml', 2)
diff --git a/test/rules/resources/lmbd/test_memory_size.py b/test/rules/resources/lmbd/test_memory_size.py
--- a/test/rules/resources/lmbd/test_memory_size.py
+++ b/test/rules/resources/lmbd/test_memory_size.py
@@ -31,4 +31,4 @@ def test_file_positive(self):
 
     def test_file_negative(self):
         """Test failure"""
-        self.helper_file_negative('templates/bad/resources_lambda.yaml', 2)
+        self.helper_file_negative('templates/bad/resources_lambda.yaml', 3)
diff --git a/test/templates/bad/resources_lambda.yaml b/test/templates/bad/resources_lambda.yaml
--- a/test/templates/bad/resources_lambda.yaml
+++ b/test/templates/bad/resources_lambda.yaml
@@ -6,6 +6,27 @@ Parameters:
   myParameterMemorySize:
     Type: Number
     Description: Memory Size
+  myMemorySize2:
+    Type: Number
+    AllowedValues:
+      - 1
+      - 384
+      - 512
+      - 640
+      - 768
+      - 896
+      - 1024
+      - 1152
+      - 1280
+      - 1408
+      - 3009
+    Default: 128
+    Description: Size of the Lambda function running the scheduler, increase size when
+      processing large numbers of instances
+  myMemorySize3:
+    Type: Number
+    Description: Size of the Lambda function running the scheduler, increase size when
+      processing large numbers of instances
   myParameterRuntime:
     Type: String
     Description: Runtime
@@ -42,3 +63,17 @@ Resources:
       Role: !GetAtt LambdaExecutionRole.Arn
       Runtime: !Ref myParameterRuntime
       MemorySize: !Ref myParameterMemorySize
+  myLambda3:
+    Type: AWS::Lambda::Function
+    Properties:
+      Handler: index.handler
+      Role: !GetAtt LambdaExecutionRole.Arn
+      Runtime: !Ref myParameterRuntime
+      MemorySize: !Ref myMemorySize2
+  myLambda4:
+    Type: AWS::Lambda::Function
+    Properties:
+      Handler: index.handler
+      Role: !GetAtt LambdaExecutionRole.Arn
+      Runtime: !Ref myParameterRuntime
+      MemorySize: !Ref myMemorySize3
diff --git a/test/templates/good/resources_lambda.yaml b/test/templates/good/resources_lambda.yaml
--- a/test/templates/good/resources_lambda.yaml
+++ b/test/templates/good/resources_lambda.yaml
@@ -8,6 +8,23 @@ Parameters:
     Description: Memory Size
     MinValue: 128
     MaxValue: 1024
+  myMemorySize2:
+    Type: Number
+    AllowedValues:
+      - 128
+      - 384
+      - 512
+      - 640
+      - 768
+      - 896
+      - 1024
+      - 1152
+      - 1280
+      - 1408
+      - 1536
+    Default: 128
+    Description: Size of the Lambda function running the scheduler, increase size when
+      processing large numbers of instances
   myParameterRuntime:
     Type: String
     Description: Runtime
@@ -56,3 +73,12 @@ Resources:
         ZipFile: "amilookup.zip"
       Runtime: !Ref myParameterRuntime
       MemorySize: !Ref myParameterMemorySize
+  myLambda3:
+    Type: AWS::Lambda::Function
+    Properties:
+      Handler: index.handler
+      Role: !GetAtt myLambdaExecutionRole.Arn
+      Code:
+        ZipFile: "amilookup.zip"
+      Runtime: !Ref myParameterRuntime
+      MemorySize: !Ref myMemorySize2