sumikko engineer blog

すみっこが落ち着くエンジニアのブログです。

AWS cloudwatchlogsのサブスクリプションフィルターのlambdaテスト

AWSのcloudwatchlogsのサブスクリプションフィルターから呼び出されるlambdaをテストするときにやりにくかったのでメモ。

  • 本家マニュアルのお言葉
サブスクリプションフィルタを介して宛先サービスに送信されるログは、Base64 でエンコードされ、gzip 形式で圧縮されます。
  • lambdaでテストするときに出てくるcloudwatchlogsの形式
{
  "awslogs": {
    "data": "BASE64ENCODED_GZIP_COMPRESSED_DATA"
  } 
}

gzipした後にbase64エンコーディングする。messageの箇所にエラーメッセージを入れる。

require 'base64'
require 'zlib'

str = <<JSON
{"messageType":"DATA_MESSAGE","owner":"123456789123","logGroup":"testLogGroup","logStream":"testLogStream","subscriptionFilters":["testFilter"],"logEvents":[{"id":"eventId1","timestamp":1440442987000,"message":"hogehogeエラーメッセージ"}]}
JSON

# gzip作成
Zlib::GzipWriter.open('./gzip/gzip.gz') {|gz|
  gz.write str
}

# base64でエンコード
cloudwatchlogs_params = Base64.encode64(File.read('./gzip/gzip.gz'))
p cloudwatchlogs_params
  • dataに標準出力された値を入力してテストデータを作成
{
  "awslogs": {
    "data": "H4sIAJTHuWAAA0VPOwrCQBDtPcbUKRJdjdoFjCJoFTsRiTrEhSQbdldFgk32\nJHZ6A0FvsxdxEhWLgffjzUwJGSoVJ7g4FwhDGAWLYD0PoyiYhOCAOOUoSfba\nHdbt+f0BAZJTkUykOBTkaFR69qONE2mJcfa3vtwBddioreSF5iIf81SjVDBc\nNrEPhVVTEB4x17VVAt9RD9Z8uvOoQnM6V8cZbfYYcxlrD/q+67rO7w2K70WC\n9djqZs3dmpc1V2uMrZ41rh5wWV1ab4fCX2T4AAAA\n"
  }
}

eclipse

  • 基本設定
// コメントの日本語が文字化け
一般 > 外観 > 色とフォント > テキストフォント > 日本語に対応したフォント(MS ゴシックなど)

// タブ・空白を表示
一般 > エディター > テキストエディター > 空白文字を表示にチェック

// gitの差分表示
ウィンドウ > 一般 > エディタ > テキストエディター > クイックDiffで使用する参照ソースを「Gitリヒビジョン」に変更。

// 保存時にフォーマットを適用
設定 > Java > エディター > 保管アクション
  • 文字化け対応

ワークスペース文字コードutf-8に設定してもeclipseがshif-jisで勝手に解釈してくれるので文字化けしてしまう場合の対応 eclipse.iniに「-Duser.language=en」を追記する。

dockerコンテナからhostにリクエストできるようにする

dokcer-composeでアプリを立ち上げていましたが、外部サービスにアクセスする処理にスタブサーバーを使いたかったので対応しました。docker-composeに組み込んでもいいのですが、それをやるほどではなかったので組み込まなかったです。

ifconfigなどを使用してプライベートIPアドレスを取得しておく

  • docker_compose.ymlに追記

ホストにリクエストしたいコンテナの設定に下記の設定を追記する。

extra_hosts:
  - "stub_server:取得したプライベートIPアドレス"
  • 実行確認

コンテナ内でcurl stub_server:8000/getのようにして実行確認を行う。

extra_hostsはコンテナの /etc/hosts ファイルにホストを追加する設定です。ホストからコンテナのリクエストの設定なのでportの設定を「8080:8000」のようにしただけだと通信できませんでした。またhost.docker.internalというDNS名も用意されていますが、これはDocker Desktop For Mac/Windowsの設定なのでWSLで起動しているdockerには効きませんでした。

https://docs.docker.jp/compose/compose-file.html#extra-hosts

Javascript/Date.toJSON

日付をJavascriptで取得してサーバーにリクエストしたときに日付がずれてしまったので、その対応。原因はtoJSONメソッドを呼ぶとUTCに変換されてしまうため。そのため日付にJST分足して対応した。下記の例は2020-11-25日に実行。

const now = new Date();
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate())

console.log(today.toJSON());
today.setHours(today.getHours() + 9)
console.log(today.toJSON());

# 出力結果
> "2020-11-24T15:00:00.000Z"
> "2020-11-25T00:00:00.000Z"

developer.mozilla.org

Pseudo-terminal will not be allocated because stdin is not a terminal

デプロイタスクを書いていたらエラーが発生しました。sshを多段階で実行したら最後に実行した箇所で端末が割り当てられないのが原因だそうです。-tオプションを付ければいいのですが、実行してもうまくいかないことがあります。その場合は-tオプションを重ねると強制的に端末が割り振られます。

ssh -t -t  user@host command

このWi-Fiネットワークでは、以前のセキュリティ標準が使用されています。別のネットワークに接続することをお勧めします

wifiが突然落ちて、もう一度つなごうとしたら「このWi-Fiネットワークでは、以前のセキュリティ標準が使用されています。別のネットワークに接続することをお勧めします」が出てきました。もう一度つないでもちょくちょく落ちていくので、下記の対応をしました。

  1. wifiにログイン
  2. セキュリティの暗号化設定を「AES +TKIP」から「AES」のみに変更
  3. wifi再起動
  4. PCからwifiにもう一度つなぎにいく。

Windowsアップデートでセキュリティレベルが引き上げられたのが原因っぽい。

jenkins/pipeline

最低限動かすのに必要なスクリプトのメモ。 cronの設定やビルド数の制御などもjenkinsファイルにそのまま書いたほうがGUIで入力しなくて済むしポータブル。 postセクションの「failure」は失敗したときのみ実行される。「cleanup 」はステップの成否にかかわらず実行される。 失敗したら一部だけリトライ処理をしたいときはscriptをそのまま書くことで対応(プラグイン探すのめんどくさいし)

pipeline {
    agent any
    triggers {
        cron('H/15 * * * *')
    }
    options {
        buildDiscarder(logRotator(numToKeepStr: '10'))
    }
    parameters {
        string(name: 'ID', defaultValue: 'id', description: ID')
        password(name: 'PASS', defaultValue: 'pass', description: 'PASS')
    }
    stages {
        stage('build') {
            steps {
                sh 'echo "build step"'
            }
        }
        stage('test') {
            steps {
                script {
                    try {
                      sh 'echo "test step"'
                    } catch(e) {
                        retry(2) {
                           sh "retry step"
                        }
                    }
                }
            }
        }
        stage('user input test') {
            steps {
                script {
                    try {
                        input message: 'このまま処理を進めますか?', ok: 'OK'
                    } catch(e) {
                        echo "中断しました。"
                        return
                    }
                }
            }
        }
    }
    post {
        failure {
            sh 'echo "failed"'
        }
        cleanup {
            sh 'always success or failed'
        }
    }
}