EC2インスタンスにRaspberry Piで電源スイッチを付けてみた【cloudpack 大阪 BLOG】

 久しぶりにRaspberryPiを触ってみて思いついたので早速作ってみました。以前はLチカやったところで終わっていましたが、Pythonを少し覚えたので何かAPIと連携させてみようと考えていました。最近、EC2インスタンスを触ることが多くなりましたが、サーバの電源を入れるということを全てWeb上でやっているので物理スイッチでわざわざ起動、停止をやってみようと思い作ってみました。
今回やってみたのは以下のような内容です。

・RaspberryPiでスイッチを押すとEC2が起動もしくは停止
・起動中 or 停止中はLEDを点滅させる
・起動、停止が完了したらslackで自分に通知

準備

RaspberryPi B+ (OSはraspbian 今回使用したバージョンは「Linux raspberrypi 3.12.28+ 」)
ブレッドボード
LED
タクトスイッチ
抵抗 330Ω(LED用)、1kΩ(タクトスイッチ用)
ジャンパーワイヤ

AWSのアクセスキー、シークレットキーの取得しておく
SlackのAPIキーの取得しておく

モジュールのインストール

pipのインストール

apt-get install python-pip

boto3(AWS SDK FOR Python)のインストール

pip install boto3

部品の配置

下記の図のように部品を配置します。GPIO、GNDの配線は間違えないようにしてください。
f:id:cloudfish:20151117005956p:plain:w512
※タクトスイッチは1kΩ、LEDは330Ωの抵抗を配置

実際に配線すると下記のようになります。
f:id:cloudfish:20151117012549j:plain:w384

配線の確認

実際に部品が正しく配置されているか確認するため、下記のプログラムを実行して動作確認を行います。

LEDの動作確認

#! /usr/bin/env python
import RPi.GPIO as GPIO
import time

LEDPIN = 21

GPIO.setwarnings(False) # Suppress warnings

GPIO.setmode( GPIO.BCM )
GPIO.setup( LEDPIN, GPIO.OUT )

while 1:
        GPIO.output( LEDPIN, True )
        time.sleep( 1.0 )
        GPIO.output( LEDPIN, False )
        time.sleep( 1.0 )

実行すると一定間隔でLEDが点滅します。点滅しなければ部品の配置や配線が間違えてないか見直してください

タクトスイッチの動作確認

#! /usr/bin/env python

import RPi.GPIO as GPIO
import time

# define
INPUT_PIN = 4

# init
GPIO.setwarnings(False) # Suppress warnings
GPIO.cleanup()
GPIO.setmode(GPIO.BCM)
GPIO.setup(INPUT_PIN,GPIO.IN)

if __name__ == "__main__":
    Btn_Flag = False

    while True:
        print (GPIO.input(INPUT_PIN))
        time.sleep(0.2)

実行してボタンを押すとボタンが押されている間はコンソールに「1」が表示されます

EC2インスタンスの起動・停止プログラム

上記のテストプログラムが正常に実行されれば実際にボタンを押してEC2のストップ、スタートができるプログラムを作成していきましょう。
AWSのアクセスキー、シークレットキー及びSlackのAPIキーは取得したものに変更してください。また、Slackの送信先は自身のユーザー名(@ + ユーザー名)に変更してください。

#! /usr/bin/env python

import RPi.GPIO as GPIO
import time
import boto3
from boto3.session import Session
import sys
import urllib
import urllib2

# define
INPUT_PIN = 4
LEDPIN = 21

# init 
GPIO.setwarnings(False)	# Suppress warnings
GPIO.cleanup()
GPIO.setmode(GPIO.BCM)
GPIO.setup(INPUT_PIN,GPIO.IN)
GPIO.setup( LEDPIN, GPIO.OUT )

#################################################################
# Function 
#################################################################
def getResourceEC2 ():
    session = Session(aws_access_key_id='ACCESS_KEY',
                      aws_secret_access_key='SECRET_KEY',
                      region_name='ap-northeast-1')
     
    ec2 = session.resource('ec2')
    return ec2

def get_ec2_state(instanceId):
    ec2 = getResourceEC2()
    instance = ec2.Instance(instanceId)
    if(instance.state['Name']=='running'):
        return True
    else:
        return False

def start_ec2(instanceId):
    ec2 = getResourceEC2()
    instance = ec2.Instance(instanceId)
    if(instance.state['Name']=='stopped'):
        instance.start()
        # Flashing LED
        led_flag = False
        while instance.state['Name'] != 'running':
           GPIO.output( LEDPIN, not led_flag)
           led_flag = not led_flag
           instance.reload()
	   time.sleep( 1.0 )
    
        GPIO.output( LEDPIN, True)

        print('EC2 Start!')
        post_slack('EC2 Start!')
    else:
        print('EC2 already Started!')
        post_slack('EC2 already Started!')

def stop_ec2(instanceId):
    ec2 = getResourceEC2()
    instance = ec2.Instance(instanceId)

    if(instance.state['Name']=='running'):
        instance.stop()
        # Flashing LED
        led_flag = False
        while instance.state['Name'] != 'stopped':
           GPIO.output( LEDPIN, not led_flag)
           led_flag = not led_flag
           instance.reload()
	   time.sleep( 1.0 )
    
        GPIO.output( LEDPIN, False)

        print('EC2 Stop!')
        post_slack('EC2 Stop!')
    else:
        print('EC2 already Stopped!')
        post_slack('EC2 already Stopped!')

def post_slack(message):
    url = "https://slack.com/api/chat.postMessage"
    params = {'token'  :'SLACK_API_KEY',
              'channel':'@USER',
              'text'   : message
             }

    req = urllib2.Request(url)
    req.add_header('Content-Type', 'application/x-www-form-urlencoded')
    req.add_data(urllib.urlencode(params))

    res = urllib2.urlopen(req)


#################################################################
# Main Function 
#################################################################
if __name__ == "__main__":
    print('Switch Start')
    
    argvs = sys.argv
    Id = argvs[1]
    Btn_Flag = get_ec2_state(Id)
    GPIO.output( LEDPIN, Btn_Flag)

    while True:
        
        if(GPIO.input(INPUT_PIN)):
           Btn_Flag = not Btn_Flag

           if(Btn_Flag):
               start_ec2(Id)
           else:
               stop_ec2(Id)

        time.sleep(0.2)

※簡略化するため、ステータスチェックなど細かい処理は省いています。

実行

下記のコマンドで実行します。引数には起動させたいEC2のインスタンスIDをセットします。
Switch Startと表示されたら、タクトスイッチを押してみましょう。

root@raspberrypi:~# python input_switch.py [instanceid]
Switch Start

しばらくすると、RaspberryPiのLEDが点滅を始めます。

AWS Management Consoleを確認してみましょう。
おお、起動中になりましたね!
f:id:cloudfish:20151117020140p:plain

起動、停止完了後
Slackにも無事通知されました!
f:id:cloudfish:20151117020445p:plain

まとめ

今回はEC2の起動、停止を行ったため、起動後にLEDが光らないなどプログラムにバグがあった時にやり直しの時間が少しかかりました。RaspberryPiと何かを連携させる場合は、まずRaspberryPiの挙動部分と連携部分を分けて事前に動作確認したうえで、それぞれ統合を進めたほうがいいように思いました。EC2のCPU使用率などを監視してしきい値超えるとLEDで点滅表示など状態を表すこともできそうですね。
電子回路は詳しくないですが、RaspberryPiはすごく簡単に色々できるようになっているので、また何か思いついたら作ってみたいと思います。

泉南  2015.11.08

 

天候  :雨

釣行時間:16:30 - 18:30
釣果  :アジ  7匹
     メバル 3匹
   ウミタナゴ 多数
   タチウオ  3匹
 
泉南の方でイワシとタチウオが釣れてるという情報があったので行ってきました。あいにく雨が強くしばらく様子見でしたが、何とか16時半くらいからサビキを始めることができました。仕掛けを投入するとエサなしでも釣れるくらいウミタナゴがわいてました。時々、アジやメバルがまじって釣れました。20cm前後のメバルを1匹煮付け用に確保しました。サビキでこれだけアジが釣れるならもしかすると青物も周っていたかもしれないです。イワシは全く釣れませんでいした。
 
 サビキはほどほどに夕暮れ前にジグにチェンジしタチウオを狙いました。日が暮れたころに、ジグの着水から1,2回シャクったタイミングでヒット。かなり遠目でヒットしました。一瞬、エソかと思いましたがタチウオがスレで掛かっていました。しばらくして隣のアングラーがワインドでヒットしだしたのでこちらもワインドに。変更してすぐにヒットしました。時合ですね。かなり足下まで寄ってきてたようです。それで時合が終わったようで、ワインドではアタリはなくなりました。
 
釣れなくなってきたので、そろそろ終わろうかと思いましたが、最後にメタルバイブレーションに変更して、遠目から色んなレンジをスローピッチで探っていると、またも足下近くでヒット!
今度は結構重く抜きあげるのを少し躊躇しましたが無事確保。帰ってから測ってみましたが、90cm弱のF4くらいで厚みもしっかりありました。(写真なし)
 
f:id:cloudfish:20151110011656j:plainf:id:cloudfish:20151110010851j:image

今季初のタチウオでした。


貝塚 2015.11.03

天候  :曇

釣行時間:15:00 - 17:00
釣果  :エソ 3匹
 
そろそろアジのシーズンも終わりかと思い、久しぶりにサビキ釣りの準備をして昼過ぎに出かけました。思ったより人が多く駐車場はほぼ一杯で釣り場所もあまりありませんでした。アジやイワシが釣れている様子は全くありませんでした。
 
しばらくサビキをしていましたが、全く釣れないので、結局、サビキを片手間にジグでキャスト開始。30分くらいするとフォールでヒット!やっぱりこの時期のこの時間帯なのでいつものエソでした。釣れないよりはマシというくらいですね。その後も立て続けにエソを2匹追加して納竿となりました。

f:id:cloudfish:20151103184553j:imagef:id:cloudfish:20151103184608j:image

f:id:cloudfish:20151103184620j:imagef:id:cloudfish:20151103184719j:image

 
夕日が凄く綺麗でした。
最後に青物釣りたいですねー
 

boto3(AWS SDK for Python)でCloudWatchからメトリクスを取得する【cloudpack 大阪 BLOG】

boto3を使ってCloudWatchからメトリクスを取得する必要が出てきたので勉強がてら簡単なサンプルを作ってみました。

環境

サーバ:CentOS6.6
Python:2.6.6
boto3:1.2.1

boto3(AWS SDK for Python)のインストール

AWSのリソースにアクセスするためのSDKをインストールします。

pip install boto3

EC2インスタンスのメトリクスを取得のサンプル

まずはEC2のCPU使用率を取得してみたいと思います。
下記のコードを記載して適当なファイル名で保存してください。

import boto3
from boto3.session import Session
import datetime
import dateutil.tz
import pprint

pp = pprint.PrettyPrinter(indent=4)

accesskey = "YOUR_ACCESSKEY"
secretkey = "YOUR_SECRETKEY"
region    = "YOUR_REGION"

session = Session(
                  aws_access_key_id=accesskey,
                  aws_secret_access_key=secretkey,
                  region_name=region)

client = session.client('cloudwatch')

# Get EC2 CPUUtilization
response = client.get_metric_statistics(
        Namespace='AWS/EC2',
        MetricName='CPUUtilization',
        Dimensions=[
        {
            'Name': 'InstanceId',
            'Value': 'i-12345678'
        },
        ],
        StartTime=datetime.datetime.utcnow() - datetime.timedelta(seconds=600),
        EndTime=datetime.datetime.utcnow(),
        Period=300,
        Statistics=['Average']
)

pp.pprint(response)

CloudWatchコンソール

リファレンスをななめ読みしただけですが、サイドメニューのMetricsがNamespaceとなりMetricNameが画面右側のMetricNameを指定します。Namespaceは「AWS/」をMetricsに付加すればよさそうです。(ここは後ほど書いてますが誤りでした)Dimensionsについては、取得したいサービスによって名称が異なるため、NameとValueを指定するようになっています。CPU使用率の場合はNameにInstanceIdをValueに実際のIDを指定します。
f:id:cloudfish:20151031174614j:plain

実行結果
python get_ec2_cpu.py
{   u'Datapoints': [   {   u'Average': 0.20000000000000001,
                           u'Timestamp': datetime.datetime(2015, 10, 31, 8, 16, tzinfo=tzutc()),
                           u'Unit': 'Percent'}],
    u'Label': 'CPUUtilization',
    'ResponseMetadata': {   'HTTPStatusCode': 200,
                            'RequestId': '1dfba5e6-7fa9-11e5-bc7c-1f8b347fd072'}}
EMRのメトリクスを取得

実際に取得したいMetricsは、EC2ではなくEMRのメトリクスを取得したかったのでEC2と同様にコードを書いてみましたが何故か取得できず。エラーは発生せず返却されるDatapointsの値に何もセットされていませんでした。スペルミスか時間指定が間違っているのかと思い見直すも問題はなさそうでした。そもそもNamespaceに問題があるのか?と疑いを抱き、list_metrics関数で取得してみると何も取得できませんでした。どうやら名前空間の指定に問題があるようで、調べてみると名前空間AWS の名前空間 - Amazon CloudWatchで定義されていました。CloudWatchのMetricsと紐付くと思い込んでいましたがそうではないようです。今回は「AWS/ElasticMapReduce」と指定して正しく値を取得することができました。

response = client.get_metric_statistics(
        #Namespace='AWS/EMR',                      ←間違い
        Namespace='AWS/ElasticMapReduce',   ←正
        MetricName='IsIdle',
        Dimensions=[
        {
            'Name': 'JobFlowId',
            'Value': 'j-1PNEZHM6MFON8'
        },
        ],
        StartTime=datetime.datetime.utcnow() - datetime.timedelta(seconds=300),
        EndTime=datetime.datetime.utcnow(),
        Period=300,
        Statistics=['Average']
)
実行結果
python boto_sample.py
{   u'Datapoints': [   {   u'Average': 1.0,
                           u'Timestamp': datetime.datetime(2015, 10, 22, 9, 20, tzinfo=tzutc()),
                           u'Unit': 'None'}],
    u'Label': 'IsIdle',
    'ResponseMetadata': {   'HTTPStatusCode': 200,
                            'RequestId': '7c3a6076-8044-11e5-82dd-9bacba3e4791'}}

Laravel5でphp-imapからgmailにアクセス【cloudpack 大阪 BLOG】

PHPからgmailを取得したいと思い、方法を調査していたところphp-imapを使って取得できることがわかりました。が、結構ハマってしまいました。
今回はLaravel5を使ってgmailから固定条件で検索したメールの件名を一覧で表示させるサンプルアプリを作成してみました。

環境

 以下の構成でサンプルアプリを作成しました。
 ApachePHPのインストール等、Laravel5が動作する環境を構築をしておいてください。

サーバー : Amazon Linux
Webサーバー : Apache 2.4
PHP : php 5.6
php framework : Laravel5

php-imapのインストール

 まずはphp-imapモジュールのインストールを行います。

yum install php56-imap

phpのバージョンに合わせてインストールしてください。

Controllerの作成

[project_root]/app/Http/Controller/GmailController.phpを作成する

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Http\Requests;
use App\Http\Controllers\Controller;

class GmailController extends Controller
{
     public function getIndex()
     {
        $server = "imap.gmail.com";
        $port = 993;                 // ポート番号
        $account = "test@gmail.com"; // Gmailアカウント
        $password = "password";      // パスワード
        $mailbox = "{".$server.":".$port."/novalidate-cert/imap/ssl}INBOX";

         // メールサーバ接続
        $mbox=null;
        $mbox = imap_open($mailbox, $account, $password) or die('Cannot connect to Gmail: ' . imap_last_error());
        
        // メール検索(検索条件:件名にTEST MAILが含んでおり、受信日時が2015/08/08以降)
        $result = imap_search($mbox,'SUBJECT "TEST MAIL" SINCE "8 August 2015" ', SE_UID);
        
        $mail=null;
        for($i = 0;$i<count($result);$i++){
            // ヘッダ情報の概要を取得
            $overview = imap_fetch_overview($mbox, $result[$i], FT_UID);
            // 件名、送信元アドレス、送信日を取得
            $subject = mb_convert_encoding(mb_decode_mimeheader($overview[0]->subject), 'utf-8');
            $from = mb_convert_encoding(mb_decode_mimeheader($overview[0]->from), 'utf-8');
            $date = date("Y-m-d H:i:s", strtotime($overview[0]->date));

            $mail['subject'] =$subject;
            $mail['date'] = $date;
            $mail['from'] =$from;

            array_push($mail_data,$mail);
        }
 
        // メールボックスのクローズ
        imap_close($mbox);

        return view('gmail.index')->with('mail_data',$mail_data);

     }
}

Viewの作成

resources/views/app.blade.phpを以下のように修正
共通レイアウトファイルでjqueryとbootstrapを読み込んでおきます。(好みで修正してください)

<!DOCTYPE html>
  <html lang="ja">
  <head>
      <meta charset="UTF-8">
      <title>Gmail Test</title>
      <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>

  </head>
  <body>
      <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>

      <div class="container">
          <div class="row">
              <div class="col-md-12">
                  @yield('content')
              </div>
          </div>
      </div>
  </body>
  </html>


[project_root]/resources/views/gmail/index.blade.php

@extends('app')
@section('content')

<h1>Gmail</h1>

<div  class="container">
    <table class="table table-striped table-bordered">
        <tr>
            <th>#</th>
            <th>date</th>
            <th>subject</th>
            <th>from</th>
        </tr>

@foreach ($mail_data as $index => $recorde)
        <tr>
            <td>{{$index+1 }}</td>
            <td> {{ $recorde['date'] }}</td>
            <td> {{ $recorde['subject'] }}</td>
            <td> {{ $recorde['from'] }}</td>
        </tr>
@endforeach

    </table>
</div>    

@endsection

Routingの設定

Route::controller('gmail', 'GmailController');

実行確認

「url/gmail」にアクセスしてみましょう。Gmailにアクセスしているため表示まで少し時間がかかります。
f:id:cloudfish:20151014212304p:plain
 正しく表示されない場合は、Gmailでブロックされている可能性が高いので、以下のハマったところを参考にしてみてください。

ハマったところ     

imap_openでCouldn't Open Stream エラー

以下のエラー画面が表示されました。
f:id:cloudfish:20151014203321p:plain

 まずは接続先、ポート番号、アカウント、パスワードに誤りがないか確認しましたが問題なさそうです。ググッてみましたが、設定を見直すというところで良く分かりませんでした。
そこで、以前にメールボックスtelnetでアクセスしたことを思い出し、コマンドで直接アクセスできるか試してみました。
 

openssl s_client -connect imap.gmail.com:993 -crlf 
? login test@gmail.com password

参考:telnet(openssl)でIMAPプロトコルを喋ってGmailに命令を出す。 - それマグで!

このコマンドで直接アクセスしても接続出来ませんでした。ということでもしかするとGmail側でブロックされているのかも?という可能性を疑ったところ、「ログイン試行をブロックしました」というメールが届いていました。(早くきづいておけば・・・)
ひとまず接続確認をしたかったので、セキュリティ的にオススメではありませんが「安全性の低いアプリがアカウントにアクセスするのを許可する」(下記参照)設定を行ったところ、コマンドでのアクセス確認ができアプリからも正常にアクセスできました。

参考:安全性の低いアプリがアカウントにアクセスするのを許可する - Google アカウント ヘルプ

このままではセキュリティ的によろしくないので他に方法がないか調べたところ、アプリ用のパスワードを設定する方法がありました。(下記参照)2段階認証を有効にしてアプリ用パスワードを発行し、プログラム内のパスワードをアプリ用パスワードに変更して再度実行して表示されることが確認できました。

参考:アプリ パスワードでログイン - Google アカウント ヘルプ

検索したメールが正しく表示されない

 次に固定文言で検索したメールを表示させたところ、タイトルにその文言が含まれていないメールが表示される問題がありました。
これは、imapの仕組みを良く分かっていなかったことと、imap_searchのリファレンスをしっかり読んでいなかったことが原因でした。コードをコピペして修正するだけではダメですね。
imapではメールにメッセージ番号とUIDの2種類の番号が割り当てられているようで、↑のコードではimap_searchの引数にSE_UIDを指定したためUIDが返されていました。当初、件名を取得するのにimap_headerinfo関数を使用していましたが、これはメッセージ番号をキーに取得する関数なので検索条件に該当しないメールが取得されていました。なので、ヘッダー情報をUIDでも取得できるimap_fetch_overview関数を使うことで解決しました。これでメールを取得できるようになったので、色々と効率化できそうです。

.ssh/configの便利な設定【cloudpack 大阪 BLOG】

 管理するサーバ台数が増えてくるとSSHでの接続が手間になりconfigに設定を書くことも多くなると思います。
 また、扱うサーバ台数が増えてくるとそもそもconfigに記載したかどうかすらも分からなくなってきます。そこで今回は、「.ssh/config」を利用するときにちょっと便利になる設定を紹介します。

Host名の補完機能

 これはHost名を補完してくれる機能です。地味に便利な機能です。

インストール方法

 以下のコマンドを実行し補完機能をインストールしてください。
この機能はsshだけでなくserviceコマンドなど他のコマンド実行時においても補完してくれます。

# Mac
brew install bash-completion
# CentOs
yum --enablerepo=epel install -y bash-completion
使い方

ssh a」とタイプしたあとTabをタイプすると一致するHost名を表示します。
候補が複数ある場合は可能性のある一覧が表示されます。

$ ssh a<Tab>
$ ssh abc_web_01

Host名の一覧表示

 Host名の一覧を表示するコマンドを自作しました。補完機能でほぼまかなえますが、Host名の先頭のを覚えていない時に。
 以下のコマンドを「.bash_profile」なりに設定してください。

設定方法
alias sshlist="cat ~/.ssh/config |grep ^Host\  |sed -e 's/^Host\ //g'"
使い方

使い方は「sshlist」とするだけでHostの一覧が表示されます。

下記のようなconfig設定があったとして

Host abc_web_01
HostName 111.111.111.001
IdentityFile ~/.ssh/abc_id_rsa1
User ec2-user

Host def_web_01
HostName 111.111.111.002
IdentityFile ~/.ssh/def_id_rsa1
User ec2-user


これに対して実行すると

$ sshlist
abc_web_01
def_web_01

Host名に「def」を含む一覧を表示

$ sshlist |grep def
def_web_01

タイムアウト防止

一定時間操作しなかった場合にタイムアウトすることがありますが、以下の設定をすると
指定時間時間ごとに通信をしてタイムアウトを防いでくれます。

ServerAliveInterval 15

サーバのタイムアウト設定は基本的にはセキュリティを考慮したもののため、
この設定をして回避するのは微妙な気がします。

おまけ

scpコマンドからでも.ssh/configが利用できます。

ファイル受信
scp  abc_web_01:/home/user/remotefile.txt /tmp/ 
ファイル送信
scp  localfile.txt abc_web_01:/home/user/

貝塚 2015.09.20

天候  :曇

釣行時間:04:00 - 07:00
釣果  :サゴシ 1匹、エソ 1匹

 

 朝の4時過ぎに釣座を確保し釣り開始。タチウオシーズンなのでこの時間でもかなり人が多いですね。かなり肌寒い状況です。まずはワインドでタチウオ狙い。今年はどうでしょうか?若干、風と波があり少しあたりが取り辛い状況でした。ワインドの色を変え、ジグに変えと色々試行して5時半過ぎまで粘りましたが、時合も特になく周りでは隣のえさ釣り師が1匹釣っていたくらいでした。 もちろん自分もヒットなし。本命の青物に期待することにします。

 

f:id:cloudfish:20150921234028j:image

 

 タチウオに見切りを付けて青物タックルに持ち替えて、ジグでキャスト開始。風もおさまってきました。1時間位キャストを続けていましたが、ベイトも見当たらずナブラもないので、今日もボウズかと諦めかけていました。が!6時半前に底付近でフォールでヒット!ヒットの仕方と引きからエソっぽいと思いつつ期待して寄せてみましたが、やっぱりエソでした。残念!せっかくですが、海にお帰りいただきました。引きだけは楽しませてもらいました。ともあれ、活性が上がってきたかと期待してキャストし続けると、中層付近でひったくるような感じでヒット!これは青物確実と思い寄せてみると今季初サゴシ!ヒットパターンは少しテンポの早いワンピッチジャークでした。サゴシを〆てすぐにキャストを開始しましたが、群れはもう去っていったのかこれ単発でした。

 
f:id:cloudfish:20150921233911j:image

 

今回はリーダーにワイヤーを使ってなかったのですが、針が1つサゴシに切られていました。サゴシの歯は鋭いですね。針を外すときはくれぐれも気をつけてください。もう一つも噛まれてボロボロになっていたので、抜き上げずにネットでランディングして良かったです。

 

 f:id:cloudfish:20150925095900j:plain