从碎片VPC中提取子网cidr块的最佳方法/库

时间:2017-03-28 22:58:34

标签: amazon-web-services amazon-ec2 subnet terraform vpc

不问编程问题。

假设您有一个带有给定cidr块的VPC。可以说是10.0.0.0/16。 现在假设您已经从VPC分配了大约20个子网。这些子网既不是连续的,也不是相同的宽度。即一个给定的子网是10.0.0.7/27,而另一个子网是10.0.128.0/25,依此类推。

现在没有编写非常复杂的代码,如果我想用32个ip地址(或n个ip地址)雕刻子网,该怎么办?我怎么得到它的cidr块?

是否有任何好的aws库,terraform库或任何人遇到过这个问题并解决了它。我希望能够创建具有给定宽度的新子网。

我知道我可以使用ec2.describe-subnets和jq以及ipcalc等等。但这正是我想要避免的。

2 个答案:

答案 0 :(得分:2)

我会使用Python netaddr package来解决您的问题:

from netaddr import *
import math

cidr = '10.0.0.0/16' # Your VPC's CIDR block

assigned = [ # Networks you've already used
  '10.0.0.7/27',
  '10.0.128.0/25'
]

needed_ips = 32 # Number of IP addresses needed

available = IPSet([cidr]) - IPSet(assigned)
needed_prefix = 32 - math.ceil(math.log2(needed_ips))
for net in available.iter_cidrs():
  if net.prefixlen <= needed_prefix:
    print(next(net.subnet(needed_prefix, 1)))
    break

答案 1 :(得分:0)

如果使用 Python,boto3 包与内置的 ipaddress 模块一起足以列出指定 VPC 的给定 prefix length 未使用的候选子网。

此脚本已使用 Python 3.9 进行测试,但它应该适用于 Python ≥3.6。定义 VPC_NAMEREQUIRED_PREFIX_LEN 的值。它将打印所需长度的所有相关未使用子网,但您可以选择调整它以减少打印。从打印的候选中,您可以仔细挑选那些尽量减少进一步碎片化的候选。

import ipaddress
from typing import List

import boto3

# Customize these parameters:
VPC_NAME = 'my-vpc'
REQUIRED_PREFIX_LEN = 23

# Get VPC CIDR
vpcs = boto3.client('ec2').describe_vpcs(Filters=[{'Name': 'tag:Name', 'Values': [config.EC2_VPC_NAME]}])['Vpcs']
assert len(vpcs) == 1
vpc = vpcs[0]
vpc_cidr = vpc['CidrBlock']
vpc_net = ipaddress.ip_network(vpc_cidr)
assert vpc_net.prefixlen < REQUIRED_PREFIX_LEN
print(f'VPC {VPC_NAME} has CIDR {vpc_cidr}.')


def print_subnets(networks: List, description: str) -> None:
    print(f"\nThe {len(networks)} {description} subnets are: {' '.join(map(str, networks))}")


# Get used subnets
used_subnets = boto3.client('ec2').get_paginator('describe_subnets').paginate(Filters=[{'Name': 'vpc-id', 'Values': [vpc['VpcId']]}]).build_full_result()['Subnets']
used_subnets = [ipaddress.ip_network(s['CidrBlock']) for s in used_subnets]
print_subnets(used_subnets, 'used')
collapsed_used_subnets = list(ipaddress.collapse_addresses(used_subnets))
print_subnets(collapsed_used_subnets, 'collapsed used')

# Get unused subnets
unused_subnets = list(vpc_net.subnets(new_prefix=REQUIRED_PREFIX_LEN))
for used_subnet in collapsed_used_subnets:
    unused_subnets = [unused_subnet for unused_subnet in unused_subnets if not unused_subnet.overlaps(used_subnet)]
print_subnets(unused_subnets, 'relevant unused')
collapsed_unused_subnets = list(ipaddress.collapse_addresses(unused_subnets))
print_subnets(collapsed_unused_subnets, 'relevant collapsed unused')

这不是一个算法高效的脚本,但除非您大规模执行此操作,否则不必如此。