mirror of
https://github.com/portainer/portainer.git
synced 2026-06-23 04:10:29 +00:00
feat(policies): define ObservabilityK8s policy type with deploy-and-connect and connect-only modes [C9S-121] (#2706)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -838,6 +838,7 @@ type (
|
||||
NodeCount int `json:"NodeCount" validate:"required"`
|
||||
TotalCPU int64 `json:"TotalCPU" validate:"required"`
|
||||
TotalMemory int64 `json:"TotalMemory" validate:"required"`
|
||||
ClusterType string `json:"ClusterType,omitempty"`
|
||||
DiagnosticsData *DiagnosticsData `json:"DiagnosticsData,omitempty"`
|
||||
PerformanceMetrics *PerformanceMetrics `json:"PerformanceMetrics,omitempty"`
|
||||
}
|
||||
@@ -2641,6 +2642,7 @@ const (
|
||||
RegistryDocker PolicyType = "registry-docker"
|
||||
ChangeConfirmation PolicyType = "change-confirmation"
|
||||
CleanupDocker PolicyType = "cleanup-docker"
|
||||
ObservabilityK8s PolicyType = "observability-k8s"
|
||||
)
|
||||
|
||||
type HelmInstallStatus string
|
||||
|
||||
@@ -66,10 +66,39 @@ func kubernetesSnapshotNodes(snapshot *portainer.KubernetesSnapshot, cli kuberne
|
||||
snapshot.TotalCPU = totalCPUs
|
||||
snapshot.TotalMemory = totalMemory
|
||||
snapshot.NodeCount = len(nodeList.Items)
|
||||
snapshot.ClusterType = clusterTypeFromProviderID(nodeList.Items[0].Spec.ProviderID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
ClusterTypeGKEAutopilot = "gke-autopilot"
|
||||
ClusterTypeEKSFargate = "eks-fargate"
|
||||
ClusterTypeAKS = "aks"
|
||||
ClusterTypeUnknown = ""
|
||||
)
|
||||
|
||||
func clusterTypeFromProviderID(providerID string) string {
|
||||
switch {
|
||||
case strings.HasPrefix(providerID, "gce://") && isGKEAutopilotProviderID(providerID):
|
||||
return ClusterTypeGKEAutopilot
|
||||
case strings.HasPrefix(providerID, "aws://") && strings.Contains(strings.ToLower(providerID), "fargate"):
|
||||
return ClusterTypeEKSFargate
|
||||
case strings.HasPrefix(providerID, "azure://"):
|
||||
return ClusterTypeAKS
|
||||
default:
|
||||
return ClusterTypeUnknown
|
||||
}
|
||||
}
|
||||
|
||||
// isGKEAutopilotProviderID detects GKE Autopilot via the gk3- node-name prefix.
|
||||
// ProviderID format: gce://PROJECT/REGION/NODE-NAME
|
||||
// Autopilot nodes: gk3-CLUSTER-POOL-SUFFIX; Standard nodes: gke-CLUSTER-POOL-SUFFIX
|
||||
func isGKEAutopilotProviderID(providerID string) bool {
|
||||
parts := strings.Split(providerID, "/")
|
||||
return len(parts) > 0 && strings.HasPrefix(parts[len(parts)-1], "gk3-")
|
||||
}
|
||||
|
||||
// KubernetesSnapshotDiagnostics returns the diagnostics data for the agent
|
||||
func KubernetesSnapshotDiagnostics(cli *kubernetes.Clientset, edgeKey string) (*portainer.DiagnosticsData, error) {
|
||||
podID := os.Getenv("HOSTNAME")
|
||||
|
||||
@@ -15,6 +15,29 @@ import (
|
||||
ktesting "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
func TestClusterTypeFromProviderID(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
providerID string
|
||||
expected string
|
||||
}{
|
||||
{"gce://my-project/us-central1/gk3-my-cluster-pool-abc123", ClusterTypeGKEAutopilot},
|
||||
{"gce://my-project/us-central1/gke-my-cluster-pool-abc123", ClusterTypeUnknown},
|
||||
{"aws:///us-east-1/fargate-12345", ClusterTypeEKSFargate},
|
||||
{"aws:///us-east-1/i-1234567890abcdef0", ClusterTypeUnknown},
|
||||
{"azure:///subscriptions/x/resourceGroups/y/providers/Microsoft.Compute/virtualMachines/NODE", ClusterTypeAKS},
|
||||
{"", ClusterTypeUnknown},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.providerID, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
require.Equal(t, tt.expected, clusterTypeFromProviderID(tt.providerID))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestKubernetesSnapshotNodes(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Create a fake client
|
||||
@@ -25,6 +48,9 @@ func TestKubernetesSnapshotNodes(t *testing.T) {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-node-1",
|
||||
},
|
||||
Spec: corev1.NodeSpec{
|
||||
ProviderID: "gce://my-project/us-central1/gk3-my-cluster-pool-abc123",
|
||||
},
|
||||
Status: corev1.NodeStatus{
|
||||
Capacity: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse("6"), // 6 CPU cores
|
||||
@@ -72,10 +98,11 @@ func TestKubernetesSnapshotNodes(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify the results - these should match what kubernetesSnapshotNodes would produce
|
||||
require.Equal(t, 3, snapshot.NodeCount) // 3 nodes
|
||||
require.Equal(t, int64(12), snapshot.TotalCPU) // 6 + 4 + 2 = 12 CPUs
|
||||
require.Equal(t, int64(25769803776), snapshot.TotalMemory) // 12GB + 8GB + 4GB = 24GB in bytes
|
||||
require.Nil(t, snapshot.PerformanceMetrics) // Performance metrics are no longer collected server-side
|
||||
require.Equal(t, 3, snapshot.NodeCount) // 3 nodes
|
||||
require.Equal(t, int64(12), snapshot.TotalCPU) // 6 + 4 + 2 = 12 CPUs
|
||||
require.Equal(t, int64(25769803776), snapshot.TotalMemory) // 12GB + 8GB + 4GB = 24GB in bytes
|
||||
require.Equal(t, ClusterTypeGKEAutopilot, snapshot.ClusterType) // detected from node1's ProviderID
|
||||
require.Nil(t, snapshot.PerformanceMetrics) // Performance metrics are no longer collected server-side
|
||||
|
||||
t.Logf("kubernetesSnapshotNodes test result: Nodes=%d, CPUs=%d, Memory=%d bytes",
|
||||
snapshot.NodeCount, snapshot.TotalCPU, snapshot.TotalMemory)
|
||||
@@ -94,6 +121,7 @@ func TestKubernetesSnapshotNodesEmptyCluster(t *testing.T) {
|
||||
require.Equal(t, 0, snapshot.NodeCount)
|
||||
require.Equal(t, int64(0), snapshot.TotalCPU)
|
||||
require.Equal(t, int64(0), snapshot.TotalMemory)
|
||||
require.Equal(t, ClusterTypeUnknown, snapshot.ClusterType)
|
||||
require.Nil(t, snapshot.PerformanceMetrics) // Performance metrics should not be set for empty cluster
|
||||
|
||||
t.Log("Empty cluster test passed - no nodes found, early return behavior confirmed")
|
||||
|
||||
Reference in New Issue
Block a user