diff --git a/frontend/providers/applaunchpad/src/pages/_document.tsx b/frontend/providers/applaunchpad/src/pages/_document.tsx
index 9e8e2a349..48fdd5f05 100644
--- a/frontend/providers/applaunchpad/src/pages/_document.tsx
+++ b/frontend/providers/applaunchpad/src/pages/_document.tsx
@@ -11,7 +11,6 @@ export default function Document() {
-
diff --git a/frontend/providers/applaunchpad/src/pages/api/checkReady.ts b/frontend/providers/applaunchpad/src/pages/api/checkReady.ts
index cd7408ee1..6dba5ade0 100644
--- a/frontend/providers/applaunchpad/src/pages/api/checkReady.ts
+++ b/frontend/providers/applaunchpad/src/pages/api/checkReady.ts
@@ -27,7 +27,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
);
if (!ingress.body.items || ingress.body.items.length === 0) {
- throw new Error('No ingress found');
+ throw new Error('Check ready error: No ingress found');
}
const checkResults = await Promise.all(
@@ -75,7 +75,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
data: checkResults
});
} catch (error: any) {
- console.error(error);
return jsonRes(res, {
code: 500,
error: error?.message
diff --git a/frontend/providers/applaunchpad/src/pages/api/getAppByAppName.ts b/frontend/providers/applaunchpad/src/pages/api/getAppByAppName.ts
index 28e476248..e9fb265fc 100644
--- a/frontend/providers/applaunchpad/src/pages/api/getAppByAppName.ts
+++ b/frontend/providers/applaunchpad/src/pages/api/getAppByAppName.ts
@@ -40,7 +40,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
})
.filter((item) => item)
.flat();
- console.log('responseData', responseData);
const data = adaptAppDetail(responseData as DeployKindsType[], getServerEnv(global.AppConfig));
diff --git a/frontend/providers/applaunchpad/src/pages/app/edit/components/ConfigmapModal.tsx b/frontend/providers/applaunchpad/src/pages/app/edit/components/ConfigmapModal.tsx
index 62a685562..1b507cda6 100644
--- a/frontend/providers/applaunchpad/src/pages/app/edit/components/ConfigmapModal.tsx
+++ b/frontend/providers/applaunchpad/src/pages/app/edit/components/ConfigmapModal.tsx
@@ -21,12 +21,16 @@ export type ConfigMapType = {
id?: string;
mountPath: string;
value: string;
+ key: string;
+ volumeName: string;
};
const ConfigmapModal = ({
defaultValue = {
mountPath: '',
- value: ''
+ value: '',
+ key: '',
+ volumeName: ''
},
listNames,
successCb,
@@ -68,7 +72,6 @@ const ConfigmapModal = ({
- {' '}
{t('filename')}
import('./CustomAccessModal'));
const ConfigmapModal = dynamic(() => import('./ConfigmapModal'));
@@ -1147,7 +1148,9 @@ const Form = ({
w={'100%'}
height={'32px'}
variant={'outline'}
- onClick={() => setConfigEdit({ mountPath: '', value: '' })}
+ onClick={() =>
+ setConfigEdit({ mountPath: '', value: '', key: '', volumeName: '' })
+ }
leftIcon={}
>
{t('form.add_configmap')}
@@ -1341,14 +1344,22 @@ const Form = ({
.map((item) => item.mountPath.toLocaleLowerCase())}
successCb={(e) => {
if (!e.id) {
- appendConfigMaps(e);
+ appendConfigMaps({
+ ...e,
+ key: mountPathToConfigMapKey(e.mountPath),
+ volumeName: getValues('appName') + '-cm'
+ });
} else {
setValue(
'configMapList',
- configMaps.map((item) => ({
- mountPath: item.id === e.id ? e.mountPath : item.mountPath,
- value: item.id === e.id ? e.value : item.value
- }))
+ configMaps.map((item) => {
+ return {
+ mountPath: item.id === e.id ? e.mountPath : item.mountPath,
+ value: item.id === e.id ? e.value : item.value,
+ key: item.id === e.id ? e.key : item.key,
+ volumeName: item.id === e.id ? e.volumeName : item.volumeName
+ };
+ })
);
}
setConfigEdit(undefined);
diff --git a/frontend/providers/applaunchpad/src/pages/app/edit/components/StoreModal.tsx b/frontend/providers/applaunchpad/src/pages/app/edit/components/StoreModal.tsx
index 98ac957f8..ffc075de2 100644
--- a/frontend/providers/applaunchpad/src/pages/app/edit/components/StoreModal.tsx
+++ b/frontend/providers/applaunchpad/src/pages/app/edit/components/StoreModal.tsx
@@ -20,7 +20,7 @@ import {
import { useForm } from 'react-hook-form';
import MyFormControl from '@/components/FormControl';
import { useTranslation } from 'next-i18next';
-import { pathToNameFormat } from '@/utils/tools';
+import { mountPathToConfigMapKey } from '@/utils/tools';
import { MyTooltip } from '@sealos/ui';
import { PVC_STORAGE_MAX } from '@/store/static';
@@ -152,7 +152,7 @@ const StoreModal = ({
return true;
},
onChange(e) {
- setValue('name', pathToNameFormat(e.target.value));
+ setValue('name', mountPathToConfigMapKey(e.target.value));
}
})}
/>
diff --git a/frontend/providers/applaunchpad/src/types/app.d.ts b/frontend/providers/applaunchpad/src/types/app.d.ts
index dc848c519..466b24af4 100644
--- a/frontend/providers/applaunchpad/src/types/app.d.ts
+++ b/frontend/providers/applaunchpad/src/types/app.d.ts
@@ -108,6 +108,8 @@ export interface AppEditType {
configMapList: {
mountPath: string;
value: string;
+ key: string;
+ volumeName: string;
}[];
storeList: {
name: string;
diff --git a/frontend/providers/applaunchpad/src/utils/adapt.ts b/frontend/providers/applaunchpad/src/utils/adapt.ts
index 3a076cf5c..42a339dce 100644
--- a/frontend/providers/applaunchpad/src/utils/adapt.ts
+++ b/frontend/providers/applaunchpad/src/utils/adapt.ts
@@ -8,7 +8,8 @@ import type {
V1Pod,
SinglePodMetrics,
CoreV1EventList,
- V2HorizontalPodAutoscaler
+ V2HorizontalPodAutoscaler,
+ V1VolumeMount
} from '@kubernetes/client-node';
import dayjs from 'dayjs';
import type {
@@ -235,7 +236,6 @@ export const adaptAppDetail = (configs: DeployKindsType[], envs: EnvResponse): A
const deployKindsMap: {
[YamlKindEnum.StatefulSet]?: V1StatefulSet;
[YamlKindEnum.Deployment]?: V1Deployment;
- // [YamlKindEnum.Service]?: V1Service;
[YamlKindEnum.ConfigMap]?: V1ConfigMap;
[YamlKindEnum.HorizontalPodAutoscaler]?: V2HorizontalPodAutoscaler;
[YamlKindEnum.Secret]?: V1Secret;
@@ -250,10 +250,86 @@ export const adaptAppDetail = (configs: DeployKindsType[], envs: EnvResponse): A
const appDeploy = deployKindsMap.Deployment || deployKindsMap.StatefulSet;
- if (!appDeploy) {
+ if (!appDeploy || !appDeploy?.metadata?.name) {
throw new Error('获取APP异常');
}
+ const appName = appDeploy.metadata?.name;
+
+ const getConfigMapVolumeNames = (): string[] => {
+ if (!deployKindsMap.ConfigMap) return [];
+
+ const configMapName = deployKindsMap.ConfigMap.metadata?.name;
+ const configMapVolumes =
+ appDeploy?.spec?.template?.spec?.volumes?.filter(
+ (volume) => volume.configMap?.name === configMapName
+ ) || [];
+
+ return configMapVolumes.map((volume) => volume.name).filter(Boolean) as string[];
+ };
+
+ const configMapVolumeNames = getConfigMapVolumeNames();
+
+ const getConfigMapList = (): Array<{
+ mountPath: string;
+ value: string;
+ key: string;
+ volumeName: string;
+ }> => {
+ const configMap = deployKindsMap.ConfigMap;
+ if (!configMap?.data || !appDeploy) {
+ return [];
+ }
+ const configMapName = configMap.metadata?.name;
+ const volumes = appDeploy.spec?.template?.spec?.volumes || [];
+ const configMapVolumes = volumes.filter((volume) => volume.configMap?.name === configMapName);
+ if (configMapVolumes.length === 0) {
+ return [];
+ }
+ const volumeMounts = appDeploy.spec?.template?.spec?.containers?.[0]?.volumeMounts || [];
+ const results: Array<{ mountPath: string; value: string; key: string; volumeName: string }> =
+ [];
+
+ configMapVolumes.forEach((volume) => {
+ const relatedMounts = volumeMounts.filter((mount) => mount.name === volume.name);
+
+ if (volume.configMap?.items && volume.configMap.items.length > 0) {
+ volume.configMap.items.forEach((item) => {
+ if (!item.key) return;
+ const matchedMount = relatedMounts.find((mount) => mount.subPath === item.path);
+
+ if (matchedMount) {
+ const value = configMap.data?.[item.key] || '';
+ results.push({
+ mountPath: matchedMount.mountPath,
+ value: value,
+ key: item.key,
+ volumeName: volume.name
+ });
+ }
+ });
+ } else {
+ relatedMounts.forEach((mount) => {
+ if (mount.subPath) {
+ const configMapKey = mount.subPath;
+ const value = configMap?.data?.[configMapKey] || '';
+
+ if (value) {
+ results.push({
+ mountPath: mount.mountPath,
+ value: value,
+ key: configMapKey,
+ volumeName: volume.name
+ });
+ }
+ }
+ });
+ }
+ });
+
+ return results.filter((item) => item.value);
+ };
+
const useGpu = !!Number(
appDeploy.spec?.template?.spec?.containers?.[0]?.resources?.limits?.[gpuResourceKey]
);
@@ -261,14 +337,23 @@ export const adaptAppDetail = (configs: DeployKindsType[], envs: EnvResponse): A
const getFilteredVolumeMounts = () => {
const volumeMounts = appDeploy?.spec?.template?.spec?.containers?.[0]?.volumeMounts || [];
- const configMapKeys = Object.keys(deployKindsMap.ConfigMap?.data || {});
const storeNames =
deployKindsMap.StatefulSet?.spec?.volumeClaimTemplates?.map(
(template) => template.metadata?.name
) || [];
return volumeMounts.filter(
- (mount) => !configMapKeys.includes(mount.name) && !storeNames.includes(mount.name)
+ (mount) => !configMapVolumeNames.includes(mount.name) && !storeNames.includes(mount.name)
+ );
+ };
+
+ const getFilteredVolumes = () => {
+ return (
+ appDeploy?.spec?.template?.spec?.volumes?.filter((volume) => {
+ if (!deployKindsMap.ConfigMap) return true;
+ const configMapName = deployKindsMap.ConfigMap.metadata?.name;
+ return !(volume.configMap?.name === configMapName);
+ }) || []
);
};
@@ -276,7 +361,7 @@ export const adaptAppDetail = (configs: DeployKindsType[], envs: EnvResponse): A
labels: appDeploy?.metadata?.labels || {},
crYamlList: configs,
id: appDeploy.metadata?.uid || ``,
- appName: appDeploy.metadata?.name || 'app Name',
+ appName: appName,
createTime: dayjs(appDeploy.metadata?.creationTimestamp).format('YYYY-MM-DD HH:mm'),
status: appStatusMap.waiting,
isPause: !!appDeploy?.metadata?.annotations?.[pauseKey],
@@ -356,7 +441,7 @@ export const adaptAppDetail = (configs: DeployKindsType[], envs: EnvResponse): A
customDomain: isCustomDomain ? domain : '',
domain: isCustomDomain
? envs.SEALOS_DOMAIN
- : item?.nodePort // 如果有 nodePort,则使用域名
+ : item?.nodePort
? domain
: domain.split('.').slice(1).join('.') || envs.SEALOS_DOMAIN
};
@@ -383,15 +468,7 @@ export const adaptAppDetail = (configs: DeployKindsType[], envs: EnvResponse): A
maxReplicas: deployKindsMap.HorizontalPodAutoscaler.spec.maxReplicas || 10
}
: defaultEditVal.hpa,
- configMapList: deployKindsMap.ConfigMap?.data
- ? Object.entries(deployKindsMap.ConfigMap.data).map(([key, value], i) => ({
- mountPath:
- appDeploy?.spec?.template.spec?.containers[0].volumeMounts?.find(
- (item) => item.name === key
- )?.mountPath || key,
- value
- }))
- : [],
+ configMapList: getConfigMapList(),
secret: atobSecretYaml(deployKindsMap?.Secret?.data?.['.dockerconfigjson']),
storeList: deployKindsMap.StatefulSet?.spec?.volumeClaimTemplates
? deployKindsMap.StatefulSet?.spec?.volumeClaimTemplates.map((item) => ({
@@ -401,8 +478,7 @@ export const adaptAppDetail = (configs: DeployKindsType[], envs: EnvResponse): A
}))
: [],
volumeMounts: getFilteredVolumeMounts(),
- // keep original non-configMap type volumes
- volumes: appDeploy?.spec?.template?.spec?.volumes || [],
+ volumes: getFilteredVolumes(),
kind: appDeploy?.kind?.toLowerCase() as 'deployment' | 'statefulset',
source: getAppSource(appDeploy)
};
diff --git a/frontend/providers/applaunchpad/src/utils/deployYaml2Json.ts b/frontend/providers/applaunchpad/src/utils/deployYaml2Json.ts
index 7c8fe5cc1..94f790b42 100644
--- a/frontend/providers/applaunchpad/src/utils/deployYaml2Json.ts
+++ b/frontend/providers/applaunchpad/src/utils/deployYaml2Json.ts
@@ -9,7 +9,7 @@ import {
} from '@/constants/app';
import { SEALOS_USER_DOMAINS } from '@/store/static';
import type { AppEditType } from '@/types/app';
-import { pathFormat, pathToNameFormat, str2Num, strToBase64 } from '@/utils/tools';
+import { pathFormat, mountPathToConfigMapKey, str2Num, strToBase64 } from '@/utils/tools';
import dayjs from 'dayjs';
import yaml from 'js-yaml';
@@ -97,44 +97,31 @@ export const json2DeployCr = (data: AppEditType, type: 'deployment' | 'statefuls
})),
imagePullPolicy: 'Always'
};
+
const configMapVolumeMounts = data.configMapList.map((item) => ({
- name: pathToNameFormat(item.mountPath),
+ name: item.volumeName,
mountPath: item.mountPath,
- subPath: pathFormat(item.mountPath)
- }));
- const configMapVolumes = data.configMapList.map((item) => ({
- name: pathToNameFormat(item.mountPath), // name === [development.***.volumeMounts[*].name]
- configMap: {
- name: data.appName, // name === configMap.yaml.meta.name
- items: [
- {
- key: pathToNameFormat(item.mountPath),
- path: pathFormat(item.mountPath) // path ===[development.***.volumeMounts[*].subPath]
- }
- ]
- }
+ subPath: item.key
}));
- const deduplicateVolumes = () => {
- const existingVolumes = data.volumes || [];
- const formVolumeNames = new Set(
- data.configMapList.map((item) => pathToNameFormat(item.mountPath))
- );
- const preservedVolumes = existingVolumes.filter(
- (volume) => !(volume.configMap && formVolumeNames.has(volume.name))
- );
- return [...preservedVolumes, ...configMapVolumes];
+ const generateConfigMapVolumes = () => {
+ if (data.configMapList.length === 0) return [];
+ const uniqueVolumeNames = [...new Set(data.configMapList.map((item) => item.volumeName))];
+ return uniqueVolumeNames.map((volumeName) => ({
+ name: volumeName,
+ configMap: {
+ name: data.appName
+ }
+ }));
};
- const deduplicateVolumeMounts = () => {
- const existingMounts = data.volumeMounts || [];
- const formMountNames = new Set(configMapVolumeMounts.map((m) => m.name));
- const preservedMounts = existingMounts.filter((mount) => !formMountNames.has(mount.name));
- return [...preservedMounts, ...configMapVolumeMounts];
- };
+ const configMapVolumes = generateConfigMapVolumes();
- const finalVolumes = deduplicateVolumes();
- const finalVolumeMounts = deduplicateVolumeMounts();
+ const finalVolumes = configMapVolumes
+ ? [...(data.volumes || []), ...configMapVolumes]
+ : data.volumes || [];
+
+ const finalVolumeMounts = [...(data.volumeMounts || []), ...configMapVolumeMounts];
// pvc settings
const storageTemplates = data.storeList.map((store) => ({
@@ -452,7 +439,7 @@ export const json2ConfigMap = (data: AppEditType) => {
const configFile: { [key: string]: string } = {};
data.configMapList.forEach((item) => {
- configFile[pathToNameFormat(item.mountPath)] = item.value; // key === [development.***.volumes[*].configMap.items[0].key]
+ configFile[item.key] = item.value;
});
const template = {
diff --git a/frontend/providers/applaunchpad/src/utils/tools.ts b/frontend/providers/applaunchpad/src/utils/tools.ts
index 5e2baa6bf..f87397a7f 100644
--- a/frontend/providers/applaunchpad/src/utils/tools.ts
+++ b/frontend/providers/applaunchpad/src/utils/tools.ts
@@ -69,12 +69,18 @@ export const pathFormat = (str: string) => {
if (str.startsWith('/')) return `.${str}`;
return `./${str}`;
};
-export const pathToNameFormat = (str: string) => {
+
+export const mountPathToConfigMapKey = (str: string) => {
const endsWithSlash = str.endsWith('/');
const withoutTrailingSlash = endsWithSlash ? str.slice(0, -1) : str;
const replacedStr = withoutTrailingSlash.replace(/_/g, '-').replace(/[\/.]/g, 'vn-');
+ const result = replacedStr.toLowerCase();
- return replacedStr.toLowerCase();
+ if (result.length > 63) {
+ return result.slice(-63);
+ }
+
+ return result;
};
/**
@@ -274,10 +280,16 @@ export const patchYamlList = ({
// find create and patch
newFormJsonList.forEach((newYamlJson) => {
- const oldFormJson = oldFormJsonList.find(
- (item) =>
- item.kind === newYamlJson.kind && item?.metadata?.name === newYamlJson?.metadata?.name
- );
+ const oldFormJson =
+ newYamlJson.kind === 'ConfigMap'
+ ? originalYamlList.find(
+ (item) =>
+ item.kind === newYamlJson.kind && item?.metadata?.name === newYamlJson?.metadata?.name
+ )
+ : oldFormJsonList.find(
+ (item) =>
+ item.kind === newYamlJson.kind && item?.metadata?.name === newYamlJson?.metadata?.name
+ );
if (oldFormJson) {
const patchRes = jsonpatch.compare(oldFormJson, newYamlJson);
@@ -299,7 +311,7 @@ export const patchYamlList = ({
if (!crOldYamlJson) return newYamlJson;
- /* Fill in volumn */
+ /* Fill in volume - Handle Deployment/StatefulSet */
if (
oldFormJson.kind === YamlKindEnum.Deployment ||
oldFormJson.kind === YamlKindEnum.StatefulSet
@@ -380,8 +392,6 @@ export const patchYamlList = ({
}
}
- console.log('patch result:', oldFormJson.metadata?.name, oldFormJson.kind, actionsJson);
-
actions.push({
type: 'patch',
kind: newYamlJson.kind as `${YamlKindEnum}`,
diff --git a/frontend/providers/template/src/pages/index.tsx b/frontend/providers/template/src/pages/index.tsx
index a4dc5955e..d5880303f 100644
--- a/frontend/providers/template/src/pages/index.tsx
+++ b/frontend/providers/template/src/pages/index.tsx
@@ -299,8 +299,6 @@ export async function getServerSideProps(content: any) {
const forcedLanguage = process.env.FORCED_LANGUAGE;
const brandName = process.env.NEXT_PUBLIC_BRAND_NAME || 'Sealos';
- console.log('content', content);
-
const local: string =
forcedLanguage ||
content?.req?.cookies?.NEXT_LOCALE ||
@@ -325,8 +323,6 @@ export async function getServerSideProps(content: any) {
}
};
- console.log('local', local);
- console.log('seoData', seoData);
return {
props: {
...(await serviceSideProps(content)),