OpenStack API 実装例

curl 使用

まずは OpenStack の環境変数を読み込む。

source ~/overcloudrc

次にユーザ名とパスワード、ドメイン名を指定し、トークンを取得する。
keystone で v2 を使用しているか v3 を使用しているかによって トークンの表示位置が変更するので注意が必要。
今回は、keysotne v3 を前提にしている。

token=$(curl -i -s -X POST -H 'Content-Type: application/json' \
-d '{"auth": {"identity": {"methods": ["'${OS_AUTH_TYPE}'"], "password": {"user": {"name": "'${OS_USERNAME}'", "password": "'${OS_PASSWORD}'", "domain": {"name": "'${OS_PROJECT_DOMAIN_NAME}'"}}}}, "scope": {"project": {"name": "'${OS_PROJECT_NAME}'", "domain": {"name": "'${OS_PROJECT_DOMAIN_NAME}'"}}}}}' \
${OS_AUTH_URL}/auth/tokens?nocatalog | grep "X-Subject-Token" | cut -d" " -f2)

あとは、先ほど取得したトークンを “X-Auth-Token” にセットして、API を発行すれば OK。

curl -i -s -X PUT ${nova_endpoint}/${project_id}/os-services/force-down \
-H "Content-Type: application/json" \
-H "Accept: application/json " \
-H "X-OpenStack-Nova-API-Version: 2.11" \
-H "X-Auth-Token: ${token}" \
-d '{"binary": "nova-compute", "host": "'${target}'", "forced_down": '${forcedown}'}'

コード全文は以下の通りとなる。

function help() {
echo "usage: ${0##*/} <target> <action>"
echo "usage: ${0##*/} [--help]"
echo ""
echo "Positional arguments:"
echo " <target> Computer name that you want to do force-down."
echo " <action> true(set force-down) or false(unset force-down)"
echo ""
echo "Optional arguments:"
echo " --help Display help menu."
}

while getopts ":vh-:" opt; do
case "$opt" in
-)
case "${OPTARG}" in
help)
help
exit 0
;;
esac
;;
esac
done

if [ $# -ne 2 ]; then
help
echo ""
echo "[ERROR] Set the correct number of arguments. (require: 2, input: $#)"
exit 1
else
target=$1

case "$2" in
"true" | "false" )
forcedown=$2
;;
* )
help
echo ""
echo "[ERROR] Please set 'true' or 'false' as 2nd arguments."
exit 1
;;
esac
fi

source ~/overcloudrc

project_id=`openstack project list | grep " ${OS_PROJECT_NAME} " | cut -d" " -f2`
nova_endpoint=`openstack endpoint list | grep " compute " | grep " public " | cut -d"|" -f8 | sed -e "s/ //g"`

token=$(curl -i -s -X POST -H 'Content-Type: application/json' -d '{"auth": {"identity": {"methods": ["'${OS_AUTH_TYPE}'"], "password": {"user": {"name": "'${OS_USERNAME}'", "password": "'${OS_PASSWORD}'", "domain": {"name": "'${OS_PROJECT_DOMAIN_NAME}'"}}}}, "scope": {"project": {"name": "'${OS_PROJECT_NAME}'", "domain": {"name": "'${OS_PROJECT_DOMAIN_NAME}'"}}}}}' ${OS_AUTH_URL}/auth/tokens?nocatalog | grep "X-Subject-Token" | cut -d" " -f2)
token=`echo ${token} | sed -e "s/[\r\n]\+//g"`

curl -i -s -X PUT ${nova_endpoint}/${project_id}/os-services/force-down -H "Content-Type: application/json" -H "Accept: application/json " -H "X-OpenStack-Nova-API-Version: 2.11" -H "X-Auth-Token: ${token}" -d '{"binary": "nova-compute", "host": "'${target}'", "forced_down": '${forcedown}'}' >/dev/null
if [ $? -eq 0 ]; then
echo "[INFO] force-down was finished successfully"
else
echo "[ERROR] force-down was failed."
fi

nova hypervisor-list

実行すると以下のように出力される。

$ ./api_nova_forcedown.sh --help
usage: api_nova_forcedown.sh <target> <action>
usage: api_nova_forcedown.sh [--help]

Positional arguments:
<target> Computer name that you want to do force-down.
<action> true(set force-down) or false(unset force-down)

Optional arguments:
--help Display help menu.
$ sh ./api_nova_forcedown.sh jfc-cmp01.nttdata.co.jp true
[INFO] force-down was finished successfully
+--------------------------------------+-------------------------+-------+---------+
| ID | Hypervisor hostname | State | Status |
+--------------------------------------+-------------------------+-------+---------+
| 1ff4b167-87c0-409b-87e9-298be57c6e11 | jfc-cmp02.nttdata.co.jp | up | enabled |
| d40ee745-18e6-43f6-b605-04ac6bb32972 | jfc-cmp01.nttdata.co.jp | down | enabled |
+--------------------------------------+-------------------------+-------+---------+
$ sh ./api_nova_forcedown.sh jfc-cmp01.nttdata.co.jp false
[INFO] force-down was finished successfully
+--------------------------------------+-------------------------+-------+---------+
| ID | Hypervisor hostname | State | Status |
+--------------------------------------+-------------------------+-------+---------+
| 1ff4b167-87c0-409b-87e9-298be57c6e11 | jfc-cmp02.nttdata.co.jp | up | enabled |
| d40ee745-18e6-43f6-b605-04ac6bb32972 | jfc-cmp01.nttdata.co.jp | up | enabled |
+--------------------------------------+-------------------------+-------+---------+

Python SDK 使用

curl を使用するケースと同様、こちらも keystone v2 と v3 で実装が若干異なってくるが、今回は v3 を前提に話を進める。

まずは OpenStack の環境変数を読み込む。

source ~/overcloudrc

次に認証情報をもとにセッションを確立する。

v3_auth = v3.Password(auth_url=os_auth_url,
username=os.environ['OS_USERNAME'],
password=os.environ['OS_PASSWORD'],
project_name=os.environ['OS_PROJECT_NAME'],
project_domain_name=os.environ['OS_PROJECT_DOMAIN_NAME'],
user_domain_name=os.environ['OS_USER_DOMAIN_NAME'])

sess = session.Session(auth=v3_auth, verify=False)

Nova API を使用する場合、最初に Nova Client のインスタンスを生成する。

import novaclient.client
n_sess = novaclient.client.Client(2, session=sess)

任意の Nova API を実行し、結果を “result” に格納する。

result = n_sess.servers.list()

最後に “result” の値を出力する。

for r in result:
print r.id, r.name;

コード全文は以下の通り。

import os
import logging

from keystoneauth1.identity import v3
from keystoneauth1 import session

import requests

class Sample:
def __init__(self):
requests.packages.urllib3.disable_warnings()
logging.basicConfig(level=logging.INFO)
self.logger = logging.getLogger(__name__)

def authorization(self):
if os.environ.get('http_proxy') or os.environ.get('https_proxy'):
self.logger.WARN("Proxy env vars set")

os_auth_url = os.environ['OS_AUTH_URL']
os_auth_url = os_auth_url.replace('v2.0', 'v3')

if not os_auth_url.endswith('v3'):
os_auth_url += '/v3'

v3_auth = v3.Password(auth_url=os_auth_url,
username=os.environ['OS_USERNAME'],
password=os.environ['OS_PASSWORD'],
project_name=os.environ['OS_PROJECT_NAME'],
project_domain_name=os.environ['OS_PROJECT_DOMAIN_NAME'],
user_domain_name=os.environ['OS_USER_DOMAIN_NAME'])

k_sess = session.Session(auth=v3_auth, verify=False)
return k_sess

def nova_sess(self):
import novaclient.client
sess = self.authorization()
n_sess = novaclient.client.Client(2, session=sess)
return n_sess

def nova_list(self):
n_sess = self.nova_sess()
result = n_sess.servers.list()
for r in result:
print r.id, r.name;

def neutron_sess(self):
import neutronclient.neutron.client
sess = self.authorization()
q_sess = neutronclient.neutron.client.Client('2.0', session=sess)
return q_sess

def neutron_list(self):
q_sess = self.neutron_sess()
result = q_sess.list_networks()['networks']
for r in result:
for k, v in r.items():
print("%s : %s" % (k, v))
print('\n')


s = Sample()
s.nova_list()
s.neutron_list()

実行すると以下の通り出力される。

03116438-bd19-4452-8339-cd992c50d156 jfc-cmp02
988877da-17eb-4a07-a610-ccab64eac23a jfc-ctr01
71d4cc92-9ab4-4678-bd53-b2c03ebe943e jfc-ctr02
09ae722c-8e05-4a02-ad86-dbe7b2232775 jfc-cmp01
3a416f50-9ea2-48f5-9168-447cda1c4f15 jfc-ctr03
provider:physical_network : ctlplane
ipv6_address_scope : None
revision_number : 8
port_security_enabled : True
provider:network_type : flat
id : 515ab5ab-e73c-428b-b145-4f9b89fac431
router:external : False
availability_zone_hints : []
availability_zones : [u'nova']
ipv4_address_scope : None
shared : False
project_id : ebe0a369198a4b92b0f294ef22386756
l2_adjacency : True
status : ACTIVE
subnets : [u'a2509cf3-fb5e-4714-8820-1b94283ccdf7']
description :
tags : []
updated_at : 2018-07-27T10:47:42Z
provider:segmentation_id : None
name : ctlplane
admin_state_up : True
tenant_id : ebe0a369198a4b92b0f294ef22386756
created_at : 2018-07-27T07:37:22Z
mtu : 1500


provider:physical_network : external
ipv6_address_scope : None
revision_number : 3
port_security_enabled : True
provider:network_type : flat
id : 91c89b6a-2d44-4489-86f9-992c9017cfe0
router:external : False
availability_zone_hints : []
availability_zones : []
ipv4_address_scope : None
shared : False
project_id : ebe0a369198a4b92b0f294ef22386756
l2_adjacency : True
status : ACTIVE
subnets : [u'f2bd3531-fb6a-49a4-b63d-d531f8575f2d']
description :
tags : []
updated_at : 2018-07-30T12:34:27Z
provider:segmentation_id : None
name : external
admin_state_up : False
tenant_id : ebe0a369198a4b92b0f294ef22386756
created_at : 2018-07-30T12:34:26Z
mtu : 1500
...