クリスマスの夜はOpenStackをPythonワンライナーでキメる(第1夜)
みなさんめりーくりすます!
この記事は、OpenStack Advent Calendar 2014の12/25の記事です。
日本OpenStackユーザ会のAdvent Calendarでは、第1回からクリスマス(またはイヴ)の夜はOpenStackをワンライナーで操作するという伝統芸をお送りしています。 2014年は4部くらいの構成でお送りする予定で、今日は、その第1夜です(今日は、まだワンライナーじゃないよ)
※決して2013年のワンライナーを解読するのに時間がかかって、締切に間に合わなそうだから、苦しまぎれに4回構成にしたってわけではありません
目標
今回の目標は、ワンライナーで仮想マシンのリストを取得するまでです。毎年こんなんですが、、、
PythonのプログラムからOpenStackを操作する方法
ぼくも、正直普段は1の方法で利用しています。2の方法をとるのは、毎年このAdvent Calendarを書くときだけです(^^;
方法1. OpenStackのPythonクライアントライブラリを利用する
方法2. 直接REST APIを叩く
REST APIを利用するためのドキュメント
以下のドキュメント(本当によく書いてあるなぁ)を参考に実装していきます。
- OpenStack API Complete Reference
- OpenStack API クイックスタート
- Identity API v2.0 (STABLE)
- Compute API v2 (CURRENT)
普通に書いてみる
python-novaclientを利用しない時点で、すでにあまり普通ではないのですが、まぁ普通に書いてみます。
novaが管理する仮想マシンのリストを取得する手順
OpenStackのREST APIを利用します。基本的にPythonが標準で提供しているライブラリのみで乗り切ります。
1. keystoneに認証してもらってトークンIDとサービスカタログを取得する
サービスカタログには、コンポーネントのエンドポイントURLが - POSTメソッド - URL: $OS_AUTH_URL/tokens - ヘッダ
Content-Type: application/json Accept: application/json
- リクエスト(JSON形式)
{ "auth": { "tenantName": $OS_TENANT_NAME, "passwordCredentials": { "username": $OS_USERNAME, "password": $OS_PASSWORD } } }
- レスポンス
{ "access": { "token": { ... 省略 ... "id": "aaaaa-bbbbb-ccccc-dddd", <-取得したトークンのID "tenant": { ... 省略 ... "id": "fc394f2ab2df4114bde39905f800dc57", <-取得したテナントID "name": $OS_TENANT_NAME } }, ... 省略 ... } }
2. keystoneからテナントIDを取得する
- GETメソッド
- URL: $OS_AUTH_URL/tenants
- ヘッダ
Content-Type: application/json Accept: application/json X-Auth-Token: トークンID <-1.で取得したトークンID
- レスポンス(JSON形式)
{ "tenants": [ { "id": テナントID, "name": "tenant-A", ...省略... }, { "id": テナントID, "name": "tenant-B", ...省略... } ], "tenants_links": [] }
3. リージョン名とテナントIDからエンドポイントURLを特定する
$OS_REGION_NAMEと2.で取得したテナントIDを利用して1.で取得したサービスカタログから、nova APIのエンドポイントURLを特定します。
4. novaから仮想マシンのリストを取得する
- GETメソッド
- URL: novaAPIのエンドポイントURL/servers
- ヘッダ
Content-Type: application/json Accept: application/json X-Auth-Token: トークンID <-1.で取得したトークンID
- レスポンス(JSON形式)
だーーーーっとJSON形式で構造化された仮想マシン情報
ソースコード(nova_list.py)
python-novaclientを使わないと、おそろしくめんどくさい...
#!/usr/bin/env python import json import re import urllib import urllib2 from os import environ as env def throw_post(url, body, header): request = urllib2.Request(url=url, data=json.dumps(body), headers=header) return json.loads(urllib2.urlopen(request).read()) def throw_get(url, header): request = urllib2.Request(url=url, headers=header) return json.loads(urllib2.urlopen(request).read()) def main(): os_auth_url = env.get('OS_AUTH_URL').rstrip('/') os_user = env.get('OS_USERNAME') os_passwd = env.get('OS_PASSWORD') os_region = env.get('OS_REGION_NAME') os_tenant = env.get('OS_TENANT_NAME') header = { 'Content-Type': 'application/json', 'Accept': 'application/json', } # # get auth-token and catalog info # auth_header = header.copy() api_tokens_url = os_auth_url + '/tokens' auth_body = dict(auth=dict(tenantName=os_tenant, passwordCredentials=dict(username=os_user, password=os_passwd))) auth_response = throw_post(api_tokens_url, auth_body, auth_header) token_info = auth_response['access']['token'] catalog_info = auth_response['access']['serviceCatalog'] # # get tenant-id # tenant_header = header.copy() api_tenants_url = os_auth_url + '/tenants' tenant_header['X-Auth-Token'] = token_info['id'] tenant_response = throw_get(api_tenants_url, tenant_header) for i in tenant_response['tenants']: if i['name'] == os_tenant: tenant_id = i['id'] # # get endpoint-url # for i in catalog_info: if i['type'] == 'compute': for j in i['endpoints']: if j['region'] == os_region and j['tenantId'] == tenant_id: os_nova_url = j['publicURL'] # # get instance list # servers_header = header.copy() servers_header['X-Auth-Token'] = token_info['id'] api_servers_url = os_nova_url + '/servers' servers_response = throw_get(api_servers_url, servers_header) for i in servers_response['servers']: print '%s %s' % (i['id'], i['name']) if __name__ == '__main__': # usage: python nova_list.py # description: get instance-list such as "nova list" main() # # [EOF] #
実行してみる
ちゃんとリストは取得できますね。
$ python nova_list.py 4f0a63bb-f79e-4850-ad5f-3156d677940b test-vm00 a4ca06c9-aff5-4363-b5aa-7a85eb18500c test-vm01 6e7c2192-253c-4b6d-94b4-f1ada8a993d8 test-vm02 213299ca-1c13-4b5e-8ce6-bbb30758f340 test-vm03
明日からが本番だぜ!
明日からは、この普通のコードをワンライナーに直して行く予定です。 あんまり期待しないでまっててね。今年のOpenStackのアドカレは、まだまだおわらないぜ!