目的
・利用しているサーバの状態を受動的に確認できるようにする
概要
puppeteerでブラウザを自動操作して、以下の操作を実施する
- AWSコンソールからログインする
- カスタムダッシュボードの画面を開く
- 目的のグラフを画像をダウンロードし、slackに通知する
前提条件
・AWSでBot用のIAMユーザを作成していること
・SlackにAppを作成して特定のchannelに投稿できるように設定していること
スクリプト
・aws-dashboard.js
const fs = require('fs');
const process = require('process');
const puppeteer = require('puppeteer');
const request = require('request');
const common = require('../lib/common');
// グラフ画像の保存先
const DIR = '/var/bot/aws_dashboard/';
// slackの設定
const CONF_SLACK = {
'url' : 'https://slack.com/api/',
'token' : '{トークン}',
'channel' : '{チャンネル}'
};
// URLの設定
const SIGNIN_URL = '{AWSのコンソールのURL}';
const DASHBOARD_URL = '{AWSのカスタムダッシュボードのURL}';
// タイミング調整用の時間設定(ミリ秒)
const WAIT_PAGE_TRANSION = 3000;
const WAIT_LITTLE = 200;
const WAIT_DASHBOARD = 10000;
(async () => {
// 起動引数を取得する
// ※args[0]はnodeプログラム、args[1]は本スクリプトのパスとなる
const accountId = process.argv[2];
const userName = process.argv[3];
const password = process.argv[4];
// ブラウザの初期設定をする
const browser = await puppeteer.launch({
headless : true, // ヘッドレスモードで起動(画面を表示しない)
slowMo : 20, // Puppeteer の動作を指定されたミリ秒単位で遅らせる
devtools : false,
ignoreHTTPSErrors: true,
defaultViewport : {
width : 1920,
height : 1080
},
args : [
'--window-size=1920,1080'
]
});
// ブラウザを起動する
const page = await browser.newPage();
// STEP1. AWSコンソール画面からサインインする
// 通常のサインインの画面を開く
await page.goto(SIGNIN_URL);
await page.waitForSelector('#next_button');
// 通常のサインイン画面
// 以下を選択・入力し、次へを押下する
// - ユーザ種別
// - アカウントID
await common.waitFor(WAIT_PAGE_TRANSION);
await page.click('input[id="iam_user_radio_button"]');
await page.type('input[id="resolving_input"]', accountId);
await common.waitFor(WAIT_LITTLE);
await page.click('#next_button');
await page.waitForSelector('#signin_button');
// IAMユーザとしてサインイン画面
// 以下を入力し、次へを押下する
// - ユーザ名
// - パスワード
await common.waitFor(WAIT_PAGE_TRANSION);
await page.type('input[id="username"]', userName);
await page.type('input[id="password"]', password);
await common.waitFor(WAIT_LITTLE);
await page.click('#signin_button');
await page.waitForSelector('#consoleNavHeader');
// STEP2. ダッシュボード画面を開く
await common.waitFor(WAIT_PAGE_TRANSION);
await page.goto(dashboardUrl);
// ローディングが終了するまで待つ
await page.waitForSelector('.cwdb-widget-container');
// STEP3. 各画像をダウンロードし、slack通知する
await common.waitFor(WAIT_DASHBOARD);
// ダウンロード用のディレクトリを作成する
const IMAGE_DIR = `${DIR}${common.imageDir()}`;
fs.mkdirSync(IMAGE_DIR);
// ダッシュボードのグラフ画像を特定するためのセレクタ一覧
const selectors = [
'.widget-2', // CPU使用率
'.widget-8' // メモリ使用量
];
let counter = 1;
for (const selector of selectors) {
// グラフを画像として保存する
const filepath = `${IMAGE_DIR}/widget_${counter}.png`;
const clip = await page.evaluate(s => {
const el = document.querySelector(s)
const { width, height, top: y, left: x } = el.getBoundingClientRect()
return { width, height, x, y }
}, selector);
await page.screenshot({clip, path: filepath});
// 保存した画像をslackに通知する
request.post({
url: `${CONF_SLACK.url}files.upload`,
formData: {
token : CONF_SLACK.token,
filename : filepath,
file : fs.createReadStream(filepath),
channels : CONF_SLACK.channel
},
function (error, response, body) {
if (!error && response.statusCode == 200) {
common.log(`push file to slack is success. filepath : ${filepath}`);
} else {
common.log(`push file to slack is failed. filepath : ${filepath}, status_code : ${response.statusCode}`);
}
}
});
counter++;
};
await common.waitFor(WAIT_PAGE_TRANSION);
await browser.close();
})();
・lib/common.js
exports.log = function(message) {
let dateStr = this.simpleDate(new Date(), 'YYYY-MM-DD hh:mm:ss')
console.log(`${dateStr}\t${message}`);
}
exports.simpleDate = function(date, format) {
format = format.replace(/YYYY/, date.getFullYear());
format = format.replace(/MM/ , ('0' + (date.getMonth() + 1)).slice(-2));
format = format.replace(/DD/ , ('0' + date.getDate()).slice(-2));
format = format.replace(/hh/ , ('0' + date.getHours()).slice(-2));
format = format.replace(/mm/ , ('0' + date.getMinutes()).slice(-2));
format = format.replace(/ss/ , ('0' + date.getSeconds()).slice(-2));
return format;
}
exports.imageDir = function() {
return this.simpleDate(new Date(), 'YYYYMMDD_hhmmss')
}
exports.waitFor = async function(sec) {
return new Promise((resolve, reject) => {
setTimeout(resolve, sec);
});
}
実行
$ node aws-dashboard.js {アカウントID} {IAMユーザ名} {IAMユーザのパスワード}