著者:しょっさん
梅雨の季節に入ってまいりました。この号が発売される頃には、梅雨もそろそろ明け、夏間近といったところでしょうか。
子供の頃は夏は朝から晩まで真っ黒になって遊び回ったものですが、大人になったら汗をかくだけで、色々やる気が削がれてしまいますね。とても不思議な気持ちではありますが、猛暑は家で落ち着いてプログラミング!
さぁ、今号もしまってまいりましょう!
記事本文掲載のシェルスクリプトマガジンvol.49は以下リンク先でご購入できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
├── 40ruby.csv ├── bin │ ├── console │ ├── reins │ └── setup ├── Gemfile ├── Gemfile.lock ├── lib │ ├── reins │ │ ├── auth_service.rb │ │ ├── config.rb │ │ ├── dispatcher.rb │ │ ├── host_registry.rb │ │ ├── task_control.rb │ │ └── version.rb │ └── reins.rb ├── LICENSE ├── Rakefile ├── README.md ├── reins.gemspec └── spec ├── reins_spec.rb └── spec_helper.rb |
1 2 3 4 5 |
#!/usr/bin/env ruby # coding: utf-8 # filename: bin/reins require "reins" Reins::start |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# coding: utf-8 # filename: lib/reins.rb require "reins/version" require "reins/dispatcher" require "reins/auth_service" require "reins/host_registry" require "reins/task_control" require "reins/config" require "socket" module Reins def start server = TCPServer.new(Reins::port) Reins::logger.info("Reins #{VERSION} を #{Reins::port} で起動しました") loop do begin Thread.start(server.accept) do |client| addr = client.peeraddr[3] keycode, command, options = client.gets.chomp.split if command == 'auth' Reins::logger.debug("#{addr} : 認証を行います") @keycode = Reins::auth_service.authenticate_key(keycode, addr) Reins::logger.debug("取得したキーコード : #{@keycode}") client.puts @keycode elsif Reins::auth_service.is_varid(keycode) == addr Reins::logger.debug("#{command} : 実行します") @host = Reins::Dispatch.new(addr, keycode) client.puts @host.command(command, options) else client.puts false end end rescue Interrupt => e p e Reins::regist_host.store server.close exit end end end module_function :start end |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# coding: utf-8 # filename: config.rb require 'logger' module Reins class << self attr_accessor :logger, :auth_service, :regist_host, :port def configure yield self end end end Reins.configure do |config| config.logger = Logger.new(ENV['REINS_LOGGER'] || "/tmp/reins.log") config.auth_service = Reins::AuthService.new(ENV['REINS_KEY'] || "106a6484291b9778c224731501d2deeb71f2b83558a0e9784fe33646f56182f69de448e92fe83fd4e57d629987f9d0dd79bf1cbca4e83b996e272ba44faa6adb") config.regist_host = Reins::HostRegistry.new(ENV['REINS_DATABASE'] || "./40ruby.csv") config.port = ENV['REINS_PORT'] || 16383 end Reins::logger.level = ENV['REINS_LOGLEVEL'] ? eval("Logger::#{ENV['REINS_LOGLEVEL']}") : Logger::WARN |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
} let(:incorrect_hosts) { ['100','[100,100]','1:0:0:1','1/0/0/1','0.0.0.1','1.0.0.0','0.0.0.0','240.0.0.1','240.255.255.254','0.256.0.1','0.0.256.1','239.255.255.255','-1.0.0.0','0.-1.0.0','0.0.-1.0','0.0.0.-1'] } before do allow(regist_test).to receive(:store).and_return(true) end describe '#create' do subject {regist_test.create(localhost, test_key) } before do regist_test.create(localhost, test_key) end it { is_expected.to eq(false) } end describe '#read_hosts' do subject {regist_test.read_hosts } context '正常に登録されている場合' do it { is_expected.to eq([]) } it 'localhost を1つ登録すると、[127.0.0.1]' do regist_test.create(localhost, test_key) is_expected.to eq([localhost]) end it '複数のアドレスを登録した場合は、複数のアドレス' do correct_hosts.each { |host|regist_test.create(host, test_key) } is_expected.to match_array(correct_hosts) end end context '不正なIPアドレスの場合' do it '有効範囲外のIPアドレスを登録しても登録されず、空の配列' do incorrect_hosts.each { |host|regist_test.create(host, test_key) } is_expected.to match_array([]) end end end describe '#read_hostkeys' do it '登録しなければ、空' do expect(regist_test.hosts).to eq([]) expect(regist_test.read_hostkeys).to eq({}) expect(regist_test.read_hostkeys.size).to eq(0) end it 'ハッシュ化された接続キーの一覧' do correct_hosts.each { |host|regist_test.create(host, test_key) } expect(regist_test.read_hostkeys.size).to eq(3) end end describe '#update' do before {regist_test.create(localhost, test_key) } context '正常に更新できる場合' do it '有効なIPアドレスへ変更すると host が変更' do before_host = localhost correct_hosts.each do |host| expect {regist_test.update(before_host, host) }.to change {regist_test.read_hosts }.from([before_host]).to([host]) before_host = host end end end context '更新できない場合' do it '有効範囲外のIPアドレスへ変更すると false' do incorrect_hosts.each do |host| expect(regist_test.update(localhost, host)).to eq(false) end end it '未登録のIPアドレスを指定すると false' do expect(regist_test.update('192.168.0.1','172.16.0.1')).to eq(false) end it 'すでに存在するIPアドレスへ変更すると false' do expect(regist_test.update('192.168.0.1',localhost)).to eq(false) end end end describe '#delete' do before {regist_test.create("192.168.0.1", test_key)} subject {regist_test.delete(localhost) } context '正常に削除できる場合' do it '登録済みのアドレスを削除すると、そのアドレス' do regist_test.create(localhost, test_key) is_expected.to eq(localhost) end end context '削除できない場合' do it { is_expected.to eq(nil) } end end end # TaskControl class のテスト describe 'TaskControl' do before { @server = TCPServer.new(24368) } after { @server.close } let(:tasks) { Reins::TaskControl.new } describe '#connect' do context 'クライアントへ接続できる場合' do subject { tasks.connect } it 'モックを使って正常接続のコール' do allow(tasks).to receive(:connect).and_return(true) is_expected.to eq(true) end end context 'クライアントへ接続できない場合' do it '接続先が存在しないと Standard Error' do # TODO: 実際は Raise ではなく、成否を True/False でもらうこととする expect{ Reins::TaskControl.new('localhost', 65000) }.to raise_error 'Not Connect' end it 'クライアントが停止していたら false' do allow(tasks).to receive(:connect).and_return(false) expect(tasks.connect).to eq(false) end end end describe '#disconnect' do context '正常に切断できた場合' do subject { tasks.disconnect } it 'こちらから、クライアントとの接続を切断して、成功すると nil' do is_expected.to eq(nil) end end end end # Dispatcher class のテスト describe 'Dispatch' do let(:test_key) { "TestKey" } let(:correct_host) { Reins::Dispatch.new("192.168.0.10", test_key)} describe '#command' do context 'ホストを追加する場合' do it 'ホストを正常に登録' do allow(Reins::regist_host).to receive(:create).and_return(true) expect(correct_host.command("add", "")).to eq(true) end end context 'ホスト一覧を出力する場合' do it 'ホスト一覧が出力された' do allow(Reins::regist_host).to receive(:read_hosts).and_return([]) expect(correct_host.command("list", "")).to eq([]) end end context 'アドレスを更新する場合' do it '正常に移行先アドレスへ更新' do allow(Reins::regist_host).to receive(:update).and_return(true) expect(correct_host.command("update", "172.16.0.1")).to eq(true) end end context 'アドレスを削除する場合' do it 'アドレスを正常に削除' do allow(Reins::regist_host).to receive(:delete).and_return("192.168.0.10") expect(correct_host.command("delete","")).to eq("192.168.0.10") end end end end end </pre] <pre class="toolbar:1 scroll:true lang:ruby decode:true" title="<プログラム5 lib/reins/dispatcher.rb>"># coding: utf-8 # filename: dispatcher.rb module Reins class Dispatch # 対象となるクライアントのIPアドレスを保持 # == パラメータ # ip:: 対象となるクライアントのIPアドレス # == 返り値 # 特になし def initialize(ip, key) @ip_address = ip @keycode = key end # コマンドを受け取って、対象の機能へ振り分ける # == パラメータ # comm:: クライアントからの要求コマンド # value:: コマンドの実行に必要な引数 # == 返り値 # exception:: 失敗した場合 # exception以外:: コマンドの実行結果 def command(comm, value) case comm when /^add/ then Reins::logger.info("#{@ip_address} を追加するよう指示がありました") Reins::regist_host.create(@ip_address, @key) when /^list/ then Reins::logger.info("一覧表示コマンドを受け付けました") Reins::regist_host.read_hosts when /^update/ then Reins::logger.info("IPアドレス更新依頼がありました") Reins::regist_host.update(@ip_address, value) when /^delete/ then Reins::logger.info("削除依頼が発生しました") Reins::regist_host.delete(@ip_address) end end end end |
1 2 3 4 5 6 7 8 9 10 11 |
$ nc kozue 16383 40ruby auth cf49cec2b1b099c8f551e4dc15694d1ea1fe3fea9e9c818a122797c4de0cdc0f8a0116d10267889c81294f069726ec9fee6dd2b599e02abc7b93580f8bb12dca ^C $ nc kozue 16383 cf49cec2b1b099c8f551e4dc15694d1ea1fe3fea9e9c818a122797c4de0cdc0f8a0116d10267889c81294f069726ec9fee6dd2b599e02abc7b93580f8bb12dca list 172.16.254.31 ^C $ nc kozue 16383 cf49cec2b1b099c8f551e4dc15694d1ea1fe3fea9e9c818a122797c4de0cdc0f8a0116d10267889c81294f069726ec9fee6dd2b599e02abc7b93580f8bb12dca delete 172.16.254.31 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
I, [2017-xx-xxTxx:xx:20.245642 #528] INFO -- : Reins 0.1.9 を 16383 で起動しました D, [2017-xx-xxTxx:xx:26.445938 #528] DEBUG -- : 172.16.254.31 : 認証を行います I, [2017-xx-xxTxx:xx:26.446158 #528] INFO -- : 172.16.254.31 : 新たにホストを登録します D, [2017-xx-xxTxx:xx:26.446249 #528] DEBUG -- : 172.16.254.31 : ホスト登録処理を行います D, [2017-xx-xxTxx:xx:26.446329 #528] DEBUG -- : 172.16.254.31 : アドレスチェックを行います D, [2017-xx-xxTxx:xx:26.446419 #528] DEBUG -- : 172.16.254.31 : アドレスに問題がありませんでした I, [2017-xx-xxTxx:xx:26.446477 #528] INFO -- : 172.16.254.31 を追加しました D, [2017-xx-xxTxx:xx:26.446504 #528] DEBUG -- : ./40ruby.csv : ホスト一覧を保存します D, [2017-xx-xxTxx:xx:26.448272 #528] DEBUG -- : 保管中... > ["172.16.254.31", "cf49cec2b1b099c8f551e4dc15694d1ea1fe3fea9e9c818a122797c4de0cdc0f8a0116d10267889c81294f069726ec9fee6dd2b599e02abc7b93580f8bb12dca", 2017-xx-xx xx:xx:26 +0900] D, [2017-xx-xxTxx:xx:26.468891 #528] DEBUG -- : 取得したキーコード : cf49cec2b1b099c8f551e4dc15694d1ea1fe3fea9e9c818a122797c4de0cdc0f8a0116d10267889c81294f069726ec9fee6dd2b599e02abc7b93580f8bb12dca D, [2017-xx-xxTxx:xx:35.041031 #528] DEBUG -- : cf49cec2b1b099c8f551e4dc15694d1ea1fe3fea9e9c818a122797c4de0cdc0f8a0116d10267889c81294f069726ec9fee6dd2b599e02abc7b93580f8bb12dca : クライアントの識別を行います D, [2017-xx-xxTxx:xx:35.041207 #528] DEBUG -- : list : 実行します I, [2017-xx-xxTxx:xx:35.041278 #528] INFO -- : 一覧表示コマンドを受け付けました D, [2017-xx-xxTxx:xx:45.886187 #528] DEBUG -- : cf49cec2b1b099c8f551e4dc15694d1ea1fe3fea9e9c818a122797c4de0cdc0f8a0116d10267889c81294f069726ec9fee6dd2b599e02abc7b93580f8bb12dca : クライアントの識別を行います D, [2017-xx-xxTxx:xx:45.886376 #528] DEBUG -- : delete : 実行します I, [2017-xx-xxTxx:xx:45.886518 #528] INFO -- : 削除依頼が発生しました I, [2017-xx-xxTxx:xx:45.886613 #528] INFO -- : 172.16.254.31 を削除しました. D, [2017-xx-xxTxx:xx:45.886645 #528] DEBUG -- : ./40ruby.csv : ホスト一覧を保存します |