Updated network assignment to blocks to consider reservations and added additional descriptors API documentation

This commit is contained in:
Matthew Garrett 2023-02-22 00:14:17 -08:00
Родитель 5ce7f0f81a
Коммит 944121d3b2
5 изменённых файлов: 142 добавлений и 70 удалений

Просмотреть файл

@ -1,4 +1,4 @@
from fastapi import APIRouter, Depends, Request, Response, HTTPException, Header, status
from fastapi import APIRouter, Depends, Request, Response, HTTPException, Header, Path, status
from fastapi.responses import JSONResponse, PlainTextResponse
from fastapi.exceptions import HTTPException as StarletteHTTPException
from fastapi.encoders import jsonable_encoder
@ -55,6 +55,7 @@ async def new_admin_db(admin_list, exclusion_list, tenant_id):
status_code = 200
)
async def get_admins(
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
@ -85,6 +86,7 @@ async def get_admins(
)
async def create_admin(
admin: Admin,
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
@ -128,13 +130,14 @@ async def create_admin(
)
async def update_admins(
admin_list: List[Admin],
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
"""
Replace the list of IPAM Administrators with the following details:
- Array **[]** of:
- Array **[ ]** of:
- **name**: Full name of the Administrator
- **email**: Email address for the Administrator
- **id**: Azure AD ObjectID for the Administrator user
@ -172,7 +175,8 @@ async def update_admins(
error_msg = "Error removing admin, please try again."
)
async def delete_admin(
objectId: UUID,
objectId: UUID = Path(..., description="Azure AD ObjectID for the target user"),
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
@ -208,6 +212,7 @@ async def delete_admin(
status_code = 200
)
async def get_exclusions(
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
@ -238,11 +243,12 @@ async def get_exclusions(
)
async def add_exclusions(
exclusions: List[Subscription],
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
"""
Add a list of excluded subscriptions:
Add a list of excluded Subscriptions:
- **[<UUID>]**: Array of Subscription ID's
"""
@ -280,11 +286,12 @@ async def add_exclusions(
)
async def update_exclusions(
exclusions: List[Subscription],
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
"""
Replace the list of excluded subscriptions:
Replace the list of excluded Subscriptions:
- **[<UUID>]**: Array of Subscription ID's
"""
@ -321,12 +328,13 @@ async def update_exclusions(
error_msg = "Error removing exclusion, please try again."
)
async def remove_exclusion(
subscriptionId: Subscription,
subscriptionId: Subscription = Path(..., description="Azure Subscription ID"),
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
"""
Remove an excluded subscription id
Remove an excluded Subscription ID.
"""
if not is_admin:

Просмотреть файл

@ -1,4 +1,4 @@
from fastapi import APIRouter, Depends, Request, Response, HTTPException, Header, status
from fastapi import APIRouter, Depends, Request, Response, HTTPException, Header, Query, Path, status
from fastapi.responses import JSONResponse, PlainTextResponse
from fastapi.exceptions import HTTPException as StarletteHTTPException
from fastapi.encoders import jsonable_encoder
@ -94,9 +94,9 @@ async def scrub_space_patch(patch):
status_code = 200
)
async def get_spaces(
expand: bool = False,
utilization: bool = False,
authorization: str = Header(None),
expand: bool = Query(False, description="Expand network references to full network objects"),
utilization: bool = Query(False, description="Append utilization information for each network"),
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
@ -180,7 +180,7 @@ async def get_spaces(
)
async def create_space(
space: SpaceReq,
authorization: str = Header(None),
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
@ -227,10 +227,10 @@ async def create_space(
status_code = 200
)
async def get_space(
space: str,
expand: bool = False,
utilization: bool = False,
authorization: str = Header(None),
space: str = Path(..., description="Name of the target Space"),
expand: bool = Query(False, description="Expand network references to full network objects"),
utilization: bool = Query(False, description="Append utilization information for each network"),
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
@ -317,8 +317,9 @@ async def get_space(
error_msg = "Error updating space, please try again."
)
async def update_space(
space: str,
updates: SpaceUpdate,
space: str = Path(..., description="Name of the target Space"),
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
@ -327,8 +328,6 @@ async def update_space(
- **[<JSON Patch>]**: Array of JSON Patches
 
Allowed operations:
- **replace**
@ -369,8 +368,9 @@ async def update_space(
error_msg = "Error deleting space, please try again."
)
async def delete_space(
space: str,
force: Optional[bool] = False,
space: str = Path(..., description="Name of the target Space"),
force: Optional[bool] = Query(False, description="Forcefully delete a Space with existing Blocks"),
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
@ -410,10 +410,10 @@ async def delete_space(
status_code = 200
)
async def get_blocks(
space: str,
expand: bool = False,
utilization: bool = False,
authorization: str = Header(None),
space: str = Path(..., description="Name of the target Space"),
expand: bool = Query(False, description="Expand network references to full network objects"),
utilization: bool = Query(False, description="Append utilization information for each network"),
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
@ -496,8 +496,9 @@ async def get_blocks(
error_msg = "Error creating block, please try again."
)
async def create_block(
space: str,
block: BlockReq,
space: str = Path(..., description="Name of the target Space"),
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
@ -548,9 +549,9 @@ async def create_block(
error_msg = "Error creating cidr reservation, please try again."
)
async def create_multi_block_reservation(
space: str,
req: SpaceCIDRReq,
authorization: str = Header(None),
space: str = Path(..., description="Name of the target Space"),
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id)
):
"""
@ -659,11 +660,11 @@ async def create_multi_block_reservation(
status_code = 200
)
async def get_block(
space: str,
block: str,
expand: bool = False,
utilization: bool = False,
authorization: str = Header(None),
space: str = Path(..., description="Name of the target Space"),
block: str = Path(..., description="Name of the target Block"),
expand: bool = Query(False, description="Expand network references to full network objects"),
utilization: bool = Query(False, description="Append utilization information for each network"),
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
@ -747,9 +748,10 @@ async def get_block(
error_msg = "Error deleting block, please try again."
)
async def delete_block(
space: str,
block: str,
force: Optional[bool] = False,
space: str = Path(..., description="Name of the target Space"),
block: str = Path(..., description="Name of the target Block"),
force: Optional[bool] = Query(False, description="Forcefully delete a Block with existing networks and/or reservations"),
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
@ -793,10 +795,10 @@ async def delete_block(
status_code = 200
)
async def available_block_nets(
space: str,
block: str,
expand: bool = False,
authorization: str = Header(None),
space: str = Path(..., description="Name of the target Space"),
block: str = Path(..., description="Name of the target Block"),
expand: bool = Query(False, description="Expand network references to full network objects"),
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
@ -860,10 +862,10 @@ async def available_block_nets(
status_code = 200
)
async def available_block_nets(
space: str,
block: str,
expand: bool = False,
authorization: str = Header(None),
space: str = Path(..., description="Name of the target Space"),
block: str = Path(..., description="Name of the target Block"),
expand: bool = Query(False, description="Expand network references to full network objects"),
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
@ -911,10 +913,10 @@ async def available_block_nets(
error_msg = "Error adding network to block, please try again."
)
async def create_block_net(
space: str,
block: str,
vnet: VNet,
authorization: str = Header(None),
space: str = Path(..., description="Name of the target Space"),
block: str = Path(..., description="Name of the target Block"),
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
@ -955,6 +957,8 @@ async def create_block_net(
raise HTTPException(status_code=400, detail="Network CIDR not within block CIDR.")
block_net_cidrs = []
resv_cidrs = IPSet(x['cidr'] for x in target_block['resv'])
block_net_cidrs += resv_cidrs
for v in target_block['vnets']:
target = next((x for x in net_list if x['id'].lower() == v['id'].lower()), None)
@ -966,7 +970,7 @@ async def create_block_net(
cidr_overlap = IPSet(block_net_cidrs) & IPSet([target_cidr])
if cidr_overlap:
raise HTTPException(status_code=400, detail="Block already contains network(s) within the CIDR range of target network.")
raise HTTPException(status_code=400, detail="Block already contains network(s) and/or reservation(s) within the CIDR range of target network.")
vnet.active = True
target_block['vnets'].append(jsonable_encoder(vnet))
@ -987,18 +991,17 @@ async def create_block_net(
error_msg = "Error updating block networks, please try again."
)
async def update_block_vnets(
space: str,
block: str,
vnets: VNetsUpdate,
authorization: str = Header(None),
space: str = Path(..., description="Name of the target Space"),
block: str = Path(..., description="Name of the target Block"),
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
"""
Replace the list of networks currently associated to the target Block with the following information:
- Array **[]** of:
- **<str>**: Azure Resource ID
- **[<str>]**: Array of Azure Resource ID's
"""
if not is_admin:
@ -1027,6 +1030,7 @@ async def update_block_vnets(
outside_block_cidr = []
net_ipset = IPSet([])
net_overlap = False
resv_ipset = IPSet(x['cidr'] for x in target_block['resv'])
for v in vnets:
target_net = next((x for x in net_list if x['id'].lower() == v.lower()), None)
@ -1047,6 +1051,9 @@ async def update_block_vnets(
if net_overlap:
raise HTTPException(status_code=400, detail="Network list contains overlapping CIDRs.")
if (net_ipset & resv_ipset):
raise HTTPException(status_code=400, detail="Network list contains CIDR(s) that overlap outstanding reservations.")
if len(outside_block_cidr) > 0:
raise HTTPException(status_code=400, detail="Network CIDR(s) not within Block CIDR: {}".format(outside_block_cidr))
@ -1080,9 +1087,10 @@ async def update_block_vnets(
error_msg = "Error removing block network(s), please try again."
)
async def delete_block_nets(
space: str,
block: str,
req: VNetsUpdate,
space: str = Path(..., description="Name of the target Space"),
block: str = Path(..., description="Name of the target Block"),
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
@ -1134,9 +1142,9 @@ async def delete_block_nets(
status_code = 200
)
async def get_block_reservations(
space: str,
block: str,
authorization: str = Header(None),
space: str = Path(..., description="Name of the target Space"),
block: str = Path(..., description="Name of the target Block"),
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
@ -1175,10 +1183,10 @@ async def get_block_reservations(
error_msg = "Error creating cidr reservation, please try again."
)
async def create_block_reservation(
space: str,
block: str,
req: BlockCIDRReq,
authorization: str = Header(None),
space: str = Path(..., description="Name of the target Space"),
block: str = Path(..., description="Name of the target Block"),
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id)
):
"""
@ -1271,10 +1279,10 @@ async def create_block_reservation(
error_msg = "Error removing block reservation(s), please try again."
)
async def delete_block_reservations(
space: str,
block: str,
req: DeleteResvReq,
authorization: str = Header(None),
space: str = Path(..., description="Name of the target Space"),
block: str = Path(..., description="Name of the target Block"),
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):

Просмотреть файл

@ -34,7 +34,7 @@ router = APIRouter(
)
async def next_available_subnet(
req: SubnetCIDRReq,
authorization: str = Header(None)
authorization: str = Header(None, description="Azure Bearer token"),
):
"""
Get the next available Subnet CIDR in a Virtual Network with the following information:

Просмотреть файл

@ -93,6 +93,7 @@ async def scrub_patch(patch):
status_code = 200
)
async def get_users(
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id),
is_admin: str = Depends(get_admin)
):
@ -133,7 +134,7 @@ async def get_users(
error_msg = "Error fetching user, please try again."
)
async def get_user(
authorization: str = Header(None),
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id)
):
"""
@ -178,7 +179,7 @@ async def get_user(
)
async def update_user(
updates: UserUpdate,
authorization: str = Header(None),
authorization: str = Header(None, description="Azure Bearer token"),
tenant_id: str = Depends(get_tenant_id)
):
"""
@ -186,8 +187,6 @@ async def update_user(
- **[<JSON Patch>]**: Array of JSON Patches
 
Allowed operations:
- **replace**

Просмотреть файл

@ -8,6 +8,7 @@ import {
fetchVHubs,
fetchSubnets,
fetchEndpoints,
fetchNetworks,
refreshAll,
getMe
} from './ipamAPI';
@ -84,6 +85,15 @@ export const fetchEndpointsAsync = createAsyncThunk(
}
);
export const fetchNetworksAsync = createAsyncThunk(
'ipam/fetchNetworks',
async (token) => {
const response = await fetchNetworks(token);
// The value we return becomes the `fulfilled` action payload
return response;
}
);
export const refreshAllAsync = createAsyncThunk(
'ipam/refreshAll',
async (token) => {
@ -142,7 +152,7 @@ export const ipamSlice = createSlice({
const vnets = action.payload.map((vnet) => {
vnet.available = (vnet.size - vnet.used);
vnet.utilization = Math.round((vnet.used / vnet.size) * 100);
vnet.prefixes = vnet.prefixes.join(", ");
// vnet.prefixes = vnet.prefixes.join(", ");
return vnet;
});
@ -163,6 +173,53 @@ export const ipamSlice = createSlice({
.addCase(fetchEndpointsAsync.fulfilled, (state, action) => {
state.endpoints = action.payload;
})
.addCase(fetchNetworksAsync.fulfilled, (state, action) => {
const vNetProvider = "Microsoft.Network/virtualNetworks";
const vHubProvider = "Microsoft.Network/virtualHubs";
const vNetData = action.payload.filter((x) => x.id.toLowerCase().includes(vNetProvider.toLowerCase()));
const vHubData = action.payload.filter((x) => x.id.toLowerCase().includes(vHubProvider.toLowerCase()));
const vnets = vNetData.map((vnet) => {
vnet.available = (vnet.size - vnet.used);
vnet.utilization = Math.round((vnet.used / vnet.size) * 100);
// vnet.prefixes = vnet.prefixes.join(", ");
return vnet;
});
state.vNets = vnets;
const subnets = vNetData.map((vnet) => {
var subnetArray = [];
vnet.subnets.forEach((subnet) => {
const subnetDetails = {
name: subnet.name,
id: `${vnet.id}/subnets/${subnet.name}`,
prefix: subnet.prefix,
resource_group: vnet.resource_group,
subscription_id: vnet.subscription_id,
tenant_id: vnet.tenant_id,
vnet_name: vnet.name,
vnet_id: vnet.id,
used: subnet.used,
size: subnet.size,
available: (subnet.size - subnet.used),
utilization: Math.round((subnet.used / subnet.size) * 100),
type: subnetMap[subnet.type]
};
subnetArray.push(subnetDetails);
});
return subnetArray;
}).flat();
state.subnets = subnets;
state.vHubs = vHubData;
})
.addCase(refreshAllAsync.fulfilled, (state, action) => {
const vNetProvider = "Microsoft.Network/virtualNetworks";
const vHubProvider = "Microsoft.Network/virtualHubs";