銀の弾丸

プログラミングに関して、いろいろ書き残していければと思っております。

AWS SAMがAWS CLIを見失う?ならPATH設定を要チェック!

f:id:takamints:20191013125055j:plain
photo credit: dolbinator1000 Over The Hill via photopin (license)

LinuxAWS CLIをインストールしてコンソールから普通に使えていたのに、SAMでサーバーレスアプリのパッケージを作成しようとすると「AWS CLIが見つからない」というエラーが出て失敗しました。ビルドできるのになんでやねんと。

どうやら、AWS CLIのPATH設定と、AWS SAMのPATH検索方法の行き違いみたいなことで発生した問題のようでした。

目次

実行環境

$ sam --version
SAM CLI, version 0.22.0)
$
$ aws --version
aws-cli/1.16.258 Python/3.6.5 Linux/4.19.78-2-lts botocore/1.12.248
$
$ uname -srm
Linux 4.19.78-2-lts x86_64
$

sam package でエラー

sam package でパッケージを作ろうとするとエラーを履いて失敗しました。

$ sam package --s3-bucket <bucket-name> --output-template-file packaged.yaml

Error: Cannot find AWS CLI installation, was looking at executables with names: 
['aws']
$

エラーメッセージは「AWS CLIのインストールが見つからない。コマンド 名 aws を探していましたが・・・」みたいな感じ。

しかしAWS CLIはインストールしていて普通に使っている状態。

ただし aws がホームディレクトリ以下の自宅の床下みたいな所にあると言っているのが気になります。 pipで自分だけ使えるようにインストールしたから、こうなっているようです。 全ユーザーが使えるようにインストールしたならこうならない。

$ which aws
/home/<user>/.local/bin/aws

とりあえずの対策

エラーメッセージで検索すると、Close済のGitのIssueがヒットしました。 少しエラーメッセージが違っていますが、おそらく同じ問題のようです。

github.com

「とりあえず /usr/bin/usr/local/bin に上記awsコマンドを置けばOK」とありますので、シンボリックリンクを張ってみればあっさり解決・・・

[~] $ cd /usr/local/bin
[/usr/local/bin] $ sudo ln -S aws /home/<user>/.local/bin/aws
[/usr/local/bin] $ cd ~/sam-app
[~/sam-app] $ sam package --s3-bucket my-sam-app-bucket --output-template-file \
packaged.yaml


Successfully packaged artifacts and wrote output template to file packaged.yaml.
Execute the following command to deploy the packaged template
aws cloudformation deploy --template-file /home/<user>/..../packaged.yaml 
--stack-name <YOUR STACK NAME>

しかしこれ、街の通り(/usr/local/bin)から自宅の床下(~/.local/bin)につながってるようで気持ちが悪い。

正しい解決法

さらにIssueを読み進めるとヒントがひとつ。 SAMはどうやらawsのありかを自前でチェックしているらしいです。 なんでそんなことしてるのかは知りませんが、案の定PATHに含まれてる ~ を正しく解釈できないらしい。 ほら言わんこっちゃない。なんで自前でやっちゃうかな。本来それはOSに任せるべきなのでは?

まあとにかく、そういうことなので .bashrc を確認すると、・・・

.bashrc

export PATH="~/.local/bin:$PATH"

普通に ~ を使っていましたね。 結局このせいでAWS SAMはAWS CLIを見つけられず、インストールされていないなんて言っていたわけです。

以下のように ~ を使わないように修正すれば問題解決。 上に書いた /usr/local/bin からのシンボリックリンクも不要ですよ。

export PATH="/home/<user>/.local/bin:$PATH"

結構時間がかかって解決しました。

AWS SAM/CloudFormationのテンプレートでDynamoDBテーブル名をLambdaの環境変数に設定するには?

f:id:takamints:20191012145048j:plain
photo credit: SurfaceWarriors 190711-N-WI365-2119 via photopin (license)

AWS SAM/CloudFormationのテンプレートで定義されるDynamoDBのテーブル名を、同じくテンプレート内に定義したLambda関数の環境変数に設定する方法です。

WEB+DB PRESS Vol.113
WEB+DB PRESS Vol.113
posted with amazlet at 19.10.12
野田 奏 小原 一哉 西岡 忍 木村 奈美 澤田 剛 成瀬 允宣 松岡 幸一郎 藤井 謙士朗 井上 真史 山口 慶子 池田 拓司 小山 哲志 末永 恭正 久保田 祐史 鈴木 恭介 牧 大輔 笹田 耕一 松本 宏太 尾形 鉄次 はまちや2 竹原 渡辺 淳 岩井 良太 吉田 健太
技術評論社
売り上げランキング: 1,406

目次

はじめに

SAM/CloudFormationのテンプレートで、テーブル名を指定せずにDynamoDBのテーブルリソースを定義すると、サーバーレスアプリの初回デプロイ時に自動的に命名されます。

このテーブル名には、SAMのアプリ名やリソース名に加えて、デプロイ時にハッシュみたいな一意なIDが使われますので、Lambdaの実装時には不明です。

テンプレートでは、DynamoDBのテーブルリソースを参照することで、まだ作成されていないテーブル名をLambdaの環境変数に設定できます。 Lambda関数では、テーブル名を環境変数から取得すればOKですね。

ということで、その書き方を以下で説明いたします。

テンプレートでLambdaの環境変数を設定する

テンプレートでLambda関数の環境変数を宣言するには、リソースの Properties/Environment/Variables に、 <環境変数名>: <環境変数の値> と記述します。 例ではリソースTypeが AWS::Serverless::Function となっていますが、AWS::Lambda::Function でも同じはず。

template.yaml

Resources:
  #サーバーレス関数の定義(API Gateway REST API+Lambda Function)
  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      Environment:
        #環境変数の宣言
        Variables:
          <環境変数名>: <環境変数の値>

環境変数にDynamoDBテーブル名を設定する

Lambdaの環境変数にDynamoDBのテーブル名を設定するには、<環境変数の値>!Ref <DyanamoDBリソース名> とします。

※ DynamoDBリソースでテーブル名をProperties/TableNameで明示的に指定していても同様に参照可能です。

template.yaml

Resources:
  #サーバーレス関数の定義(API Gateway REST API+Lambda Function)
  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      Environment:
        Variables:
          #↓DynamoDBテーブルのテーブル名を参照
          TableName: !Ref DynamoDBTable
   ・
   ・
   ・
  #DynamoDBテーブルリソースの宣言
  DynamoDBTable:
    Type: AWS::DynamoDB::Table
    Properties:
  ・
  ・
  ・

デプロイするとLambda関数の設定で、こう(↓)なります。

f:id:takamints:20191012220304p:plain

おまけ:Lambda関数実行時に環境変数を参照する

Node.js の Lambda で実行時に<環境変数の値>を参照するには process.env["<環境変数名>"] とします。

const tableName = process.env["TableName"];

f:id:takamints:20191012215355p:plain

Pythonならば、import os でosモジュールをインポートして os.environ['<環境変数名>'] です。

import os
tableName = os.environ['TableName'];

参考リンク

docs.aws.amazon.com

docs.aws.amazon.com

Git BashやMSYS2の行頭で、Tab押しちゃって固まっちゃった時の対処法

f:id:takamints:20190930203227j:plain
photo credit: verchmarco Close-up of the On / Off Button and Laptop keyboard via photopin (license)

少なくとも、ひと月に1記事は書こうとしていたのですが、2週間前に交通事故に遭っちゃいまして、1週寝込んでさらに1週、痛みと後遺障害の予感に怯えて過ごして全く書けず。気づけば9月最終日。慌てて小ネタを出しておきます。

ごめんじゃすまない! 自転車の事故 (GEIBUN MOOKS 暮らしの落とし穴から守る本)
むさしの森 法律事務所 岡田正樹
芸文社 (2016-07-21)
売り上げランキング: 149,055

ということで、コンソールでたまに頭を悩ませる困ったことの解消法。

環境によるかも知れませんが、 Git Bash (Git for Windows 同梱の MSYS2) の行頭(何も入力していない状態の入力待ち)で Tab を入力してしまうと、結構長時間無反応になっちゃいます。

ハングしているわけではないので、実はしばらく待つと戻ってきます(特に2回目以降はキャッシュされているのか、それなりに早く戻ってきますね)。 Bash のコマンド入力補完機能がPATH上にある全コマンドを列挙していると思っていますが・・・。

これ、即刻復帰させるには、CTRL+Cを押してからコンソールのウィンドウサイズを変えればOKなんですよ。

なんでそうなるのかは全くわかっていませんが・・・(そのうち調べておきます)。