単純作業を自動化して人類の無駄な時間をなくそう

このエントリーは Recruit Engineers Advent Calendar の 5日目の記事です。

www.adventar.org

目次

  1. 自己紹介
  2. 時間は有限、大切に使おう
  3. sshで30台のサーバをセットアップする
  4. expect コマンドを使おう
  5. StrictHostKeyChecking no
  6. chpasswdでパスワード設定
  7. chmod u+sとSUID
  8. seqコマンドとbash拡張構文{1..9}
  9. Excel業務を自動化しよう
  10. Win32::GuiTest でキーボード入力を自動化
  11. MouseMoveAbsPix でマウス操作を自動化
  12. マインスイーパーの自動化
  13. BadUSBによるキーボード入力の自動化
  14. まとめ

1. 自己紹介

@takesakoです。最近、まつもとゆきひろさんと岸川克己さんが技術フェローと技術顧問に就任した会社で専門役員を担当しています。 会社ではホールディングス兼務10%の傍ら、事業会社のプロダクト開発部部長、デザイングループと開発支援グループの2つのグループマネージャを兼務し、現在約70名の内製開発組織の体制構築と運営を行なっています。 会社では兼業申請により副業も認められていて、今年度は、独立行政法人2社、NPO法人1社、一般社団法人1社、公立大学法人1社、2省庁、1協議会の事業を掛け持ちしながら複数プロジェクトの進行と通常業務を並行して行なっています。現代人にとって、時間の管理と有効活用は非常に重要な課題です。

2. 時間は有限、大切に使おう

私はエンジニアですので、単純な作業はできるだけプログラムで自動化するコードを書いて、時間を生み出すようにしています。 このエントリーでは、新しくはないが、古くから使われているUNIXの素朴な技を使うことによって、地味な作業を自動化する温故知新なTIPSを紹介してみます。

3. sshで30台のサーバをセットアップする

さて、いきなり30台のLinuxサーバをセットアップする仕事が来たとします。最近はイメージのコピーで複数のサーバをセットアップできるクラウド環境が整っているため、コピー元の基本となるサーバのイメージをベースに30台のサーバに環境をコピーして作業するのが良いのですが、まとめて複数台のサーバへのコマンド実行をしたいことがあります。

まずはコピー元のオリジナルのサーバを用意し、ssh-keygenでssh秘密鍵と公開鍵のペアを作成し、公開鍵を~/.ssh/authorized_keysに追記し、ファイルのパーミッションを600にします。このユーザー名をvi /etc/sudoers で追記し、sudoできる権限にしておきます。コントローラーのサーバには秘密鍵を置き、コピー元のサーバには公開鍵のみを配置します。そして、コントローラーのサーバからsshでログインして各種セットアップを遠隔から行ないます。

4. expect コマンドを使おう

ssh で初回接続時に、~/.ssh/known_hosts に接続先sshサーバのフィンガープリントを記録するかどうか yes/no を答える場面がでてきます。

$ ssh 10.0.0.xx
The authenticity of host '10.0.0.xx (10.0.0.xx)' can't be established.
RSA key fingerprint is ff:ff:ff:ff:37:83:d8:c5:7a:56:72:c6:48:30:b3:7c.
Are you sure you want to continue connecting (yes/no)? yes

Warning: Permanently added '10.0.0.xx' (RSA) to the list of known hosts.

この yes の入力を手で毎回やるのは面倒なので、expect コマンドで自動化してしまいましょう。

#!/bin/sh
for xx in `seq 10 39`; do
  expect -c "
    set timeout 3
    spawn ssh 10.0.0.$xx
    expect \"yes/no\" { send \"yes\n\" }
    expect \":~\" { send \"exit\n\" }
    exit
  "
done

IPアドレス、10.0.0.10~39の30台のサーバに対して実行した様子です:

5. StrictHostKeyChecking no

実は、sshクライアントの接続オプションで -o 'StrictHostKeyChecking no' を指定すると、yes/noの判断を無視して常に接続することができます。

$ ssh -o 'StrictHostKeyChecking no' 10.0.0.xx

また、~/.ssh/config で「StrictHostKeyChecking no」の行を追加すると常にその設定を有効にすることができます。

$ vi ~/.ssh/config

StrictHostKeyChecking no

ただ、DNSスプーフィングなどで違うサーバに誘導されたりしたときにリスクがありますので、この設定は正直あまりお勧めできません。自己責任でご利用ください。

6. chpasswdでパスワード設定

まとめて30台のサーバのログインパスワードを設定して各ユーザに配布するシチュエーションに遭遇した場合、chpasswdコマンドを活用しましょう。

echo 'username:passw0rd' | sudo chpasswd

タブ区切りで用意した各ログイン配布情報を元にssh経由で各サーバで実行するシェルスクリプトPerlで自動生成します。

#!/usr/bin/perl
print<<EOF;
#!/bin/sh
EOF
$_ = <DATA>;
while(<DATA>) {
  chomp;
  my ($NO, $IP, $USER, $PASS) = split /\t/, $_;
  print "ssh $IP echo '$USER:\Q$PASS\E' \\| sudo chpasswd\n";
}
__DATA__
No IPアドレス  ユーザー名 パスワード
1  10.0.0.10   username    P@ssw0rd111
2  10.0.0.11   username    p!ssw1rd222
3  10.0.0.12   username    p#ssw2rd333

上記プログラムを実行すると、以下のシェルスクリプトが生成されます。Perlの文字列中に\Qと\Eで変数をはさむことにより、変数中の記号が自動でシェルエスケープされます。

#!/bin/sh
ssh 10.0.0.10 echo 'username:P\@ssw0rd111' \| sudo chpasswd
ssh 10.0.0.11 echo 'username:p\!ssw1rd222' \| sudo chpasswd
ssh 10.0.0.12 echo 'username:p\#ssw2rd333' \| sudo chpasswd

sudoの前の'|'は、sshログイン後に実行したいため、'\|'としておく必要があります。\でエスケープしないと手元のsshコマンドを実行しているサーバ上で実行されてしまいます。エスケープを注意するのはUNIXらしいですね。

ただし、今回の手法ではechoコマンドで生のパスワードを表示しているため、.bash_historyにパスワードの履歴が残りますので、sshターミナルからコピペできる手軽さの反面、セキュリティは低下しますので、ご注意ください。

7. chmod u+sとSUID

30台のサーバでsudo chmod u+s /bin/dateを実行して、dateコマンドにもSUID(SET UID)ビットを付けたいシチュエーションがあるとします。

SUIDはUNIXのファイルアクセス権限の一つで、ファイルのオーナー権限で一般ユーザがコマンドを実行できる仕組みです。SUIDがデフォルトでついているコマンドはpasswdが代表例で、root権限がなくてもユーザ権限でパスワード変更できるようになっています。

$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 23420 Aug 11  2010 /usr/bin/passwd

dateコマンドにもSUIDビットをつけて、時刻の変更をユーザ権限で行ないたいというシチュエーションです。

8. seqコマンドとbash拡張構文{1..9}

シェルで繰り返し実行するfor in文ではスペース区切りで繰り返し変数の値を指定します。

#!/bin/sh
for xx in 10 11 12 13 14; do ssh 10.0.0.$xx sudo chmod u+s /bin/date ; done

連番の数字を全部手で入力するのは面倒なので、seqコマンドの結果をバッククォートでinに渡す方法が古くから知られています。

#!/bin/sh
for xx in `seq 10 39`; do ssh 10.0.0.$xx sudo chmod u+s /bin/date ; done

最近のbashでは、`seq 10 39`相当のことが、{10..39}で書けるので、地味に便利です。bashの拡張記法わかりやすくて良いですね。

#!/bin/bash
for xx in {10..39}; do ssh 10.0.0.$xx sudo chmod u+s /bin/date ; done

9. Excel業務を自動化しよう

今度は、ちょっとテイストが変わって、外部の方とExcel方眼紙のファイルをやりとりする場合、以下のような定型項目の入力は自動化しておきます。

f:id:TAKESAKO:20161206013030p:plain

WindowsにActivePerlをインストールしておくとWin32::OLEが使えるので、現在Excelで開いているシートの項目に現在の日付や任意の文字列を自動で入力することができます。

#!/usr/bin/perl
use Win32::OLE qw();

my $Excel = Win32::OLE->GetActiveObject('Excel.Application');
my $Book  = $Excel->ActiveWorkBook;
my $Sheet = $Book->ActiveSheet;

$Sheet->Range("V3")->{Value} = @{[localtime]}[5] + 1900; # YYYY
$Sheet->Range("Z3")->{Value} = @{[localtime]}[4] + 1;    # MM
$Sheet->Range("AB3")->{Value} = @{[localtime]}[3];       # DD
$Sheet->Range("D4")->{Value} = "まなび事業本部 OL推進室";# 部署
$Sheet->Range("L4")->{Value} = "竹迫 良範";    # 氏名
$Sheet->Range("V4")->{Value} = "XXXXXXXX";     # 社員番号
$Sheet->Range("D7")->{Value} = "WXX+XXXXX";    # 内線
$Sheet->Range("L7")->{Value} = "03-XXXX-XXXX"; # 外線
$Sheet->Range("V7")->{Value} = "テプコ";       # 拠点

exit;

プログラム中でファイル名を指定して開くよりも、実はこの方が便利だったりします。

このようなExcel業務が発生する場合、プログラムで入力を自動化して時間を効率よく使うことが必須です。

10. Win32::GuiTest でキーボード入力を自動化

さらに、Win32::GuiTestモジュールをインストールすると、SendKeysでキーボード入力を自動化することができます。

use Win32::GuiTest qw(SendKeys);

system("start notepad.exe");
sleep(1);
SendKeys("foo{ENTER}");
SendKeys("bar{ENTER}");
SendKeys("bar{BS}z{ENTER}");

上記は、メモ帳(notepad.exe)を起動して、1秒待ってから、f o o 改行、b a r 改行、b a rと打って一文字削除してzを入力して改行するプログラムです。

11. MouseMoveAbsPix でマウス操作を自動化

Win32::GuiTestには、マウスを操作するAPIがあり、MouseMoveAbsPix($x, $y)で任意の座標にカーソルを移動することができます。

use Win32::GuiTest qw(:ALL);

for ($x = 0; $x < 900; $x += 2) {
  $y = sin($x / 60) * 300 + 400;
  MouseMoveAbsPix($x, $y);
}

12. マインスイーパーの自動化

これらの技術を応用してできたのが、5年前のYAPC::Asia 2011で発表したAcme::MineChanです。

yapcasia.org

ここでは、ゲームの攻略を題材にしたAIを作成していますが、実務の仕事にも応用できることは明白です。私が実際にどんな業務を自動化しているかは…内緒とさせてください。:)

13. BadUSBによるキーボード入力の自動化

BadUSBによるキーボード入力の自動化については、昨年のAdvent Calendarで記事にしましたので、IoTや電子工作に興味のある方はぜひご覧ください。

tech.recruit-mp.co.jp

14. まとめ

人類に与えられている時間は皆平等なため、どのように有限の時間を使いこなすかは、人それぞれです。 今回紹介したテクニックをさらに発展させ、ボットの開発や、機械学習による単純作業の自動化によって、人類全体の無駄な時間をなくし、エンジニア個々人のQoL(Quality of Life)を向上させましょう。