Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions rest-api/api/pkg/api/handler/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,8 @@ func (cih CreateInstanceHandler) Handle(c echo.Context) error {

subnetIDs := []uuid.UUID{}
vpcPrefixIDs := []uuid.UUID{}
subnetIfcMap := map[uuid.UUID]int{}
vpcPrefixIfcMap := map[uuid.UUID]int{}

for _, ifc := range apiRequest.Interfaces {
if ifc.SubnetID != nil {
Expand All @@ -413,6 +415,7 @@ func (cih CreateInstanceHandler) Handle(c echo.Context) error {
return cutil.NewAPIErrorResponse(c, http.StatusBadRequest, fmt.Sprintf("Subnet ID: %s specified in interfaces data in request is not valid", *ifc.SubnetID), nil)
}
subnetIDs = append(subnetIDs, subnetID)
subnetIfcMap[subnetID]++
}
if ifc.VpcPrefixID != nil {
vpcPrefixID, err := uuid.Parse(*ifc.VpcPrefixID)
Expand All @@ -421,6 +424,7 @@ func (cih CreateInstanceHandler) Handle(c echo.Context) error {
return cutil.NewAPIErrorResponse(c, http.StatusBadRequest, fmt.Sprintf("VPC Prefix ID: %s specified in interfaces data in request is not valid", *ifc.VpcPrefixID), nil)
}
vpcPrefixIDs = append(vpcPrefixIDs, vpcPrefixID)
vpcPrefixIfcMap[vpcPrefixID]++
}
}

Expand Down Expand Up @@ -479,6 +483,30 @@ func (cih CreateInstanceHandler) Handle(c echo.Context) error {
return cutil.NewAPIErrorResponse(c, http.StatusBadRequest, fmt.Sprintf("Primary VPC ID: %s for Instance must not be listed in `secondaryVpcIds`", vpc.ID), nil)
}

subnetsForUsage := make([]*cdbm.Subnet, 0, len(subnetIfcMap))
for subnetID := range subnetIfcMap {
if sn, ok := subnetIDMap[subnetID]; ok {
subnetsForUsage = append(subnetsForUsage, sn)
}
}
subnetUsageMap, usageErr := sbDAO.GetPrefixUsage(ctx, nil, subnetsForUsage...)
if usageErr != nil {
logger.Error().Err(usageErr).Msg("error getting prefix usage for Subnets")
return cutil.NewAPIErrorResponse(c, http.StatusInternalServerError, "Failed to get prefix usage for Subnet", nil)
}

vpcPrefixesForUsage := make([]*cdbm.VpcPrefix, 0, len(vpcPrefixIfcMap))
for vpcPrefixID := range vpcPrefixIfcMap {
if vp, ok := vpcPrefixIDMap[vpcPrefixID]; ok {
vpcPrefixesForUsage = append(vpcPrefixesForUsage, vp)
}
}
vpcPrefixUsageMap, vpUsageErr := vpDAO.GetPrefixUsage(ctx, nil, vpcPrefixesForUsage...)
if vpUsageErr != nil {
logger.Error().Err(vpUsageErr).Msg("error getting prefix usage for VPC Prefixes")
return cutil.NewAPIErrorResponse(c, http.StatusInternalServerError, "Failed to get prefix usage for VPC Prefix", nil)
}

for _, ifc := range apiRequest.Interfaces {
if ifc.SubnetID != nil {
subnetID := uuid.MustParse(*ifc.SubnetID)
Expand Down Expand Up @@ -509,6 +537,14 @@ func (cih CreateInstanceHandler) Handle(c echo.Context) error {
return cutil.NewAPIErrorResponse(c, http.StatusBadRequest, fmt.Sprintf("VPC: %v specified in request must have Ethernet network virtualization type in order to create Subnet based interfaces", vpc.ID), nil)
}

// Check if Subnet is exhausted
incomingInterfaceIPs := subnetIfcMap[subnetID]
subnetUsage := subnetUsageMap[subnetID]
if subnetUsage != nil && subnetUsage.AvailableIPs > 0 && subnetUsage.AcquiredIPs+uint64(incomingInterfaceIPs) > subnetUsage.AvailableIPs {
logger.Warn().Msg(fmt.Sprintf("Ip Addresses for Subnet ID: %v specified in interfaces data in request are exhausted", subnetID))
return cutil.NewAPIErrorResponse(c, http.StatusBadRequest, fmt.Sprintf("Ip Addresses for Subnet ID: %v specified in interfaces data in request are exhausted", subnetID), nil)
}

dbInterfaces = append(dbInterfaces, cdbm.Interface{
SubnetID: &subnetID,
IsPhysical: ifc.IsPhysical,
Expand Down Expand Up @@ -580,6 +616,14 @@ func (cih CreateInstanceHandler) Handle(c echo.Context) error {
return cutil.NewAPIErrorResponse(c, http.StatusBadRequest, fmt.Sprintf("VPC: %v specified in request must have FNN network virtualization type in order to create VPC Prefix based interfaces", vpc.ID), nil)
}

// Check if VPC Prefix is exhausted
incomingInterfaceIPs := vpcPrefixIfcMap[vpcPrefixID]
vpUsage := vpcPrefixUsageMap[vpcPrefixID]
if vpUsage != nil && vpUsage.AvailableIPs > 0 && vpUsage.AcquiredIPs+uint64(incomingInterfaceIPs)*2 > vpUsage.AvailableIPs {
logger.Warn().Msg(fmt.Sprintf("Ip Addresses for VPC Prefix ID: %v specified in interfaces data in request are exhausted", vpcPrefixID))
return cutil.NewAPIErrorResponse(c, http.StatusBadRequest, fmt.Sprintf("Ip Addresses for VPC Prefix ID: %v specified in interfaces data in request are exhausted", vpcPrefixID), nil)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider more specific info in the error message:

  • the number of IP addresses remaining in the VPC prefix
  • the number of interfaces specified in the request (N)
  • the number of IP addresses required to create those specified interfaces (2N)

That would help the user better define their interfaces in a way that makes use of the remaining IP space in the prefix if they wish to do so.

Something similar might be helpful for subnets, but those of course are more straightforward in that one interface uses one IP address.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @nvlitagaki , since we are raising error for IP Address exhaust, the number of IP addresses required to create those specified interfaces (2N) could be helpful or just return the current usage along with it? cc @thossain-nv

}

dbInterfaces = append(dbInterfaces, cdbm.Interface{
VpcPrefixID: &vpcPrefixID,
VpcPrefix: vpcPrefix, // We attach this here so it can be used when we convert to the API model.
Expand Down Expand Up @@ -2262,6 +2306,8 @@ func (uih UpdateInstanceHandler) Handle(c echo.Context) error {
// Collect all Subnet and VPC Prefix IDs for batch query
subnetIDs := []uuid.UUID{}
vpcPrefixIDs := []uuid.UUID{}
subnetIfcMap := map[uuid.UUID]int{}
vpcPrefixIfcMap := map[uuid.UUID]int{}

for _, ifc := range apiRequest.Interfaces {
if ifc.SubnetID != nil {
Expand All @@ -2271,6 +2317,7 @@ func (uih UpdateInstanceHandler) Handle(c echo.Context) error {
return cutil.NewAPIErrorResponse(c, http.StatusBadRequest, "Subnet ID specified in request data is not valid", nil)
}
subnetIDs = append(subnetIDs, subnetID)
subnetIfcMap[subnetID]++
}
if ifc.VpcPrefixID != nil {
vpcPrefixID, err := uuid.Parse(*ifc.VpcPrefixID)
Expand All @@ -2279,6 +2326,7 @@ func (uih UpdateInstanceHandler) Handle(c echo.Context) error {
return cutil.NewAPIErrorResponse(c, http.StatusBadRequest, "VPC Prefix ID specified in request data is not valid", nil)
}
vpcPrefixIDs = append(vpcPrefixIDs, vpcPrefixID)
vpcPrefixIfcMap[vpcPrefixID]++
}
}

Expand Down Expand Up @@ -2308,6 +2356,26 @@ func (uih UpdateInstanceHandler) Handle(c echo.Context) error {
}
}

existingSubnetIfcMap := map[uuid.UUID]int{}
existingVpcPrefixIfcMap := map[uuid.UUID]int{}
if len(apiRequest.Interfaces) > 0 {
ifcDAO := cdbm.NewInterfaceDAO(uih.dbSession)
existingIfcsForCapacity, _, err := ifcDAO.GetAll(ctx, nil, cdbm.InterfaceFilterInput{InstanceIDs: []uuid.UUID{instance.ID}}, cdbp.PageInput{Limit: cutil.GetPtr(cdbp.TotalLimit)}, nil)
if err != nil {
logger.Error().Err(err).Msg("error retrieving existing Interfaces for Instance")
return cutil.NewAPIErrorResponse(c, http.StatusInternalServerError, "Failed to retrieve existing Interfaces for Instance", nil)
}
for i := range existingIfcsForCapacity {
eifc := &existingIfcsForCapacity[i]
if eifc.SubnetID != nil {
existingSubnetIfcMap[*eifc.SubnetID]++
}
if eifc.VpcPrefixID != nil {
existingVpcPrefixIfcMap[*eifc.VpcPrefixID]++
}
}
}

// Validate each Interface against fetched data
dbInterfaces := []cdbm.Interface{}
isDeviceInfoPresent := false
Expand Down Expand Up @@ -2337,6 +2405,30 @@ func (uih UpdateInstanceHandler) Handle(c echo.Context) error {
return cutil.NewAPIErrorResponse(c, http.StatusBadRequest, fmt.Sprintf("Primary VPC ID: %s for Instance must not be listed in `secondaryVpcIds`", vpc.ID), nil)
}

subnetsForUsage := make([]*cdbm.Subnet, 0, len(subnetIfcMap))
for subnetID := range subnetIfcMap {
if sn, ok := subnetIDMap[subnetID]; ok {
subnetsForUsage = append(subnetsForUsage, sn)
}
}
subnetUsageMap, usageErr := sbDAO.GetPrefixUsage(ctx, nil, subnetsForUsage...)
if usageErr != nil {
logger.Error().Err(usageErr).Msg("error getting prefix usage for Subnets")
return cutil.NewAPIErrorResponse(c, http.StatusInternalServerError, "Failed to get prefix usage for Subnet", nil)
}

vpcPrefixesForUsage := make([]*cdbm.VpcPrefix, 0, len(vpcPrefixIfcMap))
for vpcPrefixID := range vpcPrefixIfcMap {
if vp, ok := vpcPrefixIDMap[vpcPrefixID]; ok {
vpcPrefixesForUsage = append(vpcPrefixesForUsage, vp)
}
}
vpcPrefixUsageMap, vpUsageErr := vpDAO.GetPrefixUsage(ctx, nil, vpcPrefixesForUsage...)
if vpUsageErr != nil {
logger.Error().Err(vpUsageErr).Msg("error getting prefix usage for VPC Prefixes")
return cutil.NewAPIErrorResponse(c, http.StatusInternalServerError, "Failed to get prefix usage for VPC Prefix", nil)
}

for _, ifc := range apiRequest.Interfaces {
if ifc.SubnetID != nil {
subnetID := uuid.MustParse(*ifc.SubnetID)
Expand Down Expand Up @@ -2366,6 +2458,14 @@ func (uih UpdateInstanceHandler) Handle(c echo.Context) error {
return cutil.NewAPIErrorResponse(c, http.StatusBadRequest, fmt.Sprintf("VPC: %v specified in request must have Ethernet network virtualization type in order to create Subnet based interfaces", instance.VpcID), nil)
}

// Check if Subnet is exhausted
incomingInterfaceIPs := subnetIfcMap[subnetID] - existingSubnetIfcMap[subnetID]
subnetUsage := subnetUsageMap[subnetID]
if subnetUsage != nil && subnetUsage.AvailableIPs > 0 && subnetUsage.AcquiredIPs+uint64(incomingInterfaceIPs) > subnetUsage.AvailableIPs {
logger.Warn().Msg(fmt.Sprintf("Ip Addresses for Subnet ID: %v specified in interfaces data in request are exhausted", subnetID))
return cutil.NewAPIErrorResponse(c, http.StatusBadRequest, fmt.Sprintf("Ip Addresses for Subnet ID: %v specified in interfaces data in request are exhausted", subnetID), nil)
}

dbInterfaces = append(dbInterfaces, cdbm.Interface{
SubnetID: &subnetID,
IsPhysical: ifc.IsPhysical,
Expand Down Expand Up @@ -2436,6 +2536,14 @@ func (uih UpdateInstanceHandler) Handle(c echo.Context) error {
return cutil.NewAPIErrorResponse(c, http.StatusBadRequest, fmt.Sprintf("VPC: %v specified in request must have FNN network virtualization type in order to create VPC Prefix based interfaces", instance.VpcID), nil)
}

// Check if VPC Prefix is exhausted
incomingInterfaceIPs := vpcPrefixIfcMap[vpcPrefixID] - existingVpcPrefixIfcMap[vpcPrefixID]
vpUsage := vpcPrefixUsageMap[vpcPrefixID]
if vpUsage != nil && vpUsage.AvailableIPs > 0 && vpUsage.AcquiredIPs+uint64(incomingInterfaceIPs)*2 > vpUsage.AvailableIPs {
logger.Warn().Msg(fmt.Sprintf("Ip Addresses for VPC Prefix ID: %v specified in interfaces data in request are exhausted", vpcPrefixID))
return cutil.NewAPIErrorResponse(c, http.StatusBadRequest, fmt.Sprintf("Ip Addresses for VPC Prefix ID: %v specified in interfaces data in request are exhausted", vpcPrefixID), nil)
}

dbInterfaces = append(dbInterfaces, cdbm.Interface{
VpcPrefixID: &vpcPrefixID,
VpcPrefix: vpcPrefix, // We attach this here so it can be used when we convert to the API model.
Expand Down
97 changes: 96 additions & 1 deletion rest-api/api/pkg/api/handler/instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ func testInstanceBuildVPC(t *testing.T, dbSession *cdb.Session, name string, ip

func testInstanceBuildSubnet(t *testing.T, dbSession *cdb.Session, name string, tn *cdbm.Tenant, vpc *cdbm.Vpc, cnsID *uuid.UUID, status string, user *cdbm.User) *cdbm.Subnet {
subnetDAO := cdbm.NewSubnetDAO(dbSession)
ipv4Prefix := fmt.Sprintf("10.%d.0.0/24", (int(name[0])+len(name))%200+1)

subnet, err := subnetDAO.Create(context.Background(), nil, cdbm.SubnetCreateInput{
Name: name,
Expand All @@ -288,7 +289,8 @@ func testInstanceBuildSubnet(t *testing.T, dbSession *cdb.Session, name string,
VpcID: vpc.ID,
TenantID: tn.ID,
ControllerNetworkSegmentID: cnsID,
PrefixLength: 0,
IPv4Prefix: &ipv4Prefix,
PrefixLength: 24,
Status: status,
CreatedBy: user.ID,
})
Expand Down Expand Up @@ -772,6 +774,12 @@ func TestCreateInstanceHandler_Handle(t *testing.T) {
alc1 := testInstanceSiteBuildAllocationContraints(t, dbSession, al1, cdbm.AllocationResourceTypeInstanceType, ist1.ID, cdbm.AllocationConstraintTypeReserved, 9, ipu)
assert.NotNil(t, alc1)

// Dedicated instance type for IP-exhaustion fixtures; must not consume ist1 allocation (limit 9).
istExhaustFixture := testInstanceBuildInstanceType(t, dbSession, ip, "test-instance-type-exhaust-fixture", st1, cdbm.InstanceStatusReady)
assert.NotNil(t, istExhaustFixture)
alcExhaustFixture := testInstanceSiteBuildAllocationContraints(t, dbSession, al1, cdbm.AllocationResourceTypeInstanceType, istExhaustFixture.ID, cdbm.AllocationConstraintTypeReserved, 30, ipu)
assert.NotNil(t, alcExhaustFixture)

Comment thread
coderabbitai[bot] marked this conversation as resolved.
mc1 := testInstanceBuildMachine(t, dbSession, ip.ID, st1.ID, cutil.GetPtr(false), nil)
assert.NotNil(t, mc1)

Expand Down Expand Up @@ -884,6 +892,27 @@ func TestCreateInstanceHandler_Handle(t *testing.T) {
subnetPending := testInstanceBuildSubnet(t, dbSession, "test-subnet-5", tn1, vpcSiteReady, nil, cdbm.SubnetStatusPending, tnu1)
assert.NotNil(t, subnetPending)

subnetExhaustedIPv4 := "10.99.0.0/28"
subnetExhausted, err := cdbm.NewSubnetDAO(dbSession).Create(context.Background(), nil, cdbm.SubnetCreateInput{
Name: "test-subnet-exhausted",
Description: cutil.GetPtr("Test Subnet exhausted"),
Org: tn1.Org,
SiteID: vpc1.SiteID,
VpcID: vpc1.ID,
TenantID: tn1.ID,
ControllerNetworkSegmentID: cutil.GetPtr(uuid.New()),
IPv4Prefix: &subnetExhaustedIPv4,
PrefixLength: 28,
Status: cdbm.SubnetStatusReady,
CreatedBy: tnu1.ID,
})
assert.Nil(t, err)
assert.NotNil(t, subnetExhausted)
for i := 0; i < 14; i++ {
exhaustInst := testInstanceBuildInstance(t, dbSession, fmt.Sprintf("exhaust-subnet-inst-%d", i), tn1.ID, ip.ID, st1.ID, &istExhaustFixture.ID, vpc1.ID, nil, &os1.ID, nil, cdbm.InstanceStatusReady)
testInstanceBuildInstanceInterface(t, dbSession, exhaustInst.ID, &subnetExhausted.ID, nil, nil, cdbm.InterfaceStatusPending)
}

mci1 := testInstanceBuildMachineInterface(t, dbSession, subnet1.ID, mc1.ID)
assert.NotNil(t, mci1)

Expand Down Expand Up @@ -1148,6 +1177,14 @@ func TestCreateInstanceHandler_Handle(t *testing.T) {
vpcPrefix7 := common.TestBuildVPCPrefix(t, dbSession, "test-vpcprefix-7", st1, tn1, vpc9.ID, &ipb5.ID, cutil.GetPtr("192.168.0.0/24"), cutil.GetPtr(24), cdbm.VpcPrefixStatusReady, tnu1)
vpcPrefixSite2 := common.TestBuildVPCPrefix(t, dbSession, "test-vpcprefix-site2", st2, tn1, vpc9Site2.ID, &ipbSite2.ID, cutil.GetPtr("192.170.0.0/24"), cutil.GetPtr(24), cdbm.VpcPrefixStatusReady, tnu1)
assert.NotNil(t, vpcPrefixSite2)
ipbExhausted := common.TestBuildVpcPrefixIPBlock(t, dbSession, "testipb-exhausted", st1, ip, &tn1.ID, cdbm.IPBlockRoutingTypeDatacenterOnly, "10.99.1.0", 28, cdbm.IPBlockProtocolVersionV4, false, cdbm.IPBlockStatusReady, tnu1)
assert.NotNil(t, ipbExhausted)
vpcPrefixExhausted := common.TestBuildVPCPrefix(t, dbSession, "test-vpcprefix-exhausted", st1, tn1, vpc9.ID, &ipbExhausted.ID, cutil.GetPtr("10.99.1.0/28"), cutil.GetPtr(28), cdbm.VpcPrefixStatusReady, tnu1)
assert.NotNil(t, vpcPrefixExhausted)
for i := 0; i < 8; i++ {
exhaustInst := testInstanceBuildInstance(t, dbSession, fmt.Sprintf("exhaust-vpcprefix-inst-%d", i), tn1.ID, ip.ID, st1.ID, &istExhaustFixture.ID, vpc9.ID, nil, &os1.ID, nil, cdbm.InstanceStatusReady)
testInstanceBuildInstanceInterface(t, dbSession, exhaustInst.ID, nil, &vpcPrefixExhausted.ID, nil, cdbm.InterfaceStatusPending)
}
// NvLink Logical Partition
nvllp1 := testBuildNVLinkLogicalPartition(t, dbSession, "test-nvllp-1", cutil.GetPtr("Test NVLink Logical Partition"), tnOrg, st1, tn1, cutil.GetPtr(cdbm.NVLinkLogicalPartitionStatusReady), false)
assert.NotNil(t, nvllp1)
Expand Down Expand Up @@ -3425,6 +3462,64 @@ func TestCreateInstanceHandler_Handle(t *testing.T) {
wantErr: false,
verifyChildSpanner: true,
},
{
name: "test Instance create API endpoint failed when subnet IP addresses are exhausted",
fields: fields{
dbSession: dbSession,
tc: tc,
cfg: cfg,
},
args: args{
reqData: &model.APIInstanceCreateRequest{
Name: "Test Instance subnet exhausted",
TenantID: tn1.ID.String(),
InstanceTypeID: cutil.GetPtr(ist1.ID.String()),
VpcID: vpc1.ID.String(),
OperatingSystemID: cutil.GetPtr(os1.ID.String()),
IpxeScript: cutil.GetPtr(common.DefaultIpxeScript),
Interfaces: []model.APIInterfaceCreateOrUpdateRequest{
{
SubnetID: cutil.GetPtr(subnetExhausted.ID.String()),
},
},
},
reqOrg: tnOrg,
reqUser: tnu1,
respCode: http.StatusBadRequest,
respMessage: fmt.Sprintf("Ip Addresses for Subnet ID: %v specified in interfaces data in request are exhausted", subnetExhausted.ID),
},
wantErr: false,
},
{
name: "test Instance create API endpoint failed when VPC Prefix IP addresses are exhausted",
fields: fields{
dbSession: dbSession,
tc: tc,
cfg: cfg,
},
args: args{
reqData: &model.APIInstanceCreateRequest{
Name: "Test Instance vpc prefix exhausted",
TenantID: tn1.ID.String(),
InstanceTypeID: cutil.GetPtr(ist1.ID.String()),
VpcID: vpc9.ID.String(),
OperatingSystemID: cutil.GetPtr(os1.ID.String()),
Interfaces: []model.APIInterfaceCreateOrUpdateRequest{
{
VpcPrefixID: cutil.GetPtr(vpcPrefixExhausted.ID.String()),
IsPhysical: true,
Device: cutil.GetPtr("MT42822 BlueField-2 integrated ConnectX-6 Dx network controller"),
DeviceInstance: cutil.GetPtr(0),
},
},
},
reqOrg: tnOrg,
reqUser: tnu1,
respCode: http.StatusBadRequest,
respMessage: fmt.Sprintf("Ip Addresses for VPC Prefix ID: %v specified in interfaces data in request are exhausted", vpcPrefixExhausted.ID),
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
22 changes: 17 additions & 5 deletions rest-api/api/pkg/api/handler/subnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -548,18 +548,24 @@ func (gash GetAllSubnetHandler) Handle(c echo.Context) error {

sbusageMap := map[uuid.UUID]*cip.Usage{}
if includeUsageStats {
subnetsForUsage := make([]*cdbm.Subnet, 0, len(subnets))
for i := range subnets {
sn := &subnets[i]
if sn.IPv4Block == nil {
logger.Error().Str("subnetId", sn.ID.String()).Msg("Subnet missing IPv4 Block relation for usage stats")
continue
}
prefixUsage, serr := sDAO.GetPrefixUsage(ctx, nil, sn)
subnetsForUsage = append(subnetsForUsage, sn)
}
if len(subnetsForUsage) > 0 {
prefixUsageMap, serr := sDAO.GetPrefixUsage(ctx, nil, subnetsForUsage...)
if serr != nil {
logger.Error().Err(serr).Str("subnetId", sn.ID.String()).Msg("error retrieving usage stats for Subnet")
continue
logger.Error().Err(serr).Msg("error retrieving usage stats for Subnets")
} else {
for id, usage := range prefixUsageMap {
sbusageMap[id] = usage
}
}
sbusageMap[sn.ID] = prefixUsage
}
}

Expand Down Expand Up @@ -739,11 +745,17 @@ func (gsh GetSubnetHandler) Handle(c echo.Context) error {
logger.Error().Str("subnetId", subnet.ID.String()).Msg("Subnet missing IPv4 Block relation for usage stats")
return cutil.NewAPIErrorResponse(c, http.StatusInternalServerError, "Failed to retrieve Usage Stats for Subnet", nil)
}
sbusage, err = sDAO.GetPrefixUsage(ctx, nil, subnet)
prefixUsageMap, err := sDAO.GetPrefixUsage(ctx, nil, subnet)
if err != nil {
logger.Error().Err(err).Msg("error retrieving usage stats for Subnet")
return cutil.NewAPIErrorResponse(c, http.StatusInternalServerError, "Failed to retrieve Usage Stats for Subnet", nil)
}
var ok bool
sbusage, ok = prefixUsageMap[subnet.ID]
if !ok {
logger.Error().Str("subnetId", subnet.ID.String()).Msg("Subnet missing IPv4 prefix for usage stats")
return cutil.NewAPIErrorResponse(c, http.StatusInternalServerError, "Failed to retrieve Usage Stats for Subnet", nil)
}
}

// Send response
Expand Down
Loading
Loading