【Python】JMeter の実行結果をスプレッドシートに出力するスクリプトを書いてみた【gspread】

こんにちは。
JMeter が出力する結果を Google のスプレッドシートに出力してみようと考えまして、調べてみると Python に便利なライブラリがあったんで作ってみました。
※ 下記の JMeter デプロイ用 Playbook にも入れているのでよければご利用くださいませ。
https://github.com/keisukesanuki/jmeter-MS

Python スクリプト

#!/usr/bin/python3

import gspread
import json
import csv
import sys
import itertools

# シークレットキーを絶対パスで指定
SECRETJSON = "/usr/local/jmeter/bin/sacred-drive.json"
# スプレッドシートキーを定義
SPREADSHEET_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'

############################################################################
## 関数

# 数字と文字コンバーター
def num2alpha(num):
    if num<=26:
        return chr(64+num)
    elif num%26==0:
        return num2alpha(num//26-1)+chr(90)
    else:
        return num2alpha(num//26)+chr(64+num%26)

#############################################################################
## 認証

# お約束
from oauth2client.service_account import ServiceAccountCredentials
scope = ['https://spreadsheets.google.com/feeds','https://www.googleapis.com/auth/drive']

# ダウンロードした json ファイルを定義
credentials = ServiceAccountCredentials.from_json_keyfile_name(SECRETJSON, scope)

# Google API にログイン
gc = gspread.authorize(credentials)

# スプレッドシートのシート1を開く
worksheet = gc.open_by_key(SPREADSHEET_KEY).sheet1


##############################################################################
## 処理

# コマンドライン引数を取得
args = sys.argv
csvfile = args[1]

# CSVファイルの内容を配列に代入
with open(csvfile) as fp:
    results_list_ex = list(csv.reader(fp))

# 2次元配列を1次元配列に変換
results_list = list(itertools.chain.from_iterable(results_list_ex))

# カウント変数初期化
COUNT_NUM = 1
# 空白行探索
while str(len(worksheet.cell(COUNT_NUM, 1).value)) != "0":
        COUNT_NUM += 1

# 編集する範囲を指定
cell_list = worksheet.range('A'+str(COUNT_NUM)+':'+num2alpha(len(results_list))+str(COUNT_NUM))

# cell_listにresults_listの配列を代入
for i,cell in enumerate(cell_list):
    cell.value = results_list[i]

# 結果の保存
worksheet.update_cells(cell_list)

第一引数に csv ファイルを指定することで、結果をスプレッドシートに出力するスクリプトです。
このスクリプトを後述の JMeter 起動用スクリプトで利用します。

シェルスクリプト

#!/bin/sh

DATE=$(date +"%Y%m%d")
OPTIME=$(date +"%Y%m%d-%H%M%S")
# 結果の出力先ディレクトリを指定
LOGDIR=/var/www/html/${DATE}
# JMXファイルを指定
FILE_JMX=/usr/local/jmeter/bin/templates/build-web-test-plan.jmx

# 日付ディレクトリの作成
mkdir -p ${LOGDIR}

# JMeter 起動
/usr/local/jmeter/bin/jmeter -Dsun.net.inetaddr.ttl=0 -n -t ${FILE_JMX} -j ${LOGDIR}/${OPTIME}.log -l ${LOGDIR}/${OPTIME}.jtl -e -o ${LOGDIR}/${OPTIME}_th${JMETER_THREAD}${2}/ -r

# CSV ファイルの作成
cat ${LOGDIR}/${OPTIME}_th${JMETER_THREAD}${2}/statistics.json | jq  -r ". [] | [.transaction,.sampleCount,.errorCount,.errorPct,.meanResTime,.minResTime,.maxResTime,.pct1ResTime,.pct2ResTime,.pct3ResTime,.throughput,.receivedKBytesPerSec,.sentKBytesPerSec] | @csv" | grep "Total" > ${LOGDIR}/${OPTIME}_th${JMETER_THREAD}${2}/statistics.csv

# スプレッドシートに結果を出力
/usr/local/bin/main.py ${LOGDIR}/${OPTIME}_th/statistics.csv

JMeter は json で結果を出力するので jq で無理やり csv に変換してます。

Python だと簡単に実装できて楽ですね。

補足

スクリプトの実行に下記のパッケージ導入が必要です。

yum install python3 python-devel jq
pip3 install gspread
pip3 install oauth2client

【Ansible】Ansible で AWS の3層ネットワークを構築する【IaC】

こんにちは。
表題の通り AWS の 3層ネットワークを構築する playbook を用意してみます。
※ 詳細は README を参照ください。
https://github.com/keisukesanuki/aws-vpc-3layer

作るもの

・VPC
・SUBNET
・INTERNETGATEWAY
・NATGATEWAY
・ROUTETABLE

ディレクトリ構造

.
├── README.md
├── ansible.cfg
├── hosts
├── roles
│   └── aws_vpc
│       ├── tasks
│       │   └── main.yml
│       └── vars
│           └── main.yml
└── vpc_create.yml

playbook

---
# tasks file for aws_vpc
- name: create_vpc
  ec2_vpc_net:
    name: "{{ vpc_name }}"
    cidr_block: "{{ vpc_cidr }}"
    region: "{{ region }}"
    profile: "{{ profile }}"
    dns_hostnames: yes
    dns_support: yes
  register: vpc_info

# PUBLIC_SUBNET 作成
- name: create_public_subnet
  ec2_vpc_subnet:
    vpc_id: "{{ vpc_info.vpc.id }}"
    cidr: "{{ item.pub_subnet_cidr }}"
    az: "{{ item.subnet_az }}"
    region: "{{ region }}"
    resource_tags: { "Name":"{{ item.pub_subnet_name }}" }
    profile: "{{ profile }}"
  register: pubsub_info
  with_items:
    - "{{ pub_subnet }}"

# DMZ_SUBNET 作成
- name: create_dmz_subnet
  ec2_vpc_subnet:
    vpc_id: "{{ vpc_info.vpc.id }}"
    cidr: "{{ item.dmz_subnet_cidr }}"
    az: "{{ item.subnet_az }}"
    region: "{{ region }}"
    resource_tags: { "Name":"{{ item.dmz_subnet_name }}" }
    profile: "{{ profile }}"
  register: pubsub_info
  with_items:
    - "{{ dmz_subnet }}"

# PRIVATE_SUBNET 作成
- name: create_private_subnet
  ec2_vpc_subnet:
    vpc_id: "{{ vpc_info.vpc.id }}"
    cidr: "{{ item.pri_subnet_cidr }}"
    az: "{{ item.subnet_az }}"
    region: "{{ region }}"
    resource_tags: { "Name":"{{ item.pri_subnet_name }}" }
    profile: "{{ profile }}"
  register: prisub_info
  with_items:
    - "{{ pri_subnet }}"

# IGW 作成
- name: create_igw
  ec2_vpc_igw:
    vpc_id: "{{ vpc_info.vpc.id }}"
    region: "{{ region }}"
    tags: { "Name":"{{ igw_name }}" }
    profile: "{{ profile }}"
  register: igw_info

# ROUTETABLE 作成(IGW)
- name: create_route_table
  ec2_vpc_route_table:
    vpc_id: "{{ vpc_info.vpc.id }}"
    subnets: "{{ atache_igw_subnet }}"
    routes:
      - dest: 0.0.0.0/0
        gateway_id: "{{ igw_info.gateway_id }}"
    region: "{{ region }}"
    profile: "{{ profile }}"
    resource_tags: { "Name":"{{ rttable_pub_name }}" }

# NGW の ID を取得
- name: get_subnet_id
  shell: aws ec2 describe-subnets --region {{ region }} --profile {{ profile }} --output text | grep -B 1 {{ ngw_subnet_name }} | awk 'NR==1 {print $12}'
  register: ngw_subnet_id

#- name: show
#  debug:
#    msg: "{{ ngw_subnet_id.stdout }}"

# NGW 作成
- name: create_ngw
  ec2_vpc_nat_gateway:
    subnet_id: "{{ ngw_subnet_id.stdout }}"
    region: "{{ region }}"
    profile: "{{ profile }}"
  register: ngw_info

#- name: show
#  debug:
#    msg: "{{ ngw_info.nat_gateway_id }}"

# NGW 作成まで待つ
- name: wait_for_ngw
  pause:
    minutes: 5

# ROUTETABLEの作成(NGW)
- name: create_route_table2
  ec2_vpc_route_table:
    vpc_id: "{{ vpc_info.vpc.id }}"
    subnets: "{{ atache_ngw_subnet }}"
    routes:
      - dest: 0.0.0.0/0
        gateway_id: "{{ ngw_info.nat_gateway_id }}"
    region: "{{ region }}"
    profile: "{{ profile }}"
    resource_tags: { "Name":"{{ rttable_dmz_name }}" }

NATGATEWAY の ID が上手く取得できなかったので awscli の結果をパースして ngw_subnet_id に渡しています。

変数定義

---
# vars file for aws_vpc

# REGION
  region: "ap-northeast-1"

# PROFILE
  profile: "default"

# VPC
  vpc_name: "sanuki-wd-vpc2"
  vpc_cidr: "10.10.0.0/16"

# IGW
  igw_name: "sanuki-igw2"

# NGW
  ngw_name: "sanuki-ngw2"


# NGWを作成するサブネット名
  ngw_subnet_name: "sanuki-wd-public-subnet2-a"

# ROUTETABLE(PUBLIC)
  rttable_pub_name: "sanuki-pub-rt2"

# ROUTETABLE(DMZ)
  rttable_dmz_name: "sanuki-dmz-rt2"

# PUBLIC_SUBNET
  pub_subnet:
    - { pub_subnet_cidr: "10.10.10.0/24" ,subnet_az: "ap-northeast-1a" ,pub_subnet_name: "sanuki-wd-public-subnet2-a" }
    - { pub_subnet_cidr: "10.10.20.0/24" ,subnet_az: "ap-northeast-1c" ,pub_subnet_name: "sanuki-wd-public-subnet2-c" }


# DMZ_SUBNET
  dmz_subnet:
    - { dmz_subnet_cidr: "10.10.30.0/24" ,subnet_az: "ap-northeast-1a" ,dmz_subnet_name: "sanuki-wd-dmz-subnet2-a" }
    - { dmz_subnet_cidr: "10.10.40.0/24" ,subnet_az: "ap-northeast-1c" ,dmz_subnet_name: "sanuki-wd-dmz-subnet2-c" }


# PRIVATE_SUBNET
  pri_subnet:
    - { pri_subnet_cidr: "10.10.50.0/24" ,subnet_az: "ap-northeast-1a" ,pri_subnet_name: "sanuki-wd-private-subnet2-a" }
    - { pri_subnet_cidr: "10.10.60.0/24" ,subnet_az: "ap-northeast-1c" ,pri_subnet_name: "sanuki-wd-private-subnet2-c" }

# IGWに紐付けるサブネット
  atache_igw_subnet:
    - "10.10.10.0/24"
    - "10.10.20.0/24"

# NGWに紐付けるサブネット
  atache_ngw_subnet:
    - "10.10.30.0/24"
    - "10.10.40.0/24"

NatGateway が片方の AZ にしかないため、冗長性の観点からは ? となりますが、まぁいいでしょう。

↓ 2層の playbook はこちら

【Ansible】AnsibleでAWSのネットワークを構築する【IaC】

【AWS】Data Lifecycle Manager を CloudFormation で設定してみた【dlm】

EBS のスナップショットを取得する Data Lifecycle Manager というマネージドサービスがございます。
こちらを一括で設定する CloudFormation のテンプレートを作成しました。

AWSTemplateFormatVersion: "2010-09-09"
Description: "DLM Configuration YAML"

# パラメータセッティング
Parameters:
  ProjectName:
    Type: String
  LotateNum:
    Type: Number
    Default: 3
  GetTime:
    Type: String
    Default: "18:00"

Resources:
  
  # DLM IAM ロール作成
  CreateDlmRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: 'AWSDataLifecycleManagerDefaultRole'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - dlm.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /service-role/
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSDataLifecycleManagerServiceRole
        
  # DLM 作成
  BasicLifecyclePolicy:
    Type: "AWS::DLM::LifecyclePolicy"
    Properties:
      Description: !Join [ "-", [ !Ref ProjectName, dlm ] ]
      State: "ENABLED"
      ExecutionRoleArn: !Sub "arn:aws:iam::${AWS::AccountId}:role/service-role/AWSDataLifecycleManagerDefaultRole"
      PolicyDetails:
        ResourceTypes:
          - "VOLUME"
        TargetTags:
          -
            Key: "dlmtarget"
            Value: "true"

        Schedules:
          -
            Name: !Join [ "-", [ !Ref ProjectName, daily-schedule ] ]
            TagsToAdd:
              -
                Key: "type"
                Value: !Join [ "-", [ !Ref ProjectName, scheduled-snapshot ] ]

            CreateRule:
              Interval: 24
              IntervalUnit: "HOURS"
              Times:
                - !Ref GetTime

            RetainRule:
              Count: !Ref LotateNum
            CopyTags: true

各種パラメータは下記の通りに設定して下さい。
・ProjectName ⇒ DLM リソース の prefix
・LotateNum ⇒ スナップショットの保持期間を指定
・GetTime ⇒ スナップショットの取得時間を UTCで指定 ( 例:10:00、08:35、02:48 )

【AWS】EBS のスナップショットを取得して世代管理してみる【シェルスクリプト】

こんにちは。
表題の通りです。
DLM でもよいのですが、最長のインターバルが 24 時間なので、要件が合わない時のために。

#!/bin/sh

# スナップショットの保持世代数を定義
LOTATE_NUM=3
# ホストネームを定義
HOSTNAME=
# スナップショットを取得するボリュームIDを定義
VOLID=

# スナップショットを取得
aws ec2 create-snapshot --volume-id $VOLID --tag-specification 'ResourceType="snapshot",Tags=[{Key="Name",Value="script-create"}]' --description "$HOSTNAME snapshot"

# 指定した世代数分になるようにスナップショットを削除
SNAPSHOTS_NUM=`aws ec2 describe-snapshots --output text | grep $VOLID | grep "$HOSTNAME snapshot" | wc -l`
while [ ${SNAPSHOTS_NUM} -gt ${LOTATE_NUM} ]
do
        aws ec2 delete-snapshot --snapshot-id `aws ec2 describe-snapshots --output text | grep $VOLID | grep "$HOSTNAME snapshot" | sort -k 8 | awk 'NR==1 {print $7}'`
        SNAPSHOTS_NUM=`aws ec2 describe-snapshots --output text | grep $VOLID | grep "$HOSTNAME snapshot" | wc -l`
done

# awscli の導入

curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"
sudo python get-pip.py
sudo pip install awscli
aws configure