feat(k8s): M14 Namespace 管理看板(资源配额 + 命名空间 CRUD)
- 后端: ListNamespacesDetailed/CreateNamespace/DeleteNamespace/ListResourceQuotas/ListLimitRanges - 后端: GetNamespacesDetail handler (6 API calls aggregate, not N×3) - 后端: CreateNamespaceHandler + DeleteNamespaceHandler (system NS protection) - 前端: NamespaceManagementPage.tsx (~280行) — 表格+概览卡片+创建/删除弹框 - 路由: GET/POST/DELETE /:clusterCode/namespaces + GET /namespace/:ns/detail - 验证: 9/9 通过 (urllib), TS 零错误, Vite 构建成功
This commit is contained in:
1 parent
c7b61968bc
commit
8240a88a84
33 files changed
+2029
-71
No files matched your search
@@ -1023,6 +1023,134 @@ func (c *Client) ListNamespaces() ([]string, error) {
|
||||
return names, nil
|
||||
}
|
||||
|
||||
// NamespaceItem holds full namespace metadata
|
||||
type NamespaceItem struct {
|
||||
Metadata ObjectMeta `json:"metadata"`
|
||||
Spec NamespaceSpec `json:"spec"`
|
||||
Status NamespaceStatus `json:"status"`
|
||||
}
|
||||
|
||||
// NamespaceSpec holds namespace spec
|
||||
type NamespaceSpec struct {
|
||||
Finalizers []string `json:"finalizers"`
|
||||
}
|
||||
|
||||
// NamespaceStatus holds namespace phase
|
||||
type NamespaceStatus struct {
|
||||
Phase string `json:"phase"`
|
||||
}
|
||||
|
||||
// NamespaceList wraps a list of NamespaceItem
|
||||
type NamespaceList struct {
|
||||
Items []NamespaceItem `json:"items"`
|
||||
}
|
||||
|
||||
// ListNamespacesDetailed returns all namespaces with full metadata
|
||||
func (c *Client) ListNamespacesDetailed() (*NamespaceList, error) {
|
||||
var result NamespaceList
|
||||
if err := c.get("/api/v1/namespaces", &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// GetNamespace returns a single namespace by name
|
||||
func (c *Client) GetNamespace(name string) (*NamespaceItem, error) {
|
||||
var result NamespaceItem
|
||||
path := fmt.Sprintf("/api/v1/namespaces/%s", name)
|
||||
if err := c.get(path, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// CreateNamespace creates a new namespace
|
||||
func (c *Client) CreateNamespace(name string, labels map[string]string) (*NamespaceItem, error) {
|
||||
body := map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Namespace",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": name,
|
||||
"labels": labels,
|
||||
},
|
||||
}
|
||||
var result NamespaceItem
|
||||
if err := c.post("/api/v1/namespaces", body, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// DeleteNamespace deletes a namespace by name
|
||||
func (c *Client) DeleteNamespace(name string) error {
|
||||
path := fmt.Sprintf("/api/v1/namespaces/%s", name)
|
||||
return c.delete(path)
|
||||
}
|
||||
|
||||
// ResourceQuotaItem represents a K8s ResourceQuota
|
||||
type ResourceQuotaItem struct {
|
||||
Metadata ObjectMeta `json:"metadata"`
|
||||
Spec ResourceQuotaSpec `json:"spec"`
|
||||
Status ResourceQuotaStatus `json:"status"`
|
||||
}
|
||||
|
||||
// ResourceQuotaSpec holds hard limits
|
||||
type ResourceQuotaSpec struct {
|
||||
Hard map[string]string `json:"hard"`
|
||||
Scopes []string `json:"scopes,omitempty"`
|
||||
}
|
||||
|
||||
// ResourceQuotaStatus holds used/hard counts
|
||||
type ResourceQuotaStatus struct {
|
||||
Hard map[string]string `json:"hard"`
|
||||
Used map[string]string `json:"used"`
|
||||
}
|
||||
|
||||
// ListResourceQuotas returns ResourceQuotas in a namespace, or all namespaces if ns is empty
|
||||
func (c *Client) ListResourceQuotas(namespace string) ([]ResourceQuotaItem, error) {
|
||||
var result struct {
|
||||
Items []ResourceQuotaItem `json:"items"`
|
||||
}
|
||||
var path string
|
||||
if namespace == "" {
|
||||
path = "/api/v1/resourcequotas"
|
||||
} else {
|
||||
path = fmt.Sprintf("/api/v1/namespaces/%s/resourcequotas", namespace)
|
||||
}
|
||||
if err := c.get(path, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.Items, nil
|
||||
}
|
||||
|
||||
// LimitRangeItem represents a K8s LimitRange
|
||||
type LimitRangeItem struct {
|
||||
Metadata ObjectMeta `json:"metadata"`
|
||||
Spec LimitRangeSpec `json:"spec"`
|
||||
}
|
||||
|
||||
// LimitRangeSpec holds limit items
|
||||
type LimitRangeSpec struct {
|
||||
Limits []map[string]interface{} `json:"limits"`
|
||||
}
|
||||
|
||||
// ListLimitRanges returns LimitRanges in a namespace, or all namespaces if ns is empty
|
||||
func (c *Client) ListLimitRanges(namespace string) ([]LimitRangeItem, error) {
|
||||
var result struct {
|
||||
Items []LimitRangeItem `json:"items"`
|
||||
}
|
||||
var path string
|
||||
if namespace == "" {
|
||||
path = "/api/v1/limitranges"
|
||||
} else {
|
||||
path = fmt.Sprintf("/api/v1/namespaces/%s/limitranges", namespace)
|
||||
}
|
||||
if err := c.get(path, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.Items, nil
|
||||
}
|
||||
|
||||
// --- ConfigMap ---
|
||||
|
||||
// ConfigMapList response
|
||||
@@ -1366,6 +1494,110 @@ func (c *Client) ListEvents(namespace string) (*EventList, error) {
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// RBAC — ServiceAccount / Role / RoleBinding
|
||||
// ============================================================================
|
||||
|
||||
// --- ServiceAccount ---
|
||||
|
||||
type ServiceAccountList struct {
|
||||
Items []ServiceAccountItem `json:"items"`
|
||||
}
|
||||
|
||||
type ServiceAccountItem struct {
|
||||
Metadata ObjectMeta `json:"metadata"`
|
||||
Spec struct {
|
||||
ImagePullSecrets []struct {
|
||||
Name string `json:"name"`
|
||||
} `json:"imagePullSecrets"`
|
||||
Secrets []struct {
|
||||
Name string `json:"name"`
|
||||
} `json:"secrets"`
|
||||
} `json:"secrets"`
|
||||
}
|
||||
|
||||
type ServiceAccountRaw struct {
|
||||
Metadata ObjectMeta `json:"metadata"`
|
||||
Secrets []struct {
|
||||
Name string `json:"name"`
|
||||
} `json:"secrets"`
|
||||
ImagePullSecrets []struct {
|
||||
Name string `json:"name"`
|
||||
} `json:"imagePullSecrets"`
|
||||
}
|
||||
|
||||
// ListServiceAccounts fetches ServiceAccounts in a namespace
|
||||
func (c *Client) ListServiceAccounts(namespace string) ([]ServiceAccountRaw, error) {
|
||||
var result struct {
|
||||
Items []ServiceAccountRaw `json:"items"`
|
||||
}
|
||||
path := fmt.Sprintf("/api/v1/namespaces/%s/serviceaccounts", namespace)
|
||||
if err := c.get(path, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.Items, nil
|
||||
}
|
||||
|
||||
// --- Role ---
|
||||
|
||||
type RoleList struct {
|
||||
Items []RoleItem `json:"items"`
|
||||
}
|
||||
|
||||
type RoleItem struct {
|
||||
Metadata ObjectMeta `json:"metadata"`
|
||||
Rules []PolicyRule `json:"rules"`
|
||||
}
|
||||
|
||||
type PolicyRule struct {
|
||||
Verbs []string `json:"verbs"`
|
||||
Resources []string `json:"resources"`
|
||||
APIGroups []string `json:"apiGroups"`
|
||||
}
|
||||
|
||||
// ListRoles fetches Roles in a namespace
|
||||
func (c *Client) ListRoles(namespace string) (*RoleList, error) {
|
||||
var result RoleList
|
||||
path := fmt.Sprintf("/apis/rbac.authorization.k8s.io/v1/namespaces/%s/roles", namespace)
|
||||
if err := c.get(path, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// --- RoleBinding ---
|
||||
|
||||
type RoleBindingList struct {
|
||||
Items []RoleBindingItem `json:"items"`
|
||||
}
|
||||
|
||||
type RoleBindingItem struct {
|
||||
Metadata ObjectMeta `json:"metadata"`
|
||||
RoleRef RoleRef `json:"roleRef"`
|
||||
Subjects []Subject `json:"subjects"`
|
||||
}
|
||||
|
||||
type RoleRef struct {
|
||||
Kind string `json:"kind"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type Subject struct {
|
||||
Kind string `json:"kind"`
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
}
|
||||
|
||||
// ListRoleBindings fetches RoleBindings in a namespace
|
||||
func (c *Client) ListRoleBindings(namespace string) (*RoleBindingList, error) {
|
||||
var result RoleBindingList
|
||||
path := fmt.Sprintf("/apis/rbac.authorization.k8s.io/v1/namespaces/%s/rolebindings", namespace)
|
||||
if err := c.get(path, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// YAML Apply (Dynamic resource apply)
|
||||
// ============================================================================
|
||||
|
||||
Reference in new issue
Block a user