Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix:dbprovider auto backup #4515

Merged
merged 2 commits into from Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 7 additions & 9 deletions frontend/providers/applaunchpad/next.config.js
@@ -1,8 +1,6 @@
/** @type {import('next').NextConfig} */
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const { i18n } = require('./next-i18next.config');
const analyzer = process.env === 'production' ? [new BundleAnalyzerPlugin()] : [];
const path = require('path');
const { i18n } = require('./next-i18next.config')
const path = require('path')
const nextConfig = {
i18n,
output: 'standalone',
Expand All @@ -15,14 +13,14 @@ const nextConfig = {
issuer: /\.[jt]sx?$/,
use: ['@svgr/webpack']
}
]);
config.plugins = [...config.plugins, ...analyzer];
return config;
])
config.plugins = [...config.plugins]
return config
},
transpilePackages: ['@sealos/driver'],
experimental: {
outputFileTracingRoot: path.join(__dirname, '../../')
}
};
}

module.exports = nextConfig;
module.exports = nextConfig
16 changes: 7 additions & 9 deletions frontend/providers/cronjob/next.config.js
@@ -1,8 +1,6 @@
/** @type {import('next').NextConfig} */
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const { i18n } = require('./next-i18next.config');
const analyzer = process.env === 'production' ? [new BundleAnalyzerPlugin()] : [];
const path = require('path');
const { i18n } = require('./next-i18next.config')
const path = require('path')
const nextConfig = {
i18n,
output: 'standalone',
Expand All @@ -15,14 +13,14 @@ const nextConfig = {
issuer: /\.[jt]sx?$/,
use: ['@svgr/webpack']
}
]);
config.plugins = [...config.plugins, ...analyzer];
return config;
])
config.plugins = [...config.plugins]
return config
},
experimental: {
// this includes files from the monorepo base two directories up
outputFileTracingRoot: path.join(__dirname, '../../')
}
};
}

module.exports = nextConfig;
module.exports = nextConfig
9 changes: 6 additions & 3 deletions frontend/providers/dbprovider/deploy/manifests/rbac.yaml
Expand Up @@ -9,9 +9,12 @@ kind: ClusterRole
metadata:
name: cluster-version-reader
rules:
- apiGroups: ["apps.kubeblocks.io"]
resources: [ "clusterversions" ]
verbs: [ "get", "watch", "list"]
- apiGroups: ['apps.kubeblocks.io']
resources: ['clusterversions']
verbs: ['get', 'watch', 'list']
- apiGroups: ['dataprotection.kubeblocks.io']
resources: ['backuprepos']
verbs: ['get', 'watch', 'list']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
Expand Down
16 changes: 7 additions & 9 deletions frontend/providers/dbprovider/next.config.js
@@ -1,8 +1,6 @@
/** @type {import('next').NextConfig} */
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const { i18n } = require('./next-i18next.config');
const analyzer = process.env === 'production' ? [new BundleAnalyzerPlugin()] : [];
const path = require('path');
const { i18n } = require('./next-i18next.config')
const path = require('path')
const nextConfig = {
i18n,
output: 'standalone',
Expand All @@ -15,14 +13,14 @@ const nextConfig = {
issuer: /\.[jt]sx?$/,
use: ['@svgr/webpack']
}
]);
config.plugins = [...config.plugins, ...analyzer];
return config;
])
config.plugins = [...config.plugins]
return config
},
experimental: {
// this includes files from the monorepo base two directories up
outputFileTracingRoot: path.join(__dirname, '../../')
}
};
}

module.exports = nextConfig;
module.exports = nextConfig
60 changes: 49 additions & 11 deletions frontend/providers/dbprovider/src/pages/api/backup/updatePolicy.ts
@@ -1,28 +1,33 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { ApiResp } from '@/services/kubernet';
import { DBTypeEnum } from '@/constants/db';
import { authSession } from '@/services/backend/auth';
import { getK8s } from '@/services/backend/kubernetes';
import { K8sApi, K8sApiDefault, getK8s } from '@/services/backend/kubernetes';
import { jsonRes } from '@/services/backend/response';
import { ApiResp } from '@/services/kubernet';
import { BackupRepoCRItemType } from '@/types/backup';
import * as k8s from '@kubernetes/client-node';
import { PatchUtils } from '@kubernetes/client-node';
import { DBBackupPolicyNameMap, DBTypeEnum } from '@/constants/db';
import type { NextApiRequest, NextApiResponse } from 'next';

export type Props = {
dbName: string;
dbType: `${DBTypeEnum}`;
patch: Object;
autoBackup?: {
enabled: boolean;
cronExpression: string;
method: string;
retentionPeriod: string;
repoName: string;
};
};

export default async function handler(req: NextApiRequest, res: NextApiResponse<ApiResp>) {
const { dbName, dbType, patch } = req.body as Props;
const { dbName, dbType, autoBackup } = req.body as Props;

console.log(dbName, dbType, patch);

if (!dbName || !dbType || !patch) {
jsonRes(res, {
if (!dbName || !dbType) {
return jsonRes(res, {
code: 500,
error: 'params error'
});
return;
}

const group = 'apps.kubeblocks.io';
Expand All @@ -34,6 +39,39 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
kubeconfig: await authSession(req)
});

// Get cluster backup repository
const kc = K8sApiDefault();
const backupRepos = (await kc
.makeApiClient(k8s.CustomObjectsApi)
.listClusterCustomObject('dataprotection.kubeblocks.io', 'v1alpha1', 'backuprepos')) as {
body: {
items: BackupRepoCRItemType[];
};
};
const backupRepoName = backupRepos?.body?.items?.[0]?.metadata?.name;

if (!backupRepoName) {
throw new Error('Missing backup repository');
}
const patch = autoBackup
? [
{
op: 'replace',
path: '/spec/backup',
value: {
...autoBackup,
repoName: backupRepoName
}
}
]
: [
{
op: 'replace',
path: '/spec/backup/enabled',
value: false
}
];

// get backup backupolicies.dataprotection.kubeblocks.io
const result = await k8sCustomObjects.patchNamespacedCustomObject(
group,
Expand Down
Expand Up @@ -45,7 +45,7 @@ const AppBaseInfo = ({ db = defaultDBDetail }: { db: DBDetailType }) => {
const { toast } = useToast();

const supportConnectDB = useMemo(() => {
return !!['postgresql', 'mongodb', 'apecloud-mysql', 'redis'].find(
return !!['postgresql', 'mongodb', 'apecloud-mysql', 'redis', 'milvus'].find(
(item) => item === db.dbType
);
}, [db.dbType]);
Expand Down Expand Up @@ -276,29 +276,33 @@ const AppBaseInfo = ({ db = defaultDBDetail }: { db: DBDetailType }) => {
color={'myGray.600'}
></MyIcon>
</Center>
<Center
ml="12px"
h="24px"
color={'#24282C'}
fontSize={'12px'}
bg="#F4F6F8"
borderRadius={'4px'}
px="8px"
cursor={'pointer'}
onClick={() => onclickConnectDB()}
>
<MyIcon name="terminal" w="16px" h="16px" />
{t('Direct Connection')}
</Center>
<Center fontSize={'12px'} fontWeight={400} ml="auto">
<Text> {t('External Network')} </Text>
<Switch
ml="8px"
size="sm"
isChecked={isChecked}
onChange={(e) => (isChecked ? closeNetWorkService() : onOpen())}
/>
</Center>
{db.dbType !== 'milvus' && (
<>
<Center
ml="12px"
h="24px"
color={'#24282C'}
fontSize={'12px'}
bg="#F4F6F8"
borderRadius={'4px'}
px="8px"
cursor={'pointer'}
onClick={() => onclickConnectDB()}
>
<MyIcon name="terminal" w="16px" h="16px" />
{t('Direct Connection')}
</Center>
<Center fontSize={'12px'} fontWeight={400} ml="auto">
<Text> {t('External Network')} </Text>
<Switch
ml="8px"
size="sm"
isChecked={isChecked}
onChange={(e) => (isChecked ? closeNetWorkService() : onOpen())}
/>
</Center>
</>
)}
</Flex>
<Box
mt={3}
Expand Down
Expand Up @@ -28,7 +28,7 @@ import { useForm } from 'react-hook-form';
import type { AutoBackupFormType, AutoBackupType } from '@/types/backup';
import Tabs from '@/components/Tabs';
import MySelect from '@/components/Select';
import { DBTypeEnum } from '@/constants/db';
import { DBBackupMethodNameMap, DBTypeEnum } from '@/constants/db';

enum NavEnum {
manual = 'manual',
Expand Down Expand Up @@ -168,24 +168,18 @@ const BackupModal = ({
return `${data.minute} * * * *`;
})();

const patch = [
{
op: 'replace',
path: '/spec/backup',
value: {
enabled: data.start,
cronExpression: convertCronTime(cron, -8),
method: 'backupTool',
pitrEnabled: false,
retentionPeriod: `${data.saveTime}${data.saveType}`
}
}
];
const autoBackup = {
enabled: data.start,
cronExpression: convertCronTime(cron, -8),
method: DBBackupMethodNameMap[dbType],
retentionPeriod: `${data.saveTime}${data.saveType}`,
repoName: ''
};

return updateBackupPolicy({
dbName,
dbType,
patch
autoBackup
});
},
onSuccess() {
Expand All @@ -206,18 +200,10 @@ const BackupModal = ({

const { mutate: onclickCloseAutoBackup } = useMutation({
mutationFn: async () => {
const patch = [
{
op: 'replace',
path: '/spec/backup/enabled',
value: false
}
];

return updateBackupPolicy({
dbName,
dbType,
patch
autoBackup: undefined
});
},
onSuccess() {
Expand Down
12 changes: 9 additions & 3 deletions frontend/providers/dbprovider/src/services/backend/kubernetes.ts
Expand Up @@ -3,6 +3,13 @@ import { cpuFormatToM, memoryFormatToMi } from '@/utils/tools';
import * as k8s from '@kubernetes/client-node';
import * as yaml from 'js-yaml';

// Load default kc
export function K8sApiDefault(): k8s.KubeConfig {
const kc = new k8s.KubeConfig();
kc.loadFromDefault();
return kc;
}

export function CheckIsInCluster(): [boolean, string] {
if (
process.env.KUBERNETES_SERVICE_HOST !== undefined &&
Expand Down Expand Up @@ -89,13 +96,12 @@ export async function createYaml(
for (const spec of created) {
try {
console.log('delete:', spec.kind);
client.delete(spec);
await client.delete(spec);
} catch (error) {
error;
}
}
// console.error(error, '<=create error')
return Promise.reject(error);
return Promise.reject(error?.body || 'Create Yaml Error');
}
return created;
}
Expand Down
11 changes: 11 additions & 0 deletions frontend/providers/dbprovider/src/types/backup.d.ts
Expand Up @@ -66,3 +66,14 @@ export type AutoBackupFormType = {
saveTime: number;
saveType: string;
};

export type BackupRepoCRItemType = {
kind: 'BackupRepo';
metadata: {
annotations: Record<string, string>;
creationTimestamp: Date;
labels: Record<string, string>;
name: string;
uid: string;
};
};
1 change: 1 addition & 0 deletions frontend/providers/dbprovider/src/types/cluster.d.ts
Expand Up @@ -54,6 +54,7 @@ export interface KubeBlockClusterSpec {
cronExpression: string;
method: string;
pitrEnabled: boolean;
repoName: string;
retentionPeriod: string;
};
}
Expand Down
1 change: 0 additions & 1 deletion frontend/providers/dbprovider/src/utils/json2Yaml.ts
Expand Up @@ -660,7 +660,6 @@ export const json2CreateCluster = (data: DBEditType, backupInfo?: BackupItemType
}
]
};
console.log(map[data.dbType].map((item) => yaml.dump(item)).join('\n---\n'));

return map[data.dbType].map((item) => yaml.dump(item)).join('\n---\n');
};
Expand Down