This commit is contained in:
2026-04-04 00:09:02 +08:00
commit 38e896363e
117 changed files with 119311 additions and 0 deletions

View File

@@ -0,0 +1,600 @@
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
}