fix: implement proper resource deletion for all resource types
This commit is contained in:
@@ -191,6 +191,74 @@ export default function K8sResourceList() {
|
|||||||
return () => eventSource.close()
|
return () => eventSource.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleDeleteResource = async () => {
|
||||||
|
if (!deleteTarget) return
|
||||||
|
|
||||||
|
setDeleting(true)
|
||||||
|
try {
|
||||||
|
let endpoint = '';
|
||||||
|
let kind = '';
|
||||||
|
|
||||||
|
// Determine the correct endpoint based on the selected resource kind
|
||||||
|
switch (selectedKind.key) {
|
||||||
|
case 'pod':
|
||||||
|
endpoint = '/api/v1/k8s/pod/delete'
|
||||||
|
kind = 'Pod'
|
||||||
|
break
|
||||||
|
case 'deployment':
|
||||||
|
endpoint = '/api/v1/k8s/deployment/delete'
|
||||||
|
kind = 'Deployment'
|
||||||
|
break
|
||||||
|
case 'statefulset':
|
||||||
|
endpoint = '/api/v1/k8s/statefulset/delete'
|
||||||
|
kind = 'StatefulSet'
|
||||||
|
break
|
||||||
|
case 'service':
|
||||||
|
endpoint = '/api/v1/k8s/service/delete'
|
||||||
|
kind = 'Service'
|
||||||
|
break
|
||||||
|
case 'configmap':
|
||||||
|
endpoint = '/api/v1/k8s/configmap/delete'
|
||||||
|
kind = 'ConfigMap'
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
throw new Error(`Unsupported resource kind: ${selectedKind.key}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await fetch(endpoint, {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
name: deleteTarget.name,
|
||||||
|
namespace: deleteTarget.namespace
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const result = await res.json()
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error(result.err || `Failed to delete ${kind}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
setSnackbar({
|
||||||
|
open: true,
|
||||||
|
message: `${kind} 删除成功`,
|
||||||
|
severity: 'success'
|
||||||
|
})
|
||||||
|
setDeleteDialogOpen(false)
|
||||||
|
setDeleteTarget(null)
|
||||||
|
fetchResources()
|
||||||
|
} catch (e: any) {
|
||||||
|
setSnackbar({
|
||||||
|
open: true,
|
||||||
|
message: `删除失败: ${e.message}`,
|
||||||
|
severity: 'error'
|
||||||
|
})
|
||||||
|
} finally {
|
||||||
|
setDeleting(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleDeletePod = async () => {
|
const handleDeletePod = async () => {
|
||||||
if (!deleteTarget) return
|
if (!deleteTarget) return
|
||||||
|
|
||||||
@@ -806,7 +874,7 @@ export default function K8sResourceList() {
|
|||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="error"
|
color="error"
|
||||||
onClick={handleDeletePod}
|
onClick={handleDeleteResource}
|
||||||
disabled={deleting}
|
disabled={deleting}
|
||||||
>
|
>
|
||||||
{deleting ? <CircularProgress size={24} /> : '删除'}
|
{deleting ? <CircularProgress size={24} /> : '删除'}
|
||||||
|
|||||||
@@ -72,14 +72,18 @@ func Init(ctx context.Context, address string, db *gorm.DB, store store.Store) (
|
|||||||
// resource list
|
// resource list
|
||||||
k8sAPI.Get("/namespace/list", k8s.K8sNamespaceList(ctx, db, store))
|
k8sAPI.Get("/namespace/list", k8s.K8sNamespaceList(ctx, db, store))
|
||||||
k8sAPI.Get("/deployment/list", k8s.K8sDeploymentList(ctx, db, store))
|
k8sAPI.Get("/deployment/list", k8s.K8sDeploymentList(ctx, db, store))
|
||||||
|
k8sAPI.Delete("/deployment/delete", k8s.K8sDeploymentDelete(ctx, db, store))
|
||||||
k8sAPI.Get("/statefulset/list", k8s.K8sStatefulSetList(ctx, db, store))
|
k8sAPI.Get("/statefulset/list", k8s.K8sStatefulSetList(ctx, db, store))
|
||||||
|
k8sAPI.Delete("/statefulset/delete", k8s.K8sStatefulSetDelete(ctx, db, store))
|
||||||
k8sAPI.Get("/configmap/list", k8s.K8sConfigMapList(ctx, db, store))
|
k8sAPI.Get("/configmap/list", k8s.K8sConfigMapList(ctx, db, store))
|
||||||
|
k8sAPI.Delete("/configmap/delete", k8s.K8sConfigMapDelete(ctx, db, store))
|
||||||
k8sAPI.Get("/pod/list", k8s.K8sPodList(ctx, db, store))
|
k8sAPI.Get("/pod/list", k8s.K8sPodList(ctx, db, store))
|
||||||
k8sAPI.Get("/pod/logs", k8s.K8sPodLogs(ctx, db, store))
|
k8sAPI.Get("/pod/logs", k8s.K8sPodLogs(ctx, db, store))
|
||||||
k8sAPI.Delete("/pod/delete", k8s.K8sPodDelete(ctx, db, store))
|
k8sAPI.Delete("/pod/delete", k8s.K8sPodDelete(ctx, db, store))
|
||||||
k8sAPI.Get("/pv/list", k8s.K8sPVList(ctx, db, store))
|
k8sAPI.Get("/pv/list", k8s.K8sPVList(ctx, db, store))
|
||||||
k8sAPI.Get("/pvc/list", k8s.K8sPVCList(ctx, db, store))
|
k8sAPI.Get("/pvc/list", k8s.K8sPVCList(ctx, db, store))
|
||||||
k8sAPI.Get("/service/list", k8s.K8sServiceList(ctx, db, store))
|
k8sAPI.Get("/service/list", k8s.K8sServiceList(ctx, db, store))
|
||||||
|
k8sAPI.Delete("/service/delete", k8s.K8sServiceDelete(ctx, db, store))
|
||||||
}
|
}
|
||||||
|
|
||||||
ln, err = net.Listen("tcp", address)
|
ln, err = net.Listen("tcp", address)
|
||||||
|
|||||||
@@ -799,3 +799,131 @@ func K8sPodDelete(ctx context.Context, db *gorm.DB, store store.Store) fiber.Han
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func K8sDeploymentDelete(ctx context.Context, db *gorm.DB, store store.Store) fiber.Handler {
|
||||||
|
return func(c fiber.Ctx) error {
|
||||||
|
var req struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(c.Body(), &req); err != nil {
|
||||||
|
return resp.R400(c, "", nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Name == "" || req.Namespace == "" {
|
||||||
|
return resp.R400(c, "", nil, fmt.Errorf("name and namespace are required"))
|
||||||
|
}
|
||||||
|
|
||||||
|
clientset, err := getK8sClient(db)
|
||||||
|
if err != nil {
|
||||||
|
return resp.R500(c, "", nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = clientset.AppsV1().Deployments(req.Namespace).Delete(c.Context(), req.Name, metav1.DeleteOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return resp.R500(c, "", nil, fmt.Errorf("failed to delete deployment: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp.R200(c, map[string]any{
|
||||||
|
"name": req.Name,
|
||||||
|
"namespace": req.Namespace,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func K8sStatefulSetDelete(ctx context.Context, db *gorm.DB, store store.Store) fiber.Handler {
|
||||||
|
return func(c fiber.Ctx) error {
|
||||||
|
var req struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(c.Body(), &req); err != nil {
|
||||||
|
return resp.R400(c, "", nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Name == "" || req.Namespace == "" {
|
||||||
|
return resp.R400(c, "", nil, fmt.Errorf("name and namespace are required"))
|
||||||
|
}
|
||||||
|
|
||||||
|
clientset, err := getK8sClient(db)
|
||||||
|
if err != nil {
|
||||||
|
return resp.R500(c, "", nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = clientset.AppsV1().StatefulSets(req.Namespace).Delete(c.Context(), req.Name, metav1.DeleteOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return resp.R500(c, "", nil, fmt.Errorf("failed to delete statefulset: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp.R200(c, map[string]any{
|
||||||
|
"name": req.Name,
|
||||||
|
"namespace": req.Namespace,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func K8sServiceDelete(ctx context.Context, db *gorm.DB, store store.Store) fiber.Handler {
|
||||||
|
return func(c fiber.Ctx) error {
|
||||||
|
var req struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(c.Body(), &req); err != nil {
|
||||||
|
return resp.R400(c, "", nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Name == "" || req.Namespace == "" {
|
||||||
|
return resp.R400(c, "", nil, fmt.Errorf("name and namespace are required"))
|
||||||
|
}
|
||||||
|
|
||||||
|
clientset, err := getK8sClient(db)
|
||||||
|
if err != nil {
|
||||||
|
return resp.R500(c, "", nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = clientset.CoreV1().Services(req.Namespace).Delete(c.Context(), req.Name, metav1.DeleteOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return resp.R500(c, "", nil, fmt.Errorf("failed to delete service: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp.R200(c, map[string]any{
|
||||||
|
"name": req.Name,
|
||||||
|
"namespace": req.Namespace,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func K8sConfigMapDelete(ctx context.Context, db *gorm.DB, store store.Store) fiber.Handler {
|
||||||
|
return func(c fiber.Ctx) error {
|
||||||
|
var req struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(c.Body(), &req); err != nil {
|
||||||
|
return resp.R400(c, "", nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Name == "" || req.Namespace == "" {
|
||||||
|
return resp.R400(c, "", nil, fmt.Errorf("name and namespace are required"))
|
||||||
|
}
|
||||||
|
|
||||||
|
clientset, err := getK8sClient(db)
|
||||||
|
if err != nil {
|
||||||
|
return resp.R500(c, "", nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = clientset.CoreV1().ConfigMaps(req.Namespace).Delete(c.Context(), req.Name, metav1.DeleteOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return resp.R500(c, "", nil, fmt.Errorf("failed to delete configmap: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp.R200(c, map[string]any{
|
||||||
|
"name": req.Name,
|
||||||
|
"namespace": req.Namespace,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user