Python API: OpenStack のとっておきの秘密

Python バインディングを使用して OpenStack 自動化スクリプトを作成する

OpenStack のユーザーあるいは管理者として、共通のタスクを自動化するスクリプトを作成する必要に迫られることはよくあります。OpenStack は、REST とコマンドライン・インターフェースに加え、ネイティブ Python API バインディングを公開しています。これらの Python バインディングを使用して OpenStack 自動化スクリプトの作成プロセスを大幅に単純化する方法を学んでください。

Lorin Hochstein, Lead Architect, Cloud Services, Nimbis Services

Lorin Hochstein photoLorin Hochstein は、学者上がりのソフトウェア開発者兼オペレーターです。彼は、Nimbis Services でクラウド・サービスのアーキテクト・リーダーを務めており、そこでは技術計算アプリケーションに OpenStack を採用しています。OpenStack ドキュメント化プロジェクトの常連のコントリビューターでもある彼は、ツイートを @lhochstein で、ブログを lorinhochstein.wordpress.com で行っています。



2013年 9月 26日

IaaS (Infrastructure as a Service) クラウドをデプロイするためのオープンソース・ソリューションとして、OpenStack の人気が高まっています。OpenStack にはダッシュボード Web アプリケーションが同梱されており、単一の仮想マシン (VM) インスタンスを起動するなどといった手動タスクにはこのアプリケーションを利用できますが、クラウド・ベースのタスクを自動化する場合には、OpenStack を駆動することが可能なスクリプトを作成しなければなりません。

OpenStack におけるサービス

OpenStack における「サービス」という言葉には、さまざまな意味があります。この言葉は、次のものを指して使われます。

  • OpenStack プロジェクト (Compute サービス (nova)、Identity サービス (keystone) など)
  • Identity サービスのカタログに含まれるエントリー (イメージ、コンピューティング、ボリュームなど)
  • Linux デーモン (nova-apiquantum-l3-agent など)

OpenStack プロジェクトは、Identity サービスのカタログ内にある 1 つ以上のエントリーに関連付けられ、1 つ以上の Linux デーモンによって実装されます。この記事のコンテキストでは、サービスという言葉を OpenStack プロジェクトという意味で使用します。

多くのユーザーは、OpenStack REST (Representational State Transfer) API (Application Programming Interface) を直接の対象とする自動化スクリプトを作成するか、コマンドライン・ツール (例えば、keystone または nova) を呼び出すシェル・スクリプトを作成するかの、いずれかの方法を採ります。けれども Python で OpenStack 自動化スクリプトを作成する場合には、それよりも良い方法があります。すべての OpenStack サービスでは、コマンドライン・ツールと同じ機能セットを公開するネイティブ Python API を公開しています。しかし残念ながら、これらの API を使用する方法についてはあまりドキュメントがありません。

Python プログラマーにとっては、コマンドライン・ツールや REST API を使用するよりも、Python API を使用するほうが遥かに簡単です。この記事では、一般的なユーザー・タスクと管理タスクを自動化するために OpenStack のネイティブ Python API を使用する方法を説明します。

OpenStack プロジェクトとコードネーム

OpenStack という言葉は、1 つのアプリケーションを指しているのではなく、IaaS クラウドを実装するために連携して動作する一連のサービスを指しています (ここでのサービスという言葉の意味については、囲み記事「OpenStack におけるサービス」を参照してください)。OpenStack サービスごとに正式名とコードネームがあり (表 1 を参照)、どの OpenStack サービスでも独自の Python API を公開しています。

表 1. OpenStack サービスの正式名とコードネーム
正式名コードネーム
Identity サービスkeystone
Image サービスglance
Compute サービスnova
Networking サービスquantum
Block Storage サービスcinder
Object Storage サービスswift

Python バインディングのインストール

Python バインディングは、それぞれのサービスのコマンドライン・ツールにバンドルされています。実のところ、各コマンドライン・ツールの実装には、それに対応する Python API が使用されています。これらのコマンドライン・ツールは、Python パッケージ・インストーラーである pip を使用して、Python Package Index (略称 PyPi。「参考文献」のリンクを参照) から個別にインストールすることができます。pip パッケージ名は以下のとおりです。

  • python-keystoneclient
  • python-glanceclient
  • python-novaclient
  • python-quantumclient
  • python-cinderclient
  • python-swiftclient

例えば、keystone クライアントをインストールするには、以下のコマンドを実行します。

$ pip install python-keystoneclient

上記のパッケージは、Python virtualenv または (ローカル・マシン上で root 権限を持っている場合には) システム全体の Python パッケージにインストールすることができます。

OpenStack のすべての API はバージョン管理されており、Python バインディングでは後方互換性を維持するために、これらの API の複数のバージョンをサポートしています。そのため、上記のパッケージは OpenStack サービスの古いバージョンのすべてで動作するので、最新バージョンのパッケージをダウンロードしておけば無難です。

この記事では、以下のサービスの Python API の例に焦点を当てて説明します。

  • OpenStack Identity サービス (keystone)
  • OpenStack Image サービス (glance)
  • OpenStack Compute サービス (nova)

テスト環境の構築

この記事を最大限に活用するには、実際にコード・スニペットを試すことができるように、OpenStack クラウドに管理者権限でアクセスすることをお勧めします。OpenStack クラウドへ管理者としてアクセスする権限を持っていない場合には、VM 内に OpenStack をデプロイするという方法が最も簡単です。DevStack プロジェクト (「参考文献」のリンクを参照) は、1 台のマシン上で OpenStack の開発向けデプロイメントを簡単に行えるように設計されたものです。VirtualBox のような仮想化ツールと組み合わせれば、OpenStack クラウドをノート PC上 (しかも Mac や Windows 上) で起動することができます。

あるいは、TryStack の無料アカウントを取得するという方法もあります。TryStack は、コミュニティーで保守されている OpenStack サンドボックスです (「参考文献」を参照)。ただし、TryStack で取得できるのは管理者レベルの権限ではなくユーザー・レベルの権限に限られるため、管理者権限を必要とするスクリプトについては、TryStack を使用してテストすることはできないので注意してください。


OpenStack Identity (keystone)

クライアントが Identity (keystone) API に対してリクエストを送信するには、該当する keystone クライアント Python オブジェクトをインスタンス化して、そのメソッドを呼び出します。API はバージョン管理されているため、Python クライアントは必ず特定のバージョンの API に関連付けられます。

リスト 1 に、keystone クライアントのバージョン 2.0 を使用して、Image サービスをサービス・カタログに追加する例を示します。

リスト 1. keystone での管理者ロールの作成
import keystoneclient.v2_0.client as ksclient
# Replace the method arguments with the ones from your local config
keystone = ksclient.Client(auth_url="http://192.168.27.100:35357/v2.0",
                           username="admin",
                           password="devstack",
                           tenant_name="demo")
glance_service = keystone.services.create(name="glance",
                            service_type="image",
                            description="OpenStack Image Service")

クレデンシャル

keystoneclient.v2_0.client.Client オブジェクトをインスタンス化する際には、クレデンシャルを提供する必要があります。keystone エンドポイントが受け入れるクレデンシャルには、トークン、またはユーザー名とパスワード、という 2 つのタイプがあります。管理者は、admin トークンを使用することができます。このトークンは、管理者権限を持ち、決して失効することのない特殊なトークンで、keystone サービスを実行するマシン上の /etc/keystone/keystone.conf ファイルに、admin_token 構成オプションを指定することで定義します (リスト 2 を参照)。

リスト 2. auth トークンによる認証
import keystoneclient.v2_0.client as ksclient

# Replace the values below with the ones from your local config
endpoint = "http://192.168.27.100:35357/v2.0"
admin_token = "devstack"

keystone = ksclient.Client(endpoint=endpoint, token=admin_token)

通常は、admin トークンを使用すると、セキュリティー上の理由から冷ややかな目で見られます。OpenStack Identity の開発者たちが推奨しているのは、このトークンを使うのではなく、管理者権限を持つユーザーを作成した後は、常にユーザー名とパスワードを使用して認証を行う方法です (リスト 3 を参照)。

リスト 3. ユーザー名とパスワードによる認証
import keystoneclient.v2_0.client as ksclient

# Replace the values below  the ones from your local config,
auth_url = "http://192.168.27.100:35357/v2.0"
username = "admin"
password = "devstack"
tenant_name = "demo"

keystone = ksclient.Client(auth_url=auth_url, username=username,
                           password=password, tenant_name=tenant_name)

openrc ファイルのロード

認証を単純化するために私がお勧めする方法は、クレデンシャルを環境変数にエクスポートする openrc ファイルを作成する方法です。こうすれば、ログイン情報をスクリプトにハード・コーディングする必要がなくなります。リスト 4 にサンプル openrc ファイルを記載します。

リスト 4. 環境変数からのクレデンシャルのロード
export OS_USERNAME="myname"
export OS_PASSWORD="mypassword"
export OS_TENANT_NAME="mytenant"
export OS_AUTH_URL="http://10.20.0.2:5000/v2.0/"

環境変数 OS_USERNAME、OS_PASSWORD、OS_TENANT_NAME、および OS_AUTH_URL は、すべての Python コマンドライン・ツールで標準化されています。これらの環境変数が設定されている場合、コマンドライン・ツール (keystonenova) は設定済みの環境変数を API エンドポイントに対する認証に使用します。

環境変数を現行のシェルにロードするには、bash の source 組み込みコマンドを使用します。bash を標準シェルとして使用する場合、以下の行を .profile に追加することで、ログインするたびに環境変数が自動的に設定されるようにすることもできます。

$ source openrc

openrc ファイルが取り込まれた後は、Python スクリプトによって環境からクレデンシャルを取得できるようになります。環境からログイン情報を抽出する、credentials.py という Python ファイルを作成してみましょう (リスト 5 を参照)。keystonenova がそれぞれのクライアント・イニシャライザー・メソッドで使用する変数名は若干異なるため、それぞれに別個の関数を定義していることに注意してください。

リスト 5. credentials.py
#!/usr/bin/env python
import os

def get_keystone_creds():
    d = {}
    d['username'] = os.environ['OS_USERNAME']
    d['password'] = os.environ['OS_PASSWORD']
    d['auth_url'] = os.environ['OS_AUTH_URL']
    d['tenant_name'] = os.environ['OS_TENANT_NAME']
    return d

def get_nova_creds():
    d = {}
    d['username'] = os.environ['OS_USERNAME']
    d['api_key'] = os.environ['OS_PASSWORD']
    d['auth_url'] = os.environ['OS_AUTH_URL']
    d['project_id'] = os.environ['OS_TENANT_NAME']
    return d

認証トークン

クライアント・イニシャライザーが例外をスローせずにリターンすれば、エンドポイントに対して正常に認証されたことになります。これで、戻りオブジェクトの auth_token 属性を介して発行された keystone トークンにアクセスすることができます (リスト 6 を参照)。glance API に対する認証の場合には、後で説明するように、イニシャライザーには明示的に keystone 認証トークンを引数として渡す必要があります。

リスト 6. 対話型 Python セッションで keystone エンドポイントに対して行い、成功した認証
>>> import keystoneclient.v2_0.client as ksclient
>>> from credentials import get_keystone_creds
>>> creds = get_keystone_creds()
>>> keystone = ksclient.Client(**creds)
>>> keystone.auth_token
u'MIILkAYJKoZIhvcNAQcCoIILgTCCC30CAQExCTAHBgUrDgMCGjCCCmkGCSqGSIb3DQEHAaCCCloE
ggpWeyJhY2Nlc3MiOiB7InRva2VuIjogeyJpc3N1ZWRfYXQiOiAiMjAxMy0wNS0yNlQwMjoxMjo0Mi
42MDAwMjUiLCAiZXhwaXJlcyI6ICIyMDEzLTA1LTI3VDAyOjEyOjQyWiIsICJpZCI6ICJwbGFjZWhv
bGRlciIsICJ0ZW5hbnQiOiB7ImRlc2NyaXB0aW9uIjogbnVsbCwgImVuYWJsZWQiOiB0cnVlLCAiaW
...
fI9JnOBZJwuoma8je0a1AvLff6AcJ1zFkVZGb'

注: OpenStack Identity の Grizzly リリースでは、デフォルトで公開鍵基盤のトークンを使用します。これは、それより前の OpenStack のリリースで使用されている UUID 形式のトークン (例えば、7d9fde355f09458f8e97986a5a652bfe) よりも遥かに長いトークンです。

CRUD 操作

keystone API は、基本的に CRUD (Create, Read, Update, Delete) インターフェースです。keystone API を使用したやりとりの大半は、keystone バックエンド・データベースに対する読み取り操作または変更操作のいずれかとなります。API を使用したやりとりのほとんどは、Manager オブジェクトの呼び出しによって発生します。Manager は、同じタイプのオブジェクトのコレクションを表します。例えば、UserManagerkeystone ユーザーを操作し、TenantManager はテナントを操作し、RoleManager はロールを操作するといった具合です。これらのマネージャーは、create (新規オブジェクトの作成)、get (ID に応じたオブジェクトの取得)、list (すべてのオブジェクトの取得)、delete などの操作をサポートしています。

ユーザー、テナント、ロールの作成

OpenStack をデプロイするとき、最初に行う処理の 1 つは、一般的には、keystone テナントを作成し、続いて管理者権限を持つ keystone ユーザーを作成することです。リスト 7 に、Python API を使用してこのプロセスを自動化する方法の例を示します。このスクリプトは、次の処理を行います。

  • ユーザー・ロールを作成する (Client.roles.create)。
  • 管理者ロールを作成する (Client.roles.create)。
  • 「Acme」という名前のテナントを作成する (Client.tenants.create)。
  • 「admin」という名前のユーザーを作成する (Client.users.create)。
  • Acme テナント内で admin ユーザーに管理者ロールを割り当てる (Client.roles.add_user_role)。

この時点では、Identity サービスに管理者権限を持つユーザーはまだ含まれていないため、このシナリオでは admin トークンを使用するのが妥当です。

リスト 7. ユーザー、テナント、ロールの作成
import keystoneclient.v2_0.client as ksclient
endpoint = "http://192.168.27.100:35357/v2.0"
admin_token = "devstack"

keystone = ksclient.Client(endpoint=endpoint, token=admin_token)
user_role = keystone.roles.create("user")
admin_role = keystone.roles.create("admin")
acme_tenant = keystone.tenants.create(tenant_name="Acme",
                        description="Employees of Acme Corp.",
                        enabled=True)
admin_user = keystone.users.create(name="admin",
                password="a.G'03134!j",
                email="cloudmaster@example.com", tenant_id=acme_tenant.id)
keystone.roles.add_user_role(admin_user, admin_role, acme_tenant)

サービスとエンドポイントの作成

Identity サービスを OpenStack クラウドにデプロイするとき、次に行う処理は、一般的には、keystone にクラウド内のサービスとエンドポイントを取り込むことです。リスト 8 に一例として、Client.services.create メソッドと Client.endpoints.create メソッドを使用して、Identity サービスのサービスおよびエンドポイントを追加する方法の例を示します。

リスト 8. サービスとエンドポイントの作成
import keystoneclient.v2_0.client as ksclient
creds = get_keystone_creds() # See xxx
keystone = ksclient.Client(**creds)
service = keystone.services.create(name="keystone",
                                   service_type="identity",
                                   description="OpenStack Identity Service")

keystone_publicurl = "http://192.168.27.100:5000/v2.0"
keystone_adminurl = "http://192.168.27.100:35357/v2.0"
keystone.endpoints.create(service_id=service.id,
                          region="Northeast",
                          publicurl=keystone_publicurl,
                          adminurl=keystone_adminurl,
                          internalurl=keystone_publicurl)

サービス・カタログへのアクセス

keystone の主要な機能の 1 つは、サービス・カタログとしての役割を果たすことです。クライアントは keystone を使用して、OpenStack サービスのエンドポイント URL を参照することができます。keystone API は、この機能を keystoneclient.v2_0.client.Client.service_catalog.url_for メソッドを介して公開します。このメソッドでは、サービスのタイプ (例えば、イメージ、ボリューム、コンピューティング、ネットワーク) およびエンドポイントのタイプ (publicURLinternalURLadminURL) によってサービス・エンドポイントを参照することができます。

リスト 9 に、url_for メソッドを使用して OpenStack Image サービス (glance) のエンドポイントを取得する方法を示します。

リスト 9. 対話型 Python セッションでの glance エンドポイントの照会
>>> import keystoneclient.v2_0.client as ksclient
>>> creds = get_keystone_creds() # See <a href="openrc-creds" />
>>> keystone = ksclient.Client(**creds)
>>> glance_endpoint = keystone.service_catalog.url_for(service_type='image',
                                                       endpoint_type='publicURL')
>>> glance_endpoint
u'http://192.168.27.100:9292'

OpenStack Compute (nova)

nova API のバージョン 1.1 とバージョン 2

nova API のバージョン 1.1 とバージョン 2 はまったく同じです。したがって、novaclient.client.Client イニシャライザーの最初の引数として「1.1」の代わりに「2」を渡しても構いませんが、モジュールとしては、novaclient.v2 は存在せず、novaclient.v1_1 のみが存在します。

OpenStack Compute (nova) の Python API は、OpenStack Identity API と同じように動作します。この記事では、nova API のバージョン 1.1 を使用します。したがって、この記事で使用する nova Python バインディングのバージョン 1.1 のクラスは、novaclient.v1_1 Python 名前空間にあります。

nova-api エンドポイントに対する認証

nova-api エンドポイントに対してリクエストを送信するには、novaclient.v1_1.client.Client オブジェクトを初期化してから、そのオブジェクトを呼び出します。この API のバージョン 1.1 と通信するクライアントを取得するには、2 通りの方法があります。リスト 10 に示すのは、バージョン・ストリングを引数として渡すことによって、該当するクライアントを取得する方法です。

リスト 10. バージョンを引数として渡す方法
from novaclient import client as novaclient
from credentials import get_nova_creds
creds = get_nova_creds()
nova = novaclient.Client("1.1", **creds)

リスト 11 に示すのは、バージョン 1.1 モジュールを明示的にインポートすることによって該当するクライアントを取得する方法です。

リスト 11. バージョンを直接インポートする方法
import novaclient.v1_1.client as nvclient
from credentials import get_nova_creds
creds = get_nova_creds()
nova = nvclient.Client(**creds)

インスタンスの一覧表示

現在の VM インスタンスを一覧表示するには、Client.servers.list メソッドを使用します (リスト 12 を参照)。

リスト 12. 対話型 Python セッションでの VM インスタンスの一覧の取得
>>> import novaclient.v1_1.client as nvclient
>>> from credentials import get_nova_creds
>>> creds = get_nova_creds()
>>> nova = nvclient.Client(**creds)
>>> nova.servers.list()
[<Server: cirros>]

名前によるインスタンスの取得とインスタンスの終了

インスタンスの ID は知らなくても、その名前を知っている場合には、Server.find メソッドを使用することができます。リスト 13 に、名前でインスタンスを見つけてから、Server.delete メソッドを使用してそのインスタンスを終了する方法を示します。

リスト 13. my-vm インスタンスの終了
import novaclient.v1_1.client as nvclient
from credentials import get_nova_creds
creds = get_nova_creds()
nova = nvclient.Client(**creds)

server = nova.servers.find(name="my-vm")
server.delete()

インスタンスの起動とインスタンスのステータスの確認

新しいインスタンスを起動するには、Client.servers.create メソッドを使用します (リスト 14 を参照)。注意する点として、このメソッドにはイメージとフレーバーの名前ではなく、image オブジェクトと flavor オブジェクトを渡す必要があります。この例ではまた、「mykey」という名前の鍵ペアがまだ存在しない場合には、Client.keypairs.create メソッドによって、SSH (Secure Shell) 公開鍵を ~/.ssh/id_rsa.pub にアップロードし、この鍵ペアに「mykey」という名前を付けています。そして最後に、Client.servers.get メソッドによって現在のインスタンスを取得し、そのインスタンスを使ってステータスのポーリングを行っています。

リスト 14. 新しいインスタンスの起動
import os
import time
import novaclient.v1_1.client as nvclient
from credentials import get_nova_creds
creds = get_nova_creds()
nova = nvclient.Client(**creds)
if not nova.keypairs.findall(name="mykey"):
    with open(os.path.expanduser('~/.ssh/id_rsa.pub')) as fpubkey:
        nova.keypairs.create(name="mykey", public_key=fpubkey.read())
image = nova.images.find(name="cirros")
flavor = nova.flavors.find(name="m1.tiny")
instance = nova.servers.create(name="test", image=image, flavor=flavor, key_name="mykey")

# Poll at 5 second intervals, until the status is no longer 'BUILD'
status = instance.status
while status == 'BUILD':
    time.sleep(5)
    # Retrieve the instance again so the status field updates
    instance = nova.servers.get(instance.id)
    status = instance.status
print "status: %s" % status

フローティング IP アドレスの割り当て

フローティング IP アドレスを割り当てるには、まず始めに、使用可能なフローティング IP アドレスが OpenStack にあることを確認する必要があります。それには、Client.floating_ips.list メソッドで、使用可能なフローティング IP アドレスのリストを取得します。返されたリストが空の場合、Client.floating_ips.create メソッドを使用して新しいフローティング IP アドレスを割り振った後、Server.add_floating_ip メソッドにより、その新規フローティング IP アドレスをインスタンスに割り当てます (リスト 15 を参照)。

リスト 15. フローティング IP アドレスの作成
>>> nova.floating_ips.list()
[]
>>> floating_ip = nova.floating_ips.create()
<FloatingIP fixed_ip=None, id=1, instance_id=None, ip=192.168.27.129, pool=public>
>>> instance = nova.servers.find(name="test")
>>> instance.add_floating_ip(floating_ip)

セキュリティー・グループの変更

セキュリティー・グループにルールを追加するには、Client.security_group_rules.create メソッドを使用します。リスト 16 に、SSH (ポート 22 で実行) とすべての ICMP (Internet Control Message Protocol) トラフィックを許可するようにデフォルトのセキュリティー・グループを変更する例を記載します。この例ではルールを追加するために、Client.security_groups.find メソッドを使用して、「default」という名前のセキュリティー・グループを取得しています。

リスト 16. default セキュリティー・グループでのポート 22 および ICMP の許可
import novaclient.v1_1.client as nvclient
from credentials import get_nova_creds
creds = get_nova_creds()
nova = nvclient.Client(**creds)

secgroup = nova.security_groups.find(name="default")
nova.security_group_rules.create(secgroup.id,
                               ip_protocol="tcp",
                               from_port=22,
                               to_port=22)
nova.security_group_rules.create(secgroup.id,
                               ip_protocol="icmp",
                               from_port=-1,
                               to_port=-1)

コンソール・ログの取得

Server.get_console_output メソッドは、VM の起動時にコンソールに送信されたテキストを取得します。コンソール出力を解析することで、ホスト鍵の変更による一般的な問題に対処できる可能性があります。

OpenStack のような IaaS クラウドには、SSH ホスト鍵のチェック機能がうまく動作しないという欠点があります。例えば、IP アドレスが 10.40.1.150 であるインスタンスにログインする場合、過去にログインしたことのある別のインスタンスでこの IP アドレスが使用されていたとすると、リスト 17 に示すようなエラーを受け取ります。

リスト 17. ホスト ID が変更された場合のエラー
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
6f:2b:59:46:cb:8c:81:48:06:f3:c5:db:40:23:d3:be.
Please contact your system administrator.
Add correct host key in /home/mylogin/.ssh/known_hosts to get rid of this message.
Offending key in /home/mylogin/.ssh/known_hosts:1
RSA host key for 10.40.1.150 has changed and you have requested strict checking.
Host key verification failed.

使用している VM イメージに cloud-init パッケージ (「参考文献」を参照) がインストールされている場合には、リスト 18 に示すようにコンソールにホスト鍵が出力されます。

リスト 18. コンソールでの SSH 鍵出力の例
-----BEGIN SSH HOST KEY KEYS-----
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDciNMyzj0osyPOM+
1OyseTWgkzw+M43zp5H2CchG8daRDHel7V3OHETVdI6WofNn
SdBJAwIoisRFPxyroNGiVw= root@my-name
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDU854+fNdcKMZTLCUejMOZllQmmphr6V5Aaz1F2+x2jXql5rqKQ
d5/h6OdFszcp+gdTeVtfgG++/298qodTemVVrvqwjp4eN87iHvhPxH6GDEevAKlEed2ckdAmgvzI9rcOYgR/46G9x
Iea0IdgNjMvN1baj6WPtv+HfcfH/ZV58G306lSJfbz/GVxNTIxW+Wg7ZQCAe6jWgm4oQ+66sco+7Fub24EPue3kO8
jqufqq3mY5+MFlzEHSX5B04ioG5Alw/JuqVx5+7zHt9I2wA3nzsyUdKtCTrw8V4fYEhWDm53WLOpW+8CeYCXuv+yL
7EjwLqhIH/TUuzGQiWmFGvyz root@my-name
-----END SSH HOST KEY KEYS-----

リスト 19 に示すスクリプトは、Server.get_console_output API メソッドを使用してコンソールから SSH ホスト鍵を抽出して、~/.ssh/known_hosts ファイルを更新します。これにより、SSH を使用してフローティング IP インスタンスに初めてアクセスする際に、SSH 警告は出されなくなります。

リスト 19. コンソールからの SSH ホスト鍵の抽出
import os
import subprocess
import novaclient.v1_1.client as nvclient
from credentials import get_nova_creds


def get_server(creds, servername):
    nova = nvclient.Client(**creds)
    return nova.servers.find(name=servername)


def remove_hostkey(ip):
    subprocess.call(["ssh-keygen", "-R", ip])


def get_hostkey_from_console(text):
    lines = text.split('\n')
    start = '-----BEGIN SSH HOST KEY KEYS-----\r'
    end = '-----END SSH HOST KEY KEYS-----\r'
    start_ind = lines.index(start)
    end_ind = lines.index(end)
    for i in range(start_ind+1, end_ind):
        key = lines[i].rstrip()
        if key.startswith('ssh-rsa'):
            return key
    raise KeyError("ssh host key not found")


def main():
    server = get_server(get_nova_creds(), "my-server")
    netname = "my-network"
    (fixed_ip, floating_ip) = server.networks[netname]
    # Remove existing key, if any
    remove_hostkey(floating_ip)
    output = server.get_console_output()
    key = get_hostkey_from_console(output)
    with open(os.path.expanduser("~/.ssh/known_hosts"), 'a') as f:
        f.write("{0} {1}\n".format(floating_ip, key))


if __name__ == '__main__':
    main()

OpenStack Image (glance)

OpenStack Image サービス (glance) の役割は、Compute サービスが使用する VM イメージのカタログを管理することです。

glance エンドポイントに対する認証

OpenStack Image (glance) の Python API と Compute API には、初期認証を行う際に若干異なる点があります。glance API では、以下の情報を keystone API から取得して利用する必要があります。

  • The glance エンドポイント URL
  • A keystone 認証トークン

nova API と同じく、glance API でも、API のバージョンを引数として渡すか、またはモジュールを直接インポートすることができます。リスト 20 に、API のバージョン 2 で glance エンドポイントに対して認証を行う方法の例を示します。

リスト 20. glance API での認証
import keystoneclient.v2_0.client as ksclient
import glanceclient
creds = get_keystone_creds()
keystone = ksclient.Client(**creds)
glance_endpoint = keystone.service_catalog.url_for(service_type='image',
                                                   endpoint_type='publicURL')
glance = glanceclient.Client('2',glance_endpoint, token=keystone.auth_token)

リスト 21 に示す例では、該当する glance モジュールを直接インポートしています。

リスト 21. glance モジュールを直接インポートする
import keystoneclient.v2_0.client as ksclient
import glanceclient.v2.client as glclient
creds = get_keystone_creds()
keystone = ksclient.Client(**creds)
glance_endpoint = keystone.service_catalog.url_for(service_type='image',
                                                   endpoint_type='publicURL')
glance = glclient.Client(glance_endpoint, token=keystone.auth_token)

使用可能なイメージの一覧表示

現在のイメージを一覧表示するには、Client.images.list メソッドを使用します (リスト 22 を参照)。このメソッドによってジェネレーターが返され、ジェネレーターでは nova API の list メソッドによって一覧オブジェクトが返されることに注意してください。

リスト 22. VM イメージの一覧の取得
>>> import keystoneclient.v2_0.client as ksclient
>>> import glanceclient.v2.client as glclient
>>> creds = get_keystone_creds()
>>> keystone = ksclient.Client(**creds)
>>> glance_endpoint = keystone.service_catalog.url_for(service_type='image',
...                                                    endpoint_type='publicURL')
>>> glance = glclient.Client(glance_endpoint, token=keystone.auth_token)
>>> images = glance.images.list()
>>> images
<generator object list at 0x10c8efd70>
>>> images.next()
{u'status': u'active', u'tags': [], u'kernel_id':
u'8ab02091-21ea-434c-9b7b-9b4e2ae49591', u'container_format': u'ami', u'min_ram': 0,
u'ramdisk_id': u'd36267b5-7cae-4dec-b5bc-6d2de5c89c64', u'updated_at':
u'2013-05-28T00:44:21Z', u'visibility': u'public', u'file':
u'/v2/images/cac50405-f4d4-4715-b1f6-7f00ff5030e6/file', u'min_disk': 0,
u'id': u'cac50405-f4d4-4715-b1f6-7f00ff5030e6', u'size': 25165824, u'name':
u'cirros-0.3.1-x86_64-uec', u'checksum': u'f8a2eeee2dc65b3d9b6e63678955bd83',
u'created_at': u'2013-05-28T00:44:21Z', u'disk_format': u'ami', u'protected':
False, u'schema': u'/v2/schemas/image'}

glance へのイメージのアップロード

リスト 23 に、glance API を使用してファイルをアップロードする方法の例を示します。イメージを作成するには、API のバージョン 1 を使用する必要があります。これは、Python API バインディングはバージョン 2 の create メソッドを実装していないためです。

リスト 23. glance へのイメージのアップロード
import keystoneclient.v2_0.client as ksclient
import glanceclient
creds = get_keystone_creds()
keystone = ksclient.Client(**creds)
glance_endpoint = keystone.service_catalog.url_for(service_type='image',
                                                   endpoint_type='publicURL')
glance = glanceclient.Client('1',glance_endpoint, token=keystone.auth_token)
with open('/tmp/cirros-0.3.0-x86_64-disk.img') as fimage:
    glance.images.create(name="cirros", is_public=True, disk_format="qcow2",
                         container_format="bare", data=fimage)

次のステップ

この記事では、OpenStack Python API が公開する機能の簡単な概要のみを示しています。以下では、Python API がどのような動作をするかについて、詳しく学ぶ手段をいくつか紹介します。

公式 API ドキュメント

OpenStack プロジェクトでは、すべての OpenStack Python API に関するドキュメントの保守を行っています (「参考文献」を参照)。これらすべての API には、モジュール、クラス、およびメソッドごとに自動生成されたドキュメントがあります。API によって、ドキュメントに使用例が記載されている場合もあれば、記載されていない場合もあります。

API のイントロスペクト

API について学ぶ最善の方法の 1 つは、対話型コマンドライン Python インタープリター内で API を使用することです。拡張 Python インタープリターとしての bpython インタープリターは、ユーザーの入力に合わせて有効なメソッド名を表示するだけでなく、関数の docstring も自動的に表示します (図 1 を参照)。

図 1. bpython による自動ヘルプ表示
add_floating_ip メソッドのヘルプを表示する bpython

CLI ソース・コードの調査

Python の長所の 1 つは、その可読性にあります。したがって、Python API について学ぶには、ソース・コードを読むのが一番良い方法です。ソース・コードのパッケージはいずれも OpenStack グループの GitHub でホストされています。例えば、nova API のソース・コードを入手するには、以下のコマンドを実行します。

git clone http://github.com/openstack/python-novaclient

コマンドライン・クライアントは API を使用して実装されているため、各パッケージには便利なことにサンプル・アプリケーションが同梱されています。

novaclient API の場合、最も興味深いファイルは、この API を形成する Python クラスが格納されている novaclient/v1_1 ディレクトリー内のファイルです。シェルでのコマンドライン・コマンドは、novaclient/v1_1/shell.py 内に do_* メソッドとして実装されています。例えば、nova flavor-listdo_flavor_list メソッドとして実装されており、このメソッドが最終的に Client.flavors.list API メソッドを呼び出します。

Python API を使用するその他のアプリケーションの調査

OpenStack Python API を使用するアプリケーションは他にもあります。その 1 つである OpenStack Dashboard (「参考文献」のリンクを参照) は、各種の OpenStack サービスとの通信に一貫して Python API を使用します。これは、Python API を使用するアプリケーションの好例です。特に openstack_dashboard/api ディレクトリーを調べると、Dashboard では Python API をどのように使用しているかがわかります。

OpenStack Client (「参考文献」を参照) は、さまざまな既存のクライアントの機能を 1 つのコマンドライン・インターフェースに統合するための取り組みで、他のすべてのプロジェクトの Python API を使用します。

Heat プロジェクトは、OpenStack とともに動作するように設計されたオーケストレーション層であり、OpenStack Python API を使用します。このプロジェクトについては、heat/engine/clients.py ファイルを調べてください。

Ansible は、Python ベースの構成管理ツールです。このツールには、Python API を使用する OpenStack モジュールがいくつかあります。このツールについては、Ansible OpenStack モジュールを格納している library/cloud ディレクトリーを調べてください。

Python API がどのように動作するかをいったん習得すれば、OpenStack 自動化スクリプトを作成する手段として REST API やコマンドライン・ツールを再び使おうとは思わないはずです。

参考文献

学ぶために

製品や技術を入手するために

  • python-keystoneclient: OpenStack Identity API および keystone コマンドライン・ツールです。
  • python-novaclient: OpenStack Compute API および nova コマンドライン・ツールです。
  • python-glanceclient: OpenStack Image API および glance コマンドライン・ツールです。
  • DevStack: 1 台のサーバー上で、OpenStack の開発向けデプロイメントを簡単に行うための bash スクリプトです。
  • 拡張 Python インタープリターである bpython をダウンロードしてください。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Cloud computing
ArticleID=946489
ArticleTitle=Python API: OpenStack のとっておきの秘密
publish-date=09262013