2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 11:27:17 +08:00
Files
panel/internal/data/container_network.go
2024-10-27 19:23:22 +08:00

169 lines
5.0 KiB
Go

package data
import (
"encoding/json"
"fmt"
"strings"
"time"
"github.com/spf13/cast"
"github.com/TheTNB/panel/internal/biz"
"github.com/TheTNB/panel/internal/http/request"
"github.com/TheTNB/panel/pkg/shell"
"github.com/TheTNB/panel/pkg/types"
)
type containerNetworkRepo struct {
cmd string
}
func NewContainerNetworkRepo(cmd ...string) biz.ContainerNetworkRepo {
if len(cmd) == 0 {
cmd = append(cmd, "docker")
}
return &containerNetworkRepo{
cmd: cmd[0],
}
}
// List 列出网络
func (r *containerNetworkRepo) List() ([]types.ContainerNetwork, error) {
output, err := shell.ExecfWithTimeout(10*time.Second, "%s network ls --format json", r.cmd)
if err != nil {
return nil, err
}
lines := strings.Split(output, "\n")
var networks []types.ContainerNetwork
for _, line := range lines {
if line == "" {
continue
}
var item struct {
CreatedAt string `json:"CreatedAt"`
Driver string `json:"Driver"`
ID string `json:"ID"`
IPv6 string `json:"IPv6"`
Internal string `json:"Internal"`
Labels string `json:"Labels"`
Name string `json:"Name"`
Scope string `json:"Scope"`
}
if err = json.Unmarshal([]byte(line), &item); err != nil {
return nil, fmt.Errorf("unmarshal failed: %w", err)
}
output, err = shell.ExecfWithTimeout(10*time.Second, "%s network inspect %s", r.cmd, item.ID)
if err != nil {
return nil, fmt.Errorf("inspect failed: %w", err)
}
var inspect []struct {
Name string `json:"Name"`
Id string `json:"Id"`
Created time.Time `json:"Created"`
Scope string `json:"Scope"`
Driver string `json:"Driver"`
EnableIPv6 bool `json:"EnableIPv6"`
IPAM struct {
Driver string `json:"Driver"`
Options map[string]string `json:"Options"`
Config []struct {
Subnet string `json:"Subnet"`
IPRange string `json:"IPRange"`
Gateway string `json:"Gateway"`
AuxAddress map[string]string `json:"AuxiliaryAddresses"`
} `json:"Config"`
} `json:"IPAM"`
Internal bool `json:"Internal"`
Attachable bool `json:"Attachable"`
Ingress bool `json:"Ingress"`
ConfigOnly bool `json:"ConfigOnly"`
Options map[string]string `json:"Options"`
Labels map[string]string `json:"Labels"`
}
if err = json.Unmarshal([]byte(output), &inspect); err != nil {
return nil, fmt.Errorf("unmarshal inspect failed: %w", err)
}
if len(inspect) == 0 {
return nil, fmt.Errorf("inspect empty")
}
var ipamConfigs []types.ContainerNetworkIPAMConfig
for _, ipam := range inspect[0].IPAM.Config {
ipamConfigs = append(ipamConfigs, types.ContainerNetworkIPAMConfig{
Subnet: ipam.Subnet,
IPRange: ipam.IPRange,
Gateway: ipam.Gateway,
AuxAddress: ipam.AuxAddress,
})
}
createdAt, _ := time.Parse("2006-01-02 15:04:05 -0700 MST", item.CreatedAt)
networks = append(networks, types.ContainerNetwork{
ID: item.ID,
Name: item.Name,
Driver: item.Driver,
IPv6: cast.ToBool(item.IPv6),
Internal: cast.ToBool(item.Internal),
Attachable: cast.ToBool(inspect[0].Attachable),
Ingress: cast.ToBool(inspect[0].Ingress),
Scope: item.Scope,
CreatedAt: createdAt,
IPAM: types.ContainerNetworkIPAM{
Driver: inspect[0].IPAM.Driver,
Options: types.MapToKV(inspect[0].IPAM.Options),
Config: ipamConfigs,
},
Options: types.MapToKV(inspect[0].Options),
Labels: types.SliceToKV(strings.Split(item.Labels, ",")),
})
}
return networks, nil
}
// Create 创建网络
func (r *containerNetworkRepo) Create(req *request.ContainerNetworkCreate) (string, error) {
var sb strings.Builder
sb.WriteString(fmt.Sprintf("%s network create --driver %s", r.cmd, req.Driver))
sb.WriteString(fmt.Sprintf(" %s", req.Name))
if req.Ipv4.Enabled {
sb.WriteString(fmt.Sprintf(" --subnet %s", req.Ipv4.Subnet))
sb.WriteString(fmt.Sprintf(" --gateway %s", req.Ipv4.Gateway))
if req.Ipv4.IPRange != "" {
sb.WriteString(fmt.Sprintf(" --ip-range %s", req.Ipv4.IPRange))
}
}
if req.Ipv6.Enabled {
sb.WriteString(fmt.Sprintf(" --subnet %s", req.Ipv6.Subnet))
sb.WriteString(fmt.Sprintf(" --gateway %s", req.Ipv6.Gateway))
if req.Ipv6.IPRange != "" {
sb.WriteString(fmt.Sprintf(" --ip-range %s", req.Ipv6.IPRange))
}
}
for _, label := range req.Labels {
sb.WriteString(fmt.Sprintf(" --label %s=%s", label.Key, label.Value))
}
for _, option := range req.Options {
sb.WriteString(fmt.Sprintf(" --opt %s=%s", option.Key, option.Value))
}
return shell.ExecfWithTimeout(10*time.Second, "%s", sb.String()) // nolint: govet
}
// Remove 删除网络
func (r *containerNetworkRepo) Remove(id string) error {
_, err := shell.ExecfWithTimeout(10*time.Second, "%s network rm -f %s", r.cmd, id)
return err
}
// Prune 清理未使用的网络
func (r *containerNetworkRepo) Prune() error {
_, err := shell.ExecfWithTimeout(10*time.Second, "%s network prune -f", r.cmd)
return err
}