Извлечь неназначенный блок CIDR подсети из фрагментированного VPC

Предположим, у вас есть VPC с заданным блоком cidr. Допустим, 10.0.0.0/16. Теперь предположим, что вы назначили около 20 подсетей из VPC. И эти подсети не являются смежными и не имеют одинаковой ширины. т.е. одна заданная подсеть - 10.0.0.7/27, а какая-то другая подсеть - 10.0.128.0/25 и так далее.

Что, если я хочу разделить подсеть с 32 IP-адресами (или n IP-адресами). Как мне получить его блок cidr?

Есть ли какие-нибудь хорошие библиотеки aws, библиотеки terraform или кто-нибудь сталкивался с этой проблемой и решил ее. Я хочу иметь возможность создавать новые подсети заданной ширины.

Мне известны ec2.describe-subnets, jq, ipcalc и т. Д.


person Tarun S Sandhu    schedule 28.03.2017    source источник


Ответы (2)


Я бы использовал пакет netaddr Python для решения вашей проблемы:

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
person Allen Luce    schedule 29.03.2017

При использовании Python пакет boto3 вместе со встроенным < вместе с модулем href = "https://docs.python.org/3/library/ipaddress.html" rel = "nofollow noreferrer"> ipaddress достаточно для перечисления неиспользуемых подсетей-кандидатов. заданной длины префикса для указанного VPC.

Этот сценарий был протестирован с Python 3.9, но он должен работать с Python ≥3.6. Определите значения VPC_NAME и REQUIRED_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')

Это не алгоритмически эффективный сценарий, но, если вы не делаете это в масштабе, это не обязательно.

person Acumenus    schedule 18.12.2020