package main import ( // "bufio" // "fmt" // "io/ioutil" "bufio" "bytes" "encoding/json" "fmt" "log" "net" "net/http" "os" "os/exec" "regexp" "strconv" "strings" "syscall" ) // ОС серверов Платформа и Локации // (источник ОС) // - Серверная платформа // dmidecode -t system func dmidecodeTSystem() (biosInfo, error) { var biosInfo biosInfo // нужно получить информацию из bios // cat /sys/firmware/dmi/entries/1-0/raw bi, err := os.ReadFile("/sys/firmware/dmi/entries/1-0/raw") if err != nil { err = fmt.Errorf("Ошибка получения dmi данных: %s", err) } biosInfo.Name = string(bi) return biosInfo, nil } // - Операционная система // cat /etc/os-release // cat /etc/astra_version // cat /etc/astra_license func getOs() (operatingSystem, []error) { var opsys operatingSystem var errors []error fOsInfo, err := os.ReadFile("/etc/os-release") if err != nil { err = fmt.Errorf("Ошибка чтения os-release: %s", err) errors = append(errors, err) } else { osInfoSpl := strings.Split(string(fOsInfo), "\n") for _, r := range osInfoSpl { capt, _ := regexp.MatchString("PRETTY_NAME*", r) if capt { opsys.OsRelease = strings.Split(r, "=")[1] break } } } _, err = os.Stat("/etc/astra_version") if err != nil { err = fmt.Errorf("ошибка чтения asrta_version") errors = append(errors, err) } else { } return opsys, errors } // - Пакеты // apt list --installed func getDebPackages() ([]installedPackage, error) { // читаем /var/lib/dpkg/status var debPackages []installedPackage b_dpkgStatus, err := os.ReadFile("/var/lib/dpkg/status") if err != nil { err = fmt.Errorf("Ошибка чтения файла /var/lib/dpkg/status: %s", err) return nil, err } dpkgStatus := strings.Split(string(b_dpkgStatus), "\n\n") for _, ds := range dpkgStatus { var debPackage installedPackage if len(ds) == 0 { continue } ds_s := strings.Split(ds, "\n") for _, d := range ds_s { if strings.Contains(d, "Package: ") { debPackage.Name = strings.Split(d, ": ")[1] } if strings.Contains(d, "Version: ") { debPackage.Version = strings.Split(d, ": ")[1] } } debPackages = append(debPackages, debPackage) } return debPackages, err } func getRpmPackages() ([]installedPackage, error) { var rpmPackages []installedPackage cmd := exec.Command("rpm", "-qa", "--queryformat", "%{NAME};%{VERSION}\n") output, err := cmd.Output() if err != nil { err = fmt.Errorf("Ошибка выпонения команды rpm -qa: %s", err) return nil, err } scanner := bufio.NewScanner(strings.NewReader(string(output))) for scanner.Scan() { var instpack installedPackage line := scanner.Text() parts := strings.Split(line, ";") instpack.Name = parts[0] instpack.Version = parts[1] rpmPackages = append(rpmPackages, instpack) } return rpmPackages, err } // - Размер диска и объем свободного места на диске // lsblk // df // df -i func getFsInfo() ([]fsInfo, error) { var fsInfoList []fsInfo fProcMounts, err := os.ReadFile("/proc/mounts") if err != nil { err = fmt.Errorf("Ошибка чтения файла /proc/mounts : %s", err) return fsInfoList, err } for _, mp := range strings.Split(string(fProcMounts), "\n") { var fi fsInfo var sysStatfs syscall.Statfs_t if len(mp) == 0 { continue } mp_s := strings.Split(mp, " ") fi.MountPointDevice = mp_s[0] fi.MountPointOsPath = mp_s[1] err = syscall.Statfs(fi.MountPointOsPath, &sysStatfs) if err != nil { log.Println(err) } else { fi.MountPointSize = sysStatfs.Blocks * uint64(sysStatfs.Bsize) fi.MountPointFree = sysStatfs.Blocks * uint64(sysStatfs.Bfree) } fsInfoList = append(fsInfoList, fi) // fmt.Printf("Dev: %s Path: %s Size: %d Free: %d \n", fi.MountPointDevice, fi.MountPointOsPath, fi.MountPointSize, fi.MountPointFree) } return fsInfoList, err } // - LA // top -bn1 | head -n 1 // cat /proc/loadavg func getLa() (loadAverage, error) { var la loadAverage laFile, err := os.ReadFile("/proc/loadavg") if err != nil { err = fmt.Errorf("файл proc loadavg недоступен %s", err) return la, err } laFileSplit := strings.Split(string(laFile), " ") la.OneMin = laFileSplit[0] la.FiveMin = laFileSplit[1] la.FifteenMin = laFileSplit[2] la.Processes = laFileSplit[3] return la, nil } // - Процессор // cat /proc/cpuinfo // lscpu // func getCpu() (cpu, error) { // var cpu cpu // cpuFile, err := os.ReadFile("/proc/cpuinfo") // if err != nil { // err = fmt.Errorf("Проблема с доступом к файлу proc cpuinfo %s", err) // return cpu, err // } // prevCpu := " " // for _, line := range strings.Split(string(cpuFile), "\n") { // matched, err := regexp.Match("model name", []byte(line)) // if err != nil { // err = fmt.Errorf("Ошибка при оценке регулярного выражения %s", err) // return cpu, err // } // if matched { // cpuFound := strings.Split(line, ":")[1] // if cpuFound != prevCpu { // cpu.Model = append(cpu.Model, cpuFound) // prevCpu = cpuFound // } // } // } // return cpu, nil // } func getCpuinfo() ([]cpu, error) { var cpus []cpu var err error rawCpuinfo, err := os.ReadFile("/proc/cpuinfo") var c cpu var physId []string physId = append(physId, "a") for _, cpuLine := range strings.Split(string(rawCpuinfo), "\n") { if len(strings.TrimSpace(cpuLine)) == 0 { controlPoint := 0 for _, arrayIndex := range physId { if c.PhysicalId == "" { controlPoint = 1 } if arrayIndex == c.PhysicalId { controlPoint = 1 } } if controlPoint == 0 { cpus = append(cpus, c) physId = append(physId, c.PhysicalId) c = cpu{} } else { c = cpu{} } } else { if strings.Contains(cpuLine, "vendor_id") { c.VendorId = strings.TrimSpace(strings.Split(cpuLine, ":")[1]) } if strings.Contains(cpuLine, "cpu family") { c.CpuFamily = strings.TrimSpace(strings.Split(cpuLine, ":")[1]) } if strings.Contains(cpuLine, "model") && !strings.Contains(cpuLine, "name") { c.Model = strings.TrimSpace(strings.Split(cpuLine, ":")[1]) } if strings.Contains(cpuLine, "model name") { c.ModelName = strings.TrimSpace(strings.Split(cpuLine, ":")[1]) } if strings.Contains(cpuLine, "stepping") { c.Stepping = strings.TrimSpace(strings.Split(cpuLine, ":")[1]) } if strings.Contains(cpuLine, "microcode") { c.Microcode = strings.TrimSpace(strings.Split(cpuLine, ":")[1]) } if strings.Contains(cpuLine, "cpu MHz") { c.CpuMhz = strings.TrimSpace(strings.Split(cpuLine, ":")[1]) } if strings.Contains(cpuLine, "cache size") { c.CacheSize = strings.TrimSpace(strings.Split(cpuLine, ":")[1]) } if strings.Contains(cpuLine, "physical id") { c.PhysicalId = strings.TrimSpace(strings.Split(cpuLine, ":")[1]) } if strings.Contains(cpuLine, "cpu cores") { c.CpuCores = strings.TrimSpace(strings.Split(cpuLine, ":")[1]) } if strings.Contains(cpuLine, "flags") { c.Flags = strings.TrimSpace(strings.Split(cpuLine, ":")[1]) } if strings.Contains(cpuLine, "bugs") { c.Bugs = strings.TrimSpace(strings.Split(cpuLine, ":")[1]) } if strings.Contains(cpuLine, "bogomips") { c.Bogomips = strings.TrimSpace(strings.Split(cpuLine, ":")[1]) } if strings.Contains(cpuLine, "TLB size") { c.TlbSize = strings.TrimSpace(strings.Split(cpuLine, ":")[1]) } if strings.Contains(cpuLine, "clflush size") { c.ClflushSize = strings.TrimSpace(strings.Split(cpuLine, ":")[1]) } if strings.Contains(cpuLine, "cache_alignment") { c.CacheAlignment = strings.TrimSpace(strings.Split(cpuLine, ":")[1]) } if strings.Contains(cpuLine, "address size") { c.AddressSize = strings.TrimSpace(strings.Split(cpuLine, ":")[1]) } if strings.Contains(cpuLine, "power management") { c.PowerManagement = strings.TrimSpace(strings.Split(cpuLine, ":")[1]) } } } return cpus, err } // - Объём и тип ОЗУ, объём свободной памяти в моменте // vmstat -s // free // /proc/meminfo func getRam() (ram, error) { var ram ram ramFile, err := os.ReadFile("/proc/meminfo") if err != nil { err = fmt.Errorf("Проблема с доступом к файлу proc meminfo %s", err) return ram, err } for _, line := range strings.Split(string(ramFile), "\n") { matched, _ := regexp.Match("MemTotal", []byte(line)) if matched { ram.MemTotal = strings.Trim(strings.Split(line, ":")[1], " ") } matched, _ = regexp.Match("MemFree", []byte(line)) if matched { ram.MemFree = strings.Trim(strings.Split(line, ":")[1], " ") } matched, _ = regexp.Match("Available", []byte(line)) if matched { ram.MemAvailable = strings.Trim(strings.Split(line, ":")[1], " ") } } return ram, nil } // - Uptime сервера // uptime func getUptime() (uptime, error) { var uptime uptime uptimeFile, err := os.ReadFile("/proc/uptime") if err != nil { err = fmt.Errorf("Ошибка досутпа к файлу proc uptime: %s", err) return uptime, err } uptime.WorkSeconds = strings.Split(string(uptimeFile), " ")[0] return uptime, nil } // - NTP (nrp ntpsec chrony) // Запущен ли сервис, выполнялась ли синхронизация // date -R на всех серверах инфраструктуры func getTimeService() (timeService, []error) { var timeService timeService var errors []error cmd := exec.Command("timedatectl", "show", "--property=NTPSynchronized") output, err := cmd.Output() if err != nil { err = fmt.Errorf("Ошибка получения данных timedatectl: %s", err) errors = append(errors, err) err = nil } timeService.TimeSync = strings.Trim(strings.Split(string(output), "=")[1], "\n") dir, err := os.ReadDir("/run/systemd/units") if err != nil { err = fmt.Errorf("Ошибка при получении содержимого run systemd units : %s", err) errors = append(errors, err) err = nil } else { for _, entry := range dir { matchedChrony, _ := regexp.Match("chrony", []byte(entry.Name())) if matchedChrony { timeService.TimeService = strings.Split(entry.Name(), ":")[1] break } matchedNtp, _ := regexp.Match("ntp", []byte(entry.Name())) if matchedNtp { timeService.TimeService = strings.Split(entry.Name(), ":")[1] break } timeService.TimeService = "nothing" } } return timeService, errors } // - Стандартный сбор ошибок // journalctl -xe -p4 -o json-pretty // dmesg -T --level=err,warn // dmesg \| grep -i -E 'error\|failed\|critical\|bug\|panic' или dmesg --level=warn,err // journalctl \| grep -i -E 'error\|failed\|critical\|bug\|panic' или journalctl -xe -p 4 можно since "1 day ago" -o json-pretty // journalctl -xe -p 4 --since "1 day ago" -o json-pretty func getJournalctl() ([]journalctlEntry, error) { var jList []journalctlEntry cmd := exec.Command("journalctl", "-xe", "-p 4", "--since", "1 day ago", "-o", "json-pretty") output, err := cmd.Output() if err != nil { err = fmt.Errorf("Ошибка выполнения команды journalctl -xe -p 4 --since '5 minutes ago' -o json-pretty : %s", err) return jList, err } outputSplited := strings.Split(string(output), "}\n{") for _, event := range outputSplited { var je journalctlEntry if len(event) == 0 { continue } event = strings.Trim(event, "{}") eventFull := "{" + event + "}" // err = json.Unmarshal([]byte(eventFull), &je) buf := bytes.NewBuffer([]byte(eventFull)) err = json.NewDecoder(buf).Decode(&je) if err != nil { err = fmt.Errorf("Ошибка десериализации данных: %s в итерации %s", err, eventFull) return jList, err } jList = append(jList, je) } return jList, nil } // - Порты // nmap от Платформы к Локациям и наоборот // оставим пока, двигаем в самый низ, как реализовать пока не представляю. Нужны проверки портов с учетом фаерволов // возможно это будет выполнение в лоб команды docker exec -it dci_back dcissh -a "nmap" // пока вместо открытых портов проверим запущен ли фаервол func getFirewalls() (firewalls, error) { var fwl firewalls units, err := os.ReadDir("/run/systemd/units") if err != nil { err = fmt.Errorf("Ошибка при получении содержимого run systemd units : %s", err) return fwl, err } else { for _, unit := range units { ufw, _ := regexp.Match("ufw", []byte(unit.Name())) if ufw { fwl.Ufw = "running" } nftables, _ := regexp.Match("nftables", []byte(unit.Name())) if nftables { fwl.Nftables = "running" } iptables, _ := regexp.Match("iptables", []byte(unit.Name())) if iptables { fwl.Iptables = "running" } firewalld, _ := regexp.Match("firewalld", []byte(unit.Name())) if firewalld { fwl.Firewalld = "running" } } } return fwl, nil } // - Настройки сети // NetworkManager // настройки интерфейсов // etc/hosts // etc/resolv.conf func getNetworkConf() (networkConfig, []error) { var networkConfig networkConfig var errors []error interfaces, err := net.Interfaces() if err != nil { err = fmt.Errorf("Ошибка при получении сетевых интерфейсов: %s", err) errors = append(errors, err) err = nil } else { for _, interf := range interfaces { var netInterface netInterface netInterface.Device = interf.Name netInterface.Flags = interf.Flags.String() netInterface.HwAddr = interf.HardwareAddr.String() adrs, _ := interf.Addrs() for _, adr := range adrs { netInterface.IpAddr = append(netInterface.IpAddr, adr.String()) } netInterface.Index = strconv.Itoa(interf.Index) netInterface.MTU = strconv.Itoa(interf.MTU) networkConfig.NetInterfaces = append(networkConfig.NetInterfaces, netInterface) // fmt.Printf("interf: %v\n", interf) } } units, err := os.ReadDir("/run/systemd/units") if err != nil { err = fmt.Errorf("Ошибка при получении содержимого run systemd units : %s", err) errors = append(errors, err) err = nil } else { for _, unit := range units { // Полчить статус NetworkManager matched, _ := regexp.Match("NetworkManager.services", []byte(unit.Name())) if matched { networkConfig.NetworkManager = "running" } // Полчить статус networking matchedNetworking, _ := regexp.Match("networking", []byte(unit.Name())) if matchedNetworking { networkConfig.Networking = "running" } } } nmConns, err := os.ReadDir("/run/NetworkManager/system-connections") if err != nil { err = fmt.Errorf("Ошибка при получении содержимого run NetworkManager") errors = append(errors, err) err = nil } else { for _, nmConn := range nmConns { networkConfig.NetworkManagerConn = append(networkConfig.NetworkManagerConn, nmConn.Name()) } } // Содержимое /etc/hosts linesByte, err := os.ReadFile("/etc/hosts") if err != nil { err = fmt.Errorf("Ошибка при получении содержимого etc hosts : %s", err) errors = append(errors, err) err = nil } else { lines := strings.Split(string(linesByte), "\n") for _, line := range lines { if strings.HasPrefix(line, "#") { continue } else { networkConfig.EtcHosts = append(networkConfig.EtcHosts, line) } } } return networkConfig, errors } // Возможность доступа к основным ресурсам в internet // docker-registry.ispsystem.com, download.docker.com — для доступа к Docker; // download.ispsystem.com — для обновления и установки платформы; // license6.ispsystem.com — для проверки лицензий; // metricreport.ispsystem.net — для работы сервера метрик. func getInternetResource(ispUrl string) (internetResource, error) { var ir internetResource var outErr error ipList, err := net.LookupIP(ispUrl) if err != nil { return ir, err } ir.Name = ispUrl var i []string for _, ip := range ipList { i = append(i, ip.String()) } ir.IpList = strings.Join(i, ",") httpUrl := "http://" + ispUrl httpsUrl := "https://" + ispUrl resp, err := http.Get(httpUrl) if err != nil { outErr = fmt.Errorf("Ошибка HTTP %s :: %s. ", httpUrl, err) ir.Http = err.Error() } else { ir.Http = strconv.Itoa(resp.StatusCode) } resp, err = http.Get(httpsUrl) if err != nil { outErr = fmt.Errorf("%s Ошибка HTTPS %s :: %s", outErr, httpUrl, err) ir.Https = err.Error() } else { ir.Https = strconv.Itoa(resp.StatusCode) } return ir, outErr } // 2026-02.5 получить историю. просто прочитаем файл с историей bash у root func getRootHistory() ([]rootHistoryCommand, error) { var rootHistoryCommands []rootHistoryCommand rawHistory, err := os.ReadFile("/root/.bash_history") if err != nil { err = fmt.Errorf("Ошибка при открытии файла /root/.bash_history : %s", err.Error()) return nil, err } i := 0 execTime := "" for _, line := range strings.Split(string(rawHistory), "\n") { var c rootHistoryCommand if strings.HasPrefix(line, "#") { execTime = strings.TrimLeft(line, "#") } else { c.Id = i i += 1 c.ExecutionTime = execTime c.Command = line execTime = "" rootHistoryCommands = append(rootHistoryCommands, c) } } return rootHistoryCommands, err }