diff --git a/server/routers/siteResource/createSiteResource.ts b/server/routers/siteResource/createSiteResource.ts index d3e32babd..d220a4b08 100644 --- a/server/routers/siteResource/createSiteResource.ts +++ b/server/routers/siteResource/createSiteResource.ts @@ -49,7 +49,7 @@ const createSiteResourceSchema = z name: z.string().min(1).max(255), niceId: z.string().optional(), // protocol: z.enum(["tcp", "udp"]).optional(), - mode: z.enum(["host", "cidr", "http", "ssh"]), + mode: z.enum(["host", "cidr", "http", "ssh", "inference"]), ssl: z.boolean().optional(), // only used for http mode scheme: z.enum(["http", "https"]).optional(), siteIds: z.array(z.int()).optional(), @@ -171,6 +171,9 @@ const createSiteResourceSchema = z ) .refine( (data) => { + if (data.mode == "inference") { + return true; + } return ( (data.siteIds !== undefined && data.siteIds.length > 0) || data.siteId !== undefined @@ -533,21 +536,24 @@ export async function createSiteResource( let newSiteResource: SiteResource | undefined; try { await db.transaction(async (trx) => { - const [network] = await trx - .insert(networks) - .values({ - scope: "resource", - orgId: orgId - }) - .returning(); + let network: typeof networks.$inferSelect | undefined; + if (mode !== "inference") { + [network] = await trx + .insert(networks) + .values({ + scope: "resource", + orgId: orgId + }) + .returning(); - if (!network) { - return next( - createHttpError( - HttpCode.INTERNAL_SERVER_ERROR, - `Failed to create network` - ) - ); + if (!network) { + return next( + createHttpError( + HttpCode.INTERNAL_SERVER_ERROR, + `Failed to create network` + ) + ); + } } let tcpPortRangeStringAdjusted = tcpPortRangeString; @@ -566,7 +572,7 @@ export async function createSiteResource( name, mode, ssl, - networkId: network.networkId, + networkId: network ? network.networkId : null, destination: destination, // the ssh can be null scheme, destinationPort, @@ -582,7 +588,8 @@ export async function createSiteResource( (mode == "http" || mode == "ssh" ? true : false), // default to true for http resources, otherwise false domainId, subdomain: finalSubdomain, - fullDomain + fullDomain, + requiresExitNodeConnection: mode === "inference" // in the future we might want to have different modes that do this }; if (isLicensedSshPam) { if (authDaemonPort !== undefined) @@ -600,11 +607,13 @@ export async function createSiteResource( //////////////////// update the associations //////////////////// - for (const siteId of siteIds) { - await trx.insert(siteNetworks).values({ - siteId: siteId, - networkId: network.networkId - }); + if (network) { + for (const siteId of siteIds) { + await trx.insert(siteNetworks).values({ + siteId: siteId, + networkId: network.networkId + }); + } } const [adminRole] = await trx diff --git a/server/routers/siteResource/updateSiteResource.ts b/server/routers/siteResource/updateSiteResource.ts index 7b0ef0783..1b79e7b16 100644 --- a/server/routers/siteResource/updateSiteResource.ts +++ b/server/routers/siteResource/updateSiteResource.ts @@ -50,7 +50,7 @@ const updateSiteResourceSchema = z ) .optional(), // mode: z.enum(["host", "cidr", "port"]).optional(), - mode: z.enum(["host", "cidr", "http", "ssh"]).optional(), + mode: z.enum(["host", "cidr", "http", "ssh", "inference"]).optional(), ssl: z.boolean().optional(), scheme: z.enum(["http", "https"]).nullish(), destinationPort: z.int().positive().nullish(), @@ -173,6 +173,9 @@ const updateSiteResourceSchema = z ) .refine( (data) => { + if (data.mode == "inference") { + return true; + } // if neither is provided, the existing site associations are left unchanged if (data.siteIds === undefined && data.siteId === undefined) { return true; @@ -579,13 +582,15 @@ export async function updateSiteResource( disableIcmp: mode !== undefined ? disableIcmp || - (mode == "http" || mode == "ssh" - ? true - : false) + (mode == "http" || mode == "ssh" ? true : false) : disableIcmp, domainId, subdomain: finalSubdomain, fullDomain, + networkId: + mode === "inference" ? null : undefined, + requiresExitNodeConnection: + mode !== undefined ? mode === "inference" : undefined, ...sshPamSet }) .where(and(eq(siteResources.siteResourceId, siteResourceId))) @@ -593,7 +598,20 @@ export async function updateSiteResource( //////////////////// update the associations //////////////////// - if (siteIds !== undefined) { + if (mode === "inference") { + // inference resources are not attached to any site network + if (existingSiteResource.networkId) { + await trx + .delete(siteNetworks) + .where( + eq( + siteNetworks.networkId, + existingSiteResource.networkId + ) + ); + } + updatedSiteIds = []; + } else if (siteIds !== undefined) { // delete the site - site resources associations await trx .delete(siteNetworks)