Edited at
ConoHaDay 20

php-opencloudでConoHa APIを使う

More than 3 years have passed since last update.

この記事は「ConoHa Advent Calendar2015」の20日目の記事です。

19日目は@wakadannacomさんの「ConoHaにNutanix CEがインストールできるか検討だけしてみた」

21日目は@keita299さんの「ConoHa の メール API でアドレスの登録・一覧・削除をする。」

でした。


こんにちは、ひろのぶです( ´ ω ` )

先日Twitterでこんな発言をしてしまったので、ちょっとフォローアップなどを兼ねて、php-opencloudの導入編を書いてみたいと思います。基本的に本家のドキュメントに沿っていますので、自分で読んで実装できてしまう方は読む必要ないかもです。


PHPでConoHa APIを使う

ConoHa APIはOpenStack + αな構成となっていて、要は単純なREST APIです。

ConoHa APIドキュメント

PHPはとにかくHTTPアクセスが簡単にできるので、SDKを用いなくてもAPI叩くのは簡単です。こういうの、ある意味すごい・・・。

$body = file_get_contents('http://example.com/');

そして、ConoHa API(OpenStack APIも)は以下のようなワークフローになります。各サービス(Compute, Network, Storageなど)にアクセスする前にIdentityを使って認証を済ませ、トークンをあらかじめ取得しておく必要があります。そしてトークンは有効期限があり、その間はキャッシュして置いた方が効率よくAPIにアクセスできます。(詳しくは以下のスライド15ページを参照)

パブリッククラウドConoHaを使ってOpenStack APIを理解する

SDKはこの辺のワークフローをうまく抽象化してくれます。トークンのキャッシュはある程度自分で書かないといけませんが、まぁそれでも簡単に書けます。


php-opencloud

php-opencloudはRackspaceが開発しているPHPのOpenStack SDKです。RackspaceはOpenStackベースのパブリッククラウドを展開している企業ですが、もともとOpenStackプロジェクトもRackspaceによって始められたものです。

Rackspace APIはOpenStackを拡張したもので、php-opencloudもそれに対応したライブラリです。ですが、php-opencloudはその拡張部分を除いたピュアなOpenStackを扱うためのクラスも用意されています。オフィシャルのドキュメントは基本的にRackspace向けになっているので、読むときはその辺に注意する必要があります。

php-opencloud

php-opencloud(GitHub)

Rackspaceは個人でも使えるので、ConoHa以外のOpenStack環境を触ってみたい方は使ってみると良いと思います。(ちなみにアカウント作成すると英語で確認の電話がかかってきます。私は知らなかったのでアワアワしてしまいましたが、向こうのオペレーターもそういうの慣れてるようなので何とかなりました・・・)


使ってみる

では使ってみましょう。php-opencloudはPHP5.4以上とcomposerが必要です。VPSなどでPHP環境を立てても良いのですが、今回はDockerでさくっとPHP環境を作りました。

mkdir php-opencloud && cd php-opencloud

docker pull php.5.6
docker run -v `pwd`:/php-opencloud -ti --rm --name php56 php:5.6 /bin/bash

コンテナに入ったらgitを追加でインストールしておきます

apt-get update

apt-get install -y git

そしてcomposerとphp-opencloudをインストールします

cd php-opencloud

curl -sS https://getcomposer.org/installer | php
./composer.phar require rackspace/php-opencloud
(結構時間かかる)
ls -la
total 1240
drwxrwxr-x 3 1000 1000 4096 Dec 23 05:49 .
drwxr-xr-x 53 root root 4096 Dec 23 05:47 ..
-rw-r--r-- 1 root root 70 Dec 23 05:47 composer.json
-rw-r--r-- 1 root root 11253 Dec 23 05:49 composer.lock
-rwxr-xr-x 1 root root 1238152 Dec 23 05:42 composer.phar
drwxr-xr-x 8 root root 4096 Dec 23 05:49 vendor

あとは、このディレクトリでスクリプトを書いていきます。


基本的なこと

本家ドキュメントにはRackspace setupとOpenStack setupと2つの方法が載っています。先ほど書いたとおり、php-opencloudは基本的にRackspace向けだからです。

ConoHaで使う場合は後者のOpenStack setupの内容で進めます。使うのはOpenStack\OpenStackで、あとは名前空間をuseしてOpenStackクラスをnewすればOKです。典型的な書き方は以下のようになります。

<?php

use OpenCloud\OpenStack;
use Guzzle\Http\Exception\ClientErrorResponseException;

require_once __DIR__ . '/vendor/autoload.php';

$opts = [
'username' => 'gncu********',
'password' => 'password',
'tenantName' => 'gnct*******',
];

try {
$client = new OpenStack('https://identity.tyo1.conoha.io/v2.0', $opts);
$client->authenticate();

// ここに実装を書く

} catch(ClientErrorResponseException $ex) {
// error
echo $ex->getMessage();
}

$optsにはAPIな認証情報を書きます。これはConoHaのコントロールパネルの「API」メニューにあります。


サービスを使う

先ほどのコードで$clientはあくまでREST APIを扱うためのクライアントなだけで、Compute, Network, Storageなどはまた別のオブジェクトになります。これらサービスの一覧(Catalog)を取得してみましょう。先ほどのコードの「ここに実装を書く」に下記を実装します。

<?php

$catalog = $client->getCatalog();
foreach($catalog->getItems() as $item) {
foreach($item->getEndpoints() as $endpoint) {
echo sprintf("name:%s type:%s region:%s url:%s\n",
$item->getName(),
$item->getType(),
$endpoint->region,
$endpoint->publicURL);
}
}

実行結果は以下のようになります(伏せ字の部分はTenantIDでユーザ毎に異なります)。このnameとtypeに注目して下さい。それぞれのサービスを使うにはこれらを指定してサービスオブジェクトを取得します。

name:Account Service type:account region:tyo1 url:https://account.tyo1.conoha.io/v1/****************************

name:Database Hosting Service type:databasehosting region:tyo1 url:https://database-hosting.tyo1.conoha.io/v1
name:Network Service type:network region:tyo1 url:https://networking.tyo1.conoha.io
name:Volume Service type:volumev2 region:tyo1 url:https://block-storage.tyo1.conoha.io/v2/****************************
name:Image Service type:image region:tyo1 url:https://image-service.tyo1.conoha.io
name:Compute Service type:compute region:tyo1 url:https://compute.tyo1.conoha.io/v2/****************************
name:Mail Hosting Service type:mailhosting region:tyo1 url:https://mail-hosting.tyo1.conoha.io/v1
name:DNS Service type:dns region:tyo1 url:https://dns-service.tyo1.conoha.io
name:Object Storage Service type:object-store region:tyo1 url:https://object-storage.tyo1.conoha.io/v1/nc_****************************
name:Identity Service type:identity region:sjc1 url:https://identity.sjc1.conoha.io/v2.0
name:Identity Service type:identity region:tyo1 url:https://identity.tyo1.conoha.io/v2.0
name:Identity Service type:identity region:sin1 url:https://identity.sin1.conoha.io/v2.0


Compute Serviceを使う

サービスは色々あるのですが、わかりやすいところでComputeを使ってVPSを立ててみましょう(APIの説明するときの定番ですが)。Compute Serviceは、OpenStackの仮想マシンを扱うサービスで、ConoHaではVPSを扱うことになります。なお、ここで紹介する機能は一部で、詳細は本家のドキュメントをご覧下さい。

サービスオブジェクトは以下のように取得します。引数にnameとregionを渡します。サービスに対して何か実行する場合は全てこの$computeを介して行います。

$compute = $client->computeService('Compute Service', 'tyo1');


flavorを取得してみる

OpenStackでflavorというのは仮想マシンの定義を表します。CPUコア数、メモリ、ストレージなどですね。ConoHaではVPSのプランを指します。

以下のコードを先ほどの「ここに実装を書く」のところに挿入します。これだけです、SDKの便利なところですね。

<?php

$compute = $client->computeService('Compute Service', 'tyo1');
foreach($compute->flavorList() as $img) {
echo sprintf("id:%s name:%s\n", $img->id, $img->name);
}

実行結果は以下です。

id:294639c7-72ba-43a5-8ff2-513c8995b869 name:g-2gb

id:3aa001cd-95b6-46c9-a91e-e62d6f7f06a3 name:g-16gb
id:62e8fb4b-6a26-46cd-be13-e5bbf5614d15 name:g-4gb
id:7eea7469-0d85-4f82-8050-6ae742394681 name:g-1gb
id:965affd4-d9e8-4ffb-b9a9-624d63e2d83f name:g-8gb
id:a20905c6-3733-46c4-81cc-458c7dca1bae name:g-32gb
id:c2a97b05-1b4b-4038-bbcb-343201659279 name:g-64gb


イメージ一覧を取得してみる

「イメージ」はOpenStackでは仮想マシンのディスクイメージのことで、ConoHaではOSのイメージやアプリケーションインストール済みイメージなど色々用意されています。基本的にflavorとメソッドが違うだけで同じような感じになります。

コード的には以下のようになります。flavorとメソッドが違うだけです。

<?php

foreach($compute->imageList() as $img) {
echo sprintf("id:%s name:%s\n", $img->id, $img->name);
}

実行結果は以下です

id:8f19ff24-3ff9-4beb-9603-d67dead1fc00 name:vmi-wp-kusanagi-centos-7

id:edf80c2c-fdf7-45ee-b625-9e18d40cedc6 name:vmi-zabbix-2.4-centos-7
id:e090aed7-5949-45ec-93f0-e735d8d0d29e name:s-abe-master
id:6b3a81fa-9ca1-4fb3-b000-e1495620a119 name:vmi-piwik-2.15-centos-6.7
id:7cab9247-1253-4bfd-8e4d-026fcd9168e3 name:vmi-drupal-8.0-centos-7
id:9f89b30b-09a4-4606-b27a-c33794559d51 name:ubuntu14-clean
id:238801ae-7256-453c-9133-5202aa39a621 name:vmi-opensuse-42.1-amd64
(以下略)


仮想マシン(VM)を作成する

では仮想マシンを作ってみます。ここはちょっと一手間必要になります。

VM作成APIにはsecurity_groupsとadminPassという言うオプションがあるのですが、php-opencloudはこれらのパラメータに対応していません。なので、ここはphp-opencloudのOpenStack\Compute\Resource\Serverを継承したクラスを作成し、APIへのリクエストJSONに2つのパラメータを追加する必要があります。

継承したクラスは以下のようになります。プロパティを追加して、createJSON()をオーバーライドしてJSONオブジェクトにパラメータを追加します。adminPassは元のクラスにプロパティ定義はあるのですが、createJson()内では使用されていません。これはバグっぽいですね。

class ConoHa extends Server {

protected $security_groups = [];

protected function createJson() {
$server = parent::createJson();

// adminPass
if($this->getProperty('adminPass') != null) {
$server->server->adminPass = $this->getProperty('adminPass');
}

// security_groups
$security_groups = $this->getProperty('security_groups');
if (count($security_groups) > 0) {
$server->server->security_groups = $security_groups;
}
return $server;
}
}

実際にVMを作成する部分のコードは以下です。ConoHaオブジェクトを作ってcreate()を呼びます。引数はVM作成のオプションで、一覧はドキュメントにあります。他によく使いそうなものでkeypairと言うオプションがあり、VMに設定するSSH公開鍵を指定するときに使います。

コード全文は長くなるのでGistに置いてあります。


$compute = $client->computeService('Compute Service', 'tyo1');
try {
// ConoHaクラスを使わない場合は以下のようになる
// $server = $compute->server()

$server = new ConoHa($compute);

$create_opts = [
'name' => 'test-vps',
'imageId' => 'edc9457e-e4a8-4974-8217-c254d215b460',
'flavorId' => '7eea7469-0d85-4f82-8050-6ae742394681',
'adminPass' => '***********',
"security_groups" => [
[
"name" => "default",
],
[
"name" => "gncs-ipv4-all",
],
[
"name" => "gncs-ipv6-all",
]
],
];
$resp = $server->create($create_opts);

} catch(BadResponseException $ex) {
echo $ex->getResponse();
}


トークンをキャッシュする

OpenStack APIは認証実行後にトークンが発行され、サービスにアクセスする際にそれが使われることは既に書きました。このトークンをファイルなどに書き出しておいて、2回目以降スクリプトを実行した際に使い回すことで認証をスキップすることができます。

OpenStackオブジェクト$clientにはexportCredentials()とimportCredentials()という2つのメソッドがあります。exportCredentials()はトークンを含む認証情報を書き出し、importCredentials()はその認証情報を読み込むときに使います。importCredentials()で読み込んだ認証情報が無効(トークンの有効期限切れなど)だった場合でも、SDKが自動的に再認証を行ってくれます。便利。

さて、実際にコードは以下のようになります。認証情報はPHPのstdClassなので、これをserialize()してファイルに書き出します。

$opts = [

'username' => 'gncu********',
'password' => 'password',
'tenantName' => 'gnct*******',
];

$client = new OpenStack('https://identity.tyo1.conoha.io/v2.0', $opts);

$cachefile = 'credentials.dat';
if (file_exists($cachefile)) {
$str_credential = file_get_contents($cachefile);
$credentials = unserialize($str_credential);
if($credentials) {
$client->importCredentials($credentials);
}
}

$token = $client->getTokenObject();
if(!$token || $token->hasExpired()) {
$client->authenticate();
file_put_contents($cachefile, serialize($client->exportCredentials()));
}


オブジェクトストレージを使う

そういえば昔このべんに書いたので、よかったらこちらもご覧下さい。認証部分は旧ConoHa向けの説明になっていますが、それ以外はそのまま使えます。

ConoHaオブジェクトストレージを使ってみよう(SDK+応用編)


おわりに

REST APIをそのまま叩いても良いのですが、SDKを使うとだいぶ楽できるのでどんどん使うと良いと思います(VM作成はちょっと大変でしたが、、、)。ただ、php-opencloudとConoHa API両方のドキュメントと睨めっこしながら作業するような感じになるので、まぁこれは頑張るしかないかなと。

PHPは利用者も多いですし、このドキュメントがお役に立ったら何よりです( ´ ω ` )