This commit is contained in:
Logan committed 2026-07-09 14:16:56 +08:00
1 parent 0690285147
commit 5618cd2738
154 files changed
+5021 -3161

No files matched your search

+149 -113
View File
@@ -203,16 +203,22 @@ func (c *Client) get(path string, result interface{}) error {
// getRaw performs a GET request returning raw bytes with custom Accept header
func (c *Client) getRaw(path string, accept string) ([]byte, error) {
req, err := http.NewRequest("GET", c.BaseURL+path, nil)
if err != nil { return nil, err }
if err != nil {
return nil, err
}
req.Header.Set("Accept", accept)
if c.BearerToken != "" {
req.Header.Set("Authorization", "Bearer "+c.BearerToken)
}
resp, err := c.HTTPClient.Do(req)
if err != nil { return nil, fmt.Errorf("GET %s: %w", path, err) }
if err != nil {
return nil, fmt.Errorf("GET %s: %w", path, err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil { return nil, fmt.Errorf("read body: %w", err) }
if err != nil {
return nil, fmt.Errorf("read body: %w", err)
}
if resp.StatusCode >= 400 {
return nil, fmt.Errorf("K8s API error %d: %s", resp.StatusCode, string(body[:min(len(body), 200)]))
}
@@ -222,13 +228,17 @@ func (c *Client) getRaw(path string, accept string) ([]byte, error) {
// putRaw performs a PUT request with raw body and custom Content-Type
func (c *Client) putRaw(path string, contentType string, data []byte) error {
req, err := http.NewRequest("PUT", c.BaseURL+path, strings.NewReader(string(data)))
if err != nil { return err }
if err != nil {
return err
}
req.Header.Set("Content-Type", contentType)
if c.BearerToken != "" {
req.Header.Set("Authorization", "Bearer "+c.BearerToken)
}
resp, err := c.HTTPClient.Do(req)
if err != nil { return fmt.Errorf("PUT %s: %w", path, err) }
if err != nil {
return fmt.Errorf("PUT %s: %w", path, err)
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
body, _ := io.ReadAll(resp.Body)
@@ -245,9 +255,9 @@ type NodeList struct {
}
type NodeItem struct {
Metadata ObjectMeta `json:"metadata"`
Status NodeStatus `json:"status"`
Spec NodeSpec `json:"spec"`
Metadata ObjectMeta `json:"metadata"`
Status NodeStatus `json:"status"`
Spec NodeSpec `json:"spec"`
}
type NodeSpec struct {
@@ -263,11 +273,11 @@ type NodeTaint struct {
}
type NodeStatus struct {
Capacity ResourceList `json:"capacity"`
Allocatable ResourceList `json:"allocatable"`
Capacity ResourceList `json:"capacity"`
Allocatable ResourceList `json:"allocatable"`
Conditions []NodeCondition `json:"conditions"`
NodeInfo NodeInfo `json:"nodeInfo"`
Addresses []NodeAddress `json:"addresses"`
NodeInfo NodeInfo `json:"nodeInfo"`
Addresses []NodeAddress `json:"addresses"`
}
type ResourceList map[string]string
@@ -305,14 +315,14 @@ type PodItem struct {
}
type PodSpec struct {
NodeName string `json:"nodeName"`
NodeName string `json:"nodeName"`
Containers []Container `json:"containers"`
}
type Container struct {
Name string `json:"name"`
Image string `json:"image"`
Resources ContainerRes `json:"resources"`
Name string `json:"name"`
Image string `json:"image"`
Resources ContainerRes `json:"resources"`
}
type ContainerRes struct {
@@ -321,10 +331,10 @@ type ContainerRes struct {
}
type PodStatus struct {
Phase string `json:"phase"`
PodIP string `json:"podIP"`
ContainerStatuses []ContainerStatus `json:"containerStatuses"`
Conditions []PodCondition `json:"conditions,omitempty"`
Phase string `json:"phase"`
PodIP string `json:"podIP"`
ContainerStatuses []ContainerStatus `json:"containerStatuses"`
Conditions []PodCondition `json:"conditions,omitempty"`
}
// PodCondition for pod status conditions (Scheduled, Initialized, Ready etc)
@@ -337,8 +347,30 @@ type PodCondition struct {
}
type ContainerStatus struct {
RestartCount int `json:"restartCount"`
Ready bool `json:"ready"`
Name string `json:"name"`
RestartCount int `json:"restartCount"`
Ready bool `json:"ready"`
State ContainerStatusState `json:"state,omitempty"`
LastState ContainerStatusState `json:"lastState,omitempty"`
}
// ContainerStatusState 解析容器等待/终止状态,用于 AI 诊断 ImagePullBackOff、OOMKilled 等原因。 // Logan.Li
type ContainerStatusState struct {
Waiting *ContainerStateWaiting `json:"waiting,omitempty"`
Terminated *ContainerStateTerminated `json:"terminated,omitempty"`
}
// ContainerStateWaiting 容器等待状态。 // Logan.Li
type ContainerStateWaiting struct {
Reason string `json:"reason,omitempty"`
Message string `json:"message,omitempty"`
}
// ContainerStateTerminated 容器终止状态。 // Logan.Li
type ContainerStateTerminated struct {
Reason string `json:"reason,omitempty"`
Message string `json:"message,omitempty"`
ExitCode int `json:"exitCode,omitempty"`
}
// DeploymentList response
@@ -380,8 +412,8 @@ type ServiceList struct {
}
type ServiceItem struct {
Metadata ObjectMeta `json:"metadata"`
Spec ServiceSpec `json:"spec"`
Metadata ObjectMeta `json:"metadata"`
Spec ServiceSpec `json:"spec"`
}
type ServiceSpec struct {
@@ -392,11 +424,11 @@ type ServiceSpec struct {
}
type ServicePort struct {
Name string `json:"name"`
Port int `json:"port"`
Name string `json:"name"`
Port int `json:"port"`
TargetPort interface{} `json:"targetPort"`
NodePort int `json:"nodePort"`
Protocol string `json:"protocol"`
NodePort int `json:"nodePort"`
Protocol string `json:"protocol"`
}
// IngressList response
@@ -405,13 +437,13 @@ type IngressList struct {
}
type IngressItem struct {
Metadata ObjectMeta `json:"metadata"`
Spec IngressSpec `json:"spec"`
Metadata ObjectMeta `json:"metadata"`
Spec IngressSpec `json:"spec"`
}
type IngressSpec struct {
TLS []IngressTLS `json:"tls"`
Rules []IngressRule `json:"rules"`
TLS []IngressTLS `json:"tls"`
Rules []IngressRule `json:"rules"`
}
type IngressTLS struct {
@@ -419,7 +451,7 @@ type IngressTLS struct {
}
type IngressRule struct {
Host string `json:"host"`
Host string `json:"host"`
HTTP *IngressHTTP `json:"http,omitempty"`
}
@@ -428,8 +460,8 @@ type IngressHTTP struct {
}
type IngressPath struct {
Path string `json:"path"`
PathType string `json:"pathType"`
Path string `json:"path"`
PathType string `json:"pathType"`
Backend IngressBackend `json:"backend"`
}
@@ -438,7 +470,7 @@ type IngressBackend struct {
}
type IngressBackendService struct {
Name string `json:"name"`
Name string `json:"name"`
Port IngressServicePort `json:"port"`
}
@@ -461,20 +493,20 @@ type IngressClassItem struct {
// ObjectMeta
type ObjectMeta struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
Labels map[string]string `json:"labels"`
Annotations map[string]string `json:"annotations"`
CreationTimestamp string `json:"creationTimestamp"`
Name string `json:"name"`
Namespace string `json:"namespace"`
Labels map[string]string `json:"labels"`
Annotations map[string]string `json:"annotations"`
CreationTimestamp string `json:"creationTimestamp"`
}
// SyncResult holds sync counts
type SyncResult struct {
Nodes int `json:"nodes"`
Pods int `json:"pods"`
Deployments int `json:"deployments"`
Services int `json:"services"`
Ingresses int `json:"ingresses"`
Nodes int `json:"nodes"`
Pods int `json:"pods"`
Deployments int `json:"deployments"`
Services int `json:"services"`
Ingresses int `json:"ingresses"`
Errors []string `json:"errors,omitempty"` // 各资源同步错误,便于排查 // Logan.Li
}
@@ -812,8 +844,8 @@ func (c *Client) ExecInPod(namespace, podName, container string, command []strin
url.PathEscape(namespace), url.PathEscape(podName), params.Encode())
dialer := websocket.Dialer{
TLSClientConfig: c.TLSConfig,
Subprotocols: []string{"v4.channel.k8s.io", "v3.channel.k8s.io", "channel.k8s.io"},
TLSClientConfig: c.TLSConfig,
Subprotocols: []string{"v4.channel.k8s.io", "v3.channel.k8s.io", "channel.k8s.io"},
HandshakeTimeout: 10 * time.Second,
}
header := http.Header{}
@@ -863,9 +895,9 @@ type HPAList struct {
// HPAItem represents a HorizontalPodAutoscaler
type HPAItem struct {
Metadata ObjectMeta `json:"metadata"`
Spec HPASpec `json:"spec"`
Status HPAStatus `json:"status"`
Metadata ObjectMeta `json:"metadata"`
Spec HPASpec `json:"spec"`
Status HPAStatus `json:"status"`
}
// HPASpec defines the HPA spec
@@ -885,7 +917,7 @@ type ScaleTargetRef struct {
// HPAMetric defines a metric for HPA
type HPAMetric struct {
Type string `json:"type"`
Type string `json:"type"`
Resource *struct {
Name string `json:"name"`
Target struct {
@@ -914,12 +946,12 @@ func (c *Client) ListHPAs() (*HPAList, error) {
type CreateHPARequest struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
TargetKind string `json:"targetKind"` // Deployment, StatefulSet
TargetKind string `json:"targetKind"` // Deployment, StatefulSet
TargetName string `json:"targetName"`
MinReplicas int `json:"minReplicas"`
MaxReplicas int `json:"maxReplicas"`
CPUPercent int `json:"cpuPercent"` // target average CPU utilization
MemPercent int `json:"memPercent"` // target average memory utilization (0 = disabled)
CPUPercent int `json:"cpuPercent"` // target average CPU utilization
MemPercent int `json:"memPercent"` // target average memory utilization (0 = disabled)
}
// CreateHPA creates a new HPA
@@ -1004,9 +1036,9 @@ type CronJobList struct {
// CronJobItem represents a CronJob
type CronJobItem struct {
Metadata ObjectMeta `json:"metadata"`
Spec CronJobSpec `json:"spec"`
Status CronJobStatus `json:"status"`
Metadata ObjectMeta `json:"metadata"`
Spec CronJobSpec `json:"spec"`
Status CronJobStatus `json:"status"`
}
// CronJobSpec defines the CronJob spec
@@ -1042,10 +1074,10 @@ func (c *Client) ListCronJobs() (*CronJobList, error) {
// CreateCronJobRequest is the payload for creating a CronJob
type CreateCronJobRequest struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
Schedule string `json:"schedule"` // cron expression
Image string `json:"image"`
Name string `json:"name"`
Namespace string `json:"namespace"`
Schedule string `json:"schedule"` // cron expression
Image string `json:"image"`
Command []string `json:"command"`
}
@@ -1145,9 +1177,9 @@ func (c *Client) ListNamespaces() ([]string, error) {
// NamespaceItem holds full namespace metadata
type NamespaceItem struct {
Metadata ObjectMeta `json:"metadata"`
Spec NamespaceSpec `json:"spec"`
Status NamespaceStatus `json:"status"`
Metadata ObjectMeta `json:"metadata"`
Spec NamespaceSpec `json:"spec"`
Status NamespaceStatus `json:"status"`
}
// NamespaceSpec holds namespace spec
@@ -1209,15 +1241,15 @@ func (c *Client) DeleteNamespace(name string) error {
// ResourceQuotaItem represents a K8s ResourceQuota
type ResourceQuotaItem struct {
Metadata ObjectMeta `json:"metadata"`
Spec ResourceQuotaSpec `json:"spec"`
Status ResourceQuotaStatus `json:"status"`
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"`
Hard map[string]string `json:"hard"`
Scopes []string `json:"scopes,omitempty"`
}
// ResourceQuotaStatus holds used/hard counts
@@ -1245,8 +1277,8 @@ func (c *Client) ListResourceQuotas(namespace string) ([]ResourceQuotaItem, erro
// LimitRangeItem represents a K8s LimitRange
type LimitRangeItem struct {
Metadata ObjectMeta `json:"metadata"`
Spec LimitRangeSpec `json:"spec"`
Metadata ObjectMeta `json:"metadata"`
Spec LimitRangeSpec `json:"spec"`
}
// LimitRangeSpec holds limit items
@@ -1303,17 +1335,17 @@ type SecretList struct {
// SecretItem represents a Secret (return keys only, not values)
type SecretItem struct {
Metadata ObjectMeta `json:"metadata"`
Type string `json:"type"`
DataKeys []string `json:"-"`
Metadata ObjectMeta `json:"metadata"`
Type string `json:"type"`
DataKeys []string `json:"-"`
}
// ListSecrets fetches Secrets in a namespace (names+types only, no data)
func (c *Client) ListSecrets(namespace string) (*SecretList, error) {
var result struct {
Items []struct {
Metadata ObjectMeta `json:"metadata"`
Type string `json:"type"`
Metadata ObjectMeta `json:"metadata"`
Type string `json:"type"`
Data map[string]string `json:"data"`
} `json:"items"`
}
@@ -1348,14 +1380,14 @@ type PVCItem struct {
Metadata ObjectMeta `json:"metadata"`
Spec PVCSpec `json:"spec"`
Status struct {
Phase string `json:"phase"`
Capacity map[string]string `json:"capacity"`
Phase string `json:"phase"`
Capacity map[string]string `json:"capacity"`
} `json:"status"`
}
type PVCSpec struct {
AccessModes []string `json:"accessModes"`
Resources struct {
AccessModes []string `json:"accessModes"`
Resources struct {
Requests map[string]string `json:"requests"`
} `json:"resources"`
StorageClassName string `json:"storageClassName"`
@@ -1386,16 +1418,16 @@ type StatefulSetList struct {
}
type StatefulSetItem struct {
Metadata ObjectMeta `json:"metadata"`
Spec StatefulSetSpec `json:"spec"`
Metadata ObjectMeta `json:"metadata"`
Spec StatefulSetSpec `json:"spec"`
Status struct {
Replicas int `json:"replicas"`
ReadyReplicas int `json:"readyReplicas"`
Replicas int `json:"replicas"`
ReadyReplicas int `json:"readyReplicas"`
} `json:"status"`
}
type StatefulSetSpec struct {
Replicas int `json:"replicas"`
Replicas int `json:"replicas"`
Template struct {
Spec struct {
Containers []struct {
@@ -1424,8 +1456,8 @@ type DaemonSetList struct {
}
type DaemonSetItem struct {
Metadata ObjectMeta `json:"metadata"`
Spec DaemonSetSpec `json:"spec"`
Metadata ObjectMeta `json:"metadata"`
Spec DaemonSetSpec `json:"spec"`
Status struct {
DesiredNumberScheduled int `json:"desiredNumberScheduled"`
CurrentNumberScheduled int `json:"currentNumberScheduled"`
@@ -1589,18 +1621,18 @@ type EventSource struct {
}
type EventItem struct {
Metadata ObjectMeta `json:"metadata"`
InvolvedObject InvolvedObject `json:"involvedObject"`
Type string `json:"type"`
Reason string `json:"reason"`
Message string `json:"message"`
Source EventSource `json:"source"`
ReportingComponent string `json:"reportingComponent"`
ReportingInstance string `json:"reportingInstance"`
Count int32 `json:"count"`
FirstTimestamp time.Time `json:"firstTimestamp"`
LastTimestamp time.Time `json:"lastTimestamp"`
EventTime time.Time `json:"eventTime"`
Metadata ObjectMeta `json:"metadata"`
InvolvedObject InvolvedObject `json:"involvedObject"`
Type string `json:"type"`
Reason string `json:"reason"`
Message string `json:"message"`
Source EventSource `json:"source"`
ReportingComponent string `json:"reportingComponent"`
ReportingInstance string `json:"reportingInstance"`
Count int32 `json:"count"`
FirstTimestamp time.Time `json:"firstTimestamp"`
LastTimestamp time.Time `json:"lastTimestamp"`
EventTime time.Time `json:"eventTime"`
}
type InvolvedObject struct {
@@ -1673,7 +1705,7 @@ type RoleList struct {
}
type RoleItem struct {
Metadata ObjectMeta `json:"metadata"`
Metadata ObjectMeta `json:"metadata"`
Rules []PolicyRule `json:"rules"`
}
@@ -1700,9 +1732,9 @@ type RoleBindingList struct {
}
type RoleBindingItem struct {
Metadata ObjectMeta `json:"metadata"`
RoleRef RoleRef `json:"roleRef"`
Subjects []Subject `json:"subjects"`
Metadata ObjectMeta `json:"metadata"`
RoleRef RoleRef `json:"roleRef"`
Subjects []Subject `json:"subjects"`
}
type RoleRef struct {
@@ -1775,7 +1807,7 @@ func (c *Client) applyRaw(yamlContent string) (map[string]interface{}, error) {
}
// Try GET first — if 200, it exists, do PUT. If 404, do POST.
parentPath := apiPath[:strings.LastIndex(apiPath, "/")] // without /name suffix
parentPath := apiPath[:strings.LastIndex(apiPath, "/")] // without /name suffix
_, getErr := c.getRaw(apiPath, "application/yaml")
if getErr == nil {
// Resource exists → PUT update
@@ -1801,8 +1833,10 @@ func (c *Client) applyRaw(yamlContent string) (map[string]interface{}, error) {
func (c *Client) resourceAPIPath(apiVersion, kind, namespace, name string) (string, bool) {
resource := strings.ToLower(kind) + "s"
switch kind {
case "Endpoints": resource = "endpoints"
case "PodMetrics": resource = "pods"
case "Endpoints":
resource = "endpoints"
case "PodMetrics":
resource = "pods"
}
var groupPrefix string
@@ -1829,7 +1863,9 @@ func (c *Client) resourceAPIPath(apiVersion, kind, namespace, name string) (stri
}
ns := namespace
if ns == "" { ns = "default" }
if ns == "" {
ns = "default"
}
if groupPrefix != "" {
switch kind {
@@ -1866,15 +1902,15 @@ type ReplicaSetList struct {
// ReplicaSetItem 表示一个 ReplicaSet(含完整 spec/status/metadata,用于回滚取 template)
type ReplicaSetItem struct {
Metadata ObjectMeta `json:"metadata"`
Spec ReplicaSetSpec `json:"spec"`
Status ReplicaSetStatus `json:"status"`
Metadata ObjectMeta `json:"metadata"`
Spec ReplicaSetSpec `json:"spec"`
Status ReplicaSetStatus `json:"status"`
}
// ReplicaSetSpec 与 DeploymentSpec 结构一致,关键是 template
type ReplicaSetSpec struct {
Replicas int `json:"replicas"`
Template ReplicaSetTemplate `json:"template"`
Replicas int `json:"replicas"`
Template ReplicaSetTemplate `json:"template"`
}
// ReplicaSetTemplate pod 模板