IPAM

IPAMはIPアドレス管理のサービスです。IPv4とIPv6の両方をサポートします。

IPAM定義情報は次のとおりです。

属性 概要 備考
name アドレス空間を一意に識別する名前を指定します。 -
cidr プレフィックス付きCIDR形式でアドレススペースを指定します。 -

IPAMが提供する操作は次のとおりです

  • allocate 指定されたプレフィックスを満たすアドレスを取得します。

  • release 指定されたアドレスを解放します。すぐにアドレスプールに戻され、再取得の対象になります。

アドレス取得時にtagを指定できます。tagは、ユーザが任意に指定できるテキストラベルです。tagによる検索や開放が可能になります。

Note

IPAMはデータベースでアドレス情報を管理します。したがって、以下の起動パラメータを正しく設定する必要があります。

db_product = [mysql, postgresql, sqlite]
db_host, db_port, db_name, db_user, db_pass


API

IPAMが提供するAPIは次のとおりです。

  • アドレス空間を作成する
POST /ipam
{
    "type": "object",
    "required": [
        "name",
        "cidr"
    ],
    "properties": {
        "name": {
            "type": "string",
            "description": "Specifies a name that uniquely identifies the address space"
        },
        "cidr": {
            "type": "string",
            "format": "cidr",
            "descripyion": "Specify address space in prefixed CIDR format"
        }
    }
}
  • アドレス空間を排他する
PUT /ipam/{name}
{
    "type": "object",
    "required": [
        "mutex"
    ],
    "properties": {
        "mutex": {
            "type": "boolean"
        }
    }
}

Tip

通常の操作では使用されません。 IPAMは、アドレス割り当ての内部ロックを取得します。突然のシステムダウンなどでロック解除がリークした場合、このAPIで解除できます。逆に、意図的にロックを取得して、アドレスの新しい発行をブロックすることもできます。

  • アドレスを確保する
PATCH /ipam/{name}
{
    "type": "object",
    "properties": {
        "action": {
            "type": "string",
            "enum": [
                "allocate"
            ]
        },
        "params": {
            "type": "object",
            "additionalProperties": "false",
            "required": [
                "prefix"
            ],
            "properties": {
                "prefix": {
                    "type": "integer"
                },
                "address": {
                    "type": "string"
                },
                "tag": {
                    "type": [
                        "string",
                        "null"
                    ]
                }
            }
        }
    }
}
  • アドレスを開放する(CIDR指定)
PATCH /ipam/{name}
{
    "type": "object",
    "properties": {
        "action": {
            "type": "string",
            "enum": [
                "release"
            ]
        },
        "params": {
            "type": "object",
            "additionalProperties": "false",
            "required": [
                "cidr"
            ],
            "properties": {
                "cidr": {
                    "type": "string",
                    "format": "cidr"
                }
            }
        }
    }
}
  • アドレスを開放する(tag指定)
PATCH /ipam/{name}
{
    "type": "object",
    "properties": {
        "action": {
            "type": "string",
            "enum": [
                "release"
            ]
        },
        "params": {
            "type": "object",
            "additionalProperties": "false",
            "required": [
                "tag"
            ],
            "properties": {
                "tag": {
                    "type": "string"
                }
            }
        }
    }
}
  • アドレス空間を削除する(アドレスを払い出している場合は409応答となります)
DELETE /ipam/{name}
  • アドレス空間を強制的に削除する(アドレスを払い出している場合でも強制的に削除します)
DELETE /ipam/{name}?force=true
  • アドレス空間のリストを取得する
GET /ipam
  • アドレス空間を取得する
GET /ipam/{name}
  • 指定したアドレス空間の未使用アドレスのリストを取得する
GET /ipam/{name}?unuse=true
  • 指定したアドレス空間の使用中アドレスのリストを取得する
GET /ipam/{name}?inuse=true&offset={offset}&limit={limit}
  • 指定したアドレス空間の使用中アドレスをtag指定で取得する
GET /ipam/{name}?inuse=true&offset={offset}&limit={limit}&tag={tag}
  • 指定したアドレス空間で特定のprefixを満たすアドレスリストを取得する
GET /ipam/{name}?candidate=true&prefix={prefix}&offset={offset}&limit={limit}


組み込みクラス

シナリオおよびATOMメソッドでIPAMを直接操作するための組み込みクラスが提供されています。メソッドは全てクラスメソッドですのでインスタンス化は必要ありません。

メソッド 引数 返却値 説明
ipam.create name, cidr None アドレス空間を作成する
ipam.delete name None アドレス空間を削除する
ipam.get name MU アドレス空間を取得する
ipam.inuse name, tag list[str] 使用中のアドレスを取得する
ipam.unuse name list[str] 未使用のアドレスを取得する
ipam.candidate name, prefix, offset, limit list[str] 指定したprefixを満たす在庫アドレスを取得する
ipam.allocate name, prefix, tag str アドレスを確保する
ipam.release name, cidr, tag None アドレスを開放する


  • IPv4 example
''' Execution example in interactive shell '''

# address pool creation
>>> await ipam.create("example", "192.168.100.0/24")↵
... r = await ipam.get("example")↵
... print(r.dictionary)↵
... ↵
{'name': 'example', 'cidr': '192.168.100.0/24'}↵
↵
>>> r = await ipam.unuse("example")↵
... print(r)↵
... ↵
['192.168.100.0/24']↵
↵
# address allocation
>>> addr = await ipam.allocate("example", 32)↵
... print(addr)↵
... ↵
192.168.100.0/32↵
↵
>>> addr = await ipam.allocate("example", 32)↵
... print(addr)↵
... ↵
192.168.100.1/32↵
↵
>>> addr = await ipam.allocate("example", 30)↵
... print(addr)↵
... ↵
192.168.100.4/30↵
↵
>>> r = await ipam.inuse("example")↵
... print(r)↵
... ↵
['192.168.100.0/32', '192.168.100.1/32', '192.168.100.4/30']↵
↵
>>> r = await ipam.unuse("example")↵
... print(r)↵
... ↵
['192.168.100.2/31', '192.168.100.8/29', '192.168.100.16/28', '192.168.100.32/27', '192.168.100.64/26', '192.168.100.128/25']↵
↵
# address release
>>> await ipam.release("example", "192.168.100.1/32")↵
... await ipam.release("example", "192.168.100.4/30")↵
... r = await ipam.inuse("example")↵
... print(r)↵
... ↵
['192.168.100.0/32']↵
↵
>>> r = await ipam.unuse("example")↵
... print(r)↵
... ↵
['192.168.100.1/32', '192.168.100.2/31', '192.168.100.4/30', '192.168.100.8/29', '192.168.100.16/28', '192.168.100.32/27', '192.168.100.64/26', '192.168.100.128/25']↵
↵
>>> addr = await ipam.allocate("example", 30)↵
... print(addr)↵
... ↵
192.168.100.4/30↵
↵
>>> await ipam.delete("example")↵
... ↵
Can not delete because it is in use↵
>>> await ipam.delete("example", force=True)↵
... ↵
... r = await ipam.inuse("example")↵
... ↵
Could not show IPAM↵
  • IPv6 example
''' Execution example in interactive shell '''

# address pool creation
>>> await ipam.create("example", "dead:beef::/32")↵
... r = await ipam.get("example")↵
... print(r.dictionary)↵
... ↵
{'name': 'example', 'cidr': 'dead:beef::/32'}↵
↵
>>> r = await ipam.unuse("example")↵
... print(r)↵
... ↵
['dead:beef::/32']↵
↵
# address allocation
>>> addr = await ipam.allocate("example", 128)↵
... print(addr)↵
... ↵
dead:beef::/128↵
↵
>>> addr = await ipam.allocate("example", 40)↵
... print(addr)↵
... addr = await ipam.allocate("example", 40)↵
... print(addr)↵
... ↵
dead:beef:100::/40↵
↵
dead:beef:200::/40↵
↵
>>> r = await ipam.inuse("example")↵
... print(r)↵
... ↵
['dead:beef:0000:0000:0000:0000:0000:0000/128', 'dead:beef:0100:0000:0000:0000:0000:0000/40', 'dead:beef:0200:0000:0000:0000:0000:0000/40']↵
↵
>>> r = await ipam.unuse("example")↵
... print(r)↵
... ↵
['dead:beef::1/128', 'dead:beef::2/127', 'dead:beef::4/126', 'dead:beef::8/125', 'dead:beef::10/124', 'dead:beef::20/123', 'dead:beef::40/122', 'dead:beef::80/121', 'dead:beef::100/120', 'dead:beef::200/119', 'dead:beef::400/118', 'dead:beef::800/117', 'dead:beef::1000/116', 'dead:beef::2000/115', 'dead:beef::4000/114', 'dead:beef::8000/113', 'dead:beef::1:0/112', 'dead:beef::2:0/111', 'dead:beef::4:0/110', 'dead:beef::8:0/109', 'dead:beef::10:0/108', 'dead:beef::20:0/107', 'dead:beef::40:0/106', 'dead:beef::80:0/105', 'dead:beef::100:0/104', 'dead:beef::200:0/103', 'dead:beef::400:0/102', 'dead:beef::800:0/101', 'dead:beef::1000:0/100', 'dead:beef::2000:0/99', 'dead:beef::4000:0/98', 'dead:beef::8000:0/97', 'dead:beef::1:0:0/96', 'dead:beef::2:0:0/95', 'dead:beef::4:0:0/94', 'dead:beef::8:0:0/93', 'dead:beef::10:0:0/92', 'dead:beef::20:0:0/91', 'dead:beef::40:0:0/90', 'dead:beef::80:0:0/89', 'dead:beef::100:0:0/88', 'dead:beef::200:0:0/87', 'dead:beef::400:0:0/86', 'dead:beef::800:0:0/85', 'dead:beef::1000:0:0/84', 'dead:beef::2000:0:0/83', 'dead:beef::4000:0:0/82', 'dead:beef::8000:0:0/81', 'dead:beef:0:0:1::/80', 'dead:beef:0:0:2::/79', 'dead:beef:0:0:4::/78', 'dead:beef:0:0:8::/77', 'dead:beef:0:0:10::/76', 'dead:beef:0:0:20::/75', 'dead:beef:0:0:40::/74', 'dead:beef:0:0:80::/73', 'dead:beef:0:0:100::/72', 'dead:beef:0:0:200::/71', 'dead:beef:0:0:400::/70', 'dead:beef:0:0:800::/69', 'dead:beef:0:0:1000::/68', 'dead:beef:0:0:2000::/67', 'dead:beef:0:0:4000::/66', 'dead:beef:0:0:8000::/65', 'dead:beef:0:1::/64', 'dead:beef:0:2::/63', 'dead:beef:0:4::/62', 'dead:beef:0:8::/61', 'dead:beef:0:10::/60', 'dead:beef:0:20::/59', 'dead:beef:0:40::/58', 'dead:beef:0:80::/57', 'dead:beef:0:100::/56', 'dead:beef:0:200::/55', 'dead:beef:0:400::/54', 'dead:beef:0:800::/53', 'dead:beef:0:1000::/52', 'dead:beef:0:2000::/51', 'dead:beef:0:4000::/50', 'dead:beef:0:8000::/49', 'dead:beef:1::/48', 'dead:beef:2::/47', 'dead:beef:4::/46', 'dead:beef:8::/45', 'dead:beef:10::/44', 'dead:beef:20::/43', 'dead:beef:40::/42', 'dead:beef:80::/41', 'dead:beef:300::/40', 'dead:beef:400::/38', 'dead:beef:800::/37', 'dead:beef:1000::/36', 'dead:beef:2000::/35', 'dead:beef:4000::/34', 'dead:beef:8000::/33']↵
↵
# address release
>>> await ipam.release("example", "dead:beef:100::/40")↵
... r = await ipam.inuse("example")↵
... print(r)↵
... r = await ipam.unuse("example")↵
... print(r)↵
... ↵
['dead:beef:0000:0000:0000:0000:0000:0000/128', 'dead:beef:0200:0000:0000:0000:0000:0000/40']↵
↵
['dead:beef::1/128', 'dead:beef::2/127', 'dead:beef::4/126', 'dead:beef::8/125', 'dead:beef::10/124', 'dead:beef::20/123', 'dead:beef::40/122', 'dead:beef::80/121', 'dead:beef::100/120', 'dead:beef::200/119', 'dead:beef::400/118', 'dead:beef::800/117', 'dead:beef::1000/116', 'dead:beef::2000/115', 'dead:beef::4000/114', 'dead:beef::8000/113', 'dead:beef::1:0/112', 'dead:beef::2:0/111', 'dead:beef::4:0/110', 'dead:beef::8:0/109', 'dead:beef::10:0/108', 'dead:beef::20:0/107', 'dead:beef::40:0/106', 'dead:beef::80:0/105', 'dead:beef::100:0/104', 'dead:beef::200:0/103', 'dead:beef::400:0/102', 'dead:beef::800:0/101', 'dead:beef::1000:0/100', 'dead:beef::2000:0/99', 'dead:beef::4000:0/98', 'dead:beef::8000:0/97', 'dead:beef::1:0:0/96', 'dead:beef::2:0:0/95', 'dead:beef::4:0:0/94', 'dead:beef::8:0:0/93', 'dead:beef::10:0:0/92', 'dead:beef::20:0:0/91', 'dead:beef::40:0:0/90', 'dead:beef::80:0:0/89', 'dead:beef::100:0:0/88', 'dead:beef::200:0:0/87', 'dead:beef::400:0:0/86', 'dead:beef::800:0:0/85', 'dead:beef::1000:0:0/84', 'dead:beef::2000:0:0/83', 'dead:beef::4000:0:0/82', 'dead:beef::8000:0:0/81', 'dead:beef:0:0:1::/80', 'dead:beef:0:0:2::/79', 'dead:beef:0:0:4::/78', 'dead:beef:0:0:8::/77', 'dead:beef:0:0:10::/76', 'dead:beef:0:0:20::/75', 'dead:beef:0:0:40::/74', 'dead:beef:0:0:80::/73', 'dead:beef:0:0:100::/72', 'dead:beef:0:0:200::/71', 'dead:beef:0:0:400::/70', 'dead:beef:0:0:800::/69', 'dead:beef:0:0:1000::/68', 'dead:beef:0:0:2000::/67', 'dead:beef:0:0:4000::/66', 'dead:beef:0:0:8000::/65', 'dead:beef:0:1::/64', 'dead:beef:0:2::/63', 'dead:beef:0:4::/62', 'dead:beef:0:8::/61', 'dead:beef:0:10::/60', 'dead:beef:0:20::/59', 'dead:beef:0:40::/58', 'dead:beef:0:80::/57', 'dead:beef:0:100::/56', 'dead:beef:0:200::/55', 'dead:beef:0:400::/54', 'dead:beef:0:800::/53', 'dead:beef:0:1000::/52', 'dead:beef:0:2000::/51', 'dead:beef:0:4000::/50', 'dead:beef:0:8000::/49', 'dead:beef:1::/48', 'dead:beef:2::/47', 'dead:beef:4::/46', 'dead:beef:8::/45', 'dead:beef:10::/44', 'dead:beef:20::/43', 'dead:beef:40::/42', 'dead:beef:80::/41', 'dead:beef:100::/40', 'dead:beef:300::/40', 'dead:beef:400::/38', 'dead:beef:800::/37', 'dead:beef:1000::/36', 'dead:beef:2000::/35', 'dead:beef:4000::/34', 'dead:beef:8000::/33']↵
↵
>>> addr = await ipam.allocate("example", 40)↵
... print(addr)↵
... ↵
dead:beef:100::/40↵
↵
>>> await ipam.delete("example")↵
... ↵
Can not delete because it is in use↵
>>> await ipam.delete("example", force=True)↵
... ↵
... r = await ipam.inuse("example")↵
... ↵
Could not show IPAM↵


特定のprefixを満たすアドレス在庫を取得するには以下のようにcandidateメソッドを利用します。

>>> await ipam.create("tenant_pool", "10.64.0.0/16")↵
... r = await ipam.candidate("tenant_pool", 23)↵
... print(r)↵
... ↵
↵
['10.64.0.0/23', '10.64.2.0/23', '10.64.4.0/23', '10.64.6.0/23', '10.64.8.0/23', '10.64.10.0/23', '10.64.12.0/23', '10.64.14.0/23', '10.64.16.0/23', '10.64.18.0/23', '10.64.20.0/23', '10.64.22.0/23', '10.64.24.0/23', '10.64.26.0/23', '10.64.28.0/23', '10.64.30.0/23', '10.64.32.0/23', '10.64.34.0/23', '10.64.36.0/23', '10.64.38.0/23', '10.64.40.0/23', '10.64.42.0/23', '10.64.44.0/23', '10.64.46.0/23', '10.64.48.0/23', '10.64.50.0/23', '10.64.52.0/23', '10.64.54.0/23', '10.64.56.0/23', '10.64.58.0/23', '10.64.60.0/23', '10.64.62.0/23', '10.64.64.0/23', '10.64.66.0/23', '10.64.68.0/23', '10.64.70.0/23', '10.64.72.0/23', '10.64.74.0/23', '10.64.76.0/23', '10.64.78.0/23', '10.64.80.0/23', '10.64.82.0/23', '10.64.84.0/23', '10.64.86.0/23', '10.64.88.0/23', '10.64.90.0/23', '10.64.92.0/23', '10.64.94.0/23', '10.64.96.0/23', '10.64.98.0/23', '10.64.100.0/23', '10.64.102.0/23', '10.64.104.0/23', '10.64.106.0/23', '10.64.108.0/23', '10.64.110.0/23', '10.64.112.0/23', '10.64.114.0/23', '10.64.116.0/23', '10.64.118.0/23', '10.64.120.0/23', '10.64.122.0/23', '10.64.124.0/23', '10.64.126.0/23', '10.64.128.0/23', '10.64.130.0/23', '10.64.132.0/23', '10.64.134.0/23', '10.64.136.0/23', '10.64.138.0/23', '10.64.140.0/23', '10.64.142.0/23', '10.64.144.0/23', '10.64.146.0/23', '10.64.148.0/23', '10.64.150.0/23', '10.64.152.0/23', '10.64.154.0/23', '10.64.156.0/23', '10.64.158.0/23', '10.64.160.0/23', '10.64.162.0/23', '10.64.164.0/23', '10.64.166.0/23', '10.64.168.0/23', '10.64.170.0/23', '10.64.172.0/23', '10.64.174.0/23', '10.64.176.0/23', '10.64.178.0/23', '10.64.180.0/23', '10.64.182.0/23', '10.64.184.0/23', '10.64.186.0/23', '10.64.188.0/23', '10.64.190.0/23', '10.64.192.0/23', '10.64.194.0/23', '10.64.196.0/23', '10.64.198.0/23', '10.64.200.0/23', '10.64.202.0/23', '10.64.204.0/23', '10.64.206.0/23', '10.64.208.0/23', '10.64.210.0/23', '10.64.212.0/23', '10.64.214.0/23', '10.64.216.0/23', '10.64.218.0/23', '10.64.220.0/23', '10.64.222.0/23', '10.64.224.0/23', '10.64.226.0/23', '10.64.228.0/23', '10.64.230.0/23', '10.64.232.0/23', '10.64.234.0/23', '10.64.236.0/23', '10.64.238.0/23', '10.64.240.0/23', '10.64.242.0/23', '10.64.244.0/23', '10.64.246.0/23', '10.64.248.0/23', '10.64.250.0/23', '10.64.252.0/23', '10.64.254.0/23']
>>> r = await ipam.candidate("tenant_pool", 23, offset=4, limit=5)↵...件数が多い場合は、offset/limitで範囲を絞ることができます
... print(r)↵
... ↵
↵
['10.64.8.0/23', '10.64.10.0/23', '10.64.12.0/23', '10.64.14.0/23', '10.64.16.0/23']
>>> r = await ipam.allocate("tenant_pool", address="10.64.102.0", prefix=23)↵
... print(r)↵
... ↵
↵
10.64.102.0/23
>>> r = await ipam.candidate("tenant_pool", 23)↵
... print(r)↵
... ↵
↵
['10.64.100.0/23', '10.64.96.0/23', '10.64.98.0/23', '10.64.104.0/23', '10.64.106.0/23', '10.64.108.0/23', '10.64.110.0/23', '10.64.112.0/23', '10.64.114.0/23', '10.64.116.0/23', '10.64.118.0/23', '10.64.120.0/23', '10.64.122.0/23', '10.64.124.0/23', '10.64.126.0/23', '10.64.64.0/23', '10.64.66.0/23', '10.64.68.0/23', '10.64.70.0/23', '10.64.72.0/23', '10.64.74.0/23', '10.64.76.0/23', '10.64.78.0/23', '10.64.80.0/23', '10.64.82.0/23', '10.64.84.0/23', '10.64.86.0/23', '10.64.88.0/23', '10.64.90.0/23', '10.64.92.0/23', '10.64.94.0/23', '10.64.0.0/23', '10.64.2.0/23', '10.64.4.0/23', '10.64.6.0/23', '10.64.8.0/23', '10.64.10.0/23', '10.64.12.0/23', '10.64.14.0/23', '10.64.16.0/23', '10.64.18.0/23', '10.64.20.0/23', '10.64.22.0/23', '10.64.24.0/23', '10.64.26.0/23', '10.64.28.0/23', '10.64.30.0/23', '10.64.32.0/23', '10.64.34.0/23', '10.64.36.0/23', '10.64.38.0/23', '10.64.40.0/23', '10.64.42.0/23', '10.64.44.0/23', '10.64.46.0/23', '10.64.48.0/23', '10.64.50.0/23', '10.64.52.0/23', '10.64.54.0/23', '10.64.56.0/23', '10.64.58.0/23', '10.64.60.0/23', '10.64.62.0/23', '10.64.128.0/23', '10.64.130.0/23', '10.64.132.0/23', '10.64.134.0/23', '10.64.136.0/23', '10.64.138.0/23', '10.64.140.0/23', '10.64.142.0/23', '10.64.144.0/23', '10.64.146.0/23', '10.64.148.0/23', '10.64.150.0/23', '10.64.152.0/23', '10.64.154.0/23', '10.64.156.0/23', '10.64.158.0/23', '10.64.160.0/23', '10.64.162.0/23', '10.64.164.0/23', '10.64.166.0/23', '10.64.168.0/23', '10.64.170.0/23', '10.64.172.0/23', '10.64.174.0/23', '10.64.176.0/23', '10.64.178.0/23', '10.64.180.0/23', '10.64.182.0/23', '10.64.184.0/23', '10.64.186.0/23', '10.64.188.0/23', '10.64.190.0/23', '10.64.192.0/23', '10.64.194.0/23', '10.64.196.0/23', '10.64.198.0/23', '10.64.200.0/23', '10.64.202.0/23', '10.64.204.0/23', '10.64.206.0/23', '10.64.208.0/23', '10.64.210.0/23', '10.64.212.0/23', '10.64.214.0/23', '10.64.216.0/23', '10.64.218.0/23', '10.64.220.0/23', '10.64.222.0/23', '10.64.224.0/23', '10.64.226.0/23', '10.64.228.0/23', '10.64.230.0/23', '10.64.232.0/23', '10.64.234.0/23', '10.64.236.0/23', '10.64.238.0/23', '10.64.240.0/23', '10.64.242.0/23', '10.64.244.0/23', '10.64.246.0/23', '10.64.248.0/23', '10.64.250.0/23', '10.64.252.0/23', '10.64.254.0/23']
>>> r = await ipam.allocate("tenant_pool", address="10.64.104.0", prefix=23)↵
... print(r)↵
... r = await ipam.candidate("tenant_pool", 23)↵
... print(r)↵
... ↵
10.64.104.0/23
↵
['10.64.100.0/23', '10.64.96.0/23', '10.64.98.0/23', '10.64.106.0/23', '10.64.108.0/23', '10.64.110.0/23', '10.64.112.0/23', '10.64.114.0/23', '10.64.116.0/23', '10.64.118.0/23', '10.64.120.0/23', '10.64.122.0/23', '10.64.124.0/23', '10.64.126.0/23', '10.64.64.0/23', '10.64.66.0/23', '10.64.68.0/23', '10.64.70.0/23', '10.64.72.0/23', '10.64.74.0/23', '10.64.76.0/23', '10.64.78.0/23', '10.64.80.0/23', '10.64.82.0/23', '10.64.84.0/23', '10.64.86.0/23', '10.64.88.0/23', '10.64.90.0/23', '10.64.92.0/23', '10.64.94.0/23', '10.64.0.0/23', '10.64.2.0/23', '10.64.4.0/23', '10.64.6.0/23', '10.64.8.0/23', '10.64.10.0/23', '10.64.12.0/23', '10.64.14.0/23', '10.64.16.0/23', '10.64.18.0/23', '10.64.20.0/23', '10.64.22.0/23', '10.64.24.0/23', '10.64.26.0/23', '10.64.28.0/23', '10.64.30.0/23', '10.64.32.0/23', '10.64.34.0/23', '10.64.36.0/23', '10.64.38.0/23', '10.64.40.0/23', '10.64.42.0/23', '10.64.44.0/23', '10.64.46.0/23', '10.64.48.0/23', '10.64.50.0/23', '10.64.52.0/23', '10.64.54.0/23', '10.64.56.0/23', '10.64.58.0/23', '10.64.60.0/23', '10.64.62.0/23', '10.64.128.0/23', '10.64.130.0/23', '10.64.132.0/23', '10.64.134.0/23', '10.64.136.0/23', '10.64.138.0/23', '10.64.140.0/23', '10.64.142.0/23', '10.64.144.0/23', '10.64.146.0/23', '10.64.148.0/23', '10.64.150.0/23', '10.64.152.0/23', '10.64.154.0/23', '10.64.156.0/23', '10.64.158.0/23', '10.64.160.0/23', '10.64.162.0/23', '10.64.164.0/23', '10.64.166.0/23', '10.64.168.0/23', '10.64.170.0/23', '10.64.172.0/23', '10.64.174.0/23', '10.64.176.0/23', '10.64.178.0/23', '10.64.180.0/23', '10.64.182.0/23', '10.64.184.0/23', '10.64.186.0/23', '10.64.188.0/23', '10.64.190.0/23', '10.64.192.0/23', '10.64.194.0/23', '10.64.196.0/23', '10.64.198.0/23', '10.64.200.0/23', '10.64.202.0/23', '10.64.204.0/23', '10.64.206.0/23', '10.64.208.0/23', '10.64.210.0/23', '10.64.212.0/23', '10.64.214.0/23', '10.64.216.0/23', '10.64.218.0/23', '10.64.220.0/23', '10.64.222.0/23', '10.64.224.0/23', '10.64.226.0/23', '10.64.228.0/23', '10.64.230.0/23', '10.64.232.0/23', '10.64.234.0/23', '10.64.236.0/23', '10.64.238.0/23', '10.64.240.0/23', '10.64.242.0/23', '10.64.244.0/23', '10.64.246.0/23', '10.64.248.0/23', '10.64.250.0/23', '10.64.252.0/23', '10.64.254.0/23']
>>>


アドレス払い出し時に addressを指定することもできます。

>>> await ipam.create("tenant_pool", "10.64.0.0/16")↵
>>> tenant1 = await ipam.allocate("tenant_pool", prefix=23, tag="tenant1", address="10.64.2.0")↵
... print(tenant1)↵
... ↵
↵
10.64.2.0/23
>>> r = await ipam.unuse("tenant_pool")↵
... print(r)↵
... ↵
↵
['10.64.0.0/23', '10.64.4.0/22', '10.64.8.0/21', '10.64.16.0/20', '10.64.32.0/19', '10.64.64.0/18', '10.64.128.0/17']
>>> tenant2 = await ipam.allocate("tenant_pool", prefix=23, tag="tenant2", address="10.64.4.0")↵
>>> print(tenant2)↵
... ↵
↵
10.64.4.0/23
>>> r = await ipam.unuse("tenant_pool")↵
... print(r)↵
... ↵
↵
['10.64.6.0/23', '10.64.0.0/23', '10.64.8.0/21', '10.64.16.0/20', '10.64.32.0/19', '10.64.64.0/18', '10.64.128.0/17']
>>>


アドレス取得時に tagを指定すると、次のように操作できます。

>>> await ipam.create("example", "192.168.100.0/24")↵
... addr = await ipam.allocate("example", 30, tag="userA")↵
... print(addr)↵
... ↵
192.168.100.0/30↵
↵
>>> addr = await ipam.allocate("example", 30, tag="userB")↵
... print(addr)↵
... ↵
192.168.100.4/30↵
↵
>>> r = await ipam.inuse("example", tag="userA")↵
... print(r)↵
... ↵
['192.168.100.0/30']↵
↵
>>> r = await ipam.inuse("example", tag="userB")↵
... print(r)↵
... ↵
['192.168.100.4/30']↵
↵
>>> await ipam.release("example", tag="userB")↵
... r = await ipam.inuse("example", tag="userB")↵
... print(r)↵
... ↵
[]↵
↵
>>> r = await ipam.inuse("example")↵
... print(r)↵
... ↵
['192.168.100.0/30']↵
↵


ipamオブジェクトはスレッドセーフです。以下の多重実行が可能です。

>>> await ipam.create("example", "dead:beef::/32")↵
... ↵
>>> responses = await asyncio.gather(*[ipam.allocate("example", 40) for i in range(5)])↵
... for i in responses:↵
...     print(i)↵
... ↵
dead:beef:200::/40↵
↵
dead:beef:100::/40↵
↵
dead:beef:300::/40↵
↵
dead:beef:400::/40↵
↵
dead:beef::/40↵
↵