mirror of
https://github.com/andwati/dokploy.git
synced 2026-11-11 22:45:18 +00:00
Merge pull request #2321 from Dokploy/1738-database-placement-constraints
feat(cluster-settings): Add swarm settings for databases
This commit is contained in:
+54
-32
@@ -1,3 +1,9 @@
|
|||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { HelpCircle, Settings } from "lucide-react";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { useForm } from "react-hook-form";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
import { z } from "zod";
|
||||||
import { AlertBlock } from "@/components/shared/alert-block";
|
import { AlertBlock } from "@/components/shared/alert-block";
|
||||||
import { CodeEditor } from "@/components/shared/code-editor";
|
import { CodeEditor } from "@/components/shared/code-editor";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
@@ -26,12 +32,6 @@ import {
|
|||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/components/ui/tooltip";
|
} from "@/components/ui/tooltip";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
|
||||||
import { HelpCircle, Settings } from "lucide-react";
|
|
||||||
import { useEffect } from "react";
|
|
||||||
import { useForm } from "react-hook-form";
|
|
||||||
import { toast } from "sonner";
|
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
const HealthCheckSwarmSchema = z
|
const HealthCheckSwarmSchema = z
|
||||||
.object({
|
.object({
|
||||||
@@ -181,21 +181,38 @@ const addSwarmSettings = z.object({
|
|||||||
type AddSwarmSettings = z.infer<typeof addSwarmSettings>;
|
type AddSwarmSettings = z.infer<typeof addSwarmSettings>;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
applicationId: string;
|
id: string;
|
||||||
|
type: "postgres" | "mariadb" | "mongo" | "mysql" | "redis" | "application";
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AddSwarmSettings = ({ applicationId }: Props) => {
|
export const AddSwarmSettings = ({ id, type }: Props) => {
|
||||||
const { data, refetch } = api.application.one.useQuery(
|
const queryMap = {
|
||||||
{
|
postgres: () =>
|
||||||
applicationId,
|
api.postgres.one.useQuery({ postgresId: id }, { enabled: !!id }),
|
||||||
},
|
redis: () => api.redis.one.useQuery({ redisId: id }, { enabled: !!id }),
|
||||||
{
|
mysql: () => api.mysql.one.useQuery({ mysqlId: id }, { enabled: !!id }),
|
||||||
enabled: !!applicationId,
|
mariadb: () =>
|
||||||
},
|
api.mariadb.one.useQuery({ mariadbId: id }, { enabled: !!id }),
|
||||||
);
|
application: () =>
|
||||||
|
api.application.one.useQuery({ applicationId: id }, { enabled: !!id }),
|
||||||
|
mongo: () => api.mongo.one.useQuery({ mongoId: id }, { enabled: !!id }),
|
||||||
|
};
|
||||||
|
const { data, refetch } = queryMap[type]
|
||||||
|
? queryMap[type]()
|
||||||
|
: api.mongo.one.useQuery({ mongoId: id }, { enabled: !!id });
|
||||||
|
|
||||||
const { mutateAsync, isError, error, isLoading } =
|
const mutationMap = {
|
||||||
api.application.update.useMutation();
|
postgres: () => api.postgres.update.useMutation(),
|
||||||
|
redis: () => api.redis.update.useMutation(),
|
||||||
|
mysql: () => api.mysql.update.useMutation(),
|
||||||
|
mariadb: () => api.mariadb.update.useMutation(),
|
||||||
|
application: () => api.application.update.useMutation(),
|
||||||
|
mongo: () => api.mongo.update.useMutation(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const { mutateAsync, isError, error, isLoading } = mutationMap[type]
|
||||||
|
? mutationMap[type]()
|
||||||
|
: api.mongo.update.useMutation();
|
||||||
|
|
||||||
const form = useForm<AddSwarmSettings>({
|
const form = useForm<AddSwarmSettings>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
@@ -244,7 +261,12 @@ export const AddSwarmSettings = ({ applicationId }: Props) => {
|
|||||||
|
|
||||||
const onSubmit = async (data: AddSwarmSettings) => {
|
const onSubmit = async (data: AddSwarmSettings) => {
|
||||||
await mutateAsync({
|
await mutateAsync({
|
||||||
applicationId,
|
applicationId: id || "",
|
||||||
|
postgresId: id || "",
|
||||||
|
redisId: id || "",
|
||||||
|
mysqlId: id || "",
|
||||||
|
mariadbId: id || "",
|
||||||
|
mongoId: id || "",
|
||||||
healthCheckSwarm: data.healthCheckSwarm,
|
healthCheckSwarm: data.healthCheckSwarm,
|
||||||
restartPolicySwarm: data.restartPolicySwarm,
|
restartPolicySwarm: data.restartPolicySwarm,
|
||||||
placementSwarm: data.placementSwarm,
|
placementSwarm: data.placementSwarm,
|
||||||
@@ -270,7 +292,7 @@ export const AddSwarmSettings = ({ applicationId }: Props) => {
|
|||||||
Swarm Settings
|
Swarm Settings
|
||||||
</Button>
|
</Button>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent className="sm:max-w-5xl p-0">
|
<DialogContent className="sm:max-w-5xl">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Swarm Settings</DialogTitle>
|
<DialogTitle>Swarm Settings</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
@@ -278,10 +300,10 @@ export const AddSwarmSettings = ({ applicationId }: Props) => {
|
|||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
{isError && <AlertBlock type="error">{error?.message}</AlertBlock>}
|
{isError && <AlertBlock type="error">{error?.message}</AlertBlock>}
|
||||||
<div className="px-4">
|
<div>
|
||||||
<AlertBlock type="info">
|
<AlertBlock type="info">
|
||||||
Changing settings such as placements may cause the logs/monitoring
|
Changing settings such as placements may cause the logs/monitoring,
|
||||||
to be unavailable.
|
backups and other features to be unavailable.
|
||||||
</AlertBlock>
|
</AlertBlock>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -289,13 +311,13 @@ export const AddSwarmSettings = ({ applicationId }: Props) => {
|
|||||||
<form
|
<form
|
||||||
id="hook-form-add-permissions"
|
id="hook-form-add-permissions"
|
||||||
onSubmit={form.handleSubmit(onSubmit)}
|
onSubmit={form.handleSubmit(onSubmit)}
|
||||||
className="grid grid-cols-1 md:grid-cols-2 w-full gap-4 relative"
|
className="grid grid-cols-1 md:grid-cols-2 w-full gap-4 relative mt-4"
|
||||||
>
|
>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="healthCheckSwarm"
|
name="healthCheckSwarm"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="relative max-lg:px-4 lg:pl-6 ">
|
<FormItem className="relative ">
|
||||||
<FormLabel>Health Check</FormLabel>
|
<FormLabel>Health Check</FormLabel>
|
||||||
<TooltipProvider delayDuration={0}>
|
<TooltipProvider delayDuration={0}>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
@@ -351,7 +373,7 @@ export const AddSwarmSettings = ({ applicationId }: Props) => {
|
|||||||
control={form.control}
|
control={form.control}
|
||||||
name="restartPolicySwarm"
|
name="restartPolicySwarm"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="relative max-lg:px-4 lg:pr-6 ">
|
<FormItem className="relative ">
|
||||||
<FormLabel>Restart Policy</FormLabel>
|
<FormLabel>Restart Policy</FormLabel>
|
||||||
<TooltipProvider delayDuration={0}>
|
<TooltipProvider delayDuration={0}>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
@@ -405,7 +427,7 @@ export const AddSwarmSettings = ({ applicationId }: Props) => {
|
|||||||
control={form.control}
|
control={form.control}
|
||||||
name="placementSwarm"
|
name="placementSwarm"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="relative max-lg:px-4 lg:pl-6 ">
|
<FormItem className="relative ">
|
||||||
<FormLabel>Placement</FormLabel>
|
<FormLabel>Placement</FormLabel>
|
||||||
<TooltipProvider delayDuration={0}>
|
<TooltipProvider delayDuration={0}>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
@@ -471,7 +493,7 @@ export const AddSwarmSettings = ({ applicationId }: Props) => {
|
|||||||
control={form.control}
|
control={form.control}
|
||||||
name="updateConfigSwarm"
|
name="updateConfigSwarm"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="relative max-lg:px-4 lg:pr-6 ">
|
<FormItem className="relative ">
|
||||||
<FormLabel>Update Config</FormLabel>
|
<FormLabel>Update Config</FormLabel>
|
||||||
<TooltipProvider delayDuration={0}>
|
<TooltipProvider delayDuration={0}>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
@@ -529,7 +551,7 @@ export const AddSwarmSettings = ({ applicationId }: Props) => {
|
|||||||
control={form.control}
|
control={form.control}
|
||||||
name="rollbackConfigSwarm"
|
name="rollbackConfigSwarm"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="relative max-lg:px-4 lg:pl-6 ">
|
<FormItem className="relative ">
|
||||||
<FormLabel>Rollback Config</FormLabel>
|
<FormLabel>Rollback Config</FormLabel>
|
||||||
<TooltipProvider delayDuration={0}>
|
<TooltipProvider delayDuration={0}>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
@@ -587,7 +609,7 @@ export const AddSwarmSettings = ({ applicationId }: Props) => {
|
|||||||
control={form.control}
|
control={form.control}
|
||||||
name="modeSwarm"
|
name="modeSwarm"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="relative max-lg:px-4 lg:pr-6 ">
|
<FormItem className="relative ">
|
||||||
<FormLabel>Mode</FormLabel>
|
<FormLabel>Mode</FormLabel>
|
||||||
<TooltipProvider delayDuration={0}>
|
<TooltipProvider delayDuration={0}>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
@@ -650,7 +672,7 @@ export const AddSwarmSettings = ({ applicationId }: Props) => {
|
|||||||
control={form.control}
|
control={form.control}
|
||||||
name="networkSwarm"
|
name="networkSwarm"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="relative max-lg:px-4 lg:pl-6 ">
|
<FormItem className="relative ">
|
||||||
<FormLabel>Network</FormLabel>
|
<FormLabel>Network</FormLabel>
|
||||||
<TooltipProvider delayDuration={0}>
|
<TooltipProvider delayDuration={0}>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
@@ -709,7 +731,7 @@ export const AddSwarmSettings = ({ applicationId }: Props) => {
|
|||||||
control={form.control}
|
control={form.control}
|
||||||
name="labelsSwarm"
|
name="labelsSwarm"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="relative max-lg:px-4 lg:pr-6 ">
|
<FormItem className="relative ">
|
||||||
<FormLabel>Labels</FormLabel>
|
<FormLabel>Labels</FormLabel>
|
||||||
<TooltipProvider delayDuration={0}>
|
<TooltipProvider delayDuration={0}>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
|
|||||||
+118
-82
@@ -1,3 +1,10 @@
|
|||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { Server } from "lucide-react";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { useForm } from "react-hook-form";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
import { z } from "zod";
|
||||||
import { AlertBlock } from "@/components/shared/alert-block";
|
import { AlertBlock } from "@/components/shared/alert-block";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
@@ -26,43 +33,57 @@ import {
|
|||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
|
||||||
import { Server } from "lucide-react";
|
|
||||||
import Link from "next/link";
|
|
||||||
import { useEffect } from "react";
|
|
||||||
import { useForm } from "react-hook-form";
|
|
||||||
import { toast } from "sonner";
|
|
||||||
import { z } from "zod";
|
|
||||||
import { AddSwarmSettings } from "./modify-swarm-settings";
|
import { AddSwarmSettings } from "./modify-swarm-settings";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
applicationId: string;
|
id: string;
|
||||||
|
type: "postgres" | "mariadb" | "mongo" | "mysql" | "redis" | "application";
|
||||||
}
|
}
|
||||||
|
|
||||||
const AddRedirectchema = z.object({
|
const AddRedirectchema = z.object({
|
||||||
replicas: z.number().min(1, "Replicas must be at least 1"),
|
replicas: z.number().min(1, "Replicas must be at least 1"),
|
||||||
registryId: z.string(),
|
registryId: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
type AddCommand = z.infer<typeof AddRedirectchema>;
|
type AddCommand = z.infer<typeof AddRedirectchema>;
|
||||||
|
|
||||||
export const ShowClusterSettings = ({ applicationId }: Props) => {
|
export const ShowClusterSettings = ({ id, type }: Props) => {
|
||||||
const { data } = api.application.one.useQuery(
|
const queryMap = {
|
||||||
{
|
postgres: () =>
|
||||||
applicationId,
|
api.postgres.one.useQuery({ postgresId: id }, { enabled: !!id }),
|
||||||
},
|
redis: () => api.redis.one.useQuery({ redisId: id }, { enabled: !!id }),
|
||||||
{ enabled: !!applicationId },
|
mysql: () => api.mysql.one.useQuery({ mysqlId: id }, { enabled: !!id }),
|
||||||
);
|
mariadb: () =>
|
||||||
|
api.mariadb.one.useQuery({ mariadbId: id }, { enabled: !!id }),
|
||||||
|
application: () =>
|
||||||
|
api.application.one.useQuery({ applicationId: id }, { enabled: !!id }),
|
||||||
|
mongo: () => api.mongo.one.useQuery({ mongoId: id }, { enabled: !!id }),
|
||||||
|
};
|
||||||
|
const { data, refetch } = queryMap[type]
|
||||||
|
? queryMap[type]()
|
||||||
|
: api.mongo.one.useQuery({ mongoId: id }, { enabled: !!id });
|
||||||
const { data: registries } = api.registry.all.useQuery();
|
const { data: registries } = api.registry.all.useQuery();
|
||||||
|
|
||||||
const utils = api.useUtils();
|
const mutationMap = {
|
||||||
|
postgres: () => api.postgres.update.useMutation(),
|
||||||
|
redis: () => api.redis.update.useMutation(),
|
||||||
|
mysql: () => api.mysql.update.useMutation(),
|
||||||
|
mariadb: () => api.mariadb.update.useMutation(),
|
||||||
|
application: () => api.application.update.useMutation(),
|
||||||
|
mongo: () => api.mongo.update.useMutation(),
|
||||||
|
};
|
||||||
|
|
||||||
const { mutateAsync, isLoading } = api.application.update.useMutation();
|
const { mutateAsync, isLoading } = mutationMap[type]
|
||||||
|
? mutationMap[type]()
|
||||||
|
: api.mongo.update.useMutation();
|
||||||
|
|
||||||
const form = useForm<AddCommand>({
|
const form = useForm<AddCommand>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
registryId: data?.registryId || "",
|
...(type === "application" && data && "registryId" in data
|
||||||
|
? {
|
||||||
|
registryId: data?.registryId || "",
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
replicas: data?.replicas || 1,
|
replicas: data?.replicas || 1,
|
||||||
},
|
},
|
||||||
resolver: zodResolver(AddRedirectchema),
|
resolver: zodResolver(AddRedirectchema),
|
||||||
@@ -71,7 +92,11 @@ export const ShowClusterSettings = ({ applicationId }: Props) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data?.command) {
|
if (data?.command) {
|
||||||
form.reset({
|
form.reset({
|
||||||
registryId: data?.registryId || "",
|
...(type === "application" && data && "registryId" in data
|
||||||
|
? {
|
||||||
|
registryId: data?.registryId || "",
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
replicas: data?.replicas || 1,
|
replicas: data?.replicas || 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -79,18 +104,25 @@ export const ShowClusterSettings = ({ applicationId }: Props) => {
|
|||||||
|
|
||||||
const onSubmit = async (data: AddCommand) => {
|
const onSubmit = async (data: AddCommand) => {
|
||||||
await mutateAsync({
|
await mutateAsync({
|
||||||
applicationId,
|
applicationId: id || "",
|
||||||
registryId:
|
postgresId: id || "",
|
||||||
data?.registryId === "none" || !data?.registryId
|
redisId: id || "",
|
||||||
? null
|
mysqlId: id || "",
|
||||||
: data?.registryId,
|
mariadbId: id || "",
|
||||||
|
mongoId: id || "",
|
||||||
|
...(type === "application"
|
||||||
|
? {
|
||||||
|
registryId:
|
||||||
|
data?.registryId === "none" || !data?.registryId
|
||||||
|
? null
|
||||||
|
: data?.registryId,
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
replicas: data?.replicas,
|
replicas: data?.replicas,
|
||||||
})
|
})
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
toast.success("Command Updated");
|
toast.success("Command Updated");
|
||||||
await utils.application.one.invalidate({
|
await refetch();
|
||||||
applicationId,
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
toast.error("Error updating the command");
|
toast.error("Error updating the command");
|
||||||
@@ -103,10 +135,10 @@ export const ShowClusterSettings = ({ applicationId }: Props) => {
|
|||||||
<div>
|
<div>
|
||||||
<CardTitle className="text-xl">Cluster Settings</CardTitle>
|
<CardTitle className="text-xl">Cluster Settings</CardTitle>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
Add the registry and the replicas of the application
|
Modify swarm settings for the service.
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
</div>
|
</div>
|
||||||
<AddSwarmSettings applicationId={applicationId} />
|
<AddSwarmSettings id={id} type={type} />
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="flex flex-col gap-4">
|
<CardContent className="flex flex-col gap-4">
|
||||||
<AlertBlock type="info">
|
<AlertBlock type="info">
|
||||||
@@ -144,58 +176,62 @@ export const ShowClusterSettings = ({ applicationId }: Props) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{registries && registries?.length === 0 ? (
|
{type === "application" && (
|
||||||
<div className="pt-10">
|
|
||||||
<div className="flex flex-col items-center gap-3">
|
|
||||||
<Server className="size-8 text-muted-foreground" />
|
|
||||||
<span className="text-base text-muted-foreground">
|
|
||||||
To use a cluster feature, you need to configure at least a
|
|
||||||
registry first. Please, go to{" "}
|
|
||||||
<Link
|
|
||||||
href="/dashboard/settings/cluster"
|
|
||||||
className="text-foreground"
|
|
||||||
>
|
|
||||||
Settings
|
|
||||||
</Link>{" "}
|
|
||||||
to do so.
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<>
|
<>
|
||||||
<FormField
|
{registries && registries?.length === 0 ? (
|
||||||
control={form.control}
|
<div className="pt-10">
|
||||||
name="registryId"
|
<div className="flex flex-col items-center gap-3">
|
||||||
render={({ field }) => (
|
<Server className="size-8 text-muted-foreground" />
|
||||||
<FormItem>
|
<span className="text-base text-muted-foreground">
|
||||||
<FormLabel>Select a registry</FormLabel>
|
To use a cluster feature, you need to configure at least
|
||||||
<Select
|
a registry first. Please, go to{" "}
|
||||||
onValueChange={field.onChange}
|
<Link
|
||||||
defaultValue={field.value}
|
href="/dashboard/settings/cluster"
|
||||||
>
|
className="text-foreground"
|
||||||
<SelectTrigger>
|
>
|
||||||
<SelectValue placeholder="Select a registry" />
|
Settings
|
||||||
</SelectTrigger>
|
</Link>{" "}
|
||||||
<SelectContent>
|
to do so.
|
||||||
<SelectGroup>
|
</span>
|
||||||
{registries?.map((registry) => (
|
</div>
|
||||||
<SelectItem
|
</div>
|
||||||
key={registry.registryId}
|
) : (
|
||||||
value={registry.registryId}
|
<>
|
||||||
>
|
<FormField
|
||||||
{registry.registryName}
|
control={form.control}
|
||||||
</SelectItem>
|
name="registryId"
|
||||||
))}
|
render={({ field }) => (
|
||||||
<SelectItem value={"none"}>None</SelectItem>
|
<FormItem>
|
||||||
<SelectLabel>
|
<FormLabel>Select a registry</FormLabel>
|
||||||
Registries ({registries?.length})
|
<Select
|
||||||
</SelectLabel>
|
onValueChange={field.onChange}
|
||||||
</SelectGroup>
|
defaultValue={field.value}
|
||||||
</SelectContent>
|
>
|
||||||
</Select>
|
<SelectTrigger>
|
||||||
</FormItem>
|
<SelectValue placeholder="Select a registry" />
|
||||||
)}
|
</SelectTrigger>
|
||||||
/>
|
<SelectContent>
|
||||||
|
<SelectGroup>
|
||||||
|
{registries?.map((registry) => (
|
||||||
|
<SelectItem
|
||||||
|
key={registry.registryId}
|
||||||
|
value={registry.registryId}
|
||||||
|
>
|
||||||
|
{registry.registryName}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
<SelectItem value={"none"}>None</SelectItem>
|
||||||
|
<SelectLabel>
|
||||||
|
Registries ({registries?.length})
|
||||||
|
</SelectLabel>
|
||||||
|
</SelectGroup>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { ShowResources } from "@/components/dashboard/application/advanced/show-resources";
|
import { ShowResources } from "@/components/dashboard/application/advanced/show-resources";
|
||||||
import { ShowVolumes } from "@/components/dashboard/application/advanced/volumes/show-volumes";
|
import { ShowVolumes } from "@/components/dashboard/application/advanced/volumes/show-volumes";
|
||||||
import { ShowCustomCommand } from "@/components/dashboard/postgres/advanced/show-custom-command";
|
import { ShowCustomCommand } from "@/components/dashboard/postgres/advanced/show-custom-command";
|
||||||
|
import { ShowClusterSettings } from "../application/advanced/cluster/show-cluster-settings";
|
||||||
import { RebuildDatabase } from "./rebuild-database";
|
import { RebuildDatabase } from "./rebuild-database";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -12,6 +13,7 @@ export const ShowDatabaseAdvancedSettings = ({ id, type }: Props) => {
|
|||||||
return (
|
return (
|
||||||
<div className="flex w-full flex-col gap-5">
|
<div className="flex w-full flex-col gap-5">
|
||||||
<ShowCustomCommand id={id} type={type} />
|
<ShowCustomCommand id={id} type={type} />
|
||||||
|
<ShowClusterSettings id={id} type={type} />
|
||||||
<ShowVolumes id={id} type={type} />
|
<ShowVolumes id={id} type={type} />
|
||||||
<ShowResources id={id} type={type} />
|
<ShowResources id={id} type={type} />
|
||||||
<RebuildDatabase id={id} type={type} />
|
<RebuildDatabase id={id} type={type} />
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
ALTER TABLE "postgres" ADD COLUMN "healthCheckSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "postgres" ADD COLUMN "restartPolicySwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "postgres" ADD COLUMN "placementSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "postgres" ADD COLUMN "updateConfigSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "postgres" ADD COLUMN "rollbackConfigSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "postgres" ADD COLUMN "modeSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "postgres" ADD COLUMN "labelsSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "postgres" ADD COLUMN "networkSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "postgres" ADD COLUMN "replicas" integer DEFAULT 1 NOT NULL;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mariadb" ADD COLUMN "healthCheckSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mariadb" ADD COLUMN "restartPolicySwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mariadb" ADD COLUMN "placementSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mariadb" ADD COLUMN "updateConfigSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mariadb" ADD COLUMN "rollbackConfigSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mariadb" ADD COLUMN "modeSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mariadb" ADD COLUMN "labelsSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mariadb" ADD COLUMN "networkSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mariadb" ADD COLUMN "replicas" integer DEFAULT 1 NOT NULL;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mongo" ADD COLUMN "healthCheckSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mongo" ADD COLUMN "restartPolicySwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mongo" ADD COLUMN "placementSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mongo" ADD COLUMN "updateConfigSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mongo" ADD COLUMN "rollbackConfigSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mongo" ADD COLUMN "modeSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mongo" ADD COLUMN "labelsSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mongo" ADD COLUMN "networkSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mongo" ADD COLUMN "replicas" integer DEFAULT 1 NOT NULL;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mysql" ADD COLUMN "healthCheckSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mysql" ADD COLUMN "restartPolicySwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mysql" ADD COLUMN "placementSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mysql" ADD COLUMN "updateConfigSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mysql" ADD COLUMN "rollbackConfigSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mysql" ADD COLUMN "modeSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mysql" ADD COLUMN "labelsSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mysql" ADD COLUMN "networkSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mysql" ADD COLUMN "replicas" integer DEFAULT 1 NOT NULL;--> statement-breakpoint
|
||||||
|
ALTER TABLE "redis" ADD COLUMN "healthCheckSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "redis" ADD COLUMN "restartPolicySwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "redis" ADD COLUMN "placementSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "redis" ADD COLUMN "updateConfigSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "redis" ADD COLUMN "rollbackConfigSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "redis" ADD COLUMN "modeSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "redis" ADD COLUMN "labelsSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "redis" ADD COLUMN "networkSwarm" json;--> statement-breakpoint
|
||||||
|
ALTER TABLE "redis" ADD COLUMN "replicas" integer DEFAULT 1 NOT NULL;
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -736,6 +736,13 @@
|
|||||||
"when": 1754207407121,
|
"when": 1754207407121,
|
||||||
"tag": "0104_omniscient_randall",
|
"tag": "0104_omniscient_randall",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 105,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1754259281559,
|
||||||
|
"tag": "0105_clumsy_quicksilver",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
+18
-15
@@ -1,3 +1,17 @@
|
|||||||
|
import { validateRequest } from "@dokploy/server/lib/auth";
|
||||||
|
import { createServerSideHelpers } from "@trpc/react-query/server";
|
||||||
|
import copy from "copy-to-clipboard";
|
||||||
|
import { GlobeIcon, HelpCircle, ServerOff } from "lucide-react";
|
||||||
|
import type {
|
||||||
|
GetServerSidePropsContext,
|
||||||
|
InferGetServerSidePropsType,
|
||||||
|
} from "next";
|
||||||
|
import Head from "next/head";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import { type ReactElement, useEffect, useState } from "react";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
import superjson from "superjson";
|
||||||
import { ShowClusterSettings } from "@/components/dashboard/application/advanced/cluster/show-cluster-settings";
|
import { ShowClusterSettings } from "@/components/dashboard/application/advanced/cluster/show-cluster-settings";
|
||||||
import { AddCommand } from "@/components/dashboard/application/advanced/general/add-command";
|
import { AddCommand } from "@/components/dashboard/application/advanced/general/add-command";
|
||||||
import { ShowPorts } from "@/components/dashboard/application/advanced/ports/show-port";
|
import { ShowPorts } from "@/components/dashboard/application/advanced/ports/show-port";
|
||||||
@@ -39,20 +53,6 @@ import {
|
|||||||
} from "@/components/ui/tooltip";
|
} from "@/components/ui/tooltip";
|
||||||
import { appRouter } from "@/server/api/root";
|
import { appRouter } from "@/server/api/root";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { validateRequest } from "@dokploy/server/lib/auth";
|
|
||||||
import { createServerSideHelpers } from "@trpc/react-query/server";
|
|
||||||
import copy from "copy-to-clipboard";
|
|
||||||
import { GlobeIcon, HelpCircle, ServerOff } from "lucide-react";
|
|
||||||
import type {
|
|
||||||
GetServerSidePropsContext,
|
|
||||||
InferGetServerSidePropsType,
|
|
||||||
} from "next";
|
|
||||||
import Head from "next/head";
|
|
||||||
import Link from "next/link";
|
|
||||||
import { useRouter } from "next/router";
|
|
||||||
import { type ReactElement, useEffect, useState } from "react";
|
|
||||||
import { toast } from "sonner";
|
|
||||||
import superjson from "superjson";
|
|
||||||
|
|
||||||
type TabState =
|
type TabState =
|
||||||
| "projects"
|
| "projects"
|
||||||
@@ -345,7 +345,10 @@ const Service = (
|
|||||||
<TabsContent value="advanced">
|
<TabsContent value="advanced">
|
||||||
<div className="flex flex-col gap-4 pt-2.5">
|
<div className="flex flex-col gap-4 pt-2.5">
|
||||||
<AddCommand applicationId={applicationId} />
|
<AddCommand applicationId={applicationId} />
|
||||||
<ShowClusterSettings applicationId={applicationId} />
|
<ShowClusterSettings
|
||||||
|
id={applicationId}
|
||||||
|
type="application"
|
||||||
|
/>
|
||||||
|
|
||||||
<ShowResources id={applicationId} type="application" />
|
<ShowResources id={applicationId} type="application" />
|
||||||
<ShowVolumes id={applicationId} type="application" />
|
<ShowVolumes id={applicationId} type="application" />
|
||||||
|
|||||||
@@ -24,7 +24,25 @@ import { redirects } from "./redirects";
|
|||||||
import { registry } from "./registry";
|
import { registry } from "./registry";
|
||||||
import { security } from "./security";
|
import { security } from "./security";
|
||||||
import { server } from "./server";
|
import { server } from "./server";
|
||||||
import { applicationStatus, certificateType, triggerType } from "./shared";
|
import {
|
||||||
|
applicationStatus,
|
||||||
|
certificateType,
|
||||||
|
type HealthCheckSwarm,
|
||||||
|
HealthCheckSwarmSchema,
|
||||||
|
type LabelsSwarm,
|
||||||
|
LabelsSwarmSchema,
|
||||||
|
type NetworkSwarm,
|
||||||
|
NetworkSwarmSchema,
|
||||||
|
type PlacementSwarm,
|
||||||
|
PlacementSwarmSchema,
|
||||||
|
type RestartPolicySwarm,
|
||||||
|
RestartPolicySwarmSchema,
|
||||||
|
type ServiceModeSwarm,
|
||||||
|
ServiceModeSwarmSchema,
|
||||||
|
triggerType,
|
||||||
|
type UpdateConfigSwarm,
|
||||||
|
UpdateConfigSwarmSchema,
|
||||||
|
} from "./shared";
|
||||||
import { sshKeys } from "./ssh-key";
|
import { sshKeys } from "./ssh-key";
|
||||||
import { generateAppName } from "./utils";
|
import { generateAppName } from "./utils";
|
||||||
export const sourceType = pgEnum("sourceType", [
|
export const sourceType = pgEnum("sourceType", [
|
||||||
@@ -46,64 +64,6 @@ export const buildType = pgEnum("buildType", [
|
|||||||
"railpack",
|
"railpack",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export interface HealthCheckSwarm {
|
|
||||||
Test?: string[] | undefined;
|
|
||||||
Interval?: number | undefined;
|
|
||||||
Timeout?: number | undefined;
|
|
||||||
StartPeriod?: number | undefined;
|
|
||||||
Retries?: number | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RestartPolicySwarm {
|
|
||||||
Condition?: string | undefined;
|
|
||||||
Delay?: number | undefined;
|
|
||||||
MaxAttempts?: number | undefined;
|
|
||||||
Window?: number | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PlacementSwarm {
|
|
||||||
Constraints?: string[] | undefined;
|
|
||||||
Preferences?: Array<{ Spread: { SpreadDescriptor: string } }> | undefined;
|
|
||||||
MaxReplicas?: number | undefined;
|
|
||||||
Platforms?:
|
|
||||||
| Array<{
|
|
||||||
Architecture: string;
|
|
||||||
OS: string;
|
|
||||||
}>
|
|
||||||
| undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UpdateConfigSwarm {
|
|
||||||
Parallelism: number;
|
|
||||||
Delay?: number | undefined;
|
|
||||||
FailureAction?: string | undefined;
|
|
||||||
Monitor?: number | undefined;
|
|
||||||
MaxFailureRatio?: number | undefined;
|
|
||||||
Order: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ServiceModeSwarm {
|
|
||||||
Replicated?: { Replicas?: number | undefined } | undefined;
|
|
||||||
Global?: {} | undefined;
|
|
||||||
ReplicatedJob?:
|
|
||||||
| {
|
|
||||||
MaxConcurrent?: number | undefined;
|
|
||||||
TotalCompletions?: number | undefined;
|
|
||||||
}
|
|
||||||
| undefined;
|
|
||||||
GlobalJob?: {} | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NetworkSwarm {
|
|
||||||
Target?: string | undefined;
|
|
||||||
Aliases?: string[] | undefined;
|
|
||||||
DriverOpts?: { [key: string]: string } | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LabelsSwarm {
|
|
||||||
[name: string]: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const applications = pgTable("application", {
|
export const applications = pgTable("application", {
|
||||||
applicationId: text("applicationId")
|
applicationId: text("applicationId")
|
||||||
.notNull()
|
.notNull()
|
||||||
@@ -283,94 +243,6 @@ export const applicationsRelations = relations(
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const HealthCheckSwarmSchema = z
|
|
||||||
.object({
|
|
||||||
Test: z.array(z.string()).optional(),
|
|
||||||
Interval: z.number().optional(),
|
|
||||||
Timeout: z.number().optional(),
|
|
||||||
StartPeriod: z.number().optional(),
|
|
||||||
Retries: z.number().optional(),
|
|
||||||
})
|
|
||||||
.strict();
|
|
||||||
|
|
||||||
const RestartPolicySwarmSchema = z
|
|
||||||
.object({
|
|
||||||
Condition: z.string().optional(),
|
|
||||||
Delay: z.number().optional(),
|
|
||||||
MaxAttempts: z.number().optional(),
|
|
||||||
Window: z.number().optional(),
|
|
||||||
})
|
|
||||||
.strict();
|
|
||||||
|
|
||||||
const PreferenceSchema = z
|
|
||||||
.object({
|
|
||||||
Spread: z.object({
|
|
||||||
SpreadDescriptor: z.string(),
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
.strict();
|
|
||||||
|
|
||||||
const PlatformSchema = z
|
|
||||||
.object({
|
|
||||||
Architecture: z.string(),
|
|
||||||
OS: z.string(),
|
|
||||||
})
|
|
||||||
.strict();
|
|
||||||
|
|
||||||
const PlacementSwarmSchema = z
|
|
||||||
.object({
|
|
||||||
Constraints: z.array(z.string()).optional(),
|
|
||||||
Preferences: z.array(PreferenceSchema).optional(),
|
|
||||||
MaxReplicas: z.number().optional(),
|
|
||||||
Platforms: z.array(PlatformSchema).optional(),
|
|
||||||
})
|
|
||||||
.strict();
|
|
||||||
|
|
||||||
const UpdateConfigSwarmSchema = z
|
|
||||||
.object({
|
|
||||||
Parallelism: z.number(),
|
|
||||||
Delay: z.number().optional(),
|
|
||||||
FailureAction: z.string().optional(),
|
|
||||||
Monitor: z.number().optional(),
|
|
||||||
MaxFailureRatio: z.number().optional(),
|
|
||||||
Order: z.string(),
|
|
||||||
})
|
|
||||||
.strict();
|
|
||||||
|
|
||||||
const ReplicatedSchema = z
|
|
||||||
.object({
|
|
||||||
Replicas: z.number().optional(),
|
|
||||||
})
|
|
||||||
.strict();
|
|
||||||
|
|
||||||
const ReplicatedJobSchema = z
|
|
||||||
.object({
|
|
||||||
MaxConcurrent: z.number().optional(),
|
|
||||||
TotalCompletions: z.number().optional(),
|
|
||||||
})
|
|
||||||
.strict();
|
|
||||||
|
|
||||||
const ServiceModeSwarmSchema = z
|
|
||||||
.object({
|
|
||||||
Replicated: ReplicatedSchema.optional(),
|
|
||||||
Global: z.object({}).optional(),
|
|
||||||
ReplicatedJob: ReplicatedJobSchema.optional(),
|
|
||||||
GlobalJob: z.object({}).optional(),
|
|
||||||
})
|
|
||||||
.strict();
|
|
||||||
|
|
||||||
const NetworkSwarmSchema = z.array(
|
|
||||||
z
|
|
||||||
.object({
|
|
||||||
Target: z.string().optional(),
|
|
||||||
Aliases: z.array(z.string()).optional(),
|
|
||||||
DriverOpts: z.object({}).optional(),
|
|
||||||
})
|
|
||||||
.strict(),
|
|
||||||
);
|
|
||||||
|
|
||||||
const LabelsSwarmSchema = z.record(z.string());
|
|
||||||
|
|
||||||
const createSchema = createInsertSchema(applications, {
|
const createSchema = createInsertSchema(applications, {
|
||||||
appName: z.string(),
|
appName: z.string(),
|
||||||
createdAt: z.string(),
|
createdAt: z.string(),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { relations } from "drizzle-orm";
|
import { relations } from "drizzle-orm";
|
||||||
import { integer, pgTable, text } from "drizzle-orm/pg-core";
|
import { integer, json, pgTable, text } from "drizzle-orm/pg-core";
|
||||||
import { createInsertSchema } from "drizzle-zod";
|
import { createInsertSchema } from "drizzle-zod";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
@@ -7,7 +7,23 @@ import { backups } from "./backups";
|
|||||||
import { mounts } from "./mount";
|
import { mounts } from "./mount";
|
||||||
import { projects } from "./project";
|
import { projects } from "./project";
|
||||||
import { server } from "./server";
|
import { server } from "./server";
|
||||||
import { applicationStatus } from "./shared";
|
import {
|
||||||
|
applicationStatus,
|
||||||
|
type HealthCheckSwarm,
|
||||||
|
HealthCheckSwarmSchema,
|
||||||
|
type LabelsSwarm,
|
||||||
|
LabelsSwarmSchema,
|
||||||
|
type NetworkSwarm,
|
||||||
|
NetworkSwarmSchema,
|
||||||
|
type PlacementSwarm,
|
||||||
|
PlacementSwarmSchema,
|
||||||
|
type RestartPolicySwarm,
|
||||||
|
RestartPolicySwarmSchema,
|
||||||
|
type ServiceModeSwarm,
|
||||||
|
ServiceModeSwarmSchema,
|
||||||
|
type UpdateConfigSwarm,
|
||||||
|
UpdateConfigSwarmSchema,
|
||||||
|
} from "./shared";
|
||||||
import { generateAppName } from "./utils";
|
import { generateAppName } from "./utils";
|
||||||
|
|
||||||
export const mariadb = pgTable("mariadb", {
|
export const mariadb = pgTable("mariadb", {
|
||||||
@@ -38,6 +54,15 @@ export const mariadb = pgTable("mariadb", {
|
|||||||
applicationStatus: applicationStatus("applicationStatus")
|
applicationStatus: applicationStatus("applicationStatus")
|
||||||
.notNull()
|
.notNull()
|
||||||
.default("idle"),
|
.default("idle"),
|
||||||
|
healthCheckSwarm: json("healthCheckSwarm").$type<HealthCheckSwarm>(),
|
||||||
|
restartPolicySwarm: json("restartPolicySwarm").$type<RestartPolicySwarm>(),
|
||||||
|
placementSwarm: json("placementSwarm").$type<PlacementSwarm>(),
|
||||||
|
updateConfigSwarm: json("updateConfigSwarm").$type<UpdateConfigSwarm>(),
|
||||||
|
rollbackConfigSwarm: json("rollbackConfigSwarm").$type<UpdateConfigSwarm>(),
|
||||||
|
modeSwarm: json("modeSwarm").$type<ServiceModeSwarm>(),
|
||||||
|
labelsSwarm: json("labelsSwarm").$type<LabelsSwarm>(),
|
||||||
|
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
||||||
|
replicas: integer("replicas").default(1).notNull(),
|
||||||
createdAt: text("createdAt")
|
createdAt: text("createdAt")
|
||||||
.notNull()
|
.notNull()
|
||||||
.$defaultFn(() => new Date().toISOString()),
|
.$defaultFn(() => new Date().toISOString()),
|
||||||
@@ -83,6 +108,14 @@ const createSchema = createInsertSchema(mariadb, {
|
|||||||
externalPort: z.number(),
|
externalPort: z.number(),
|
||||||
description: z.string().optional(),
|
description: z.string().optional(),
|
||||||
serverId: z.string().optional(),
|
serverId: z.string().optional(),
|
||||||
|
healthCheckSwarm: HealthCheckSwarmSchema.nullable(),
|
||||||
|
restartPolicySwarm: RestartPolicySwarmSchema.nullable(),
|
||||||
|
placementSwarm: PlacementSwarmSchema.nullable(),
|
||||||
|
updateConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||||
|
rollbackConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||||
|
modeSwarm: ServiceModeSwarmSchema.nullable(),
|
||||||
|
labelsSwarm: LabelsSwarmSchema.nullable(),
|
||||||
|
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const apiCreateMariaDB = createSchema
|
export const apiCreateMariaDB = createSchema
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { relations } from "drizzle-orm";
|
import { relations } from "drizzle-orm";
|
||||||
import { boolean, integer, pgTable, text } from "drizzle-orm/pg-core";
|
import { boolean, integer, json, pgTable, text } from "drizzle-orm/pg-core";
|
||||||
import { createInsertSchema } from "drizzle-zod";
|
import { createInsertSchema } from "drizzle-zod";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
@@ -7,7 +7,23 @@ import { backups } from "./backups";
|
|||||||
import { mounts } from "./mount";
|
import { mounts } from "./mount";
|
||||||
import { projects } from "./project";
|
import { projects } from "./project";
|
||||||
import { server } from "./server";
|
import { server } from "./server";
|
||||||
import { applicationStatus } from "./shared";
|
import {
|
||||||
|
applicationStatus,
|
||||||
|
type HealthCheckSwarm,
|
||||||
|
HealthCheckSwarmSchema,
|
||||||
|
type LabelsSwarm,
|
||||||
|
LabelsSwarmSchema,
|
||||||
|
type NetworkSwarm,
|
||||||
|
NetworkSwarmSchema,
|
||||||
|
type PlacementSwarm,
|
||||||
|
PlacementSwarmSchema,
|
||||||
|
type RestartPolicySwarm,
|
||||||
|
RestartPolicySwarmSchema,
|
||||||
|
type ServiceModeSwarm,
|
||||||
|
ServiceModeSwarmSchema,
|
||||||
|
type UpdateConfigSwarm,
|
||||||
|
UpdateConfigSwarmSchema,
|
||||||
|
} from "./shared";
|
||||||
import { generateAppName } from "./utils";
|
import { generateAppName } from "./utils";
|
||||||
|
|
||||||
export const mongo = pgTable("mongo", {
|
export const mongo = pgTable("mongo", {
|
||||||
@@ -34,6 +50,15 @@ export const mongo = pgTable("mongo", {
|
|||||||
applicationStatus: applicationStatus("applicationStatus")
|
applicationStatus: applicationStatus("applicationStatus")
|
||||||
.notNull()
|
.notNull()
|
||||||
.default("idle"),
|
.default("idle"),
|
||||||
|
healthCheckSwarm: json("healthCheckSwarm").$type<HealthCheckSwarm>(),
|
||||||
|
restartPolicySwarm: json("restartPolicySwarm").$type<RestartPolicySwarm>(),
|
||||||
|
placementSwarm: json("placementSwarm").$type<PlacementSwarm>(),
|
||||||
|
updateConfigSwarm: json("updateConfigSwarm").$type<UpdateConfigSwarm>(),
|
||||||
|
rollbackConfigSwarm: json("rollbackConfigSwarm").$type<UpdateConfigSwarm>(),
|
||||||
|
modeSwarm: json("modeSwarm").$type<ServiceModeSwarm>(),
|
||||||
|
labelsSwarm: json("labelsSwarm").$type<LabelsSwarm>(),
|
||||||
|
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
||||||
|
replicas: integer("replicas").default(1).notNull(),
|
||||||
createdAt: text("createdAt")
|
createdAt: text("createdAt")
|
||||||
.notNull()
|
.notNull()
|
||||||
.$defaultFn(() => new Date().toISOString()),
|
.$defaultFn(() => new Date().toISOString()),
|
||||||
@@ -79,6 +104,14 @@ const createSchema = createInsertSchema(mongo, {
|
|||||||
description: z.string().optional(),
|
description: z.string().optional(),
|
||||||
serverId: z.string().optional(),
|
serverId: z.string().optional(),
|
||||||
replicaSets: z.boolean().default(false),
|
replicaSets: z.boolean().default(false),
|
||||||
|
healthCheckSwarm: HealthCheckSwarmSchema.nullable(),
|
||||||
|
restartPolicySwarm: RestartPolicySwarmSchema.nullable(),
|
||||||
|
placementSwarm: PlacementSwarmSchema.nullable(),
|
||||||
|
updateConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||||
|
rollbackConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||||
|
modeSwarm: ServiceModeSwarmSchema.nullable(),
|
||||||
|
labelsSwarm: LabelsSwarmSchema.nullable(),
|
||||||
|
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const apiCreateMongo = createSchema
|
export const apiCreateMongo = createSchema
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { relations } from "drizzle-orm";
|
import { relations } from "drizzle-orm";
|
||||||
import { integer, pgTable, text } from "drizzle-orm/pg-core";
|
import { integer, json, pgTable, text } from "drizzle-orm/pg-core";
|
||||||
import { createInsertSchema } from "drizzle-zod";
|
import { createInsertSchema } from "drizzle-zod";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
@@ -7,7 +7,23 @@ import { backups } from "./backups";
|
|||||||
import { mounts } from "./mount";
|
import { mounts } from "./mount";
|
||||||
import { projects } from "./project";
|
import { projects } from "./project";
|
||||||
import { server } from "./server";
|
import { server } from "./server";
|
||||||
import { applicationStatus } from "./shared";
|
import {
|
||||||
|
applicationStatus,
|
||||||
|
type HealthCheckSwarm,
|
||||||
|
HealthCheckSwarmSchema,
|
||||||
|
type LabelsSwarm,
|
||||||
|
LabelsSwarmSchema,
|
||||||
|
type NetworkSwarm,
|
||||||
|
NetworkSwarmSchema,
|
||||||
|
type PlacementSwarm,
|
||||||
|
PlacementSwarmSchema,
|
||||||
|
type RestartPolicySwarm,
|
||||||
|
RestartPolicySwarmSchema,
|
||||||
|
type ServiceModeSwarm,
|
||||||
|
ServiceModeSwarmSchema,
|
||||||
|
type UpdateConfigSwarm,
|
||||||
|
UpdateConfigSwarmSchema,
|
||||||
|
} from "./shared";
|
||||||
import { generateAppName } from "./utils";
|
import { generateAppName } from "./utils";
|
||||||
|
|
||||||
export const mysql = pgTable("mysql", {
|
export const mysql = pgTable("mysql", {
|
||||||
@@ -36,6 +52,15 @@ export const mysql = pgTable("mysql", {
|
|||||||
applicationStatus: applicationStatus("applicationStatus")
|
applicationStatus: applicationStatus("applicationStatus")
|
||||||
.notNull()
|
.notNull()
|
||||||
.default("idle"),
|
.default("idle"),
|
||||||
|
healthCheckSwarm: json("healthCheckSwarm").$type<HealthCheckSwarm>(),
|
||||||
|
restartPolicySwarm: json("restartPolicySwarm").$type<RestartPolicySwarm>(),
|
||||||
|
placementSwarm: json("placementSwarm").$type<PlacementSwarm>(),
|
||||||
|
updateConfigSwarm: json("updateConfigSwarm").$type<UpdateConfigSwarm>(),
|
||||||
|
rollbackConfigSwarm: json("rollbackConfigSwarm").$type<UpdateConfigSwarm>(),
|
||||||
|
modeSwarm: json("modeSwarm").$type<ServiceModeSwarm>(),
|
||||||
|
labelsSwarm: json("labelsSwarm").$type<LabelsSwarm>(),
|
||||||
|
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
||||||
|
replicas: integer("replicas").default(1).notNull(),
|
||||||
createdAt: text("createdAt")
|
createdAt: text("createdAt")
|
||||||
.notNull()
|
.notNull()
|
||||||
.$defaultFn(() => new Date().toISOString()),
|
.$defaultFn(() => new Date().toISOString()),
|
||||||
@@ -81,6 +106,14 @@ const createSchema = createInsertSchema(mysql, {
|
|||||||
externalPort: z.number(),
|
externalPort: z.number(),
|
||||||
description: z.string().optional(),
|
description: z.string().optional(),
|
||||||
serverId: z.string().optional(),
|
serverId: z.string().optional(),
|
||||||
|
healthCheckSwarm: HealthCheckSwarmSchema.nullable(),
|
||||||
|
restartPolicySwarm: RestartPolicySwarmSchema.nullable(),
|
||||||
|
placementSwarm: PlacementSwarmSchema.nullable(),
|
||||||
|
updateConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||||
|
rollbackConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||||
|
modeSwarm: ServiceModeSwarmSchema.nullable(),
|
||||||
|
labelsSwarm: LabelsSwarmSchema.nullable(),
|
||||||
|
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const apiCreateMySql = createSchema
|
export const apiCreateMySql = createSchema
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { relations } from "drizzle-orm";
|
import { relations } from "drizzle-orm";
|
||||||
import { integer, pgTable, text } from "drizzle-orm/pg-core";
|
import { integer, json, pgTable, text } from "drizzle-orm/pg-core";
|
||||||
import { createInsertSchema } from "drizzle-zod";
|
import { createInsertSchema } from "drizzle-zod";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
@@ -7,7 +7,23 @@ import { backups } from "./backups";
|
|||||||
import { mounts } from "./mount";
|
import { mounts } from "./mount";
|
||||||
import { projects } from "./project";
|
import { projects } from "./project";
|
||||||
import { server } from "./server";
|
import { server } from "./server";
|
||||||
import { applicationStatus } from "./shared";
|
import {
|
||||||
|
applicationStatus,
|
||||||
|
type HealthCheckSwarm,
|
||||||
|
HealthCheckSwarmSchema,
|
||||||
|
type LabelsSwarm,
|
||||||
|
LabelsSwarmSchema,
|
||||||
|
type NetworkSwarm,
|
||||||
|
NetworkSwarmSchema,
|
||||||
|
type PlacementSwarm,
|
||||||
|
PlacementSwarmSchema,
|
||||||
|
type RestartPolicySwarm,
|
||||||
|
RestartPolicySwarmSchema,
|
||||||
|
type ServiceModeSwarm,
|
||||||
|
ServiceModeSwarmSchema,
|
||||||
|
type UpdateConfigSwarm,
|
||||||
|
UpdateConfigSwarmSchema,
|
||||||
|
} from "./shared";
|
||||||
import { generateAppName } from "./utils";
|
import { generateAppName } from "./utils";
|
||||||
|
|
||||||
export const postgres = pgTable("postgres", {
|
export const postgres = pgTable("postgres", {
|
||||||
@@ -35,6 +51,16 @@ export const postgres = pgTable("postgres", {
|
|||||||
applicationStatus: applicationStatus("applicationStatus")
|
applicationStatus: applicationStatus("applicationStatus")
|
||||||
.notNull()
|
.notNull()
|
||||||
.default("idle"),
|
.default("idle"),
|
||||||
|
|
||||||
|
healthCheckSwarm: json("healthCheckSwarm").$type<HealthCheckSwarm>(),
|
||||||
|
restartPolicySwarm: json("restartPolicySwarm").$type<RestartPolicySwarm>(),
|
||||||
|
placementSwarm: json("placementSwarm").$type<PlacementSwarm>(),
|
||||||
|
updateConfigSwarm: json("updateConfigSwarm").$type<UpdateConfigSwarm>(),
|
||||||
|
rollbackConfigSwarm: json("rollbackConfigSwarm").$type<UpdateConfigSwarm>(),
|
||||||
|
modeSwarm: json("modeSwarm").$type<ServiceModeSwarm>(),
|
||||||
|
labelsSwarm: json("labelsSwarm").$type<LabelsSwarm>(),
|
||||||
|
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
||||||
|
replicas: integer("replicas").default(1).notNull(),
|
||||||
createdAt: text("createdAt")
|
createdAt: text("createdAt")
|
||||||
.notNull()
|
.notNull()
|
||||||
.$defaultFn(() => new Date().toISOString()),
|
.$defaultFn(() => new Date().toISOString()),
|
||||||
@@ -78,6 +104,14 @@ const createSchema = createInsertSchema(postgres, {
|
|||||||
createdAt: z.string(),
|
createdAt: z.string(),
|
||||||
description: z.string().optional(),
|
description: z.string().optional(),
|
||||||
serverId: z.string().optional(),
|
serverId: z.string().optional(),
|
||||||
|
healthCheckSwarm: HealthCheckSwarmSchema.nullable(),
|
||||||
|
restartPolicySwarm: RestartPolicySwarmSchema.nullable(),
|
||||||
|
placementSwarm: PlacementSwarmSchema.nullable(),
|
||||||
|
updateConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||||
|
rollbackConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||||
|
modeSwarm: ServiceModeSwarmSchema.nullable(),
|
||||||
|
labelsSwarm: LabelsSwarmSchema.nullable(),
|
||||||
|
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const apiCreatePostgres = createSchema
|
export const apiCreatePostgres = createSchema
|
||||||
|
|||||||
@@ -1,12 +1,28 @@
|
|||||||
import { relations } from "drizzle-orm";
|
import { relations } from "drizzle-orm";
|
||||||
import { integer, pgTable, text } from "drizzle-orm/pg-core";
|
import { integer, json, pgTable, text } from "drizzle-orm/pg-core";
|
||||||
import { createInsertSchema } from "drizzle-zod";
|
import { createInsertSchema } from "drizzle-zod";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { mounts } from "./mount";
|
import { mounts } from "./mount";
|
||||||
import { projects } from "./project";
|
import { projects } from "./project";
|
||||||
import { server } from "./server";
|
import { server } from "./server";
|
||||||
import { applicationStatus } from "./shared";
|
import {
|
||||||
|
applicationStatus,
|
||||||
|
type HealthCheckSwarm,
|
||||||
|
HealthCheckSwarmSchema,
|
||||||
|
type LabelsSwarm,
|
||||||
|
LabelsSwarmSchema,
|
||||||
|
type NetworkSwarm,
|
||||||
|
NetworkSwarmSchema,
|
||||||
|
type PlacementSwarm,
|
||||||
|
PlacementSwarmSchema,
|
||||||
|
type RestartPolicySwarm,
|
||||||
|
RestartPolicySwarmSchema,
|
||||||
|
type ServiceModeSwarm,
|
||||||
|
ServiceModeSwarmSchema,
|
||||||
|
type UpdateConfigSwarm,
|
||||||
|
UpdateConfigSwarmSchema,
|
||||||
|
} from "./shared";
|
||||||
import { generateAppName } from "./utils";
|
import { generateAppName } from "./utils";
|
||||||
|
|
||||||
export const redis = pgTable("redis", {
|
export const redis = pgTable("redis", {
|
||||||
@@ -35,6 +51,15 @@ export const redis = pgTable("redis", {
|
|||||||
applicationStatus: applicationStatus("applicationStatus")
|
applicationStatus: applicationStatus("applicationStatus")
|
||||||
.notNull()
|
.notNull()
|
||||||
.default("idle"),
|
.default("idle"),
|
||||||
|
healthCheckSwarm: json("healthCheckSwarm").$type<HealthCheckSwarm>(),
|
||||||
|
restartPolicySwarm: json("restartPolicySwarm").$type<RestartPolicySwarm>(),
|
||||||
|
placementSwarm: json("placementSwarm").$type<PlacementSwarm>(),
|
||||||
|
updateConfigSwarm: json("updateConfigSwarm").$type<UpdateConfigSwarm>(),
|
||||||
|
rollbackConfigSwarm: json("rollbackConfigSwarm").$type<UpdateConfigSwarm>(),
|
||||||
|
modeSwarm: json("modeSwarm").$type<ServiceModeSwarm>(),
|
||||||
|
labelsSwarm: json("labelsSwarm").$type<LabelsSwarm>(),
|
||||||
|
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
||||||
|
replicas: integer("replicas").default(1).notNull(),
|
||||||
projectId: text("projectId")
|
projectId: text("projectId")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => projects.projectId, { onDelete: "cascade" }),
|
.references(() => projects.projectId, { onDelete: "cascade" }),
|
||||||
@@ -73,6 +98,14 @@ const createSchema = createInsertSchema(redis, {
|
|||||||
externalPort: z.number(),
|
externalPort: z.number(),
|
||||||
description: z.string().optional(),
|
description: z.string().optional(),
|
||||||
serverId: z.string().optional(),
|
serverId: z.string().optional(),
|
||||||
|
healthCheckSwarm: HealthCheckSwarmSchema.nullable(),
|
||||||
|
restartPolicySwarm: RestartPolicySwarmSchema.nullable(),
|
||||||
|
placementSwarm: PlacementSwarmSchema.nullable(),
|
||||||
|
updateConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||||
|
rollbackConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
||||||
|
modeSwarm: ServiceModeSwarmSchema.nullable(),
|
||||||
|
labelsSwarm: LabelsSwarmSchema.nullable(),
|
||||||
|
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const apiCreateRedis = createSchema
|
export const apiCreateRedis = createSchema
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { pgEnum } from "drizzle-orm/pg-core";
|
import { pgEnum } from "drizzle-orm/pg-core";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
export const applicationStatus = pgEnum("applicationStatus", [
|
export const applicationStatus = pgEnum("applicationStatus", [
|
||||||
"idle",
|
"idle",
|
||||||
@@ -14,3 +15,149 @@ export const certificateType = pgEnum("certificateType", [
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
export const triggerType = pgEnum("triggerType", ["push", "tag"]);
|
export const triggerType = pgEnum("triggerType", ["push", "tag"]);
|
||||||
|
|
||||||
|
export interface HealthCheckSwarm {
|
||||||
|
Test?: string[] | undefined;
|
||||||
|
Interval?: number | undefined;
|
||||||
|
Timeout?: number | undefined;
|
||||||
|
StartPeriod?: number | undefined;
|
||||||
|
Retries?: number | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RestartPolicySwarm {
|
||||||
|
Condition?: string | undefined;
|
||||||
|
Delay?: number | undefined;
|
||||||
|
MaxAttempts?: number | undefined;
|
||||||
|
Window?: number | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PlacementSwarm {
|
||||||
|
Constraints?: string[] | undefined;
|
||||||
|
Preferences?: Array<{ Spread: { SpreadDescriptor: string } }> | undefined;
|
||||||
|
MaxReplicas?: number | undefined;
|
||||||
|
Platforms?:
|
||||||
|
| Array<{
|
||||||
|
Architecture: string;
|
||||||
|
OS: string;
|
||||||
|
}>
|
||||||
|
| undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdateConfigSwarm {
|
||||||
|
Parallelism: number;
|
||||||
|
Delay?: number | undefined;
|
||||||
|
FailureAction?: string | undefined;
|
||||||
|
Monitor?: number | undefined;
|
||||||
|
MaxFailureRatio?: number | undefined;
|
||||||
|
Order: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServiceModeSwarm {
|
||||||
|
Replicated?: { Replicas?: number | undefined } | undefined;
|
||||||
|
Global?: {} | undefined;
|
||||||
|
ReplicatedJob?:
|
||||||
|
| {
|
||||||
|
MaxConcurrent?: number | undefined;
|
||||||
|
TotalCompletions?: number | undefined;
|
||||||
|
}
|
||||||
|
| undefined;
|
||||||
|
GlobalJob?: {} | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NetworkSwarm {
|
||||||
|
Target?: string | undefined;
|
||||||
|
Aliases?: string[] | undefined;
|
||||||
|
DriverOpts?: { [key: string]: string } | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LabelsSwarm {
|
||||||
|
[name: string]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const HealthCheckSwarmSchema = z
|
||||||
|
.object({
|
||||||
|
Test: z.array(z.string()).optional(),
|
||||||
|
Interval: z.number().optional(),
|
||||||
|
Timeout: z.number().optional(),
|
||||||
|
StartPeriod: z.number().optional(),
|
||||||
|
Retries: z.number().optional(),
|
||||||
|
})
|
||||||
|
.strict();
|
||||||
|
|
||||||
|
export const RestartPolicySwarmSchema = z
|
||||||
|
.object({
|
||||||
|
Condition: z.string().optional(),
|
||||||
|
Delay: z.number().optional(),
|
||||||
|
MaxAttempts: z.number().optional(),
|
||||||
|
Window: z.number().optional(),
|
||||||
|
})
|
||||||
|
.strict();
|
||||||
|
|
||||||
|
export const PreferenceSchema = z
|
||||||
|
.object({
|
||||||
|
Spread: z.object({
|
||||||
|
SpreadDescriptor: z.string(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.strict();
|
||||||
|
|
||||||
|
export const PlatformSchema = z
|
||||||
|
.object({
|
||||||
|
Architecture: z.string(),
|
||||||
|
OS: z.string(),
|
||||||
|
})
|
||||||
|
.strict();
|
||||||
|
|
||||||
|
export const PlacementSwarmSchema = z
|
||||||
|
.object({
|
||||||
|
Constraints: z.array(z.string()).optional(),
|
||||||
|
Preferences: z.array(PreferenceSchema).optional(),
|
||||||
|
MaxReplicas: z.number().optional(),
|
||||||
|
Platforms: z.array(PlatformSchema).optional(),
|
||||||
|
})
|
||||||
|
.strict();
|
||||||
|
|
||||||
|
export const UpdateConfigSwarmSchema = z
|
||||||
|
.object({
|
||||||
|
Parallelism: z.number(),
|
||||||
|
Delay: z.number().optional(),
|
||||||
|
FailureAction: z.string().optional(),
|
||||||
|
Monitor: z.number().optional(),
|
||||||
|
MaxFailureRatio: z.number().optional(),
|
||||||
|
Order: z.string(),
|
||||||
|
})
|
||||||
|
.strict();
|
||||||
|
|
||||||
|
export const ReplicatedSchema = z
|
||||||
|
.object({
|
||||||
|
Replicas: z.number().optional(),
|
||||||
|
})
|
||||||
|
.strict();
|
||||||
|
|
||||||
|
export const ReplicatedJobSchema = z
|
||||||
|
.object({
|
||||||
|
MaxConcurrent: z.number().optional(),
|
||||||
|
TotalCompletions: z.number().optional(),
|
||||||
|
})
|
||||||
|
.strict();
|
||||||
|
|
||||||
|
export const ServiceModeSwarmSchema = z
|
||||||
|
.object({
|
||||||
|
Replicated: ReplicatedSchema.optional(),
|
||||||
|
Global: z.object({}).optional(),
|
||||||
|
ReplicatedJob: ReplicatedJobSchema.optional(),
|
||||||
|
GlobalJob: z.object({}).optional(),
|
||||||
|
})
|
||||||
|
.strict();
|
||||||
|
|
||||||
|
export const NetworkSwarmSchema = z.array(
|
||||||
|
z
|
||||||
|
.object({
|
||||||
|
Target: z.string().optional(),
|
||||||
|
Aliases: z.array(z.string()).optional(),
|
||||||
|
DriverOpts: z.object({}).optional(),
|
||||||
|
})
|
||||||
|
.strict(),
|
||||||
|
);
|
||||||
|
|
||||||
|
export const LabelsSwarmSchema = z.record(z.string());
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import type { CreateServiceOptions } from "dockerode";
|
|||||||
import {
|
import {
|
||||||
calculateResources,
|
calculateResources,
|
||||||
generateBindMounts,
|
generateBindMounts,
|
||||||
|
generateConfigContainer,
|
||||||
generateFileMounts,
|
generateFileMounts,
|
||||||
generateVolumeMounts,
|
generateVolumeMounts,
|
||||||
prepareEnvironmentVariables,
|
prepareEnvironmentVariables,
|
||||||
@@ -34,6 +35,17 @@ export const buildMariadb = async (mariadb: MariadbNested) => {
|
|||||||
const defaultMariadbEnv = `MARIADB_DATABASE="${databaseName}"\nMARIADB_USER="${databaseUser}"\nMARIADB_PASSWORD="${databasePassword}"\nMARIADB_ROOT_PASSWORD="${databaseRootPassword}"${
|
const defaultMariadbEnv = `MARIADB_DATABASE="${databaseName}"\nMARIADB_USER="${databaseUser}"\nMARIADB_PASSWORD="${databasePassword}"\nMARIADB_ROOT_PASSWORD="${databaseRootPassword}"${
|
||||||
env ? `\n${env}` : ""
|
env ? `\n${env}` : ""
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
|
const {
|
||||||
|
HealthCheck,
|
||||||
|
RestartPolicy,
|
||||||
|
Placement,
|
||||||
|
Labels,
|
||||||
|
Mode,
|
||||||
|
RollbackConfig,
|
||||||
|
UpdateConfig,
|
||||||
|
Networks,
|
||||||
|
} = generateConfigContainer(mariadb);
|
||||||
const resources = calculateResources({
|
const resources = calculateResources({
|
||||||
memoryLimit,
|
memoryLimit,
|
||||||
memoryReservation,
|
memoryReservation,
|
||||||
@@ -54,6 +66,7 @@ export const buildMariadb = async (mariadb: MariadbNested) => {
|
|||||||
Name: appName,
|
Name: appName,
|
||||||
TaskTemplate: {
|
TaskTemplate: {
|
||||||
ContainerSpec: {
|
ContainerSpec: {
|
||||||
|
HealthCheck,
|
||||||
Image: dockerImage,
|
Image: dockerImage,
|
||||||
Env: envVariables,
|
Env: envVariables,
|
||||||
Mounts: [...volumesMount, ...bindsMount, ...filesMount],
|
Mounts: [...volumesMount, ...bindsMount, ...filesMount],
|
||||||
@@ -63,20 +76,17 @@ export const buildMariadb = async (mariadb: MariadbNested) => {
|
|||||||
Args: ["-c", command],
|
Args: ["-c", command],
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
|
Labels,
|
||||||
},
|
},
|
||||||
Networks: [{ Target: "dokploy-network" }],
|
Networks,
|
||||||
|
RestartPolicy,
|
||||||
|
Placement,
|
||||||
Resources: {
|
Resources: {
|
||||||
...resources,
|
...resources,
|
||||||
},
|
},
|
||||||
Placement: {
|
|
||||||
Constraints: ["node.role==manager"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Mode: {
|
|
||||||
Replicated: {
|
|
||||||
Replicas: 1,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
Mode,
|
||||||
|
RollbackConfig,
|
||||||
EndpointSpec: {
|
EndpointSpec: {
|
||||||
Mode: "dnsrr",
|
Mode: "dnsrr",
|
||||||
Ports: externalPort
|
Ports: externalPort
|
||||||
@@ -90,6 +100,7 @@ export const buildMariadb = async (mariadb: MariadbNested) => {
|
|||||||
]
|
]
|
||||||
: [],
|
: [],
|
||||||
},
|
},
|
||||||
|
UpdateConfig,
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
const service = docker.getService(appName);
|
const service = docker.getService(appName);
|
||||||
@@ -97,6 +108,10 @@ export const buildMariadb = async (mariadb: MariadbNested) => {
|
|||||||
await service.update({
|
await service.update({
|
||||||
version: Number.parseInt(inspect.Version.Index),
|
version: Number.parseInt(inspect.Version.Index),
|
||||||
...settings,
|
...settings,
|
||||||
|
TaskTemplate: {
|
||||||
|
...settings.TaskTemplate,
|
||||||
|
ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
} catch {
|
} catch {
|
||||||
await docker.createService(settings);
|
await docker.createService(settings);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import type { CreateServiceOptions } from "dockerode";
|
|||||||
import {
|
import {
|
||||||
calculateResources,
|
calculateResources,
|
||||||
generateBindMounts,
|
generateBindMounts,
|
||||||
|
generateConfigContainer,
|
||||||
generateFileMounts,
|
generateFileMounts,
|
||||||
generateVolumeMounts,
|
generateVolumeMounts,
|
||||||
prepareEnvironmentVariables,
|
prepareEnvironmentVariables,
|
||||||
@@ -81,6 +82,17 @@ ${command ?? "wait $MONGOD_PID"}`;
|
|||||||
env ? `\n${env}` : ""
|
env ? `\n${env}` : ""
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
|
const {
|
||||||
|
HealthCheck,
|
||||||
|
RestartPolicy,
|
||||||
|
Placement,
|
||||||
|
Labels,
|
||||||
|
Mode,
|
||||||
|
RollbackConfig,
|
||||||
|
UpdateConfig,
|
||||||
|
Networks,
|
||||||
|
} = generateConfigContainer(mongo);
|
||||||
|
|
||||||
const resources = calculateResources({
|
const resources = calculateResources({
|
||||||
memoryLimit,
|
memoryLimit,
|
||||||
memoryReservation,
|
memoryReservation,
|
||||||
@@ -102,6 +114,7 @@ ${command ?? "wait $MONGOD_PID"}`;
|
|||||||
Name: appName,
|
Name: appName,
|
||||||
TaskTemplate: {
|
TaskTemplate: {
|
||||||
ContainerSpec: {
|
ContainerSpec: {
|
||||||
|
HealthCheck,
|
||||||
Image: dockerImage,
|
Image: dockerImage,
|
||||||
Env: envVariables,
|
Env: envVariables,
|
||||||
Mounts: [...volumesMount, ...bindsMount, ...filesMount],
|
Mounts: [...volumesMount, ...bindsMount, ...filesMount],
|
||||||
@@ -116,20 +129,17 @@ ${command ?? "wait $MONGOD_PID"}`;
|
|||||||
Args: ["-c", command],
|
Args: ["-c", command],
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
Labels,
|
||||||
},
|
},
|
||||||
Networks: [{ Target: "dokploy-network" }],
|
Networks,
|
||||||
|
RestartPolicy,
|
||||||
|
Placement,
|
||||||
Resources: {
|
Resources: {
|
||||||
...resources,
|
...resources,
|
||||||
},
|
},
|
||||||
Placement: {
|
|
||||||
Constraints: ["node.role==manager"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Mode: {
|
|
||||||
Replicated: {
|
|
||||||
Replicas: 1,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
Mode,
|
||||||
|
RollbackConfig,
|
||||||
EndpointSpec: {
|
EndpointSpec: {
|
||||||
Mode: "dnsrr",
|
Mode: "dnsrr",
|
||||||
Ports: externalPort
|
Ports: externalPort
|
||||||
@@ -143,6 +153,7 @@ ${command ?? "wait $MONGOD_PID"}`;
|
|||||||
]
|
]
|
||||||
: [],
|
: [],
|
||||||
},
|
},
|
||||||
|
UpdateConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -151,6 +162,10 @@ ${command ?? "wait $MONGOD_PID"}`;
|
|||||||
await service.update({
|
await service.update({
|
||||||
version: Number.parseInt(inspect.Version.Index),
|
version: Number.parseInt(inspect.Version.Index),
|
||||||
...settings,
|
...settings,
|
||||||
|
TaskTemplate: {
|
||||||
|
...settings.TaskTemplate,
|
||||||
|
ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
} catch {
|
} catch {
|
||||||
await docker.createService(settings);
|
await docker.createService(settings);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import type { CreateServiceOptions } from "dockerode";
|
|||||||
import {
|
import {
|
||||||
calculateResources,
|
calculateResources,
|
||||||
generateBindMounts,
|
generateBindMounts,
|
||||||
|
generateConfigContainer,
|
||||||
generateFileMounts,
|
generateFileMounts,
|
||||||
generateVolumeMounts,
|
generateVolumeMounts,
|
||||||
prepareEnvironmentVariables,
|
prepareEnvironmentVariables,
|
||||||
@@ -40,6 +41,17 @@ export const buildMysql = async (mysql: MysqlNested) => {
|
|||||||
: `MYSQL_DATABASE="${databaseName}"\nMYSQL_ROOT_PASSWORD="${databaseRootPassword}"${
|
: `MYSQL_DATABASE="${databaseName}"\nMYSQL_ROOT_PASSWORD="${databaseRootPassword}"${
|
||||||
env ? `\n${env}` : ""
|
env ? `\n${env}` : ""
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
|
const {
|
||||||
|
HealthCheck,
|
||||||
|
RestartPolicy,
|
||||||
|
Placement,
|
||||||
|
Labels,
|
||||||
|
Mode,
|
||||||
|
RollbackConfig,
|
||||||
|
UpdateConfig,
|
||||||
|
Networks,
|
||||||
|
} = generateConfigContainer(mysql);
|
||||||
const resources = calculateResources({
|
const resources = calculateResources({
|
||||||
memoryLimit,
|
memoryLimit,
|
||||||
memoryReservation,
|
memoryReservation,
|
||||||
@@ -60,6 +72,7 @@ export const buildMysql = async (mysql: MysqlNested) => {
|
|||||||
Name: appName,
|
Name: appName,
|
||||||
TaskTemplate: {
|
TaskTemplate: {
|
||||||
ContainerSpec: {
|
ContainerSpec: {
|
||||||
|
HealthCheck,
|
||||||
Image: dockerImage,
|
Image: dockerImage,
|
||||||
Env: envVariables,
|
Env: envVariables,
|
||||||
Mounts: [...volumesMount, ...bindsMount, ...filesMount],
|
Mounts: [...volumesMount, ...bindsMount, ...filesMount],
|
||||||
@@ -69,20 +82,17 @@ export const buildMysql = async (mysql: MysqlNested) => {
|
|||||||
Args: ["-c", command],
|
Args: ["-c", command],
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
|
Labels,
|
||||||
},
|
},
|
||||||
Networks: [{ Target: "dokploy-network" }],
|
Networks,
|
||||||
|
RestartPolicy,
|
||||||
|
Placement,
|
||||||
Resources: {
|
Resources: {
|
||||||
...resources,
|
...resources,
|
||||||
},
|
},
|
||||||
Placement: {
|
|
||||||
Constraints: ["node.role==manager"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Mode: {
|
|
||||||
Replicated: {
|
|
||||||
Replicas: 1,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
Mode,
|
||||||
|
RollbackConfig,
|
||||||
EndpointSpec: {
|
EndpointSpec: {
|
||||||
Mode: "dnsrr",
|
Mode: "dnsrr",
|
||||||
Ports: externalPort
|
Ports: externalPort
|
||||||
@@ -96,6 +106,7 @@ export const buildMysql = async (mysql: MysqlNested) => {
|
|||||||
]
|
]
|
||||||
: [],
|
: [],
|
||||||
},
|
},
|
||||||
|
UpdateConfig,
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
const service = docker.getService(appName);
|
const service = docker.getService(appName);
|
||||||
@@ -103,6 +114,10 @@ export const buildMysql = async (mysql: MysqlNested) => {
|
|||||||
await service.update({
|
await service.update({
|
||||||
version: Number.parseInt(inspect.Version.Index),
|
version: Number.parseInt(inspect.Version.Index),
|
||||||
...settings,
|
...settings,
|
||||||
|
TaskTemplate: {
|
||||||
|
...settings.TaskTemplate,
|
||||||
|
ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
} catch {
|
} catch {
|
||||||
await docker.createService(settings);
|
await docker.createService(settings);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import type { CreateServiceOptions } from "dockerode";
|
|||||||
import {
|
import {
|
||||||
calculateResources,
|
calculateResources,
|
||||||
generateBindMounts,
|
generateBindMounts,
|
||||||
|
generateConfigContainer,
|
||||||
generateFileMounts,
|
generateFileMounts,
|
||||||
generateVolumeMounts,
|
generateVolumeMounts,
|
||||||
prepareEnvironmentVariables,
|
prepareEnvironmentVariables,
|
||||||
@@ -33,6 +34,17 @@ export const buildPostgres = async (postgres: PostgresNested) => {
|
|||||||
const defaultPostgresEnv = `POSTGRES_DB="${databaseName}"\nPOSTGRES_USER="${databaseUser}"\nPOSTGRES_PASSWORD="${databasePassword}"${
|
const defaultPostgresEnv = `POSTGRES_DB="${databaseName}"\nPOSTGRES_USER="${databaseUser}"\nPOSTGRES_PASSWORD="${databasePassword}"${
|
||||||
env ? `\n${env}` : ""
|
env ? `\n${env}` : ""
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
|
const {
|
||||||
|
HealthCheck,
|
||||||
|
RestartPolicy,
|
||||||
|
Placement,
|
||||||
|
Labels,
|
||||||
|
Mode,
|
||||||
|
RollbackConfig,
|
||||||
|
UpdateConfig,
|
||||||
|
Networks,
|
||||||
|
} = generateConfigContainer(postgres);
|
||||||
const resources = calculateResources({
|
const resources = calculateResources({
|
||||||
memoryLimit,
|
memoryLimit,
|
||||||
memoryReservation,
|
memoryReservation,
|
||||||
@@ -53,6 +65,7 @@ export const buildPostgres = async (postgres: PostgresNested) => {
|
|||||||
Name: appName,
|
Name: appName,
|
||||||
TaskTemplate: {
|
TaskTemplate: {
|
||||||
ContainerSpec: {
|
ContainerSpec: {
|
||||||
|
HealthCheck,
|
||||||
Image: dockerImage,
|
Image: dockerImage,
|
||||||
Env: envVariables,
|
Env: envVariables,
|
||||||
Mounts: [...volumesMount, ...bindsMount, ...filesMount],
|
Mounts: [...volumesMount, ...bindsMount, ...filesMount],
|
||||||
@@ -62,20 +75,17 @@ export const buildPostgres = async (postgres: PostgresNested) => {
|
|||||||
Args: ["-c", command],
|
Args: ["-c", command],
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
|
Labels,
|
||||||
},
|
},
|
||||||
Networks: [{ Target: "dokploy-network" }],
|
Networks,
|
||||||
|
RestartPolicy,
|
||||||
|
Placement,
|
||||||
Resources: {
|
Resources: {
|
||||||
...resources,
|
...resources,
|
||||||
},
|
},
|
||||||
Placement: {
|
|
||||||
Constraints: ["node.role==manager"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Mode: {
|
|
||||||
Replicated: {
|
|
||||||
Replicas: 1,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
Mode,
|
||||||
|
RollbackConfig,
|
||||||
EndpointSpec: {
|
EndpointSpec: {
|
||||||
Mode: "dnsrr",
|
Mode: "dnsrr",
|
||||||
Ports: externalPort
|
Ports: externalPort
|
||||||
@@ -89,6 +99,7 @@ export const buildPostgres = async (postgres: PostgresNested) => {
|
|||||||
]
|
]
|
||||||
: [],
|
: [],
|
||||||
},
|
},
|
||||||
|
UpdateConfig,
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
const service = docker.getService(appName);
|
const service = docker.getService(appName);
|
||||||
@@ -96,6 +107,10 @@ export const buildPostgres = async (postgres: PostgresNested) => {
|
|||||||
await service.update({
|
await service.update({
|
||||||
version: Number.parseInt(inspect.Version.Index),
|
version: Number.parseInt(inspect.Version.Index),
|
||||||
...settings,
|
...settings,
|
||||||
|
TaskTemplate: {
|
||||||
|
...settings.TaskTemplate,
|
||||||
|
ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("error", error);
|
console.log("error", error);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import type { CreateServiceOptions } from "dockerode";
|
|||||||
import {
|
import {
|
||||||
calculateResources,
|
calculateResources,
|
||||||
generateBindMounts,
|
generateBindMounts,
|
||||||
|
generateConfigContainer,
|
||||||
generateFileMounts,
|
generateFileMounts,
|
||||||
generateVolumeMounts,
|
generateVolumeMounts,
|
||||||
prepareEnvironmentVariables,
|
prepareEnvironmentVariables,
|
||||||
@@ -31,6 +32,17 @@ export const buildRedis = async (redis: RedisNested) => {
|
|||||||
const defaultRedisEnv = `REDIS_PASSWORD="${databasePassword}"${
|
const defaultRedisEnv = `REDIS_PASSWORD="${databasePassword}"${
|
||||||
env ? `\n${env}` : ""
|
env ? `\n${env}` : ""
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
|
const {
|
||||||
|
HealthCheck,
|
||||||
|
RestartPolicy,
|
||||||
|
Placement,
|
||||||
|
Labels,
|
||||||
|
Mode,
|
||||||
|
RollbackConfig,
|
||||||
|
UpdateConfig,
|
||||||
|
Networks,
|
||||||
|
} = generateConfigContainer(redis);
|
||||||
const resources = calculateResources({
|
const resources = calculateResources({
|
||||||
memoryLimit,
|
memoryLimit,
|
||||||
memoryReservation,
|
memoryReservation,
|
||||||
@@ -51,6 +63,7 @@ export const buildRedis = async (redis: RedisNested) => {
|
|||||||
Name: appName,
|
Name: appName,
|
||||||
TaskTemplate: {
|
TaskTemplate: {
|
||||||
ContainerSpec: {
|
ContainerSpec: {
|
||||||
|
HealthCheck,
|
||||||
Image: dockerImage,
|
Image: dockerImage,
|
||||||
Env: envVariables,
|
Env: envVariables,
|
||||||
Mounts: [...volumesMount, ...bindsMount, ...filesMount],
|
Mounts: [...volumesMount, ...bindsMount, ...filesMount],
|
||||||
@@ -59,20 +72,17 @@ export const buildRedis = async (redis: RedisNested) => {
|
|||||||
"-c",
|
"-c",
|
||||||
command ? command : `redis-server --requirepass ${databasePassword}`,
|
command ? command : `redis-server --requirepass ${databasePassword}`,
|
||||||
],
|
],
|
||||||
|
Labels,
|
||||||
},
|
},
|
||||||
Networks: [{ Target: "dokploy-network" }],
|
Networks,
|
||||||
|
RestartPolicy,
|
||||||
|
Placement,
|
||||||
Resources: {
|
Resources: {
|
||||||
...resources,
|
...resources,
|
||||||
},
|
},
|
||||||
Placement: {
|
|
||||||
Constraints: ["node.role==manager"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Mode: {
|
|
||||||
Replicated: {
|
|
||||||
Replicas: 1,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
Mode,
|
||||||
|
RollbackConfig,
|
||||||
EndpointSpec: {
|
EndpointSpec: {
|
||||||
Mode: "dnsrr",
|
Mode: "dnsrr",
|
||||||
Ports: externalPort
|
Ports: externalPort
|
||||||
@@ -86,6 +96,7 @@ export const buildRedis = async (redis: RedisNested) => {
|
|||||||
]
|
]
|
||||||
: [],
|
: [],
|
||||||
},
|
},
|
||||||
|
UpdateConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -94,6 +105,10 @@ export const buildRedis = async (redis: RedisNested) => {
|
|||||||
await service.update({
|
await service.update({
|
||||||
version: Number.parseInt(inspect.Version.Index),
|
version: Number.parseInt(inspect.Version.Index),
|
||||||
...settings,
|
...settings,
|
||||||
|
TaskTemplate: {
|
||||||
|
...settings.TaskTemplate,
|
||||||
|
ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
} catch {
|
} catch {
|
||||||
await docker.createService(settings);
|
await docker.createService(settings);
|
||||||
|
|||||||
@@ -348,7 +348,9 @@ export const calculateResources = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const generateConfigContainer = (application: ApplicationNested) => {
|
export const generateConfigContainer = (
|
||||||
|
application: Partial<ApplicationNested>,
|
||||||
|
) => {
|
||||||
const {
|
const {
|
||||||
healthCheckSwarm,
|
healthCheckSwarm,
|
||||||
restartPolicySwarm,
|
restartPolicySwarm,
|
||||||
@@ -362,7 +364,7 @@ export const generateConfigContainer = (application: ApplicationNested) => {
|
|||||||
networkSwarm,
|
networkSwarm,
|
||||||
} = application;
|
} = application;
|
||||||
|
|
||||||
const haveMounts = mounts.length > 0;
|
const haveMounts = mounts && mounts.length > 0;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...(healthCheckSwarm && {
|
...(healthCheckSwarm && {
|
||||||
|
|||||||
Reference in New Issue
Block a user