単純作業を自動化して人類の無駄な時間をなくそう
このエントリーは Recruit Engineers Advent Calendar の 5日目の記事です。
目次
- 自己紹介
- 時間は有限、大切に使おう
- sshで30台のサーバをセットアップする
- expect コマンドを使おう
- StrictHostKeyChecking no
- chpasswdでパスワード設定
- chmod u+sとSUID
- seqコマンドとbash拡張構文{1..9}
- Excel業務を自動化しよう
- Win32::GuiTest でキーボード入力を自動化
- MouseMoveAbsPix でマウス操作を自動化
- マインスイーパーの自動化
- BadUSBによるキーボード入力の自動化
- まとめ
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方眼紙のファイルをやりとりする場合、以下のような定型項目の入力は自動化しておきます。
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です。
- YAPC::Asia Tokyo 2011 で Acme::MineChan を発表してきました | TAKESAKO
- Perlで無理ゲーム攻略 (How to play Win32::GuiTest)」の詳細 - YAPC::Asia Tokyo 2011
ここでは、ゲームの攻略を題材にしたAIを作成していますが、実務の仕事にも応用できることは明白です。私が実際にどんな業務を自動化しているかは…内緒とさせてください。:)
13. BadUSBによるキーボード入力の自動化
BadUSBによるキーボード入力の自動化については、昨年のAdvent Calendarで記事にしましたので、IoTや電子工作に興味のある方はぜひご覧ください。
14. まとめ
人類に与えられている時間は皆平等なため、どのように有限の時間を使いこなすかは、人それぞれです。 今回紹介したテクニックをさらに発展させ、ボットの開発や、機械学習による単純作業の自動化によって、人類全体の無駄な時間をなくし、エンジニア個々人のQoL(Quality of Life)を向上させましょう。