Go言語:sshパッケージを使って対話型SSHクライアントを実装する

code.google.com/p/go.crypto/sshで提供されているsshパッケージを使って、標準のsshコマンドと同等の対話型SSHクライアントを実装してみた。

コードは以下。
https://github.com/inatus/ssh-client-go

API・コード例はGoDocに記載されている。
http://godoc.org/code.google.com/p/go.crypto/ssh

しかし、Sessionを作るところまでは例があるからいいとして、その先がよくわからない。
セッションを開始するメソッドと以下のようなものがあるようだ。

  • Run: コマンドを引数に指定。コマンドの実行が完了するまでWaitが掛かり、結果はSessionのStdio、Stderrに出力される。
  • Start: コマンドを引数に指定。コマンドの実行完了を待たずに先に進む。結果はSessionのStdio、Stderrに出力される。つまり、Startメソッドを実行した直後には結果が出力されない。
  • Shell: コマンドを実行せずにシェルを開始する。
  • Output: コマンドを引数に指定。コマンドの実行が完了するまでWaitが掛かり、結果が戻り値に返る。
  • CombinedOutput: コマンドを引数に指定。コマンドの実行が完了するまでWaitが掛かり、結果が戻り値に返る。標準出力に加え標準エラー出力が返る。

また、Sessionに対してこれらのメソッドは一度しか実行できない。
これらのメソッドの中で、Shell以外は非対話型的な実行を想定していると思われる。したがって、Shellを用いる。

Shellメソッドを実行すると、ログイン直後の出力がStdioに出力される。これをOSの標準出力に出力するようにした。

session.Stdout = os.Stdout
session.Stderr = os.Stderr

次に、ログイン後のコマンド受付処理を実装する。コマンドはStdinに受け付けられる。端末の標準入力から入力されたコマンドをStdinPipeを使ってSessionのStdinに伝える。

in, _ := session.StdinPipe()
for {
  reader := bufio.NewReader(os.Stdin)
  str, _ := reader.ReadString('n')
  fmt.Fprint(in, str)
}

この際、以下に注意する。

  • StdinPipeはセッションを開始する前に取得すること。
  • コマンドの末尾には改行コード(n)を付けること。

これで通常のsshコマンドと同等な対話型SSHクライアントが構築できる。
ただし、パスワードのマスクやテキストエディタの起動などがうまくできない。

Ubuntu 12.04 サーバでファイルシステム全体を定期的にバックアップする

Linuxを使っていて困るのがバックアップである。
MacだったらTimeMachineに任せればファイルシステム全体を自動でバックアップしてくれる。
LinuxでもCUI、GUIそれぞれにいろいろなツールがあるようだが、
duplicityとcronを使ってファイルシステム全体を定期的にバックアップできるようにしてみた。

概要

duplicityによるフルバックアップ・増分バックアップをcronで定期的実行するように設定する。

手順

Ubuntuには標準でduplicityとcronがインストールされているはず。
duplicityでフルバックアップ・増分バックアップを実行するバッチファイルを作成し
そのバッチファイルをcronに登録する。

バックアップ実行バッチファイルの作成

以下のようにduplicityでバックアップを実行するバッチファイルを作成する。
まずはフルバックアップ用。

#! /bin/sh
duplicity full --no-encryption 
--archive-dir /mnt/backup/archive 
--exclude /dev 
--exclude /mnt 
--exclude /tmp 
--exclude /proc 
--exclude /sys 
--exclude /run 
--exclude /var/run 
--exclude /var/lock 
/ file:///mnt/backup/data

引数・オプションの意味は以下のとおり。

  • --no-encryptionで暗号化なしを指定
  • --archive-dirにバックアップ状態を保存しておくディレクトリを指定
  • --excludeで以下のディレクトリをバックアップ対象から除外
    • /dev デバイスのファイルを格納
    • /mnt 外部ストレージ等のマウントポイント
    • /tmp 一時ファイルを格納
    • /proc プロセス情報を格納
    • /sys デバイスの情報を格納
    • /run システムデータを格納
    • /var/run 起動してからのシステムデータを格納
    • /var/lock 二重起動などをチェックするロックファイルを格納
  • バックアップ対象はファイルシステム全体
  • バックアップ先はfile:///mnt/backup/data

一度フルバックアップを手動で取っておく。

次に、差分バックアップのバッチファイルを作成する。

#! /bin/sh
duplicity incremental --no-encryption 
--archive-dir /mnt/backup/archive 
--exclude /dev 
--exclude /mnt 
--exclude /tmp 
--exclude /proc 
--exclude /sys 
--exclude /run 
--exclude /var/run 
--exclude /var/lock 
/ file:///mnt/backup/data

引数をfullをincrementalに変えただけ。

バッチファイルをcronに登録

最後に、バッチファイルの実行をcronに登録する。
まずはcrontabを実行。

$ sudo crontab -e
Select an editor.  To change later, run 'select-editor'.
  1. /bin/ed
  2. /bin/nano        <---- easiest
  3. /usr/bin/vim.basic
  4. /usr/bin/vim.tiny

Choose 1-4 [2]: 

好きなエディタを選択する。
男は黙ってvim。
テキストファイルが表示されるので、どこでも良いので以下のように記述する。

0 0 * * 0 /bin/sh /mnt/backup/script/incrementalbackup.sh > /dev/null 2>&1

指定の意味は以下のとおり。

  • 曜日
  • ユーザ
  • コマンド

コマンドには先ほど作成した増分バックアップ用バッチスクリプトを指定し、結果を/dev/nullに出力する。
これを指定しないと実行結果が毎回メールで届くらしい。

Go言語:templateパッケージでHTML等テキストファイルを読み込む(応用編2)

templateパッケージでHTML等の任意のテキストファイルを読み込み、出力する方法を説明する。
応用編その2ではテンプレート内に埋め込む「アクション」で利用できる様々な機能について解説する。
なお、APIバージョンGo1で説明する。
バージョン3ではパッケージ名、関数名が異なるので注意。

概要

templateパッケージでは、任意のテキストを読み込み、テキストに埋め込まれたタグに対してデータの評価や制御(アクションという)をおこなって出力する。
templateパッケージ応用編1では、アクションの基本的な機能について説明したが、今回は以下のようなさらに高度な機能について説明する。

  • {{if}}アクションにnot、and、or評価をおこなう。
  • 配列、Slice、Mapのサイズや任意のインデックスの値を取得する。
  • 出力結果のフォーマットをおこなう。
  • 任意の演算をおこなった結果を出力する。

not演算によりbool値を評価する

package main

import (
	"fmt"
	"os"
	"text/template"
)

const templateString string = `
{{if not .}}TRUE {{/* not演算をおこなう */}}
{{else}}FALSE
{{end}}
`

func main() {
	var t = template.Must(template.New("text").Parse(templateString))

	if err := t.Execute(os.Stdout, true); err != nil { // trueを渡す
		fmt.Println(err.Error())
	}
}

実行結果

FALSE

and, or演算によりbool値を評価する

package main

import (
	"fmt"
	"os"
	"text/template"
)

const templateString string = `
{{with .}}
    {{if and .Field1 .Field2}}TRUE {{/* and演算をおこなう */}}
    {{else}}FALSE
    {{end}}
    {{if or .Field1 .Field2}}TRUE {{/* or演算をおこなう */}}
    {{else}}FALSE
    {{end}}
{{end}}
`

type Fields struct {
    Field1 bool
    Field2 bool
}

func main() {
    f := Fields{true, false}

	var t = template.Must(template.New("text").Parse(templateString))

	if err := t.Execute(os.Stdout, f); err != nil { // 構造体Fieldsを渡す
		fmt.Println(err.Error())
	}
}

実行結果

FALSE
    
TRUE

配列のサイズや任意のインデックスの値を出力する

package main

import (
	"fmt"
	"os"
	"text/template"
)

const templateString string = `
{{len .}} {{/* 配列のサイズを出力する */}}
{{index . 1}} {{/* 配列の[1]の値を出力する */}}
`

func main() {
    array := []int{1, 2, 4, 8}

	var t = template.Must(template.New("text").Parse(templateString))

	if err := t.Execute(os.Stdout, array); err != nil { // 配列を渡す
		fmt.Println(err.Error())
	}
}

実行結果

4
2

変数に一度値を格納し、出力する

package main

import (
	"fmt"
	"os"
	"text/template"
)

const templateString string = `
{{range $i, $v := .}}{{$i}}:{{$v}}
{{end}}
`

func main() {
    array := []int{1, 2, 4, 8}

	var t = template.Must(template.New("text").Parse(templateString))

	if err := t.Execute(os.Stdout, array); err != nil { // 配列を渡す
		fmt.Println(err.Error())
	}
}

実行結果

0:1
1:2
2:4
3:8

値のフォーマットを変更して出力する

package main

import (
	"fmt"
	"os"
	"text/template"
)

const templateString string = `
{{.Tags}}

{{html .Tags}} {{/* <や"などhtmlタグに用いる文字列をエスケープする */}}
{{.Tags | html}}

{{printf "%c" .Char}} {{/* 文字型で出力する */}}
{{.Char | printf "%c"}}
`

type Fields struct {
    Tags string
    Char int
}

func main() {
    f := Fields{"<a href="aaa">link</a>", 65}

	var t = template.Must(template.New("text").Parse(templateString))

	if err := t.Execute(os.Stdout, f); err != nil { // 構造体Fieldsを渡す
		fmt.Println(err.Error())
	}
}

実行結果


<a href="aaa">link</a>

&lt;a href=&#34;aaa&#34;&gt;link&lt;/a&gt;
&lt;a href=&#34;aaa&#34;&gt;link&lt;/a&gt;

A
A

構造体に定義された関数を呼び出した結果を利用する

package main

import (
	"fmt"
	"os"
	"text/template"
)

const templateString string = `
{{if call .F .Field}}TRUE {{/* 構造体に定義されたF関数をFieldフィールドを引数として呼び出す */}}
{{else}}FALSE
{{end}}
`

type Fields struct {
	Field int
    F func(n int) bool 
}

func validate(n int) bool {
    if n > 0 {
		return true
	}
	return false
}

func main() {
    f := Fields{-10, validate}

	var t = template.Must(template.New("text").Parse(templateString))

	if err := t.Execute(os.Stdout, f); err != nil { // 構造体Fieldsを渡す
		fmt.Println(err.Error())
	}
}

実行結果

FALSE

解説

変数

{{.}}{{range .}} {{.}} {{end}}のように直接値を出力するだけでなく、一度変数に格納した値を出力することができる。
任意の値を変数に格納するには以下のように記述する。

$変数名 := 値

配列の値だけでなく、インデックスを一緒に出力したい場合などに使用する。

{{range $i, $x := .}} {{$i}}:{{$x}} {{end}}

関数

  • bool値の評価にnot, and, orを利用できる。
  • not 引数

    引数のbool値をnot演算した結果を返す。

    and 引数1 引数2

    引数1引数2のbool値をand演算した結果を返す。

    or 引数1 引数2

    引数1引数2のbool値をor演算した結果を返す。

  • 配列、Slice、Mapのサイズ取得にlen任意のインデックスの値の取得にindexを利用できる。
  • len 引数

    引数のサイズを返す。

    index 引数1 引数2

    引数1のインデックス[引数2]の値を返す。

  • <や"などhtmlタグに用いる文字列をエスケープするためにhtmlを利用できる。
  • html 引数
    値 | html

    どちらも出力結果は同じ。
    |により、|の左側で評価された値が右側の関数の第2引数として用いられる。

  • fmtパッケージによるフォーマット変更にprint, printf, printlnを利用できる。
  • print 引数1 引数2 ...
    printf 引数1 引数2 ...
    println 引数1 引数2 ...
    値 | print 引数1

    fmtパッケージの各Print系関数を利用する。
    引数1にはフォーマット、引数2以降には出力対象の値を指定する。
    使用できるフォーマットはfmtパッケージの各Print系関数と同じ。
    例として以下のように使用する。

    {{printf "%c, %d" .Var1 .Var2}}

  • 構造体や変数に定義された関数を呼び出すためにcallを利用できる。
  • templateではアクションタグ内で四則演算等、何らかのロジックを実行した結果を出力することができない。
    代わりに、templateに渡す変数や構造体に定義した関数を呼び出しその結果を用いることができる。
    以下のようにアクションタグを指定する。

    call 関数名 (引数1) ...

    関数名で指定した関数を引数1に続く引数で呼び出す。
    引数がない場合は引数1以降の部分は省略する。
    変数や構造体には以下のように関数を定義する。

    type FuncStruct struct {
        F func(n int) string
    }
    
    func doSomething(n int) string {
        // do something
    }
    
    func main() {
        s := FuncStruct{doSomething}
        ...
    }
    

    この例で関数doSomethingを呼び出した結果を出力するには以下のようにアクションタグを指定する。

    {{call .F 100}}

    Go言語:templateパッケージでHTML等テキストファイルを読み込む(応用編1)

    templateパッケージでHTML等の任意のテキストファイルを読み込み、出力する方法を説明する。
    応用編ではテンプレート内に埋め込む「アクション」について解説する。
    なお、APIバージョンGo1で説明する。
    バージョン3ではパッケージ名、関数名が異なるので注意。

    概要

    templateパッケージでは、任意のテキストを読み込み、テキストに埋め込まれたタグに対してデータの評価や制御(アクションという)をおこなって出力する。いくつかのアクションの指定により、以下のようなことができる。

    • テンプレートに渡された引数や構造体のフィールドを出力する。
    • テンプレートに渡されたbool値を評価し、出力を制御する。
    • テンプレートに渡された配列、Slice、Mapのデータを繰り返し出力する。

    配列の要素をすべて表示するサンプル

    package main
    
    import (
    	"fmt"
    	"os"
    	"text/template"
    )
    
    const templateString string = `テンプレートの始め
    {{range .}}
    繰り返し処理 {{.}}
    {{end}}
    テンプレートの終わり
    `
    
    func main() {
    	var stringArray []string = []string{"Hello", "World", "!!!!"}
    	var t = template.Must(template.New("html").Parse(templateString))
    
    	if err := t.Execute(os.Stdout, stringArray); err != nil { // 配列を渡す 
    		fmt.Println(err.Error())
    	}
    }
    

    出力結果

    テンプレートの始め
    
    繰り返し処理 Hello
    
    繰り返し処理 World
    
    繰り返し処理 !!!!
    
    テンプレートの終わり
    

    構造体、Mapの要素の表示、if文による条件分岐を用いたサンプル

    package main
    
    import (
    	"fmt"
    	"os"
    	"text/template"
    )
    
    type Struct struct {
        SampleString string
        SampleMap map[string]MapValue
        SampleBool bool
    }
    
    type MapValue struct {
        IntValue int
        StringValue string
    }
    
    const templateString string = `テンプレートの始め
    {{with .}}
        Structが空でなければこの先を出力する
        {{.SampleString}}:フィールドの値を出力
        {{range .SampleMap}}
            Mapの繰り返し処理 {{.IntValue}}: {{.StringValue}}
        {{end}}
        {{if .SampleBool}}
            bool変数がtrueならば出力
        {{else}}
            bool変数がfalseならば出力
        {{end}}
    {{end}}
    テンプレートの終わり
    `
    
    func main() {
        values := Struct{"サンプルテキスト", make(map[string]MapValue), false}
        values.SampleMap["first"] = MapValue{1, "Hello"}
        values.SampleMap["second"] = MapValue{2, "World"}
        values.SampleMap["third"] = MapValue{3, "!!!!"}
    	var t = template.Must(template.New("text").Parse(templateString))
    
    	if err := t.Execute(os.Stdout, values); err != nil { // 構造体を渡す 
    		fmt.Println(err.Error())
    	}
    }
    

    出力結果

    テンプレートの始め
    
        Structが空でなければこの先を出力する
        サンプルテキスト:フィールドの値を出力
        
            Mapの繰り返し処理 1: Hello
        
            Mapの繰り返し処理 2: World
        
            Mapの繰り返し処理 3: !!!!
        
        
            bool変数がfalseならば出力
        
    
    テンプレートの終わり
    

    解説

    アクションタグの種類

    {{.}}

    テンプレートに渡された引数を出力する。

    {{.Member}}

    テンプレートに渡された引数が構造体の場合、Memberフィールドの値を出力する。

    {{if .}} 分岐1 {{else}} 分岐2 {{end}}

    テンプレートに渡された引数のbool値がtrueの場合「分岐1」が出力され、falseの場合「分岐2」が出力される。{{else}}は省略できる。

    {{range .}} {{.}} {{else}} なし {{end}}

    テンプレートに渡された引数が配列、Slice、Mapの場合、lengthが1以上の場合はすべての要素を表示し({{.}}を要素数分繰り返し)、lengthが0の場合には「なし」が表示される。{{else}}は省略できる。

    {{with .}} 分岐1 {{else}} 分岐2 {{end}}

    テンプレートに渡された引数の値が空でない場合「分岐1」が出力され、空の場合「分岐2」が出力される。{{else}}は省略できる。

    応用

    テンプレートを実際のWebアプリケーションに用いる例を紹介する。
    サンプルとしてLegacy-BBSを参照してもらいたい。
    このサンプルは、下記の2つの部分に分かれている。

    • メッセージを投稿するためのフォーム部分
    • 投稿時に名前やメッセージが空白でないかのバリデーションを行い、エラーメッセージを表示する。
      バリデーションの結果を{{if}}で判定し、エラーの表示をおこなう。

    • 投稿されたメッセージを表示する部分
    • データストアに格納されている複数のメッセージを表示する。
      メッセージは構造体Entry_viewの配列に格納し、{{range}}により表示をおこなう。

    構造体とテンプレートのサンプルは下記の通り。
    なお、この例にはこれらの構造体のデータを取得・出力するロジックは省略している。
    ロジックについてはまた別の機会に説明する。

    type View struct {
    	Entries      []Entry_view
    	Errors       Validation
    }
    
    type Entry_view struct {
    	Name    string
    	Email   string
    	Title   string
    	Message string
    	Date    string
    }
    
    type Validation struct {
    	NameError    bool
    	MessageError bool
    }
    
    <html>
    <body>
        <p>Legacy BBS Sample</p>
        {{/* メッセージを投稿するためのフォーム部分 */}}
        <form method="POST" action="">
            {{with .Errors}}
                Submitter
                <input type="text" name="name" /><br />
                {{if .NameError}}<font color="red">Enter a submitter</font><br />{{end}}
                Mail
                <input type="text" name="email" /><br />
                Title
                <input type="text" name="title" /><br />
                Message
                <textarea name="message"></textarea><br />
                {{if .MessageError}}<font color="red">Enter a message</font><br />{{end}}
                <input type="submit" name="submit" value="Submit" />
            {{end}}
        </form>
    
        {{/* 投稿されたメッセージを表示する部分 */}}
        {{range .Entries}}
            <hr />
            <p>
                {{.Title}}  Submitter:
                {{if .Email}}<a href="mailto:{{.Email}}">{{.Name}}</a>
                {{else}}{{.Name}}
                {{end}}
                Date: {{.Date}}
            </p>
            <p>{{.Message}}</p>
        {{end}}
    </body>
    </html>
    

    応用編2ではアクションタグに使用できる関数や変数を説明する。

    Go言語:templateパッケージでHTML等テキストファイルを読み込む(基礎編)

    templateパッケージでHTML等の任意のテキストファイルを読み込み、出力する方法を説明する。
    なお、APIバージョンGo1で説明する。
    バージョン3ではパッケージ名、関数名が異なるので注意。

    概要

    templateパッケージでは、任意のテキストファイルを読み込み、テキストファイルに埋め込まれたプレースホルダに文字列を変換して出力する。例えば、以下のような機能を利用できる。

    • ブラウザからのgetリクエストに対して外部HTMLファイルを読み込み、任意のデータをHTMLに埋め込んでレスポンスとして返す。
    • メールの本文テンプレートとして作成したテキストファイルを読み込み、任意のデータを本文に埋め込んでメールを送信する。

    単にhtmlファイルを読み込んで出力するだけのサンプル

    package main
    
    import (
        "os"
        "fmt"
        "text/template"
    )
    
    func main() {
    	var t = template.Must(template.ParseFiles("plainSample.html")) // 外部テンプレートファイルの読み込み
        
    	if err := t.Execute(os.Stdout, nil); err != nil { // テンプレート出力
            fmt.Println(err.Error())
        }
    }

    plainSample.html

    <html>
        <head>
            <title>Sample Html</title>
        </head>
        <body>
            <h1>Htmlサンプル</h1>
            サンプルテキスト
        </body>
    </html>

    出力結果

    <html>
        <head>
            <title>Sample Html</title>
        </head>
        <body>
            <h1>Htmlサンプル</h1>
            サンプルテキスト
        </body>
    </html>

    プレースホルダを使用した場合のサンプル

    package templatesample
    
    import (
        "fmt"
        "net/http"
        "text/template"
    )
    
    type Member struct {
        Name string
        Message string
    }
    
    func init() {
        http.HandleFunc("/", handler)
    }
    
    func handler(w http.ResponseWriter, r *http.Request) {
        member := Member{"inatus", "はじめまして。<br>よろしくお願いいたします。"}
        var t = template.Must(template.ParseFiles("placeholderSample.html")) // 外部テンプレートファイルの読み込み
        
    	if err := t.Execute(w, member); err != nil { // テンプレート出力
            fmt.Println(err.Error())
        }
    }
    

    placeholderSample.html

    <html>
        <head>
            <title>Sample Html</title>
        </head>
        <body>
            <h1>Htmlサンプル</h1>
            <h3>{{.Name}}</h3>
            {{.Message}}
        </body>
    </html>

    ブラウザ表示結果

    出力をstring型のオブジェクトに格納するサンプル

    
    package main
    
    import (
        "fmt"
        "bytes"
        "text/template"
    )
    
    type Member struct {
        Name string
        Message string
    }
    
    func main() {
        member := Member{"inatus", "はじめまして。<br>よろしくお願いいたします。"}
        var body bytes.Buffer
        var t = template.Must(template.ParseFiles("placeholderSample.html")) // 外部テンプレートファイルの読み込み
        
    	if err := t.Execute(&body, member); err != nil { // テンプレート出力
            fmt.Println(err.Error())
        }
    
        var str string = body.String()
    }
    

    解説

    パッケージ

    下記の2種がある。

    • text/template: 汎用テンプレート用のパッケージ。
    • html/template: プレースホルダに変換対象の文字列のhtmlタグをエスケープする。サニタイジングに有効。

    インポートするパッケージをhtml/templateに変更して上記の「プレースホルダを使用した場合のサンプル」を実行した結果は以下の通り。

    内部的には<&lt;>&gt;といったように文字列変換される。

    テンプレートの読み込み

    var t = template.Must(template.ParseFiles("placeholderSample.html"))

    template.ParseFiles関数の引数で渡すパスにあるファイルを読み込む。
    パスではなくstringをそのまま引数に渡すこともできる。

    var t = template.Must(template.New("html").Parse("<html><body>サンプル</body></html>"))

    プレースホルダ変換文字列の指定と出力

    if err := t.Execute(w, member); err != nil { // テンプレート出力
        fmt.Println(err.Error())
    }

    上記のテンプレート読み込みの出力変数に対しExecute関数を実行する。
    1つ目の引数には出力先のio.Writerインタフェイスを指定する。io.Writerインタフェイスには例えば下記のようなものがある。

    • http.ResponseWriter: httpレスポンスへの出力
    • os.Stdout: 標準出力
    • bytes.Buffer: 変数への出力

    2つ目の引数にはプレースホルダへの変換対象となる文字列を含んだ変数(通常は構造体)を指定する。読み込んだテンプレートのプレースホルダ名({{.Variable}})は必ず構造体のメンバ名として存在しなければならない。

    応用編では使用できるプレースホルダのバリエーションを解説する。

    Go言語でWebアプリケーションを作成する

    githubレポジトリに公開しているSpring MVCで実装したLeagacyなBBSサンプルと同じ物をGo言語で実装してみた。
    ポイントはどこまでSpring MVCに肉薄できるか。


    Go言語実装のLegacyBBSサンプルのgithubレポジトリ
    Google App Engineにデプロイ済みサンプル

    次回以降、数回に分けて要素技術を紹介していく。

    Javaアプリケーションコンテナ Jelasticの使い方

    JavaアプリケーションコンテナのJelasticを試してみた。

    イメージとしてはGoogle App EngineのJavaに特化した版。

    現在beta版で無料で使えることもあって、一度試してみる価値あり。

    Jelasticのトップ画面。

    まずはサーバの場所を北米とヨーロッパから選び、メールアドレスを入力してアカウント登録をする。

    現時点ではヨーロッパサーバのほうが軽い印象。

    メールで認証コードが送られてくるので入力する。

    構成を決める。

    Cloudletという単位でノードに割り当てるリソースを設定できる。

    負荷分散構成も可能。

    アプリケーションサーバとJavaのバージョンも同時に指定する。

    データベースにはNoSQLも指定できる。

    今回はレガシーBBSサンプルをデプロイするので、実行環境に合わせ、Java 6、Tomcat 6、MySQL 5.0を選択。

    コンソール画面。

    まずはMySQLの設定を行う。

    MySQL 5.5の右側のOpen in browserアイコンをクリック。

    メールに届いているID、Passwordによりログインする。

    MySQLのコンソール画面。

    データベースタブを選択。

    データベース一覧。

    今回はtestデータベースにアプリケーションを動かすために必要なテーブルを挿入する。

    testをクリック。

    操作タブを開き、エンコーディング(照合順序)をutf8_general_ciに変更する。

    SQLタブを選択し、githubレポジトリのentry_table.sqlの内容をコピペして実行。

    構造タブを確認すると、entryテーブルが追加されている。

    次にtestデータベースにユーザを追加する。

    特権タブから、「新しいユーザを追加する」をクリック。

    ユーザ名、パスワードを入力してユーザを追加する。

    Jelasticコンソールを開き、MySQL 5.5の右側のconfigアイコンをクリックする。

    中程のビューからmy.cnfを開き、画像の箇所に下記の設定を追加する。

    default-character-set=utf8
    character_set_server=utf8
    skip-character-set-client-handshake

    Saveし、MySQL 5.5の右側のRestart nodeアイコンからリスタートする。

    MySQL 5.5の右側のInfoメニューからデータベースのURLを確認する。

    githubレポジトリからコードをダウンロードし、src/main/resources/META-INF/jdbc.propertiesを編集してデータベースのURL、先ほど作成したユーザ名・パスワードを設定してmavenからwarファイルにpackageする。

    中程のDeployment managerタブのUploadボタンから作成したwarファイルをアップロードする。

    しばらくするとアップロードされる。

    アップロードが完了したwarファイルの右側のアイコンから環境名を選択する。

    以上で設定・デプロイが完了。

    Tomcat 6の下に表示されるwarファイル名の右側のOpen in browserアイコンからアプリケーションを実行する。

    アプリケーションの実行ができた。
    印象としてはちょっと重い。
    正式サービスが始まったらいくらくらいになるのだろうか。