cfn-python-lint

先日 [yamllintのconfig](https://qiita.com/komeda-shinji/items/bc88d6ba6e5673988f00) という記事を書きましたが、CloudFormation のテンプレートをチェクしたいなら、cfn-python-lint (https://github.com/awslabs/cfn-python-lint) をおすすめします。

CloudFormation テンプレートの文法チェックだけでなく、セマンティック・チェックもしてくれます。

cfn-lint という npm モジュールがあるため、名前の衝突をさけてか、cfn-python-lint となっていますが、パッケージ名、実行コマンドは、ともに `cfn-lint` になります。

# インストール

```
$ pip install cfn-lint
```

# ヘルプ

```Console
usage: cfn-lint [-h] [-t TEMPLATE [TEMPLATE ...]] [-b] [-d]
                [-f {quiet,parseable,json}] [-l] [-r REGIONS [REGIONS ...]]
                [-a APPEND_RULES [APPEND_RULES ...]]
                [-i IGNORE_CHECKS [IGNORE_CHECKS ...]]
                [-c INCLUDE_CHECKS [INCLUDE_CHECKS ...]] [-o OVERRIDE_SPEC]
                [-v] [-u]
                [TEMPLATE [TEMPLATE ...]]

CloudFormation Linter

optional arguments:
  -h, --help            show this help message and exit

Standard:
  TEMPLATE              The CloudFormation template to be linted
  -t TEMPLATE [TEMPLATE ...], --template TEMPLATE [TEMPLATE ...]
                        The CloudFormation template to be linted
  -b, --ignore-bad-template
                        Ignore failures with Bad template
  -f {quiet,parseable,json}, --format {quiet,parseable,json}
                        Output Format
  -l, --list-rules      list all the rules
  -r REGIONS [REGIONS ...], --regions REGIONS [REGIONS ...]
                        list the regions to validate against.
  -i IGNORE_CHECKS [IGNORE_CHECKS ...], --ignore-checks IGNORE_CHECKS [IGNORE_CHECKS ...]
                        only check rules whose id do not match these values
  -c INCLUDE_CHECKS [INCLUDE_CHECKS ...], --include-checks INCLUDE_CHECKS [INCLUDE_CHECKS ...]
                        include rules whose id match these values
  -v, --version         Version of cfn-lint

Advanced / Debugging:
  -d, --debug           Enable debug logging
  -a APPEND_RULES [APPEND_RULES ...], --append-rules APPEND_RULES [APPEND_RULES ...]
                        specify one or more rules directories using one or
                        more --append-rules arguments.
  -o OVERRIDE_SPEC, --override-spec OVERRIDE_SPEC
                        A CloudFormation Spec override file that allows
                        customization
  -u, --update-specs    Update the CloudFormation Specs

```

# つかいかた

テストに使ったテンプレートはこのようなものです。

```sample.yaml     
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: |
  API Gateway Custom Integration Template
Globals:
  Function:
    Timeout: 30
Parameters:
  LambdaFuncArn:
    Type: String
  LambdaApiId:
    Type: String
  LambdaAPIRootResourceId:
    Type: String
Resources:
  LambdaAPIRootPost:
    Type: 'AWS::ApiGateway::Method'
    Properties:
      AuthorizationType: NONE
      ResourceId: !Sub ${LambdaAPIRootResourceId}
      RestApiId: !Sub ${LambdaApiId}
      HttpMethod: POST
      Integration:
        Type: AWS
        Uri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaFuncArn}/invocations'
        IntegrationHttpMethod: POST
        IntegrationResponses:
          - StatusCode: 200
            ResponseTemplates:
              application/json: ""
        ContentHandling: CONVERT_TO_TEXT
        PassthroughBehavior: WHEN_NO_TEMPLATES
        RequestTemplates:
          application/x-www-form-urlencoded: |
            {
                "headers": {
            #foreach($key in $input.params().header.keySet())
                   "$key": "$input.params().header.get($key)"#if($foreach.hasNext),#end
            #end
                },
                "body": $input.json("$")
            }
      MethodResponses:
        - StatusCode: 200
```

```
$ cfn-lint sample.yaml
E3012 Property Resources/LambdaAPIRootPost/Properties/Integration/IntegrationResponses/0/StatusCode should be of type String
sample.yaml:28:13

E3012 Property Resources/LambdaAPIRootPost/Properties/MethodResponses/0/StatusCode should be of type String
sample.yaml:44:11

```

StatusCode の値は文字列であるべきと指摘されています。yamllint では文法チェックしてかできないのに対し、cfn-lint ではこのようなセマンティックのチェックもしてくれます。

```diff
--- sample.yaml	2018-10-24 15:55:32.000000000 +0900
+++ sample.yaml	2018-10-24 16:03:47.000000000 +0900
@@ -25,7 +25,7 @@
         Uri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaFuncArn}/invocations'
         IntegrationHttpMethod: POST
         IntegrationResponses:
-          - StatusCode: 200
+          - StatusCode: '200'
             ResponseTemplates:
               application/json: ""
         ContentHandling: CONVERT_TO_TEXT
@@ -41,4 +41,4 @@
                 "body": $input.json("$")
             }
       MethodResponses:
-        - StatusCode: 200
+        - StatusCode: '200'
```

指摘されたところを修正すると警告は出なくなりました。

```
$ yamllint sample.yaml
$
```