mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-06-24 00:25:27 +02:00
Compare commits
12 Commits
ulimits
...
copilot/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f2859fd2a9 | ||
|
|
f5fa39b97e | ||
|
|
0a3a90c4e9 | ||
|
|
f440df343a | ||
|
|
4ec282b2f3 | ||
|
|
c039e638a6 | ||
|
|
65ffc63da4 | ||
|
|
5ba120567f | ||
|
|
8a335789b3 | ||
|
|
de2579401c | ||
|
|
6c90075a64 | ||
|
|
0a401843f8 |
@@ -147,6 +147,7 @@ const baseApp: ApplicationNested = {
|
|||||||
dockerContextPath: null,
|
dockerContextPath: null,
|
||||||
rollbackActive: false,
|
rollbackActive: false,
|
||||||
stopGracePeriodSwarm: null,
|
stopGracePeriodSwarm: null,
|
||||||
|
ulimitsSwarm: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
describe("unzipDrop using real zip files", () => {
|
describe("unzipDrop using real zip files", () => {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ type MockCreateServiceOptions = {
|
|||||||
TaskTemplate?: {
|
TaskTemplate?: {
|
||||||
ContainerSpec?: {
|
ContainerSpec?: {
|
||||||
StopGracePeriod?: number;
|
StopGracePeriod?: number;
|
||||||
|
Ulimits?: Array<{ Name: string; Soft: number; Hard: number }>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
@@ -57,6 +58,7 @@ const createApplication = (
|
|||||||
},
|
},
|
||||||
replicas: 1,
|
replicas: 1,
|
||||||
stopGracePeriodSwarm: 0n,
|
stopGracePeriodSwarm: 0n,
|
||||||
|
ulimitsSwarm: null,
|
||||||
serverId: "server-id",
|
serverId: "server-id",
|
||||||
...overrides,
|
...overrides,
|
||||||
}) as unknown as ApplicationNested;
|
}) as unknown as ApplicationNested;
|
||||||
@@ -110,4 +112,50 @@ describe("mechanizeDockerContainer", () => {
|
|||||||
"StopGracePeriod",
|
"StopGracePeriod",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("passes ulimits to ContainerSpec when ulimitsSwarm is defined", async () => {
|
||||||
|
const ulimits = [
|
||||||
|
{ Name: "nofile", Soft: 10000, Hard: 20000 },
|
||||||
|
{ Name: "nproc", Soft: 4096, Hard: 8192 },
|
||||||
|
];
|
||||||
|
const application = createApplication({ ulimitsSwarm: ulimits });
|
||||||
|
|
||||||
|
await mechanizeDockerContainer(application);
|
||||||
|
|
||||||
|
expect(createServiceMock).toHaveBeenCalledTimes(1);
|
||||||
|
const call = createServiceMock.mock.calls[0];
|
||||||
|
if (!call) {
|
||||||
|
throw new Error("createServiceMock should have been called once");
|
||||||
|
}
|
||||||
|
const [settings] = call;
|
||||||
|
expect(settings.TaskTemplate?.ContainerSpec?.Ulimits).toEqual(ulimits);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("omits Ulimits when ulimitsSwarm is null", async () => {
|
||||||
|
const application = createApplication({ ulimitsSwarm: null });
|
||||||
|
|
||||||
|
await mechanizeDockerContainer(application);
|
||||||
|
|
||||||
|
expect(createServiceMock).toHaveBeenCalledTimes(1);
|
||||||
|
const call = createServiceMock.mock.calls[0];
|
||||||
|
if (!call) {
|
||||||
|
throw new Error("createServiceMock should have been called once");
|
||||||
|
}
|
||||||
|
const [settings] = call;
|
||||||
|
expect(settings.TaskTemplate?.ContainerSpec).not.toHaveProperty("Ulimits");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("omits Ulimits when ulimitsSwarm is an empty array", async () => {
|
||||||
|
const application = createApplication({ ulimitsSwarm: [] });
|
||||||
|
|
||||||
|
await mechanizeDockerContainer(application);
|
||||||
|
|
||||||
|
expect(createServiceMock).toHaveBeenCalledTimes(1);
|
||||||
|
const call = createServiceMock.mock.calls[0];
|
||||||
|
if (!call) {
|
||||||
|
throw new Error("createServiceMock should have been called once");
|
||||||
|
}
|
||||||
|
const [settings] = call;
|
||||||
|
expect(settings.TaskTemplate?.ContainerSpec).not.toHaveProperty("Ulimits");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ const baseApp: ApplicationNested = {
|
|||||||
username: null,
|
username: null,
|
||||||
dockerContextPath: null,
|
dockerContextPath: null,
|
||||||
stopGracePeriodSwarm: null,
|
stopGracePeriodSwarm: null,
|
||||||
|
ulimitsSwarm: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const baseDomain: Domain = {
|
const baseDomain: Domain = {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { InfoIcon } from "lucide-react";
|
import { InfoIcon, Plus, Trash2 } from "lucide-react";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useFieldArray, useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { AlertBlock } from "@/components/shared/alert-block";
|
import { AlertBlock } from "@/components/shared/alert-block";
|
||||||
@@ -21,10 +21,18 @@ import {
|
|||||||
FormLabel,
|
FormLabel,
|
||||||
FormMessage,
|
FormMessage,
|
||||||
} from "@/components/ui/form";
|
} from "@/components/ui/form";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
import {
|
import {
|
||||||
createConverter,
|
createConverter,
|
||||||
NumberInputWithSteps,
|
NumberInputWithSteps,
|
||||||
} from "@/components/ui/number-input";
|
} from "@/components/ui/number-input";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
import {
|
import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
TooltipContent,
|
TooltipContent,
|
||||||
@@ -50,13 +58,36 @@ const memoryConverter = createConverter(1024 * 1024, (mb) => {
|
|||||||
: `${formatNumber(mb)} MB`;
|
: `${formatNumber(mb)} MB`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const ulimitSchema = z.object({
|
||||||
|
Name: z.string().min(1, "Name is required"),
|
||||||
|
Soft: z.coerce.number().int().min(-1, "Must be >= -1"),
|
||||||
|
Hard: z.coerce.number().int().min(-1, "Must be >= -1"),
|
||||||
|
});
|
||||||
|
|
||||||
const addResourcesSchema = z.object({
|
const addResourcesSchema = z.object({
|
||||||
memoryReservation: z.string().optional(),
|
memoryReservation: z.string().optional(),
|
||||||
cpuLimit: z.string().optional(),
|
cpuLimit: z.string().optional(),
|
||||||
memoryLimit: z.string().optional(),
|
memoryLimit: z.string().optional(),
|
||||||
cpuReservation: z.string().optional(),
|
cpuReservation: z.string().optional(),
|
||||||
|
ulimitsSwarm: z.array(ulimitSchema).optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const ULIMIT_PRESETS = [
|
||||||
|
{ value: "nofile", label: "nofile (Open Files)" },
|
||||||
|
{ value: "nproc", label: "nproc (Processes)" },
|
||||||
|
{ value: "memlock", label: "memlock (Locked Memory)" },
|
||||||
|
{ value: "stack", label: "stack (Stack Size)" },
|
||||||
|
{ value: "core", label: "core (Core File Size)" },
|
||||||
|
{ value: "cpu", label: "cpu (CPU Time)" },
|
||||||
|
{ value: "data", label: "data (Data Segment)" },
|
||||||
|
{ value: "fsize", label: "fsize (File Size)" },
|
||||||
|
{ value: "locks", label: "locks (File Locks)" },
|
||||||
|
{ value: "msgqueue", label: "msgqueue (Message Queues)" },
|
||||||
|
{ value: "nice", label: "nice (Nice Priority)" },
|
||||||
|
{ value: "rtprio", label: "rtprio (Real-time Priority)" },
|
||||||
|
{ value: "sigpending", label: "sigpending (Pending Signals)" },
|
||||||
|
];
|
||||||
|
|
||||||
export type ServiceType =
|
export type ServiceType =
|
||||||
| "postgres"
|
| "postgres"
|
||||||
| "mongo"
|
| "mongo"
|
||||||
@@ -107,10 +138,16 @@ export const ShowResources = ({ id, type }: Props) => {
|
|||||||
cpuReservation: "",
|
cpuReservation: "",
|
||||||
memoryLimit: "",
|
memoryLimit: "",
|
||||||
memoryReservation: "",
|
memoryReservation: "",
|
||||||
|
ulimitsSwarm: [],
|
||||||
},
|
},
|
||||||
resolver: zodResolver(addResourcesSchema),
|
resolver: zodResolver(addResourcesSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { fields, append, remove } = useFieldArray({
|
||||||
|
control: form.control,
|
||||||
|
name: "ulimitsSwarm",
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data) {
|
if (data) {
|
||||||
form.reset({
|
form.reset({
|
||||||
@@ -118,6 +155,7 @@ export const ShowResources = ({ id, type }: Props) => {
|
|||||||
cpuReservation: data?.cpuReservation || undefined,
|
cpuReservation: data?.cpuReservation || undefined,
|
||||||
memoryLimit: data?.memoryLimit || undefined,
|
memoryLimit: data?.memoryLimit || undefined,
|
||||||
memoryReservation: data?.memoryReservation || undefined,
|
memoryReservation: data?.memoryReservation || undefined,
|
||||||
|
ulimitsSwarm: data?.ulimitsSwarm || [],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [data, form, form.reset]);
|
}, [data, form, form.reset]);
|
||||||
@@ -134,6 +172,10 @@ export const ShowResources = ({ id, type }: Props) => {
|
|||||||
cpuReservation: formData.cpuReservation || null,
|
cpuReservation: formData.cpuReservation || null,
|
||||||
memoryLimit: formData.memoryLimit || null,
|
memoryLimit: formData.memoryLimit || null,
|
||||||
memoryReservation: formData.memoryReservation || null,
|
memoryReservation: formData.memoryReservation || null,
|
||||||
|
ulimitsSwarm:
|
||||||
|
formData.ulimitsSwarm && formData.ulimitsSwarm.length > 0
|
||||||
|
? formData.ulimitsSwarm
|
||||||
|
: null,
|
||||||
})
|
})
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
toast.success("Resources Updated");
|
toast.success("Resources Updated");
|
||||||
@@ -325,6 +367,145 @@ export const ShowResources = ({ id, type }: Props) => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Ulimits Section */}
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<FormLabel className="text-base">Ulimits</FormLabel>
|
||||||
|
<TooltipProvider>
|
||||||
|
<Tooltip delayDuration={0}>
|
||||||
|
<TooltipTrigger>
|
||||||
|
<InfoIcon className="h-4 w-4 text-muted-foreground" />
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent className="max-w-xs">
|
||||||
|
<p>
|
||||||
|
Set resource limits for the container. Each ulimit has
|
||||||
|
a soft limit (warning threshold) and hard limit
|
||||||
|
(maximum allowed). Use -1 for unlimited.
|
||||||
|
</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={() =>
|
||||||
|
append({ Name: "nofile", Soft: 65535, Hard: 65535 })
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Plus className="h-4 w-4 mr-1" />
|
||||||
|
Add Ulimit
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{fields.length > 0 && (
|
||||||
|
<div className="space-y-3">
|
||||||
|
{fields.map((field, index) => (
|
||||||
|
<div
|
||||||
|
key={field.id}
|
||||||
|
className="flex items-start gap-3 p-3 border rounded-lg bg-muted/30"
|
||||||
|
>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={`ulimitsSwarm.${index}.Name`}
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem className="flex-1">
|
||||||
|
<FormLabel className="text-xs">Type</FormLabel>
|
||||||
|
<Select
|
||||||
|
onValueChange={field.onChange}
|
||||||
|
value={field.value}
|
||||||
|
>
|
||||||
|
<FormControl>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue placeholder="Select ulimit" />
|
||||||
|
</SelectTrigger>
|
||||||
|
</FormControl>
|
||||||
|
<SelectContent>
|
||||||
|
{ULIMIT_PRESETS.map((preset) => (
|
||||||
|
<SelectItem
|
||||||
|
key={preset.value}
|
||||||
|
value={preset.value}
|
||||||
|
>
|
||||||
|
{preset.label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={`ulimitsSwarm.${index}.Soft`}
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem className="w-32">
|
||||||
|
<FormLabel className="text-xs">
|
||||||
|
Soft Limit
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
min={-1}
|
||||||
|
placeholder="65535"
|
||||||
|
{...field}
|
||||||
|
onChange={(e) =>
|
||||||
|
field.onChange(Number(e.target.value))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={`ulimitsSwarm.${index}.Hard`}
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem className="w-32">
|
||||||
|
<FormLabel className="text-xs">
|
||||||
|
Hard Limit
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
min={-1}
|
||||||
|
placeholder="65535"
|
||||||
|
{...field}
|
||||||
|
onChange={(e) =>
|
||||||
|
field.onChange(Number(e.target.value))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className="mt-6 text-destructive hover:text-destructive"
|
||||||
|
onClick={() => remove(index)}
|
||||||
|
>
|
||||||
|
<Trash2 className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{fields.length === 0 && (
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
No ulimits configured. Click "Add Ulimit" to set
|
||||||
|
resource limits.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex w-full justify-end">
|
<div className="flex w-full justify-end">
|
||||||
<Button isLoading={isLoading} type="submit">
|
<Button isLoading={isLoading} type="submit">
|
||||||
Save
|
Save
|
||||||
|
|||||||
@@ -404,8 +404,7 @@ const MENU: Menu = {
|
|||||||
url: "/dashboard/settings/license",
|
url: "/dashboard/settings/license",
|
||||||
icon: Key,
|
icon: Key,
|
||||||
// Only enabled for admins in non-cloud environments
|
// Only enabled for admins in non-cloud environments
|
||||||
isEnabled: ({ auth }) =>
|
isEnabled: ({ auth }) => !!(auth?.role === "owner"),
|
||||||
!!(auth?.role === "owner" || auth?.role === "admin"),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isSingle: true,
|
isSingle: true,
|
||||||
|
|||||||
@@ -166,7 +166,12 @@ export function LicenseKeySettings() {
|
|||||||
{!haveValidLicenseKey && (
|
{!haveValidLicenseKey && (
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
disabled={isSaving || isValidating || isDeactivating}
|
disabled={
|
||||||
|
isSaving ||
|
||||||
|
isValidating ||
|
||||||
|
isDeactivating ||
|
||||||
|
!licenseKey.trim()
|
||||||
|
}
|
||||||
isLoading={isActivating}
|
isLoading={isActivating}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
6
apps/dokploy/drizzle/0142_outstanding_tusk.sql
Normal file
6
apps/dokploy/drizzle/0142_outstanding_tusk.sql
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
ALTER TABLE "application" ADD COLUMN "ulimitsSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mariadb" ADD COLUMN "ulimitsSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mongo" ADD COLUMN "ulimitsSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mysql" ADD COLUMN "ulimitsSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "postgres" ADD COLUMN "ulimitsSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "redis" ADD COLUMN "ulimitsSwarm" json;
|
||||||
7284
apps/dokploy/drizzle/meta/0142_snapshot.json
Normal file
7284
apps/dokploy/drizzle/meta/0142_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -995,6 +995,13 @@
|
|||||||
"when": 1770490719123,
|
"when": 1770490719123,
|
||||||
"tag": "0141_plain_earthquake",
|
"tag": "0141_plain_earthquake",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 142,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1770615019498,
|
||||||
|
"tag": "0142_outstanding_tusk",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { IS_CLOUD, validateRequest } from "@dokploy/server";
|
import { validateRequest } from "@dokploy/server";
|
||||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||||
import type { GetServerSidePropsContext } from "next";
|
import type { GetServerSidePropsContext } from "next";
|
||||||
import type { ReactElement } from "react";
|
import type { ReactElement } from "react";
|
||||||
@@ -45,7 +45,7 @@ export async function getServerSideProps(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (user.role === "member") {
|
if (user.role !== "owner") {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
permanent: true,
|
permanent: true,
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 4.6 KiB |
@@ -12,7 +12,7 @@ import {
|
|||||||
|
|
||||||
export const licenseKeyRouter = createTRPCRouter({
|
export const licenseKeyRouter = createTRPCRouter({
|
||||||
activate: adminProcedure
|
activate: adminProcedure
|
||||||
.input(z.object({ licenseKey: z.string() }))
|
.input(z.object({ licenseKey: z.string().min(1) }))
|
||||||
.mutation(async ({ input, ctx }) => {
|
.mutation(async ({ input, ctx }) => {
|
||||||
try {
|
try {
|
||||||
const currentUserId = ctx.user.id;
|
const currentUserId = ctx.user.id;
|
||||||
@@ -74,6 +74,13 @@ export const licenseKeyRouter = createTRPCRouter({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx.user.role !== "owner") {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "FORBIDDEN",
|
||||||
|
message: "You are not authorized to validate a license key",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!currentUser.licenseKey) {
|
if (!currentUser.licenseKey) {
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
code: "BAD_REQUEST",
|
code: "BAD_REQUEST",
|
||||||
@@ -164,6 +171,13 @@ export const licenseKeyRouter = createTRPCRouter({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx.user.role !== "owner") {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "FORBIDDEN",
|
||||||
|
message: "You are not authorized to get enterprise settings",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
enableEnterpriseFeatures: !!currentUser.enableEnterpriseFeatures,
|
enableEnterpriseFeatures: !!currentUser.enableEnterpriseFeatures,
|
||||||
licenseKey: currentUser.licenseKey ?? "",
|
licenseKey: currentUser.licenseKey ?? "",
|
||||||
@@ -200,6 +214,13 @@ export const licenseKeyRouter = createTRPCRouter({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx.user.role !== "owner") {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "FORBIDDEN",
|
||||||
|
message: "You are not authorized to update enterprise settings",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
await db
|
await db
|
||||||
.update(user)
|
.update(user)
|
||||||
.set({
|
.set({
|
||||||
|
|||||||
@@ -1,5 +1,18 @@
|
|||||||
import { getPublicIpWithFallback, LICENSE_KEY_URL } from "@dokploy/server";
|
import { getPublicIpWithFallback, LICENSE_KEY_URL } from "@dokploy/server";
|
||||||
|
|
||||||
|
const LICENSE_SERVER_UNREACHABLE =
|
||||||
|
"Could not reach the license server. Check your connection or try again later.";
|
||||||
|
|
||||||
|
function isNetworkError(error: unknown): boolean {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
if (error.message === "fetch failed") return true;
|
||||||
|
const cause = (error as Error & { cause?: { code?: string } }).cause;
|
||||||
|
const code = cause?.code;
|
||||||
|
return code === "ECONNREFUSED" || code === "ENOTFOUND" || code === "ETIMEDOUT";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
export const validateLicenseKey = async (licenseKey: string) => {
|
export const validateLicenseKey = async (licenseKey: string) => {
|
||||||
try {
|
try {
|
||||||
const ip = await getPublicIpWithFallback();
|
const ip = await getPublicIpWithFallback();
|
||||||
@@ -22,6 +35,9 @@ export const validateLicenseKey = async (licenseKey: string) => {
|
|||||||
console.error(
|
console.error(
|
||||||
error instanceof Error ? error.message : "Failed to validate license key",
|
error instanceof Error ? error.message : "Failed to validate license key",
|
||||||
);
|
);
|
||||||
|
if (isNetworkError(error)) {
|
||||||
|
throw new Error(LICENSE_SERVER_UNREACHABLE);
|
||||||
|
}
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -48,6 +64,9 @@ export const activateLicenseKey = async (licenseKey: string) => {
|
|||||||
console.error(
|
console.error(
|
||||||
error instanceof Error ? error.message : "Failed to activate license key",
|
error instanceof Error ? error.message : "Failed to activate license key",
|
||||||
);
|
);
|
||||||
|
if (isNetworkError(error)) {
|
||||||
|
throw new Error(LICENSE_SERVER_UNREACHABLE);
|
||||||
|
}
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -76,6 +95,9 @@ export const deactivateLicenseKey = async (licenseKey: string) => {
|
|||||||
? error.message
|
? error.message
|
||||||
: "Failed to deactivate license key",
|
: "Failed to deactivate license key",
|
||||||
);
|
);
|
||||||
|
if (isNetworkError(error)) {
|
||||||
|
throw new Error(LICENSE_SERVER_UNREACHABLE);
|
||||||
|
}
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ import {
|
|||||||
type ServiceModeSwarm,
|
type ServiceModeSwarm,
|
||||||
ServiceModeSwarmSchema,
|
ServiceModeSwarmSchema,
|
||||||
triggerType,
|
triggerType,
|
||||||
|
type UlimitsSwarm,
|
||||||
|
UlimitsSwarmSchema,
|
||||||
type UpdateConfigSwarm,
|
type UpdateConfigSwarm,
|
||||||
UpdateConfigSwarmSchema,
|
UpdateConfigSwarmSchema,
|
||||||
} from "./shared";
|
} from "./shared";
|
||||||
@@ -172,6 +174,7 @@ export const applications = pgTable("application", {
|
|||||||
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
||||||
stopGracePeriodSwarm: bigint("stopGracePeriodSwarm", { mode: "bigint" }),
|
stopGracePeriodSwarm: bigint("stopGracePeriodSwarm", { mode: "bigint" }),
|
||||||
endpointSpecSwarm: json("endpointSpecSwarm").$type<EndpointSpecSwarm>(),
|
endpointSpecSwarm: json("endpointSpecSwarm").$type<EndpointSpecSwarm>(),
|
||||||
|
ulimitsSwarm: json("ulimitsSwarm").$type<UlimitsSwarm>(),
|
||||||
//
|
//
|
||||||
replicas: integer("replicas").default(1).notNull(),
|
replicas: integer("replicas").default(1).notNull(),
|
||||||
applicationStatus: applicationStatus("applicationStatus")
|
applicationStatus: applicationStatus("applicationStatus")
|
||||||
@@ -364,6 +367,7 @@ const createSchema = createInsertSchema(applications, {
|
|||||||
cleanCache: z.boolean().optional(),
|
cleanCache: z.boolean().optional(),
|
||||||
stopGracePeriodSwarm: z.bigint().nullable(),
|
stopGracePeriodSwarm: z.bigint().nullable(),
|
||||||
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
|
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
|
||||||
|
ulimitsSwarm: UlimitsSwarmSchema.nullable(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const apiCreateApplication = createSchema.pick({
|
export const apiCreateApplication = createSchema.pick({
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ import {
|
|||||||
RestartPolicySwarmSchema,
|
RestartPolicySwarmSchema,
|
||||||
type ServiceModeSwarm,
|
type ServiceModeSwarm,
|
||||||
ServiceModeSwarmSchema,
|
ServiceModeSwarmSchema,
|
||||||
|
type UlimitsSwarm,
|
||||||
|
UlimitsSwarmSchema,
|
||||||
type UpdateConfigSwarm,
|
type UpdateConfigSwarm,
|
||||||
UpdateConfigSwarmSchema,
|
UpdateConfigSwarmSchema,
|
||||||
} from "./shared";
|
} from "./shared";
|
||||||
@@ -67,6 +69,7 @@ export const mariadb = pgTable("mariadb", {
|
|||||||
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
||||||
stopGracePeriodSwarm: bigint("stopGracePeriodSwarm", { mode: "bigint" }),
|
stopGracePeriodSwarm: bigint("stopGracePeriodSwarm", { mode: "bigint" }),
|
||||||
endpointSpecSwarm: json("endpointSpecSwarm").$type<EndpointSpecSwarm>(),
|
endpointSpecSwarm: json("endpointSpecSwarm").$type<EndpointSpecSwarm>(),
|
||||||
|
ulimitsSwarm: json("ulimitsSwarm").$type<UlimitsSwarm>(),
|
||||||
replicas: integer("replicas").default(1).notNull(),
|
replicas: integer("replicas").default(1).notNull(),
|
||||||
createdAt: text("createdAt")
|
createdAt: text("createdAt")
|
||||||
.notNull()
|
.notNull()
|
||||||
@@ -141,6 +144,7 @@ const createSchema = createInsertSchema(mariadb, {
|
|||||||
networkSwarm: NetworkSwarmSchema.nullable(),
|
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||||
stopGracePeriodSwarm: z.bigint().nullable(),
|
stopGracePeriodSwarm: z.bigint().nullable(),
|
||||||
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
|
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
|
||||||
|
ulimitsSwarm: UlimitsSwarmSchema.nullable(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const apiCreateMariaDB = createSchema.pick({
|
export const apiCreateMariaDB = createSchema.pick({
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ import {
|
|||||||
RestartPolicySwarmSchema,
|
RestartPolicySwarmSchema,
|
||||||
type ServiceModeSwarm,
|
type ServiceModeSwarm,
|
||||||
ServiceModeSwarmSchema,
|
ServiceModeSwarmSchema,
|
||||||
|
type UlimitsSwarm,
|
||||||
|
UlimitsSwarmSchema,
|
||||||
type UpdateConfigSwarm,
|
type UpdateConfigSwarm,
|
||||||
UpdateConfigSwarmSchema,
|
UpdateConfigSwarmSchema,
|
||||||
} from "./shared";
|
} from "./shared";
|
||||||
@@ -70,6 +72,7 @@ export const mongo = pgTable("mongo", {
|
|||||||
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
||||||
stopGracePeriodSwarm: bigint("stopGracePeriodSwarm", { mode: "bigint" }),
|
stopGracePeriodSwarm: bigint("stopGracePeriodSwarm", { mode: "bigint" }),
|
||||||
endpointSpecSwarm: json("endpointSpecSwarm").$type<EndpointSpecSwarm>(),
|
endpointSpecSwarm: json("endpointSpecSwarm").$type<EndpointSpecSwarm>(),
|
||||||
|
ulimitsSwarm: json("ulimitsSwarm").$type<UlimitsSwarm>(),
|
||||||
replicas: integer("replicas").default(1).notNull(),
|
replicas: integer("replicas").default(1).notNull(),
|
||||||
createdAt: text("createdAt")
|
createdAt: text("createdAt")
|
||||||
.notNull()
|
.notNull()
|
||||||
@@ -138,6 +141,7 @@ const createSchema = createInsertSchema(mongo, {
|
|||||||
networkSwarm: NetworkSwarmSchema.nullable(),
|
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||||
stopGracePeriodSwarm: z.bigint().nullable(),
|
stopGracePeriodSwarm: z.bigint().nullable(),
|
||||||
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
|
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
|
||||||
|
ulimitsSwarm: UlimitsSwarmSchema.nullable(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const apiCreateMongo = createSchema.pick({
|
export const apiCreateMongo = createSchema.pick({
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ import {
|
|||||||
RestartPolicySwarmSchema,
|
RestartPolicySwarmSchema,
|
||||||
type ServiceModeSwarm,
|
type ServiceModeSwarm,
|
||||||
ServiceModeSwarmSchema,
|
ServiceModeSwarmSchema,
|
||||||
|
type UlimitsSwarm,
|
||||||
|
UlimitsSwarmSchema,
|
||||||
type UpdateConfigSwarm,
|
type UpdateConfigSwarm,
|
||||||
UpdateConfigSwarmSchema,
|
UpdateConfigSwarmSchema,
|
||||||
} from "./shared";
|
} from "./shared";
|
||||||
@@ -65,6 +67,7 @@ export const mysql = pgTable("mysql", {
|
|||||||
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
||||||
stopGracePeriodSwarm: bigint("stopGracePeriodSwarm", { mode: "bigint" }),
|
stopGracePeriodSwarm: bigint("stopGracePeriodSwarm", { mode: "bigint" }),
|
||||||
endpointSpecSwarm: json("endpointSpecSwarm").$type<EndpointSpecSwarm>(),
|
endpointSpecSwarm: json("endpointSpecSwarm").$type<EndpointSpecSwarm>(),
|
||||||
|
ulimitsSwarm: json("ulimitsSwarm").$type<UlimitsSwarm>(),
|
||||||
replicas: integer("replicas").default(1).notNull(),
|
replicas: integer("replicas").default(1).notNull(),
|
||||||
createdAt: text("createdAt")
|
createdAt: text("createdAt")
|
||||||
.notNull()
|
.notNull()
|
||||||
@@ -138,6 +141,7 @@ const createSchema = createInsertSchema(mysql, {
|
|||||||
networkSwarm: NetworkSwarmSchema.nullable(),
|
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||||
stopGracePeriodSwarm: z.bigint().nullable(),
|
stopGracePeriodSwarm: z.bigint().nullable(),
|
||||||
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
|
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
|
||||||
|
ulimitsSwarm: UlimitsSwarmSchema.nullable(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const apiCreateMySql = createSchema.pick({
|
export const apiCreateMySql = createSchema.pick({
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ import {
|
|||||||
RestartPolicySwarmSchema,
|
RestartPolicySwarmSchema,
|
||||||
type ServiceModeSwarm,
|
type ServiceModeSwarm,
|
||||||
ServiceModeSwarmSchema,
|
ServiceModeSwarmSchema,
|
||||||
|
type UlimitsSwarm,
|
||||||
|
UlimitsSwarmSchema,
|
||||||
type UpdateConfigSwarm,
|
type UpdateConfigSwarm,
|
||||||
UpdateConfigSwarmSchema,
|
UpdateConfigSwarmSchema,
|
||||||
} from "./shared";
|
} from "./shared";
|
||||||
@@ -65,6 +67,7 @@ export const postgres = pgTable("postgres", {
|
|||||||
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
||||||
stopGracePeriodSwarm: bigint("stopGracePeriodSwarm", { mode: "bigint" }),
|
stopGracePeriodSwarm: bigint("stopGracePeriodSwarm", { mode: "bigint" }),
|
||||||
endpointSpecSwarm: json("endpointSpecSwarm").$type<EndpointSpecSwarm>(),
|
endpointSpecSwarm: json("endpointSpecSwarm").$type<EndpointSpecSwarm>(),
|
||||||
|
ulimitsSwarm: json("ulimitsSwarm").$type<UlimitsSwarm>(),
|
||||||
replicas: integer("replicas").default(1).notNull(),
|
replicas: integer("replicas").default(1).notNull(),
|
||||||
createdAt: text("createdAt")
|
createdAt: text("createdAt")
|
||||||
.notNull()
|
.notNull()
|
||||||
@@ -132,6 +135,7 @@ const createSchema = createInsertSchema(postgres, {
|
|||||||
networkSwarm: NetworkSwarmSchema.nullable(),
|
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||||
stopGracePeriodSwarm: z.bigint().nullable(),
|
stopGracePeriodSwarm: z.bigint().nullable(),
|
||||||
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
|
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
|
||||||
|
ulimitsSwarm: UlimitsSwarmSchema.nullable(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const apiCreatePostgres = createSchema.pick({
|
export const apiCreatePostgres = createSchema.pick({
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import {
|
|||||||
RestartPolicySwarmSchema,
|
RestartPolicySwarmSchema,
|
||||||
type ServiceModeSwarm,
|
type ServiceModeSwarm,
|
||||||
ServiceModeSwarmSchema,
|
ServiceModeSwarmSchema,
|
||||||
|
type UlimitsSwarm,
|
||||||
|
UlimitsSwarmSchema,
|
||||||
type UpdateConfigSwarm,
|
type UpdateConfigSwarm,
|
||||||
UpdateConfigSwarmSchema,
|
UpdateConfigSwarmSchema,
|
||||||
} from "./shared";
|
} from "./shared";
|
||||||
@@ -64,6 +66,7 @@ export const redis = pgTable("redis", {
|
|||||||
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
||||||
stopGracePeriodSwarm: bigint("stopGracePeriodSwarm", { mode: "bigint" }),
|
stopGracePeriodSwarm: bigint("stopGracePeriodSwarm", { mode: "bigint" }),
|
||||||
endpointSpecSwarm: json("endpointSpecSwarm").$type<EndpointSpecSwarm>(),
|
endpointSpecSwarm: json("endpointSpecSwarm").$type<EndpointSpecSwarm>(),
|
||||||
|
ulimitsSwarm: json("ulimitsSwarm").$type<UlimitsSwarm>(),
|
||||||
replicas: integer("replicas").default(1).notNull(),
|
replicas: integer("replicas").default(1).notNull(),
|
||||||
|
|
||||||
environmentId: text("environmentId")
|
environmentId: text("environmentId")
|
||||||
@@ -120,6 +123,7 @@ const createSchema = createInsertSchema(redis, {
|
|||||||
networkSwarm: NetworkSwarmSchema.nullable(),
|
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||||
stopGracePeriodSwarm: z.bigint().nullable(),
|
stopGracePeriodSwarm: z.bigint().nullable(),
|
||||||
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
|
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
|
||||||
|
ulimitsSwarm: UlimitsSwarmSchema.nullable(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const apiCreateRedis = createSchema.pick({
|
export const apiCreateRedis = createSchema.pick({
|
||||||
|
|||||||
@@ -86,6 +86,14 @@ export interface EndpointSpecSwarm {
|
|||||||
Ports?: EndpointPortConfigSwarm[] | undefined;
|
Ports?: EndpointPortConfigSwarm[] | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UlimitSwarm {
|
||||||
|
Name: string;
|
||||||
|
Soft: number;
|
||||||
|
Hard: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UlimitsSwarm = UlimitSwarm[];
|
||||||
|
|
||||||
export const HealthCheckSwarmSchema = z
|
export const HealthCheckSwarmSchema = z
|
||||||
.object({
|
.object({
|
||||||
Test: z.array(z.string()).optional(),
|
Test: z.array(z.string()).optional(),
|
||||||
@@ -189,3 +197,13 @@ export const EndpointSpecSwarmSchema = z
|
|||||||
Ports: z.array(EndpointPortConfigSwarmSchema).optional(),
|
Ports: z.array(EndpointPortConfigSwarmSchema).optional(),
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
|
export const UlimitSwarmSchema = z
|
||||||
|
.object({
|
||||||
|
Name: z.string().min(1),
|
||||||
|
Soft: z.number().int().min(-1),
|
||||||
|
Hard: z.number().int().min(-1),
|
||||||
|
})
|
||||||
|
.strict();
|
||||||
|
|
||||||
|
export const UlimitsSwarmSchema = z.array(UlimitSwarmSchema);
|
||||||
|
|||||||
@@ -220,6 +220,7 @@ const rollbackApplication = async (
|
|||||||
RollbackConfig,
|
RollbackConfig,
|
||||||
UpdateConfig,
|
UpdateConfig,
|
||||||
Networks,
|
Networks,
|
||||||
|
Ulimits,
|
||||||
} = generateConfigContainer(fullContext as ApplicationNested);
|
} = generateConfigContainer(fullContext as ApplicationNested);
|
||||||
|
|
||||||
const bindsMount = generateBindMounts(mounts);
|
const bindsMount = generateBindMounts(mounts);
|
||||||
@@ -254,6 +255,7 @@ const rollbackApplication = async (
|
|||||||
Args: ["-c", command],
|
Args: ["-c", command],
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
|
...(Ulimits && { Ulimits }),
|
||||||
Labels,
|
Labels,
|
||||||
},
|
},
|
||||||
Networks,
|
Networks,
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ export const createCommand = (compose: ComposeNested) => {
|
|||||||
let command = "";
|
let command = "";
|
||||||
|
|
||||||
if (composeType === "docker-compose") {
|
if (composeType === "docker-compose") {
|
||||||
command = `compose -p ${appName} -f ${path} up -d --build --remove-orphans`;
|
command = `compose -p ${appName} -f ${path} up -d --build --pull always --remove-orphans`;
|
||||||
} else if (composeType === "stack") {
|
} else if (composeType === "stack") {
|
||||||
command = `stack deploy -c ${path} ${appName} --prune --with-registry-auth`;
|
command = `stack deploy -c ${path} ${appName} --prune --with-registry-auth`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ export const mechanizeDockerContainer = async (
|
|||||||
Networks,
|
Networks,
|
||||||
StopGracePeriod,
|
StopGracePeriod,
|
||||||
EndpointSpec,
|
EndpointSpec,
|
||||||
|
Ulimits,
|
||||||
} = generateConfigContainer(application);
|
} = generateConfigContainer(application);
|
||||||
|
|
||||||
const bindsMount = generateBindMounts(mounts);
|
const bindsMount = generateBindMounts(mounts);
|
||||||
@@ -142,7 +143,7 @@ export const mechanizeDockerContainer = async (
|
|||||||
args.length > 0 && {
|
args.length > 0 && {
|
||||||
Args: args,
|
Args: args,
|
||||||
}),
|
}),
|
||||||
|
...(Ulimits && { Ulimits }),
|
||||||
Labels,
|
Labels,
|
||||||
},
|
},
|
||||||
Networks,
|
Networks,
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ export const buildMariadb = async (mariadb: MariadbNested) => {
|
|||||||
Networks,
|
Networks,
|
||||||
StopGracePeriod,
|
StopGracePeriod,
|
||||||
EndpointSpec,
|
EndpointSpec,
|
||||||
|
Ulimits,
|
||||||
} = generateConfigContainer(mariadb);
|
} = generateConfigContainer(mariadb);
|
||||||
const resources = calculateResources({
|
const resources = calculateResources({
|
||||||
memoryLimit,
|
memoryLimit,
|
||||||
@@ -83,7 +84,7 @@ export const buildMariadb = async (mariadb: MariadbNested) => {
|
|||||||
args.length > 0 && {
|
args.length > 0 && {
|
||||||
Args: args,
|
Args: args,
|
||||||
}),
|
}),
|
||||||
|
...(Ulimits && { Ulimits }),
|
||||||
Labels,
|
Labels,
|
||||||
},
|
},
|
||||||
Networks,
|
Networks,
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ ${command ?? "wait $MONGOD_PID"}`;
|
|||||||
Networks,
|
Networks,
|
||||||
StopGracePeriod,
|
StopGracePeriod,
|
||||||
EndpointSpec,
|
EndpointSpec,
|
||||||
|
Ulimits,
|
||||||
} = generateConfigContainer(mongo);
|
} = generateConfigContainer(mongo);
|
||||||
|
|
||||||
const resources = calculateResources({
|
const resources = calculateResources({
|
||||||
@@ -139,7 +140,7 @@ ${command ?? "wait $MONGOD_PID"}`;
|
|||||||
!replicaSets && {
|
!replicaSets && {
|
||||||
Args: args,
|
Args: args,
|
||||||
}),
|
}),
|
||||||
|
...(Ulimits && { Ulimits }),
|
||||||
Labels,
|
Labels,
|
||||||
},
|
},
|
||||||
Networks,
|
Networks,
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ export const buildMysql = async (mysql: MysqlNested) => {
|
|||||||
Networks,
|
Networks,
|
||||||
StopGracePeriod,
|
StopGracePeriod,
|
||||||
EndpointSpec,
|
EndpointSpec,
|
||||||
|
Ulimits,
|
||||||
} = generateConfigContainer(mysql);
|
} = generateConfigContainer(mysql);
|
||||||
const resources = calculateResources({
|
const resources = calculateResources({
|
||||||
memoryLimit,
|
memoryLimit,
|
||||||
@@ -89,7 +90,7 @@ export const buildMysql = async (mysql: MysqlNested) => {
|
|||||||
args.length > 0 && {
|
args.length > 0 && {
|
||||||
Args: args,
|
Args: args,
|
||||||
}),
|
}),
|
||||||
|
...(Ulimits && { Ulimits }),
|
||||||
Labels,
|
Labels,
|
||||||
},
|
},
|
||||||
Networks,
|
Networks,
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ export const buildPostgres = async (postgres: PostgresNested) => {
|
|||||||
Networks,
|
Networks,
|
||||||
StopGracePeriod,
|
StopGracePeriod,
|
||||||
EndpointSpec,
|
EndpointSpec,
|
||||||
|
Ulimits,
|
||||||
} = generateConfigContainer(postgres);
|
} = generateConfigContainer(postgres);
|
||||||
const resources = calculateResources({
|
const resources = calculateResources({
|
||||||
memoryLimit,
|
memoryLimit,
|
||||||
@@ -82,7 +83,7 @@ export const buildPostgres = async (postgres: PostgresNested) => {
|
|||||||
args.length > 0 && {
|
args.length > 0 && {
|
||||||
Args: args,
|
Args: args,
|
||||||
}),
|
}),
|
||||||
|
...(Ulimits && { Ulimits }),
|
||||||
Labels,
|
Labels,
|
||||||
},
|
},
|
||||||
Networks,
|
Networks,
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ export const buildRedis = async (redis: RedisNested) => {
|
|||||||
Networks,
|
Networks,
|
||||||
StopGracePeriod,
|
StopGracePeriod,
|
||||||
EndpointSpec,
|
EndpointSpec,
|
||||||
|
Ulimits,
|
||||||
} = generateConfigContainer(redis);
|
} = generateConfigContainer(redis);
|
||||||
const resources = calculateResources({
|
const resources = calculateResources({
|
||||||
memoryLimit,
|
memoryLimit,
|
||||||
@@ -87,6 +88,7 @@ export const buildRedis = async (redis: RedisNested) => {
|
|||||||
Command: ["/bin/sh"],
|
Command: ["/bin/sh"],
|
||||||
Args: ["-c", `redis-server --requirepass ${databasePassword}`],
|
Args: ["-c", `redis-server --requirepass ${databasePassword}`],
|
||||||
}),
|
}),
|
||||||
|
...(Ulimits && { Ulimits }),
|
||||||
Labels,
|
Labels,
|
||||||
},
|
},
|
||||||
Networks,
|
Networks,
|
||||||
|
|||||||
@@ -508,6 +508,7 @@ export const generateConfigContainer = (
|
|||||||
networkSwarm,
|
networkSwarm,
|
||||||
stopGracePeriodSwarm,
|
stopGracePeriodSwarm,
|
||||||
endpointSpecSwarm,
|
endpointSpecSwarm,
|
||||||
|
ulimitsSwarm,
|
||||||
} = application;
|
} = application;
|
||||||
|
|
||||||
const sanitizedStopGracePeriodSwarm =
|
const sanitizedStopGracePeriodSwarm =
|
||||||
@@ -584,6 +585,10 @@ export const generateConfigContainer = (
|
|||||||
})) || [],
|
})) || [],
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
...(ulimitsSwarm &&
|
||||||
|
ulimitsSwarm.length > 0 && {
|
||||||
|
Ulimits: ulimitsSwarm,
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user