APR
18

_images/acslogo.pngApache CloudStackのCommitterになりました。CloudStackのKVMサポート周りへパッチを投げてきたことが評価されたのでしょうか。CloudStackの開発への参加を通じて、OSS開発のワークフローや、大規模ソフトウェアのアーキテクチャ設計など、それぞれのメリット・デメリット含めて、多くのことを学ぶことが出来ました。まだまだ力不足感は否めませんが、これからも時間を見つけてApache CloudStackコミュニティへの貢献を続けることで、その発展の一助になれればと思います。

APR
4

Roslyn build preview公開

Published:2014-04-04 15:57:20 UTC

BUILD 2014のKeynoteの場で、C# CompilerのC#再実装であるRoslynの最新プレビュー版が公開されましたね。合わせて、RoslynのApache License 2.0でのOSS化も発表され、.NET界隈にとって、エポックメイキングな発表でした。これで、Mono(やXamarin)はランタイムやOSS化されていないライブラリの開発に注力すればよいことになり、Windows以外でのC#利用も促進されそうです。

ざっとRoslynのドキュメントに目を通した限りでは、以前のCTPから大きく追加されたAPIなどは見当たらず(Scripting機能とかどうなっているのでしょう)、むしろC#の言語機能の細かい強化に注力していたのでしょうか。新しい言語機能については、SDKに添付のUpcoming Features in C#というドキュメントが詳しく、さっそく.NET Compiler Platform (Roslyn) Preview | ++C++; // 未確認飛行 C ブログ: で解説がされています。

ドキュメントを読んでいて個人的に気になったのが、FAQのCan I rewrite source code within the compiler pipeline? という項目で、残念ながら、コンパイラパイプラインの途中でフックして動作に介入することは出来ないようです。Roslynが最初に発表された時の謳い文句として、モノシリックなこれまでのコンパイラのパイプラインをコンポーネントごとに分割してユーザーに開放する、というのがあったように記憶しているのですが、やはりパフォーマンスの要件的にパイプラインの途中への介入は実現できなかったのでしょうか。属性でのマークアップベースのDSLからコンパイル時にメモリ上のSyntaxを書き換えるようなものを作りたいと考えていたので、少し残念です。MSBuildでpre-buildのターゲットとしてcsc.exeにコードが渡る前にコードを書き換える方法が代替手段として提示されていますが、その場合だとコードを書き換えた結果をファイルに書き出すことになり、コードの再編集が必要になった時に使いづらいDSLになってしまうのが懸念点です。

なんにせよ、C#が着実に前に進んでいることが感じられるKeynoteでした。より詳細が解説された各セッションのスライド、ビデオの公開が待ち遠しいですね。

APR
4

OneGet

Published:2014-04-04 15:09:58 UTC

OneGetという、Microsoft公式のパッケージマネージャが公開されたようです。Windows Serverにとって地味にインパクト大な新ツールになりそうですね。ようやくか、という気もします。プラガブルな構造をとっており、裏の実装はプラグインという形で差し替えられるようです。現在は、Chocolateyを利用するためのプラグインが提供されているようですが、Chocolateyはその提供されているパッケージの信頼性を担保するための仕組みが十分に機能しているとは言えないので、Microsoft公式でパッケージの提供元を認証したレポジトリが欲しいものです。逆にそういった信頼性を担保するための仕組みがないと、Chocolatey同様、利用は厳しいですね。

前回のエントリでは、Marvinを用いて、CloudStackの結合テストを実行する方法について解説しました。その際、テストの実行環境としてUbuntuを使用しましたが、普段自分はWindows上のIntelliJ IDEA Community Editionを使ってCloudStackのコードを開発している為、テストコードの開発、実行環境も出来ればWindowsに揃えたいところです。このエントリでは、Marvinのテストコード開発環境をPyCharmを使ってWindows上に構築した際の手順を解説します。

ツールのインストール

PyCharm

image

IntelliJ(のCommunity Edition)は、Java開発用のIDEですが、IntelliJから派生したPython開発用のIDEとして、PyCharmというものがあります。このPyCharm、IntelliJと同じく、Community Editionとしてフリー版が用意されており、今回はこれを利用してMarvinのテストを記述する方法を解説していきます。

http://www.jetbrains.com/pycharm/ からダウンロードできます。

Java

PyCharmの実行は、Javaが必要であり、また、後半の手順で、Marvinをコンパイルする際にも必要になるので、インストールしましょう。

http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html からダウンロードできます。

インストールが出来たら、忘れずにPATHを通しておきましょう。

MinGW

後半の手順で、MarvinをMavenでコンパイルする際に、bashが必要になります。MinGWなどをインストールしましょう。

http://www.mingw.org/ からダウンロードできます。

Python for Windows

PyCharmは、あくまでもIDEであり、Pythonの実行環境は提供しません。Python for windowsを別途インストールしましょう。

http://www.python.org/downloads/ からダウンロードできます。

インストールが出来たら、忘れずにPATHを通しておきましょう。

setuptools、pip

Pythonのパッケージ管理システムのsetuptools、pipをインストールしましょう。setuptoolsをセットアップするためのPythonスクリプトが配布されていますので、ダウンロードの上実行し、setuptoolsがパッケージを配置するC:\Python27\ScriptsにPATHを通した上でeasy_installコマンドからpipをインストールしましょう。

wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py
python ez_setup.py

# ここでC:\Python27\ScriptsをPATHに設定

easy_install pip

Marvinが依存する外部ライブラリ

続いてはMarvinが依存する外部ライブラリです。mysql-connector-pythonと、pycryptoが必要ですので、それぞれインストールしましょう。

http://dev.mysql.com/downloads/connector/python/

http://www.voidspace.org.uk/python/modules.shtml#pycrypto

Marvin

そして本命のMarvinのインストールです。こちらは、Mavenでビルドしてパッケージを作成し、それを先ほどインストールしたpipでインストールするという流れになります。

まずは、CloudStackの開発に使用しているIntelliJで、MavinをMavenでビルドし、パッケージを作成しましょう。(IntelliJによるCloudStackの開発環境の構築は、CloudStack開発ことはじめ (1)開発環境のセットアップ –IntelliJ IDEA Community Editionのススメ -をご覧ください。)

image

作成されたパッケージは、tools/marvin/distディレクトリ以下に配置されます。

以下のように、pipコマンドでインストールを行いましょう。インストールを行うと、依存するパッケージ(nosetests)なども同時にインストールされます。

pip install tools/marvin/dist/Marvin-0.1.0.zip

以上で、一連のインストールは完了です。

PyCharmのセットアップ

プロジェクトの作成

続いて、PyCharmのセットアップを進めていきましょう。まずは、CloudStackのPyCharmプロジェクトの作成です。IntelliJでCloudStackの開発をする際に使用しているプロジェクトをそのまま使いたいところですが、使用しようとするとプロジェクトファイルが競合してしまいます。仕方がないので、別のディレクトリにレポジトリをクローンしてそのレポジトリをインポートする形で別のプロジェクトとして開発を進めましょう。

git clone https://github.com/apache/cloudstack.git cloudstack_py

プロジェクトのテストランナーの変更

CloudStackの結合テストは、nosetestsで書かれていますので、PyCharmで結合テストを実行するには、プロジェクトのテストランナー設定を変更する必要があります。
ProjectのSettingsダイアログを開き、Python Integrated Tools->Default test runnerと項目を辿り、”Notestests”に設定しましょう。

image

テストコード実行時のパラメータの変更

続いて、nosetestsのオプションのデフォルトパラメータの変更を行い、nosetestsにmarvinプラグイン、marvinのconfigが読み込まれるようにしましょう。

--with-marvin --marvin-config=<MarvinのConfigへのパス> --load

 

テストの実行

テストの実行は、テストコードのコンテキストメニューから開始できます。
image

 

PyCharmに統合されたテストランナーの表示

テスト結果は、PyCharmに統合されたテストランナーが進捗含めわかりやすく表示してくれます。
image

PyCharmでのデバッグ実行

続いては、デバッグ実行です。ブレークポイントを打ち、デバッグ実行することで、コードの実行を任意の箇所で止めながらデバッグすることが可能です。

image
勿論、操作感は、IntelliJやRubyMineと同じです。その場で書いたコードを現在のコンテキストで評価する、Expression Evaluationウィンドウも健在です。いいですね。

以上、PyCharmでMarvinによるCloudStackのテストコードをデバッグする方法の紹介でした。今回のエントリが、テストコード開発を始めるきっかけになれば幸いです。

 

 

なお、自分は触ったことはないですが、Windows上で動作するPython IDEのもう一つの選択肢として、Python Tools for Visual StudioというIDEもあります。Visual Studioというとお高そうなイメージがありますが、こちらは無償です。PyCharmと比較すると、nosetestsのテストランナーが統合されてない点は劣りますが、一方でPyCharm Community Editionでは提供されていない、リモートデバッグ機能があるなど、優れた点もあります。こちらも、検討してみると面白いかもしれません。
image

http://cloudstack.jp/wp-content/uploads/2014/02/ccc.japan_32.jpg3/6にCloudStack Day Japan 2014というCloudStackについてのカンファレンスが東京のソラシティ カンファレンスセンターで開催されるそうです。Apache CloudStackのPMC(Project Management Committee)メンバーのChip ChildersやHugo Trippaersも来日してセッションを持つそうなので、非常に期待が持てますね。そのCloudStack Day Japan関連のBlogイベントである、CloudStack Blogコンテストに、このエントリは参加しています。

 

以前、「CloudStack開発ことはじめ」と題して、CloudStackの開発環境をセットアップする手順として、IntelliJ IDEAでCloudStackをビルド、デバックしたり、JenkinsでCloudStackのパッケージをビルドする手順を紹介しました(1) (2) (3)。ビルド、デバッグ、パッケージングまできたら、次のテーマはテストでしょう、ということで、今回のエントリでは、Marvinを利用した、CloudStackの結合テストの自動化について解説を行います。

Marvinとは

Marvin is the CloudStack automation framework. It originated as a tool for integration testing but is now also used to build DevCloud as well as to provide a Python CloudStack API binding.

CloudStack Developer Guide

…ということで、MarvinとはCloudStackの自動化フレームワークです。今回目的の結合テストだけでなく、DevCloudや、Pythonの CloudStack API bindingにも使われているようですね。

 

環境構成

今回は、このMarvinを用いて、DevCloudではない、物理ホスト上にデプロイされたCloudStackに対して、結合テストを実行することをゴールとします。DevCloudも手軽でよいのですが、より信頼性の高いテスト結果を得るためには、結合テストはサービスを実際に展開する構成と揃えたテスト環境で実行したいものです。ということで、今回は、既に物理サーバー上に構築済みのCloudStack環境に対してMarvinで結合テストを走らせることを目的とします。

Marvinのインストール

git clone https://github.com/apache/cloudstack.git
cd cloudstack
mvn -P developer,systemvm clean install
mvn -P developer -pl :cloud-apidoc
mvn -P developer -pl :cloud-marvin

まずは、cloudstackのソースコードを落としてきた上で、MarvinのパッケージをMavenでコンパイルします(紛らわしい。。)ドキュメントによると、依存関係にあるのはAPIdocだけ、という話だったのですが、実行してみたところエラーが出てしまったのでとりあえずCloudStackの普通のコンパイルも行ったうえで再度APIdocとMarvinのパッケージのコンパイルを試みたところ、成功しました。

ls -al tools/marvin/dist
total 256
drwxrwxr-x 2 ynojima ynojima   4096  3月  3 04:58 .
drwxrwxr-x 6 ynojima ynojima   4096  3月  3 05:03 ..
-rw-rw-r-- 1 ynojima ynojima 251359  3月  3 05:03 Marvin-0.1.0.tar.gz

コンパイルに成功すると、tools/marvin/dist以下に、Marvinのパッケージが出来ています。

pip install tools/marvin/dist/Marvin-0.1.0.tar.gz

これを、pipでインストールしてmarvinのインストールは完了です。

Management Serverの設定

さて、Marvinは、CloudStackの処理の自動化と、その結果のAssertのために、CloudStackのAPIキーとCloudStackのデータベースへの接続を必要とします。

RootAdmin権限を持つユーザーのAPIキーを用意しておきましょう。Accounts、Usersと辿っていった先の鍵穴マークのアイコンから生成できます。

image

続いてデータベースへの接続。CloudStackのデータベースをcloud-setup-databasesコマンドでセットアップすると、確か全ソースIP addressからの接続を許可したcloudというユーザーを作成してくれちゃっているので、

iptables -I INPUT -p tcp --dport 3306 -j ACCEPT

iptablesでMySQLのポートを開けてやると、別ホストからMavinを実行出来るようになります。今回は簡単のため、ソースIP addressを絞っていませんが、Management Serverが直接インターネットに面している場合は、ちゃんと絞りましょう。

Marvinの設定ファイル

続いて、Marvinの設定ファイルを用意しましょう。

{
    "dbSvr": {
        "dbSvr": "<mysql server ip address>",
        "passwd": "cloud",
        "db": "cloud",
        "port": 3306,
        "user": "cloud"
    },
    "mgtSvr": [
        {
            "mgtSvrIp": "<management server ip address>",
            "port": <api port>,
            "apiKey": "<api key>",
            "securityKey": "<security key>" // secretkeyではない点注意
        }
    ]
}

Marvinの設定ファイルはJSON形式です。最低限必要な情報は、以上の通りです。前項で用意したAPIキーと、DBアクセス情報を埋めた上で、保存してください。

Marvinのテストコード

MarvinのテストコードはPythonのテストフレームワークである、noseで記述されます。mavinは、noseのプラグインという位置づけで、テストコードの基本的な記述方法は、noseのドキュメントを参考にすると良いでしょう。

また、test/integrationディレクトリ以下に、Marvinで記述されたCloudStackのテストコードが山とありますので、こちらも参考にすると良いでしょう。

一例として、以下にtest/integration/test_global_settings.pyに対してコメントを付けたものを載せます。

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
""" P1 tests for updating the granular Configuration parameter with scope and resource id provided.
"""
#Import Local Modules
from marvin.cloudstackTestCase import *
from marvin.cloudstackAPI import *
from marvin.integration.lib.utils import *
from marvin.integration.lib.base import *
from marvin.integration.lib.common import *
from nose.plugins.attrib import attr
#Import System modules

class TestUpdateConfigWithScope(cloudstackTestCase): #noseでは、Testで始まるクラスがテストケース扱いされます
    """
    Test to update a configuration (global setting) at various scopes
    """
    def setUp(self): #xUnitフレームワークでおなじみのsetUpメソッド。テスト環境の準備をここで記述します。クラスメソッドとしてやれば、各テストメソッド毎の実行ではなく、テストクラス毎に実行されます。
        self.apiClient = self.testClient.getApiClient() #設定ファイルに記述したAPIキーがセットされたAPIClientのインスタンスの取得。getDbClientとすれば、DBのクライアントが取得出来ます。

    @attr(tags=["simulator", "devcloud", "basic", "advanced"]) #テストコードを実行する条件
    def test_UpdateConfigParamWithScope(self):
        """
        test update configuration setting at zone level scope
        @return:
        """
        updateConfigurationCmd = updateConfiguration.updateConfigurationCmd() #設定変更APIコマンドの組み立て
        updateConfigurationCmd.name = "use.external.dns"
        updateConfigurationCmd.value = "true"
        updateConfigurationCmd.scopename = "zone"
        updateConfigurationCmd.scopeid = 1

        updateConfigurationResponse = self.apiClient.updateConfiguration(updateConfigurationCmd) #APIコマンドの呼び出し
        self.debug("updated the parameter %s with value %s"%(updateConfigurationResponse.name, updateConfigurationResponse.value))

        listConfigurationsCmd = listConfigurations.listConfigurationsCmd()
        listConfigurationsCmd.cfgName = updateConfigurationResponse.name
        listConfigurationsCmd.scopename = "zone"
        listConfigurationsCmd.scopeid = 1
        listConfigurationsResponse = self.apiClient.listConfigurations(listConfigurationsCmd) #先ほど変更した設定の読み出し

        self.assertNotEqual(len(listConfigurationsResponse), 0, "Check if the list API \
                            returns a non-empty response")

        for item in listConfigurationsResponse:
            if item.name == updateConfigurationResponse.name:
                configParam = item

        self.assertEqual(configParam.value, updateConfigurationResponse.value, "Check if the update API returned \
                         is the same as the one we got in the list API") #変更時のAPIの戻り値とListした結果の比較

    def tearDown(self): #xUnitフレームワークでおなじみのtearDownメソッド。変更した設定の取り消し
        """
        Reset the configuration back to false
        @return:
        """
        updateConfigurationCmd = updateConfiguration.updateConfigurationCmd()
        updateConfigurationCmd.name = "use.external.dns"
        updateConfigurationCmd.value = "false"
        updateConfigurationCmd.scopename = "zone"
        updateConfigurationCmd.scopeid = 1
        self.apiClient.updateConfiguration(updateConfigurationCmd)

 

Marvinの実行

では、実際に結合テストを実行してみましょう。noseのテストランナーはnosetestsコマンドで、以下のようにオプションを指定して実行します。

nosetests --with-marvin --load --log-folder-path=<ログの出力ディレクトリ> --marvin-config=<Marvinの設定ファイル> <Marvinのテストコード>

すると、指定したログ出力ディレクトリ以下に、タイムスタンプが名前になったディレクトリが作成され、その下にfailed_plus_exceptions.txt、results.txt、runinfo.txtの3ファイルが作成されます。
テストの実行に成功すると、results.txtには以下のような出力がされ、失敗した場合は、failed_plus_exceptions.txtに失敗時のスタックトレースが出力されます。

test update configuration setting at zone level scope ... ok

----------------------------------------------------------------------
Ran 1 test in 0.147s

OK

VMのデプロイテスト

では次はVMのデプロイの結合テストを実行してみましょう。同じく、test/integration/smokeディレクトリ以下に、test_deploy_vm.pyというテストコードがあります。VMのデプロイを行い、そのレスポンスの検証を行ってくれるテストケースです。
一部、私の手元の物理サーバーで構築したCloudStack(KVM)環境だと動かなかった点があるので、注記すると、コンストラクタの中でテストデータを記述している部分で、デプロイに利用するテンプレートのostypeがCentOS 5.3 (64bit)となっていましたが、手元のCloudStack 4.3 RCの検証環境では、5.5のテンプレートが配備されているので、その点だけ修正する必要がありました。

 

    def __init__(self):
        self.testdata = {
            #data to create an account
            "account": {
                "email": "test@test.com",
                "firstname": "Test",
                "lastname": "User",
                "username": "test",
                "password": "password",
            },
            #data reqd for virtual machine creation
            "virtual_machine" : {
                "name" : "testvm",
                "displayname" : "Test VM",
            },
            #small service offering
            "service_offering": {
                "small": {
                    "name": "Small Instance",
                    "displaytext": "Small Instance",
                    "cpunumber": 1,
                    "cpuspeed": 100,
                    "memory": 256,
                },
            },
            "ostype": 'CentOS 5.5 (64-bit)',
        }

これを修正の上、同じく実行すると、

nosetests --with-marvin --marvin-config=../marvin/esxi.cfg --load test/integration/smoke/test_deploy_vm.py --log-folder-path=../marvin/

image
VMの作成が自動で行われ…

image
やがて立ち上がり、アサート処理が行われ、最終的に自動で削除されます。

テスト結果:

Test Deploy Virtual Machine ... ok

----------------------------------------------------------------------
Ran 1 test in 227.015s

OK

ちなみに、テストランナーの実行時に、テストファイルの指定を外してやると、そのディレクトリ以下のテストケースが全て実行されます。便利ですね。

nosetests --with-marvin --marvin-config=../marvin/esxi.cfg --load --log-folder-path=../marvin/

 

おわりに

以上、CloudStackの結合テストをMarvinで自動化する方法でした。ソフトウェアの開発は、バグとの戦いであり、バグを洗い出すためのテストの自動化は必須です。特に、CloudStackは、セットアップの一手順毎に時間のかかるリソース(VM、ストレージ)を管理するソフトウェアであることから、結合テストの各ケースの消化にとにかく時間が掛かるものであり(VMデプロイテストは自動化しても上の結果の通り、227秒掛かっています)、また複数のハイパバイザ、複数のストレージタイプ、ネットワークタイプをサポートしていることから、組み合わせは膨大な数に昇り、人手で実施しようとすると追いつきません。自動化することで、夜間バッチで実行したり、多数のマシンを並べて、並列実行させることも可能になります。今回は、既に構築済みのCloudStack環境に対して、Marvinでテストを実行する方法を解説しましたが、Marvinは、ゾーンやポッドの構成を設定ファイルに記述することで、テスト環境のセットアップの自動化も行う機能もあり、多数のテスト環境の構築の自動化用途にも最適です。

Marvinは、CloudStackの開発者にとって、自分の書いたコードが、ユーザーに対してリグレッションを発生させていないか確認する強力な手段です。OSSは、地理的に離れた様々な人が一つのコードベースをよってたかって開発する以上、テストのないコードは、壊されても文句は言えません。開発する際に、Marvinでの結合テストのコードも書いてコミットしておけば、今後別のCloudStackのコントリビュータがコードを弄った場合も、ユーザーに対してリグレッションが起きないことを担保出来ます。

そして同時に、MarvinはCloudStackのオペレータにとっても、強力なツールの一つになりえます。プロダクション環境のCloudStackに対して、デプロイやスナップショットのテストといった、ユーザー操作を模したテストを定期実行すれば、ユーザーからみたサービスの健全性の監視に使えます。ステージング環境に構築した新しいバージョンのCloudStackに対して自社の利用環境にあわせてカスタマイズしたテストスイートをMarvinで実行することは、CloudStack APIの受け入れテストの自動化に使えます。更に進めて、Communityで開発中のコードに対して自動化された結合テストを常に実行し、バグがあればコミュニティにフィードバックを行うようにすれば、開発段階の時点で、自社の利用環境で発生するリグレッションを潰すことが出来、サービスイン前の受け入れテスト不合格からくるプロジェクト遅延のリスクを抑えることが出来ます。

以上、今回のエントリが、CloudStack開発、そして結合テストを始めるにあたっての参考になれば幸いです。

FEB
6

https://issues.apache.org/jira/browse/CLOUDSTACK-2328 で教えてもらった話なのですが、CentOS 6.5のカーネルにVXLANサポートがバックポートされて使えるようになっています。便利になりましたね。

# ip link add vxlan0 type vxlan id 1000 group 239.1.1.1 dev eth0
# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:fc:8b:9b brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 00:0c:29:fc:8b:a5 brd ff:ff:ff:ff:ff:ff
4: eth2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 00:0c:29:fc:8b:af brd ff:ff:ff:ff:ff:ff
5: eth3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 00:0c:29:fc:8b:b9 brd ff:ff:ff:ff:ff:ff
8: vxlan0: <BROADCAST,MULTICAST> mtu 1450 qdisc noop state DOWN
    link/ether 6a:97:59:a7:90:65 brd ff:ff:ff:ff:ff:ff
FEB
6

Management Serverをセットアップする前に、vhd-utilをManagement Serverに配置しておく必要があります。

参考:https://cloudstack.apache.org/docs/en-US/Apache_CloudStack/4.0.2/html/Installation_Guide/management-server-install-flow.html

ライセンス上の問題から、一緒に配布出来ないための措置の模様。面倒ですね。。あまりマニュアル読まずに進めてたら嵌りました。。

rsyncで/var/www/html/centos以下にミラーを取得する方法のメモ。過去のリリースが含まれたミラーをrsyncで公開してくれているftp.rken.jpに感謝。

#!/bin/bash

rsync="/usr/bin/rsync -avSHP --delete"
mirror="rsync://ftp.riken.jp/centos"

verlist="6.3 6.4 6.5"
baselist="os updates addons extras isos"
archlist="x86_64"
repo_base_dir="/var/www/html/centos"

if [ -f /var/lock/subsys/rsync_updates ]; then
    echo "Updates via rsync already running."
    exit 0
fi

touch /var/lock/subsys/rsync_updates

for ver in $verlist
do
  for base in $baselist
  do
    for arch in $archlist
    do
      repo_dir=$repo_base_dir/$ver/$base/$arch/
      remote=$mirror/$ver/$base/$arch/

      mkdir -p $repo_dir

      $rsync $remote $repo_dir
    done
  done
done

rm -f /var/lock/subsys/rsync_updates

このエントリは、CloudStack Advent Calendarの12月17日分のエントリです。

さて、12/4のエントリでは、CloudStackをIntelliJ IDEAでビルドする方法を説明しました12/6のエントリでは、JenkinsでCloudStackのdebパッケージをビルドする方法を説明しました。今日はそのdebパッケージを使ってCloudStackを実際に構築したとして、その環境をIntelliJ IDEAからリモートデバッグをする方法を解説します。

Debuggee(CloudStack)の設定

CloudStackはJavaのプログラムですが、Javaは起動時のオプションで、リモートデバッグの受付を設定出来ます。Management Serverの場合はTomcatの設定ファイル(/etc/cloudstack/management/tomcat6.conf)、KVM Host Agentの場合は起動スクリプト(/etc/init.d/cloudstack-agent)内で起動オプションを設定変更できるので、例えば以下のように変更を加えると、8787番ポートでデバッガのアタッチを待ち受けるようになります。

sed -i 's/JAVA_OPTS="/JAVA_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,address=5005,server=y,suspend=n /g' /etc/cloudstack/management/tomcat6.conf
sed -i 's/$JSVC -cp/$JSVC -Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005 -cp/g' /etc/init.d/cloudstack-agent

なお、上記の例ではsuspendオプションにnを渡していますが、yを渡すと、デバッガがアタッチされるまで実行が抑止されます。このオプションは、起動してすぐ、デバッガをアタッチする間もなく実行されてしまう箇所のデバッグをするときに有効です。yを渡しておくと、デバッガがアタッチされるまで実行が抑止されることでその箇所のデバッグが可能になります。

Debugger(IntelliJ IDEA)の設定

“Run”メニューの”Edit configuration”メニューから、“Run/Debug Configuration”ウィンドウを開きます。

すると、デバッグ対象を左上の"+"ボタンから追加できるので、"Remote"を選択して追加し、NameとHost、Portを対象のサーバーにあわせて適宜編集してください。

image

これを対象のサーバー分だけ繰り返すと、Debugボタンを押したときにデバッグ対象を選択してリモートデバッグを行えるようになります。

image

当然、ソースコード中にブレークポイントを置いてコードの実行を一時停止させたり、

image

Intelli J IDEAの"Expression Evaluation"ウィンドウという、Visual Studioで言うところの"Immidiate Window"的な、入力した式を現在のスコープで評価するツールを使ったりすることも出来ます。

image

ちょっと短めですが、以上、CloudStackをIntelliJ IDEAでリモートデバッグするまでの手順の紹介でした。CloudStackは、比較的OSSとしてはドキュメントが充実している方ですが、それでも開発が非常にアクティブなこともあり、ドキュメント化されていない仕様や、周知が十分でない仕様変更が多くあります。CloudStackの開発にこれから取り組もうという方は勿論、CloudStackを導入するにあたって、仕様を深く理解しようとコードを追う人にとっても、この記事が一つの参考になれば幸いです。

このエントリは、CloudStack Advent Calendar 12月6日分のエントリです。

前回のエントリに引き続きCloudStackの開発方法について書いていきます。前回のエントリではIntelliJ IDEAを使って、CloudStackのコードを手元でビルド出来るところまでセットアップする方法を紹介しました。ただビルドするだけではなく、パッケージとして纏めるところまで出来たら、自分でコードの変更を加えたCloudStackをインストールしてテストするときに便利だよね、ということで、今日はamd64版向けのdebパッケージを自分でビルドしてみましょう。そして、debパッケージをビルドするだけではなく、今回はJenkinsでビルドサーバーを立てて、Jenkinsでdebパッケージをビルドしてみることを目指します。

Jenkinサーバーのセットアップ

debパッケージをビルドするため、前回のエントリで使っていたWindows+IntelliJ IDEA環境から離れて、今日はUbuntu ServerにJenkinsをインストールしてみましょう。今回は12.04 LTSを使用しました。

Javaの開発環境のインストール

まずはJavaの開発環境のセットアップから。Oracle JDKをインストールしていきます。標準ではOracle JDKは入らないので、ppaを使用して、以下のようにインストールします。

sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java7-installer
sudo bash -c "echo \"JAVA_HOME=/usr/lib/jvm/java-7-oracle/\" >> /etc/profile"
sudo bash -c "echo \"export JAVA_HOME" >> /etc/profile"
sudo bash -c "echo \"JAVA_HOME=/usr/lib/jvm/java-7-oracle/\" >> /etc/default/tomcat6" 

add-apt-repositoryが見つからないと起こられる場合は、以下のコマンドでインストールできます。あるいは自分でレポジトリを追加してもよいでしょう。

sudo apt-get install python-software-properties

つづいてMavenのインストール

sudo apt-get install maven

状況確認。ちゃんとインストールされてますね。

mvn -v
Apache Maven 3.0.4
Maven home: /usr/share/maven
Java version: 1.7.0_45, vendor: Oracle Corporation
Java home: /usr/lib/jvm/java-7-oracle/jre
Default locale: en_US, platform encoding: ANSI_X3.4-1968
OS name: "linux", version: "3.8.0-34-generic", arch: "amd64", family: "unix"

パッケージビルド用のツールのインストール

パッケージビルド時に必要となるツールを、以下のコマンドでインストールしましょう。

sudo apt-get install debhelper tomcat6 genisoimage python-mysqldb

Jenkinsのインストール

そしてJenkinsを以下のコマンドでインストールしましょう。今回はパッケージからインストールを行います。

sudo apt-get install jenkins-tomcat

では、JenkinsのWeb UIにアクセスしてみましょう。デフォルトで、ポート8080番で立ち上がっています。

image

本当はここでちゃんとユーザーや認証の設定などをするべきなのですが、今回はCloudStackをビルドすることに絞って説明を行います。

まずは、「Jenkinsの管理」->「システムの設定」からMavenを追加します。3.0.4をパッケージからインストールしてあるので、そのパスをMAVEN_HOME欄に設定します。

image

続いて、プラグインの追加画面から、Git Pluginの追加を行います。プラグインの追加が終わったら、有効化するために、Jenkinsを再起動する必要があります。

image

debパッケージのビルド

image

さて、いよいよパッケージのビルドをするために、Jenkinsのジョブのセットアップを行いましょう。Jenkinsのトップから、「新規ジョブ作成」を選択し、適宜名前をつけてジョブを作成してください。

image

ジョブの設定画面では、ソースコード管理システムはGitを選択し、Repository URLには使用しているレポジトリのURLを入力してください。
ビルドの項は、「ビルド手順の追加」から「シェルの実行」を選択し、以下の内容を貼り付けてください。

cd $WORKSPACE
VERSION=`(mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version) | grep '^[0-9]\.'`
rm -rf dists
mkdir -p $WORKSPACE/dists/debian
tar --transform s,^\./,cloudstack-${VERSION}/, -c -z -f dists/debian/cloudstack-${VERSION}.tgz --exclude .git --exclude dists .
cd $WORKSPACE/dists/debian
tar -xzf cloudstack-${VERSION}.tgz
cd $WORKSPACE/dists/debian/cloudstack-${VERSION}
dpkg-buildpackage -uc -us
cd $WORKSPACE/dists/debian
mkdir -p $WORKSPACE/dists/debian/main/binary-amd64
mv *.deb *.changes *.dsc main/binary-amd64
cd $WORKSPACE
dpkg-scanpackages dists/debian/main/binary-amd64 /dev/null | tee $WORKSPACE/dists/debian/main/binary-amd64/Packages | gzip -9 > $WORKSPACE/dists/debian/main/binary-amd64/Packages.gz

以上で、Jenkinsのジョブのセットアップは完了しました。これでジョブを実行すれば、以下のようにビルドに成功する筈です。

image

そして、ワークスペースのdists/debian/main/binary-amd64/ディレクトリ配下には、debパッケージとPackagesファイルが生成されている筈です。

image

このdebパッケージを使えば、ビルドされたCloudStackをDebian/Ubuntu環境にインストールすることが出来ます。また、同時に生成されたPackagesファイルは、そのディレクトリ配下にあるパッケージの情報を含んだメタデータファイルであり、aptコマンドがそのディレクトリをレポジトリとして扱うことを可能にします。Jenkinsはワークスペースの内容をデフォルトでインターネットに対して公開してくれるので、そのURLを対象のサーバーにレポジトリとして登録すれば、Jenkinsサーバーをレポジトリとして使用することが出来ます。

sudo add-apt-repocitory 'http://<domain>:8080/jenkins/job/<jobname>/ws/dists/debian main'

CloudStackの実際のインストール手順については、CloudStack Installation Guideを参照されると良いかと思います。

以上、CloudStackのdebパッケージをビルドするためのJenkinsジョブセットアップ手順でした。明日のAdvent Calenderの担当は・・・誰なんだろう。。