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

Binary file not shown.

View File

@@ -0,0 +1,37 @@
module dci6-support
go 1.24.0
toolchain go1.24.4
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/go-connections v0.6.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-sql-driver/mysql v1.9.3 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.7.6 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/moby/api v1.52.0 // indirect
github.com/moby/moby/client v0.2.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
go.opentelemetry.io/otel v1.35.0 // indirect
go.opentelemetry.io/otel/metric v1.35.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
golang.org/x/crypto v0.37.0 // indirect
golang.org/x/sync v0.13.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.24.0 // indirect
)

View File

@@ -0,0 +1,66 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk=
github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/moby/api v1.52.0 h1:00BtlJY4MXkkt84WhUZPRqt5TvPbgig2FZvTbe3igYg=
github.com/moby/moby/api v1.52.0/go.mod h1:8mb+ReTlisw4pS6BRzCMts5M49W5M7bKt1cJy/YbAqc=
github.com/moby/moby/client v0.2.1 h1:1Grh1552mvv6i+sYOdY+xKKVTvzJegcVMhuXocyDz/k=
github.com/moby/moby/client v0.2.1/go.mod h1:O+/tw5d4a1Ha/ZA/tPxIZJapJRUS6LNZ1wiVRxYHyUE=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -0,0 +1,15 @@
package main
func getHwServerInfo(runningSql runningSqlServer, server_id string) (hwServer, error) {
var hwS hwServer
var err error
return hwS, err
}
func getHwSwitchInfo(runningSql runningSqlServer, server_id string) (hwServer, error) {
var hwS hwServer
var err error
return hwS, err
}

View File

@@ -0,0 +1 @@
package main

View File

@@ -0,0 +1,62 @@
package main
type hwServer struct {
Id int `json:"id"`
Status string `json:"status"`
// StatusInfo string `json:"status"` везде NULL надо по возможности посмотреть на боевых платформах
Warehouse int `json:"warehouse"`
Uuid string `json:"uuid"`
Barcode string `json:"barcode"`
SerialNumber string `json:"serial_number"`
Note string `json:"note"`
CustomField string `json:"custom_field"`
CreatedAt string `json:"created_at"`
WarehouseStatus string `json:"warehouse_status"`
Name string `json:"name"`
Rack int `json:"rack"`
Unit float64 `json:"unit"`
Mac string `json:"mac"`
MainIpv4 int `json:"main_ipv4"` // по возможности получить из таблицы ip
MainIpv6 int `json:"main_ipv6"` // по возможности получить из таблицы ip
UserNote string `json:"user_note"`
OsTemplate string `json:"os_template"`
HardwareInfo string `json:"hardware_info"`
PerformInfo string `json:"perform_info"`
Settings string `json:"settings"`
Model string `json:"model"`
Configuration string `json:"configuration"`
CustomConfiguration string `json:"custom_configuration"`
IsCustomConfiguration int `json:"is_custom_configuration"`
Platform int `json:"platform"` //получить платформу из таблицы
// Owner
}
type hwSwitch struct {
Id int `json:"id"`
Name string `json:"name"`
Hostname string `json:"hostname"`
Note string `json:"note"`
Rack int `json:"rack"`
Location int `json:"location"`
Status string `json:"status"`
StatusInfo string `json:"status_info"`
Warehouse string `json:"warehouse"`
WarehouseStatus string `json:"warehouse_status"`
WarehouseStatusInfo string `json:"warehouse_status_info"`
Device string `json:"device"`
AdditionalInfo string `json:"additional_info"`
Unit float64 `json:"unit"`
Size float64 `json:"size"`
LastUpdate string `json:"last_update"`
LastSuccessUpdate string `json:"last_success_update"`
AggregationAllowed int `json:"aggregation_allowed"`
Model string `json:"model"`
WarehousePortCount int `json:"warehouse_port_count"`
ExploitationStatus string `json:"exploitation_status"`
CustomParams string `json:"custom_params"`
CustomField string `json:"custom_field"`
Weight float64 `json:"weight"`
ConnectedPduId int `json:"connected_pdu_id"`
ConnectedUpsId int `json:"connected_ups_id"`
TaskmgrTask []taskManagerTask `json:"taskmgr_tasks"`
}

View File

@@ -0,0 +1 @@
package main

View File

@@ -0,0 +1,79 @@
package main
import (
"context"
"fmt"
"os"
"regexp"
"github.com/moby/moby/client"
)
func isDciPlatform() (bool, []error) {
var result bool
var errors []error
// наличие сервиса dci
units, err := os.ReadDir("/run/systemd/units")
dciService := false
if err != nil {
err = fmt.Errorf("Ошибка доступа к директории systemd units: %s", err)
errors = append(errors, err)
err = nil
dciService = false
} else {
for _, unit := range units {
matched, _ := regexp.Match("dci.service", []byte(unit.Name()))
if matched {
dciService = true
}
}
}
// наличие config.json
configJson := false
files, err := os.ReadDir("/opt/ispsystem/dci/")
if err != nil {
err = fmt.Errorf("Ошибка при чтении директории opt ispsystem dci")
errors = append(errors, err)
err = nil
configJson = false
} else {
for _, file := range files {
matched, _ := regexp.Match("config.json", []byte(file.Name()))
if matched {
configJson = true
}
}
}
// запущенный контейнер dci_back
dciBack := false
apiClient, err := client.New(client.FromEnv)
if err != nil {
err = fmt.Errorf("Ошибка при создании docker клиента %s", err)
errors = append(errors, err)
err = nil
} else {
defer apiClient.Close()
containers, err := apiClient.ContainerList(context.Background(), client.ContainerListOptions{All: true})
if err != nil {
err = fmt.Errorf("Ошибка получения списка контейнеров : %s", err)
errors = append(errors, err)
err = nil
} else {
for _, ctr := range containers.Items {
if ctr.Names[0] == "/dci_back" {
dciBack = true
}
}
}
}
if dciService {
result = true
} else if configJson {
result = true
} else if dciBack {
result = true
} else {
result = false
}
return result, errors
}

View File

@@ -0,0 +1,3 @@
package main
// Просканировать с сервера порты на Локации

View File

@@ -0,0 +1,454 @@
package main
import (
"archive/zip"
"encoding/json"
"flag"
"fmt"
"log"
"os"
"strings"
"time"
)
func main() {
var out outputServerStruct
var err error
var errs []error
var showVer bool
var verbose bool
var isPlatform bool
var isLocation bool
version := "2603-01.8"
ticketName := flag.String("ticket", "not_number", "номер тикета isp")
flag.BoolVar(&showVer, "v", false, "версия")
flag.BoolVar(&showVer, "version", false, "версия")
flag.BoolVar(&verbose, "verbose", false, "подробно")
flag.BoolVar(&isPlatform, "platform", false, "будет запущен сбор данных по платформе")
flag.BoolVar(&isLocation, "location", false, "будет запущен сбор данных по локации")
hwName := flag.String("hw", "", "исследуемое оборудование пример -hw switch:13")
flag.Parse()
if showVer {
fmt.Println(version)
return
}
now := time.Now()
formatedNow := now.Format("2006-01-02_15-04")
outputDir := "isp_" + *ticketName + "_" + formatedNow
err = os.Mkdir(outputDir, 0644)
if err != nil {
log.Println(err)
outputDir = "."
}
logInfo, logWarn, logErr := createLogger(outputDir, verbose)
logInfo.Println("=====================СТАРТ СБОРА ДАННЫХ=====================")
// флаг номер тикета
logInfo.Println("Уточняем, что утилита запущена на сервере с платформой")
logInfo.Println("Получаем информацию о BIOS : bios_info")
out.BiosInfo, err = dmidecodeTSystem()
if err != nil {
logWarn.Println(err)
}
logInfo.Println("Получаем информацию об операционной системе: os_info")
out.OperatingSystem, errs = getOs()
// ставим OsRelease = NA значит вообще не получилось
if len(errs) > 0 {
for _, e := range errs {
logWarn.Println(e)
}
}
logInfo.Println("Получаем информацию об установленных пакетах: installed_packages")
if strings.Contains(out.OperatingSystem.OsRelease, "Ubuntu") || out.OperatingSystem.AstraVersion != "" {
out.InstalledPackages, err = getDebPackages()
if err != nil {
logWarn.Println(err)
}
} else {
out.InstalledPackages, err = getRpmPackages()
if err != nil {
logWarn.Println(err)
}
}
logInfo.Print("Получаем содержимое файла /root/.bash_history")
out.RootHistory, err = getRootHistory()
if err != nil {
logWarn.Println(err)
}
logInfo.Println("Получаем информацию о файловой системе сервера: fs_informations")
out.FsInformations, err = getFsInfo()
if err != nil {
logWarn.Println(err)
}
logInfo.Println("Получаем информацию о средней загрзке сервера: load_average")
out.LoadAverage, err = getLa()
if err != nil {
logWarn.Println(err)
}
logInfo.Println("Получаем информацию о процессоре: cpu")
out.Cpus, err = getCpuinfo()
if err != nil {
logWarn.Println(err)
}
logInfo.Println("Получаем информацию о памяти: ram")
out.Ram, err = getRam()
if err != nil {
logWarn.Println(err)
}
logInfo.Println("Получаем информацию об аптайме: uptime")
out.Uptime, err = getUptime()
if err != nil {
logWarn.Println(err)
}
logInfo.Println("Получаем информацию о службе времени: time_service")
out.TimeService, errs = getTimeService()
for _, e := range errs {
logWarn.Println(e)
}
logInfo.Println("Получаем информацию о записях в journalctl xe p4 since 1 day ago: journalctl_entries")
out.JournalctlEntries, err = getJournalctl()
if err != nil {
logWarn.Println(err)
}
logInfo.Println("Получаем информацию о фаерволах: firewalls")
out.Firewalls, err = getFirewalls()
if err != nil {
logWarn.Println(err)
}
logInfo.Println("Получаем информацию о правилах nftables nft list ruleset")
out.NftRuleset, errs = getNftRuleset(outputDir)
if err != nil {
logWarn.Println(err)
}
for _, err := range errs {
logWarn.Println(err)
}
logInfo.Println("Получаем информацию о сетевых настройках: network_config")
out.NetworkConfig, errs = getNetworkConf()
for _, e := range errs {
logWarn.Println(e)
}
logInfo.Println("Получаем информацию о доступности необходимых интернет-ресурсов: internet_required")
requiredResources := []string{"docker-registry.ispsystem.com", "download.docker.com", "download.ispsystem.com", "license.ispsystem.com", "metricreport.ispsystem.net"}
for _, ispUrl := range requiredResources {
ir, err := getInternetResource(ispUrl)
if err != nil {
logWarn.Println(err)
}
out.InternetRequired = append(out.InternetRequired, ir)
}
//TODO Тут проблемы, активные службы не попали в json
logInfo.Println("Получаем информацию о настройках безопасности")
if strings.Contains(out.OperatingSystem.OsRelease, "Ubuntu") {
out.SecSetUbuntu, err = getSecSettingsUbuntu()
if err != nil {
logWarn.Println(err)
}
} else if strings.Contains(out.OperatingSystem.OsRelease, "Alma") {
out.SecSetAlma, err = getSecSettingsAlma()
if err != nil {
logWarn.Println(err)
}
} else {
out.SecSetALSE, errs = getSecSettingsAlse()
for _, e := range errs {
logWarn.Println(e)
}
}
logInfo.Println("Получаем информацию docker ps -a")
out.DockerPsA, err = getDockerPsA()
if err != nil {
logWarn.Println(err)
}
logInfo.Println("Информация о ресурсах контейнеров docker stats -a --no-stream")
out.DockerStats, err = getDockerStats()
if err != nil {
logWarn.Println(err)
}
logInfo.Println("Получаем логи и статус supervisord")
out.DockerSupervisor, errs = getDockerSupervisordLog(out, outputDir)
for _, e := range errs {
logWarn.Println(e)
}
//
//
//
//
// Запаковываем в json
outJson, err := json.Marshal(out)
err = os.WriteFile(outputDir+"/server_information.json", outJson, 0644)
if err != nil {
logErr.Println(err)
}
//
//
//
//
//
// ПЛАТФОРМА
//
//
//
//
//
//
//
logInfo.Println("Начинаем сбор данных по ПЛАТФОРМЕ")
isPlatform, errs = isDciPlatform()
//
//
//
//
// НУЖНА ПРОВЕРКА
//
if len(errs) > 0 {
for _, e := range errs {
logWarn.Println(e)
}
logWarn.Println("В таком случае предположим, что сбор данных происходит на платформе")
isPlatform = true
}
//
//
//
//
//
//
//
if isPlatform {
var platformStruct outputPlatformStruct
runningSql, err := getRunningSqlServer()
// Если я не смогу определить какой sql то тут придётся упасть, а значит файлы нужно скопировать раньше
// И логи контейнеров получить тоже раньше
if err != nil {
logErr.Fatalln(err)
}
var ispDbname string
if runningSql.Type == "pgsql" {
ispDbname, err = checkIspDbname(runningSql)
if err != nil {
logErr.Fatalln(err)
}
}
logInfo.Println("Получаем информацию из таблицы dci_location")
platformStruct.DciLocations, errs = getDciLocationDB(ispDbname, runningSql)
for _, e := range errs {
logWarn.Println(e)
}
logInfo.Println("Получаем base64 docker-compose из таблицы dci_location")
platformStruct.DciLocationDockerComposes, errs = getDciLocationComposeDB(ispDbname, runningSql)
for _, e := range errs {
logWarn.Println(e)
}
//
logInfo.Println("Получаем информацию о задачах с ошибками за месяц")
platformStruct.TaskManagerTask, errs = getDciTaskMonthErrorsDB(ispDbname, runningSql)
for _, e := range errs {
logWarn.Println(e)
}
//
// Позволит прикинуть какие локации больше нагружены, и в целом нагрузку на платформу
logInfo.Println("Получаем информацию о количестве оборудования по локациям")
platformStruct.HwByLocations, errs = getDciLocationHWCountDB(ispDbname, runningSql, platformStruct)
for _, e := range errs {
logWarn.Println(e)
}
//
logInfo.Println("Получаем информацию об установленных плагинах")
platformStruct.InstalledPlugin, errs = getDciPluginsDB(ispDbname, runningSql)
for _, e := range errs {
logWarn.Println(e)
}
//
// Получаем просто количество пользователей, получать какую то ещё информацию о пользователях вредно
logInfo.Println("Получаем количество пользователей")
platformStruct.Users, err = getDciUsersCountDB(ispDbname, runningSql)
if err != nil {
logWarn.Println(err)
}
//
// Не забираем сами настройки ldap потому что они нам ничего особо не скажут, проверить мы их не можем, а сам факт передачи этой информации может смутить пользователя
logInfo.Println("Проверяем наличие настроек ldap")
platformStruct.Ldaps, errs = getDciLdapDB(ispDbname, runningSql)
for _, e := range errs {
logWarn.Println(e)
}
//
//
logInfo.Println("Получаем информацию о репозиториях операционных систем")
platformStruct.Repos, errs = getDciRepoDB(ispDbname, runningSql)
for _, e := range errs {
logWarn.Println(e)
}
//
logInfo.Println("Получаем шаблоны ОС из репозиториев не ispsystem")
platformStruct.OsTemplates, errs = getDciOsTemplatesDB(ispDbname, runningSql, platformStruct)
for _, e := range errs {
logWarn.Println(e)
}
//
logInfo.Println("Получаем инфорамцию о доверенных серверах в Real IP")
platformStruct.RealIP, err = getDciRealIpDB(ispDbname, runningSql)
if err != nil {
logWarn.Println(err)
}
//
//
logInfo.Println("Получаем информацию о заданиях резервного копирования платформы")
platformStruct.BackupTasks, errs = getDciBackupTask(ispDbname, runningSql)
for _, e := range errs {
logWarn.Println(e)
}
//
//получаем информацию о лицензии dci licensse check и dci license info пока что оптимальные варианты, но было бы лучше получить непосредственно код этих флагов и встроить его сюда.
logInfo.Println("Получаем информацию о лицензии")
platformStruct.License, errs = getLicenseInlfo()
for _, err := range errs {
logWarn.Println(err)
}
//
// Копируем файлы config.json и docker-compose.yaml, а также собираем имена всех файлов из /opt/ispsystem
var copiedFiles copiedFiles
logInfo.Println("Копируем config.json")
err = copyFiles("/opt/ispsystem/dci/config.json", outputDir+"/config.json")
if err != nil {
copiedFiles.Config = "error"
logWarn.Printf("Оибка при копировании файла config.json: %s", err)
} else {
copiedFiles.Config = "done"
}
logInfo.Println("Копируем install.log")
err = copyFiles("/opt/ispsystem/dci/install.log", outputDir+"/config.json")
if err != nil {
copiedFiles.InstallLog = "error"
logWarn.Printf("Оибка при копировании файла install.log: %s", err)
} else {
copiedFiles.InstallLog = "done"
}
logInfo.Println("Копируем docker-compose.yaml")
err = copyFiles("/opt/ispsystem/dci/docker-compose.yaml", outputDir+"/docker-compose.yaml")
if err != nil {
copiedFiles.PlatformDockerCompose = "error"
logWarn.Printf("Оибка при копировании файла docker-compose.yaml: %s", err)
} else {
copiedFiles.PlatformDockerCompose = "done"
}
logInfo.Println("Собираем названия файлов из директории /opt/ispsystem/")
ispFiles, errs := getIspFileNames("/opt/ispsystem/")
for _, er := range errs {
logWarn.Printf("Ошибка получения имени файла: %err", er)
}
copiedFiles.FileNames = ispFiles
platformStruct.CopiedFiles = copiedFiles
//
logInfo.Println("=====================КОНЕЦ СБОРА ДАННЫХ=====================")
outJsonPlatform, err := json.Marshal(platformStruct)
err = os.WriteFile(outputDir+"/dci_platform_information.json", outJsonPlatform, 0644)
if err != nil {
logErr.Println(err)
}
//
//
//
//
// HARDWARE
//
//
//
//
if *hwName != "" {
hw := strings.Split(*hwName, ":")
if len(hw) == 1 {
logErr.Printf("Оборудование %s указано неверно. Правильный формат оборудования \" -hw switch:13 \" где switch тип оборудования (switch, pdu, server, ups, san), а 13 его id", *hwName)
} else {
switch hw[0] {
case "server":
getHwServerInfo(runningSql, hw[1])
case "switch":
getHwSwitchInfo(runningSql, hw[1])
}
}
}
} else {
logWarn.Fatalln("Утилитиа запущена не на сервере платформы.")
}
//
//
//
//
//
// ЗАПАКОВКА РЕЗУЛЬТАТОВ В АРХИВ
//
//
//
//
//
outFiles, err := os.ReadDir(outputDir)
if err != nil {
fmt.Printf("Возникла ошибка %s при чтении %s из директории %s", err, outFiles, outputDir)
} else {
zipArchName := outputDir + ".zip"
fmt.Printf("Создаём архив %s\n", zipArchName)
newZipFile, err := os.Create(zipArchName)
if err != nil {
fmt.Printf("Ошибка %s создания архива %s", err, zipArchName)
defer newZipFile.Close()
} else {
zipWriter := zip.NewWriter(newZipFile)
for _, zFile := range outFiles {
err = addToArchive(zipWriter, outputDir+"/"+zFile.Name())
if err != nil {
fmt.Printf("Ошибка %s при добавлении файла %s в архив", err, zFile.Name())
}
}
err = zipWriter.Close()
}
defer newZipFile.Close()
}
}

View File

@@ -0,0 +1,52 @@
package main
import (
"archive/zip"
"io"
"log"
"os"
)
func createLogger(logDir string, verbose bool) (*log.Logger, *log.Logger, *log.Logger) {
logFile, err := os.OpenFile(logDir+"/dci_support_info.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
log.Println("Failed to open log file:", err)
logInfo := log.New(os.Stdout, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)
logWarn := log.New(os.Stdout, "WARN: ", log.Ldate|log.Ltime|log.Lshortfile)
logErr := log.New(os.Stderr, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)
return logInfo, logWarn, logErr
} else {
if verbose {
mw := io.MultiWriter(os.Stdout, logFile)
mwErr := io.MultiWriter(os.Stderr, logFile)
log.SetOutput(mw)
logInfo := log.New(mw, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)
logWarn := log.New(mw, "WARN: ", log.Ldate|log.Ltime|log.Lshortfile)
logErr := log.New(mwErr, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)
return logInfo, logWarn, logErr
} else {
log.SetOutput(logFile)
logInfo := log.New(logFile, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)
logWarn := log.New(logFile, "WARN: ", log.Ldate|log.Ltime|log.Lshortfile)
logErr := log.New(logFile, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)
return logInfo, logWarn, logErr
}
}
}
func addToArchive(zipWriter *zip.Writer, filename string) error {
fileToZip, err := os.Open(filename)
if err != nil {
return err
}
defer fileToZip.Close()
w, err := zipWriter.Create(filename)
if err != nil {
return err
}
if _, err := io.Copy(w, fileToZip); err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,2 @@
компиляция со статической линковкой
CGO_ENABLED=0 go build -a -ldflags="-s -w" -o dci6-support

View File

@@ -0,0 +1,43 @@
package main
type outputPlatformStruct struct {
// IspSettings []ispSetting `json:"isp_settings"`
DciLocations []dciLocation `json:"dci_locations"`
DciLocationDockerComposes []dciLocationDockerCompose `json:"dci_location_dockercomposes"`
TaskManagerTask []taskManagerTask `json:"task_manager_task"`
HwByLocations []hwByLocation `json:"hw_by_locations"`
InstalledPlugin []installedPlugin `json:"installed_plugin"`
Users users `json:"users"`
Ldaps []ldap `json:"ldaps"`
Repos []repo `json:"repos"`
OsTemplates []osTemplate `json:"os_template"`
RealIP realIP `json:"real_ip"`
BackupTasks []backupTask `json:"backup_tasks"`
CopiedFiles copiedFiles `json:"copied_files"`
License license `json:"license"`
// ShowProcesslist []processlist `json:"show_processlist"`
}
type outputServerStruct struct {
BiosInfo biosInfo `json:"bios_info"`
OperatingSystem operatingSystem `json:"operating_system"`
InstalledPackages []installedPackage `json:"installed_packages"`
FsInformations []fsInfo `json:"fs_informations"`
LoadAverage loadAverage `json:"load_average"`
Cpus []cpu `json:"cpu"`
Ram ram `json:"ram"`
Uptime uptime `json:"uptime"`
TimeService timeService `json:"time_service"`
JournalctlEntries []journalctlEntry `json:"journalctl_entries"`
Firewalls firewalls `json:"firewalls"`
NetworkConfig networkConfig `json:"network_config"`
InternetRequired []internetResource `json:"internet_required"`
SecSetALSE secSetALSE `json:"security_settings_alse"`
SecSetUbuntu secSetUbuntu `json:"security_settings_ubuntu"`
SecSetAlma secSetAlma `json:"security_settings_alma"`
DockerPsA []dockerPs `json:"docker_ps_a"`
DockerStats []dockerStats `json:"docker_stats"`
DockerSupervisor []dockerSupervisor `json:"docker_supervisor"`
NftRuleset nftRuleset `json:"nft_rulest"`
RootHistory []rootHistoryCommand `json:"root_history_command"`
}

View File

@@ -0,0 +1,63 @@
package main
import (
"errors"
"fmt"
"io"
"os"
)
func copyFiles(src, dst string) error {
isSrcExist, err := os.Stat(src)
if err != nil {
return err
}
if !isSrcExist.Mode().IsRegular() {
return &os.PathError{
Op: "copy",
Path: src,
Err: errors.New("не является обычным файлом"),
}
}
source, err := os.Open(src)
if err != nil {
return err
}
defer source.Close()
destination, err := os.Create(dst)
if err != nil {
return err
}
defer destination.Close()
_, err = io.Copy(destination, source)
return err
}
func getIspFileNames(dirName string) ([]string, []error) {
var fileList []string
var errs []error
ispList, err := os.ReadDir(dirName)
if err != nil {
err = fmt.Errorf("Ошибка при получении содержимого директории %s : %s", dirName, err)
errs = append(errs, err)
err = nil
}
for _, entry := range ispList {
dirPath := dirName + "/" + entry.Name()
if entry.IsDir() {
interList, interErrs := getIspFileNames(dirPath)
for _, ie := range interErrs {
errs = append(errs, ie)
}
for _, il := range interList {
fileList = append(fileList, il)
}
}
fileList = append(fileList, dirPath)
}
return fileList, errs
}

View File

@@ -0,0 +1,133 @@
package main
// type ispSetting struct {
// // select name, value from isp_settings;
// Name string `json:"name"`
// Value string `json:"value"`
// }
type dciLocation struct {
// select id,status,status_info,name,ssh_address,ssh_port,ssh_user,setup_info,params_dhcp,params_redis,params_nginx,params_netflow,settings,is_main,proxy_params,userspace,patch from dci_1.dci_location;
Id int `json:"id"`
Status string `json:"status"`
StatusInfo string `json:"status_info"`
Name string `json:"name"`
SshAddress string `json:"ssh_address"`
SshPort int `json:"ssh_port"`
SshUser string `json:"ssh_user"`
SetupInfo string `json:"setup_info"`
ParamsDhcp string `json:"params_dhcp"`
ParamsRedis string `json:"params_redis"`
ParamsNginx string `json:"params_nginx"`
ParamsNetflow string `json:"params_netflow"`
Settings string `json:"settings"`
IsMain int `json:"is_main"`
ProxyParams string `json:"proxy_params"`
Userspace int `json:"userspace"`
Patch string `json:"patch"`
}
type dciLocationDockerCompose struct {
// select id,name,docker_compose from dci_1.dci_location;
Id int `json:"id"`
Name string `json:"name"`
DockerCompose string `json:"docker_compose"`
}
type taskManagerTask struct {
// select id,name,status,registration_time from auth.taskmgr_task where status != 'complete' and registration_time >= NOW() - INTERVAL 1 MONTH;
Id int `json:"id"`
Name string `json:"name"`
RegistrationTime string `json:"registration_time"`
RequestInfo string `json:"request_info"`
Output string `json:"output"`
Status string `json:"status"`
}
type hwByLocation struct {
// SELECT
// (SELECT COUNT(id) from dci_server WHERE location = 2) as server,
// (SELECT COUNT(id) from dci_switch WHERE location = 2) as switch,
// (SELECT count(id) from dci_pdu WHERE location = 2) as pdu,
// (SELECT COUNT(id) from dci_ups WHERE location = 2) as ups,
// (SELECT COUNT(id) from dci_server WHERE location = 2) +
// (SELECT COUNT(id) from dci_switch WHERE location = 2) +
// (SELECT count(id) from dci_pdu WHERE location = 2) +
// (SELECT COUNT(id) from dci_ups WHERE location = 2) as total_location_2;
Location int `json:"location"`
Server int `json:"server"`
Switch int `json:"switch"`
Pdu int `json:"pdu"`
Ups int `json:"ups"`
}
type installedPlugin struct {
// select name,status,version,current_version from ps_plugin;
Name string `json:"name"`
Status string `json:"string"`
Version string `json:"version"`
CurrentVersion string `json:"current_version"`
}
type users struct {
Count int `json:"count"`
}
type ldap struct {
Id int `json:"id"`
Name string `json:"name"`
LastSync string `json:"last_sync"`
}
type repo struct {
// SELECT id,name,url FROM dci_repo
Id int `json:"id"`
Name string `json:"name"`
Url string `json:"url"`
}
type osTemplate struct {
// SELECT id,name,filename,macro,metainfo,directory_name,repository,size from dci_os_template where repo != 1 /* репозиторий ispsystem*/
Id int `json:"id"`
Name string `json:"name"`
Filename string `json:"filename"`
Macro string `json:"macro"`
Metainfo string `json:"metainfo"`
DirectoryName string `json:"directory_name"`
Repository int `json:"repository"`
Size int `json:"size"`
}
// type processlist struct {
// // SELECT * FROM information_schema.processlist WHERE COMMAND != 'Sleep' AND TIME > 0 ORDER BY TIME DESC;
// Id int `json:"id"`
// User string `json:"user"`
// Host string `json:"host"`
// Db string `json:"db"`
// Command string `json:"command"`
// Time int `json:"time"`
// State string `json:"state"`
// Info string `json:"info"`
// }
type realIP struct {
// SELECT name, value FROM auth.isp_settings WHERE name = "trusted_servers"
Name string `json:"name"`
Value string `json:"value"`
}
type backupTask struct {
// SELECT id,enabled,cron_expression,limit_count,limit_size_mib FROM backup_task
Id int `json:"id"`
Enabled int `json:"enabled"`
CronExpression string `json:"cron_expression"`
LimitCount int `json:"limit_count"`
LimitSizeMib int `json:"limit_size_mib"`
}
type copiedFiles struct {
FileNames []string `json:"file_names"`
Config string `json:"config"`
PlatformDockerCompose string `json:"platform_docker_compose"`
InstallLog string `json:"install_log"`
}

View File

@@ -0,0 +1,28 @@
package main
import (
"fmt"
"os/exec"
)
func getLicenseInlfo() (license, []error) {
var errors []error
var lic license
cmd := exec.Command("dci", "license", "check")
output, err := cmd.Output()
if err != nil {
err = fmt.Errorf("Ошибка выполнения команды dci license check : %s", err)
errors = append(errors, err)
}
lic.LicenseCheck = string(output)
cmd = exec.Command("dci", "license", "info")
output, err = cmd.Output()
if err != nil {
err = fmt.Errorf("Ошибка выполнения команды dci license info : %s", err)
errors = append(errors, err)
}
lic.LicenseInfo = string(output)
return lic, errors
}

View File

@@ -0,0 +1,579 @@
package main
import (
"fmt"
"log"
"strconv"
"strings"
)
func getDciLocationDB(ispDbName string, runningSql runningSqlServer) ([]dciLocation, []error) {
dbName := "dci_1"
if ispDbName == "isp" {
dbName = ispDbName
}
query := "SELECT id, status, COALESCE(status_info, 'null') as status_info, name, ssh_address, ssh_port, ssh_user, COALESCE(setup_info, 'null') as setup_info, COALESCE(params_dhcp, 'null') as params_dhcp, COALESCE(params_redis, 'null') as params_redis, COALESCE(params_nginx, 'null') as params_nginx, COALESCE(params_netflow, 'null') as params_netflow, COALESCE(settings, 'null') as settings, CASE WHEN is_main THEN 1 ELSE 0 END as is_main, COALESCE(proxy_params, '') as proxy_params, COALESCE(userspace, 0) as userspace, COALESCE(patch, 'null') as patch FROM dci_location;"
var errs []error
var dl []dciLocation
if runningSql.Type == "mysql" {
rows, db, err := mysqlQuery(query, dbName, runningSql)
if err != nil {
err = fmt.Errorf("Ошибка выполнения запроса к таблице %s.dci_location : %s", dbName, err.Error())
errs = append(errs, err)
return dl, errs
}
defer db.Close()
defer rows.Close()
for rows.Next() {
var dciLoc dciLocation
err = rows.Scan(&dciLoc.Id, &dciLoc.Status, &dciLoc.StatusInfo, &dciLoc.Name, &dciLoc.SshAddress, &dciLoc.SshPort, &dciLoc.SshUser, &dciLoc.SetupInfo, &dciLoc.ParamsDhcp, &dciLoc.ParamsRedis, &dciLoc.ParamsNginx, &dciLoc.ParamsNetflow, &dciLoc.Settings, &dciLoc.IsMain, &dciLoc.ProxyParams, &dciLoc.Userspace, &dciLoc.Patch)
if err != nil {
err = fmt.Errorf("Ошибка сканирования результатов запроса в структуру dciLocation : %s", err.Error())
errs = append(errs, err)
continue
}
dl = append(dl, dciLoc)
}
} else if runningSql.Type == "pgsql" {
rows, pool, err := pgsqlQuery(query, dbName, runningSql)
// dbName dci_1
if err != nil {
err = fmt.Errorf("Ошибка выполнения запроса к таблице %s.dci_location : %s", dbName, err.Error())
errs = append(errs, err)
return dl, errs
}
defer pool.Close()
defer rows.Close()
for rows.Next() {
var dciLoc dciLocation
err = rows.Scan(&dciLoc.Id, &dciLoc.Status, &dciLoc.StatusInfo, &dciLoc.Name, &dciLoc.SshAddress, &dciLoc.SshPort, &dciLoc.SshUser, &dciLoc.SetupInfo, &dciLoc.ParamsDhcp, &dciLoc.ParamsRedis, &dciLoc.ParamsNginx, &dciLoc.ParamsNetflow, &dciLoc.Settings, &dciLoc.IsMain, &dciLoc.ProxyParams, &dciLoc.Userspace, &dciLoc.Patch)
if err != nil {
err = fmt.Errorf("Ошибка сканирования результатов запроса в структуру dciLocation : %s", err.Error())
errs = append(errs, err)
continue
}
dl = append(dl, dciLoc)
}
}
return dl, errs
}
func getDciLocationComposeDB(ispDbName string, runningSql runningSqlServer) ([]dciLocationDockerCompose, []error) {
dbName := "dci_1"
if ispDbName == "isp" {
dbName = ispDbName
}
var errs []error
var dlc []dciLocationDockerCompose
query := "SELECT id,name,docker_compose FROM dci_location;"
switch runningSql.Type {
case "mysql":
rows, db, err := mysqlQuery(query, dbName, runningSql)
if err != nil {
err = fmt.Errorf("Ошибка выполнения запроса к таблице %s.dci_location : %s", dbName, err.Error())
errs = append(errs, err)
return dlc, errs
}
defer db.Close()
defer rows.Close()
for rows.Next() {
var dciLocCompose dciLocationDockerCompose
err = rows.Scan(&dciLocCompose.Id, &dciLocCompose.Name, &dciLocCompose.DockerCompose)
if err != nil {
err = fmt.Errorf("Ошибка записи в структуру dciLocationDockerCompose : %s", err.Error())
}
dlc = append(dlc, dciLocCompose)
}
case "pgsql":
rows, pool, err := pgsqlQuery(query, dbName, runningSql)
if err != nil {
err = fmt.Errorf("Ошибка выполнения запроса к таблице %s.dci_location : %s", dbName, err.Error())
errs = append(errs, err)
return dlc, errs
}
defer rows.Close()
defer pool.Close()
for rows.Next() {
var dciLocCompose dciLocationDockerCompose
err = rows.Scan(&dciLocCompose.Id, &dciLocCompose.Name, &dciLocCompose.DockerCompose)
if err != nil {
err = fmt.Errorf("Ошибка записи в структуру dciLocationDockerCompose : %s", err.Error())
}
dlc = append(dlc, dciLocCompose)
}
}
return dlc, errs
}
func getDciTaskMonthErrorsDB(ispDbName string, runningSql runningSqlServer) ([]taskManagerTask, []error) {
var tm []taskManagerTask
var errs []error
dbName := "auth"
if ispDbName == "isp" {
dbName = ispDbName
}
switch runningSql.Type {
case "mysql":
query := "SELECT id,name,registration_time,request_info,output,status FROM taskmgr_task WHERE status != 'complete' AND registration_time >= NOW() - INTERVAL 1 MONTH;"
rows, db, err := mysqlQuery(query, dbName, runningSql)
if err != nil {
err = fmt.Errorf("Ошибка выполнения запроса к таблице %s.taskmgr_task : %s", dbName, err.Error())
errs = append(errs, err)
return tm, errs
}
defer rows.Close()
defer db.Close()
for rows.Next() {
var taskManagerFailed taskManagerTask
err = rows.Scan(&taskManagerFailed.Id, &taskManagerFailed.Name, &taskManagerFailed.RegistrationTime, &taskManagerFailed.RequestInfo, &taskManagerFailed.Output, &taskManagerFailed.Status)
if err != nil {
err = fmt.Errorf("Ошибка записи в структуру taskManagerFailed : %s", err.Error())
}
tm = append(tm, taskManagerFailed)
}
case "pgsql":
query := "SELECT id,name,registration_time,request_info,output,status FROM taskmgr_task WHERE status != 'complete' AND registration_time >= NOW() - INTERVAL '1 MONTH';"
rows, pool, err := pgsqlQuery(query, dbName, runningSql)
if err != nil {
err = fmt.Errorf("Ошибка выполнения запроса к таблице %s.taskmgr_task : %s", dbName, err.Error())
errs = append(errs, err)
return tm, errs
}
defer rows.Close()
defer pool.Close()
for rows.Next() {
var taskManagerFailed taskManagerTask
err = rows.Scan(&taskManagerFailed.Id, &taskManagerFailed.Name, &taskManagerFailed.RegistrationTime, &taskManagerFailed.RequestInfo, &taskManagerFailed.Output, &taskManagerFailed.Status)
if err != nil {
err = fmt.Errorf("Ошибка записи в структуру taskManagerFailed : %s", err.Error())
}
log.Println(taskManagerFailed.Id)
tm = append(tm, taskManagerFailed)
}
}
return tm, errs
}
func getDciLocationHWCountDB(ispDbName string, runningSql runningSqlServer, platformStruct outputPlatformStruct) ([]hwByLocation, []error) {
var hw []hwByLocation
var errs []error
dbName := "dci_1"
if ispDbName == "isp" {
dbName = ispDbName
}
// dbName dci_1
for _, loc := range platformStruct.DciLocations {
locId := strconv.Itoa(loc.Id)
query := "select (SELECT COUNT(id) FROM dci_server WHERE location = " + locId + ") AS server, (SELECT COUNT(id) FROM dci_switch WHERE location = " + locId + ") AS switch, (SELECT count(id) FROM dci_pdu WHERE location = " + locId + ") AS pdu, (SELECT COUNT(id) FROM dci_ups WHERE location = " + locId + ") AS ups;"
switch runningSql.Type {
case "mysql":
rows, db, err := mysqlQuery(query, dbName, runningSql)
if err != nil {
err = fmt.Errorf("Ошибка выполнения запроса к таблицам с оборудованиям : %s", err.Error())
errs = append(errs, err)
return hw, errs
}
defer db.Close()
defer rows.Close()
for rows.Next() {
var hwByLocation hwByLocation
err = rows.Scan(&hwByLocation.Server, &hwByLocation.Switch, &hwByLocation.Pdu, &hwByLocation.Ups)
if err != nil {
err = fmt.Errorf("Ошибка записи в структуру hwByLocation: %s", err.Error())
}
hwByLocation.Location = loc.Id
hw = append(hw, hwByLocation)
}
case "pgsql":
rows, pool, err := pgsqlQuery(query, dbName, runningSql)
if err != nil {
err = fmt.Errorf("Ошибка выполнения запроса к таблицам с оборудованием : %s", err.Error())
errs = append(errs, err)
return hw, errs
}
defer pool.Close()
defer rows.Close()
for rows.Next() {
var hwByLocation hwByLocation
err = rows.Scan(&hwByLocation.Server, &hwByLocation.Switch, &hwByLocation.Pdu, &hwByLocation.Ups)
if err != nil {
err = fmt.Errorf("Ошибка записи в структуру hwByLocation: %s", err.Error())
}
hwByLocation.Location = loc.Id
hw = append(hw, hwByLocation)
}
}
}
return hw, errs
}
func getDciPluginsDB(ispDbName string, runningSql runningSqlServer) ([]installedPlugin, []error) {
var ip []installedPlugin
var errs []error
dbName := "auth"
if ispDbName == "isp" {
dbName = ispDbName
}
query := "SELECT COALESCE(name, 'null'), COALESCE(status, 'null'), COALESCE(version, 'null'), COALESCE(current_version, 'null') from ps_plugin;"
switch runningSql.Type {
case "mysql":
rows, db, err := mysqlQuery(query, dbName, runningSql)
if err != nil {
err = fmt.Errorf("Ошибка выполнения запроса к таблице %s.ps_plugin : %s", dbName, err.Error())
errs = append(errs, err)
return ip, errs
}
defer db.Close()
defer rows.Close()
for rows.Next() {
var instPlug installedPlugin
err = rows.Scan(&instPlug.Name, &instPlug.Status, &instPlug.Version, &instPlug.CurrentVersion)
if err != nil {
err = fmt.Errorf("Ошибка записи в структуру installedPlugin : %s", err.Error())
errs = append(errs, err)
}
ip = append(ip, instPlug)
}
case "pgsql":
rows, pool, err := pgsqlQuery(query, dbName, runningSql)
if err != nil {
err = fmt.Errorf("Ошибка выполнения запроса к таблице %s.ps_plugin : %s", dbName, err.Error())
errs = append(errs, err)
return ip, errs
}
defer pool.Close()
defer rows.Close()
for rows.Next() {
var instPlug installedPlugin
err = rows.Scan(&instPlug.Name, &instPlug.Status, &instPlug.Version, &instPlug.CurrentVersion)
if err != nil {
err = fmt.Errorf("Ошибка записи в структуру installedPlugin : %s", err.Error())
errs = append(errs, err)
}
ip = append(ip, instPlug)
}
}
return ip, errs
}
func getDciUsersCountDB(ispDbName string, runningSql runningSqlServer) (users, error) {
var u users
var err error
dbName := "auth"
if ispDbName == "isp" {
dbName = ispDbName
}
query := "SELECT COUNT(id) FROM auth_user;"
switch runningSql.Type {
case "mysql":
rows, db, err := mysqlQuery(query, dbName, runningSql)
if err != nil {
err = fmt.Errorf("Ошибка выполнения запроса к таблице %s.auth_user : %s", dbName, err.Error())
return u, err
}
defer db.Close()
defer rows.Close()
for rows.Next() {
err = rows.Scan(&u.Count)
if err != nil {
err = fmt.Errorf("Ошибка записи в структуру users")
if rows != nil {
rows.Close()
}
return u, err
}
}
case "pgsql":
rows, pool, err := pgsqlQuery(query, dbName, runningSql)
if err != nil {
err = fmt.Errorf("Ошибка выполнения запроса к таблице %s.auth_user : %s", dbName, err.Error())
return u, err
}
defer pool.Close()
defer rows.Close()
for rows.Next() {
err = rows.Scan(&u.Count)
if err != nil {
err = fmt.Errorf("Ошибка записи в структуру users")
if rows != nil {
rows.Close()
}
return u, err
}
}
}
return u, err
}
func getDciLdapDB(ispDbName string, runningSql runningSqlServer) ([]ldap, []error) {
var ldaps []ldap
var errs []error
dbName := "auth"
if ispDbName == "isp" {
dbName = ispDbName
}
query := "SELECT id,name,last_sync FROM auth_ldap;"
switch runningSql.Type {
case "mysql":
rows, db, err := mysqlQuery(query, dbName, runningSql)
if err != nil {
err = fmt.Errorf("Ошибка при выполнении запроса к %s.auth_ldap : %s", dbName, err.Error())
errs = append(errs, err)
return ldaps, errs
}
defer db.Close()
defer rows.Close()
for rows.Next() {
var ldap ldap
err = rows.Scan(&ldap.Id, &ldap.Name, &ldap.LastSync)
if err != nil {
err = fmt.Errorf("Ошибка при записи структуры ldap : %s", err.Error())
errs = append(errs, err)
}
ldaps = append(ldaps, ldap)
}
case "pgsql":
rows, pool, err := pgsqlQuery(query, dbName, runningSql)
if err != nil {
err = fmt.Errorf("Ошибка при выполнении запроса к %s.auth_ldap : %s", dbName, err.Error())
errs = append(errs, err)
return ldaps, errs
}
defer pool.Close()
defer rows.Close()
for rows.Next() {
var ldap ldap
err = rows.Scan(&ldap.Id, &ldap.Name, &ldap.LastSync)
if err != nil {
err = fmt.Errorf("Ошибка при записи структуры ldap : %s", err.Error())
errs = append(errs, err)
}
ldaps = append(ldaps, ldap)
}
}
return ldaps, errs
}
func getDciRepoDB(ispDbName string, runningSql runningSqlServer) ([]repo, []error) {
var repos []repo
var errs []error
query := "SELECT id,name,url FROM dci_repo"
dbName := "dci_1"
if ispDbName == "isp" {
dbName = ispDbName
}
switch runningSql.Type {
case "mysql":
rows, db, err := mysqlQuery(query, dbName, runningSql)
if err != nil {
err = fmt.Errorf("Ошибка выполнения запроса к %s.dci_repo : %s", dbName, err.Error())
errs = append(errs, err)
return repos, errs
}
defer db.Close()
defer rows.Close()
for rows.Next() {
var repo repo
err = rows.Scan(&repo.Id, &repo.Name, &repo.Url)
if err != nil {
err = fmt.Errorf("Ошибка запписи в структуру repo : %s", err.Error())
errs = append(errs, err)
}
repos = append(repos, repo)
}
case "pgsql":
rows, pool, err := pgsqlQuery(query, dbName, runningSql)
if err != nil {
err = fmt.Errorf("Ошибка выполнения запроса к %s.dci_repo : %s", dbName, err.Error())
errs = append(errs, err)
return repos, errs
}
defer pool.Close()
defer rows.Close()
for rows.Next() {
var repo repo
err = rows.Scan(&repo.Id, &repo.Name, &repo.Url)
if err != nil {
err = fmt.Errorf("Ошибка запписи в структуру repo : %s", err.Error())
errs = append(errs, err)
}
repos = append(repos, repo)
}
}
return repos, errs
}
func getDciOsTemplatesDB(ispDbName string, runningSql runningSqlServer, platformStruct outputPlatformStruct) ([]osTemplate, []error) {
var ispRepSlice []string
for _, r := range platformStruct.Repos {
if strings.Contains(r.Url, "download.ispsystem.com") {
ispRepSlice = append(ispRepSlice, strconv.Itoa(r.Id))
}
}
ispRep := strings.Join(ispRepSlice, ",")
var osTemplates []osTemplate
var errs []error
query := "SELECT id,name,filename,macro,metainfo,directory_name,repository,size from dci_os_template where repository not in (" + ispRep + ");"
dbName := "dci_1"
if ispDbName == "isp" {
dbName = ispDbName
}
switch runningSql.Type {
case "mysql":
rows, db, err := mysqlQuery(query, dbName, runningSql)
if err != nil {
err = fmt.Errorf("Ошибка при выполнении запроса к %s.dci_os_template : %s", dbName, err.Error())
errs = append(errs, err)
return osTemplates, errs
}
defer db.Close()
defer rows.Close()
for rows.Next() {
var ostempl osTemplate
err = rows.Scan(&ostempl.Id, &ostempl.Name, &ostempl.Filename, &ostempl.Macro, &ostempl.Metainfo, &ostempl.DirectoryName, &ostempl.Repository, &ostempl.Size)
if err != nil {
err = fmt.Errorf("Ошибка записи в структуру osTemplate : %s", err.Error())
errs = append(errs, err)
}
osTemplates = append(osTemplates, ostempl)
}
case "pgsql":
rows, pool, err := pgsqlQuery(query, dbName, runningSql)
if err != nil {
err = fmt.Errorf("Ошибка при выполнении запроса к %s.dci_os_template : %s", dbName, err.Error())
errs = append(errs, err)
return osTemplates, errs
}
defer pool.Close()
defer rows.Close()
for rows.Next() {
var ostempl osTemplate
err = rows.Scan(&ostempl.Id, &ostempl.Name, &ostempl.Filename, &ostempl.Macro, &ostempl.Metainfo, &ostempl.DirectoryName, &ostempl.Repository, &ostempl.Size)
if err != nil {
err = fmt.Errorf("Ошибка записи в структуру osTemplate : %s", err.Error())
errs = append(errs, err)
}
osTemplates = append(osTemplates, ostempl)
}
}
return osTemplates, errs
}
func getDciRealIpDB(ispDbName string, runningSql runningSqlServer) (realIP, error) {
dbName := "dci_1"
if ispDbName == "isp" {
dbName = ispDbName
}
var ri realIP
var err error
query := "SELECT name, value FROM isp_settings WHERE name = 'trusted_servers';"
switch runningSql.Type {
case "mysql":
// TODO Тут важно проверить, что это хранится в таблице isp_settings в базе dci_1, а не auth Эта таблица есть в обеих базах и там разные настройки
rows, db, err := mysqlQuery(query, dbName, runningSql)
if err != nil {
err = fmt.Errorf("Ошибка запроса к %s.isp_settings : %s", dbName, err.Error())
return ri, err
}
defer db.Close()
defer rows.Close()
for rows.Next() {
var ri realIP
err = rows.Scan(&ri.Name, &ri.Value)
if err != nil {
err = fmt.Errorf("Ошибка записи в структуру realIP : %s", err.Error())
}
}
case "pgsql":
// TODO Тут важно проверить, что это хранится в таблице isp_settings в базе dci_1, а не auth Эта таблица есть в обеих базах и там разные настройки
rows, pool, err := pgsqlQuery(query, dbName, runningSql)
if err != nil {
err = fmt.Errorf("Ошибка запроса к %s.isp_settings : %s", dbName, err.Error())
return ri, err
}
defer pool.Close()
defer rows.Close()
for rows.Next() {
var ri realIP
err = rows.Scan(&ri.Name, &ri.Value)
if err != nil {
err = fmt.Errorf("Ошибка записи в структуру realIP : %s", err.Error())
}
}
}
return ri, err
}
func getDciBackupTask(ispDbName string, runningSql runningSqlServer) ([]backupTask, []error) {
var bts []backupTask
var errs []error
dbName := "auth"
if ispDbName == "isp" {
dbName = ispDbName
}
query := "SELECT id,enabled,cron_expression,limit_count,limit_size_mib FROM backup_task;"
switch runningSql.Type {
case "mysql":
rows, db, err := mysqlQuery(query, dbName, runningSql)
if err != nil {
err = fmt.Errorf("Ошибка запроса к %s.backup_task : %s", dbName, err)
errs = append(errs, err)
return bts, errs
}
defer db.Close()
defer rows.Close()
for rows.Next() {
var bt backupTask
err = rows.Scan(&bt.Id, &bt.Enabled, &bt.CronExpression, &bt.LimitCount, &bt.LimitSizeMib)
if err != nil {
err = fmt.Errorf("Ошибка записи в структуру backupTask : %s", err.Error())
}
bts = append(bts, bt)
}
case "pgsql":
rows, pool, err := pgsqlQuery(query, dbName, runningSql)
if err != nil {
err = fmt.Errorf("Ошибка запроса к %s.backup_task : %s", dbName, err)
errs = append(errs, err)
return bts, errs
}
defer pool.Close()
defer rows.Close()
for rows.Next() {
var bt backupTask
err = rows.Scan(&bt.Id, &bt.Enabled, &bt.CronExpression, &bt.LimitCount, &bt.LimitSizeMib)
if err != nil {
err = fmt.Errorf("Ошибка записи в структуру backupTask : %s", err.Error())
}
bts = append(bts, bt)
}
}
return bts, errs
}

View File

@@ -0,0 +1,6 @@
package main
type license struct {
LicenseCheck string `json:"license_check"`
LicenseInfo string `json:"license_info"`
}

View File

@@ -0,0 +1,165 @@
package main
type biosInfo struct {
Name string `json:"name"`
}
type operatingSystem struct {
OsRelease string `json:"os_name"`
AstraVersion string `json:"astra_version"`
AstraLicense string `json:"astra_license"`
}
type installedPackage struct {
Name string `json:"name"`
Version string `json:"version"`
}
type fsInfo struct {
MountPointDevice string `json:"mount_point_devices"`
MountPointOsPath string `json:"mount_point_os_path"`
MountPointSize uint64 `json:"mount_point_size"`
MountPointFree uint64 `json:"mount_point_free"`
}
type loadAverage struct {
OneMin string `json:"la_onemin"`
FiveMin string `json:"la_fivemin"`
FifteenMin string `json:"la_fifteenmin"`
Processes string `json:"la_processes"`
}
// type cpu struct {
// Model []string `json:"model"`
// }
type cpu struct {
VendorId string `json:"vendor_id"`
CpuFamily string `json:"cpu_family"`
Model string `json:"model"`
ModelName string `json:"model_name"`
Stepping string `json:"stepping"`
Microcode string `json:"microcode"`
CpuMhz string `json:"cpu_mhz"`
CacheSize string `json:"cache_size"`
PhysicalId string `json:"phusical_id"`
CpuCores string `json:"cpu_cores"`
Flags string `json:"flags"`
Bugs string `json:"bugs"`
Bogomips string `json:"bogomips"`
TlbSize string `json:"tlb_size"`
ClflushSize string `json:"clflush_size"`
CacheAlignment string `json:"cache_alignment"`
AddressSize string `json:"address_size"`
PowerManagement string `json:"power_management"`
}
type ram struct {
MemTotal string `json:"mem_total"`
MemFree string `json:"mem_free"`
MemAvailable string `json:"mem_available"`
}
type uptime struct {
WorkSeconds string `json:"work_seconds"`
}
type timeService struct {
TimeService string `json:"time_service"`
TimeSync string `json:"time_sync"`
}
type journalctlEntry struct {
Timestamp string `json:"__REALTIME_TIMESTAMP"`
CommandLine string `json:"_CMDLINE"`
CommandName string `json:"_COMM"`
SyslogIdentifier string `json:"SYSLOG_IDENTIFIER"`
Message string `json:"MESSAGE"`
}
type firewalls struct {
Ufw string `json:"ufw"`
Nftables string `json:"nftables"`
Iptables string `json:"iptables"`
Firewalld string `json:"firewalld"`
}
type netInterface struct {
Device string `json:"device"`
Flags string `json:"flags"`
HwAddr string `json:"hardware_address"`
IpAddr []string `json:"ip_addr"`
Index string `json:"index"`
MTU string `json:"mtu"`
}
type networkConfig struct {
NetInterfaces []netInterface `json:"net_interfaces"`
NetworkManager string `json:"networkmanager"`
NetworkManagerConn []string `json:"networkmanager_conn"`
Networking string `json:"networking"`
EtcHosts []string `json:"etc_hosts"`
}
type internetResource struct {
Name string `json:"name"`
Http string `json:"http"`
Https string `json:"https"`
IpList string `json:"ip_list"`
}
type secSetALSE struct {
Apparmor string `json:"apparmor"`
Selinux string `json:"selinux"`
Parsec string `json:"parsec"`
Mic string `json:"astra_mic"`
Mac string `json:"astra_mac"`
Digsig string `json:"digsig"`
Sudo string `json:"sudo"`
Nochmodx string `json:"nochmodx"`
Interpret string `json:"interpret"`
SudoersAstraAdmin string `json:"sudoers_astraadmin"`
SudoersSudo string `json:"sudoers_sudo"`
AstraAdmin string `json:"astra-admin"`
}
type secSetUbuntu struct {
Apparmor string `json:"apparmor"`
}
type secSetAlma struct {
Selinux string `json:"selinux"`
}
type dockerPs struct {
Id string `json:"id"`
Image string `json:"image"`
Names []string `json:"names"`
Created int64 `json:"running_for"`
State string `json:"state"`
Status string `json:"status"`
// Health string `json:"health"`
}
type dockerStats struct {
BlockIO string `json:"BlockIO"`
CPUPerc string `json:"CPUPerc"`
Container string `json:"Container"`
ID string `json:"ID"`
MemPerc string `json:"MemPerc"`
MemUsage string `json:"MemUsage"`
Name string `json:"Name"`
NetIO string `json:"NetIO"`
PIDs string `json:"PIDs"`
}
type dockerSupervisor struct {
Id string `json:"id"`
Name string `json:"name"`
SupStatus string `json:"sup_status"`
}
type rootHistoryCommand struct {
Id int `json:"id"`
ExecutionTime string `json:"excution_time"`
Command string `json:"command"`
}

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
}

View File

@@ -0,0 +1,121 @@
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"os"
"os/exec"
"strings"
"github.com/moby/moby/client"
)
func getDockerPsA() ([]dockerPs, error) {
var dps []dockerPs
var err error
//
apiClient, err := client.New(client.FromEnv)
if err != nil {
err = fmt.Errorf("Ошибка при создании docker клиента %s", err)
return dps, err
}
defer apiClient.Close()
containers, err := apiClient.ContainerList(context.Background(), client.ContainerListOptions{All: true})
if err != nil {
err = fmt.Errorf("Ошибка получения списка контейнеров : %s", err)
return dps, err
}
for _, ctr := range containers.Items {
var dp dockerPs
dp.Id = ctr.ID
dp.Image = ctr.Image
dp.Names = ctr.Names
dp.Created = ctr.Created
dp.State = string(ctr.State)
dp.Status = ctr.Status
// dp.Health = string(ctr.Health.Status)
dps = append(dps, dp)
}
return dps, err
}
func getDockerStats() ([]dockerStats, error) {
var ds []dockerStats
var err error
cmd := exec.Command("docker", "stats", "-a", "--no-stream", "--format", "{{ json . }}")
output, err := cmd.Output()
if err != nil {
err = fmt.Errorf("Ошибка выполнения docker stats -a --format \"{{ json . }}\"")
return ds, err
}
for _, stat := range strings.Split(strings.TrimSpace(string(output)), "\n") {
var docS dockerStats
if stat == "" {
continue
}
buf := bytes.NewBuffer([]byte(stat))
err := json.NewDecoder(buf).Decode(&docS)
if err != nil {
err = fmt.Errorf("Ошибка десериализации переменной %v в строке %s", err, stat)
return ds, err
}
ds = append(ds, docS)
}
return ds, err
}
func getDockerSupervisordLog(outputServerStruct outputServerStruct, outDir string) ([]dockerSupervisor, []error) {
var dS []dockerSupervisor
var errs []error
for _, d := range outputServerStruct.DockerStats {
dSup := dockerSupervisor{
Id: d.ID,
Name: d.Name,
}
// 1. Ищем supervisord.log
cmd := exec.Command("docker", "exec", d.Name, "bash", "-c", "find / -name supervisord.log 2>/dev/null | head -1")
output, err := cmd.Output()
if err != nil || len(output) == 0 {
errs = append(errs, fmt.Errorf("supervisord.log не найден в контейнере %s", d.Name))
dS = append(dS, dSup)
continue
}
// Очищаем путь от пробелов и переносов
logPath := strings.TrimSpace(string(output))
// 2. Читаем содержимое файла
cmd = exec.Command("docker", "exec", d.Name, "bash", "-c", fmt.Sprintf("cat %s", logPath))
logContent, err := cmd.Output()
if err != nil {
errs = append(errs, fmt.Errorf("ошибка чтения supervisord.log в %s: %s", d.Name, err.Error()))
} else {
// Сохраняем лог в файл
supervisordLogFile := fmt.Sprintf("%s/%s_supervisord.log", outDir, d.Name)
if err := os.WriteFile(supervisordLogFile, logContent, 0644); err != nil {
errs = append(errs, fmt.Errorf("ошибка записи лога %s: %s", d.Name, err.Error()))
}
}
// 3. Получаем supervisorctl status
cmd = exec.Command("docker", "exec", d.Name, "bash", "-c", "supervisorctl status")
status, err := cmd.Output()
if err != nil {
errs = append(errs, fmt.Errorf("ошибка supervisorctl status в %s: %s", d.Name, err.Error()))
} else {
dSup.SupStatus = string(status)
}
dS = append(dS, dSup)
}
return dS, errs
}

View File

@@ -0,0 +1,60 @@
package main
import (
"fmt"
"os"
"os/exec"
"strconv"
"strings"
)
// для всех обычных фаерволов хватит двух команд
// iptables --version если в ответе есть nf_tables (а это почти 100% случаев теперь), то просто команда
// nft -j list ruleset
// в ином случае можно добавить iptables -L
// довольно сложный json, быстро у меня не получится его разоброать. Временно, я заберу просто вывод без json построчно
// и так же, построчно отображу в читалке. Там даже в простом варианте из убунты, где их никто не настраивал, 590 строк.
// значит пока что структура nfrRuleset
// type nftRuleset struct {
// Lines []string
// }
//
func getNftRuleset(dirName string) (nftRuleset, []error) {
var rules nftRuleset
var errs []error
cmd := exec.Command("nft", "list", "ruleset")
output, err := cmd.Output()
if err != nil {
err = fmt.Errorf("Ошибка при выполнении команды fmt list ruleset : %v", err)
errs = append(errs, err)
return rules, errs
}
i := 0
rulesFile, err := os.Create(dirName + "/nftListRuleset.txt")
if err != nil {
err = fmt.Errorf("Ошибка создания файла nftListRuleset.txt : %v", err)
errs = append(errs, err)
for line := range strings.SplitSeq(string(output), "\n") {
line = strconv.Itoa(i) + " " + strings.TrimSpace(line)
rules.Lines = append(rules.Lines, line)
i += 1
}
} else {
for line := range strings.SplitSeq(string(output), "\n") {
line = strings.TrimSpace(line) + "\n"
_, err := rulesFile.WriteString(line)
if err != nil {
err = fmt.Errorf("Ошибка при записи в файл nftListRuleset.txt")
errs = append(errs, err)
}
line = strconv.Itoa(i) + " " + strings.TrimSpace(line)
rules.Lines = append(rules.Lines, line)
i += 1
}
}
defer rulesFile.Close()
return rules, errs
}

View File

@@ -0,0 +1,8 @@
package main
// я расчитываю в дальнейшем вернуться к этому. Json структура nftables непростая, поэтому я или разгадаю сам как её анмаршалить, или сопру из одной из двух библиотек на гитхабе. Или вообще их заиспользую.
// пока что просто построчно выведу правила nft list ruleset
type nftRuleset struct {
Lines []string `json:"lines"`
}

View File

@@ -0,0 +1,257 @@
package main
import (
"errors"
"fmt"
"os"
"os/exec"
"os/user"
"regexp"
"strings"
)
// - Безопасность
//
// ALSE
//
// parsec
// astra-mic-control status
// astra-mac-control status
//
// astra-digsig-control status
// astra-sudo-control status
// astra-nochmodx-lock status
// astra-interpreters-lock status
// etc/sudoers %astra-admin ALL=(ALL:ALL) NOPASSWD: ALL %sudo ALL=(ALL:ALL) NOPASSWD: ALL
// группу astra-admin
// TODO команды astra-... status нужно проверить в файлах директории /parsecfs/
func getSecSettingsAlse() (secSetALSE, []error) {
var secSet secSetALSE
var errs []error
//apparmor
// parsec
runSystemd, err := os.ReadDir("/run/systemd/units")
if err != nil {
err = fmt.Errorf("Ошибка чтения директории /run/systemd/units: %s", err)
errs = append(errs, err)
err = nil
}
for _, run := range runSystemd {
matchedPars, _ := regexp.Match("parsec", []byte(run.Name()))
if matchedPars {
secSet.Parsec = "active"
}
matchedApparm, _ := regexp.Match("apparmor", []byte(run.Name()))
if matchedApparm {
secSet.Apparmor = "active"
}
}
// selinux
if _, err := os.Stat("/etc/selinux/config"); errors.Is(err, os.ErrNotExist) {
secSet.Selinux = "notexist"
} else {
seFile, err := os.ReadFile("/etc/selinux/config")
if err != nil {
err = fmt.Errorf("Ошибка. Файл selinux conf существует, но не может быть прочитан: %s", err)
errs = append(errs, err)
err = nil
}
sestatus := 0
for _, sf := range strings.Split(string(seFile), "\n") {
matchedConfig, _ := regexp.Match(sf, []byte("byteSELINUX=disabled"))
if matchedConfig {
secSet.Selinux = "disabled"
sestatus = 1
}
}
if sestatus == 0 {
secSet.Selinux = "enabled"
}
}
// astra-mic-control status
cmd := exec.Command("astra-mic-control", "is-enabled")
mic, err := cmd.Output()
if err != nil {
err = fmt.Errorf("Ошибка выполнения astra-mic-control is-enabled : %s", err)
errs = append(errs, err)
err = nil
}
secSet.Mic = string(mic)
// astra-mac-control status
cmd = exec.Command("astra-mac-control", "is-enabled")
mac, err := cmd.Output()
if err != nil {
err = fmt.Errorf("Ошибка выполнения astra-mac-control is-enabled : %s", err)
errs = append(errs, err)
err = nil
}
secSet.Mac = string(mac)
// astra-digsig-control status
if _, err := os.Stat("/etc/digsig/digsig_initramfs.conf"); errors.Is(err, os.ErrNotExist) {
secSet.Digsig = "file notexist"
} else {
f, err := os.ReadFile("/etc/digsig/digsig_initramfs.conf")
if err != nil {
err = fmt.Errorf("Ошибка. Файл digsig_initramfs.conf существует, но не может быть прочитан: %s", err)
errs = append(errs, err)
}
i := 0
for _, sf := range strings.Split(string(f), "\n") {
matchedConfig, _ := regexp.Match(sf, []byte("DIGSIG_ELF_MODE=0"))
if matchedConfig {
secSet.Digsig = "disabled"
i = 1
}
}
if i == 0 {
secSet.Digsig = "enabled"
}
}
// astra-sudo-control status
cmd = exec.Command("astra-sudo-control", "is-enabled")
sudo, err := cmd.Output()
if err != nil {
err = fmt.Errorf("Ошибка выполнения astra-sudo-control is-enabled : %s", err)
errs = append(errs, err)
err = nil
}
secSet.Sudo = string(sudo)
// astra-nochmodx-lock status
cmd = exec.Command("astra-nochmodx-control", "is-enabled")
nochmodx, err := cmd.Output()
if err != nil {
err = fmt.Errorf("Ошибка выполнения astra-nochmodx-control is-enabled : %s", err)
errs = append(errs, err)
err = nil
}
secSet.Nochmodx = string(nochmodx)
// astra-interpreters-lock status
cmd = exec.Command("astra-nochmodx-control", "is-enabled")
interpret, err := cmd.Output()
if err != nil {
err = fmt.Errorf("Ошибка выполнения astra-interpreters-lock is-enabled : %s", err)
errs = append(errs, err)
err = nil
}
secSet.Interpret = string(interpret)
// etc/sudoers %astra-admin ALL=(ALL:ALL) NOPASSWD: ALL %sudo ALL=(ALL:ALL) NOPASSWD: ALL
if _, err = os.Stat("/etc/sudoers"); errors.Is(err, os.ErrNotExist) {
secSet.SudoersAstraAdmin = "file notexist"
} else {
f, err := os.ReadFile("/etc/sudoers")
if err != nil {
err = fmt.Errorf("Ошибка чтения файла etc sudoers: %s", err)
errs = append(errs, err)
err = nil
} else {
i := 0
for _, sf := range strings.Split(string(f), "\n") {
matchedConfig, _ := regexp.Match(sf, []byte("%astra-admin ALL=(ALL:ALL) NOPASSWD: ALL"))
if matchedConfig {
secSet.SudoersAstraAdmin = "astra-admin nopass"
i = 1
}
}
if i == 0 {
secSet.SudoersAstraAdmin = "astra-admin notnopass"
}
}
}
// etc/sudoers %sudo ALL=(ALL:ALL) NOPASSWD: ALL
if _, err = os.Stat("/etc/sudoers"); errors.Is(err, os.ErrNotExist) {
secSet.SudoersAstraAdmin = "file notexist"
} else {
f, err := os.ReadFile("/etc/sudoers")
if err != nil {
err = fmt.Errorf("Ошибка чтения файла etc sudoers: %s", err)
errs = append(errs, err)
err = nil
} else {
i := 0
for _, sf := range strings.Split(string(f), "\n") {
matchedConfig, _ := regexp.Match(sf, []byte("%sudo ALL=(ALL:ALL) NOPASSWD: ALL"))
if matchedConfig {
secSet.SudoersSudo = "sudo nopass"
i = 1
}
}
if i == 0 {
secSet.SudoersSudo = "astra-admin notnopass"
}
}
}
// группу astra-admin
curUser, err := user.Current()
if err != nil {
err = fmt.Errorf("Ошибка получения данных о текущем пользователе: %s", err)
errs = append(errs, err)
err = nil
}
curUserGroups, err := curUser.GroupIds()
if err != nil {
err = fmt.Errorf("Ошибка получения групп текущего пользователя: %s", err)
errs = append(errs, err)
err = nil
}
for _, grpId := range curUserGroups {
grp, err := user.LookupGroupId(grpId)
if err != nil {
err = fmt.Errorf("Ошибка получения информации о группе: %s", err)
errs = append(errs, err)
err = nil
}
if grp.Name == "astra-admin" {
secSet.SudoersAstraAdmin = "astra-admin"
}
}
return secSet, nil
}
// Ubuntu apparmor
func getSecSettingsUbuntu() (secSetUbuntu, error) {
var secSetUbuntu secSetUbuntu
runSystemd, err := os.ReadDir("/run/systemd/units")
if err != nil {
err = fmt.Errorf("Ошибка чтения директории /run/systemd/units: %s", err)
return secSetUbuntu, err
}
for _, run := range runSystemd {
matched, _ := regexp.Match("apparmor", []byte(run.Name()))
if matched {
fmt.Println(run.Name())
secSetUbuntu.Apparmor = "active"
}
}
return secSetUbuntu, nil
}
// Almalinux selinux
func getSecSettingsAlma() (secSetAlma, error) {
var secSetAlma secSetAlma
if _, err := os.Stat("/etc/selinux/config"); errors.Is(err, os.ErrNotExist) {
secSetAlma.Selinux = "notexist"
} else {
seFile, err := os.ReadFile("/etc/selinux/config")
if err != nil {
err = fmt.Errorf("Ошибка. Файл selinux conf существует, но не может быть прочитан: %s", err)
return secSetAlma, err
}
sestatus := 0
for _, sf := range strings.Split(string(seFile), "\n") {
matchedConfig, _ := regexp.Match("SELINUX=disabled", []byte(sf))
if matchedConfig {
secSetAlma.Selinux = "disabled"
sestatus = 1
}
}
if sestatus == 0 {
secSetAlma.Selinux = "enabled"
}
}
return secSetAlma, nil
}

View File

@@ -0,0 +1,172 @@
package main
import (
"context"
"database/sql"
"fmt"
"regexp"
"strings"
_ "github.com/go-sql-driver/mysql"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/moby/moby/client"
)
type runningSqlServer struct {
Type string `json:"type"`
IPaddr string `json:"ipaddr"`
Password string `json:"password"`
}
func getRunningSqlServer() (runningSqlServer, error) {
var runningSql runningSqlServer
// запущенный контейнер sql
apiClient, err := client.New(client.FromEnv)
if err != nil {
err = fmt.Errorf("Ошибка при создании docker клиента %s", err)
return runningSql, err
}
defer apiClient.Close()
// пробуем этот метод!
ctx := context.Background()
containers, err := apiClient.ContainerList(ctx, client.ContainerListOptions{All: true})
if err != nil {
err = fmt.Errorf("Ошибка получения списка контейнеров : %s", err)
return runningSql, err
}
for _, ctr := range containers.Items {
// println(ctr.Names[0])
if ctr.Names[0] == "/mysql" {
runningSql.Type = "mysql"
for _, nets := range ctr.NetworkSettings.Networks {
runningSql.IPaddr = nets.IPAddress.String()
}
cont, err := apiClient.ContainerInspect(ctx, ctr.ID, client.ContainerInspectOptions{})
if err != nil {
return runningSql, err
}
for _, e := range cont.Container.Config.Env {
matched, _ := regexp.Match("PASSWORD", []byte(e))
if matched {
runningSql.Password = strings.Split(e, "=")[1]
}
}
} else if ctr.Names[0] == "/pgsql" {
runningSql.Type = "pgsql"
for _, nets := range ctr.NetworkSettings.Networks {
runningSql.IPaddr = nets.IPAddress.String()
}
cont, err := apiClient.ContainerInspect(ctx, ctr.ID, client.ContainerInspectOptions{})
if err != nil {
return runningSql, err
}
for _, e := range cont.Container.Config.Env {
matched, _ := regexp.Match("POSTGRES_PASSWORD", []byte(e))
if matched {
runningSql.Password = strings.Split(e, "=")[1]
}
}
}
}
return runningSql, nil
}
func checkIspDbname(runningSql runningSqlServer) (string, error) {
var dbname string
var dbnames []string
query := "SELECT datname FROM pg_database;"
rows, pool, err := pgsqlQuery(query, "postgres", runningSql)
defer pool.Close()
defer rows.Close()
if err != nil {
err = fmt.Errorf("Ошибка выполнения запроса к таблице postgres : %s", err.Error())
return dbname, err
} else {
for rows.Next() {
var db string
err = rows.Scan(&db)
if err != nil {
err = fmt.Errorf("Ошибка сканирования результатов запроса списка баз данных : %s", err.Error())
return dbname, err
// continue
}
dbnames = append(dbnames, db)
}
}
// if rows != nil {
// rows.Close()
// }
for _, d := range dbnames {
if d == "isp" {
dbname = "isp"
}
}
return dbname, nil
}
// func pgsqlQuery(query, dbname string, runningSql runningSqlServer) (pgx.Rows, error) {
// dsn := "postgres://root:" + runningSql.Password + "@" + runningSql.IPaddr + ":5432/" + dbname
// connect, err := pgx.Connect(context.Background(), dsn)
// err = connect.Ping(context.Background())
// if err != nil {
// return nil, err
// }
// result, err := connect.Query(context.Background(), query)
// if err != nil {
// err = fmt.Errorf("Ошибка выполнения запроса к БД: %s", err)
// return result, err
// }
// defer connect.Close(context.Background())
// return result, nil
// }
func pgsqlQuery(query, dbname string, runningSql runningSqlServer) (pgx.Rows, *pgxpool.Pool, error) {
dsn := "postgres://root:" + runningSql.Password + "@" + runningSql.IPaddr + ":5432/" + dbname
pool, err := pgxpool.New(context.Background(), dsn)
if err != nil {
return nil, nil, err
}
rows, err := pool.Query(context.Background(), query)
if err != nil {
pool.Close()
return nil, nil, fmt.Errorf("Ошибка выполнения запроса к БД: %s", err)
}
return rows, pool, nil
}
func mysqlQuery(query, dbname string, runningSql runningSqlServer) (*sql.Rows, *sql.DB, error) {
dsn := "root:" + runningSql.Password + "@tcp(" + runningSql.IPaddr + ":3306)/" + dbname
db, err := sql.Open("mysql", dsn)
if err != nil {
return nil, nil, err
}
if err := db.Ping(); err != nil {
err = fmt.Errorf("Ошибка проверки подключения к БД mysql: %s", err)
db.Close()
return nil, nil, err
}
result, err := db.Query(query)
if err != nil {
err = fmt.Errorf("Ошибка выполнения запроса %s: %s", query, err)
db.Close()
return nil, nil, err
}
return result, db, nil
}

View File

@@ -0,0 +1,2 @@
## 2602-3
TODO найти куда падают ошибки опроса комплектующих. в dci_server_component_error пусто