centos7 dockerインストールメモ

centos7にdockerを入れてみる。

yum -y install docker-io
service docker start
chkconfig docker on
systemctl status docker.service
● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
   Active: active (running) since 木 2016-02-04 21:56:39 JST; 23s ago
     Docs: http://docs.docker.com
 Main PID: 14787 (docker)
   CGroup: /system.slice/docker.service
           mq14787 /usr/bin/docker daemon --selinux-enabled

 2月 04 21:56:22 localhost.localdomain docker[14787]: time="2016-02-04T...
 2月 04 21:56:38 localhost.localdomain docker[14787]: time="2016-02-04T...
 2月 04 21:56:38 localhost.localdomain docker[14787]: time="2016-02-04T...
 2月 04 21:56:38 localhost.localdomain docker[14787]: time="2016-02-04T...
 2月 04 21:56:38 localhost.localdomain docker[14787]: time="2016-02-04T...
 2月 04 21:56:39 localhost.localdomain docker[14787]: time="2016-02-04T...
 2月 04 21:56:39 localhost.localdomain docker[14787]: time="2016-02-04T...
 2月 04 21:56:39 localhost.localdomain docker[14787]: time="2016-02-04T...
 2月 04 21:56:39 localhost.localdomain docker[14787]: time="2016-02-04T...
 2月 04 21:56:39 localhost.localdomain systemd[1]: Started Docker Appli...
Hint: Some lines were ellipsized, use -l to show in full.
docker pull centos
docker run -i -t centos /bin/bash
yum update -y
exit
docker ps -a
docker commit ID centos/test
docker run -i -t centos/test /bin/bash

Antビルドスクリプト

ビルドしてjarを作るだけです。

<?xml version="1.0" encoding="UTF-8"?>

<project name="DaoTraining" default="makeJar">

<property name="env.workspace"       value="./build"/>
<property name="env.compile"         value="./build/bin"/>
<property name="env.src"             value="./src"/>
<property name="env.lib"             value="./lib"/>
<property name="env.jar.name"        value="batch.jar"/>
<property name="env.jar.description" value="test jar"/>

<tstamp prefix="build-info">
	<format property="current-date" pattern="yyyy-MM-dd HH:mm:ss" locale="en"/>
</tstamp>

<target name="all" depends="clearDirectory, compile, makeJar" />

<target name="clearDirectory">
	<echo level="info" message="*** clear build directory ***" />
	<delete dir="${env.workspace}" />
	<mkdir dir="${env.workspace}" />
	<mkdir dir="${env.compile}" />
</target>

<target name="compile" depends="clearDirectory">
	<echo level="info" message="*** compile source files ***" />
	<javac srcdir="${env.src}" destdir="${env.compile}" debug="on"  optimize="off" includeAntRuntime="no" encoding="UTF-8">
		<classpath>
			<fileset dir="${env.lib}" />
		</classpath>
	</javac>
</target>

<target name="makeJar" depends="compile">
<echo level="info" message="*** make jar file ***" />
	<jar destfile="${env.workspace}/${env.jar.name}" basedir="${env.compile}">
	<manifest>
		<attribute name="Built-Time" value="${build-info.current-date}"/>
		<attribute name="Built-Name" value="${env.jar.description}" />
	</manifest>
	</jar>
	<delete dir="${env.compile}"/>
</target>

</project>

ビルドしてjarファイルを作成後、classファイルを削除します。
タグとタグ、属性としてdest,base,srcというキーワードを覚えておけば、後は自動補完で行けそうです。
MavenとかGradleの方が新しいし、依存関係の解消ができないのでAntを使っている既存プロジェクトでなければ使わないかも。

2016/04/24 追記
未定義プロパティを参照していた箇所を削除。

PythonでJSONを受けて処理する(ABC版)

抽象クラスを作成して、http://d.hatena.ne.jp/matasaburou/20151003/1443882557を作成。
Python3で動作確認済み。
Python2で動かす場合は下記が必要。

  1. 「from http.server」ではなく「from BaseHTTPServer」にする
  2. styleの違いでエラーが出るので、ABCとabstractmethodは使用しない

myResponseHandler.py

# -*- coding: utf-8 -*-

from abc import ABCMeta, abstractmethod
from http.server import BaseHTTPRequestHandler

#
# HTTPリクエストハンドラ 抽象クラス
#
class MyRequestHandler(BaseHTTPRequestHandler, metaclass=ABCMeta):

	def initialize(self, requestCharset='UTF-8', responseCharset='UTF-8', statusCode=200, responseContentType='text'):
		"""
			__init__はHTTPServer側から引数なしで呼び出されるため、初期化処理を別途実施します。
		"""
		# 文字コード
		self._reqCharset  = requestCharset
		self._respCharset = responseCharset
		# リザルトコード
		self._code = statusCode
		# コンテンツタイプ
		self._respContentType = responseContentType

	def _loadRequestBody(self):
		"""
			HTTPリクエストからリクエストボディを取得します。
		"""
		content_length = int(self.headers.get('content-length'))
		return self.rfile.read(content_length).decode(self._reqCharset)

	def _setResponseHeaders(self):
		self.send_response(self._code)
		self.send_header('Content-type', self._respContentType)
		self.end_headers()

	@abstractmethod
	def parseRequest(self, requestBody):
		"""
			HTTPリクエストBODYを解析します。
			特に解析が必要ない場合、下記のような実装が必要です。

				def parseRequest(self, requestBody):
					pass
		"""
		raise NotImplementedError()

	@abstractmethod
	def createResponse(self):
		"""
			HTTPレスポンスBODYを作成します。
			特に解析が必要ない場合、下記のような実装が必要です。

				def createResponse(self):
					return ''
		"""
		raise NotImplementedError()

	def do_POST(self):
		self.initialize()

		self.parseRequest(self._loadRequestBody())
		responseBody = self.createResponse()
		if responseBody == None:
			responseBody = ''
		elif not isinstance(responseBody, str):
			responseBody = str(responseBody)

		self._setResponseHeaders()

		# レスポンス送信
		self.wfile.write(responseBody.encode(self._respCharset))

responseBodyが文字列でなかった場合、文字列に型変換するのは微妙な気がします。
文字列じゃなかったら例外発生させて、createResponse側ではデコレーターで戻り値を強制するのがベター?

jsonResponseHandler.py

# -*- coding: utf-8 -*-

import json
from src.myRequestHandler import MyRequestHandler

#
# JSONハンドラ クラス
#
class JSONRequestHandler(MyRequestHandler):

	def initialize(self):
		super().initialize('UTF-8', 'UTF-8', 200, 'text/json')

	def parseRequest(self, requestBody):
		# JSONレスポンス作成用の種別を取得します。
		jsonData = json.loads(requestBody)
		self._type = ''
		if 'type' not in jsonData:
			self._type = 'notype'
		else:
			self._type = jsonData['type']

	def createResponse(self):
		# 種別を元にレスポンスを作成します。
		if self._type == 'auth':
			response = 'do something for auth request.'
		elif self._type == 'update':
			response = 'do something for update request.'
		else:
			response = 'reponse has undefined type.'

		return json.dumps({'data': response})

dummyHTTPServer.py

'''
Created on 2015/12/29

@author: saburou
'''

from src.jsonResponseServer import JSONRequestHandler
from http.server import HTTPServer

server = HTTPServer(('', 8000), JSONRequestHandler)

try:
    print(u'ダミーHTTPサーバーを開始します。')
    server.serve_forever()
except Exception as e:
    print(u'ダミーHTTPサーバーを終了します。')
    type(u'タイプ:' + e)
    print(u'メッセージ:' + e.message)

HTTPサーバー側のエラー処理は適当。
(例外キャッチの意味はなさそうですが、未確認)

2016/12/25 追記

以下の方がモアベターのようです。

try:
    print(u'ダミーHTTPサーバーを開始します。')
    server.serve_forever()
except Exception as e:
    print(u'ダミーHTTPサーバーを終了します。')
    type(u'タイプ:' + e)
    print(u'メッセージ:' + e.message)
finally:
    server.server_close()

python2.7 Gmail経由メール送信

Gmailサーバー経由でメール送信。
2段階認証を有効にしていない場合、安全性の低いアクセスを許可してもうまくいかなかった。
2段階認証を有効にしている場合、パスワードは2段階認証時のパスワード。

python2.7からau(ezweb.ne.jp)への送信確認済み。

# coding: utf-8

import email
from email.header import decode_header
from email.header import Header
from email.MIMEText import MIMEText
from email import Utils
from smtplib import SMTP_SSL

class GmailSMTPSender(object):
    def __init__(self, user, password):
        self.user = user
        self.password = password
        self.smtp_host = 'smtp.gmail.com'
        self.smtp_port = 465
        self.email_default_encoding = 'iso-2022-jp'
        self.timeout = 60

    def sendmail(self, fromAddr, toAddr, cc, bcc, subject, body):
        try:
            conn = SMTP_SSL(self.smtp_host, self.smtp_port)
            conn.login(self.user, self.password)
            msg = MIMEText(body, 'plain', self.email_default_encoding)
            msg['Subject'] = Header(subject, self.email_default_encoding)
            msg['From'] = fromAddr
            msg['To'] = ', '.join(toAddr)
            msg['Date'] = Utils.formatdate(localtime=True)
            conn.sendmail(fromAddr, toAddr, msg.as_string())
        except:
            raise
        finally:
            conn.close()


client = GmailSMTPSender('username', 'password')

subject = u"件名"
body = u"日本語でも大丈夫"

client.sendmail('from_address', 'to_address', None, None, subject, body)

PythonでJSONを受けて処理をする

レスポンスから取得したJSONを出力

import sys
import json
from http.server import BaseHTTPRequestHandler, HTTPServer

#
#リクエストからJSONを取得し、整形して出力します。
#
class JsonResponseHandler(BaseHTTPRequestHandler):

	def do_POST(self):
		content_len = int(self.headers.get('content-length'))
		requestBody = self.rfile.read(content_len).decode('UTF-8')
		print('requestBody=' + requestBody)
		jsonData = json.loads(requestBody)
		print('**JSON**')
		print(json.dumps(jsonData, sort_keys=False, indent=4, separators={',', ':'}))
		self.send_response(200)
		self.send_header('Content-type', 'text/json')
		self.end_headers()

server = HTTPServer(('', 8000), JsonResponseHandler)
server.serve_forever()

レスポンス送信

curl -H "Content-type: application/json" -X POST -d "{\"user\" : \"test\", \"type\" : \"test\", \"params\" : {\"id\" : 1234, \"data\" : 5}}" http://localhost:8000/

サーバー側出力

{
    "type","test":
    "user","test":
    "params",{
        "data",5:
        "id",1234
    }
}

JSON内の特定キーを元に異なるレスポンスを返す

import sys
import json
from http.server import BaseHTTPRequestHandler, HTTPServer

#
#JSON内の情報を元に、異なる値を応答します。
#
class JsonResponseHandler(BaseHTTPRequestHandler):

	def do_POST(self):
		content_len = int(self.headers.get('content-length'))
		requestBody = self.rfile.read(content_len).decode('UTF-8')
		print('requestBody=' + requestBody)
		jsonData = json.loads(requestBody)
		self.send_response(200)
		self.send_header('Content-type', 'text/json')
		self.end_headers()

		responseValue = ''

		if 'type' not in jsonData:
			responseValue = 'type not found.'
		else:
			print('type=' + jsonData['type'])
			if jsonData['type'] == 'auth':
				responseValue = 'do something for auth request.'
			elif jsonData['type'] == 'update':
				responseValue = 'do something for update request.'
			else:
				responseValue = 'reponse has undefined type.'

		self.wfile.write(responseValue.encode('UTF-8'))

server = HTTPServer(('', 8000), JsonResponseHandler)
server.serve_forever()

リクエスト送信1(typeなし)

curl -H "Content-type: application/json" -X POST -d "{\"user\" : \"test\", \"params\" : {\"id\" : 1234, \"data\" : 5}}" http://localhost:8000/
type not found.

リクエスト送信2(定義されていないtypeあり)

curl -H "Content-type: application/json" -X POST -d "{\"user\" : \"test\", \"type\" : \"test\", \"params\" : {\"id\" : 1234, \"data\" : 5}}" http://localhost:8000/
reponse has undefined type.

リクエスト送信3(定義されているtypeあり)

curl -H "Content-type: application/json" -X POST -d "{\"user\" : \"test\", \"type\" : \"auth\", \"params\" : {\"id\" : 1234, \"data\" : 5}}" http://localhost:8000/
do something for auth request.

お手軽でいいですね。
JSONを扱うロジックのテストには使えそうです。

PythonでJSONを受けてJSONを返す

pythonは標準でhttpサーバーが入っているということで、触ってみた。

必要なソフトウェア

インストール、設定方法は割愛。

curlはHTTPリクエスト送信用。

送信するJSON

{"user" : "test", "type" : "test", "params" : {"id" : 1234, "data" : 5}}

ソース(jsonResponseServer.py)

import sys
import json
import random
from http.server import BaseHTTPRequestHandler, HTTPServer

class JsonResponseHandler(BaseHTTPRequestHandler):

        def do_POST(self):
                content_len = int(self.headers.get('content-length'))
                requestBody = self.rfile.read(content_len).decode('UTF-8')
                print('JSON=' + requestBody)
#               requestBody = '{"user" : "test", "params" : {"id" : 123, "data" : 5}}'
                jsonData = json.loads(requestBody)
                user = jsonData['user']
                id = jsonData['params']['id']
                data = jsonData['params']['data']
                print('user=' + user)
                print('id=' + str(id))
                print('data=' + str(data))
                self.send_response(200)
                self.send_header('Content-type', 'text/json')
                self.end_headers()

                responseValue = random.random() * 10
                responseData = json.dumps({'data': responseValue})
                self.wfile.write(responseData.encode('UTF-8'))

server = HTTPServer(('', 8000), JsonResponseHandler)
server.serve_forever()

以下のコマンドで実行。

python3 jsonResponseServer.py

リクエスト送信

curlで以下のようにしてリクエストを送信する。
windows版のため、「"」の前に「\」を入れている。
2行目のレスポンスが返ってくる。

curl -H "Content-type: application/json" -X POST -d "{\"user\" : \"test\", \"type\" : \"test\", \"params\" : {\"id\" : 1234, \"data\" : 5}}" http://192.168.0.10:8000/
{"data": 6.010660103182533}

SNMPトラップを送信する

snmptrapコマンドのインストール、設定については割愛。

snmptrapコマンド

snmptrap -v 2c -c community 127.0.0.1 '' .1.3.6.1.6.3.1.1.5.3 .1.3.6.1.6.3.1.1.5.3.1 s "test message"

「1.3.6.1.6.3.1.1.5.3」はlinkDown。
v2cではオプションとして送信先しか指定できない模様。
oidに色々種類があるので、要確認。
参考URL。

  1. http://software.fujitsu.com/jp/manual/manualfiles/M070125/J2X13000/05Z200/refrad/refr0527.html
  2. http://www.atmarkit.co.jp/ait/articles/0303/21/news002.html
  3. http://www.itmedia.co.jp/enterprise/articles/0705/31/news042_2.html

送信確認

tcpdumpでパケットが送信できているかの確認。wiresharkで内容を確認するため、「-w」オプションをつける。

tcpdump -n -s 0 -i eth0 -w packet.cap

送信元と送信先が同じマシンの場合、ループバック「-i lo」でキャプチャしないとダメ?