working on system management
This commit is contained in:
@@ -175,3 +175,173 @@ func (s *Service) GenerateSupportBundle(ctx context.Context, outputPath string)
|
||||
return nil
|
||||
}
|
||||
|
||||
// NetworkInterface represents a network interface
|
||||
type NetworkInterface struct {
|
||||
Name string `json:"name"`
|
||||
IPAddress string `json:"ip_address"`
|
||||
Subnet string `json:"subnet"`
|
||||
Status string `json:"status"` // "Connected" or "Down"
|
||||
Speed string `json:"speed"` // e.g., "10 Gbps", "1 Gbps"
|
||||
Role string `json:"role"` // "Management", "ISCSI", or empty
|
||||
}
|
||||
|
||||
// ListNetworkInterfaces lists all network interfaces
|
||||
func (s *Service) ListNetworkInterfaces(ctx context.Context) ([]NetworkInterface, error) {
|
||||
// First, get all interface names and their states
|
||||
cmd := exec.CommandContext(ctx, "ip", "link", "show")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to list interfaces", "error", err)
|
||||
return nil, fmt.Errorf("failed to list interfaces: %w", err)
|
||||
}
|
||||
|
||||
interfaceMap := make(map[string]*NetworkInterface)
|
||||
lines := strings.Split(string(output), "\n")
|
||||
|
||||
s.logger.Debug("Parsing network interfaces", "output_lines", len(lines))
|
||||
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Parse interface name and state
|
||||
// Format: "2: ens18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000"
|
||||
// Look for lines that start with a number followed by ":" (interface definition line)
|
||||
// Simple check: line starts with digit, contains ":", and contains "state"
|
||||
if len(line) > 0 && line[0] >= '0' && line[0] <= '9' && strings.Contains(line, ":") && strings.Contains(line, "state") {
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Extract interface name (e.g., "ens18:" or "lo:")
|
||||
ifaceName := strings.TrimSuffix(parts[1], ":")
|
||||
if ifaceName == "" || ifaceName == "lo" {
|
||||
continue // Skip loopback
|
||||
}
|
||||
|
||||
// Extract state - look for "state UP" or "state DOWN" in the line
|
||||
state := "Down"
|
||||
if strings.Contains(line, "state UP") {
|
||||
state = "Connected"
|
||||
} else if strings.Contains(line, "state DOWN") {
|
||||
state = "Down"
|
||||
}
|
||||
|
||||
s.logger.Info("Found interface", "name", ifaceName, "state", state)
|
||||
|
||||
interfaceMap[ifaceName] = &NetworkInterface{
|
||||
Name: ifaceName,
|
||||
Status: state,
|
||||
Speed: "Unknown",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s.logger.Debug("Found interfaces from ip link", "count", len(interfaceMap))
|
||||
|
||||
// Get IP addresses for each interface
|
||||
cmd = exec.CommandContext(ctx, "ip", "-4", "addr", "show")
|
||||
output, err = cmd.Output()
|
||||
if err != nil {
|
||||
s.logger.Warn("Failed to get IP addresses", "error", err)
|
||||
} else {
|
||||
lines = strings.Split(string(output), "\n")
|
||||
var currentIfaceName string
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Parse interface name (e.g., "2: ens18: <BROADCAST,MULTICAST,UP,LOWER_UP>")
|
||||
if strings.Contains(line, ":") && !strings.Contains(line, "inet") && !strings.HasPrefix(line, "valid_lft") && !strings.HasPrefix(line, "altname") {
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) >= 2 {
|
||||
currentIfaceName = strings.TrimSuffix(parts[1], ":")
|
||||
s.logger.Debug("Processing interface for IP", "name", currentIfaceName)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Parse IP address (e.g., "inet 10.10.14.16/24 brd 10.10.14.255 scope global ens18")
|
||||
if strings.HasPrefix(line, "inet ") && currentIfaceName != "" && currentIfaceName != "lo" {
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) >= 2 {
|
||||
ipWithSubnet := parts[1] // e.g., "10.10.14.16/24"
|
||||
ipParts := strings.Split(ipWithSubnet, "/")
|
||||
if len(ipParts) == 2 {
|
||||
ip := ipParts[0]
|
||||
subnet := ipParts[1]
|
||||
|
||||
// Find or create interface
|
||||
iface, exists := interfaceMap[currentIfaceName]
|
||||
if !exists {
|
||||
s.logger.Debug("Creating new interface entry", "name", currentIfaceName)
|
||||
iface = &NetworkInterface{
|
||||
Name: currentIfaceName,
|
||||
Status: "Down",
|
||||
Speed: "Unknown",
|
||||
}
|
||||
interfaceMap[currentIfaceName] = iface
|
||||
}
|
||||
|
||||
iface.IPAddress = ip
|
||||
iface.Subnet = subnet
|
||||
s.logger.Debug("Set IP for interface", "name", currentIfaceName, "ip", ip, "subnet", subnet)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert map to slice
|
||||
var interfaces []NetworkInterface
|
||||
s.logger.Debug("Converting interface map to slice", "map_size", len(interfaceMap))
|
||||
for _, iface := range interfaceMap {
|
||||
// Get speed for each interface using ethtool
|
||||
if iface.Name != "" && iface.Name != "lo" {
|
||||
cmd := exec.CommandContext(ctx, "ethtool", iface.Name)
|
||||
output, err := cmd.Output()
|
||||
if err == nil {
|
||||
// Parse speed from ethtool output
|
||||
ethtoolLines := strings.Split(string(output), "\n")
|
||||
for _, ethtoolLine := range ethtoolLines {
|
||||
if strings.Contains(ethtoolLine, "Speed:") {
|
||||
parts := strings.Fields(ethtoolLine)
|
||||
if len(parts) >= 2 {
|
||||
iface.Speed = parts[1]
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determine role based on interface name or IP (simple heuristic)
|
||||
// You can enhance this with configuration file or database lookup
|
||||
if strings.Contains(iface.Name, "eth") || strings.Contains(iface.Name, "ens") {
|
||||
// Default to Management for first interface, ISCSI for others
|
||||
if iface.Name == "eth0" || iface.Name == "ens18" {
|
||||
iface.Role = "Management"
|
||||
} else {
|
||||
// Check if IP is in typical iSCSI range (10.x.x.x)
|
||||
if strings.HasPrefix(iface.IPAddress, "10.") && iface.IPAddress != "" {
|
||||
iface.Role = "ISCSI"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
interfaces = append(interfaces, *iface)
|
||||
}
|
||||
|
||||
// If no interfaces found, return empty slice
|
||||
if len(interfaces) == 0 {
|
||||
s.logger.Warn("No network interfaces found")
|
||||
return []NetworkInterface{}, nil
|
||||
}
|
||||
|
||||
s.logger.Info("Listed network interfaces", "count", len(interfaces))
|
||||
return interfaces, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user