CodeBuildでSpecify either 'DefinitionUri' or 'DefinitionBody' property and not both

# DefinitionBodyは書いているのに怒られた

AWS SAMを使用したデプロイを行っていて、ドハマリしたのでメモを共有します

## 前提環境

- クロスリージョン&クロスアカウントなサーバレスアプリケーションのデプロイをSAMで行う
    - CodeCommit
    - CodePipeline
    - CodeBuild
        - AmazonLinux node4.4.6 (eb-nodejs-4.4.6-amazonlinux-64:2.1.3)

## 現象

### CloudFormationテンプレート
下記のようなCloudFormationテンプレートを作成

```template.yaml
  HelloFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: hello.handler
      Runtime: nodejs6.10
      CodeUri: ./src/
  Api:
    Type: AWS::Serverless::Api
    Properties:
      StageName: !Ref Stage
      DefinitionBody:
        swagger: "2.0"
        info:
          version: "1.0"
          title: "HelloApi"
        schemes:
        - https
        basePath: !Sub /${Stage}
        paths:
          /hello:
            get:
              x-amazon-apigateway-integration:
                uri: !Sub  "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HelloFunction.Arn}/invocations"
                passthroughBehavior: "when_no_match"
                httpMethod: "POST"
                type: "aws_proxy"
```

### CodeBuild
CodeBuildでテスト＆デプロイを行う

```buildspec.yml
version: 0.1

phases:
  install:
    commands:
      - curl -o /usr/local/bin/jq -L https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64 && chmod +x /usr/local/bin/jq
      - mkdir ~/.aws
      - aws sts assume-role --role-arn ${DEV_CFN_ROLE} --role-session-name codebuild | jq -r '"[default]\naws_access_key_id = \(.Credentials.AccessKeyId)\naws_secret_access_key = \(.Credentials.SecretAccessKey)\naws_session_token = \(.Credentials.SessionToken)\n"' >> ~/.aws/credentials
      - cd test && npm install && npm install -g mocha
  pre_build:
    commands:
      - echo Test Started on `date`
      - cd test && mocha test.js | tee test.log
  build:
    commands:
      - echo Build started on `date`
      - aws cloudformation --region ap-northeast-1 package --template-file template.yaml --s3-bucket ${DEV_SAM_BUCKET} --output-template-file outputTemplate.yaml
      - aws cloudformation --region ap-northeast-1 deploy --template-file outputTemplate.yaml --stack-name ${PROJECT_ID} --capabilities CAPABILITY_IAM --parameter-overrides Stage=${STAGE}
  post_build:
    commands:
      - echo Build completed on `date`
artifacts:
  files:
    - '**/*'
```

### 実行結果

```
[Container] 2017/04/29 02:07:51 Waiting for changeset to be created..
[Container] 2017/04/29 02:08:02 Failed to create the changeset: Waiter ChangeSetCreateComplete failed: Waiter encountered a terminal failure state Status: FAILED. Reason: Transform AWS::Serverless-2016-10-31 failed with: Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [Api] is invalid. Specify either 'DefinitionUri' or 'DefinitionBody' property and not both
```

template.yamlにはDefinitionBodyが正しく入っているのに怒られた！

## 解決

https://github.com/awslabs/serverless-application-model/issues/93

**aws-cliのバグだったΣ(ﾟДﾟ)**

### buildspec.ymlの修正

使っていたCodeBuildコンテナのaws-cliが古いことが原因だったようなので、上記issueにも記載の通り、aws-cliをアップデートしてあげる

```buildspec.yml
version: 0.1

phases:
  install:
    commands:
      - pip install --upgrade awscli
      - curl -o /usr/local/bin/jq -L https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64 && chmod +x /usr/local/bin/jq
      - mkdir ~/.aws
      - aws sts assume-role --role-arn ${DEV_CFN_ROLE} --role-session-name codebuild | jq -r '"[default]\naws_access_key_id = \(.Credentials.AccessKeyId)\naws_secret_access_key = \(.Credentials.SecretAccessKey)\naws_session_token = \(.Credentials.SessionToken)\n"' >> ~/.aws/credentials
      - cd test && npm install && npm install -g mocha
  pre_build:
    commands:
      - echo Test Started on `date`
      - cd test && mocha test.js | tee test.log
  build:
    commands:
      - echo Build started on `date`
      - aws cloudformation --region ap-northeast-1 package --template-file template.yaml --s3-bucket ${DEV_SAM_BUCKET} --output-template-file outputTemplate.yaml
      - aws cloudformation --region ap-northeast-1 deploy --template-file outputTemplate.yaml --stack-name ${PROJECT_ID} --capabilities CAPABILITY_IAM --parameter-overrides Stage=${STAGE}
  post_build:
    commands:
      - echo Build completed on `date`
artifacts:
  files:
    - '**/*'
```

### 実行結果

```
[Container] 2017/04/29 04:03:34 Waiting for changeset to be created..
[Container] 2017/04/29 04:03:45 Waiting for stack create/update to complete
[Container] 2017/04/29 04:04:16 Successfully created/updated stack - helloproject
```
無事デプロイ出来ました

## 教訓
パッケージはアップデートしてから使いましょう。。。