ぴよ丸水産

週末ファゴッティストによる技術ブログ

【Jenkins】JenkinsからJMeterで負荷試験をやってみる

はじめに

JenkinsからJMeterを使用した負荷試験をやってみました。
JMeter全然使いこなせてないウーマンですが、
そのあたりは目をつむって。。
Jenkinsでこう設定すると、こんな感じで実行できて、こんな風に結果が見えます、
をざっくりまとめてみました。

pythonもろもろのバージョンなど、環境特有のものかもですが、
いろいろトラブったのでおまけでトラブルシュートの軌跡をメモしておきました。
トラブルシュートは相変わらずパワープレーですが、悪しからず。。

目次

環境情報

項目
OS RHEL7
Python 2.7.5
Jenkins 2.138.2
Jenkins Performance Plugin 3.1.17
Apache JMeter 5.1.1

要件

  • GitLabのPerformansTest.gitにjmxファイルを格納しておく
  • Jenkinsジョブを実行すると、最新masterのjmxファイルがテストシナリオとして試験が実行される

JenkinsにPerformance Plugin追加

plugins.jenkins.io

JenkinsからJMeterによる負荷試験実行するために、
Performance Pluginをインストールします。

Performance PluginはTaurusという自動テストフレームワークから
Jmeterなどのテストツールを実行する仕組みのようです。

gettaurus.org

プラグインのインストールは、下記の方法で行いました。

  1. Performance Pluginにアクセスし、Archivesをクリック
  2. 3.17をクリックしてダウンロード
  3. ダウンロードしたperformance.hpiをJenkinsにアップロード
    • Jenkinsの管理->プラグインの管理->高度な設定タブ->プラグインのアップロード

f:id:blue-38:20200519173032p:plain

ジョブの作成

新規ジョブの作成を押下し、フリースタイル・プロジェクトのビルドを選択し、
新規ジョブを作成します。

ソースコードの管理

ディレクトリに固定で置いても良いと思いますが、
今回Gitで試験シナリオを定義したJmxファイルを管理する構成にしてみたので、
下記のように設定しました。

f:id:blue-38:20200519173059p:plain

ビルド

ビルド手順の追加からRun Performance Testを選択します。

f:id:blue-38:20200519173127p:plain

Taurus tool parameters:に実行するJmxファイル名を指定します。

f:id:blue-38:20200519173147p:plain

そのほかの項目はデフォルトから変えていないですが、
Automatically generate performance reportは結果出力に必要なパラメータのようです。

ビルド後の処理

ビルド後の処理の追加からPublish Performance test results reportを選択します。

f:id:blue-38:20200519173226p:plain

Source data files (autodetects format):**/*.jtlを指定します。
それ以外はデフォルトのままです。

f:id:blue-38:20200519173210p:plain

ジョブの実行結果

#(ジョブの実行No)をクリックして、Performance Reportをクリックすると表示されます。

Jmxファイルの内容によるので、参考程度ですが、
こんな感じに出力されました。
今回の実行結果+過去結果からの推移が可視化されるようです。

f:id:blue-38:20200519173239p:plain

おわりに

JMeterを使い込んでないので、
JMeter単体で使う場合とのギャップを語ることはできませんが、
下記3点がポイントだと思います。

  • GitLabでテストシナリオをバージョン管理
  • スケジュール実行可
  • Jenkinsで試験結果推移の可視化

おまけ:トラブルシュート

私の検証環境特有の問題だと思うので、別出しでまとめました。
あとコンソールログが消えちゃったりしたので、ふわっと書いてます。

bztvirtualenvpip installしろやと言われ、ジョブエラー

すみません、ジョブのコンソールログ消えちゃいました。
手動でbztインストールを試行しました。
virtualenvはすんなりはいりましたが、
ジョブ動かしたら結局venvした先でbztがインストールできず詰んだ
(プロキシの関係かな、、あきらめたので未調査)ので、
bztインストールしました。

pip install bzt
DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. A future version of pip will drop support for Python 2.7. More details about Python 2 support in pip, can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support
Collecting bzt
  Downloading bzt-1.13.9-py2.py3-none-any.whl (311 kB)
     |????????????????????????????????| 311 kB 2.3 MB/s

~(略)~

Collecting Appium-Python-Client
  Downloading Appium-Python-Client-1.0.0.tar.gz (51 kB)
     |????????????????????????????????| 51 kB 285 kB/s
    ERROR: Command errored out with exit status 1:
     command: /usr/bin/python -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-b0nYvk/Appium-Python-Client/setup.py'"'"'; __file__='"'"'/tmp/pip-install-b0nYvk/Appium-Python-Client/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base /tmp/pip-install-b0nYvk/Appium-Python-Client/pip-egg-info
         cwd: /tmp/pip-install-b0nYvk/Appium-Python-Client/
    Complete output (8 lines):
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-install-b0nYvk/Appium-Python-Client/setup.py", line 19, in <module>
        from appium.common.helper import library_version
      File "appium/common/helper.py", line 20
        def extract_const_attributes(cls: type) -> Dict[str, Any]:
                                        ^
    SyntaxError: invalid syntax
    ----------------------------------------
ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.
WARNING: You are using pip version 20.0.2; however, version 20.1 is available.
You should consider upgrading via the '/usr/bin/python -m pip install --upgrade pip' command.

Appium-Python-Clientのインストールでこけているようです。

https://pypi.org/project/Appium-Python-Client/

Notice
Since v1.0.0, only Python 3 is supported

とのことなので、Python2も対応してるバージョンをインストールしました。

# pip install Appium-Python-Client==0.51

さっきとは違うエラーが出てきました。

Collecting Appium-Python-Client==0.51
  Downloading Appium-Python-Client-0.51.tar.gz (56 kB)
     |????????????????????????????????| 56 kB 445 kB/s
    ERROR: Command errored out with exit status 1:
     command: /usr/bin/python -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-Docu3L/Appium-Python-Client/setup.py'"'"'; __file__='"'"'/tmp/pip-install-Docu3L/Appium-Python-Client/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base /tmp/pip-pip-egg-info-C2pD_b
         cwd: /tmp/pip-install-Docu3L/Appium-Python-Client/
    Complete output (5 lines):
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-install-Docu3L/Appium-Python-Client/setup.py", line 37, in <module>
        packages=find_packages(include=['appium*']),
    TypeError: find_packages() got an unexpected keyword argument 'include'
    ----------------------------------------
ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.

https://github.com/appium/python-client/issues/397

同じことて困ってる人いました。
私もsetuptoolsのバージョンが低いのかな。。。と思い。

# pip show setuptools
Name: setuptools
Version: 0.9.8
Summary: Easily download, build, install, upgrade, and uninstall Python packages
Home-page: https://pypi.python.org/pypi/setuptools
Author: Python Packaging Authority
Author-email: distutils-sig@python.org
License: PSF or ZPL
Location: /usr/lib/python2.7/site-packages
Requires:
Required-by:

上げてみました。怖いくらい上がってしまった。

# pip install -U setuptools
pip install -U setuptools
DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip, can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support
Collecting setuptools
  Downloading setuptools-44.1.0-py2.py3-none-any.whl (583 kB)
     |????????????????????????????????| 583 kB 409 kB/s
Installing collected packages: setuptools
  Attempting uninstall: setuptools
    Found existing installation: setuptools 0.9.8
    Uninstalling setuptools-0.9.8:
      Successfully uninstalled setuptools-0.9.8
Successfully installed setuptools-44.1.0

もう一度bztインストール試行!
先に進めてエラーが変わりました。

ERROR: Cannot uninstall 'chardet'. It is a distutils installed project and thus we cannot accurately determine which files belong to it which would lead to only a partial uninstall.

https://stackoverflow.com/questions/49915951/cannot-uninstall-chardet

こちらを参考にchardetを一回消しました。
もう一度bztインストール試行!
ようやくbztインストールできました。

# pip show bzt
Name: bzt
Version: 1.13.9
Summary: Taurus Tool for Continuous Testing
Home-page: http://gettaurus.org/
Author: Andrey Pokhilko
Author-email: andrey@blazemeter.com
License: Apache 2.0
Location: /usr/lib/python2.7/site-packages
Requires: nose, requests, pytest, terminaltables, psutil, fuzzyset, progressbar33, astunparse, pyvirtualdisplay, gevent, colorlog, cssselect, selenium, pyyaml, apiritif, lxml, hdrpy, ipaddress, colorama, urwid, Appium-Python-Client
Required-by:

JMeterのインストール失敗

もう一度ジョブ流してみました。

11:36:23 INFO: Taurus CLI Tool v1.13.9
11:36:23 INFO: Starting with configs: ['/var/lib/jenkins/workspace/Execute_Performance_Test/jenkins-report.yml', '/tmp/jmx_HIaZOv.json']
11:36:23 INFO: No personal config found, creating one at /var/lib/jenkins/.bzt-rc
11:36:23 INFO: Configuring...
11:36:23 INFO: Artifacts dir: /var/lib/jenkins/workspace/Execute_Performance_Test/2020-05-19_11-36-23.694021
11:36:23 INFO: Preparing...
11:36:24 INFO: Will install JMeter into /var/lib/jenkins/.bzt/jmeter-taurus/5.1.1
11:36:33 WARNING: Failed to check for updates
11:36:34 ERROR: Can't fetch https://jmeter.apache.org/download_jmeter.cgi
11:36:34 INFO: Downloading: https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-5.1.1.zip
11:36:39 ERROR: Error while downloading https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-5.1.1.zip: Unsuccessful download from https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-5.1.1.zip
11:36:39 ERROR: Internal Error: JMeter download failed: No more links to try
11:36:39 INFO: Post-processing...
11:36:39 INFO: Artifacts dir: /var/lib/jenkins/workspace/Execute_Performance_Test/2020-05-19_11-36-23.694021
11:36:39 WARNING: Done performing with code: 1
Build step 'Run Performance Test' changed build result to FAILURE
Creating parser with percentiles:'0,50,90,100,' filterRegex:
Performance: Recording JMeter reports '**/*.jtl'
Performance: No threshold configured for making the test unstable
Performance: No threshold configured for making the test failure
Started calculate disk usage of build
Finished Calculation of disk usage of build in 0 seconds
Started calculate disk usage of workspace
Finished Calculation of disk usage of workspace in 0 seconds
Finished: FAILURE

JMeterのインストールで止まりました。
プロキシ配下の環境のため、Jenkinsを通してインストールできていないのかもしれません。
(このへん、切り分けてないです)
パワープレーですが、
/var/lib/jenkins/.bzt/jmeter-taurus/5.1.1(ディレクトリは自分で掘りました)に、

# wget https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-5.1.1.zip

で取得したzipファイルを解凍してソースを配置すれば、動きます。
所有者や権限は気を付けてください。

【Redmine】プラグイン紹介 その2

はじめに

Redmine4.1.0に入れてお試ししてみたプラグインを紹介します。
その2です。

目次

環境

Redmine Work Time Plugin

バージョン 公式URL
0.4.0 https://www.redmine.org/plugins/redmine_work_time

工数管理をサポートするプラグインです。
ユーザ別に何のタスクにどのくらい工数をかけているかを見える化できます。
Redmine絶対神としてタスク管理しているPJは、
稼働管理表がRedmineで自動的に生成できるので、効果を発揮すると思います。

Pluginの話をする前に、
Redmineにデフォルトで入っている作業時間管理機能を見ておきましょう。

Redmineの工数管理機能 | Redmine.JP Blog

  • 一覧

f:id:blue-38:20200416115607p:plain

各個人がどのタスクにいつどれだけ工数をかけたのか、
わからないこともないですが、
カレンダー風にサマってくれてる方がユーザ的には嬉しいのかなと思います。

  • 入力画面

時間を記録ボタンを押下すると入力画面に遷移します。

f:id:blue-38:20200416115727p:plain

チケットの編集画面からでも入力できます。

f:id:blue-38:20200416115743p:plain

ユーザ的には、一日の終わりにまとめてつけたかったりするので、
いちいちチケット番号検索したり、
チケットにアクセスしたりが若干面倒な気がします。

そこで、Work Time Pluginを入れると、、、(ここからが本題)
工数タブからこの画面が見えます。

f:id:blue-38:20200416115856p:plain

一覧と入力画面は1画面に収まってます。
日毎工数-YYYY-MM-DDのところにアサインされてるタスクが並んでるので、
その日働いた工数を記録して、更新ボタンを押せば一覧に反映されます。

ロールに紐づく権限(管理ロールと権限)を操作して、
ほかの人の工数の読み書きができるようになります。
f:id:blue-38:20200416120303p:plain
このプルダウンでユーザを切り替えできます。
f:id:blue-38:20200416120158p:plain

個人単位のサマリが見やすくなったのがポイントだと思います。

さらに、月間集計表も出せます。
f:id:blue-38:20200416120317p:plain

付け替え設定もできるようで、、
PJ管理の経験がないので利用シーンが思いつきませんが、
外見せをよくするために工作するときに使うのかな?
ごにょごにょできるみたいです。

付け替えた月間集計と付け替えないバージョンの月間集計、
どちらも表示可能です。

おわりに

Redmine Work Time Pluginのポイントは、以下の通りです。

  • 入力UIがいい感じ
  • 個人単位のサマリが見やすい
  • 月間集計の出力ができる

【Redmine】プラグイン紹介 その1

はじめに

Redmine4.1.0に入れてお試ししてみたプラグインを紹介します。
そんな使いこんでるわけでもないので、
どんな風に使うのかは半分想像ですが。。
たくさん書こうと思ってましたが、
試したやつ全部書くとけっこうボリューミーになるので、 シリーズ化します。

目次

環境

Redmine Banner

バージョン 公式URL
0.3.1 https://www.redmine.org/plugins/redmine_banner

Redmineのユーザへ一斉通知するプラグインです。
プラグインを入れると上部に「バナー」のメニューが追加されます。

f:id:blue-38:20200409173656p:plain

プロジェクトのタブにも追加されます。

f:id:blue-38:20200409173900p:plain

設定画面は以下の通りです。

f:id:blue-38:20200409174531p:plain

項目名 説明
表示対象 誰に表示するか(ログインしてる人?してない人?全員?)
メッセージタイプ メッセージの重要度(アイコンが変わる)
表示位置 ヘッダORフッタOR両方/ログインページのみ
バナーメッセージ 表示するメッセージ。マークダウンで書ける!
リンク [詳細]のリンク先に設定される
表示期間 バナーを出す期間を設定できる

有効にする□にチェックして、適用を押下すると、

こんな風に表示されます。

f:id:blue-38:20200409173931p:plain

一番下のバナー管理者グループっていうのは、
バナーで通知できる人を所属させるグループです。
GlobalBanner_Adminグループに一般ピーポを所属させてみると、
その人もバナーのメニューから通知出せるようになってました。

Redmine Issue Templates

バージョン 公式URL
1.0.1 https://www.redmine.org/plugins/redmine_issue_templates

チケットの書き方って、センスが問われるもので、
人によって書きっぷりが違ってきてしまうことって多々ありますよね。
このプラグインを使えば、
説明欄の定型文などをテンプレートとして登録できます。
多少チケットの書きっぷり問題は解決するのではないかと思われます。

テンプレートはRedmine全体(グローバル)でも管理できるし、
プロジェクトごとにも管理できます。

グローバルのテンプレートは管理->グローバルチケットテンプレートから

f:id:blue-38:20200409173428p:plain

プロジェクトごとのテンプレートはチケットテンプレートタブから

f:id:blue-38:20200409173540p:plain

設定画面は以下の通りです。

f:id:blue-38:20200409174032p:plain

項目名 説明
テンプレート名 テンプレート名(そのままですね)
トラッカー テンプレートを適用するトラッカー
チケットタイトル タイトルも任意でテンプレート化できる。接頭に【XXXX】つけるとか、よくありそう
チケット本文 ここにテンプレート(定型文、見出しなど)を定義
メモ このテンプレートに対するメモ
関連リンク テンプレートの利用例とか、テンプレートに対する参考情報のリンク
関連リンクのタイトル リンクにタイトルつけられる
デフォルト値 有効にすると、新規チケット作成でトラッカーを選択した瞬間テンプレートが反映される
有効 新規チケット作成の時に選べるようにするためには有効にする

新規チケット作成で、
テンプレートを選ぶと、

登録したテンプレートが呼び出せます。

f:id:blue-38:20200409174045p:plain

おわりに

知られざる便利プラグインはまだまだたくさんある気がするので、
ほかにもいろいろ試そうかと思います。

すでに入れてるプラグインは、
若干キャプチャでチラ見せしてますがね!

おまけ

2月に室内楽の本番がありました。
テレワークのBGMにどうぞ。

【AWS】Systems Manager 自作オートメーションドキュメント その2

はじめに

AWSのSystems Managerで、(以下SSM)
オートメーションドキュメントを自作したので、
やりたいこと別に紹介します!

前前回導入編を書いて、前回「その1」を書いて、
その続編的な何かです。

blue-38.hatenablog.com

blue-38.hatenablog.com

目次

■値を取得して別のステップで使いたい

ステップ1のレスポンスで帰ってきた値を変数に格納しておけば、
そのあとのステップで、
ステップ名.変数名みたいな感じで使用できます。

例えば、
対象EC2インスタンスのNameタグの値を取得してみます。

  - name: getNameTag
    action: 'aws:executeAwsApi'
    inputs:
      Service: ec2
      Api: DescribeTags
      Filters:
        - Name: resource-id
          Values:
            - '{{ InstanceId }}'
        - Name: key
          Values:
            - Name
    outputs:
      - Name: InstanceName
        Selector: 'Tags[0].Value'
        Type: String

上記のように取得すれば、後のステップで、
{{ getNameTag.InstanceName }}のように使えます。

ポイント

  • action: 'aws:executeAwsApi'で`APIを実行
    • DescribeXXXを使うことが多いかな
    • 期待するレスポンスを得るために、Filters:を使う
  • outputs:で格納する変数をName:に定義&格納する値へのパスをSelector:に記述
  • 使う時は、前述のとおり、{{ ステップ名.変数名 }}

■RDSのDBインスタンスを操作したい

メンテナンスウィンドウのターゲットに、
RDSのDBインスタンスを設定して、
オートメーションドキュメントで操作を自動化してみます。

まず、メンテナンスウィンドウでの
ターゲットの設定は、
Choose a resource group
リソースタイプがAWS::RDS::DBInstanceのリソースグループを指定するイメージです。
※EC2インスタンス以外のターゲットを指定する方法がこれしかない気がします。
※あれば知りたい

上記のようなメンテナンスウィンドウから
呼び出されるオートメーションドキュメントを書こうとしたときの注意点です。

parameters:
  DBInstanceId:
    type: String
    description: (Required) The DBInstance's ID.

たとえば、上記のように入力パラメータを定義し、
メンテナンスウィンドウでのタスク登録で、

f:id:blue-38:20200211212714p:plain
メンテナンスウィンドウ-タスク登録画面

こんな風に、{{ TARGET_ID }}を指定すると、
オートメーション実行時に、 DBInstanceIdに実際に入力される値は、
arn:aws:rds:ap-northeast-1:000000000000:db:piyomaru-dbのように、
ARNの値が入ってきます。

RDSを操作するようなAPIを使う場合って、
DB識別子が必須パラメータが多いので、
1ステップ目で、
ARNからDB識別子を取得するようにしてます。

mainSteps:
  - name: GetDBInstanceIdentifier
    action: 'aws:executeAwsApi'
    inputs:
      Service: rds
      Api: DescribeDBInstances
      Filters:
        - Name: db-instance-id
          Values:
            - '{{ DBInstanceId }}'
    outputs:
      - Name: DBInstanceIdentifier
        Selector: 'DBInstances[0].DBInstanceIdentifier'

■値を取得して別のステップで使いたい
おさらいですが、
取得したDB識別子は、この後のステップで、
GetDBInstanceIdentifier.DBInstanceIdentifierとして使えます。

動かし始めたとき、
DB識別子が入ってくれると勝手に勘違いしていたので、
紛らわしい命名になっていますが、
DBInstanceIdDBarnとかにすると分かりやすいかもですね。

続きの処理の例です。
スナップショット作成してみました。

  - name: CreateRDSSnapshot
    action: 'aws:executeAwsApi'
    inputs:
      Service: rds
      Api: CreateDBSnapshot
      DBInstanceIdentifier: '{{ GetDBInstanceIdentifier.DBInstanceIdentifier }}'
      DBSnapshotIdentifier: '{{ global:DATE }}-{{ GetDBInstanceIdentifier.DBInstanceIdentifier }}'

■分岐したい

スクリプトみたいに、
あまり器用なことはできませんが、
分岐の記法はあります。

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/automation-branchdocs.html

ちょっと書いてみました。
対象のEC2インスタンスが特定のEC2インスタンスだった場合、
echo "Hello World"してね!そうじゃない場合は、眠りましょう!
というオートメーションドキュメントです。

description: Exec runCommand to specified Instance.
schemaVersion: '0.3'
parameters:
  InstanceId:
    type: String
    description: (Required) The ID of the Amazon EC2 instance.
mainSteps:
  - name: Jadgment Instance
    action: 'aws:branch'
    inputs:
      Choices:
        - NextStep: runCommand
          Variable: '{{ InstanceId }}'
          StringEquals: i-026828bd5e33fba70
      Default: Sleep
  - name: runCommand
    action: 'aws:runCommand'
    inputs:
      DocumentName: AWS-RunShellScript
      InstanceIds:
        - i-0000aaaa0000bbbb
      Parameters:
        commands:
          - 'echo "Hello World"'
    isEnd: true
  - name: Sleep
    action: 'aws:sleep'
    inputs:
      Duration: PT5S

ポイント

  • action:aws:branchを指定する
  • NextStep:に分岐先のステップ名を定義
    • 複数分岐条件があれば、複数定義できる
  • どの条件にも合致しない場合の分岐先はDefault:に定義
  • 分岐先で処理を終了する場合にはisEndを定義
    • 定義しておかないと、止まらずに上から下にそのまま流れてしまう

おわりに

「その2」はちょっと応用バージョンみたいなネタをまとめてみました。
ただ、あんまりアクロバットなことをするなら
Lambdaの方が適していると思います。
自作オートメーションドキュメントの実例はあまりネットに落ちてない気がするので、
誰かの役に立てば幸いです。

【読書】リーダブルコード読みました

はじめに

ずっと読もうと思っていた
リーダブルコードを読んだので、
響いたことを、自分なりに咀嚼してつらつらと書きます!

www.oreilly.co.jp

この記事の【ポイント】部分は、
ほぼ自分への戒めです。

今までの自身の愚かなコードを振り返りつつ…
振り返るほどコーディングの経験ないけども。

命名

脇役的な変数にも愛を持って命名する

念のために定義しておこう~いらなかったら消そう~
と思って、適当な変数定義して、
結局消さずに居座られるあるある
置換もめんどくて、そのままにしちゃうあるある

tmp_hogehogeとか気を抜くと使ってしまう気がします。
というか、中間結果を保持するだけの変数は、
乱立させないように気をつけます。

【ポイント】

  • tmpという文字列も「一時的」とか意味を持つので、適当に使わない
  • 変数を無駄に増やさない

その関数にはどんな動作が期待される?

コードを読む側の先入観を想定して書くと、
より読みやすくなるとのことです。

書き手としては意識したことなかったですが、
読み手的にはGet…()みたいな関数は、
メンバの値を返すだけの軽めの関数かなぁと期待します。
確かにGet…()が何十行にわたる重厚なコードだったら萎えますね。

【ポイント】

  • 関数は、読み手が期待する動作(のレベル感)を想像して命名する

コメント

無駄なコメント削減

心配性なもので、
明日には記憶喪失になってたらどうしようと思い、
やたら細かくコメントしてしまいます。
ただ、コメントが無駄に多いのもスマートさに欠けるし、
見た目から読む気を削ぎますよね。

【ポイント】

  • コード見ればわかることはコメントしない
  • コメントしなくて済むような命名を意識する
    • #〇〇を定義とかやめよう。。

意図を記録する

記憶喪失まではいかなくても、
やたら凝ったコード書いて、
翌週、え、私何がしたくて、こんなコード書いたの…
ってなることはあります。
そんなときのためにも、
「意図」をコメントとして残すのは大事です。

【ポイント】

  • 何を思ってそのコードを書いたのか、コメントに残す
  • 夢中になって書いた傑作コードほど、未来の自分のために書き残す

コードの手段ではなく目的を書く

例えば、

古いメッセージを削除するために、
メッセージ一覧を取得して、最古メッセージIDを特定して、delete実行する。

とか、そんな処理があったとしたら、
コメントするべきなのは、
メッセージ一覧を取得して、最古メッセージIDを特定して、delete実行する。
ではなく、
古いメッセージを削除
がベター、ということですかね。

目的を書いておけば、
三者が見たとき、「え、この目的達成できてなくね?」
ってなった時に、バグが発覚できるので、
救われる命があるかもしれませんね。

【ポイント】

  • 目的が書いてあれば、第三者がレビューしやすいかも

関数の切り出し方

書籍で述べていることを簡潔にまとめると、
読み手をコード全体を通した目標に集中させるために、
目標に直接的に関係ない部分を
積極的に関数化しましょと言っています。

コードも読みやすくなるし、
メンテもしやすくなるります。

【ポイント】

  • 関数の切り出し観点
    • コード全体を通した目標に直接関係ない
    • 汎用的で、使いまわせそう
  • やりすぎない笑(調子に乗って、関数作りすぎても逆に見づらい)

おわりに

コーディング歴は半年くらいの雛鳥なので、
行き当たりばったりで書いていることが多く、
なかなか刺さりました。

もう少し経験積んだら、
読む観点も変わってくるのかなと感じました。
定期的に自戒のために、読み続けたい名著です。

【AWS】Systems Manager 自作オートメーションドキュメント その1

はじめに

AWSのSystems Managerで、(以下SSM)
オートメーションドキュメントを自作したので、
やりたいこと別に紹介します!

前回導入編を書いたので、その続編的な何かです。

blue-38.hatenablog.com

目次

API使って操作したい

下記の例は、DBインスタンスのスナップショットを作成するAPI
CreateDBSnapshotを使って、
命名規則に則ったスナップショットを作成します。

description: Create DB snapshot
schemaVersion: '0.3'
parameters:
  DBInstanceId:
    type: String
    description: (Required) The identifier of the Amazon RDS DB instance.
mainSteps:
  - name: CreateRDSSnapshot
    action: 'aws:executeAwsApi'
    inputs:
      Service: rds
      Api: CreateDBSnapshot
      DBInstanceIdentifier: '{{ DBInstanceId }}'
      DBSnapshotIdentifier: 'Ops-{{ global:DATE }}-{{ DBInstanceId }}'

parametersDBInstanceIdではDB識別子を指定するイメージです。

ポイント

  • action:'aws:executeAwsApi'を指定すれば、APIが使える
  • inputs:Apiに、使用するAPIを指定する
  • APIの引数をinputsに追加する
    • 今回の場合は、CreateDBSnapshotRequest Parametersを参考に指定
    • DBInstanceIdentifierはパラメータのDBInstanceIdの値を、DBSnapshotIdentifier命名規則に沿って指定
    • APIの情報は、大体操作方法をググると出てくる
  • ちなみに{{ global:DATE }}は日付をとってくるシステム変数

■ステータスの変化を待ちたい

APICreateなんとかを使ってなんか作ったとして、
その何かが指定した状態に変わるのを待つことができます。
下記の例は、■API使って操作したいで作成したスナップショットの状態が
availableになるのを待ちます。

# ヘッダは省略
  - name: VarifyRDSSnapshot
    action: 'aws:waitForAwsResourceProperty'
    inputs:
      Service: rds
      Api: DescribeDBSnapshots
      PropertySelector: 'DBSnapshots[0].Status'
      DesiredValues:
        - available
      DBSnapshotIdentifier: 'Ops-{{ global:DATE }}-{{ DBInstanceId }}'

ポイント

  • action:'aws:waitForAwsResourceProperty'を使用
  • Api:には状態をトレースしたい対象の表示(Describe)系APIを指定
    • 今回の場合は、DBスナップショットの状態が知りたいので、DescribeDBSnapshotsを指定
  • PropertySelector:には、Apiで取得できるレスポンスから状態へのJSONパスを指定
  • DesiredValues:には、期待する状態を指定
  • DBSnapshotIdentifier:DescribeDBSnapshotsに対する引数

■別のオートメーションドキュメントを呼び出したい

下記の例は、RDSのリードレプリカを作成するオートメーションドキュメントを
呼び出しています。
※呼び出し先ドキュメントは■API使って操作したい■ステータスの変化を待ちたいの連結版だと思っていただければ。。

# ヘッダは省略
  - name: CallCreateDBSnapshotAutomation
    action: 'aws:executeAutomation'
    inputs:
      DocumentName: CreateDBSnapshot
      RuntimeParameters:
        DBInstanceIdentifier:
          - '{{ DBInstanceId }}'

ポイント

  • action:は、'aws:executeAutomation'を指定
  • inputs:DocumentNameは呼び出すオートメーションドキュメントを指定
  • RuntimeParameters:には指定するオートメーションドキュメントのパラメータを指定
    • 呼び出し先のオートメーションドキュメントのparameters:で定義しているパラメータ

■コマンドを投入したい

方法はいくつかありますが、
オートメーションドキュメントで実行する方法を紹介します。
下記の例は、
対象のEC2インスタンス(Linux)に対して、cat /etc/hostsを実行します。
出力結果は、オートメーションの実行履歴から確認できます。

description: exec command
schemaVersion: '0.3'
parameters:
  InstanceId:
    type: String
mainSteps:
  - name: CatHostsFile
    action: 'aws:runCommand'
    inputs:
      DocumentName: AWS-RunShellScript
      InstanceIds:
        - '{{ InstanceId }}'
      Parameters:
        commands:
          - cat /etc/hosts

実体は、AWS-RunShellScriptというコマンドドキュメントを
外部から呼び出しているだけです。
ただコマンド実行したいだけなら、
AWS-RunShellScriptを実行すればよいと思います。
(書いてて気づいた)

ただ、オートメーションドキュメントに組み込みたいんじゃ!っていう場合は、
この書き方で実現できます。
私は、aws:branchで分岐させた先で使いました。
※分岐させる書き方は次回書きます。

ポイント

  • action:はコマンドドキュメントを呼び出す'aws:runCommand'を指定
  • コマンドドキュメントはAWS-RunShellScriptを指定
  • InstanceIdsには対象のEC2インスタンスを指定
  • Parameters:commands:に投入したいコマンドを記述

■眠りたい

オートメーションドキュメントでは下記のように眠ります。
時間はISO 8601の書式で記述します。
タイムスタンプでの指定も可能です。

# ヘッダは省略
  - name: Sleep
    action: 'aws:sleep'
    inputs:
      Duration: PT5S

ポイント

  • 時間はISO 8601の書式で記述
  • タイムスタンプでの指定も可能(Duration→Timestampにする)

おわりに

AWSコンソールからポチポチやっていることや、
EC2インスタンスにログインしてコマンドたたくなど、
それらを並べてフローにできるので、
なかなか便利です。

参考

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/automation-actions.html

【AWS】Systems Manager使ってみる 導入編

はじめに

AWS環境の運用自動化するのに、
AWS Systems Manager(以下、SSM)を試行中です。
今回は導入編ということで、
メンテナンスウィンドウを動かす最低限のチュートリアルを書きました。
オートメーションドキュメントの自作とかもやってみたので、
別記事で公開します。

AWS Systems Managerとは

公式サイトの紹介ページはこちら

AWS Systems Manager(運用時の洞察を改善し、実行)| AWSaws.amazon.com

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/what-is-systems-manager.html

機能はいくつかあるようですが、
私が使ってみたのはAutomationの機能です。
メンテナンスウィンドウから、

  • ターゲット
  • タスク(オートメーションドキュメント)
  • スケジュール

を登録して、実行します。
※ざっくり説明してます。詳細は後述。

動作確認環境

事前準備

SSM Automationタスク用IAMロールの作成

SSMからAWS上のリソースに対して
実行しようとする操作を許可するための
IAMロールを作成します。
以下、SSMServiceRoleとします。(説明の便宜上)

https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-maintenance-permissions.html

実行するタスクに応じて、
ポリシーをアタッチする必要があります。

例えばオートメーションドキュメントの中で、
DescribeInstancesというAPIを使う場合は、
SSMServiceRoleに
DescribeInstancesを許可するポリシーをアタッチしていないと、
実行時、権限がないよってエラーになります。

Step fails when it is Execute/Cancelling action. 
An error occurred (AccessDenied) when calling the DescribeInstances operation: 
User: arn:aws:sts::XXXXXXXXXXXX:assumed-role/SSMServiceRole/OrchestrationService is not authorized to perform: 
ec2:DescribeInstances. Please refer to Automation Service Troubleshooting Guide for more diagnosis details.

SSMに操作されるEC2用のIAMロールの作成

SSMに操作されるEC2インスタンス割り当てるIAMロールを作成します。
以下、EC2InstanceRoleForSSMとします。(説明の便宜上)

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/setup-instance-profile.html

AmazonSSMManagedInstanceCoreはアタッチ必須です。
S3やAD、CloudwatchとEC2を連携するような操作をするには、
カスタムポリシーが必要みたいです。

メンテナンスウィンドウの登録

メンテナンスウィンドウの設定手順は、こちら。

https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-maintenance-working.html

今回は、AWSにデフォルトで登録されている、
オートメーションドキュメントを使用して、
EC2インスタンスを18時に停止するメンテナンスウィンドウを作ってみます。

① Systems Manager のコンソールを開く
②[メンテナンスウィンドウの作成]を押下
③以下の項目を入力し、 [メンテナンスウィンドウの作成]を押下

No 項目名
1 名前 StopEC2Instance
2 説明 Stop EC2 Instance at 18:00.
3 指定 Cronスケジュールビルダー
4 ウィンドウの開始 毎日の18:00
5 期間 1
6 タスクの開始を停止 0
7 ウィンドウの開始日 指定なし
8 ウィンドウの終了日 指定なし
9 タイムゾーンのスケジュール (GMT+09:00)Japan

④ 作成したメンテナンスウィンドウを選択し、[編集]を押下
⑤ターゲットタブを開き、[ターゲットの編集]を押下
⑥以下の項目を入力し、 [ターゲットの登録]を押下

No 項目
1 名前 TargetHosts
2 説明 Hosts stopped at 18:00
3 所有者情報 指定なし
4 Target Selection Choose instances manually
5 インスタンス ★対象のインスタンスたち

インスタンスが出てこない場合は、以下をチェック

⑦タスクタブに移動して、[タスクを登録する]を押下
⑧[オートメーションタスクの登録]を押下
⑨以下の項目を入力し、 [タスクの登録]を押下

No 項目
1 名前 StopInstance
2 説明
3 オートメーションドキュメント AWS-StopEC2Instance
4 ドキュメントのバージョン ランタイムのデフォルトバージョン
5 優先度 1
6 ターゲット 登録済みのターゲットグループの選択:TargetHosts
7 レート制御-並行性 1ターゲット
8 レート制御-誤差閾値 0エラー
9 IAMサービスロール カスタムサービスロールを使用する:SSMServiceRole
10 入力パラメータ-InstanceId {{ TARGET_ID }}

※優先度って何…?

  • タスクの実行順番を制御できます。
  • 優先度は今回は1タスクのみなので、1にしてます。
  • 複数タスクを順次実行する場合は、優先度の値の昇順で実施されます。

オートメーションドキュメントの実体は、
AWS Systems Managerコンソールの左ペインの[ドキュメント]にあります。

これで、18時にEC2インスタンスを停止してくれるメンテナンスウィンドウができました。
タスクの実行履歴は履歴タブから確認できます。

おわりに

オートメーションドキュメント、
もとから入っているものでもけっこういろんなことできそうです。
SSMで運用チームが幸せになる使い方を模索中です。