mirror of
https://github.com/fosrl/pangolin.git
synced 2026-07-12 00:42:21 +02:00
Add usage tracking to blueprints
This commit is contained in:
@@ -8,7 +8,7 @@ import {
|
|||||||
userSiteResources,
|
userSiteResources,
|
||||||
clientSiteResources
|
clientSiteResources
|
||||||
} from "@server/db";
|
} from "@server/db";
|
||||||
import { Config, ConfigSchema } from "./types";
|
import { Config, ConfigSchema, isTargetsOnlyResource } from "./types";
|
||||||
import {
|
import {
|
||||||
PublicResourcesResults,
|
PublicResourcesResults,
|
||||||
updatePublicResources
|
updatePublicResources
|
||||||
@@ -34,6 +34,12 @@ import {
|
|||||||
rebuildClientAssociationsFromSiteResource,
|
rebuildClientAssociationsFromSiteResource,
|
||||||
waitForSiteResourceRebuildIdle
|
waitForSiteResourceRebuildIdle
|
||||||
} from "../rebuildClientAssociations";
|
} from "../rebuildClientAssociations";
|
||||||
|
import { build } from "@server/build";
|
||||||
|
import HttpCode from "@server/types/HttpCode";
|
||||||
|
import createHttpError from "http-errors";
|
||||||
|
import next from "next";
|
||||||
|
import { LimitId } from "../billing";
|
||||||
|
import { usageService } from "../billing/usageService";
|
||||||
|
|
||||||
type ApplyBlueprintArgs = {
|
type ApplyBlueprintArgs = {
|
||||||
orgId: string;
|
orgId: string;
|
||||||
@@ -64,6 +70,7 @@ export async function applyBlueprint({
|
|||||||
|
|
||||||
let publicResourcesResults: PublicResourcesResults = [];
|
let publicResourcesResults: PublicResourcesResults = [];
|
||||||
let privateResourcesResults: ClientResourcesResults = [];
|
let privateResourcesResults: ClientResourcesResults = [];
|
||||||
|
|
||||||
await db.transaction(async (trx) => {
|
await db.transaction(async (trx) => {
|
||||||
await updateResourcePolicies(orgId, config, trx);
|
await updateResourcePolicies(orgId, config, trx);
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,12 @@ import { getNextAvailableAliasAddress } from "../ip";
|
|||||||
import { createCertificate } from "#dynamic/routers/certificates/createCertificate";
|
import { createCertificate } from "#dynamic/routers/certificates/createCertificate";
|
||||||
import { isLicensedOrSubscribed } from "#dynamic/lib/isLicencedOrSubscribed";
|
import { isLicensedOrSubscribed } from "#dynamic/lib/isLicencedOrSubscribed";
|
||||||
import { tierMatrix } from "../billing/tierMatrix";
|
import { tierMatrix } from "../billing/tierMatrix";
|
||||||
|
import { build } from "@server/build";
|
||||||
|
import HttpCode from "@server/types/HttpCode";
|
||||||
|
import createHttpError from "http-errors";
|
||||||
|
import next from "next";
|
||||||
|
import { LimitId } from "../billing";
|
||||||
|
import { usageService } from "../billing/usageService";
|
||||||
|
|
||||||
async function getDomainForSiteResource(
|
async function getDomainForSiteResource(
|
||||||
siteResourceId: number | undefined,
|
siteResourceId: number | undefined,
|
||||||
@@ -413,6 +419,34 @@ export async function updatePrivateResources(
|
|||||||
oldSites: existingSiteIds
|
oldSites: existingSiteIds
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
// create a brand new resource
|
||||||
|
|
||||||
|
if (build == "saas") {
|
||||||
|
const usage = await usageService.getUsage(
|
||||||
|
orgId,
|
||||||
|
LimitId.PRIVATE_RESOURCES
|
||||||
|
);
|
||||||
|
if (!usage) {
|
||||||
|
throw new Error(
|
||||||
|
`Usage data not found for org ${orgId} and limit ${LimitId.PRIVATE_RESOURCES}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const rejectResource = await usageService.checkLimitSet(
|
||||||
|
orgId,
|
||||||
|
|
||||||
|
LimitId.PRIVATE_RESOURCES,
|
||||||
|
{
|
||||||
|
...usage,
|
||||||
|
instantaneousValue: (usage.instantaneousValue || 0) + 1
|
||||||
|
} // We need to add one to know if we are violating the limit
|
||||||
|
);
|
||||||
|
if (rejectResource) {
|
||||||
|
throw new Error(
|
||||||
|
"Private resource limit exceeded. Please upgrade your plan."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let aliasAddress: string | null = null;
|
let aliasAddress: string | null = null;
|
||||||
let releaseAliasLock: (() => Promise<void>) | null = null;
|
let releaseAliasLock: (() => Promise<void>) | null = null;
|
||||||
if (
|
if (
|
||||||
@@ -609,6 +643,8 @@ export async function updatePrivateResources(
|
|||||||
`Created new client resource ${newResource.name} (${newResource.siteResourceId}) for org ${orgId}`
|
`Created new client resource ${newResource.name} (${newResource.siteResourceId}) for org ${orgId}`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await usageService.add(orgId, LimitId.PRIVATE_RESOURCES, 1, trx);
|
||||||
|
|
||||||
results.push({
|
results.push({
|
||||||
newSiteResource: newResource,
|
newSiteResource: newResource,
|
||||||
newSites: allSites,
|
newSites: allSites,
|
||||||
|
|||||||
@@ -51,6 +51,11 @@ import { build } from "@server/build";
|
|||||||
import { encrypt } from "@server/lib/crypto";
|
import { encrypt } from "@server/lib/crypto";
|
||||||
import { generateId } from "@server/auth/sessions/app";
|
import { generateId } from "@server/auth/sessions/app";
|
||||||
import serverConfig from "@server/lib/config";
|
import serverConfig from "@server/lib/config";
|
||||||
|
import HttpCode from "@server/types/HttpCode";
|
||||||
|
import createHttpError from "http-errors";
|
||||||
|
import next from "next";
|
||||||
|
import { LimitId } from "../billing";
|
||||||
|
import { usageService } from "../billing/usageService";
|
||||||
|
|
||||||
export type PublicResourcesResults = {
|
export type PublicResourcesResults = {
|
||||||
proxyResource: Resource;
|
proxyResource: Resource;
|
||||||
@@ -1005,6 +1010,33 @@ export async function updatePublicResources(
|
|||||||
logger.debug(`Updated resource ${existingResource.resourceId}`);
|
logger.debug(`Updated resource ${existingResource.resourceId}`);
|
||||||
} else {
|
} else {
|
||||||
// create a brand new resource
|
// create a brand new resource
|
||||||
|
|
||||||
|
if (build == "saas") {
|
||||||
|
const usage = await usageService.getUsage(
|
||||||
|
orgId,
|
||||||
|
LimitId.PUBLIC_RESOURCES
|
||||||
|
);
|
||||||
|
if (!usage) {
|
||||||
|
throw new Error(
|
||||||
|
`Usage data not found for org ${orgId} and limit ${LimitId.PUBLIC_RESOURCES}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const rejectResource = await usageService.checkLimitSet(
|
||||||
|
orgId,
|
||||||
|
|
||||||
|
LimitId.PUBLIC_RESOURCES,
|
||||||
|
{
|
||||||
|
...usage,
|
||||||
|
instantaneousValue: (usage.instantaneousValue || 0) + 1
|
||||||
|
} // We need to add one to know if we are violating the limit
|
||||||
|
);
|
||||||
|
if (rejectResource) {
|
||||||
|
throw new Error(
|
||||||
|
"Public resource limit exceeded. Please upgrade your plan."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let domain;
|
let domain;
|
||||||
if (
|
if (
|
||||||
["http", "ssh", "rdp", "vnc"].includes(resourceData.mode || "")
|
["http", "ssh", "rdp", "vnc"].includes(resourceData.mode || "")
|
||||||
@@ -1294,6 +1326,8 @@ export async function updatePublicResources(
|
|||||||
await createTarget(newResource.resourceId, targetData);
|
await createTarget(newResource.resourceId, targetData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await usageService.add(orgId, LimitId.PUBLIC_RESOURCES, 1, trx);
|
||||||
|
|
||||||
logger.debug(`Created resource ${newResource.resourceId}`);
|
logger.debug(`Created resource ${newResource.resourceId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ export async function createClient(
|
|||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
"Public resource limit exceeded. Please upgrade your plan."
|
"Machine client limit exceeded. Please upgrade your plan."
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user