Files
kor-elf-shield/internal/daemon/docker_monitor/client/docker.go
Leonid Nikitin b9719f7eaf Add Docker event monitoring and chain clearing functionality
- Introduced `Events` method in Docker client to stream and handle Docker events.
- Added `Clear` method to nftables chain interface for clearing rules.
- Enhanced daemon lifecycle to include Docker event monitoring when Docker support is enabled.
- Updated nftables rule management with event-driven chain clearing and reloading.
2026-01-04 16:06:01 +05:00

159 lines
3.2 KiB
Go

package client
import (
"bufio"
"context"
"fmt"
"os/exec"
"git.kor-elf.net/kor-elf-shield/kor-elf-shield/internal/log"
)
type Docker interface {
FetchBridges() (Bridges, error)
FetchContainers(bridgeID string) (Containers, error)
Bridges() ([]string, error)
BridgeNames() ([]string, error)
BridgeName(bridgeID string) (string, error)
BridgeSubnet(bridgeID string) (string, error)
Containers(bridgeID string) ([]string, error)
ContainerNetworks(containerID string) (DockerContainerInspect, error)
Events() (<-chan string, <-chan error)
}
type docker struct {
path string
ctx context.Context
logger log.Logger
}
func NewDocker(path string, ctx context.Context, logger log.Logger) Docker {
return &docker{
path: path,
ctx: ctx,
logger: logger,
}
}
func (d *docker) FetchBridges() (Bridges, error) {
bridges := Bridges{}
list, err := d.Bridges()
if err != nil {
return nil, err
}
for _, bridgeId := range list {
bridgeName, err := d.BridgeName(bridgeId)
if err != nil {
d.logger.Error(err.Error())
continue
}
bridgeSubnet, err := d.BridgeSubnet(bridgeId)
if err != nil {
d.logger.Error(err.Error())
continue
}
var containers Containers
containers, err = d.FetchContainers(bridgeId)
if err != nil {
d.logger.Error(err.Error())
}
bridges = append(bridges, Bridge{
ID: bridgeId,
Name: bridgeName,
Subnet: bridgeSubnet,
Containers: containers,
})
}
return bridges, nil
}
func (d *docker) FetchContainers(bridgeID string) (Containers, error) {
containers := Containers{}
list, err := d.Containers(bridgeID)
if err != nil {
return nil, err
}
for _, containerID := range list {
info, err := d.ContainerNetworks(containerID)
if err != nil {
d.logger.Error(err.Error())
continue
}
networks := ContainerNetworks{
IPAddresses: []IPInfo{},
Ports: d.parsePorts(info),
}
for _, networkData := range info.NetworkSettings.Networks {
if networkData.IPAddress != "" {
ipVesion, err := ipVersion(networkData.IPAddress)
if err != nil {
d.logger.Error(err.Error())
continue
}
networks.IPAddresses = append(networks.IPAddresses, IPInfo{Address: networkData.IPAddress, Version: ipVesion})
}
}
containers = append(containers, Container{
ID: containerID,
Networks: networks,
})
}
return containers, nil
}
func (d *docker) command(args ...string) ([]byte, error) {
cmd := exec.CommandContext(d.ctx, d.path, args...)
result, err := cmd.CombinedOutput()
if err != nil {
return nil, fmt.Errorf(string(result))
}
return result, nil
}
func (d *docker) Events() (<-chan string, <-chan error) {
eventsChan := make(chan string)
errChan := make(chan error)
go func() {
defer close(eventsChan)
defer close(errChan)
args := []string{
"events",
"--filter", "type=container",
"--filter", "event=start",
"--filter", "event=die",
"--format",
"{{json .}}",
}
cmd := exec.CommandContext(d.ctx, "docker", args...)
stdout, err := cmd.StdoutPipe()
if err != nil {
errChan <- err
return
}
if err := cmd.Start(); err != nil {
errChan <- err
return
}
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
eventsChan <- scanner.Text()
}
}()
return eventsChan, errChan
}