feat: add k8s secret deployer

This commit is contained in:
Fu Diwei
2024-10-18 17:49:37 +08:00
parent 411b7bbfe2
commit 8e906cbf23
24 changed files with 786 additions and 1120 deletions

View File

@@ -140,8 +140,10 @@ const DeployItem = ({ item, onDelete, onSave }: DeployItemProps) => {
config: { accesses },
} = useConfig();
const { t } = useTranslation();
const access = accesses.find((access) => access.id === item.access);
const getImg = () => {
const getTypeIcon = () => {
if (!access) {
return "";
}
@@ -173,7 +175,7 @@ const DeployItem = ({ item, onDelete, onSave }: DeployItemProps) => {
<div className="flex justify-between text-sm p-3 items-center text-stone-700 dark:text-stone-200">
<div className="flex space-x-2 items-center">
<div>
<img src={getImg()} className="w-9"></img>
<img src={getTypeIcon()} className="w-9"></img>
</div>
<div className="text-stone-600 flex-col flex space-y-0 dark:text-stone-200">
<div>{getTypeName()}</div>
@@ -239,7 +241,8 @@ const DeployEditDialog = ({ trigger, deployConfig, onSave }: DeployEditDialogPro
let t;
if (temp && temp.length > 1) {
t = temp[1];
// TODO: code smell, maybe a dictionary is better
t = temp[0] === "k8s" ? temp[0] : temp[1];
} else {
t = locDeployConfig.type;
}
@@ -419,7 +422,7 @@ const DeployEditDialog = ({ trigger, deployConfig, onSave }: DeployEditDialogPro
);
};
type TargetType = "ssh" | "cdn" | "webhook" | "local" | "oss" | "dcdn";
type TargetType = "oss" | "cdn" | "dcdn" | "local" | "ssh" | "webhook" | "k8s";
type DeployEditProps = {
type: TargetType;
@@ -428,18 +431,20 @@ type DeployEditProps = {
const DeployEdit = ({ type }: DeployEditProps) => {
const getDeploy = () => {
switch (type) {
case "ssh":
return <DeployToSSH />;
case "local":
return <DeployToSSH />;
case "cdn":
return <DeployToCDN />;
case "dcdn":
return <DeployToCDN />;
case "oss":
return <DeployToOSS />;
case "ssh":
return <DeployToSSH />;
case "local":
return <DeployToSSH />;
case "webhook":
return <DeployToWebhook />;
case "k8s":
return <DeployToKubernetes />;
default:
return <DeployToCDN />;
}
@@ -474,9 +479,9 @@ const DeployToSSH = () => {
<>
<div className="flex flex-col space-y-2">
<div>
<Label>{t("access.authorization.form.ssh_cert_path.label")}</Label>
<Label>{t("domain.deployment.form.ssh_cert_path.label")}</Label>
<Input
placeholder={t("access.authorization.form.ssh_cert_path.label")}
placeholder={t("domain.deployment.form.ssh_cert_path.label")}
className="w-full mt-1"
value={data?.config?.certPath}
onChange={(e) => {
@@ -491,9 +496,9 @@ const DeployToSSH = () => {
/>
</div>
<div>
<Label>{t("access.authorization.form.ssh_key_path.label")}</Label>
<Label>{t("domain.deployment.form.ssh_key_path.label")}</Label>
<Input
placeholder={t("access.authorization.form.ssh_key_path.placeholder")}
placeholder={t("domain.deployment.form.ssh_key_path.placeholder")}
className="w-full mt-1"
value={data?.config?.keyPath}
onChange={(e) => {
@@ -509,11 +514,11 @@ const DeployToSSH = () => {
</div>
<div>
<Label>{t("access.authorization.form.ssh_pre_command.label")}</Label>
<Label>{t("domain.deployment.form.ssh_pre_command.label")}</Label>
<Textarea
className="mt-1"
value={data?.config?.preCommand}
placeholder={t("access.authorization.form.ssh_pre_command.placeholder")}
placeholder={t("domain.deployment.form.ssh_pre_command.placeholder")}
onChange={(e) => {
const newData = produce(data, (draft) => {
if (!draft.config) {
@@ -527,11 +532,11 @@ const DeployToSSH = () => {
</div>
<div>
<Label>{t("access.authorization.form.ssh_command.label")}</Label>
<Label>{t("domain.deployment.form.ssh_command.label")}</Label>
<Textarea
className="mt-1"
value={data?.config?.command}
placeholder={t("access.authorization.form.ssh_command.placeholder")}
placeholder={t("domain.deployment.form.ssh_command.placeholder")}
onChange={(e) => {
const newData = produce(data, (draft) => {
if (!draft.config) {
@@ -548,70 +553,30 @@ const DeployToSSH = () => {
);
};
const DeployToCDN = () => {
const { deploy: data, setDeploy, error, setError } = useDeployEditContext();
const DeployToWebhook = () => {
const { deploy: data, setDeploy } = useDeployEditContext();
const { t } = useTranslation();
const { setError } = useDeployEditContext();
useEffect(() => {
setError({});
}, []);
useEffect(() => {
const resp = domainSchema.safeParse(data.config?.domain);
if (!resp.success) {
setError({
...error,
domain: JSON.parse(resp.error.message)[0].message,
});
} else {
setError({
...error,
domain: "",
});
}
}, [data]);
const domainSchema = z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
message: t("common.errmsg.domain_invalid"),
});
return (
<div className="flex flex-col space-y-2">
<div>
<Label>{t("domain.deployment.form.cdn_domain.label")}</Label>
<Input
placeholder={t("domain.deployment.form.cdn_domain.placeholder")}
className="w-full mt-1"
value={data?.config?.domain}
onChange={(e) => {
const temp = e.target.value;
const resp = domainSchema.safeParse(temp);
if (!resp.success) {
setError({
...error,
domain: JSON.parse(resp.error.message)[0].message,
});
} else {
setError({
...error,
domain: "",
});
<>
<KVList
variables={data?.config?.variables}
onValueChange={(variables: KVType[]) => {
const newData = produce(data, (draft) => {
if (!draft.config) {
draft.config = {};
}
const newData = produce(data, (draft) => {
if (!draft.config) {
draft.config = {};
}
draft.config.domain = temp;
});
setDeploy(newData);
}}
/>
<div className="text-red-600 text-sm mt-1">{error?.domain}</div>
</div>
</div>
draft.config.variables = variables;
});
setDeploy(newData);
}}
/>
</>
);
};
@@ -681,6 +646,7 @@ const DeployToOSS = () => {
<Label>{t("domain.deployment.form.oss_endpoint.label")}</Label>
<Input
placeholder={t("domain.deployment.form.oss_endpoint.placeholder")}
className="w-full mt-1"
value={data?.config?.endpoint}
onChange={(e) => {
@@ -697,7 +663,7 @@ const DeployToOSS = () => {
/>
<div className="text-red-600 text-sm mt-1">{error?.endpoint}</div>
<Label>{t("domain.deployment.form.oss_bucket")}</Label>
<Label>{t("domain.deployment.form.oss_bucket.label")}</Label>
<Input
placeholder={t("domain.deployment.form.oss_bucket.placeholder")}
className="w-full mt-1"
@@ -729,9 +695,9 @@ const DeployToOSS = () => {
/>
<div className="text-red-600 text-sm mt-1">{error?.bucket}</div>
<Label>{t("domain.deployment.form.cdn_domain.label")}</Label>
<Label>{t("domain.deployment.form.domain.label")}</Label>
<Input
placeholder={t("domain.deployment.form.cdn_domain.label")}
placeholder={t("domain.deployment.form.domain.label")}
className="w-full mt-1"
value={data?.config?.domain}
onChange={(e) => {
@@ -765,29 +731,161 @@ const DeployToOSS = () => {
);
};
const DeployToWebhook = () => {
const { deploy: data, setDeploy } = useDeployEditContext();
const DeployToCDN = () => {
const { deploy: data, setDeploy, error, setError } = useDeployEditContext();
const { t } = useTranslation();
useEffect(() => {
setError({});
}, []);
useEffect(() => {
const resp = domainSchema.safeParse(data.config?.domain);
if (!resp.success) {
setError({
...error,
domain: JSON.parse(resp.error.message)[0].message,
});
} else {
setError({
...error,
domain: "",
});
}
}, [data]);
const domainSchema = z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
message: t("common.errmsg.domain_invalid"),
});
return (
<div className="flex flex-col space-y-2">
<div>
<Label>{t("domain.deployment.form.domain.label")}</Label>
<Input
placeholder={t("domain.deployment.form.domain.placeholder")}
className="w-full mt-1"
value={data?.config?.domain}
onChange={(e) => {
const temp = e.target.value;
const resp = domainSchema.safeParse(temp);
if (!resp.success) {
setError({
...error,
domain: JSON.parse(resp.error.message)[0].message,
});
} else {
setError({
...error,
domain: "",
});
}
const newData = produce(data, (draft) => {
if (!draft.config) {
draft.config = {};
}
draft.config.domain = temp;
});
setDeploy(newData);
}}
/>
<div className="text-red-600 text-sm mt-1">{error?.domain}</div>
</div>
</div>
);
};
const DeployToKubernetes = () => {
const { t } = useTranslation();
const { setError } = useDeployEditContext();
useEffect(() => {
setError({});
}, []);
const { deploy: data, setDeploy } = useDeployEditContext();
useEffect(() => {
if (!data.id) {
setDeploy({
...data,
config: {
namespace: "default",
secretName: "",
secretDataKeyForCrt: "tls.crt",
secretDataKeyForKey: "tls.key",
},
});
}
}, []);
return (
<>
<KVList
variables={data?.config?.variables}
onValueChange={(variables: KVType[]) => {
const newData = produce(data, (draft) => {
if (!draft.config) {
draft.config = {};
}
draft.config.variables = variables;
});
setDeploy(newData);
}}
/>
<div className="flex flex-col space-y-2">
<div>
<Label>{t("domain.deployment.form.k8s_namespace.label")}</Label>
<Input
placeholder={t("domain.deployment.form.k8s_namespace.label")}
className="w-full mt-1"
value={data?.config?.namespace}
onChange={(e) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.namespace = e.target.value;
});
setDeploy(newData);
}}
/>
</div>
<div>
<Label>{t("domain.deployment.form.k8s_secret_name.label")}</Label>
<Input
placeholder={t("domain.deployment.form.k8s_secret_name.label")}
className="w-full mt-1"
value={data?.config?.secretName}
onChange={(e) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.secretName = e.target.value;
});
setDeploy(newData);
}}
/>
</div>
<div>
<Label>{t("domain.deployment.form.k8s_secret_data_key_for_crt.label")}</Label>
<Input
placeholder={t("domain.deployment.form.k8s_secret_data_key_for_crt.label")}
className="w-full mt-1"
value={data?.config?.secretDataKeyForCrt}
onChange={(e) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.secretDataKeyForCrt = e.target.value;
});
setDeploy(newData);
}}
/>
</div>
<div>
<Label>{t("domain.deployment.form.k8s_secret_data_key_for_key.label")}</Label>
<Input
placeholder={t("domain.deployment.form.k8s_secret_data_key_for_key.label")}
className="w-full mt-1"
value={data?.config?.secretDataKeyForKey}
onChange={(e) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.secretDataKeyForKey = e.target.value;
});
setDeploy(newData);
}}
/>
</div>
</div>
</>
);
};

View File

@@ -75,6 +75,7 @@ export const targetTypeMap: Map<string, [string, string]> = new Map([
["local", ["common.provider.local", "/imgs/providers/local.svg"]],
["ssh", ["common.provider.ssh", "/imgs/providers/ssh.svg"]],
["webhook", ["common.provider.webhook", "/imgs/providers/webhook.svg"]],
["k8s-secret", ["common.provider.kubernetes.secret", "/imgs/providers/k8s.svg"]],
]);
export const targetTypeKeys = Array.from(targetTypeMap.keys());

View File

@@ -59,14 +59,6 @@
"access.authorization.form.ssh_key_file.placeholder": "Please select file",
"access.authorization.form.ssh_key_passphrase.label": "Key Passphrase (Log-in using private key)",
"access.authorization.form.ssh_key_passphrase.placeholder": "Please enter Key Passphrase",
"access.authorization.form.ssh_key_path.label": "Private Key Save Path",
"access.authorization.form.ssh_key_path.placeholder": "Please enter private key save path",
"access.authorization.form.ssh_cert_path.label": "Certificate Save Path",
"access.authorization.form.ssh_cert_path.placeholder": "Please enter certificate save path",
"access.authorization.form.ssh_pre_command.label": "Pre-deployment Command",
"access.authorization.form.ssh_pre_command.placeholder": "Command to be executed before deploying the certificate",
"access.authorization.form.ssh_command.label": "Command",
"access.authorization.form.ssh_command.placeholder": "Please enter command",
"access.authorization.form.webhook_url.label": "Webhook URL",
"access.authorization.form.webhook_url.placeholder": "Please enter Webhook URL",
"access.authorization.form.k8s_kubeconfig.label": "KubeConfig",

View File

@@ -69,6 +69,7 @@
"common.provider.ssh": "SSH Deployment",
"common.provider.webhook": "Webhook",
"common.provider.kubernetes": "Kubernetes",
"common.provider.kubernetes.secret": "Kubernetes - Secret",
"common.provider.dingtalk": "DingTalk",
"common.provider.telegram": "Telegram",
"common.provider.lark": "Lark"

View File

@@ -7,5 +7,5 @@
"dashboard.statistics.disabled": "Not Enabled",
"dashboard.statistics.unit": "",
"dashboard.history": "Deployment History"
"dashboard.history": "Recently Deployment History"
}

View File

@@ -39,7 +39,7 @@
"domain.application.form.advanced_settings.label": "Advanced Settings",
"domain.application.form.key_algorithm.label": "Certificate Key Algorithm",
"domain.application.form.key_algorithm.placeholder": "Please select certificate key algorithm",
"domain.application.form.timeout.label": "DNS Propagation Timeout (seconds)",
"domain.application.form.timeout.label": "DNS Propagation Timeout (Seconds)",
"domain.application.form.timeoue.placeholder": "Please enter maximum waiting time for DNS propagation",
"domain.application.unsaved.message": "Please save applyment configuration first",
@@ -51,11 +51,28 @@
"domain.deployment.form.access.label": "Access Configuration",
"domain.deployment.form.access.placeholder": "Please select provider authorization configuration",
"domain.deployment.form.access.list": "Provider Authorization Configurations",
"domain.deployment.form.cdn_domain.label": "Deploy to domain",
"domain.deployment.form.cdn_domain.placeholder": "Please enter CDN domain",
"domain.deployment.form.domain.label": "Deploy to domain (Single domain only, not wildcard domain)",
"domain.deployment.form.domain.placeholder": "Please enter domain to be deployed",
"domain.deployment.form.ssh_key_path.label": "Private Key Save Path",
"domain.deployment.form.ssh_key_path.placeholder": "Please enter private key save path",
"domain.deployment.form.ssh_cert_path.label": "Certificate Save Path",
"domain.deployment.form.ssh_cert_path.placeholder": "Please enter certificate save path",
"domain.deployment.form.ssh_pre_command.label": "Pre-deployment Command",
"domain.deployment.form.ssh_pre_command.placeholder": "Command to be executed before deploying the certificate",
"domain.deployment.form.ssh_command.label": "Command",
"domain.deployment.form.ssh_command.placeholder": "Please enter command",
"domain.deployment.form.oss_endpoint.label": "Endpoint",
"domain.deployment.form.oss_bucket": "Bucket",
"domain.deployment.form.oss_bucket.placeholder": "Please enter Bucket",
"domain.deployment.form.oss_endpoint.placeholder": "Please enter endpoint",
"domain.deployment.form.oss_bucket.label": "Bucket",
"domain.deployment.form.oss_bucket.placeholder": "Please enter bucket",
"domain.deployment.form.k8s_namespace.label": "Namespace",
"domain.deployment.form.k8s_namespace.placeholder": "Please enter namespace",
"domain.deployment.form.k8s_secret_name.label": "Secret Name",
"domain.deployment.form.k8s_secret_name.placeholder": "Please enter secret name",
"domain.deployment.form.k8s_secret_data_key_for_key.label": "Secret Data Key for PublicKey",
"domain.deployment.form.k8s_secret_data_key_for_key.placeholder": "Please enter secret data key for public key",
"domain.deployment.form.k8s_secret_data_key_for_crt.label": "Secret Data Key for Certificate",
"domain.deployment.form.k8s_secret_data_key_for_crt.placeholder": "Please enter secret data key for certificate",
"domain.deployment.form.variables.label": "Variable",
"domain.deployment.form.variables.key": "Name",
"domain.deployment.form.variables.value": "Value",

View File

@@ -1,5 +1,5 @@
{
"history.page.title": "Deployment",
"history.page.title": "Deployment History",
"history.nodata": "You have not created any deployments yet, please add a domain to start deployment!",

View File

@@ -59,14 +59,6 @@
"access.authorization.form.ssh_key_file.placeholder": "请选择文件",
"access.authorization.form.ssh_key_passphrase.label": "Key 口令(使用私钥登录)",
"access.authorization.form.ssh_key_passphrase.placeholder": "请输入 Key 口令",
"access.authorization.form.ssh_key_path.label": "私钥保存路径",
"access.authorization.form.ssh_key_path.placeholder": "请输入私钥保存路径",
"access.authorization.form.ssh_cert_path.label": "证书保存路径",
"access.authorization.form.ssh_cert_path.placeholder": "请输入证书保存路径",
"access.authorization.form.ssh_pre_command.label": "前置 Command",
"access.authorization.form.ssh_pre_command.placeholder": "在部署证书前执行的前置命令",
"access.authorization.form.ssh_command.label": "Command",
"access.authorization.form.ssh_command.placeholder": "请输入要执行的命令",
"access.authorization.form.webhook_url.label": "Webhook URL",
"access.authorization.form.webhook_url.placeholder": "请输入 Webhook URL",
"access.authorization.form.k8s_kubeconfig.label": "KubeConfig",

View File

@@ -69,6 +69,7 @@
"common.provider.ssh": "SSH 部署",
"common.provider.webhook": "Webhook",
"common.provider.kubernetes": "Kubernetes",
"common.provider.kubernetes.secret": "Kubernetes - Secret",
"common.provider.dingtalk": "钉钉",
"common.provider.telegram": "Telegram",
"common.provider.lark": "飞书"

View File

@@ -7,5 +7,5 @@
"dashboard.statistics.disabled": "未启用",
"dashboard.statistics.unit": "个",
"dashboard.history": "部署历史"
"dashboard.history": "最近部署"
}

View File

@@ -51,11 +51,28 @@
"domain.deployment.form.access.label": "授权配置",
"domain.deployment.form.access.placeholder": "请选择授权配置",
"domain.deployment.form.access.list": "已有的服务商授权配置",
"domain.deployment.form.cdn_domain.label": "部署到域名",
"domain.deployment.form.cdn_domain.placeholder": "请输入 CDN 域名",
"domain.deployment.form.domain.label": "部署到域名(仅支持单个域名;不支持泛域名)",
"domain.deployment.form.domain.placeholder": "请输入部署到的域名",
"domain.deployment.form.ssh_key_path.label": "私钥保存路径",
"domain.deployment.form.ssh_key_path.placeholder": "请输入私钥保存路径",
"domain.deployment.form.ssh_cert_path.label": "证书保存路径",
"domain.deployment.form.ssh_cert_path.placeholder": "请输入证书保存路径",
"domain.deployment.form.ssh_pre_command.label": "前置命令",
"domain.deployment.form.ssh_pre_command.placeholder": "在部署证书前执行的命令",
"domain.deployment.form.ssh_command.label": "命令",
"domain.deployment.form.ssh_command.placeholder": "请输入要执行的命令",
"domain.deployment.form.oss_endpoint.label": "Endpoint",
"domain.deployment.form.oss_bucket": "存储桶",
"domain.deployment.form.oss_endpoint.placeholder": "请输入 Endpoint",
"domain.deployment.form.oss_bucket.label": "存储桶",
"domain.deployment.form.oss_bucket.placeholder": "请输入存储桶名",
"domain.deployment.form.k8s_namespace.label": "命名空间",
"domain.deployment.form.k8s_namespace.placeholder": "请输入 K8S 命名空间",
"domain.deployment.form.k8s_secret_name.label": "Secret 名称",
"domain.deployment.form.k8s_secret_name.placeholder": "请输入 K8S Secret 名称",
"domain.deployment.form.k8s_secret_data_key_for_key.label": "Secret 数据键(用于存放公钥的 Key",
"domain.deployment.form.k8s_secret_data_key_for_key.placeholder": "请输入 K8S Secret 中用于存放公钥的数据键",
"domain.deployment.form.k8s_secret_data_key_for_crt.label": "Secret 数据键(用于存放证书的 Key",
"domain.deployment.form.k8s_secret_data_key_for_crt.placeholder": "请输入 K8S Secret 中用于存放证书的数据键",
"domain.deployment.form.variables.label": "变量",
"domain.deployment.form.variables.key": "变量名",
"domain.deployment.form.variables.value": "值",

View File

@@ -1,5 +1,5 @@
{
"history.page.title": "部署",
"history.page.title": "部署历史",
"history.nodata": "你暂未创建任何部署,请先添加域名进行部署吧!",