GMOインターネットが提供するVPSサービス「ConoHa」のAPIを使って、オリジナルコマンドを使ったサーバー管理方法を3回に渡ってレポートします。Vol.1では、APIを利用するメリットや利用方法をご紹介します。
ConoHaのAPI
ConoHaはGMOインターネットが提供するVPSサービスです。初期費用無しでひと月630円から使えます。現時点では残念ながらWindowsはありませんが、豊富なテンプレートイメージと高速SSDで快適サーバーがすぐに利用できるサービスです。
https://www.conoha.jp/
VPSサービス「ConoHa byGMO」
ConoHaのサービス管理はWebで提供されているコントロールパネルから行いますが、独自のプログラムから制御もできるようにAPIが公開されています。
ConoHaのREST API情報
ConoHaのAPIはHTTPSベースのREST APIとなっており、指定されたURL対して、GETやPOSTのリクエストを送ることによってデータのやりとりを行い、利用することができます。実行結果はJSON形式で成形されたデータを受け取ることになります。今回作成するPowerShellのコマンドは、このRESTAPIを利用して作り込んでいきます。
PowrShellからAPIを利用するメリット
ConoHaのAPIを利用した場合、結果はすべてJSON形式の文字列として返されることになります。プログラムではこのJSONの文字列を解析して目的の情報を取り出す必要があります。また、取り出した情報も単純な文字列となりますので、これらを使ってなにかアクションをと考えた場合、さらに一工夫が必要となります。PowerShellでは、JSON形式のデータを自動的に解析してオブジェクトとして扱えるPSCustomObjectという便利な機能が用意されています。
例えば、仮想マシン情報をPowerShellからAPIを利用して取得した場合、JSONデータを受け取ると、動的なオブジェクトとしてきちんと分類した状態で格納し、その属性として仮想マシン名や状態、メモリの容量などきちんと名前付された値として取り扱うことができるようになります。オブジェクトとして扱えることで、変数に格納したり、汎用的なPowerShellのコマンドをそのまま利用することも可能となるので、開発効率が格段にアップします。PowerShellはWindowsに標準で搭載されているシェル&開発言語で、PowerShell ISEというエディタツールもあらかじめインストールされているので、手軽に開発をはじめることができます。
例:ConoHa上の稼働中サーバーを全て停止するコマンドを一行で実行。
Get-cVM | ? State -eq "Active" | Stop-cVM
APIを利用するには
まずはサービスの申し込みが必要です。ConoHaのTopページ(https://www.conoha.jp/)より申し込みを行っておきましょう。サービスの申し込みが完了すると、コントロールパネルにログインできるようになります。ConoHaのAPIを利用するには、コントロールパネルにログインするためのユーザーアカウントとは別に、APIユーザーの登録が必要です。
まずはAPIユーザーを追加しておきましょう。コントロールパネルの左メニューから「API」を選択し、「追加」ボタンをクリックします。
コントロールパネルからAPIを選択
APIユーザーのパスワードを設定して「保存」ボタンをクリックします。
APIユーザーパスワードを設定
ユーザー名は自動的に割り当てられます。APIのユーザー登録が完了したら、テナント情報のプルダウンを開いてテナントIDとテナント名を確認します。テナント名はAPIのユーザー名と同一になっています。これらの情報はREST APIを利用する時に必要となります。
テナント情報の確認
APIは利用する機能やリージョン(データーセンターの場所)ごとにエンドポイント(URL)が異なります。コード内ではこのエンドポイントを利用することになりますので確認しておきましょう。
エンドポイント情報
ConoHaのAPIの利用方法は、ConoHa API Documentationに記載されています。リクエストデータを送信するURLや必要なパラメーター、Linuxのcurlコマンドで実行する場合のサンプルコードなどが記載されています。PowerShellから利用する場合にも、同様の情報が必要となりますのでこちらを参考にコマンドを作成していきます。
ConoHa API Documantation
オリジナルコマンドの作成:Invoke-RestMethodの使い方
今回作成するサンプルコード
$apiUser = "gncu12345678"
$password = "paSSword123456#$%"
$tenantId = "487727e3921d44e3bfe7ebb337bf085e"
$script:token = ""
Function Get-cTokenHeader(){
$body = '{"auth":{"passwordCredentials":{"username":"' + $apiUser + '","password":"' + $password+'"},"tenantId":"' + $tenantId+'"}}'
$tokenUrl = "https://identity.tyo1.conoha.io/v2.0/tokens"
If($script:token){
$expiresTime = Get-Date -Date $script:token.access.token.expires
If ($expiresTime -lt (Get-Date)){
$script:token = Invoke-RestMethod $tokenUrl -Method POST -Body $body
}
}Else{
$script:token = Invoke-RestMethod $tokenUrl -Method POST -Body $body
}
$tokenId = $script:token.access.token.id
Return @{"X-Auth-Token" = $tokenId}
}
Function Get-cVM(){
Param(
$Name
)
$tokenHeader = Get-cTokenHeader
$requestUrl = "https://compute.tyo1.conoha.io/v2/$tenantId/servers/detail"
$result = Invoke-RestMethod $requestUrl -Headers $tokenHeader -Method GET
$servers = $result.servers
$objAry = @()
ForEach($server in $servers){
$id = $server.id
$tagName = $server.metadata.instance_name_tag
$state = $server.status
$flavorId = $server.flavor.id
$flavor = Get-cFlavor $flavorId
$vcpu = $flavor.vcpus
$ram = $flavor.ram / 1024
$disk = $flavor.disk
$ip = ($server.addresses.($server.addresses.PSObject.Properties.name) | ? version -eq 4).addr
$objPs = New-Object PSCustomObject
$objPs | Add-Member -NotePropertyMembers @{ID = $id}
$objPs | Add-Member -NotePropertyMembers @{Name = $tagName}
$objPs | Add-Member -NotePropertyMembers @{State = $state}
$objPs | Add-Member -NotePropertyMembers @{vCPU = $vcpu}
$objPs | Add-Member -NotePropertyMembers @{Disk = $disk}
$objPs | Add-Member -NotePropertyMembers @{Memory = $ram}
$objPs | Add-Member -NotePropertyMembers @{IPAddress = $ip}
$objAry += ($objPs | Select-Object ID, Name, State, Memory, Disk, vCPU, IPAddress)
}
$VM = $objAry
If($Name -ne $null){
$VM = $VM | ? Name -eq $Name
}
If($VM -eq $null){
Write-Host ("""$Name"" という名前の仮想マシンが見つかりません。") -ForegroundColor Red
}Else{
Return $VM
}
}
Function Get-cFlavor($flavorId){
$tokenHeader = Get-cTokenHeader
$requestUrl = "https://compute.tyo1.conoha.io/v2/$tenantId/flavors/$flavorId"
$result = Invoke-RestMethod $requestUrl -Headers $tokenHeader -Method GET
Return $result.flavor
}
PowerShellには、REST APIを利用する場合に最適なコマンド「Invoke-RestMethod」が用意されています。コマンドの引数にURLとメソッド(POST、GET)を指定して、送信Dataを指定するだけで、APIからの情報を取得することができます。さらに、JSON形式のデータを自動的にPSCustomObjectに格納してくれるので、JSONの文字列データを解析して目的の情報を取り出すといった文字列操作は必要ありません。
簡単な例として、ConoHaのバージョン情報を取得してみましょう。
リクエストURLは「https://identity.tyo1.conoha.io/v2.0」、メソッドは「POST」となります。Invoke-RestMethodコマンドで実行するとこのようになります。
PS C:\> Invoke-RestMethod "https://identity.tyo1.conoha.io/v2.0" -Method GETversion-------@{status=stable; updated=2015-05-12T09:00:00Z; media-types=System.Object[]; id=v2.0; links=System.Object[]}
実行結果として「version」という見出しの配列(@{〇〇〇})文字列が表示されています。文字列のように見えますが、すでにPSCustomObjectとして格納されている状態です。
実行結果を$resという変数に格納して、プロパティー値として、「version.id」を表示してみましょう。バージョン情報が取得できました。
PS C:\> $res = Invoke-RestMethod "https://identity.tyo1.conoha.io/v2.0" -Method GET$res.version.idv2.0
APIの実行結果は、元々はJSON形式のデータで送られてきています。JSON形式のデータとして表示し、確認してみましょう。ConvertTo-JSONコマンドで実行結果を変換します。
PS C:\> $res = Invoke-RestMethod "https://identity.tyo1.conoha.io/v2.0" -Method GETPS C:\> ConvertTo-JSON $res{ "version": { "status": "stable", "updated": "2015-05-12T09:00:00Z", "media-types": [ "@{base=application/json}", "@{base=application/xml}" ], "id": "v2.0", "links": [ "@{href=https://identity.tyo1.conoha.io/v2.0/; rel=self}", "@{href=https://www.conoha.jp/docs/; type=text/html; rel=describedby}" ] }}
APIの解説ページと同じJSONデータが確認できました。
オリジナルコマンドの作成:トークンの取得
先ほどのバージョン情報を取得する場合では必要ありませんでしたが、ConoHaのAPIを利用する場合には、コマンドにトークンと呼ばれる「認証済み」情報を付加して実行する必要があります。トークンは先ほどコントロールパネルで追加したテナント情報(テナントID、APIユーザー、パスワード)を元にREST APIを利用して発行されます。一度発行されたトークンは24時間の有効期限があり、その間であれば繰り返し利用することが可能です。
APIの解説ページを見てみましょう。
必要な情報としては、
ParameterValueStyleDescriptionusernameユーザー名plainユーザー名passwordユーザーパスワードplainユーザーパスワードtenantId (Optional)Tenant IDplainテナントID
このようになっています。curlコマンドのサンプルコードを見てみましょう。
curl -i -X POST \-H "Accept: application/json" \-d '{"auth":{"passwordCredentials":{"username":"ConoHa","password":"paSSword123456#$%"},"tenantId":"487727e3921d44e3bfe7ebb337bf085e"}}' \https://identity.tyo1.conoha.io/v2.0/tokens
Invoke-RestMethod コマンドで必要となる情報としては、メソッドの”POST”、「-d」の送信する文字列データ、リクエスト先のURLとなります。
送信する文字列データは
'{"auth":{"passwordCredentials":{"username":"<ユーザー名>","password":"<ユーザーパスワード>"},"tenantId":"<テナントID>"}}'
となっています。最後の「\」マークは改行コードなので省略します。
ここまでの情報をInvoke-RestMethodコマンドで置き換えるとこのようになります。
PS C:\> $apiUser = "gncu12345678"$password = "paSSword123456#$%"$tenantId = "487727e3921d44e3bfe7ebb337bf085e"$body = '{"auth":{"passwordCredentials":{"username":"' + $apiUser + '","password":"' + $password+'"},"tenantId":"' + $tenantId+'"}}'$tokenUrl = “https://identity.tyo1.conoha.io/v2.0/tokens”Invoke-RestMethod $tokenUrl -Method POST -Body $body
Invoke-RestMethod $tokenUrl -Method POST -Body $body : Invoke-RestMethodコマンドに各設定値を指定して実行します。
ここまでを実行してみましょう。データが取得できていれば成功です。
access------@{token=; serviceCatalog=System.Object[]; user=; metadata=}
取得したトークン情報で必要となるのが、「access.token.id」(トークンID)の値です。トークンIDは他のAPIの機能を利用する場合に、Invoke-RestMethodコマンドのヘッダー情報「-Header」オプションに「@{"X-Auth-Token" = <トークンID>}」としてIDictionary型で指定することで認証済みのリクエストとして実行可能となります。(参考:IDictionaryはキーと値を1つのペアとしたコレクション変数の型。)
ここまでをGet-cTokenHeaderという名前で1つのコマンドとしてまとめてみましょう。また、他のコマンドでも利用する可能性がある変数は、コマンドのブロック外で共通変数として定義しておきます。
$apiUser = "gncu12345678"
$password = "paSSword123456#$%"
$tenantId = "487727e3921d44e3bfe7ebb337bf085e"
Function Get-cTokenHeader(){
$body = '{"auth":{"passwordCredentials":{"username":"' + $apiUser + '","password":"' + $password+'"},"tenantId":"' + $tenantId+'"}}'
$tokenUrl = “https://identity.tyo1.conoha.io/v2.0/tokens”
$token = Invoke-RestMethod $tokenUrl -Method POST -Body $body
$tokenId = $token.access.token.id
Return @{"X-Auth-Token" = $tokenId}
}
実行結果はこのようになります。トークンIDを含んだIDictionary型のヘッダー情報が作成されていれば成功です。
PS C:\> Get-cTokenHeaderName Value---- -----X-Auth-Token 0643af2d2105456690efad28107ed23d
取得したトークンは24時間の有効期限が設定されています。他のAPIを利用する場合に同じトークンIDが利用可能です。パフォーマンンスアップにもつながるので、トークンを再利用するためのロジックを追加しておきましょう。
$apiUser = "gncu12345678"
$password = "paSSword123456#$%"
$tenantId = "487727e3921d44e3bfe7ebb337bf085e"
$script:token = ""
Function Get-cTokenHeader(){
$body = '{"auth":{"passwordCredentials":{"username":"' + $apiUser + '","password":"' + $password+'"},"tenantId":"' + $tenantId+'"}}'
$tokenUrl = "https://identity.tyo1.conoha.io/v2.0/tokens"
If($script:token){
$expiresTime = Get-Date -Date $script:token.access.token.expires
If ($expiresTime -lt (Get-Date)){
$script:token = Invoke-RestMethod $tokenUrl -Method POST -Body $body
}
}Else{
$script:token = Invoke-RestMethod $tokenUrl -Method POST -Body $body
}
$tokenId = $script:token.access.token.id
Return @{"X-Auth-Token" = $tokenId}
}
1-3:スクリプト共通で利用する定数として定義しておきます。PowerShellではSet-VariableコマンドのConstantオプションで定数を定義できるのですが、ここは簡易的にしています。
4:Get-cTokenHeaderコマンドで取得したトークン情報を格納しておく変数です。スクリプト内で共通に参照するので、「$script:」オプションを付けています。
10 :トークンを格納した変数にトークン情報が入っている場合と、空の場合で分岐します。
11 :トークン情報が入っている場合は、$token.access.token.expire からトークンの有効期限を取得します。
12 :トークンの有効期限が終了していた場合は、トークン情報を再取得します。
15 :トークン情報が空の場合は、トークン情報を取得します。
以上で効率的にトークンの再利用が可能となりました。ここまで作成したコマンドは、スクリプトファイルとして「PSdeConoHa.ps1」という名前で保存しておきましょう。
サーバー一覧の取得
サーバー一覧を取得するコマンドを作成する前に、コントロールパネルからいくつかサーバー(=仮想マシン)を作成しておきましょう。左メニューから「サーバーの追加」を選択します。”タイプ:VPS”、”リージョン:東京”として、他の項目は任意で指定して作成しておきます。
サーバーの追加
VM一覧詳細取得のAPI解説ページを見てみましょう。
必要な情報としては、以下です。
ParameterValueStyleDescriptionX-Auth-TokenUserトークンheaderトークンIDtenant_idTenant IDURIテナントIDchanges-since (Optional)ISO 8601 dateTime (2016-04-04T17:08Z)query削除されたものを含む、指定時間からのVM一覧image (Optional)queryVMに使用されているイメージIDflavor (Optional)queryVMに使用されているフレーバーIDname (Optional)queryVM名marker (Optional)query表示される最後のUUIDlimit (Optional)queryVMの表示数status (Optional)queryVMの状態
「Style」がqueryとなっている項目はオプションです。必須ではありませんので任意で指定します。必要な項目としては、「Userトークン」と「テナントID」となります。
curlコマンドのサンプルコードを見てみましょう。
curl -i -X GET \-H "Accept: application/json" \-H "X-Auth-Token: 35941e7df872405d84e5b026dba8323c" \https://compute.tyo1.conoha.io/v2/1864e71d2deb46f6b47526b69c65a45d/servers/detail
Invoke-RestMethodコマンドで必要となる情報としては、メソッドの”GET”、「-H」のヘッダー情報としてトークン、リクエスト送信先のURLとなります。トークンは先ほど作成した「Get-cTokenHeader」コマンドで取得できます。URLは https://compute.tyo1.conoha.io/v2/<テナントID>/servers/detailとなっています。東京以外のリージョンでサーバーを作成した場合は「compute.tyo1.conoha.io」の部分が異なりますので、コントロールパネルの「エンドポイント」で確認しましょう。
ここまでの情報をInvoke-RestMethodコマンドで置き換えるとこのようになります。
PS C:\> $tokenHeader = Get-cTokenHeader$requestUrl = "https://compute.tyo1.conoha.io/v2/$tenantId/servers/detail"Invoke-RestMethod $requestUrl -Headers $tokenHeader -Method GET
実行してみましょう。データが取得できていれば成功です。
servers-------{@{status=ACTIVE; updated=2017-11-13T02:31:57Z; hostId=6d67cc67c8e7f133bb22ed9ac52a8cc4d1c737595ec28...
実行結果のserversにはConoHa上のすべてのサーバーの詳細な情報が含まれています。試しに以下を実行してみると、仮想マシンの台数分だけ情報が繰り返し表示されます。
PS C:\> $tokenHeader = Get-cTokenHeader$requestUrl = "https://compute.tyo1.conoha.io/v2/$tenantId/servers/detail"$result = Invoke-RestMethod $requestUrl -Headers $tokenHeader -Method GET$servers = $result.serversForEach($server in $servers){$server}status : ACTIVEupdated : 2017-11-13T02:31:57ZhostId : 6d67cc67c8e7f133bb22ed9ac52a8cc4d1c737595ec2892c3a7cc8e4OS-EXT-SRV-ATTR:host : cn-a11018.g2.tyo1.v4addresses : @{ext-150-95-150-0-23=System.Object[]}links : {@{href=https://compute.tyo1.conoha.io/v2/07af275f5800401f83d9f1e2913fe37e/servers/a7b8c9c5-b17c-4446-9b06-337d17083bf4; rel=self}, @{href=https://compute.tyo1.conoha.io/07af275f5800401f83d9f1e2913fe37e/servers/a7b8c9c5-b17c-4446-9b06-337d17083bf4; rel=bookmark}}key_name :image : @{id=5a933dc9-c2ec-48d7-98e4-a72d408c9ffb; links=System.Object[]}OS-EXT-STS:task_state :OS-EXT-STS:vm_state : activeOS-EXT-SRV-ATTR:instance_name : tyo1-00118ab8OS-SRV-USG:launched_at : 2017-11-05T07:23:09.000000OS-EXT-SRV-ATTR:hypervisor_hostname : cn-a11018.g2.tyo1.v4flavor : @{id=7eea7469-0d85-4f82-8050-6ae742394681; links=System.Object[]}id : a7b8c9c5-b17c-4446-9b06-337d17083bf4security_groups : {@{name=default}, @{name=gncs-ipv6-all}, @{name=gncs-ipv4-all}}OS-SRV-USG:terminated_at :OS-EXT-AZ:availability_zone : novauser_id : fcdaf312424446acb12adced7b449047name : 150-95-151-89created : 2017-11-05T07:22:59Ztenant_id : 07af275f5800401f83d9f1e2913fe37eOS-DCF:diskConfig : MANUALos-extended-volumes:volumes_attached : {}accessIPv4 :accessIPv6 :progress : 0OS-EXT-STS:power_state : 1config_drive : Truemetadata : @{instance_name_tag=vps- 2017-11-05-16-15; backup_status=active; backup_id=; properties={"vnc_keymap":"ja","hw_video_model":"vga","hw_vif_model":"virtio","hw_disk_bus":"virtio","cdrom_path":""}; backup_set=0}...
情報量が非常に多いため、作成するコマンドではこれらの中から必要な情報を選択して表示することにします。Invoke-RestMethodコマンドの実行結果は元々PSCustomObjectが配列に格納されたものなので、Get-cVMという名前でサーバー一覧情報を取得して抽出するコマンドを作成し、同様にPSCustomObjectが配列に格納された実行結果を返すようにします。
Function Get-cVM(){
Param(
$Name
)
$tokenHeader = Get-cTokenHeader
$requestUrl = "https://compute.tyo1.conoha.io/v2/$tenantId/servers/detail"
$result = Invoke-RestMethod $requestUrl -Headers $tokenHeader -Method GET
$servers = $result.servers
$objAry = @()
ForEach($server in $servers){
$id = $server.id
$tagName = $server.metadata.instance_name_tag
$state = $server.status
$flavorId = $server.flavor.id
$flavor = Get-cFlavor $flavorId
$vcpu = $flavor.vcpus
$ram = $flavor.ram / 1024
$disk = $flavor.disk
$ip = ($server.addresses.($server.addresses.PSObject.Properties.name) | ? version -eq 4).addr
$objPs = New-Object PSCustomObject
$objPs | Add-Member -NotePropertyMembers @{ID = $id}
$objPs | Add-Member -NotePropertyMembers @{Name = $tagName}
$objPs | Add-Member -NotePropertyMembers @{State = $state}
$objPs | Add-Member -NotePropertyMembers @{vCPU = $vcpu}
$objPs | Add-Member -NotePropertyMembers @{Disk = $disk}
$objPs | Add-Member -NotePropertyMembers @{Memory = $ram}
$objPs | Add-Member -NotePropertyMembers @{IPAddress = $ip}
$objAry += ($objPs | Select-Object ID, Name, State, Memory, Disk, vCPU, IPAddress)
}
$VM = $objAry
If($Name -ne $null){
$VM = $VM | ? Name -eq $Name
}
If($VM -eq $null){
Write-Host ("""$Name"" という名前の仮想マシンが見つかりません。") -ForegroundColor Red
}Else{
Return $VM
}
}
Function Get-cFlavor($flavorId){
$tokenHeader = Get-cTokenHeader
$requestUrl = "https://compute.tyo1.conoha.io/v2/$tenantId/flavors/$flavorId"
$result = Invoke-RestMethod $requestUrl -Headers $tokenHeader -Method GET
Return $result.flavor
}
1-4 :Paramで定義した変数$Nameはコマンドの引数として利用します。単一のサーバー情報を取得する場合に指定します。
7 :Invoke-RestMethodコマンドの実行結果を$resultに格納しておきます。
8:サーバー情報は$result.serversで取得します。
10 :APIから取得したサーバー情報から抽出した情報を格納するための配列を定義します。この配列には一台一台のサーバー情報をPSCustomObjectに格納したものが入ります。
11:サーバーを1台ごとに参照して情報を抽出します。
13 :$server.metadata.instance_name_tagが、ユーザーがコントロールパネルから見た場合のサーバー名(ネームタグ)となります。
15:$flavorId = $server.flavor.idはサーバーのプラン情報のIDとなります。
16-19 :Get-cFlavorコマンドを作成して、プラン情報からサーバーのメモリ容量、CPU、ディスクサイズを取得します。
20 :IPv4のアドレスのみ取得しています。
22-29 :PSCustomObjectを定義して、取得した情報を「キー:値」のペアとして登録します。
30 :配列に格納しておきます。
34 :パラメーターで定義した$Nameに値が入っていた場合は、その名前でフィルタします。
37-38 :指定された仮想マシンが見つからない場合はエラーを表示します。
40 :コマンドの実行結果として、配列に格納されたPSCustomObjectを返します。
44 :flavorIDからサーバーのプランを抽出するためのコマンドを作成します。
46-48 :tenantIDとflavorIDを指定してAPIからプランを取得します。
コマンドを実行してみましょう。シンプルで分かりやすいサーバー情報が取得できいています。
PS C:\> Get-cVMID : a7b8c9c5-b17c-4446-9b06-337d17083bf4Name : vps-2017-11-05-16-15State : ACTIVEMemory : 1Disk : 50vCPU : 2IPAddress : 150.95.151.89ID : 1e08705e-72a5-423a-b9d6-0783e37c98ecName : vps-2017-10-24-12-29State : ACTIVEMemory : 4Disk : 50vCPU : 4IPAddress : 150.95.184.136ID : fe3ec4d2-1af7-4800-a2f8-6ceadd00f8d8Name : vps-2017-10-03-16-52State : ACTIVEMemory : 4Disk : 50vCPU : 4IPAddress : 150.95.156.236
以上のように、ConoHaのREST APIはPowerShellのInvoke-RestMethodコマンドとPSCustomObjectを利用することで、とても使いやすいものとなります。次回以降も引き続きPowerShellでConoHaをどうにかするべく、コマンドを作成していきましょう。また、オリジナルコマンドをさらに使いやすくするためにモジュールとして登録する方法も紹介する予定です。