SlideShare a Scribd company logo
1 of 44
Download to read offline
(Advent Calendar 2012 JP)

         (openstack)
       (Open source software to build public and private clouds.)



    ( イヴの夜は OpenStack を
  (Common Lisp) でキメる! )
     ( まあ、 ( キメなくてもいいんだけどね・・・ ( いや、キメてください。 ( お願いします。 ))))




              (2012.12.24 @irix_jp)
                                                                    1
m9(^Д^) プギャーwww

●   イヴの夜にこんな資料作ってるヤツwww




                          orz

                                2
気を取り直して・・・

 ●   OpenStack は全ての命令を API サーバが「 ReST
     形式」で受付けます。
                      Client
                    Command                    DB
Admin
  or
Users                                                OpenStack
                           Client
         Horizon                                     Component
                           Library
                          (python)    API
                                     Server   AMQP

        OpenStack
        Component

          Other                                       External
         Program                                      Software


                                                                 3
ということは・・・

●   HTTP のリクエストが投げられれば、何にからでも
    操作可能!
    ●   そう、 Common Lisp からでも!
        –   おまけで Ruby とか Perl とか Curl とか Wget でも。




                                                    4
Common Lisp のはじめ方

●   まずは好みの処理系を選ぶ
    ●   Common Lisp は厳密には「言語」では無く、「仕様」
    ●   この仕様に準拠して実装されたプログラムを
        「 Common Lisp 処理系」と呼びます。

    ●   代表的な処理系
        –   Clozure CL ・・・おすすめ!( Win/Linux/Mac で動く)
        –   SBCL ・・・処理が早い。 Linux なら安心。 Win だと苦しい。
        –   Allegro CL ・・・商用。評価版あり。リッチな IDE 付き。
        –   Lisp Works ・・・商用。使った事無いです。


            より詳しい情報はこちら http://ja.wikipedia.org/wiki/Common_Lisp   5
早速動かす

●   Clozure CL を使います( Linux 想定)
    ●   ここから DL
        –   http://ccl.clozure.com/download.html
             ●   自分の環境に合わせたものを選択


    ●   解凍して適当に配置。
        –   /opt/ccl とか

    ●   とりあえず実行してみる
        –   /opt/ccl/lx86cl   ・・・ 32bit 環境はこちら
        –   /opt/ccl/lx86cl64  ・・・64 bit 環境はこちら

                                                   6
早速動かす

●   これで OK
    $ /opt/ccl/lx86cl64
    Welcome to Clozure Common Lisp Version 1.8-r15286M   (LinuxX8664)!
    ? ← これがプロンプト


●   とりあえず Hello World
    ? "Hello World"
    "Hello World"



●   超簡単!!!


                                                                         7
もう少し Lisp っぽく

●   format 関数を使った例
    ? (format t "~a" "Hello World")
    Hello World
    NIL

●   エラーしたら
    ?   (format r "~a" "Hello World")
    >   Error: Unbound variable: R
    >   While executing: CCL::CHEAP-EVAL-IN-ENVIRONMENT, in process listener(1).
    >   Type :GO to continue, :POP to abort, :R for a list of available restarts.
    >   If continued: Retry getting the value of R.
    >   Type :? for other options.
    1   > q
         Debbuger が起動するので冷静に「 q 」
●   終了
    ? (quit)

                                                                                8
プロンプト入力が低機能杉www

●   補完も履歴参照もできねーよwww
    ●   案ずるな、バッチ実行できる。
        –   適当なファイルを準備
            ●   test.lisp
                (format t "~a" "Hello World")

        –   コマンドラインから
                $ /opt/ccl/lx86cl64 -Q -b < test.lisp
                Hello World
                NIL
            ●   -Q だんまりモード。プロンプトや起動メッセージを表示しない。
            ●   -b バッチモード。標準入力から受け取った式を評価して終了。


                                                        9
エディタ

●   Emacs でも、 VIM でも xxxx.lisp とファイル名をつ
    ければ、 Lisp Mode になるので好きな方で。

●   Emacs だと Slime という Lisp 開発をインタラク
    ティブに行える便利ツールがあるので、慣れてきた
    らコレを使うのがおすすめ。
    ●   Superior Lisp Interaction Mode for Emacs
        –   http://common-lisp.net/project/slime/


    ●   Emacs ユーザなら Lispbox を使うのもあり。いろいろ
        揃った All in One 環境
        –   http://common-lisp.net/project/lispbox/

                                                      10
パッケージ管理

●   Python に PIP 、 Ruby に GEM 、 Perl に CPAN が
    あるように・・・

●   Common Lisp にも Quiacklisp というパッケージ
    管理の仕組みがあります。
    ●   サイトはこちら
        –   http://www.quicklisp.org/




                                            11
パッケージ管理

●   導入は簡単
    $ wget http://beta.quicklisp.org/quicklisp.lisp
    $ /opt/ccl/lx86cl64
    Welcome to Clozure Common Lisp Version 1.8-r15286M (LinuxX8664)!
    ?
    ? (load "quicklisp.lisp")
    .
    ..
    ...
    ? (quicklisp-quickstart:install)
    .        プロキシを経由する場合 (quicklisp-quickstart:install :proxy "http://192.168.128.254:8080")
    ..
    ...
    ? (ql:add-to-init-file)
    .
    ..
    ...
    ? (quit)



                                                                                               12
パッケージの導入

●   HTTP リクエストを投げるパッケージを導入
    ? (ql:quickload :drakma)
    ●   初回のみ、パッケージの DL が実行される。

●   ついでに json パッケージも
    ? (ql:quickload :cl-json)




●   パッケージの検索
    ? (ql:system-apropos "json")



                                   13
drakma がエラーするヤツ

●   OS の環境によってはエラーが起きる
    [package cl+ssl]
    > Error: Unable to load any of the alternatives:
    >           ("libssl.so.1.0.0" "libssl.so.0.9.8" "libssl.so" "libssl.so.4")
    > While executing: CFFI::FL-ERROR, in process listener(1).
    > Type :POP to abort, :R for a list of available restarts.
    > Type :? for other options.


●   libssl のファイル名の問題だけなので、適当にリン
    ク貼ればおk
    $ find / |grep libssl.so
    $ sudo ln -s /usr/lib64/libssl.so.10 /usr/lib64/libssl.so

●   再実行
    ? (ql:quickload :drakma)

                                                                             14
ここから本編

●   ようやくだよ!




              15
keystone へリクエストを投げる

●   とりあえず何の工夫も無く openstack.lisp
    (ql:quickload :drakma)
    (drakma:http-request "http://cc:5000/v2.0/tokens")



●   実行すると当然エラー( 404 Not Found )
    ●   指定されたリクエスト方式で、ヘッダ・データをちゃんと
        含める必要がある。




                                                         16
keystone へリクエストを投げる

●   ちゃんと投げてみる
    ●    最初の方はおまじない
    ; ライブラリのロード
    (ql:quickload :drakma)    ; HTTP クライアント
    (ql:quickload :cl-json)   ; JSON パーサ

    ; デフォルトエンコードを指定
    (setf drakma:*drakma-default-external-format* :utf-8)

    ; application/json をテキストとして扱う
    (pushnew (cons "application" "json") drakma:*text-content-types* :test #'equal)

    (drakma:http-request "http://192.168.100.52:5000/v2.0/tokens"
              :content-type "application/json"
              :method       :post
              :content      "{"auth": {"tenantName": "demo", "passwordCredentials": {"username": "demo",
    "password": "openstack"}}}")




                                                                                                                  17
keystone へリクエストを投げる

●   keystone に認証をかけるには
    ●   Content-tyep: application/json で、
    ●   データ部に json 形式で以下の内容を含めて、
        –   テナント名
        –   ユーザ名
        –   パスワード
    ●   http://keystone-address:5000/v2.0/tokens
        –   へ POST する。




                                                   18
keystone へリクエストを投げる

●   もう少しスマートに、
    ●    まず json を生成する関数を作ってみる
    ; ライブラリのロード
    (ql:quickload :drakma)    ; HTTP クライアント
    (ql:quickload :cl-json)   ; JSON パーサ

    ; デフォルトエンコードを指定
    (setf drakma:*drakma-default-external-format* :utf-8)

    ; application/json をテキストとして扱う
    (pushnew (cons "application" "json") drakma:*text-content-types* :test #'equal)

    (defun auth-create-json (tenantName username password)
            "keystone へ送る JSON を生成する "
            (json:encode-json-to-string
                    `(("auth" ("tenantName" . ,tenantName) ("passwordCredentials" ("username" . ,username)
    ("password" . ,password))))))

    (auth-create-json "demo" "demo" "openstack")




                                                                                                             19
keystone へリクエストを投げる

●   前のページの続き
    ●    リクエストを投げる関数も作る
    (defun auth-post-json (url tenantName username password)
            "JSON を keystone へ送付し、認証情報を得る "
            (drakma:http-request url
                    :content-type "application/json"
                    :method       :post
                    :content      (auth-create-json tenantName username password)))

    (auth-post-json "http://192.168.100.52:5000/v2.0/tokens" "demo" "demo" "openstack")




    ●    これを実行すると、それっぽい JSON が返ってくる(と思
         う



                                                                                          20
ここまでのコード

●   これ以降のコードはこの下に追記していく
    ●    openstack.lisp
    ; ライブラリのロード
    (ql:quickload :drakma)    ; HTTP クライアント
    (ql:quickload :cl-json)   ; JSON パーサ

    ; デフォルトエンコードを指定
    (setf drakma:*drakma-default-external-format* :utf-8)

    ; application/json をテキストとして扱う
    (pushnew (cons "application" "json") drakma:*text-content-types* :test #'equal)

    (defun auth-create-json (tenantName username password)
            "keystone へ送る JSON を生成する "
            (json:encode-json-to-string
                    `(("auth" ("tenantName" . ,tenantName) ("passwordCredentials" ("username" . ,username)
    ("password" . ,password))))))

    (defun auth-post-json (url tenantName username password)
            "JSON を keystone へ送付し、認証情報を得る "
            (drakma:http-request url
                    :content-type "application/json"
                    :method       :post
                    :content      (auth-create-json tenantName username password)))



                                                                                                             21
認証結果

    ●    さっきの関数を実行してみると・・・
(auth-post-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "password")


"{"access": {"token": {"expires": "2012-12-21T15:24:01Z", "id": "27ae438762604ffe824fdc5a12b08b4e", "tenant":
{"enabled":
true, "description": "", "name": "demo", "id": "ad6bc57213b04c7f867aadbab97519e3"}}, "serviceCatalog":
[{"endpoints": [{"adminURL": "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3", "region": "RegionOne",
"internalURL": "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3", "id": "aecda37bbc384097bb38e0ac2de8264a
", "publicURL": "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3"}], "endpoints_links":
[], "type": "compute", "name": "nova"}, {"endpoints":
[{"adminURL": "http://157.7.133.23:9696/", "region": "RegionOne", "internalURL": "http://157.7.133.23:9696/", "i
d": "1753832bfd754f7f8d61e13dda948be6", "publicURL": "http://157.7.133.23:9696/"}], "endpoints_links": [], "type":
"network", "name": "quantum"}, {"endpoints": [{"adminURL": "http://157.7.133.23:9292", "region": "RegionOne",
"internalURL": "http://157.7.133.23:9292", "id": "940eef79e0ad4716b5035cfcf77a8916", "publicURL": "http://157.7.13
3.23:9292"}], "endpoints_links": [], "type": "image", "name": "glance"}, {"endpoints":
[{"adminURL": "http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3", "region": "RegionOne", "internalURL":
"http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3", "id": "557a9527f0a94d908613260107738e3a", "publicURL"
: "http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3"}], "endpoints_links":
[], "type": "volume", "name": "cinder"}, {"endpoints": [{"adminURL": "http://157.7.133.23:8773/services/Admin",
"region": "RegionOne", "internalURL": "http://157.7.133.23:8773/services/Cloud", "id": "dadd326ef5904cecaf4a058a73
4003f2", "publicURL": "http://157.7.133.23:8773/services/Cloud"}], "endpoints_links": [], "type": "ec2", "name":
"ec2"}, {"endpoints":
[{"adminURL": "http://157.7.133.23:35357/v2.0", "region": "RegionOne", "internalURL": "http://157.7.133.23:5000/v2
.0", "id": "1d763970d0b24d49be57eb7368044fd6", "publicURL": "http://157.7.133.23:5000/v2.0"}], "endpoints_links":
[], "type": "identity", "name": "keystone"}], "user": {"username": "demo", "roles_links":
[], "id": "5f003e1815ea4f76991a8b824402a918", "roles": [{"name": "Member"}], "name": "demo"}, "metadata":
{"is_admin": 0, "roles": ["f55588c94cba4cce9f1cf2e4a15f490b"]}}}"



                                                                                            できてるっぽい                    22
JSON をパースする

    ●    cl-json のデコーダーを使って、リスト形式へ変換
(json:decode-json-from-string (auth-post-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$"))


((:ACCESS (:TOKEN (:EXPIRES . "2012-12-21T15:45:52Z") (:ID . "729038529271455c849b8ce5249d1af3") (:TENANT (:ENABLED . T)
(:DESCRIPTION . "") (:NAME . "demo") (:ID . "ad6bc57213b04c7f867aadbab97519e3"))) (:SERVICE-CATALOG ((:ENDPOINTS ((:ADMIN-
+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:REGION . "RegionOne") (:INTERNAL-+URL+ .
"http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:ID . "aecda37bbc384097bb38e0ac2de8264a") (:PUBLIC-+URL+ .
"http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3"))) (:ENDPOINTS--LINKS) (:TYPE . "compute") (:NAME . "nova"))
((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:9696/") (:REGION . "RegionOne") (:INTERNAL-+URL+ .
"http://157.7.133.23:9696/") (:ID . "1753832bfd754f7f8d61e13dda948be6") (:PUBLIC-+URL+ . "http://157.7.133.23:9696/")))
(:ENDPOINTS--LINKS) (:TYPE . "network") (:NAME . "quantum")) ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:9292")
(:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:9292") (:ID . "940eef79e0ad4716b5035cfcf77a8916") (:PUBLIC-
+URL+ . "http://157.7.133.23:9292"))) (:ENDPOINTS--LINKS) (:TYPE . "image") (:NAME . "glance")) ((:ENDPOINTS ((:ADMIN-+URL+ .
"http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3") (:REGION . "RegionOne") (:INTERNAL-+URL+ .
"http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3") (:ID . "557a9527f0a94d908613260107738e3a") (:PUBLIC-+URL+ .
"http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3"))) (:ENDPOINTS--LINKS) (:TYPE . "volume") (:NAME . "cinder"))
((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:8773/services/Admin") (:REGION . "RegionOne") (:INTERNAL-+URL+ .
"http://157.7.133.23:8773/services/Cloud") (:ID . "dadd326ef5904cecaf4a058a734003f2") (:PUBLIC-+URL+ .
"http://157.7.133.23:8773/services/Cloud"))) (:ENDPOINTS--LINKS) (:TYPE . "ec2") (:NAME . "ec2")) ((:ENDPOINTS ((:ADMIN-+URL+
. "http://157.7.133.23:35357/v2.0") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:5000/v2.0") (:ID .
"1d763970d0b24d49be57eb7368044fd6") (:PUBLIC-+URL+ . "http://157.7.133.23:5000/v2.0"))) (:ENDPOINTS--LINKS) (:TYPE .
"identity") (:NAME . "keystone"))) (:USER (:USERNAME . "demo") (:ROLES--LINKS) (:ID . "5f003e1815ea4f76991a8b824402a918")
(:ROLES ((:NAME . "Member"))) (:NAME . "demo")) (:METADATA (:IS--ADMIN . 0) (:ROLES "f55588c94cba4cce9f1cf2e4a15f490b"))))

    このリストをよく見ると、以下のような構造になっている。

    ((:ACCESS (:TOKEN ....) (:SERVICE-CATALOG...) (:USER ...) (:METADATA..))

                                                                                                                       23
リスト操作

     ●    First 関数でリストから最初の要素を取り出す
(first
  (json:decode-json-from-string (auth-post-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$")))


(:ACCESS (:TOKEN (:EXPIRES . "2012-12-21T16:05:39Z") (:ID . "e79e348b0115468891a8c7bf752f4d64") (:TENANT (:ENABLED . T) (:DESCRIPTION . "") (:NAME .
"demo") (:ID . "ad6bc57213b04c7f867aadbab97519e3"))) (:SERVICE-CATALOG ((:ENDPOINTS ((:ADMIN-+URL+ .
"http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:REGION . "RegionOne") (:INTERNAL-+URL+ .
"http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:ID . "aecda37bbc384097bb38e0ac2de8264a") (:PUBLIC-+URL+ .
"http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3"))) (:ENDPOINTS--LINKS) (:TYPE . "compute") (:NAME . "nova")) ((:ENDPOINTS ((:ADMIN-
+URL+ . "http://157.7.133.23:9696/") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:9696/") (:ID .
"1753832bfd754f7f8d61e13dda948be6") (:PUBLIC-+URL+ . "http://157.7.133.23:9696/"))) (:ENDPOINTS--LINKS) (:TYPE . "network") (:NAME . "quantum"))
((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:9292") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:9292") (:ID .
"940eef79e0ad4716b5035cfcf77a8916") (:PUBLIC-+URL+ . "http://157.7.133.23:9292"))) (:ENDPOINTS--LINKS) (:TYPE . "image") (:NAME . "glance"))
((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3") (:REGION . "RegionOne") (:INTERNAL-+URL+ .
"http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3") (:ID . "557a9527f0a94d908613260107738e3a") (:PUBLIC-+URL+ .
"http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3"))) (:ENDPOINTS--LINKS) (:TYPE . "volume") (:NAME . "cinder")) ((:ENDPOINTS ((:ADMIN-
+URL+ . "http://157.7.133.23:8773/services/Admin") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:8773/services/Cloud") (:ID .
"dadd326ef5904cecaf4a058a734003f2") (:PUBLIC-+URL+ . "http://157.7.133.23:8773/services/Cloud"))) (:ENDPOINTS--LINKS) (:TYPE . "ec2") (:NAME .
"ec2")) ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:35357/v2.0") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:5000/v2.0")
(:ID . "1d763970d0b24d49be57eb7368044fd6") (:PUBLIC-+URL+ . "http://157.7.133.23:5000/v2.0"))) (:ENDPOINTS--LINKS) (:TYPE . "identity") (:NAME .
"keystone"))) (:USER (:USERNAME . "demo") (:ROLES--LINKS) (:ID . "5f003e1815ea4f76991a8b824402a918") (:ROLES ((:NAME . "Member"))) (:NAME . "demo"))
(:METADATA (:IS--ADMIN . 0) (:ROLES "f55588c94cba4cce9f1cf2e4a15f490b")))



     (:ACCESS (:TOKEN ....) (:SERVICE-CATALOG...) (:USER ...) (:METADATA..)

     一つカッコが取れる。




                                                                                                                                              24
リスト操作

     ●      さらに一つづつ取り出してみると
(first (first
          (json:decode-json-from-string (auth-post-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$"))))

→ :ACCESS



(second (first
          (json:decode-json-from-string (auth-post-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$"))))

→ (:TOKEN (:EXPIRES . "2012-12-21T16:08:44Z") (:ID . "e23f631ca4c74d64970f3bc21c21147c") (:TENANT (:ENABLED . T) (:DESCRIPTION . "") (:NAME .
"demo") (:ID . "ad6bc57213b04c7f867aadbab97519e3")))



(fourth (first
          (json:decode-json-from-string (auth-post-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$"))))

→ (:USER (:USERNAME . "demo") (:ROLES--LINKS) (:ID . "5f003e1815ea4f76991a8b824402a918") (:ROLES ((:NAME . "Member"))) (:NAME . "demo"))




     (:ACCESS (:TOKEN ....) (:SERVICE-CATALOG...) (:USER ...) (:METADATA..)

     と、上から一つずつ要素が取り出せる。




                                                                                                                                                25
リスト操作

    ●    ここから TOKEN を取り出してみる。
(cdr
 (third
  (second
   (first
     (json:decode-json-from-string (auth-post-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$"))))))

→ "ce26db6126e342a8b604019463f34bb7"




    ●    芸はないけど、こんな感じで TOKEN が取り出せ
         る。
          ●   しかしこの方法は場所決め打ちで取り出しているので、
              汎用性がなさすぎる。
                –   TOKEN の場所が
                       ●   :TOKEN → :ID にあることを利用すると・・・

                                                                                                                       26
ループと判定

     ●    ループで回して if で判定すると TOKEN が取得で
          きる。
(block exit
  (dolist
      (x (first
          (json:decode-json-from-string (auth-post-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$"))))
    (if (listp x)
        (if (eql :TOKEN (first x))
            (dolist (y x)
              (if (listp y)
                  (if (eql :ID (first y))
                      (return-from exit (cdr y)))))))))

→ "e2f35b1dca014a38a4eb9afb55eb752d"




                                                                                                                                 27
TOKEN を取得する関数

     ●    JSON を受け取り、 TOKEN を返す関数
(defun auth-return-token-from-json (json)
  "keystone が返す JSON を受け取り、 TOKEN を抽出して返す関数 "
  (block exit
    (dolist
        (x (first
            (json:decode-json-from-string json)))
      (if (listp x)
          (if (eql :TOKEN (first x))
              (dolist (y x)
                (if (listp y)
                    (if (eql :ID (first y))
                        (return-from exit (cdr y))))))))))




     ●    実行すると・・・
(auth-return-token-from-json (auth-post-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$"))

→ "c71bb1f6e88b4032a4413c94a7f2bd46"




                                                                                                                    28
もう少し汎用的に

     ●    keystone から JSON を受け取って、リスト変換して
          返す関数
     ●    リスト変換された JSON とキーを受け取ってキーが
          存在するリストを返す関数
(defun auth-return-list-from-json (url tenantName username password)
  "keystone から認証 JSON を受け取り、リストへ変換して返す "
   (first
    (json:decode-json-from-string
     (auth-post-json url tenantName username password))))

(defun auth-return-list-from-json (json key)
  "json とキーを一つ受け取り、キーがマッチしたリストを返す "
  (block exit
    (dolist
        (x (first
            (json:decode-json-from-string json)))
      (if (listp x)
          (if (eql key (first x))
              (return-from exit x))))))


(auth-return-key-from-json (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") :TOKEN)

(:TOKEN (:EXPIRES . "2012-12-24T14:52:59Z") (:ID . "f116354e97494b52a1f06ad04e45580c") (:TENANT (:ENABLED . T) (:DESCRIPTION . "") (:NAME .
"demo") (:ID . "ad6bc57213b04c7f867aadbab97519e3")))


                                                                                                                                        29
任意のデータを取り出す
(defun auth-return-specified-key-from-json-list (json-list &rest keys)
  " 指定されたキーを取り出す "
  (let ((x json-list))
    (dolist (key keys)
      (setf x (auth-return-key-from-json x key)))
    x))

(auth-return-specified-key-from-json-list
   (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") :TOKEN :ID)
→ (:ID . "68013432d7274ad78b3630461cb385ef")

(auth-return-specified-key-from-json-list
    (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") :SERVICE-CATALOG)
→ (:SERVICE-CATALOG ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:REGION . "RegionOne")
(:INTERNAL-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:ID . "aecda37bbc384097bb38e0ac2de8264a") (:PUBLIC-+URL+ .
"http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3"))) (:ENDPOINTS--LINKS) (:TYPE . "compute") (:NAME . "nova")) ((:ENDPOINTS
((:ADMIN-+URL+ . "http://157.7.133.23:9696/") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:9696/") (:ID .
"1753832bfd754f7f8d61e13dda948be6") (:PUBLIC-+URL+ . "http://157.7.133.23:9696/"))) (:ENDPOINTS--LINKS) (:TYPE . "network") (:NAME .
"quantum")) ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:9292") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:9292")
(:ID . "940eef79e0ad4716b5035cfcf77a8916") (:PUBLIC-+URL+ . "http://157.7.133.23:9292"))) (:ENDPOINTS--LINKS) (:TYPE . "image") (:NAME .
"glance")) ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3") (:REGION . "RegionOne") (:INTERNAL-
+URL+ . "http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3") (:ID . "557a9527f0a94d908613260107738e3a") (:PUBLIC-+URL+ .
"http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3"))) (:ENDPOINTS--LINKS) (:TYPE . "volume") (:NAME . "cinder")) ((:ENDPOINTS
((:ADMIN-+URL+ . "http://157.7.133.23:8773/services/Admin") (:REGION . "RegionOne") (:INTERNAL-+URL+ .
"http://157.7.133.23:8773/services/Cloud") (:ID . "dadd326ef5904cecaf4a058a734003f2") (:PUBLIC-+URL+ .
"http://157.7.133.23:8773/services/Cloud"))) (:ENDPOINTS--LINKS) (:TYPE . "ec2") (:NAME . "ec2")) ((:ENDPOINTS ((:ADMIN-+URL+ .
"http://157.7.133.23:35357/v2.0") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:5000/v2.0") (:ID .
"1d763970d0b24d49be57eb7368044fd6") (:PUBLIC-+URL+ . "http://157.7.133.23:5000/v2.0"))) (:ENDPOINTS--LINKS) (:TYPE . "identity") (:NAME .
"keystone")))

(auth-return-specified-key-from-json-list
    (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") :METADATA :ROLES)
→ (:ROLES "f55588c94cba4cce9f1cf2e4a15f490b")

(auth-return-specified-key-from-json-list
    (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") :USER :USERNAME)
→ (:USERNAME . "demo")



                                                                                                                                        30
エンドポイントの抽出

     ●    auth-return-specified-key-from-json-list 関数
          で大体のデータは取り出せるが・・・
            ●   ENDPOINT はデータ形式がめんどくさい
(:SERVICE-CATALOG
   ((:ENDPOINTS
      ((:ADMIN-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3")
       (:REGION . "RegionOne")
       (:INTERNAL-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3")
       (:ID . "aecda37bbc384097bb38e0ac2de8264a")
       (:PUBLIC-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3")))
    (:ENDPOINTS—LINKS) (:TYPE . "compute") (:NAME . "nova"))

   ((:ENDPOINTS
      ((:ADMIN-+URL+ . "http://157.7.133.23:9696/")
       (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:9696/")
       (:ID . "1753832bfd754f7f8d61e13dda948be6")
       (:PUBLIC-+URL+ . "http://157.7.133.23:9696/")))
    (:ENDPOINTS--LINKS) (:TYPE . "network") (:NAME . "quantum"))

   ((:ENDPOINTS
      ((:ADMIN-+URL+ . "http://157.7.133.23:9292")
       (:REGION . "RegionOne")
       (:INTERNAL-+URL+ . "http://157.7.133.23:9292")
       (:ID . "940eef79e0ad4716b5035cfcf77a8916")
       (:PUBLIC-+URL+ . "http://157.7.133.23:9292")))
    (:ENDPOINTS--LINKS) (:TYPE . "image") (:NAME . "glance"))
        .......



                                                                                            31
エンドポイントの抽出

     ●    まずエンドポイントの要素1つを調べて、それが欲し
          いデータならば t(true) を返す関数を作る
(defun auth-check-endpoint-name (endpoint-list servicename)
  "1 つのエンドポイントを受け取り、それが servicename にマッチするエンドポイントならば t"
  (if (consp endpoint-list)
      (dolist (x endpoint-list)
        (if (consp x)
            (if (eql (first x) :NAME)
                (progn
                  (if (string-equal (cdr x) servicename)
                       (return-from auth-check-endpoint-name t))))))
      nil))

(second
  (auth-return-specified-key-from-json-list
    (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") :SERVICE-CATALOG))

→ ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:REGION . "RegionOne") (:INTERNAL-+URL+ .
"http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:ID . "aecda37bbc384097bb38e0ac2de8264a") (:PUBLIC-+URL+ .
"http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3"))) (:ENDPOINTS--LINKS) (:TYPE . "compute") (:NAME . "nova"))

(auth-check-endpoint-name
   (second (auth-return-specified-key-from-json-list
              (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") :SERVICE-CATALOG)) "nova")
→ T

(auth-check-endpoint-name
   (second (auth-return-specified-key-from-json-list
              (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") :SERVICE-CATALOG)) "quantum")
→ NIL



                                                                                                                                           32
エンドポイントの抽出

     ●   マップ関数を使ったリスト操作
           ●    マップ関数を使うとリストの要素に対して、一括した操作
                が行える。
           ●    以下は指定した文字列にマッチするサービス名を含む
                要素のみを残して、残りを破棄する例
CL-USER> (remove-if-not #'(lambda (x) (auth-check-endpoint-name x "nova"))
                    (auth-return-specified-key-from-json-list
                     (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") :SERVICE-CATALOG))
→ (((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:REGION . "RegionOne") (:INTERNAL-+URL+ .
"http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:ID . "aecda37bbc384097bb38e0ac2de8264a") (:PUBLIC-+URL+ .
"http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3"))) (:ENDPOINTS--LINKS) (:TYPE . "compute") (:NAME . "nova")))

CL-USER> (remove-if-not #'(lambda (x) (auth-check-endpoint-name x "quantum"))
                    (auth-return-specified-key-from-json-list
                     (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") :SERVICE-CATALOG))
→ (((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:9696/") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:9696/") (:ID .
"1753832bfd754f7f8d61e13dda948be6") (:PUBLIC-+URL+ . "http://157.7.133.23:9696/"))) (:ENDPOINTS--LINKS) (:TYPE . "network") (:NAME .
"quantum")))

CL-USER> (remove-if-not #'(lambda (x) (auth-check-endpoint-name x "notmatch"))
                    (auth-return-specified-key-from-json-list
                     (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") :SERVICE-CATALOG))
→ NIL



                                                                                                                                          33
エンドポイントの抽出

     ●   関数化しておく
(defun auth-return-specified-endpoint (json-list servicename)
  " サービスカタログから指定のエンドポイントのみを抽出する "
  (remove-if-not #'(lambda (x) (auth-check-endpoint-name x servicename))
                 (auth-return-specified-key-from-json-list json-list :SERVICE-CATALOG)))



CL-USER> (auth-return-specified-endpoint
             (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") "nova")
→ (((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:REGION . "RegionOne") (:INTERNAL-+URL+ .
"http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:ID . "aecda37bbc384097bb38e0ac2de8264a") (:PUBLIC-+URL+ .
"http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3"))) (:ENDPOINTS--LINKS) (:TYPE . "compute") (:NAME . "nova")))

CL-USER> (auth-return-specified-endpoint
             (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") "quantum")
→ (((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:9696/") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:9696/") (:ID .
"1753832bfd754f7f8d61e13dda948be6") (:PUBLIC-+URL+ . "http://157.7.133.23:9696/"))) (:ENDPOINTS--LINKS) (:TYPE . "network") (:NAME .
"quantum")))

CL-USER> (auth-return-specified-endpoint
             (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") "nomatch")
→ NIL




                                                                                                                                      34
コラム1:マップ関数

●   「マップ」というのは、 Hadoop の MapReduce の
    Map と似た処理。
    ●   (1 2 3 4 5) みたいなリストの要素全てに計算を適用さ
        せる関数の事をマップ関数と読んでいる。

    ●   全ての要素に x 2を適用。
        –   (mapcar #'(lambda (x) (* x 2)) '(1 2 3 4 5))
            → (1 4 6 8 10)




                                                           35
コラム2:ベクター

●   同じ型の要素を持ったリスト(配列)をベクターと呼
    ぶ。
    ●   (1 2 3 4 5) や ("a" "b" "c" "d" "e")

●   このベクターに対して map 関数のような処理を実
    行する時に、 CPU が各要素に対する演算を並列に
    行えるように作られた CPU をベクタープロセッサと
    いう
    ●   ベクターデータに対する並列計算が得意な CPU
    ●   対して、スカラープロセッサは for で要素を一つずつ取
        り出して計算されるイメージ。
        10 年以上前に聞いた話で、記憶も曖昧なので間違ってるかも         36
後少し

     ●   ここまでくると、コレまでの関数の組合せで、ほぼ任
         意のデータが取得できるようになる。
           ●    いったんコレまでのコードを整理
; ライブラリのロード
(ql:quickload :drakma)    ; HTTP クライアント
(ql:quickload :cl-json)   ; JSON パーサ

; デフォルトエンコードを指定
(setf drakma:*drakma-default-external-format* :utf-8)

; application/json をテキストとして扱う
(pushnew (cons "application" "json") drakma:*text-content-types* :test #'equal)

(defun auth-create-json (tenantName username password)
  "keystone へ送る JSON を生成する "
  (json:encode-json-to-string
   `(("auth" ("tenantName" . ,tenantName) ("passwordCredentials" ("username" . ,username) ("password" . ,password))))))

(defun auth-post-json (url tenantName username password)
  "JSON を keystone へ送付し、認証情報を得る "
  (drakma:http-request url
                        :content-type "application/json"
                        :method       :post
                        :content      (auth-create-json tenantName username password)))




                                                                                                                          37
後少し

     ●   続き
(defun auth-return-list-from-json (url tenantName username password)
  "keystone から認証 JSON を受け取り、リストへ変換して返す "
   (first
    (json:decode-json-from-string
     (auth-post-json url tenantName username password))))

(defun auth-return-key-from-json (json-list key)
  " リスト変換された json とキーを一つ受け取り、キーがマッチしたリストを返す "
  (block exit
    (dolist
        (x json-list)
      (if (listp x)
          (if (eql key (first x))
              (return-from exit x))))))

(defun auth-return-specified-key-from-json-list (json-list &rest keys)
  " 指定されたキーを取り出す "
  (let ((x json-list))
    (dolist (key keys)
      (setf x (auth-return-key-from-json x key)))
    x))




                                                                         38
後少し

     ●   続き
(defun auth-check-endpoint-name (endpoint-list servicename)
  "1 つのエンドポイントを受け取り、それが servicename にマッチするエンドポイントならば t"
  (if (consp endpoint-list)
      (dolist (x endpoint-list)
        (if (consp x)
            (if (eql (first x) :NAME)
                (progn
                  (if (string-equal (cdr x) servicename)
                       (return-from auth-check-endpoint-name t))))))
      nil))

(defun auth-return-specified-endpoint (json-list servicename)
  " サービスカタログから指定のエンドポイントのみを抽出する "
  (remove-if-not #'(lambda (x) (auth-check-endpoint-name x servicename))
                 (auth-return-specified-key-from-json-list json-list :SERVICE-CATALOG)))




                                                                                           39
これまでに出てきたこと

●   以下の基礎
    ●   リスト操作
    ●   関数
    ●   マップ
    ●   条件分岐
    ●   ループ




                40
さらに学習するには

●   マクロ
●   コンディション(例外処理)
●   CLOS (オブジェクト)
●   パッケージ
    などなど・・・




                    41
とりあえずまとめ

●   今回は JSON を一旦リストへ変換して、様々なリス
    ト操作を試してみました。

●   マクロやオブジェクトを使うともっと効率的にデータ
    抽出が可能です。

●   もしこれで Common Lisp に興味を持った方がい
    れば、後述の参考書籍を見て、本格的に学習してみ
    てください。

                                 42
おすすめ書籍

●   実践 Common Lisp
    ●   Practical Common Lisp
●   実用 Common Lisp
    ●   Paradigms of Artificial Intelligence Programming
●   計算機プログラムの構造と解釈
    ●   Structure and Interpretation of Computer Programs
         –   英語版がオンラインで読めます。
         –   http://mitpress.mit.edu/sicp/
●   On Lisp
●   LET OVER LAMBD
                                                            43
おすすめサイト

●   xyzzy Lisp Programming
    ●   http://www.geocities.jp/m_hiroi/xyzzy_lisp.html


●   逆引き CommonLisp
    ●   http://tips.lisp-users.org/common-lisp/


●   モダン Common Lisp
    ●   http://dev.ariel-networks.com/wp/archives/tag/common-lisp




                                                                    44

More Related Content

What's hot

C16 45分でわかるPostgreSQLの仕組み by 山田努
C16 45分でわかるPostgreSQLの仕組み by 山田努C16 45分でわかるPostgreSQLの仕組み by 山田努
C16 45分でわかるPostgreSQLの仕組み by 山田努Insight Technology, Inc.
 
Nuxt.js + microCMS + netlify
Nuxt.js + microCMS + netlifyNuxt.js + microCMS + netlify
Nuxt.js + microCMS + netlifyogawatti
 
PostgreSQLアーキテクチャ入門(PostgreSQL Conference 2012)
PostgreSQLアーキテクチャ入門(PostgreSQL Conference 2012)PostgreSQLアーキテクチャ入門(PostgreSQL Conference 2012)
PostgreSQLアーキテクチャ入門(PostgreSQL Conference 2012)Uptime Technologies LLC (JP)
 
Osc2015 hokkaido postgresql-semi-stuructured-datatype
Osc2015 hokkaido postgresql-semi-stuructured-datatypeOsc2015 hokkaido postgresql-semi-stuructured-datatype
Osc2015 hokkaido postgresql-semi-stuructured-datatypeToshi Harada
 
Hackers Champloo 2016 postgresql-9.6
Hackers Champloo 2016 postgresql-9.6Hackers Champloo 2016 postgresql-9.6
Hackers Champloo 2016 postgresql-9.6Toshi Harada
 
AvailabilityZoneとHostAggregate
AvailabilityZoneとHostAggregateAvailabilityZoneとHostAggregate
AvailabilityZoneとHostAggregateHiroki Ishikawa
 
あなたの知らないPostgreSQL監視の世界
あなたの知らないPostgreSQL監視の世界あなたの知らないPostgreSQL監視の世界
あなたの知らないPostgreSQL監視の世界Yoshinori Nakanishi
 
Azure Storage Partition Internals
Azure Storage Partition  Internals Azure Storage Partition  Internals
Azure Storage Partition Internals Takekazu Omi
 
Gluster fs and_swiftapi_20120429
Gluster fs and_swiftapi_20120429Gluster fs and_swiftapi_20120429
Gluster fs and_swiftapi_20120429Etsuji Nakai
 
PostgreSQLの新バージョン -PostgreSQL9.4- のご紹介
PostgreSQLの新バージョン -PostgreSQL9.4- のご紹介PostgreSQLの新バージョン -PostgreSQL9.4- のご紹介
PostgreSQLの新バージョン -PostgreSQL9.4- のご紹介Insight Technology, Inc.
 
20160121 データサイエンティスト協会 木曜セミナー #5
20160121 データサイエンティスト協会 木曜セミナー #520160121 データサイエンティスト協会 木曜セミナー #5
20160121 データサイエンティスト協会 木曜セミナー #5Koichiro Sasaki
 
Javaトラブルに備えよう #jjug_ccc #ccc_h2
Javaトラブルに備えよう #jjug_ccc #ccc_h2Javaトラブルに備えよう #jjug_ccc #ccc_h2
Javaトラブルに備えよう #jjug_ccc #ccc_h2Norito Agetsuma
 
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)Hironobu Suzuki
 
HandlerSocket plugin for MySQL
HandlerSocket plugin for MySQLHandlerSocket plugin for MySQL
HandlerSocket plugin for MySQLakirahiguchi
 

What's hot (20)

Hive chapter 2
Hive chapter 2Hive chapter 2
Hive chapter 2
 
C16 45分でわかるPostgreSQLの仕組み by 山田努
C16 45分でわかるPostgreSQLの仕組み by 山田努C16 45分でわかるPostgreSQLの仕組み by 山田努
C16 45分でわかるPostgreSQLの仕組み by 山田努
 
Openresty
OpenrestyOpenresty
Openresty
 
Nuxt.js + microCMS + netlify
Nuxt.js + microCMS + netlifyNuxt.js + microCMS + netlify
Nuxt.js + microCMS + netlify
 
PostgreSQLアーキテクチャ入門(PostgreSQL Conference 2012)
PostgreSQLアーキテクチャ入門(PostgreSQL Conference 2012)PostgreSQLアーキテクチャ入門(PostgreSQL Conference 2012)
PostgreSQLアーキテクチャ入門(PostgreSQL Conference 2012)
 
Osc2015 hokkaido postgresql-semi-stuructured-datatype
Osc2015 hokkaido postgresql-semi-stuructured-datatypeOsc2015 hokkaido postgresql-semi-stuructured-datatype
Osc2015 hokkaido postgresql-semi-stuructured-datatype
 
PostgreSQL Query Cache - "pqc"
PostgreSQL Query Cache - "pqc"PostgreSQL Query Cache - "pqc"
PostgreSQL Query Cache - "pqc"
 
Hackers Champloo 2016 postgresql-9.6
Hackers Champloo 2016 postgresql-9.6Hackers Champloo 2016 postgresql-9.6
Hackers Champloo 2016 postgresql-9.6
 
AvailabilityZoneとHostAggregate
AvailabilityZoneとHostAggregateAvailabilityZoneとHostAggregate
AvailabilityZoneとHostAggregate
 
あなたの知らないPostgreSQL監視の世界
あなたの知らないPostgreSQL監視の世界あなたの知らないPostgreSQL監視の世界
あなたの知らないPostgreSQL監視の世界
 
Openstack+Ceph設定ガイド
Openstack+Ceph設定ガイドOpenstack+Ceph設定ガイド
Openstack+Ceph設定ガイド
 
Azure Storage Partition Internals
Azure Storage Partition  Internals Azure Storage Partition  Internals
Azure Storage Partition Internals
 
Gluster fs and_swiftapi_20120429
Gluster fs and_swiftapi_20120429Gluster fs and_swiftapi_20120429
Gluster fs and_swiftapi_20120429
 
PostgreSQLの新バージョン -PostgreSQL9.4- のご紹介
PostgreSQLの新バージョン -PostgreSQL9.4- のご紹介PostgreSQLの新バージョン -PostgreSQL9.4- のご紹介
PostgreSQLの新バージョン -PostgreSQL9.4- のご紹介
 
20160121 データサイエンティスト協会 木曜セミナー #5
20160121 データサイエンティスト協会 木曜セミナー #520160121 データサイエンティスト協会 木曜セミナー #5
20160121 データサイエンティスト協会 木曜セミナー #5
 
PostgreSQLアーキテクチャ入門
PostgreSQLアーキテクチャ入門PostgreSQLアーキテクチャ入門
PostgreSQLアーキテクチャ入門
 
Vacuum徹底解説
Vacuum徹底解説Vacuum徹底解説
Vacuum徹底解説
 
Javaトラブルに備えよう #jjug_ccc #ccc_h2
Javaトラブルに備えよう #jjug_ccc #ccc_h2Javaトラブルに備えよう #jjug_ccc #ccc_h2
Javaトラブルに備えよう #jjug_ccc #ccc_h2
 
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)
 
HandlerSocket plugin for MySQL
HandlerSocket plugin for MySQLHandlerSocket plugin for MySQL
HandlerSocket plugin for MySQL
 

Viewers also liked

Open stack advent calendar 2012jp 12/17 Cloud on Cloud
Open stack advent calendar 2012jp 12/17 Cloud on CloudOpen stack advent calendar 2012jp 12/17 Cloud on Cloud
Open stack advent calendar 2012jp 12/17 Cloud on Cloudirix_jp
 
glance replicator
glance replicatorglance replicator
glance replicatoririx_jp
 
Eucalyptus on OpenStack
Eucalyptus on OpenStackEucalyptus on OpenStack
Eucalyptus on OpenStackirix_jp
 
OSC.Cloud 2012 分散システムを支えるメッセージングの仕組み
OSC.Cloud 2012 分散システムを支えるメッセージングの仕組みOSC.Cloud 2012 分散システムを支えるメッセージングの仕組み
OSC.Cloud 2012 分散システムを支えるメッセージングの仕組みirix_jp
 
OSC.Cloud 2012 インフラエンジニアがOpenStackを学ぶべきたった一つの理由
OSC.Cloud 2012 インフラエンジニアがOpenStackを学ぶべきたった一つの理由OSC.Cloud 2012 インフラエンジニアがOpenStackを学ぶべきたった一つの理由
OSC.Cloud 2012 インフラエンジニアがOpenStackを学ぶべきたった一つの理由irix_jp
 
Hot の書き方(Template Version 2015-04-30) 前編
Hot の書き方(Template Version 2015-04-30) 前編Hot の書き方(Template Version 2015-04-30) 前編
Hot の書き方(Template Version 2015-04-30) 前編irix_jp
 
OpenStack Advent Calendar 2012 JP 12/15
OpenStack Advent Calendar 2012 JP 12/15OpenStack Advent Calendar 2012 JP 12/15
OpenStack Advent Calendar 2012 JP 12/15irix_jp
 
OpenStack Object Storage; Usage
OpenStack Object Storage; UsageOpenStack Object Storage; Usage
OpenStack Object Storage; Usageirix_jp
 
OSC2012 Nagoya - OpenStack - Storage System; Overview
OSC2012 Nagoya - OpenStack - Storage System; OverviewOSC2012 Nagoya - OpenStack - Storage System; Overview
OSC2012 Nagoya - OpenStack - Storage System; Overviewirix_jp
 
CloudStack Ecosystem Day - OpenStack/Swift
CloudStack Ecosystem Day - OpenStack/SwiftCloudStack Ecosystem Day - OpenStack/Swift
CloudStack Ecosystem Day - OpenStack/Swiftirix_jp
 
JTF2016 The strategy and Sun Tzu
JTF2016 The strategy and Sun TzuJTF2016 The strategy and Sun Tzu
JTF2016 The strategy and Sun Tzuirix_jp
 

Viewers also liked (12)

Open stack advent calendar 2012jp 12/17 Cloud on Cloud
Open stack advent calendar 2012jp 12/17 Cloud on CloudOpen stack advent calendar 2012jp 12/17 Cloud on Cloud
Open stack advent calendar 2012jp 12/17 Cloud on Cloud
 
glance replicator
glance replicatorglance replicator
glance replicator
 
Eucalyptus on OpenStack
Eucalyptus on OpenStackEucalyptus on OpenStack
Eucalyptus on OpenStack
 
OSC.Cloud 2012 分散システムを支えるメッセージングの仕組み
OSC.Cloud 2012 分散システムを支えるメッセージングの仕組みOSC.Cloud 2012 分散システムを支えるメッセージングの仕組み
OSC.Cloud 2012 分散システムを支えるメッセージングの仕組み
 
OSC.Cloud 2012 インフラエンジニアがOpenStackを学ぶべきたった一つの理由
OSC.Cloud 2012 インフラエンジニアがOpenStackを学ぶべきたった一つの理由OSC.Cloud 2012 インフラエンジニアがOpenStackを学ぶべきたった一つの理由
OSC.Cloud 2012 インフラエンジニアがOpenStackを学ぶべきたった一つの理由
 
Hot の書き方(Template Version 2015-04-30) 前編
Hot の書き方(Template Version 2015-04-30) 前編Hot の書き方(Template Version 2015-04-30) 前編
Hot の書き方(Template Version 2015-04-30) 前編
 
OpenStack Advent Calendar 2012 JP 12/15
OpenStack Advent Calendar 2012 JP 12/15OpenStack Advent Calendar 2012 JP 12/15
OpenStack Advent Calendar 2012 JP 12/15
 
Doc Display
Doc DisplayDoc Display
Doc Display
 
OpenStack Object Storage; Usage
OpenStack Object Storage; UsageOpenStack Object Storage; Usage
OpenStack Object Storage; Usage
 
OSC2012 Nagoya - OpenStack - Storage System; Overview
OSC2012 Nagoya - OpenStack - Storage System; OverviewOSC2012 Nagoya - OpenStack - Storage System; Overview
OSC2012 Nagoya - OpenStack - Storage System; Overview
 
CloudStack Ecosystem Day - OpenStack/Swift
CloudStack Ecosystem Day - OpenStack/SwiftCloudStack Ecosystem Day - OpenStack/Swift
CloudStack Ecosystem Day - OpenStack/Swift
 
JTF2016 The strategy and Sun Tzu
JTF2016 The strategy and Sun TzuJTF2016 The strategy and Sun Tzu
JTF2016 The strategy and Sun Tzu
 

Similar to OpenStack + Common Lisp

Web技術勉強会23回目
Web技術勉強会23回目Web技術勉強会23回目
Web技術勉強会23回目龍一 田中
 
10分で作る Node.js Auto Scale 環境 with CloudFormation
10分で作る Node.js Auto Scale 環境 with CloudFormation10分で作る Node.js Auto Scale 環境 with CloudFormation
10分で作る Node.js Auto Scale 環境 with CloudFormationKazuyuki Honda
 
Handlersocket etc. 20110906
Handlersocket etc. 20110906Handlersocket etc. 20110906
Handlersocket etc. 20110906akirahiguchi
 
tcpdump & xtrabackup @ MySQL Casual Talks #1
tcpdump & xtrabackup @ MySQL Casual Talks #1tcpdump & xtrabackup @ MySQL Casual Talks #1
tcpdump & xtrabackup @ MySQL Casual Talks #1Ryosuke IWANAGA
 
Lisp Tutorial for Pythonista Day 6
Lisp Tutorial for Pythonista Day 6Lisp Tutorial for Pythonista Day 6
Lisp Tutorial for Pythonista Day 6Ransui Iso
 
Cloud Foundry: Open Platform as a Service
Cloud Foundry: Open Platform as a ServiceCloud Foundry: Open Platform as a Service
Cloud Foundry: Open Platform as a ServiceShunsuke Kurumatani
 
Cookpad 17 day Tech internship 2017 言語処理系入門 Rubyをコンパイルしよう
Cookpad 17 day Tech internship 2017 言語処理系入門 RubyをコンパイルしようCookpad 17 day Tech internship 2017 言語処理系入門 Rubyをコンパイルしよう
Cookpad 17 day Tech internship 2017 言語処理系入門 RubyをコンパイルしようKoichi Sasada
 
Web Operations and Perl kansai.pm#14
Web Operations and Perl kansai.pm#14Web Operations and Perl kansai.pm#14
Web Operations and Perl kansai.pm#14Masahiro Nagano
 
JOSUG2014 OpenStack 4th birthday party in Japan; the way of OpenStack API Dragon
JOSUG2014 OpenStack 4th birthday party in Japan; the way of OpenStack API DragonJOSUG2014 OpenStack 4th birthday party in Japan; the way of OpenStack API Dragon
JOSUG2014 OpenStack 4th birthday party in Japan; the way of OpenStack API DragonNaoto Gohko
 
配布用Beginnerならきっと役立つmaster slave環境
配布用Beginnerならきっと役立つmaster slave環境配布用Beginnerならきっと役立つmaster slave環境
配布用Beginnerならきっと役立つmaster slave環境yut148atgmaildotcom
 
恋に落ちるデプロイツール
恋に落ちるデプロイツール恋に落ちるデプロイツール
恋に落ちるデプロイツールtotty jp
 
PaaSの作り方 Sqaleの場合
PaaSの作り方 Sqaleの場合PaaSの作り方 Sqaleの場合
PaaSの作り方 Sqaleの場合hiboma
 
Lxc cf201207-presen
Lxc cf201207-presenLxc cf201207-presen
Lxc cf201207-presenKouhei Maeda
 
Javaで簡単にgpgpu aparapi
Javaで簡単にgpgpu aparapiJavaで簡単にgpgpu aparapi
Javaで簡単にgpgpu aparapiKen'ichi Sakiyama
 
AWSとAnsibleで実践!プロビジョニング入門‐Lamp+Laravel-
AWSとAnsibleで実践!プロビジョニング入門‐Lamp+Laravel-AWSとAnsibleで実践!プロビジョニング入門‐Lamp+Laravel-
AWSとAnsibleで実践!プロビジョニング入門‐Lamp+Laravel-靖 小田島
 
TripleOの光と闇
TripleOの光と闇TripleOの光と闇
TripleOの光と闇Manabu Ori
 
How to use Ceph RBD as CloudStack Primary Storage
How to use Ceph RBD as CloudStack Primary StorageHow to use Ceph RBD as CloudStack Primary Storage
How to use Ceph RBD as CloudStack Primary StorageKimihiko Kitase
 

Similar to OpenStack + Common Lisp (20)

Web技術勉強会23回目
Web技術勉強会23回目Web技術勉強会23回目
Web技術勉強会23回目
 
10分で作る Node.js Auto Scale 環境 with CloudFormation
10分で作る Node.js Auto Scale 環境 with CloudFormation10分で作る Node.js Auto Scale 環境 with CloudFormation
10分で作る Node.js Auto Scale 環境 with CloudFormation
 
Handlersocket etc. 20110906
Handlersocket etc. 20110906Handlersocket etc. 20110906
Handlersocket etc. 20110906
 
tcpdump & xtrabackup @ MySQL Casual Talks #1
tcpdump & xtrabackup @ MySQL Casual Talks #1tcpdump & xtrabackup @ MySQL Casual Talks #1
tcpdump & xtrabackup @ MySQL Casual Talks #1
 
Lisp Tutorial for Pythonista Day 6
Lisp Tutorial for Pythonista Day 6Lisp Tutorial for Pythonista Day 6
Lisp Tutorial for Pythonista Day 6
 
Cloud Foundry: Open Platform as a Service
Cloud Foundry: Open Platform as a ServiceCloud Foundry: Open Platform as a Service
Cloud Foundry: Open Platform as a Service
 
Cookpad 17 day Tech internship 2017 言語処理系入門 Rubyをコンパイルしよう
Cookpad 17 day Tech internship 2017 言語処理系入門 RubyをコンパイルしようCookpad 17 day Tech internship 2017 言語処理系入門 Rubyをコンパイルしよう
Cookpad 17 day Tech internship 2017 言語処理系入門 Rubyをコンパイルしよう
 
MoteMote Compiler Plugin
MoteMote Compiler PluginMoteMote Compiler Plugin
MoteMote Compiler Plugin
 
Web Operations and Perl kansai.pm#14
Web Operations and Perl kansai.pm#14Web Operations and Perl kansai.pm#14
Web Operations and Perl kansai.pm#14
 
Nodejs
NodejsNodejs
Nodejs
 
JOSUG2014 OpenStack 4th birthday party in Japan; the way of OpenStack API Dragon
JOSUG2014 OpenStack 4th birthday party in Japan; the way of OpenStack API DragonJOSUG2014 OpenStack 4th birthday party in Japan; the way of OpenStack API Dragon
JOSUG2014 OpenStack 4th birthday party in Japan; the way of OpenStack API Dragon
 
配布用Beginnerならきっと役立つmaster slave環境
配布用Beginnerならきっと役立つmaster slave環境配布用Beginnerならきっと役立つmaster slave環境
配布用Beginnerならきっと役立つmaster slave環境
 
恋に落ちるデプロイツール
恋に落ちるデプロイツール恋に落ちるデプロイツール
恋に落ちるデプロイツール
 
PaaSの作り方 Sqaleの場合
PaaSの作り方 Sqaleの場合PaaSの作り方 Sqaleの場合
PaaSの作り方 Sqaleの場合
 
Shelly
ShellyShelly
Shelly
 
Lxc cf201207-presen
Lxc cf201207-presenLxc cf201207-presen
Lxc cf201207-presen
 
Javaで簡単にgpgpu aparapi
Javaで簡単にgpgpu aparapiJavaで簡単にgpgpu aparapi
Javaで簡単にgpgpu aparapi
 
AWSとAnsibleで実践!プロビジョニング入門‐Lamp+Laravel-
AWSとAnsibleで実践!プロビジョニング入門‐Lamp+Laravel-AWSとAnsibleで実践!プロビジョニング入門‐Lamp+Laravel-
AWSとAnsibleで実践!プロビジョニング入門‐Lamp+Laravel-
 
TripleOの光と闇
TripleOの光と闇TripleOの光と闇
TripleOの光と闇
 
How to use Ceph RBD as CloudStack Primary Storage
How to use Ceph RBD as CloudStack Primary StorageHow to use Ceph RBD as CloudStack Primary Storage
How to use Ceph RBD as CloudStack Primary Storage
 

More from irix_jp

The invitation to Infrastructure CI
The invitation to Infrastructure CIThe invitation to Infrastructure CI
The invitation to Infrastructure CIirix_jp
 
The NoOps strategy and tactics
The NoOps strategy and tacticsThe NoOps strategy and tactics
The NoOps strategy and tacticsirix_jp
 
The practical guide of Infrastructure CI
The practical guide of Infrastructure CIThe practical guide of Infrastructure CI
The practical guide of Infrastructure CIirix_jp
 
The strategy from the Iserlohn fortress at JTF2018
The strategy from the Iserlohn fortress at JTF2018The strategy from the Iserlohn fortress at JTF2018
The strategy from the Iserlohn fortress at JTF2018irix_jp
 
JOSUG 34th Meetup
JOSUG 34th Meetup JOSUG 34th Meetup
JOSUG 34th Meetup irix_jp
 
Japan OpenStack User Group 34th Meetup - Handson Environment
Japan OpenStack User Group 34th Meetup - Handson EnvironmentJapan OpenStack User Group 34th Meetup - Handson Environment
Japan OpenStack User Group 34th Meetup - Handson Environmentirix_jp
 
OpenStack Summit Report
OpenStack Summit ReportOpenStack Summit Report
OpenStack Summit Reportirix_jp
 
OSC2016.Enterprise OpenStack & Cloud Native Applications
OSC2016.Enterprise OpenStack & Cloud Native ApplicationsOSC2016.Enterprise OpenStack & Cloud Native Applications
OSC2016.Enterprise OpenStack & Cloud Native Applicationsirix_jp
 
OSC2016 Kyoto Heat + Ansible + Jupyter
OSC2016 Kyoto Heat + Ansible + JupyterOSC2016 Kyoto Heat + Ansible + Jupyter
OSC2016 Kyoto Heat + Ansible + Jupyteririx_jp
 
空回りのクラウド基盤導入
空回りのクラウド基盤導入空回りのクラウド基盤導入
空回りのクラウド基盤導入irix_jp
 
クラウド時代のエンジニア魂と企業に必要なカルチャーチェンジ(前半)
クラウド時代のエンジニア魂と企業に必要なカルチャーチェンジ(前半)クラウド時代のエンジニア魂と企業に必要なカルチャーチェンジ(前半)
クラウド時代のエンジニア魂と企業に必要なカルチャーチェンジ(前半)irix_jp
 
Josug 20th meetup アンケート集計
Josug 20th meetup アンケート集計Josug 20th meetup アンケート集計
Josug 20th meetup アンケート集計irix_jp
 
OSC@Kyoto2014 OpenStack概要
OSC@Kyoto2014 OpenStack概要OSC@Kyoto2014 OpenStack概要
OSC@Kyoto2014 OpenStack概要irix_jp
 
H26第1回 沖縄オープンラボラトリ・ハンズオンセミナー:ボリューム操作編
H26第1回 沖縄オープンラボラトリ・ハンズオンセミナー:ボリューム操作編H26第1回 沖縄オープンラボラトリ・ハンズオンセミナー:ボリューム操作編
H26第1回 沖縄オープンラボラトリ・ハンズオンセミナー:ボリューム操作編irix_jp
 
H26第1回 沖縄オープンラボラトリ・ハンズオンセミナー:OpenStack 基礎操作編
H26第1回 沖縄オープンラボラトリ・ハンズオンセミナー:OpenStack 基礎操作編H26第1回 沖縄オープンラボラトリ・ハンズオンセミナー:OpenStack 基礎操作編
H26第1回 沖縄オープンラボラトリ・ハンズオンセミナー:OpenStack 基礎操作編irix_jp
 
JTF2014:OpenStackの概要と最新技術動向
JTF2014:OpenStackの概要と最新技術動向JTF2014:OpenStackの概要と最新技術動向
JTF2014:OpenStackの概要と最新技術動向irix_jp
 
Interop2014 - OpenStackの概要と最新技術動向(Icehouse)
Interop2014 - OpenStackの概要と最新技術動向(Icehouse)Interop2014 - OpenStackの概要と最新技術動向(Icehouse)
Interop2014 - OpenStackの概要と最新技術動向(Icehouse)irix_jp
 
Okinawa Open Days - OpenStack Overview
Okinawa Open Days - OpenStack OverviewOkinawa Open Days - OpenStack Overview
Okinawa Open Days - OpenStack Overviewirix_jp
 
OSC2013 Tokyo Spring OpenStack Overview
OSC2013 Tokyo Spring OpenStack OverviewOSC2013 Tokyo Spring OpenStack Overview
OSC2013 Tokyo Spring OpenStack Overviewirix_jp
 

More from irix_jp (19)

The invitation to Infrastructure CI
The invitation to Infrastructure CIThe invitation to Infrastructure CI
The invitation to Infrastructure CI
 
The NoOps strategy and tactics
The NoOps strategy and tacticsThe NoOps strategy and tactics
The NoOps strategy and tactics
 
The practical guide of Infrastructure CI
The practical guide of Infrastructure CIThe practical guide of Infrastructure CI
The practical guide of Infrastructure CI
 
The strategy from the Iserlohn fortress at JTF2018
The strategy from the Iserlohn fortress at JTF2018The strategy from the Iserlohn fortress at JTF2018
The strategy from the Iserlohn fortress at JTF2018
 
JOSUG 34th Meetup
JOSUG 34th Meetup JOSUG 34th Meetup
JOSUG 34th Meetup
 
Japan OpenStack User Group 34th Meetup - Handson Environment
Japan OpenStack User Group 34th Meetup - Handson EnvironmentJapan OpenStack User Group 34th Meetup - Handson Environment
Japan OpenStack User Group 34th Meetup - Handson Environment
 
OpenStack Summit Report
OpenStack Summit ReportOpenStack Summit Report
OpenStack Summit Report
 
OSC2016.Enterprise OpenStack & Cloud Native Applications
OSC2016.Enterprise OpenStack & Cloud Native ApplicationsOSC2016.Enterprise OpenStack & Cloud Native Applications
OSC2016.Enterprise OpenStack & Cloud Native Applications
 
OSC2016 Kyoto Heat + Ansible + Jupyter
OSC2016 Kyoto Heat + Ansible + JupyterOSC2016 Kyoto Heat + Ansible + Jupyter
OSC2016 Kyoto Heat + Ansible + Jupyter
 
空回りのクラウド基盤導入
空回りのクラウド基盤導入空回りのクラウド基盤導入
空回りのクラウド基盤導入
 
クラウド時代のエンジニア魂と企業に必要なカルチャーチェンジ(前半)
クラウド時代のエンジニア魂と企業に必要なカルチャーチェンジ(前半)クラウド時代のエンジニア魂と企業に必要なカルチャーチェンジ(前半)
クラウド時代のエンジニア魂と企業に必要なカルチャーチェンジ(前半)
 
Josug 20th meetup アンケート集計
Josug 20th meetup アンケート集計Josug 20th meetup アンケート集計
Josug 20th meetup アンケート集計
 
OSC@Kyoto2014 OpenStack概要
OSC@Kyoto2014 OpenStack概要OSC@Kyoto2014 OpenStack概要
OSC@Kyoto2014 OpenStack概要
 
H26第1回 沖縄オープンラボラトリ・ハンズオンセミナー:ボリューム操作編
H26第1回 沖縄オープンラボラトリ・ハンズオンセミナー:ボリューム操作編H26第1回 沖縄オープンラボラトリ・ハンズオンセミナー:ボリューム操作編
H26第1回 沖縄オープンラボラトリ・ハンズオンセミナー:ボリューム操作編
 
H26第1回 沖縄オープンラボラトリ・ハンズオンセミナー:OpenStack 基礎操作編
H26第1回 沖縄オープンラボラトリ・ハンズオンセミナー:OpenStack 基礎操作編H26第1回 沖縄オープンラボラトリ・ハンズオンセミナー:OpenStack 基礎操作編
H26第1回 沖縄オープンラボラトリ・ハンズオンセミナー:OpenStack 基礎操作編
 
JTF2014:OpenStackの概要と最新技術動向
JTF2014:OpenStackの概要と最新技術動向JTF2014:OpenStackの概要と最新技術動向
JTF2014:OpenStackの概要と最新技術動向
 
Interop2014 - OpenStackの概要と最新技術動向(Icehouse)
Interop2014 - OpenStackの概要と最新技術動向(Icehouse)Interop2014 - OpenStackの概要と最新技術動向(Icehouse)
Interop2014 - OpenStackの概要と最新技術動向(Icehouse)
 
Okinawa Open Days - OpenStack Overview
Okinawa Open Days - OpenStack OverviewOkinawa Open Days - OpenStack Overview
Okinawa Open Days - OpenStack Overview
 
OSC2013 Tokyo Spring OpenStack Overview
OSC2013 Tokyo Spring OpenStack OverviewOSC2013 Tokyo Spring OpenStack Overview
OSC2013 Tokyo Spring OpenStack Overview
 

Recently uploaded

Postman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By DanielPostman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By Danieldanielhu54
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムsugiuralab
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...Toru Tamaki
 
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A surveyToru Tamaki
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdftaisei2219
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Yuma Ohgami
 
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略Ryo Sasaki
 
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)Hiroki Ichikura
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものですiPride Co., Ltd.
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNetToru Tamaki
 

Recently uploaded (10)

Postman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By DanielPostman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By Daniel
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システム
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
 
論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdf
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
 
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
 
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものです
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet
 

OpenStack + Common Lisp

  • 1. (Advent Calendar 2012 JP) (openstack) (Open source software to build public and private clouds.) ( イヴの夜は OpenStack を (Common Lisp) でキメる! ) ( まあ、 ( キメなくてもいいんだけどね・・・ ( いや、キメてください。 ( お願いします。 )))) (2012.12.24 @irix_jp) 1
  • 2. m9(^Д^) プギャーwww ● イヴの夜にこんな資料作ってるヤツwww orz 2
  • 3. 気を取り直して・・・ ● OpenStack は全ての命令を API サーバが「 ReST 形式」で受付けます。 Client Command DB Admin or Users OpenStack Client Horizon Component Library (python) API Server AMQP OpenStack Component Other External Program Software 3
  • 4. ということは・・・ ● HTTP のリクエストが投げられれば、何にからでも 操作可能! ● そう、 Common Lisp からでも! – おまけで Ruby とか Perl とか Curl とか Wget でも。 4
  • 5. Common Lisp のはじめ方 ● まずは好みの処理系を選ぶ ● Common Lisp は厳密には「言語」では無く、「仕様」 ● この仕様に準拠して実装されたプログラムを 「 Common Lisp 処理系」と呼びます。 ● 代表的な処理系 – Clozure CL ・・・おすすめ!( Win/Linux/Mac で動く) – SBCL ・・・処理が早い。 Linux なら安心。 Win だと苦しい。 – Allegro CL ・・・商用。評価版あり。リッチな IDE 付き。 – Lisp Works ・・・商用。使った事無いです。 より詳しい情報はこちら http://ja.wikipedia.org/wiki/Common_Lisp 5
  • 6. 早速動かす ● Clozure CL を使います( Linux 想定) ● ここから DL – http://ccl.clozure.com/download.html ● 自分の環境に合わせたものを選択 ● 解凍して適当に配置。 – /opt/ccl とか ● とりあえず実行してみる – /opt/ccl/lx86cl   ・・・ 32bit 環境はこちら – /opt/ccl/lx86cl64  ・・・64 bit 環境はこちら 6
  • 7. 早速動かす ● これで OK $ /opt/ccl/lx86cl64 Welcome to Clozure Common Lisp Version 1.8-r15286M (LinuxX8664)! ? ← これがプロンプト ● とりあえず Hello World ? "Hello World" "Hello World" ● 超簡単!!! 7
  • 8. もう少し Lisp っぽく ● format 関数を使った例 ? (format t "~a" "Hello World") Hello World NIL ● エラーしたら ? (format r "~a" "Hello World") > Error: Unbound variable: R > While executing: CCL::CHEAP-EVAL-IN-ENVIRONMENT, in process listener(1). > Type :GO to continue, :POP to abort, :R for a list of available restarts. > If continued: Retry getting the value of R. > Type :? for other options. 1 > q Debbuger が起動するので冷静に「 q 」 ● 終了 ? (quit) 8
  • 9. プロンプト入力が低機能杉www ● 補完も履歴参照もできねーよwww ● 案ずるな、バッチ実行できる。 – 適当なファイルを準備 ● test.lisp (format t "~a" "Hello World") – コマンドラインから $ /opt/ccl/lx86cl64 -Q -b < test.lisp Hello World NIL ● -Q だんまりモード。プロンプトや起動メッセージを表示しない。 ● -b バッチモード。標準入力から受け取った式を評価して終了。 9
  • 10. エディタ ● Emacs でも、 VIM でも xxxx.lisp とファイル名をつ ければ、 Lisp Mode になるので好きな方で。 ● Emacs だと Slime という Lisp 開発をインタラク ティブに行える便利ツールがあるので、慣れてきた らコレを使うのがおすすめ。 ● Superior Lisp Interaction Mode for Emacs – http://common-lisp.net/project/slime/ ● Emacs ユーザなら Lispbox を使うのもあり。いろいろ 揃った All in One 環境 – http://common-lisp.net/project/lispbox/ 10
  • 11. パッケージ管理 ● Python に PIP 、 Ruby に GEM 、 Perl に CPAN が あるように・・・ ● Common Lisp にも Quiacklisp というパッケージ 管理の仕組みがあります。 ● サイトはこちら – http://www.quicklisp.org/ 11
  • 12. パッケージ管理 ● 導入は簡単 $ wget http://beta.quicklisp.org/quicklisp.lisp $ /opt/ccl/lx86cl64 Welcome to Clozure Common Lisp Version 1.8-r15286M (LinuxX8664)! ? ? (load "quicklisp.lisp") . .. ... ? (quicklisp-quickstart:install) . プロキシを経由する場合 (quicklisp-quickstart:install :proxy "http://192.168.128.254:8080") .. ... ? (ql:add-to-init-file) . .. ... ? (quit) 12
  • 13. パッケージの導入 ● HTTP リクエストを投げるパッケージを導入 ? (ql:quickload :drakma) ● 初回のみ、パッケージの DL が実行される。 ● ついでに json パッケージも ? (ql:quickload :cl-json) ● パッケージの検索 ? (ql:system-apropos "json") 13
  • 14. drakma がエラーするヤツ ● OS の環境によってはエラーが起きる [package cl+ssl] > Error: Unable to load any of the alternatives: > ("libssl.so.1.0.0" "libssl.so.0.9.8" "libssl.so" "libssl.so.4") > While executing: CFFI::FL-ERROR, in process listener(1). > Type :POP to abort, :R for a list of available restarts. > Type :? for other options. ● libssl のファイル名の問題だけなので、適当にリン ク貼ればおk $ find / |grep libssl.so $ sudo ln -s /usr/lib64/libssl.so.10 /usr/lib64/libssl.so ● 再実行 ? (ql:quickload :drakma) 14
  • 15. ここから本編 ● ようやくだよ! 15
  • 16. keystone へリクエストを投げる ● とりあえず何の工夫も無く openstack.lisp (ql:quickload :drakma) (drakma:http-request "http://cc:5000/v2.0/tokens") ● 実行すると当然エラー( 404 Not Found ) ● 指定されたリクエスト方式で、ヘッダ・データをちゃんと 含める必要がある。 16
  • 17. keystone へリクエストを投げる ● ちゃんと投げてみる ● 最初の方はおまじない ; ライブラリのロード (ql:quickload :drakma) ; HTTP クライアント (ql:quickload :cl-json) ; JSON パーサ ; デフォルトエンコードを指定 (setf drakma:*drakma-default-external-format* :utf-8) ; application/json をテキストとして扱う (pushnew (cons "application" "json") drakma:*text-content-types* :test #'equal) (drakma:http-request "http://192.168.100.52:5000/v2.0/tokens" :content-type "application/json" :method :post :content "{"auth": {"tenantName": "demo", "passwordCredentials": {"username": "demo", "password": "openstack"}}}") 17
  • 18. keystone へリクエストを投げる ● keystone に認証をかけるには ● Content-tyep: application/json で、 ● データ部に json 形式で以下の内容を含めて、 – テナント名 – ユーザ名 – パスワード ● http://keystone-address:5000/v2.0/tokens – へ POST する。 18
  • 19. keystone へリクエストを投げる ● もう少しスマートに、 ● まず json を生成する関数を作ってみる ; ライブラリのロード (ql:quickload :drakma) ; HTTP クライアント (ql:quickload :cl-json) ; JSON パーサ ; デフォルトエンコードを指定 (setf drakma:*drakma-default-external-format* :utf-8) ; application/json をテキストとして扱う (pushnew (cons "application" "json") drakma:*text-content-types* :test #'equal) (defun auth-create-json (tenantName username password) "keystone へ送る JSON を生成する " (json:encode-json-to-string `(("auth" ("tenantName" . ,tenantName) ("passwordCredentials" ("username" . ,username) ("password" . ,password)))))) (auth-create-json "demo" "demo" "openstack") 19
  • 20. keystone へリクエストを投げる ● 前のページの続き ● リクエストを投げる関数も作る (defun auth-post-json (url tenantName username password) "JSON を keystone へ送付し、認証情報を得る " (drakma:http-request url :content-type "application/json" :method :post :content (auth-create-json tenantName username password))) (auth-post-json "http://192.168.100.52:5000/v2.0/tokens" "demo" "demo" "openstack") ● これを実行すると、それっぽい JSON が返ってくる(と思 う 20
  • 21. ここまでのコード ● これ以降のコードはこの下に追記していく ● openstack.lisp ; ライブラリのロード (ql:quickload :drakma) ; HTTP クライアント (ql:quickload :cl-json) ; JSON パーサ ; デフォルトエンコードを指定 (setf drakma:*drakma-default-external-format* :utf-8) ; application/json をテキストとして扱う (pushnew (cons "application" "json") drakma:*text-content-types* :test #'equal) (defun auth-create-json (tenantName username password) "keystone へ送る JSON を生成する " (json:encode-json-to-string `(("auth" ("tenantName" . ,tenantName) ("passwordCredentials" ("username" . ,username) ("password" . ,password)))))) (defun auth-post-json (url tenantName username password) "JSON を keystone へ送付し、認証情報を得る " (drakma:http-request url :content-type "application/json" :method :post :content (auth-create-json tenantName username password))) 21
  • 22. 認証結果 ● さっきの関数を実行してみると・・・ (auth-post-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "password") "{"access": {"token": {"expires": "2012-12-21T15:24:01Z", "id": "27ae438762604ffe824fdc5a12b08b4e", "tenant": {"enabled": true, "description": "", "name": "demo", "id": "ad6bc57213b04c7f867aadbab97519e3"}}, "serviceCatalog": [{"endpoints": [{"adminURL": "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3", "region": "RegionOne", "internalURL": "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3", "id": "aecda37bbc384097bb38e0ac2de8264a ", "publicURL": "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3"}], "endpoints_links": [], "type": "compute", "name": "nova"}, {"endpoints": [{"adminURL": "http://157.7.133.23:9696/", "region": "RegionOne", "internalURL": "http://157.7.133.23:9696/", "i d": "1753832bfd754f7f8d61e13dda948be6", "publicURL": "http://157.7.133.23:9696/"}], "endpoints_links": [], "type": "network", "name": "quantum"}, {"endpoints": [{"adminURL": "http://157.7.133.23:9292", "region": "RegionOne", "internalURL": "http://157.7.133.23:9292", "id": "940eef79e0ad4716b5035cfcf77a8916", "publicURL": "http://157.7.13 3.23:9292"}], "endpoints_links": [], "type": "image", "name": "glance"}, {"endpoints": [{"adminURL": "http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3", "region": "RegionOne", "internalURL": "http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3", "id": "557a9527f0a94d908613260107738e3a", "publicURL" : "http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3"}], "endpoints_links": [], "type": "volume", "name": "cinder"}, {"endpoints": [{"adminURL": "http://157.7.133.23:8773/services/Admin", "region": "RegionOne", "internalURL": "http://157.7.133.23:8773/services/Cloud", "id": "dadd326ef5904cecaf4a058a73 4003f2", "publicURL": "http://157.7.133.23:8773/services/Cloud"}], "endpoints_links": [], "type": "ec2", "name": "ec2"}, {"endpoints": [{"adminURL": "http://157.7.133.23:35357/v2.0", "region": "RegionOne", "internalURL": "http://157.7.133.23:5000/v2 .0", "id": "1d763970d0b24d49be57eb7368044fd6", "publicURL": "http://157.7.133.23:5000/v2.0"}], "endpoints_links": [], "type": "identity", "name": "keystone"}], "user": {"username": "demo", "roles_links": [], "id": "5f003e1815ea4f76991a8b824402a918", "roles": [{"name": "Member"}], "name": "demo"}, "metadata": {"is_admin": 0, "roles": ["f55588c94cba4cce9f1cf2e4a15f490b"]}}}" できてるっぽい 22
  • 23. JSON をパースする ● cl-json のデコーダーを使って、リスト形式へ変換 (json:decode-json-from-string (auth-post-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$")) ((:ACCESS (:TOKEN (:EXPIRES . "2012-12-21T15:45:52Z") (:ID . "729038529271455c849b8ce5249d1af3") (:TENANT (:ENABLED . T) (:DESCRIPTION . "") (:NAME . "demo") (:ID . "ad6bc57213b04c7f867aadbab97519e3"))) (:SERVICE-CATALOG ((:ENDPOINTS ((:ADMIN- +URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:ID . "aecda37bbc384097bb38e0ac2de8264a") (:PUBLIC-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3"))) (:ENDPOINTS--LINKS) (:TYPE . "compute") (:NAME . "nova")) ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:9696/") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:9696/") (:ID . "1753832bfd754f7f8d61e13dda948be6") (:PUBLIC-+URL+ . "http://157.7.133.23:9696/"))) (:ENDPOINTS--LINKS) (:TYPE . "network") (:NAME . "quantum")) ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:9292") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:9292") (:ID . "940eef79e0ad4716b5035cfcf77a8916") (:PUBLIC- +URL+ . "http://157.7.133.23:9292"))) (:ENDPOINTS--LINKS) (:TYPE . "image") (:NAME . "glance")) ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3") (:ID . "557a9527f0a94d908613260107738e3a") (:PUBLIC-+URL+ . "http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3"))) (:ENDPOINTS--LINKS) (:TYPE . "volume") (:NAME . "cinder")) ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:8773/services/Admin") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:8773/services/Cloud") (:ID . "dadd326ef5904cecaf4a058a734003f2") (:PUBLIC-+URL+ . "http://157.7.133.23:8773/services/Cloud"))) (:ENDPOINTS--LINKS) (:TYPE . "ec2") (:NAME . "ec2")) ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:35357/v2.0") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:5000/v2.0") (:ID . "1d763970d0b24d49be57eb7368044fd6") (:PUBLIC-+URL+ . "http://157.7.133.23:5000/v2.0"))) (:ENDPOINTS--LINKS) (:TYPE . "identity") (:NAME . "keystone"))) (:USER (:USERNAME . "demo") (:ROLES--LINKS) (:ID . "5f003e1815ea4f76991a8b824402a918") (:ROLES ((:NAME . "Member"))) (:NAME . "demo")) (:METADATA (:IS--ADMIN . 0) (:ROLES "f55588c94cba4cce9f1cf2e4a15f490b")))) このリストをよく見ると、以下のような構造になっている。 ((:ACCESS (:TOKEN ....) (:SERVICE-CATALOG...) (:USER ...) (:METADATA..)) 23
  • 24. リスト操作 ● First 関数でリストから最初の要素を取り出す (first (json:decode-json-from-string (auth-post-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$"))) (:ACCESS (:TOKEN (:EXPIRES . "2012-12-21T16:05:39Z") (:ID . "e79e348b0115468891a8c7bf752f4d64") (:TENANT (:ENABLED . T) (:DESCRIPTION . "") (:NAME . "demo") (:ID . "ad6bc57213b04c7f867aadbab97519e3"))) (:SERVICE-CATALOG ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:ID . "aecda37bbc384097bb38e0ac2de8264a") (:PUBLIC-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3"))) (:ENDPOINTS--LINKS) (:TYPE . "compute") (:NAME . "nova")) ((:ENDPOINTS ((:ADMIN- +URL+ . "http://157.7.133.23:9696/") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:9696/") (:ID . "1753832bfd754f7f8d61e13dda948be6") (:PUBLIC-+URL+ . "http://157.7.133.23:9696/"))) (:ENDPOINTS--LINKS) (:TYPE . "network") (:NAME . "quantum")) ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:9292") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:9292") (:ID . "940eef79e0ad4716b5035cfcf77a8916") (:PUBLIC-+URL+ . "http://157.7.133.23:9292"))) (:ENDPOINTS--LINKS) (:TYPE . "image") (:NAME . "glance")) ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3") (:ID . "557a9527f0a94d908613260107738e3a") (:PUBLIC-+URL+ . "http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3"))) (:ENDPOINTS--LINKS) (:TYPE . "volume") (:NAME . "cinder")) ((:ENDPOINTS ((:ADMIN- +URL+ . "http://157.7.133.23:8773/services/Admin") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:8773/services/Cloud") (:ID . "dadd326ef5904cecaf4a058a734003f2") (:PUBLIC-+URL+ . "http://157.7.133.23:8773/services/Cloud"))) (:ENDPOINTS--LINKS) (:TYPE . "ec2") (:NAME . "ec2")) ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:35357/v2.0") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:5000/v2.0") (:ID . "1d763970d0b24d49be57eb7368044fd6") (:PUBLIC-+URL+ . "http://157.7.133.23:5000/v2.0"))) (:ENDPOINTS--LINKS) (:TYPE . "identity") (:NAME . "keystone"))) (:USER (:USERNAME . "demo") (:ROLES--LINKS) (:ID . "5f003e1815ea4f76991a8b824402a918") (:ROLES ((:NAME . "Member"))) (:NAME . "demo")) (:METADATA (:IS--ADMIN . 0) (:ROLES "f55588c94cba4cce9f1cf2e4a15f490b"))) (:ACCESS (:TOKEN ....) (:SERVICE-CATALOG...) (:USER ...) (:METADATA..) 一つカッコが取れる。 24
  • 25. リスト操作 ● さらに一つづつ取り出してみると (first (first (json:decode-json-from-string (auth-post-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$")))) → :ACCESS (second (first (json:decode-json-from-string (auth-post-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$")))) → (:TOKEN (:EXPIRES . "2012-12-21T16:08:44Z") (:ID . "e23f631ca4c74d64970f3bc21c21147c") (:TENANT (:ENABLED . T) (:DESCRIPTION . "") (:NAME . "demo") (:ID . "ad6bc57213b04c7f867aadbab97519e3"))) (fourth (first (json:decode-json-from-string (auth-post-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$")))) → (:USER (:USERNAME . "demo") (:ROLES--LINKS) (:ID . "5f003e1815ea4f76991a8b824402a918") (:ROLES ((:NAME . "Member"))) (:NAME . "demo")) (:ACCESS (:TOKEN ....) (:SERVICE-CATALOG...) (:USER ...) (:METADATA..) と、上から一つずつ要素が取り出せる。 25
  • 26. リスト操作 ● ここから TOKEN を取り出してみる。 (cdr (third (second (first (json:decode-json-from-string (auth-post-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$")))))) → "ce26db6126e342a8b604019463f34bb7" ● 芸はないけど、こんな感じで TOKEN が取り出せ る。 ● しかしこの方法は場所決め打ちで取り出しているので、 汎用性がなさすぎる。 – TOKEN の場所が ● :TOKEN → :ID にあることを利用すると・・・ 26
  • 27. ループと判定 ● ループで回して if で判定すると TOKEN が取得で きる。 (block exit (dolist (x (first (json:decode-json-from-string (auth-post-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$")))) (if (listp x) (if (eql :TOKEN (first x)) (dolist (y x) (if (listp y) (if (eql :ID (first y)) (return-from exit (cdr y))))))))) → "e2f35b1dca014a38a4eb9afb55eb752d" 27
  • 28. TOKEN を取得する関数 ● JSON を受け取り、 TOKEN を返す関数 (defun auth-return-token-from-json (json) "keystone が返す JSON を受け取り、 TOKEN を抽出して返す関数 " (block exit (dolist (x (first (json:decode-json-from-string json))) (if (listp x) (if (eql :TOKEN (first x)) (dolist (y x) (if (listp y) (if (eql :ID (first y)) (return-from exit (cdr y)))))))))) ● 実行すると・・・ (auth-return-token-from-json (auth-post-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$")) → "c71bb1f6e88b4032a4413c94a7f2bd46" 28
  • 29. もう少し汎用的に ● keystone から JSON を受け取って、リスト変換して 返す関数 ● リスト変換された JSON とキーを受け取ってキーが 存在するリストを返す関数 (defun auth-return-list-from-json (url tenantName username password) "keystone から認証 JSON を受け取り、リストへ変換して返す " (first (json:decode-json-from-string (auth-post-json url tenantName username password)))) (defun auth-return-list-from-json (json key) "json とキーを一つ受け取り、キーがマッチしたリストを返す " (block exit (dolist (x (first (json:decode-json-from-string json))) (if (listp x) (if (eql key (first x)) (return-from exit x)))))) (auth-return-key-from-json (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") :TOKEN) (:TOKEN (:EXPIRES . "2012-12-24T14:52:59Z") (:ID . "f116354e97494b52a1f06ad04e45580c") (:TENANT (:ENABLED . T) (:DESCRIPTION . "") (:NAME . "demo") (:ID . "ad6bc57213b04c7f867aadbab97519e3"))) 29
  • 30. 任意のデータを取り出す (defun auth-return-specified-key-from-json-list (json-list &rest keys) " 指定されたキーを取り出す " (let ((x json-list)) (dolist (key keys) (setf x (auth-return-key-from-json x key))) x)) (auth-return-specified-key-from-json-list (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") :TOKEN :ID) → (:ID . "68013432d7274ad78b3630461cb385ef") (auth-return-specified-key-from-json-list (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") :SERVICE-CATALOG) → (:SERVICE-CATALOG ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:ID . "aecda37bbc384097bb38e0ac2de8264a") (:PUBLIC-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3"))) (:ENDPOINTS--LINKS) (:TYPE . "compute") (:NAME . "nova")) ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:9696/") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:9696/") (:ID . "1753832bfd754f7f8d61e13dda948be6") (:PUBLIC-+URL+ . "http://157.7.133.23:9696/"))) (:ENDPOINTS--LINKS) (:TYPE . "network") (:NAME . "quantum")) ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:9292") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:9292") (:ID . "940eef79e0ad4716b5035cfcf77a8916") (:PUBLIC-+URL+ . "http://157.7.133.23:9292"))) (:ENDPOINTS--LINKS) (:TYPE . "image") (:NAME . "glance")) ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3") (:REGION . "RegionOne") (:INTERNAL- +URL+ . "http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3") (:ID . "557a9527f0a94d908613260107738e3a") (:PUBLIC-+URL+ . "http://157.7.133.23:8776/v1/ad6bc57213b04c7f867aadbab97519e3"))) (:ENDPOINTS--LINKS) (:TYPE . "volume") (:NAME . "cinder")) ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:8773/services/Admin") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:8773/services/Cloud") (:ID . "dadd326ef5904cecaf4a058a734003f2") (:PUBLIC-+URL+ . "http://157.7.133.23:8773/services/Cloud"))) (:ENDPOINTS--LINKS) (:TYPE . "ec2") (:NAME . "ec2")) ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:35357/v2.0") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:5000/v2.0") (:ID . "1d763970d0b24d49be57eb7368044fd6") (:PUBLIC-+URL+ . "http://157.7.133.23:5000/v2.0"))) (:ENDPOINTS--LINKS) (:TYPE . "identity") (:NAME . "keystone"))) (auth-return-specified-key-from-json-list (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") :METADATA :ROLES) → (:ROLES "f55588c94cba4cce9f1cf2e4a15f490b") (auth-return-specified-key-from-json-list (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") :USER :USERNAME) → (:USERNAME . "demo") 30
  • 31. エンドポイントの抽出 ● auth-return-specified-key-from-json-list 関数 で大体のデータは取り出せるが・・・ ● ENDPOINT はデータ形式がめんどくさい (:SERVICE-CATALOG ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:ID . "aecda37bbc384097bb38e0ac2de8264a") (:PUBLIC-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3"))) (:ENDPOINTS—LINKS) (:TYPE . "compute") (:NAME . "nova")) ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:9696/") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:9696/") (:ID . "1753832bfd754f7f8d61e13dda948be6") (:PUBLIC-+URL+ . "http://157.7.133.23:9696/"))) (:ENDPOINTS--LINKS) (:TYPE . "network") (:NAME . "quantum")) ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:9292") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:9292") (:ID . "940eef79e0ad4716b5035cfcf77a8916") (:PUBLIC-+URL+ . "http://157.7.133.23:9292"))) (:ENDPOINTS--LINKS) (:TYPE . "image") (:NAME . "glance")) ....... 31
  • 32. エンドポイントの抽出 ● まずエンドポイントの要素1つを調べて、それが欲し いデータならば t(true) を返す関数を作る (defun auth-check-endpoint-name (endpoint-list servicename) "1 つのエンドポイントを受け取り、それが servicename にマッチするエンドポイントならば t" (if (consp endpoint-list) (dolist (x endpoint-list) (if (consp x) (if (eql (first x) :NAME) (progn (if (string-equal (cdr x) servicename) (return-from auth-check-endpoint-name t)))))) nil)) (second (auth-return-specified-key-from-json-list (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") :SERVICE-CATALOG)) → ((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:ID . "aecda37bbc384097bb38e0ac2de8264a") (:PUBLIC-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3"))) (:ENDPOINTS--LINKS) (:TYPE . "compute") (:NAME . "nova")) (auth-check-endpoint-name (second (auth-return-specified-key-from-json-list (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") :SERVICE-CATALOG)) "nova") → T (auth-check-endpoint-name (second (auth-return-specified-key-from-json-list (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") :SERVICE-CATALOG)) "quantum") → NIL 32
  • 33. エンドポイントの抽出 ● マップ関数を使ったリスト操作 ● マップ関数を使うとリストの要素に対して、一括した操作 が行える。 ● 以下は指定した文字列にマッチするサービス名を含む 要素のみを残して、残りを破棄する例 CL-USER> (remove-if-not #'(lambda (x) (auth-check-endpoint-name x "nova")) (auth-return-specified-key-from-json-list (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") :SERVICE-CATALOG)) → (((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:ID . "aecda37bbc384097bb38e0ac2de8264a") (:PUBLIC-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3"))) (:ENDPOINTS--LINKS) (:TYPE . "compute") (:NAME . "nova"))) CL-USER> (remove-if-not #'(lambda (x) (auth-check-endpoint-name x "quantum")) (auth-return-specified-key-from-json-list (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") :SERVICE-CATALOG)) → (((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:9696/") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:9696/") (:ID . "1753832bfd754f7f8d61e13dda948be6") (:PUBLIC-+URL+ . "http://157.7.133.23:9696/"))) (:ENDPOINTS--LINKS) (:TYPE . "network") (:NAME . "quantum"))) CL-USER> (remove-if-not #'(lambda (x) (auth-check-endpoint-name x "notmatch")) (auth-return-specified-key-from-json-list (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") :SERVICE-CATALOG)) → NIL 33
  • 34. エンドポイントの抽出 ● 関数化しておく (defun auth-return-specified-endpoint (json-list servicename) " サービスカタログから指定のエンドポイントのみを抽出する " (remove-if-not #'(lambda (x) (auth-check-endpoint-name x servicename)) (auth-return-specified-key-from-json-list json-list :SERVICE-CATALOG))) CL-USER> (auth-return-specified-endpoint (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") "nova") → (((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3") (:ID . "aecda37bbc384097bb38e0ac2de8264a") (:PUBLIC-+URL+ . "http://157.7.133.23:8774/v2/ad6bc57213b04c7f867aadbab97519e3"))) (:ENDPOINTS--LINKS) (:TYPE . "compute") (:NAME . "nova"))) CL-USER> (auth-return-specified-endpoint (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") "quantum") → (((:ENDPOINTS ((:ADMIN-+URL+ . "http://157.7.133.23:9696/") (:REGION . "RegionOne") (:INTERNAL-+URL+ . "http://157.7.133.23:9696/") (:ID . "1753832bfd754f7f8d61e13dda948be6") (:PUBLIC-+URL+ . "http://157.7.133.23:9696/"))) (:ENDPOINTS--LINKS) (:TYPE . "network") (:NAME . "quantum"))) CL-USER> (auth-return-specified-endpoint (auth-return-list-from-json "http://cc-myvps:5000/v2.0/tokens" "demo" "demo" "^openstack2012$") "nomatch") → NIL 34
  • 35. コラム1:マップ関数 ● 「マップ」というのは、 Hadoop の MapReduce の Map と似た処理。 ● (1 2 3 4 5) みたいなリストの要素全てに計算を適用さ せる関数の事をマップ関数と読んでいる。 ● 全ての要素に x 2を適用。 – (mapcar #'(lambda (x) (* x 2)) '(1 2 3 4 5)) → (1 4 6 8 10) 35
  • 36. コラム2:ベクター ● 同じ型の要素を持ったリスト(配列)をベクターと呼 ぶ。 ● (1 2 3 4 5) や ("a" "b" "c" "d" "e") ● このベクターに対して map 関数のような処理を実 行する時に、 CPU が各要素に対する演算を並列に 行えるように作られた CPU をベクタープロセッサと いう ● ベクターデータに対する並列計算が得意な CPU ● 対して、スカラープロセッサは for で要素を一つずつ取 り出して計算されるイメージ。 10 年以上前に聞いた話で、記憶も曖昧なので間違ってるかも 36
  • 37. 後少し ● ここまでくると、コレまでの関数の組合せで、ほぼ任 意のデータが取得できるようになる。 ● いったんコレまでのコードを整理 ; ライブラリのロード (ql:quickload :drakma) ; HTTP クライアント (ql:quickload :cl-json) ; JSON パーサ ; デフォルトエンコードを指定 (setf drakma:*drakma-default-external-format* :utf-8) ; application/json をテキストとして扱う (pushnew (cons "application" "json") drakma:*text-content-types* :test #'equal) (defun auth-create-json (tenantName username password) "keystone へ送る JSON を生成する " (json:encode-json-to-string `(("auth" ("tenantName" . ,tenantName) ("passwordCredentials" ("username" . ,username) ("password" . ,password)))))) (defun auth-post-json (url tenantName username password) "JSON を keystone へ送付し、認証情報を得る " (drakma:http-request url :content-type "application/json" :method :post :content (auth-create-json tenantName username password))) 37
  • 38. 後少し ● 続き (defun auth-return-list-from-json (url tenantName username password) "keystone から認証 JSON を受け取り、リストへ変換して返す " (first (json:decode-json-from-string (auth-post-json url tenantName username password)))) (defun auth-return-key-from-json (json-list key) " リスト変換された json とキーを一つ受け取り、キーがマッチしたリストを返す " (block exit (dolist (x json-list) (if (listp x) (if (eql key (first x)) (return-from exit x)))))) (defun auth-return-specified-key-from-json-list (json-list &rest keys) " 指定されたキーを取り出す " (let ((x json-list)) (dolist (key keys) (setf x (auth-return-key-from-json x key))) x)) 38
  • 39. 後少し ● 続き (defun auth-check-endpoint-name (endpoint-list servicename) "1 つのエンドポイントを受け取り、それが servicename にマッチするエンドポイントならば t" (if (consp endpoint-list) (dolist (x endpoint-list) (if (consp x) (if (eql (first x) :NAME) (progn (if (string-equal (cdr x) servicename) (return-from auth-check-endpoint-name t)))))) nil)) (defun auth-return-specified-endpoint (json-list servicename) " サービスカタログから指定のエンドポイントのみを抽出する " (remove-if-not #'(lambda (x) (auth-check-endpoint-name x servicename)) (auth-return-specified-key-from-json-list json-list :SERVICE-CATALOG))) 39
  • 40. これまでに出てきたこと ● 以下の基礎 ● リスト操作 ● 関数 ● マップ ● 条件分岐 ● ループ 40
  • 41. さらに学習するには ● マクロ ● コンディション(例外処理) ● CLOS (オブジェクト) ● パッケージ などなど・・・ 41
  • 42. とりあえずまとめ ● 今回は JSON を一旦リストへ変換して、様々なリス ト操作を試してみました。 ● マクロやオブジェクトを使うともっと効率的にデータ 抽出が可能です。 ● もしこれで Common Lisp に興味を持った方がい れば、後述の参考書籍を見て、本格的に学習してみ てください。 42
  • 43. おすすめ書籍 ● 実践 Common Lisp ● Practical Common Lisp ● 実用 Common Lisp ● Paradigms of Artificial Intelligence Programming ● 計算機プログラムの構造と解釈 ● Structure and Interpretation of Computer Programs – 英語版がオンラインで読めます。 – http://mitpress.mit.edu/sicp/ ● On Lisp ● LET OVER LAMBD 43
  • 44. おすすめサイト ● xyzzy Lisp Programming ● http://www.geocities.jp/m_hiroi/xyzzy_lisp.html ● 逆引き CommonLisp ● http://tips.lisp-users.org/common-lisp/ ● モダン Common Lisp ● http://dev.ariel-networks.com/wp/archives/tag/common-lisp 44