Skip to content

Commit

Permalink
Merge pull request #418 from sinamics/assign-ip-by-index
Browse files Browse the repository at this point in the history
Assign unused subnet automatically
  • Loading branch information
sinamics authored May 19, 2024
2 parents bd15710 + 727fc31 commit 8d26add
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/components/networkByIdPage/ipv4Assignment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export const Ipv4Assignment = ({ central = false, organizationId }: IProp) => {
return (
<div>
{/* if network.duplicateRoutes.length > 0 show badge */}
{network?.duplicateRoutes.length > 0 ? (
{network?.duplicateRoutes?.length > 0 ? (
<div role="alert" className="alert bg-base-100 mb-5">
<svg
xmlns="http://www.w3.org/2000/svg"
Expand Down
4 changes: 3 additions & 1 deletion src/server/api/routers/networkRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export const networkRouter = createTRPCRouter({
if (input.central) {
return await ztController.get_controller_networks(ctx, input.central);
}

const networks = await ctx.prisma.network.findMany({
where: {
authorId: ctx.session.user.id,
Expand Down Expand Up @@ -139,7 +140,7 @@ export const networkRouter = createTRPCRouter({
);

// Generate CIDR options for IP configuration
const { cidrOptions } = IPv4gen(null);
const { cidrOptions } = IPv4gen(null, []);

/**
* Merging logic to ensure that members who only exist in local database ( added manually ) are also included in the response
Expand Down Expand Up @@ -541,6 +542,7 @@ export const networkRouter = createTRPCRouter({
// generate network params
const { ipAssignmentPools, routes, v4AssignMode } = IPv4gen(
input.updateParams.routes[0].target,
[],
);

// prepare update params
Expand Down
18 changes: 17 additions & 1 deletion src/server/api/routers/organizationRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { throwError } from "~/server/helpers/errorHandler";
import { sendWebhook } from "~/utils/webhook";
import { nameGeneratorConfig } from "../services/networkService";
import rateLimit from "~/utils/rateLimit";
import { RoutesEntity } from "~/types/local/network";

// Create a Zod schema for the HookType enum
const HookTypeEnum = z.enum(Object.values(HookType) as [HookType, ...HookType[]]);
Expand Down Expand Up @@ -353,8 +354,22 @@ export const organizationRouter = createTRPCRouter({
},
});

// get used IPs from the database
const usedCidr = await ctx.prisma.network.findMany({
where: {
organizationId: input.organizationId,
},
select: {
routes: true,
},
});
// Extract the target from the routes
const usedIPs = usedCidr.map((nw) =>
(nw.routes as RoutesEntity[])?.map((r) => r.target),
);

// Generate ipv4 address, cidr, start & end
const ipAssignmentPools = IPv4gen(null);
const ipAssignmentPools = IPv4gen(null, usedIPs);

if (!input?.networkName) {
// Generate adjective and noun word
Expand All @@ -378,6 +393,7 @@ export const organizationRouter = createTRPCRouter({
name: input.networkName,
nwid: newNw.nwid,
description: input.orgName,
routes: ipAssignmentPools.routes,
},
},
},
Expand Down
15 changes: 14 additions & 1 deletion src/server/api/services/networkService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,21 @@ export const networkProvisioningFactory = async ({ ctx, input }) => {
);
}
}
// get used IPs from the database
const usedCidr = await ctx.prisma.network.findMany({
where: {
authorId: ctx.session.user.id,
},
select: {
routes: true,
},
});
// Extract the target from the routes
const usedIPs = usedCidr.map((nw) => nw.routes?.map((r) => r.target));

// Flatten the array
// Generate ipv4 address, cidr, start & end
const ipAssignmentPools = IPv4gen(null);
const ipAssignmentPools = IPv4gen(null, usedIPs, input.central);

if (!input?.name) {
// Generate adjective and noun word
Expand All @@ -74,6 +86,7 @@ export const networkProvisioningFactory = async ({ ctx, input }) => {
create: {
name: newNw.name,
nwid: newNw.nwid,
routes: ipAssignmentPools.routes,
},
},
},
Expand Down
46 changes: 41 additions & 5 deletions src/utils/IPv4gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,48 @@ const cidrOptions = [
"172.25.30.0/24",
];

const generateCidr = () => {
return cidrOptions[Math.floor(Math.random() * cidrOptions.length)];
};
const generateCidr = (usedCidr: string[][], getRandom = false) => {
// If getRandom is true, return one randomly
if (getRandom) {
return cidrOptions[Math.floor(Math.random() * cidrOptions.length)];
}

// Flatten the usedCidr array
const flattenedUsedCidr = usedCidr.flat();

// Count the frequency of each CIDR in the usedCidr array
const cidrFrequency: { [key: string]: number } = {};
for (const cidr of flattenedUsedCidr) {
if (cidrFrequency[cidr]) {
cidrFrequency[cidr]++;
} else {
cidrFrequency[cidr] = 1;
}
}

// Filter the available CIDRs
const availableCidr = cidrOptions.filter((cidr) => !flattenedUsedCidr.includes(cidr));

export const IPv4gen = (CIDR: string | null) => {
const cidr = CIDR ? CIDR : generateCidr();
// If there are available CIDRs, return the first one
if (availableCidr.length > 0) {
return availableCidr[0];
}

// If no available CIDRs, find the CIDR with the fewest occurrences
let leastUsedCidr = cidrOptions[0];
let minCount = Infinity;
for (const cidr of cidrOptions) {
const count = cidrFrequency[cidr] || 0;
if (count < minCount) {
minCount = count;
leastUsedCidr = cidr;
}
}

return leastUsedCidr;
};
export const IPv4gen = (CIDR: string | null, usedCidr, getRandom = false) => {
const cidr = CIDR ? CIDR : generateCidr(usedCidr, getRandom);

const [start, prefix] = cidr.split("/");
const host32 = ((1 << (32 - parseInt(prefix))) - 1) >>> 0;
Expand Down
5 changes: 4 additions & 1 deletion src/utils/ztApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,10 @@ export const central_network_detail = async (
: [];

// Get available cidr options.
const ipAssignmentPools = IPv4gen(null);
const getRandomCidr = true;
const usedIps = [];
const ipAssignmentPools = IPv4gen(null, usedIps, getRandomCidr);

const { cidrOptions } = ipAssignmentPools;
const { id: networkId, config: networkConfig, ...restData } = network;

Expand Down

0 comments on commit 8d26add

Please sign in to comment.