iControl RESTの基本

# はじめに
iControl RESTとは、BIG-IPのステータスを取得したり、設定を変更したりするためのREST APIのことです。このページでは、iControl RESTを利用する上でのごく基本的な情報を記載します。

# 参考情報
 - [DevCentral:iControl REST Home](https://devcentral.f5.com/wiki/iControlREST.HomePage.ashx)
 - [DevCentral:Demystifying iControl REST](https://devcentral.f5.com/articles/demystifying-icontrol-rest-part-1-understanding-the-request-uri)
 - [iCnontrol REST API User Guide, Version12.1.0](https://devcentral.f5.com/d/icontrol-rest-api-user-guide-version-1210)
   - iControl RESTのマニュアル
 - [iControl REST API Reference Version 12.0](https://devcentral.f5.com/d/icontrol-rest-api-reference-version-120)
   - iControl RESTのAPIリファレンス

 - [BIG-IP Traffic Management Shell(tmsh) Reference Guide](https://support.f5.com/content/kb/en-us/products/big-ip_ltm/manuals/product/bigip-tmsh-reference-12-0-0/_jcr_content/pdfAttach/download/file.res/bigip-tmsh-reference-12-0-0.pdf)
    - tmshのマニュアル

# 環境
本ページの情報は、BIG-IPのバージョン v12.1.2 を対象に動作を確認しています。

# 免責事項
本ページの内容に誤り等があり、参考にされた方がなんらかの損害を被った場合、一切の責任は負いません。

#iControlの基本

**iControlは（ほぼ）TMSHをREST APIで実装したもの**
と、DevCentralにありました。

[iControl REST 101: What is iControl REST?](https://devcentral.f5.com/articles/icontrol-rest-101-what-is-icontrol-rest#.Uvv21BCwI3V)

> Once you’ve learned it in tmsh, you’ve learned it in iControl REST.
> （TMSHで学習したことは、iControl RESTにも通用します。）
> So…it’s just remote tmsh?
> （つまり、iControl RESTとは、リモートですか？）
> Well, sort of. It’s not quite as simple as that, but nearly.
> （それほど単純には言えませんが、それに近いものと言えます。）

大雑把に言えば、iControlとは、REST APIで実装されたtmshインタフェースと言えます。例えば、任意のPoolのステータスを取得する場合、tmshでは"show ltm pool \<pool名\>"というコマンドを実行します。

![iControl_Image_1_tmsh.png](https://qiita-image-store.s3.amazonaws.com/0/157891/0945b6fd-cbb8-ecf8-49ca-26ac1da33b75.png)

これをiControlで実行する場合、"https://<big-ipアドレス>/mgmt/tm/ltm/pool/~Common~\<pool名\>/" というURLに対してGETリクエストを実行することになります。

![iControl_Image_1_icontrol.png](https://qiita-image-store.s3.amazonaws.com/0/157891/bb5994b7-eb18-a9ed-f1e3-6cf212fb9349.png)

tmshの応答は人間に読みやすくフォーマットされたテキストですが、iControl RESTでは、JSONフォーマットで応答します。

すでにBIG-IPをtmshで操作した経験がある人は、iControl RESTを使う上で必要なのは、RESTやJSONといった一般的なWeb APIに対する知識です。一方、RESTやJSONの経験がある人がBIG-IPのiControl RESTを扱おうとする場合、BIG-IPのコマンドラインインタフェースであるtmshについて調べることが近道になります。

## iControl RESTのURI構造
iControl REST APIのURI構造については、次のページが参考になります。

[F5 Python SDK: REST API Endpoints](http://pythonhosted.org/f5-sdk/userguide/endpoints.html)

```
http://192.168.1.1/mgmt/tm/ltm/pool/~Common~mypool/members/~Common~m1:80
                  |----|--|---|----|--------------|-------|-------------|
                  |root|OC|OC |Coll| Resource     | SC    |SubColl Resrc|
```

BIG-IPでは、様々なオブジェクト（例えばVirtual ServerやPool, Node）を作成しますが、ResourceやSubcoll Resourceの部分が、任意のオブジェクトを指定する部分になります。

Resourceを指定せずにGETリクエストを実行すれば、Collection配下の情報を一括で取得できます。例えば、

```bash

(tmos)# list ltm pool
ltm pool test-pool {
    members {
        NodeA:http {
            address 1.1.1.100
        }
    }
}
ltm pool test-pool1 {
    members {
        NodeB:http {
            address 1.1.1.101
        }
    }
}
```

このように二つのPoolが設定されている場合、

```bash
curl -sk -u admin:admin -X GET https://bigip-ve/mgmt/tm/ltm/pool
```
このようなリクエストを実行すれば、二つのPoolの情報が得られます。これは"tmsh list(またはshow) ltm pool" を実行するのと同じことです。

<details><summary>実行例(長いので折りたたみ表示）</summary><div>

```bash
$ curl -sk -u admin:admin https://bigip-ve/mgmt/tm/ltm/pool/ | jq
{
  "kind": "tm:ltm:pool:poolcollectionstate",
  "selfLink": "https://localhost/mgmt/tm/ltm/pool?ver=12.1.2",
  "items": [
    {
      "kind": "tm:ltm:pool:poolstate",
      "name": "test-pool",
      "partition": "Common",
      "fullPath": "/Common/test-pool",
      "generation": 449,
      "selfLink": "https://localhost/mgmt/tm/ltm/pool/~Common~test-pool?ver=12.1.2",
      "allowNat": "yes",
      "allowSnat": "yes",
      "ignorePersistedWeight": "disabled",
      "ipTosToClient": "pass-through",
      "ipTosToServer": "pass-through",
      "linkQosToClient": "pass-through",
      "linkQosToServer": "pass-through",
      "loadBalancingMode": "round-robin",
      "minActiveMembers": 0,
      "minUpMembers": 0,
      "minUpMembersAction": "failover",
      "minUpMembersChecking": "disabled",
      "queueDepthLimit": 0,
      "queueOnConnectionLimit": "disabled",
      "queueTimeLimit": 0,
      "reselectTries": 0,
      "serviceDownAction": "none",
      "slowRampTime": 10,
      "membersReference": {
        "link": "https://localhost/mgmt/tm/ltm/pool/~Common~test-pool/members?ver=12.1.2",
        "isSubcollection": true
      }
    },
    {
      "kind": "tm:ltm:pool:poolstate",
      "name": "test-pool1",
      "partition": "Common",
      "fullPath": "/Common/test-pool1",
      "generation": 451,
      "selfLink": "https://localhost/mgmt/tm/ltm/pool/~Common~test-pool1?ver=12.1.2",
      "allowNat": "yes",
      "allowSnat": "yes",
      "ignorePersistedWeight": "disabled",
      "ipTosToClient": "pass-through",
      "ipTosToServer": "pass-through",
      "linkQosToClient": "pass-through",
      "linkQosToServer": "pass-through",
      "loadBalancingMode": "round-robin",
      "minActiveMembers": 0,
      "minUpMembers": 0,
      "minUpMembersAction": "failover",
      "minUpMembersChecking": "disabled",
      "queueDepthLimit": 0,
      "queueOnConnectionLimit": "disabled",
      "queueTimeLimit": 0,
      "reselectTries": 0,
      "serviceDownAction": "none",
      "slowRampTime": 10,
      "membersReference": {
        "link": "https://localhost/mgmt/tm/ltm/pool/~Common~test-pool1/members?ver=12.1.2",
        "isSubcollection": true
      }
    }
  ]
}
```

</div></details>

###SubCollectionもまとめて取得する
上記実行例の中に、以下のような箇所があります。

```text
      "membersReference": {
        "link": "https://localhost/mgmt/tm/ltm/pool/~Common~test-pool1/members?ver=12.1.2",
        "isSubcollection": true
      }
```

これは、Resouce （今回の場合、Pool）の中に、Sub Collection（今回の場合、Pool Member）が存在することを示しています。Sub Collectionの情報を取得するには、個別にSubCollectionのURLに対してGETリクエストを送信する以外に、Poolの取得時、URLのパラメータに「**?expandSubcollections=true**」をつける方法があります。

「?expandSubcollections=true」を付加した場合、SubCollectionの情報もあわせて応答します。

<details><summary>「?expandSubcollections=true」を付加した実行例(長いので折りたたみ表示）</summary><div>

```bash
$ curl -sk -u admin:admin https://bigip-ve/mgmt/tm/ltm/pool/?expandSubcollections=true | jq
{
  "kind": "tm:ltm:pool:poolcollectionstate",
  "selfLink": "https://localhost/mgmt/tm/ltm/pool?expandSubcollections=true&ver=12.1.2",
  "items": [
    {
      "kind": "tm:ltm:pool:poolstate",
      "name": "test-pool",
      "partition": "Common",
      "fullPath": "/Common/test-pool",
      "generation": 449,
      "selfLink": "https://localhost/mgmt/tm/ltm/pool/~Common~test-pool?ver=12.1.2",
      "allowNat": "yes",
      "allowSnat": "yes",
      "ignorePersistedWeight": "disabled",
      "ipTosToClient": "pass-through",
      "ipTosToServer": "pass-through",
      "linkQosToClient": "pass-through",
      "linkQosToServer": "pass-through",
      "loadBalancingMode": "round-robin",
      "minActiveMembers": 0,
      "minUpMembers": 0,
      "minUpMembersAction": "failover",
      "minUpMembersChecking": "disabled",
      "queueDepthLimit": 0,
      "queueOnConnectionLimit": "disabled",
      "queueTimeLimit": 0,
      "reselectTries": 0,
      "serviceDownAction": "none",
      "slowRampTime": 10,
      "membersReference": {
        "link": "https://localhost/mgmt/tm/ltm/pool/~Common~test-pool/members?ver=12.1.2",
        "isSubcollection": true,
        "items": [
          {
            "kind": "tm:ltm:pool:members:membersstate",
            "name": "NodeA:80",
            "partition": "Common",
            "fullPath": "/Common/NodeA:80",
            "generation": 449,
            "selfLink": "https://localhost/mgmt/tm/ltm/pool/~Common~test-pool/members/~Common~NodeA:80?ver=12.1.2",
            "address": "1.1.1.100",
            "connectionLimit": 0,
            "dynamicRatio": 1,
            "ephemeral": "false",
            "fqdn": {
              "autopopulate": "disabled"
            },
            "inheritProfile": "enabled",
            "logging": "disabled",
            "monitor": "default",
            "priorityGroup": 0,
            "rateLimit": "disabled",
            "ratio": 1,
            "session": "user-enabled",
            "state": "unchecked",
            "nameReference": {
              "link": "https://localhost/mgmt/tm/ltm/node/~Common~NodeA:80?ver=12.1.2"
            }
          }
        ]
      }
    },
    {
      "kind": "tm:ltm:pool:poolstate",
      "name": "test-pool1",
      "partition": "Common",
      "fullPath": "/Common/test-pool1",
      "generation": 451,
      "selfLink": "https://localhost/mgmt/tm/ltm/pool/~Common~test-pool1?ver=12.1.2",
      "allowNat": "yes",
      "allowSnat": "yes",
      "ignorePersistedWeight": "disabled",
      "ipTosToClient": "pass-through",
      "ipTosToServer": "pass-through",
      "linkQosToClient": "pass-through",
      "linkQosToServer": "pass-through",
      "loadBalancingMode": "round-robin",
      "minActiveMembers": 0,
      "minUpMembers": 0,
      "minUpMembersAction": "failover",
      "minUpMembersChecking": "disabled",
      "queueDepthLimit": 0,
      "queueOnConnectionLimit": "disabled",
      "queueTimeLimit": 0,
      "reselectTries": 0,
      "serviceDownAction": "none",
      "slowRampTime": 10,
      "membersReference": {
        "link": "https://localhost/mgmt/tm/ltm/pool/~Common~test-pool1/members?ver=12.1.2",
        "isSubcollection": true,
        "items": [
          {
            "kind": "tm:ltm:pool:members:membersstate",
            "name": "NodeB:80",
            "partition": "Common",
            "fullPath": "/Common/NodeB:80",
            "generation": 451,
            "selfLink": "https://localhost/mgmt/tm/ltm/pool/~Common~test-pool1/members/~Common~NodeB:80?ver=12.1.2",
            "address": "1.1.1.101",
            "connectionLimit": 0,
            "dynamicRatio": 1,
            "ephemeral": "false",
            "fqdn": {
              "autopopulate": "disabled"
            },
            "inheritProfile": "enabled",
            "logging": "disabled",
            "monitor": "default",
            "priorityGroup": 0,
            "rateLimit": "disabled",
            "ratio": 1,
            "session": "user-enabled",
            "state": "unchecked",
            "nameReference": {
              "link": "https://localhost/mgmt/tm/ltm/node/~Common~NodeB:80?ver=12.1.2"
            }
          }
        ]
      }
    }
  ]
}
```
</div></details>

"membersReference"の中に、Pool Memberの情報が含まれていることがわかります。


##iControl RESTのデータ構造
iControl RESTでは、データのやり取りにはJSON(JavaScript Object Notation)形式を使用します。JSONを使うことで、複雑なデータ構造を表すことができます。JSONに関しては、Qiitaや、世の中に多数の説明ページがあるので、知りたい方はそちらを参照してください。

## iControl RESTのHTTPリクエストメソッド
iControl RESTではHTTPメソッドによって対象に対する操作方法を指定します。これは、tmshコマンドの先頭の引数にあたります。

|　　　　| HTTP Method | tmsh   | 
|:-----:|:------:|:-----------:|
|設定の確認| GET   | show or list   |
|設定の作成| POST  | create |
|設定の変更| PATCH | modify |
|設定の削除| DELETE| delete |

## iControl REST実行のサンプル
tmshコマンドの文法は、iControl RESTと類似性が高く、tmshコマンドをiContol RESTに置き換えるのは簡単です。ノードに対する操作を例に、tmshとiControl RESETでおなじ操作をするサンプルをいくつかあげてみます。iControl RESTのためのクライアントにはcurlを使います。

 - Nodeの確認

```bash
tmsh
(tmsh) $ show ltm node / list ltm node 

icontrol
$ curl -k -u admin:admin  -H "Content-Type: application/json" \
  -X GET https://bigip-ve/mgmt/tm/ltm/node
```

 - Nodeの新規作成

```bash
tmsh
(tmsh) $ create ltm node NodeA { address 1.1.1.100 } 

icontrol
$ curl -k -u admin:admin  -H "Content-Type: application/json" \
  -d '{"name":"NodeA", "address":"1.1.1.100"}' \
  -X POST https://bigip-ve/mgmt/tm/ltm/node
```

 - Nodeの設定変更

```bash
tmsh
(tmsh) $ modify ltm node NodeA { description "HTTP Server" } 

icontrol
$ curl -k -u admin:admin  -H "Content-Type: application/json" \
  -d '{"description":"HTTP Server"}' \
  -X PATCH https://bigip-ve/mgmt/tm/ltm/node/~Common~NodeA
```

 - Nodeの削除

```bash
tmsh
(tmsh) $ delete ltm node NodeA

icontrol
$ curl -k -u admin:admin  -H "Content-Type: application/json" \
  -d '{"description":"HTTP Server"}' \
  -X DELETE https://bigip-ve/mgmt/tm/ltm/node/~Common~NodeA
```

## 補足
###URLに使用できるパラメータについて
紹介した「expandSubcollections」以外にもいくつかのパラメータを利用できます。
詳細は[こちらを参照](https://devcentral.f5.com/articles/demystifying-icontrol-rest-part-3-how-to-pass-query-parameters-and-tmsh-options)。

### iControlでData Group Listを更新するときの注意点
いつか書きます。


以上です。