【さくらのクラウドAPI】curlでサーバー一覧取得してみた

## 概要

さくらクラウドを普段使っているのですが、curlでさくらのクラウドAPIを叩きサーバー一覧を取得する方法をまとめてみました。
公式ドキュメントと合わせて補完してください。

https://developer.sakura.ad.jp/cloud/api/1.1/server/#get_server

### できるようになること

- curlでさくらのクラウドAPIを叩き、サーバー一覧を取得できる
- 欲しいプロパティを含んだレスポンスのみを取得することができる（Includeオプション）
- サーバー名や電源の状態などで情報を絞ることできる（Filterオプション）

### 必要なもの

1. **curlが実行できるターミナル**
  - Windows, Mac, LinuxどのOSでもだいたい実行できると思います。できない場合は環境を用意してください。
1. **アクセストークン、アクセストークンシークレット**
  - さくらのクラウドホームからAPIキーを作成し、上記の2つを控えておいてください。後ほど使用します。
  - 詳しい作成方法は下のリンクから 

https://manual.sakura.ad.jp/cloud/api/apikey.html

## curlコマンド

- サンプルに記載している`Access Token`,`Token Secret`はご自身のものに置き換えてください。
- サンプルでは石狩第1ゾーン`is1a`のサーバー一覧を取得していますが、他のゾーンの場合はAPI URLの`is1a`を以下を参考に置き換えてください。
  - **石狩第1**: `is1a` ← サンプルはこのゾーンを参照
  - **石狩第2**: `is1b`
  - **東京第1**: `tk1a`
  - **東京第2**: `tk1b`
     - 石狩第2であれば `https://secure.sakura.ad.jp/cloud/zone/is1b/api/cloud/1.1/server/`

今回はこちらの環境でテストします。コンパネのスクリーンショットです。
![sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/901444/68790d4f-24ee-e662-2577-8983b3b25713.png)

## サンプル1（すべての情報）

最初は何も考えずアクセストークン、アクセストークンシークレットを設定して、サーバー一覧のAPIを叩いてみます。

```terminal
curl -u "Access Token":"Access Token Secret" \
  https://secure.sakura.ad.jp/cloud/zone/is1a/api/cloud/1.1/server/ \
  --get
```

### 実行結果

```json
{"From":0,"Count":2,"Total":2,"Servers":[{"Index":0,"ID":"113301644830","Name":"server02","HostName":"server02","Description":"","Availability":"available","ServiceClass":"cloud\/plan\/1core-1gb-g2","InterfaceDriver":"virtio","CreatedAt":"2021-09-13T08:55:50+09:00","ModifiedAt":"2021-09-13T08:58:59+09:00","Icon":null,"ServerPlan":{"ID":200001001,"Name":"\u30d7\u30e9\u30f3\/1Core-1GB","CPU":1,"MemoryMB":1024,"Commitment":"standard","Generation":200,"ServiceClass":"cloud\/plan\/1core-1gb-g2"},"Zone":{"ID":31001,"DisplayOrder":20031001,"Name":"is1a","Description":"\u77f3\u72e9\u7b2c1\u30be\u30fc\u30f3","IsDummy":false,"VNCProxy":{"HostName":"sac-is1a-vnc.cloud.sakura.ad.jp","IPAddress":"61.211.224.152"},"FTPServer":{"HostName":"sac-is1a-ftp.cloud.sakura.ad.jp","IPAddress":"133.242.31.244"},"Settings":{"SelectableGenerations":[200],"DefaultGeneration":200,"DisabledDiskPlans":[{"Generation":100,"ServiceClasses":["cloud\/disk\/ssd\/40g","cloud\/disk\/ssd\/1t","cloud\/disk\/ssd\/2t","cloud\/disk\/ssd\/4t","cloud\/disk\/iscsi\/8t","cloud\/disk\/iscsi\/12t"]}],"Subnet":{"Plan":{"Member":[28,27,26],"Staff":[28,27,26,25,24]}},"DisablePassport":false,"DisablePrivateHost":false,"SuspendPrivateHost":false},"Region":{"ID":310,"Name":"\u77f3\u72e9","Description":"\u77f3\u72e9","NameServers":["133.242.0.3","133.242.0.4"]}},"Instance":{"Server":{"ID":"113301644830"},"Status":"down","BeforeStatus":"cleaning","Warnings":"none","WarningsValue":0,"StatusChangedAt":"2021-09-13T09:26:23+09:00","MigrationProgress":null,"MigrationSchedule":null,"MigrationAllowed":null,"ModifiedAt":"2021-09-13T09:26:23+09:00","Host":null,"CDROM":null},"Disks":[{"ID":"113301644832","Name":"server02","Connection":"virtio","ConnectionOrder":1,"ReinstallCount":0,"ToBeInitialized":false,"Availability":"available","SizeMB":20480,"Plan":{"ID":4},"Storage":{"ID":"3100196407","Generation":200,"MountIndex":"3100196407","Class":"iscsi1204"},"BundleInfo":null}],"Interfaces":[{"ID":"113301644831","MACAddress":"9C:A3:BA:26:8F:98","IPAddress":"153.120.135.250","UserIPAddress":null,"HostName":null,"Switch":{"ID":"113201219670","Name":"\u30b9\u30a4\u30c3\u30c1","Scope":"shared","Subnet":{"ID":null,"NetworkAddress":"153.120.135.0","NetworkMaskLen":24,"DefaultRoute":"153.120.135.1","Internet":{"BandWidthMbps":100}},"UserSubnet":null},"PacketFilter":null}],"Appliance":null,"PrivateHost":null,"Tags":[]},{"Index":1,"ID":"113301645700","Name":"server01","HostName":"server01","Description":"","Availability":"available","ServiceClass":"cloud\/plan\/1core-1gb-g2","InterfaceDriver":"virtio","CreatedAt":"2021-09-13T11:15:03+09:00","ModifiedAt":"2021-09-13T11:16:23+09:00","Icon":null,"ServerPlan":{"ID":200001001,"Name":"\u30d7\u30e9\u30f3\/1Core-1GB","CPU":1,"MemoryMB":1024,"Commitment":"standard","Generation":200,"ServiceClass":"cloud\/plan\/1core-1gb-g2"},"Zone":{"ID":31001,"DisplayOrder":20031001,"Name":"is1a","Description":"\u77f3\u72e9\u7b2c1\u30be\u30fc\u30f3","IsDummy":false,"VNCProxy":{"HostName":"sac-is1a-vnc.cloud.sakura.ad.jp","IPAddress":"61.211.224.152"},"FTPServer":{"HostName":"sac-is1a-ftp.cloud.sakura.ad.jp","IPAddress":"133.242.31.244"},"Settings":{"SelectableGenerations":[200],"DefaultGeneration":200,"DisabledDiskPlans":[{"Generation":100,"ServiceClasses":["cloud\/disk\/ssd\/40g","cloud\/disk\/ssd\/1t","cloud\/disk\/ssd\/2t","cloud\/disk\/ssd\/4t","cloud\/disk\/iscsi\/8t","cloud\/disk\/iscsi\/12t"]}],"Subnet":{"Plan":{"Member":[28,27,26],"Staff":[28,27,26,25,24]}},"DisablePassport":false,"DisablePrivateHost":false,"SuspendPrivateHost":false},"Region":{"ID":310,"Name":"\u77f3\u72e9","Description":"\u77f3\u72e9","NameServers":["133.242.0.3","133.242.0.4"]}},"Instance":{"Server":{"ID":"113301645700"},"Status":"up","BeforeStatus":"down","Warnings":"none","WarningsValue":0,"StatusChangedAt":"2021-09-13T11:16:38+09:00","MigrationProgress":null,"MigrationSchedule":null,"MigrationAllowed":null,"ModifiedAt":"2021-09-13T11:16:38+09:00","Host":{"Name":"sac-is1a-sv431","InfoURL":"","Class":"dynamic","Commitment":"standard","ForPrivate":false,"Generation":200,"Version":302,"SystemVersion":"SAKURA Internet [CLOUD SERVICE 3.2]","PrivateHost":null},"CDROM":null},"Disks":[{"ID":"113301645703","Name":"server01","Connection":"virtio","ConnectionOrder":1,"ReinstallCount":0,"ToBeInitialized":false,"Availability":"available","SizeMB":20480,"Plan":{"ID":4},"Storage":{"ID":"3100196416","Generation":200,"MountIndex":"3100196416","Class":"iscsi1204"},"BundleInfo":null}],"Interfaces":[{"ID":"113301645701","MACAddress":"9C:A3:BA:22:BC:96","IPAddress":"153.120.20.49","UserIPAddress":null,"HostName":null,"Switch":{"ID":"112700342899","Name":"\u30b9\u30a4\u30c3\u30c1","Scope":"shared","Subnet":{"ID":null,"NetworkAddress":"153.120.20.0","NetworkMaskLen":24,"DefaultRoute":"153.120.20.1","Internet":{"BandWidthMbps":100}},"UserSubnet":{"DefaultRoute":"192.168.0.1","NetworkMaskLen":28}},"PacketFilter":null}],"Appliance":null,"PrivateHost":null,"Tags":[]}],"is_ok":true}
```

サーバーのエンドポイントから取得できるすべての情報が含まれているのでとても読みにくいですし、一列で表示されてしまうので理解に時間がかかりますね。
なのでJson整形ツールで読みやすい形にするといいと思います。

https://lab.syncer.jp/Tool/JSON-Viewer/

整形して記事に貼ると長すぎるのでここではやめときます。

## サンプル2 （Filterオプション）

自分が欲しいサーバーの情報だけを取得することができる`Filterオプション`の使い方です。
今回は**電源が入っているサーバー一覧取得**のサンプルです。

`Filter`オブジェクトを付与し、その中に自分が検索したい情報を`プロパティ:値`形式で追加すると、その内容で検索された結果を取得できます。
今回は`Instance.Status（電源状態）`が`up（起動中）`のものを取得するので`{ Filter: {"Instance.Status":"up"} }`を追加します。

```terminal
curl -u "Access Token":"Access Token Secret" \
  https://secure.sakura.ad.jp/cloud/zone/is1a/api/cloud/1.1/server/ \
  --get \
  --data-urlencode '{"Filter":{"Instance.Status":"up"}}'
```

### 実行結果

電源がオンのサーバー情報のみが含まれていることがわかります。

```json
{"From":0,"Count":1,"Total":1,"Servers":[{"Index":0,"ID":"113301645700","Name":"server01","HostName":"server01","Description":"","Availability":"available","ServiceClass":"cloud\/plan\/1core-1gb-g2","InterfaceDriver":"virtio","CreatedAt":"2021-09-13T11:15:03+09:00","ModifiedAt":"2021-09-13T11:16:23+09:00","Icon":null,"ServerPlan":{"ID":200001001,"Name":"\u30d7\u30e9\u30f3\/1Core-1GB","CPU":1,"MemoryMB":1024,"Commitment":"standard","Generation":200,"ServiceClass":"cloud\/plan\/1core-1gb-g2"},"Zone":{"ID":31001,"DisplayOrder":20031001,"Name":"is1a","Description":"\u77f3\u72e9\u7b2c1\u30be\u30fc\u30f3","IsDummy":false,"VNCProxy":{"HostName":"sac-is1a-vnc.cloud.sakura.ad.jp","IPAddress":"61.211.224.152"},"FTPServer":{"HostName":"sac-is1a-ftp.cloud.sakura.ad.jp","IPAddress":"133.242.31.244"},"Settings":{"SelectableGenerations":[200],"DefaultGeneration":200,"DisabledDiskPlans":[{"Generation":100,"ServiceClasses":["cloud\/disk\/ssd\/40g","cloud\/disk\/ssd\/1t","cloud\/disk\/ssd\/2t","cloud\/disk\/ssd\/4t","cloud\/disk\/iscsi\/8t","cloud\/disk\/iscsi\/12t"]}],"Subnet":{"Plan":{"Member":[28,27,26],"Staff":[28,27,26,25,24]}},"DisablePassport":false,"DisablePrivateHost":false,"SuspendPrivateHost":false},"Region":{"ID":310,"Name":"\u77f3\u72e9","Description":"\u77f3\u72e9","NameServers":["133.242.0.3","133.242.0.4"]}},"Instance":{"Server":{"ID":"113301645700"},"Status":"up","BeforeStatus":"down","Warnings":"none","WarningsValue":0,"StatusChangedAt":"2021-09-13T11:16:38+09:00","MigrationProgress":null,"MigrationSchedule":null,"MigrationAllowed":null,"ModifiedAt":"2021-09-13T11:16:38+09:00","Host":{"Name":"sac-is1a-sv431","InfoURL":"","Class":"dynamic","Commitment":"standard","ForPrivate":false,"Generation":200,"Version":302,"SystemVersion":"SAKURA Internet [CLOUD SERVICE 3.2]","PrivateHost":null},"CDROM":null},"Disks":[{"ID":"113301645703","Name":"server01","Connection":"virtio","ConnectionOrder":1,"ReinstallCount":0,"ToBeInitialized":false,"Availability":"available","SizeMB":20480,"Plan":{"ID":4},"Storage":{"ID":"3100196416","Generation":200,"MountIndex":"3100196416","Class":"iscsi1204"},"BundleInfo":null}],"Interfaces":[{"ID":"113301645701","MACAddress":"9C:A3:BA:22:BC:96","IPAddress":"153.120.20.49","UserIPAddress":null,"HostName":null,"Switch":{"ID":"112700342899","Name":"\u30b9\u30a4\u30c3\u30c1","Scope":"shared","Subnet":{"ID":null,"NetworkAddress":"153.120.20.0","NetworkMaskLen":24,"DefaultRoute":"153.120.20.1","Internet":{"BandWidthMbps":100}},"UserSubnet":{"DefaultRoute":"192.168.0.1","NetworkMaskLen":28}},"PacketFilter":null}],"Appliance":null,"PrivateHost":null,"Tags":[]}],"is_ok":true}
```

## サンプル3（Includeオプション）

サンプル1、2はプロパティが多すぎるので`Includeオプション`で情報を少なくしてみましょう。
今回は`ID（リソースID）, Name:（名前）, CreatedAt（作成日時）, Instance.Status（電源状態）, Zone.Name（ゾーン名前）`を取得したいと思います。

欲しい情報を変更したいときは`Include`の中を好きなものに変更してください。
ちなみに取得できるプロパティ一覧があるわけではないので、サンプル1に表示されているプロパティの中から好きなものを探してください。

探すのが大変な人のために例を置いておきます。

- `Server.CPU`: サーバーのCPU
- `Server.MemoryMB`: サーバーのメモリ
- `HostName`: ホストの名前
- `Disk`: 接続されているディスク情報
- `Interface`: NICの情報


```terminal
curl -u "Access Token":"Access Token Secret" \
  https://secure.sakura.ad.jp/cloud/zone/is1a/api/cloud/1.1/server/ \
  --get \
  --data-urlencode '{"Include":["ID","Name","CreatedAt","Instance.Status","Zone.Name"]}'
```

### 実行結果

`Include`で指定したプロパティのみがレスポンスに含まれていることが確認できると思います。

```json
{"From":0,"Count":2,"Total":2,"Servers":[{"Index":0,"ID":"113301644830","Name":"server02","CreatedAt":"2021-09-13T08:55:50+09:00","Zone":{"Name":"is1a"},"Instance":{"Status":"down"}},{"Index":1,"ID":"113301645700","Name":"server01","CreatedAt":"2021-09-13T11:15:03+09:00","Zone":{"Name":"is1a"},"Instance":{"Status":"up"}}],"is_ok":true}
```

整形するとこんな感じです。すごくスッキリしましたね。

```json
{
    "From": 0,
    "Count": 2,
    "Total": 2,
    "Servers": [
        {
            "Index": 0,
            "ID": "113300928621",
            "Name": "server01",
            "CreatedAt": "2021-05-12T14:54:03+09:00",
            "Zone": {
                "Name": "is1a"
            },
            "Instance": {
                "Status": "up"
            }
        },
        {
            "Index": 1,
            "ID": "113301644830",
            "Name": "server02",
            "CreatedAt": "2021-09-13T08:55:50+09:00",
            "Zone": {
                "Name": "is1a"
            },
            "Instance": {
                "Status": "down"
            }
        }
    ],
    "is_ok": true
}
```



## サンプル4 （Filter & Includeの合わせ技）

最後に電源がオンのサーバー & レスポンスを（`ID, Name, CreatedAt, Instance.Status, Zone.Name`）の一覧を取得したいと思います。
オプションに`Filter`と`Include`を追加して必要なプロパティを加えるだけですね。簡単です。

```terminal
curl -u "Access Token":"Access Token Secret" \
  https://secure.sakura.ad.jp/cloud/zone/is1a/api/cloud/1.1/server/ \
  --get \
  --data-urlencode '{"Include":["ID","Name","CreatedAt","Instance.Status","Zone.Name"],"Filter":{"Instance.Status":"up"}}'
```

### 実行結果

```json
{"From":0,"Count":1,"Total":1,"Servers":[{"Index":0,"ID":"113301645700","Name":"server01","CreatedAt":"2021-09-13T11:15:03+09:00","Zone":{"Name":"is1a"},"Instance":{"Status":"up"}}],"is_ok":true}
```

整形するとこんな感じです。かなり読みやすくなりました。

```json
{
    "From": 0,
    "Count": 1,
    "Total": 1,
    "Servers": [
        {
            "Index": 0,
            "ID": "113301645700",
            "Name": "server01",
            "CreatedAt": "2021-09-13T11:15:03+09:00",
            "Zone": {
                "Name": "is1a"
            },
            "Instance": {
                "Status": "up"
            }
        }
    ],
    "is_ok": true
}
```

## まとめ

これでさくらのクラウドで作成したサーバー一覧をcurlで取得することができるようになりました。
今回紹介したオプション以外にも`Exclude`や`Sort`など情報を使いやすくするオプションが複数ありますのでぜひ公式のドキュメントも参照ください。

https://manual.sakura.ad.jp/cloud/api/apikey.html


あまり`curl`でAPIを叩く人はいないかもしれないですが、ぜひお試しください。
次回は`node.js`でAPIを叩くサンプルを紹介します。