You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							311 lines
						
					
					
						
							7.8 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							311 lines
						
					
					
						
							7.8 KiB
						
					
					
				
								package main
							 | 
						|
								
							 | 
						|
								import (
							 | 
						|
									"context"
							 | 
						|
									"fmt"
							 | 
						|
									"io"
							 | 
						|
									"log"
							 | 
						|
									"net/http"
							 | 
						|
									"os"
							 | 
						|
									"os/exec"
							 | 
						|
									"path/filepath"
							 | 
						|
									"strings"
							 | 
						|
									"syscall"
							 | 
						|
									"time"
							 | 
						|
								
							 | 
						|
									"github.com/seaweedfs/seaweedfs/telemetry/proto"
							 | 
						|
									"github.com/seaweedfs/seaweedfs/weed/telemetry"
							 | 
						|
									protobuf "google.golang.org/protobuf/proto"
							 | 
						|
								)
							 | 
						|
								
							 | 
						|
								const (
							 | 
						|
									serverPort = "18080" // Use different port to avoid conflicts
							 | 
						|
									serverURL  = "http://localhost:" + serverPort
							 | 
						|
								)
							 | 
						|
								
							 | 
						|
								func main() {
							 | 
						|
									fmt.Println("Starting SeaweedFS Telemetry Integration Test")
							 | 
						|
								
							 | 
						|
									// Start telemetry server
							 | 
						|
									fmt.Println("Starting telemetry server...")
							 | 
						|
									serverCmd, err := startTelemetryServer()
							 | 
						|
									if err != nil {
							 | 
						|
										log.Fatalf("Failed to start telemetry server: %v", err)
							 | 
						|
									}
							 | 
						|
									defer stopServer(serverCmd)
							 | 
						|
								
							 | 
						|
									// Wait for server to start
							 | 
						|
									if !waitForServer(serverURL+"/health", 15*time.Second) {
							 | 
						|
										log.Fatal("Telemetry server failed to start")
							 | 
						|
									}
							 | 
						|
									fmt.Println("Telemetry server started successfully")
							 | 
						|
								
							 | 
						|
									// Test protobuf marshaling first
							 | 
						|
									fmt.Println("Testing protobuf marshaling...")
							 | 
						|
									if err := testProtobufMarshaling(); err != nil {
							 | 
						|
										log.Fatalf("Protobuf marshaling test failed: %v", err)
							 | 
						|
									}
							 | 
						|
									fmt.Println("Protobuf marshaling test passed")
							 | 
						|
								
							 | 
						|
									// Test protobuf client
							 | 
						|
									fmt.Println("Testing protobuf telemetry client...")
							 | 
						|
									if err := testTelemetryClient(); err != nil {
							 | 
						|
										log.Fatalf("Telemetry client test failed: %v", err)
							 | 
						|
									}
							 | 
						|
									fmt.Println("Telemetry client test passed")
							 | 
						|
								
							 | 
						|
									// Test server metrics endpoint
							 | 
						|
									fmt.Println("Testing Prometheus metrics endpoint...")
							 | 
						|
									if err := testMetricsEndpoint(); err != nil {
							 | 
						|
										log.Fatalf("Metrics endpoint test failed: %v", err)
							 | 
						|
									}
							 | 
						|
									fmt.Println("Metrics endpoint test passed")
							 | 
						|
								
							 | 
						|
									// Test stats API
							 | 
						|
									fmt.Println("Testing stats API...")
							 | 
						|
									if err := testStatsAPI(); err != nil {
							 | 
						|
										log.Fatalf("Stats API test failed: %v", err)
							 | 
						|
									}
							 | 
						|
									fmt.Println("Stats API test passed")
							 | 
						|
								
							 | 
						|
									// Test instances API
							 | 
						|
									fmt.Println("Testing instances API...")
							 | 
						|
									if err := testInstancesAPI(); err != nil {
							 | 
						|
										log.Fatalf("Instances API test failed: %v", err)
							 | 
						|
									}
							 | 
						|
									fmt.Println("Instances API test passed")
							 | 
						|
								
							 | 
						|
									fmt.Println("All telemetry integration tests passed!")
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func startTelemetryServer() (*exec.Cmd, error) {
							 | 
						|
									// Get the directory where this test is running
							 | 
						|
									testDir, err := os.Getwd()
							 | 
						|
									if err != nil {
							 | 
						|
										return nil, fmt.Errorf("failed to get working directory: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Navigate to the server directory (from main seaweedfs directory)
							 | 
						|
									serverDir := filepath.Join(testDir, "telemetry", "server")
							 | 
						|
								
							 | 
						|
									cmd := exec.Command("go", "run", ".",
							 | 
						|
										"-port="+serverPort,
							 | 
						|
										"-dashboard=false",
							 | 
						|
										"-cleanup=1m",
							 | 
						|
										"-max-age=1h")
							 | 
						|
								
							 | 
						|
									cmd.Dir = serverDir
							 | 
						|
								
							 | 
						|
									// Create log files for server output
							 | 
						|
									logFile, err := os.Create("telemetry-server-test.log")
							 | 
						|
									if err != nil {
							 | 
						|
										return nil, fmt.Errorf("failed to create log file: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									cmd.Stdout = logFile
							 | 
						|
									cmd.Stderr = logFile
							 | 
						|
								
							 | 
						|
									if err := cmd.Start(); err != nil {
							 | 
						|
										return nil, fmt.Errorf("failed to start server: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									return cmd, nil
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func stopServer(cmd *exec.Cmd) {
							 | 
						|
									if cmd != nil && cmd.Process != nil {
							 | 
						|
										cmd.Process.Signal(syscall.SIGTERM)
							 | 
						|
										cmd.Wait()
							 | 
						|
								
							 | 
						|
										// Clean up log file
							 | 
						|
										os.Remove("telemetry-server-test.log")
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func waitForServer(url string, timeout time.Duration) bool {
							 | 
						|
									ctx, cancel := context.WithTimeout(context.Background(), timeout)
							 | 
						|
									defer cancel()
							 | 
						|
								
							 | 
						|
									fmt.Printf("Waiting for server at %s...\n", url)
							 | 
						|
								
							 | 
						|
									for {
							 | 
						|
										select {
							 | 
						|
										case <-ctx.Done():
							 | 
						|
											return false
							 | 
						|
										default:
							 | 
						|
											resp, err := http.Get(url)
							 | 
						|
											if err == nil {
							 | 
						|
												resp.Body.Close()
							 | 
						|
												if resp.StatusCode == http.StatusOK {
							 | 
						|
													return true
							 | 
						|
												}
							 | 
						|
											}
							 | 
						|
											time.Sleep(500 * time.Millisecond)
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func testProtobufMarshaling() error {
							 | 
						|
									// Test protobuf marshaling/unmarshaling
							 | 
						|
									testData := &proto.TelemetryData{
							 | 
						|
										ClusterId:         "test-cluster-12345",
							 | 
						|
										Version:           "test-3.45",
							 | 
						|
										Os:                "linux/amd64",
							 | 
						|
										VolumeServerCount: 2,
							 | 
						|
										TotalDiskBytes:    1000000,
							 | 
						|
										TotalVolumeCount:  10,
							 | 
						|
										FilerCount:        1,
							 | 
						|
										BrokerCount:       1,
							 | 
						|
										Timestamp:         time.Now().Unix(),
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Marshal
							 | 
						|
									data, err := protobuf.Marshal(testData)
							 | 
						|
									if err != nil {
							 | 
						|
										return fmt.Errorf("failed to marshal protobuf: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									fmt.Printf("   Protobuf size: %d bytes\n", len(data))
							 | 
						|
								
							 | 
						|
									// Unmarshal
							 | 
						|
									testData2 := &proto.TelemetryData{}
							 | 
						|
									if err := protobuf.Unmarshal(data, testData2); err != nil {
							 | 
						|
										return fmt.Errorf("failed to unmarshal protobuf: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Verify data
							 | 
						|
									if testData2.ClusterId != testData.ClusterId {
							 | 
						|
										return fmt.Errorf("protobuf data mismatch: expected %s, got %s",
							 | 
						|
											testData.ClusterId, testData2.ClusterId)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if testData2.VolumeServerCount != testData.VolumeServerCount {
							 | 
						|
										return fmt.Errorf("volume server count mismatch: expected %d, got %d",
							 | 
						|
											testData.VolumeServerCount, testData2.VolumeServerCount)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									return nil
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func testTelemetryClient() error {
							 | 
						|
									// Create telemetry client
							 | 
						|
									client := telemetry.NewClient(serverURL+"/api/collect", true)
							 | 
						|
								
							 | 
						|
									// Create test data using protobuf format
							 | 
						|
									testData := &proto.TelemetryData{
							 | 
						|
										Version:           "test-3.45",
							 | 
						|
										Os:                "linux/amd64",
							 | 
						|
										VolumeServerCount: 3,
							 | 
						|
										TotalDiskBytes:    1073741824, // 1GB
							 | 
						|
										TotalVolumeCount:  50,
							 | 
						|
										FilerCount:        2,
							 | 
						|
										BrokerCount:       1,
							 | 
						|
										Timestamp:         time.Now().Unix(),
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Send telemetry data
							 | 
						|
									if err := client.SendTelemetry(testData); err != nil {
							 | 
						|
										return fmt.Errorf("failed to send telemetry: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									fmt.Printf("   Sent telemetry for cluster: %s\n", client.GetInstanceID())
							 | 
						|
								
							 | 
						|
									// Wait a bit for processing
							 | 
						|
									time.Sleep(2 * time.Second)
							 | 
						|
								
							 | 
						|
									return nil
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func testMetricsEndpoint() error {
							 | 
						|
									resp, err := http.Get(serverURL + "/metrics")
							 | 
						|
									if err != nil {
							 | 
						|
										return fmt.Errorf("failed to get metrics: %v", err)
							 | 
						|
									}
							 | 
						|
									defer resp.Body.Close()
							 | 
						|
								
							 | 
						|
									if resp.StatusCode != http.StatusOK {
							 | 
						|
										return fmt.Errorf("metrics endpoint returned status %d", resp.StatusCode)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Read response and check for expected metrics
							 | 
						|
									content, err := io.ReadAll(resp.Body)
							 | 
						|
									if err != nil {
							 | 
						|
										return fmt.Errorf("failed to read metrics response: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									contentStr := string(content)
							 | 
						|
									expectedMetrics := []string{
							 | 
						|
										"seaweedfs_telemetry_total_clusters",
							 | 
						|
										"seaweedfs_telemetry_active_clusters",
							 | 
						|
										"seaweedfs_telemetry_reports_received_total",
							 | 
						|
										"seaweedfs_telemetry_volume_servers",
							 | 
						|
										"seaweedfs_telemetry_disk_bytes",
							 | 
						|
										"seaweedfs_telemetry_volume_count",
							 | 
						|
										"seaweedfs_telemetry_filer_count",
							 | 
						|
										"seaweedfs_telemetry_broker_count",
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									for _, metric := range expectedMetrics {
							 | 
						|
										if !strings.Contains(contentStr, metric) {
							 | 
						|
											return fmt.Errorf("missing expected metric: %s", metric)
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Check that we have at least one report received
							 | 
						|
									if !strings.Contains(contentStr, "seaweedfs_telemetry_reports_received_total 1") {
							 | 
						|
										fmt.Printf("   Warning: Expected at least 1 report received, metrics content:\n%s\n", contentStr)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									fmt.Printf("   Found %d expected metrics\n", len(expectedMetrics))
							 | 
						|
								
							 | 
						|
									return nil
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func testStatsAPI() error {
							 | 
						|
									resp, err := http.Get(serverURL + "/api/stats")
							 | 
						|
									if err != nil {
							 | 
						|
										return fmt.Errorf("failed to get stats: %v", err)
							 | 
						|
									}
							 | 
						|
									defer resp.Body.Close()
							 | 
						|
								
							 | 
						|
									if resp.StatusCode != http.StatusOK {
							 | 
						|
										return fmt.Errorf("stats API returned status %d", resp.StatusCode)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Read and verify JSON response
							 | 
						|
									content, err := io.ReadAll(resp.Body)
							 | 
						|
									if err != nil {
							 | 
						|
										return fmt.Errorf("failed to read stats response: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									contentStr := string(content)
							 | 
						|
									if !strings.Contains(contentStr, "total_instances") {
							 | 
						|
										return fmt.Errorf("stats response missing total_instances field")
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									fmt.Printf("   Stats response: %s\n", contentStr)
							 | 
						|
								
							 | 
						|
									return nil
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func testInstancesAPI() error {
							 | 
						|
									resp, err := http.Get(serverURL + "/api/instances?limit=10")
							 | 
						|
									if err != nil {
							 | 
						|
										return fmt.Errorf("failed to get instances: %v", err)
							 | 
						|
									}
							 | 
						|
									defer resp.Body.Close()
							 | 
						|
								
							 | 
						|
									if resp.StatusCode != http.StatusOK {
							 | 
						|
										return fmt.Errorf("instances API returned status %d", resp.StatusCode)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Read response
							 | 
						|
									content, err := io.ReadAll(resp.Body)
							 | 
						|
									if err != nil {
							 | 
						|
										return fmt.Errorf("failed to read instances response: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									fmt.Printf("   Instances response length: %d bytes\n", len(content))
							 | 
						|
								
							 | 
						|
									return nil
							 | 
						|
								}
							 |