mirror of
https://github.com/yusing/godoxy.git
synced 2026-04-23 16:58:31 +02:00
feat: docker over tls (#178)
This commit is contained in:
@@ -28,21 +28,21 @@ func GetContainer(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dockerHost, ok := docker.GetDockerHostByContainerID(id)
|
dockerCfg, ok := docker.GetDockerCfgByContainerID(id)
|
||||||
if !ok {
|
if !ok {
|
||||||
c.JSON(http.StatusNotFound, apitypes.Error("container not found"))
|
c.JSON(http.StatusNotFound, apitypes.Error("container not found"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := docker.NewClient(dockerHost)
|
dockerClient, err := docker.NewClient(dockerCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Error(apitypes.InternalServerError(err, "failed to create docker client"))
|
c.Error(apitypes.InternalServerError(err, "failed to create docker client"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
defer client.Close()
|
defer dockerClient.Close()
|
||||||
|
|
||||||
cont, err := client.ContainerInspect(c.Request.Context(), id)
|
cont, err := dockerClient.ContainerInspect(c.Request.Context(), id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Error(apitypes.InternalServerError(err, "failed to inspect container"))
|
c.Error(apitypes.InternalServerError(err, "failed to inspect container"))
|
||||||
return
|
return
|
||||||
@@ -54,7 +54,7 @@ func GetContainer(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, &Container{
|
c.JSON(http.StatusOK, &Container{
|
||||||
Server: dockerHost,
|
Server: dockerCfg.URL,
|
||||||
Name: cont.Name,
|
Name: cont.Name,
|
||||||
ID: cont.ID,
|
ID: cont.ID,
|
||||||
Image: cont.Image,
|
Image: cont.Image,
|
||||||
|
|||||||
@@ -57,13 +57,13 @@ func Logs(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement levels
|
// TODO: implement levels
|
||||||
dockerHost, ok := docker.GetDockerHostByContainerID(id)
|
dockerCfg, ok := docker.GetDockerCfgByContainerID(id)
|
||||||
if !ok {
|
if !ok {
|
||||||
c.JSON(http.StatusNotFound, apitypes.Error(fmt.Sprintf("container %s not found", id)))
|
c.JSON(http.StatusNotFound, apitypes.Error(fmt.Sprintf("container %s not found", id)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dockerClient, err := docker.NewClient(dockerHost)
|
dockerClient, err := docker.NewClient(dockerCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Error(apitypes.InternalServerError(err, "failed to get docker client"))
|
c.Error(apitypes.InternalServerError(err, "failed to get docker client"))
|
||||||
return
|
return
|
||||||
@@ -105,7 +105,7 @@ func Logs(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Err(err).
|
log.Err(err).
|
||||||
Str("server", dockerHost).
|
Str("server", dockerCfg.URL).
|
||||||
Str("container", id).
|
Str("container", id).
|
||||||
Msg("failed to de-multiplex logs")
|
Msg("failed to de-multiplex logs")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,13 +28,13 @@ func Restart(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dockerHost, ok := docker.GetDockerHostByContainerID(req.ID)
|
dockerCfg, ok := docker.GetDockerCfgByContainerID(req.ID)
|
||||||
if !ok {
|
if !ok {
|
||||||
c.JSON(http.StatusNotFound, apitypes.Error("container not found"))
|
c.JSON(http.StatusNotFound, apitypes.Error("container not found"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := docker.NewClient(dockerHost)
|
client, err := docker.NewClient(dockerCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Error(apitypes.InternalServerError(err, "failed to create docker client"))
|
c.Error(apitypes.InternalServerError(err, "failed to create docker client"))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -34,13 +34,13 @@ func Start(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dockerHost, ok := docker.GetDockerHostByContainerID(req.ID)
|
dockerCfg, ok := docker.GetDockerCfgByContainerID(req.ID)
|
||||||
if !ok {
|
if !ok {
|
||||||
c.JSON(http.StatusNotFound, apitypes.Error("container not found"))
|
c.JSON(http.StatusNotFound, apitypes.Error("container not found"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := docker.NewClient(dockerHost)
|
client, err := docker.NewClient(dockerCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Error(apitypes.InternalServerError(err, "failed to create docker client"))
|
c.Error(apitypes.InternalServerError(err, "failed to create docker client"))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -34,13 +34,13 @@ func Stop(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dockerHost, ok := docker.GetDockerHostByContainerID(req.ID)
|
dockerCfg, ok := docker.GetDockerCfgByContainerID(req.ID)
|
||||||
if !ok {
|
if !ok {
|
||||||
c.JSON(http.StatusNotFound, apitypes.Error("container not found"))
|
c.JSON(http.StatusNotFound, apitypes.Error("container not found"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := docker.NewClient(dockerHost)
|
client, err := docker.NewClient(dockerCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Error(apitypes.InternalServerError(err, "failed to create docker client"))
|
c.Error(apitypes.InternalServerError(err, "failed to create docker client"))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -318,9 +318,9 @@ func (state *state) loadRouteProviders() error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, dockerHost := range providers.Docker {
|
for name, dockerCfg := range providers.Docker {
|
||||||
providersProducer.Go(func() {
|
providersProducer.Go(func() {
|
||||||
providersCh <- route.NewDockerProvider(name, dockerHost)
|
providersCh <- route.NewDockerProvider(name, dockerCfg)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,12 +32,12 @@ type (
|
|||||||
HealthCheck types.HealthCheckConfig `json:"healthcheck"`
|
HealthCheck types.HealthCheckConfig `json:"healthcheck"`
|
||||||
}
|
}
|
||||||
Providers struct {
|
Providers struct {
|
||||||
Files []string `json:"include" yaml:"include,omitempty" validate:"dive,filepath"`
|
Files []string `json:"include" yaml:"include,omitempty" validate:"dive,filepath"`
|
||||||
Docker map[string]string `json:"docker" yaml:"docker,omitempty" validate:"non_empty_docker_keys,dive,unix_addr|url"`
|
Docker map[string]types.DockerProviderConfig `json:"docker" yaml:"docker,omitempty" validate:"non_empty_docker_keys"`
|
||||||
Agents []*agent.AgentConfig `json:"agents" yaml:"agents,omitempty"`
|
Agents []*agent.AgentConfig `json:"agents" yaml:"agents,omitempty"`
|
||||||
Notification []*notif.NotificationConfig `json:"notification" yaml:"notification,omitempty"`
|
Notification []*notif.NotificationConfig `json:"notification" yaml:"notification,omitempty"`
|
||||||
Proxmox []proxmox.Config `json:"proxmox" yaml:"proxmox,omitempty"`
|
Proxmox []proxmox.Config `json:"proxmox" yaml:"proxmox,omitempty"`
|
||||||
MaxMind *maxmind.Config `json:"maxmind" yaml:"maxmind,omitempty"`
|
MaxMind *maxmind.Config `json:"maxmind" yaml:"maxmind,omitempty"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ func init() {
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
serialization.MustRegisterValidation("non_empty_docker_keys", func(fl validator.FieldLevel) bool {
|
serialization.MustRegisterValidation("non_empty_docker_keys", func(fl validator.FieldLevel) bool {
|
||||||
m := fl.Field().Interface().(map[string]string)
|
m := fl.Field().Interface().(map[string]types.DockerProviderConfig)
|
||||||
for k := range m {
|
for k := range m {
|
||||||
if k == "" {
|
if k == "" {
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import (
|
|||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/yusing/godoxy/agent/pkg/agent"
|
"github.com/yusing/godoxy/agent/pkg/agent"
|
||||||
"github.com/yusing/godoxy/internal/common"
|
"github.com/yusing/godoxy/internal/common"
|
||||||
|
"github.com/yusing/godoxy/internal/types"
|
||||||
httputils "github.com/yusing/goutils/http"
|
httputils "github.com/yusing/goutils/http"
|
||||||
"github.com/yusing/goutils/task"
|
"github.com/yusing/goutils/task"
|
||||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||||
@@ -28,6 +29,8 @@ type (
|
|||||||
SharedClient struct {
|
SharedClient struct {
|
||||||
*client.Client
|
*client.Client
|
||||||
|
|
||||||
|
cfg types.DockerProviderConfig
|
||||||
|
|
||||||
refCount atomic.Int32
|
refCount atomic.Int32
|
||||||
closedOn atomic.Int64
|
closedOn atomic.Int64
|
||||||
|
|
||||||
@@ -120,7 +123,7 @@ func Clients() map[string]*SharedClient {
|
|||||||
// Returns:
|
// Returns:
|
||||||
// - Client: the Docker client connection.
|
// - Client: the Docker client connection.
|
||||||
// - error: an error if the connection failed.
|
// - error: an error if the connection failed.
|
||||||
func NewClient(host string, unique ...bool) (*SharedClient, error) {
|
func NewClient(cfg types.DockerProviderConfig, unique ...bool) (*SharedClient, error) {
|
||||||
initClientCleanerOnce.Do(initClientCleaner)
|
initClientCleanerOnce.Do(initClientCleaner)
|
||||||
|
|
||||||
u := false
|
u := false
|
||||||
@@ -128,6 +131,8 @@ func NewClient(host string, unique ...bool) (*SharedClient, error) {
|
|||||||
u = unique[0]
|
u = unique[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
host := cfg.URL
|
||||||
|
|
||||||
if !u {
|
if !u {
|
||||||
clientMapMu.Lock()
|
clientMapMu.Lock()
|
||||||
defer clientMapMu.Unlock()
|
defer clientMapMu.Unlock()
|
||||||
@@ -185,6 +190,10 @@ func NewClient(host string, unique ...bool) (*SharedClient, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg.TLS != nil {
|
||||||
|
opt = append(opt, client.WithTLSClientConfig(cfg.TLS.CAFile, cfg.TLS.CertFile, cfg.TLS.KeyFile))
|
||||||
|
}
|
||||||
|
|
||||||
client, err := client.NewClientWithOpts(opt...)
|
client, err := client.NewClientWithOpts(opt...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -192,6 +201,7 @@ func NewClient(host string, unique ...bool) (*SharedClient, error) {
|
|||||||
|
|
||||||
c := &SharedClient{
|
c := &SharedClient{
|
||||||
Client: client,
|
Client: client,
|
||||||
|
cfg: cfg,
|
||||||
addr: addr,
|
addr: addr,
|
||||||
key: host,
|
key: host,
|
||||||
dial: dial,
|
dial: dial,
|
||||||
@@ -228,7 +238,7 @@ func (c *SharedClient) InterceptHTTPClient(intercept httputils.InterceptFunc) {
|
|||||||
func (c *SharedClient) CloneUnique() *SharedClient {
|
func (c *SharedClient) CloneUnique() *SharedClient {
|
||||||
// there will be no error here
|
// there will be no error here
|
||||||
// since we are using the same host from a valid client.
|
// since we are using the same host from a valid client.
|
||||||
c, _ = NewClient(c.key, true)
|
c, _ = NewClient(c.cfg, true)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ var (
|
|||||||
ErrNoNetwork = errors.New("no network found")
|
ErrNoNetwork = errors.New("no network found")
|
||||||
)
|
)
|
||||||
|
|
||||||
func FromDocker(c *container.Summary, dockerHost string) (res *types.Container) {
|
func FromDocker(c *container.Summary, dockerCfg types.DockerProviderConfig) (res *types.Container) {
|
||||||
actualLabels := maps.Clone(c.Labels)
|
actualLabels := maps.Clone(c.Labels)
|
||||||
|
|
||||||
_, isExplicit := c.Labels[LabelAliases]
|
_, isExplicit := c.Labels[LabelAliases]
|
||||||
@@ -46,7 +46,7 @@ func FromDocker(c *container.Summary, dockerHost string) (res *types.Container)
|
|||||||
|
|
||||||
isExcluded, _ := strconv.ParseBool(helper.getDeleteLabel(LabelExclude))
|
isExcluded, _ := strconv.ParseBool(helper.getDeleteLabel(LabelExclude))
|
||||||
res = &types.Container{
|
res = &types.Container{
|
||||||
DockerHost: dockerHost,
|
DockerCfg: dockerCfg,
|
||||||
Image: helper.parseImage(),
|
Image: helper.parseImage(),
|
||||||
ContainerName: helper.getName(),
|
ContainerName: helper.getName(),
|
||||||
ContainerID: c.ID,
|
ContainerID: c.ID,
|
||||||
@@ -68,11 +68,11 @@ func FromDocker(c *container.Summary, dockerHost string) (res *types.Container)
|
|||||||
State: c.State,
|
State: c.State,
|
||||||
}
|
}
|
||||||
|
|
||||||
if agent.IsDockerHostAgent(dockerHost) {
|
if agent.IsDockerHostAgent(dockerCfg.URL) {
|
||||||
var ok bool
|
var ok bool
|
||||||
res.Agent, ok = agent.GetAgent(dockerHost)
|
res.Agent, ok = agent.GetAgent(dockerCfg.URL)
|
||||||
if !ok {
|
if !ok {
|
||||||
addError(res, fmt.Errorf("agent %q not found", dockerHost))
|
addError(res, fmt.Errorf("agent %q not found", dockerCfg.URL))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,13 +91,13 @@ func IsBlacklisted(c *types.Container) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func UpdatePorts(c *types.Container) error {
|
func UpdatePorts(c *types.Container) error {
|
||||||
client, err := NewClient(c.DockerHost)
|
dockerClient, err := NewClient(c.DockerCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer client.Close()
|
defer dockerClient.Close()
|
||||||
|
|
||||||
inspect, err := client.ContainerInspect(context.Background(), c.ContainerID)
|
inspect, err := dockerClient.ContainerInspect(context.Background(), c.ContainerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -162,14 +162,14 @@ func isDatabase(c *types.Container) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func isLocal(c *types.Container) bool {
|
func isLocal(c *types.Container) bool {
|
||||||
if strings.HasPrefix(c.DockerHost, "unix://") {
|
if strings.HasPrefix(c.DockerCfg.URL, "unix://") {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// treat it as local if the docker host is the same as the environment variable
|
// treat it as local if the docker host is the same as the environment variable
|
||||||
if c.DockerHost == EnvDockerHost {
|
if c.DockerCfg.URL == EnvDockerHost {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
url, err := url.Parse(c.DockerHost)
|
url, err := url.Parse(c.DockerCfg.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -189,7 +189,7 @@ func setPublicHostname(c *types.Container) {
|
|||||||
c.PublicHostname = "127.0.0.1"
|
c.PublicHostname = "127.0.0.1"
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
url, err := url.Parse(c.DockerHost)
|
url, err := url.Parse(c.DockerCfg.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.PublicHostname = "127.0.0.1"
|
c.PublicHostname = "127.0.0.1"
|
||||||
return
|
return
|
||||||
@@ -257,7 +257,7 @@ func loadDeleteIdlewatcherLabels(c *types.Container, helper containerHelper) {
|
|||||||
if hasIdleTimeout {
|
if hasIdleTimeout {
|
||||||
idwCfg := new(types.IdlewatcherConfig)
|
idwCfg := new(types.IdlewatcherConfig)
|
||||||
idwCfg.Docker = &types.DockerConfig{
|
idwCfg.Docker = &types.DockerConfig{
|
||||||
DockerHost: c.DockerHost,
|
DockerCfg: c.DockerCfg,
|
||||||
ContainerID: c.ContainerID,
|
ContainerID: c.ContainerID,
|
||||||
ContainerName: c.ContainerName,
|
ContainerName: c.ContainerName,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
|
"github.com/yusing/godoxy/internal/types"
|
||||||
expect "github.com/yusing/goutils/testing"
|
expect "github.com/yusing/goutils/testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ func TestContainerExplicit(t *testing.T) {
|
|||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
c := FromDocker(&container.Summary{Names: []string{"test"}, State: "test", Labels: tt.labels}, "")
|
c := FromDocker(&container.Summary{Names: []string{"test"}, State: "test", Labels: tt.labels}, types.DockerProviderConfig{})
|
||||||
expect.Equal(t, c.IsExplicit, tt.isExplicit)
|
expect.Equal(t, c.IsExplicit, tt.isExplicit)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -73,7 +74,7 @@ func TestContainerHostNetworkMode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
c := FromDocker(tt.container, "")
|
c := FromDocker(tt.container, types.DockerProviderConfig{})
|
||||||
expect.Equal(t, c.IsHostNetworkMode, tt.isHostNetworkMode)
|
expect.Equal(t, c.IsHostNetworkMode, tt.isHostNetworkMode)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,18 +2,19 @@ package docker
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/puzpuzpuz/xsync/v4"
|
"github.com/puzpuzpuz/xsync/v4"
|
||||||
|
"github.com/yusing/godoxy/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
var idDockerHostMap = xsync.NewMap[string, string](xsync.WithPresize(100))
|
var idDockerCfgMap = xsync.NewMap[string, types.DockerProviderConfig](xsync.WithPresize(100))
|
||||||
|
|
||||||
func GetDockerHostByContainerID(id string) (string, bool) {
|
func GetDockerCfgByContainerID(id string) (types.DockerProviderConfig, bool) {
|
||||||
return idDockerHostMap.Load(id)
|
return idDockerCfgMap.Load(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetDockerHostByContainerID(id, host string) {
|
func SetDockerCfgByContainerID(id string, cfg types.DockerProviderConfig) {
|
||||||
idDockerHostMap.Store(id, host)
|
idDockerCfgMap.Store(id, cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteDockerHostByContainerID(id string) {
|
func DeleteDockerCfgByContainerID(id string) {
|
||||||
idDockerHostMap.Delete(id)
|
idDockerCfgMap.Delete(id)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
|
"github.com/yusing/godoxy/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
var listOptions = container.ListOptions{
|
var listOptions = container.ListOptions{
|
||||||
@@ -19,8 +20,8 @@ var listOptions = container.ListOptions{
|
|||||||
All: true,
|
All: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListContainers(ctx context.Context, clientHost string) ([]container.Summary, error) {
|
func ListContainers(ctx context.Context, dockerCfg types.DockerProviderConfig) ([]container.Summary, error) {
|
||||||
dockerClient, err := NewClient(clientHost)
|
dockerClient, err := NewClient(dockerCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,14 +19,14 @@ type DockerProvider struct {
|
|||||||
|
|
||||||
var startOptions = container.StartOptions{}
|
var startOptions = container.StartOptions{}
|
||||||
|
|
||||||
func NewDockerProvider(dockerHost, containerID string) (idlewatcher.Provider, error) {
|
func NewDockerProvider(dockerCfg types.DockerProviderConfig, containerID string) (idlewatcher.Provider, error) {
|
||||||
client, err := docker.NewClient(dockerHost)
|
client, err := docker.NewClient(dockerCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &DockerProvider{
|
return &DockerProvider{
|
||||||
client: client,
|
client: client,
|
||||||
watcher: watcher.NewDockerWatcher(dockerHost),
|
watcher: watcher.NewDockerWatcher(dockerCfg),
|
||||||
containerID: containerID,
|
containerID: containerID,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ func NewWatcher(parent task.Parent, r types.Route, cfg *types.IdlewatcherConfig)
|
|||||||
depCont := depRoute.ContainerInfo()
|
depCont := depRoute.ContainerInfo()
|
||||||
if depCont != nil {
|
if depCont != nil {
|
||||||
depCfg.Docker = &types.DockerConfig{
|
depCfg.Docker = &types.DockerConfig{
|
||||||
DockerHost: depCont.DockerHost,
|
DockerCfg: depCont.DockerCfg,
|
||||||
ContainerID: depCont.ContainerID,
|
ContainerID: depCont.ContainerID,
|
||||||
ContainerName: depCont.ContainerName,
|
ContainerName: depCont.ContainerName,
|
||||||
}
|
}
|
||||||
@@ -256,7 +256,7 @@ func NewWatcher(parent task.Parent, r types.Route, cfg *types.IdlewatcherConfig)
|
|||||||
var kind string
|
var kind string
|
||||||
switch {
|
switch {
|
||||||
case cfg.Docker != nil:
|
case cfg.Docker != nil:
|
||||||
p, err = provider.NewDockerProvider(cfg.Docker.DockerHost, cfg.Docker.ContainerID)
|
p, err = provider.NewDockerProvider(cfg.Docker.DockerCfg, cfg.Docker.ContainerID)
|
||||||
kind = "docker"
|
kind = "docker"
|
||||||
default:
|
default:
|
||||||
p, err = provider.NewProxmoxProvider(cfg.Proxmox.Node, cfg.Proxmox.VMID)
|
p, err = provider.NewProxmoxProvider(cfg.Proxmox.Node, cfg.Proxmox.VMID)
|
||||||
|
|||||||
@@ -18,8 +18,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type DockerProvider struct {
|
type DockerProvider struct {
|
||||||
name, dockerHost string
|
name string
|
||||||
l zerolog.Logger
|
dockerCfg types.DockerProviderConfig
|
||||||
|
l zerolog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -29,10 +30,10 @@ const (
|
|||||||
|
|
||||||
var ErrAliasRefIndexOutOfRange = gperr.New("index out of range")
|
var ErrAliasRefIndexOutOfRange = gperr.New("index out of range")
|
||||||
|
|
||||||
func DockerProviderImpl(name, dockerHost string) ProviderImpl {
|
func DockerProviderImpl(name string, dockerCfg types.DockerProviderConfig) ProviderImpl {
|
||||||
return &DockerProvider{
|
return &DockerProvider{
|
||||||
name,
|
name,
|
||||||
dockerHost,
|
dockerCfg,
|
||||||
log.With().Str("type", "docker").Str("name", name).Logger(),
|
log.With().Str("type", "docker").Str("name", name).Logger(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,14 +55,14 @@ func (p *DockerProvider) Logger() *zerolog.Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *DockerProvider) NewWatcher() watcher.Watcher {
|
func (p *DockerProvider) NewWatcher() watcher.Watcher {
|
||||||
return watcher.NewDockerWatcher(p.dockerHost)
|
return watcher.NewDockerWatcher(p.dockerCfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *DockerProvider) loadRoutesImpl() (route.Routes, gperr.Error) {
|
func (p *DockerProvider) loadRoutesImpl() (route.Routes, gperr.Error) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
containers, err := docker.ListContainers(ctx, p.dockerHost)
|
containers, err := docker.ListContainers(ctx, p.dockerCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, gperr.Wrap(err)
|
return nil, gperr.Wrap(err)
|
||||||
}
|
}
|
||||||
@@ -70,7 +71,7 @@ func (p *DockerProvider) loadRoutesImpl() (route.Routes, gperr.Error) {
|
|||||||
routes := make(route.Routes)
|
routes := make(route.Routes)
|
||||||
|
|
||||||
for _, c := range containers {
|
for _, c := range containers {
|
||||||
container := docker.FromDocker(&c, p.dockerHost)
|
container := docker.FromDocker(&c, p.dockerCfg)
|
||||||
|
|
||||||
if container.Errors != nil {
|
if container.Errors != nil {
|
||||||
errs.Add(container.Errors)
|
errs.Add(container.Errors)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/yusing/godoxy/internal/docker"
|
"github.com/yusing/godoxy/internal/docker"
|
||||||
|
"github.com/yusing/godoxy/internal/types"
|
||||||
expect "github.com/yusing/goutils/testing"
|
expect "github.com/yusing/goutils/testing"
|
||||||
|
|
||||||
_ "embed"
|
_ "embed"
|
||||||
@@ -28,7 +29,7 @@ func TestParseDockerLabels(t *testing.T) {
|
|||||||
Ports: []container.Port{
|
Ports: []container.Port{
|
||||||
{Type: "tcp", PrivatePort: 1234, PublicPort: 1234},
|
{Type: "tcp", PrivatePort: 1234, PublicPort: 1234},
|
||||||
},
|
},
|
||||||
}, "/var/run/docker.sock"),
|
}, types.DockerProviderConfig{URL: "unix:///var/run/docker.sock"}),
|
||||||
)
|
)
|
||||||
expect.NoError(t, err)
|
expect.NoError(t, err)
|
||||||
expect.True(t, routes.Contains("app"))
|
expect.True(t, routes.Contains("app"))
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
D "github.com/yusing/godoxy/internal/docker"
|
D "github.com/yusing/godoxy/internal/docker"
|
||||||
"github.com/yusing/godoxy/internal/route"
|
"github.com/yusing/godoxy/internal/route"
|
||||||
routeTypes "github.com/yusing/godoxy/internal/route/types"
|
routeTypes "github.com/yusing/godoxy/internal/route/types"
|
||||||
|
"github.com/yusing/godoxy/internal/types"
|
||||||
expect "github.com/yusing/goutils/testing"
|
expect "github.com/yusing/goutils/testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,7 +31,7 @@ func makeRoutes(cont *container.Summary, dockerHostIP ...string) route.Routes {
|
|||||||
}
|
}
|
||||||
cont.ID = "test"
|
cont.ID = "test"
|
||||||
p.name = "test"
|
p.name = "test"
|
||||||
routes := expect.Must(p.routesFromContainerLabels(D.FromDocker(cont, host)))
|
routes := expect.Must(p.routesFromContainerLabels(D.FromDocker(cont, types.DockerProviderConfig{URL: host})))
|
||||||
for _, r := range routes {
|
for _, r := range routes {
|
||||||
r.Finalize()
|
r.Finalize()
|
||||||
}
|
}
|
||||||
@@ -38,7 +39,7 @@ func makeRoutes(cont *container.Summary, dockerHostIP ...string) route.Routes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExplicitOnly(t *testing.T) {
|
func TestExplicitOnly(t *testing.T) {
|
||||||
p := NewDockerProvider("a!", "")
|
p := NewDockerProvider("a!", types.DockerProviderConfig{})
|
||||||
expect.True(t, p.IsExplicitOnly())
|
expect.True(t, p.IsExplicitOnly())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,7 +199,7 @@ func TestApplyLabelWithRefIndexError(t *testing.T) {
|
|||||||
"proxy.*.port": "4444",
|
"proxy.*.port": "4444",
|
||||||
"proxy.#4.scheme": "https",
|
"proxy.#4.scheme": "https",
|
||||||
},
|
},
|
||||||
}, "")
|
}, types.DockerProviderConfig{})
|
||||||
var p DockerProvider
|
var p DockerProvider
|
||||||
_, err := p.routesFromContainerLabels(c)
|
_, err := p.routesFromContainerLabels(c)
|
||||||
expect.ErrorIs(t, ErrAliasRefIndexOutOfRange, err)
|
expect.ErrorIs(t, ErrAliasRefIndexOutOfRange, err)
|
||||||
@@ -210,7 +211,7 @@ func TestApplyLabelWithRefIndexError(t *testing.T) {
|
|||||||
D.LabelAliases: "a,b",
|
D.LabelAliases: "a,b",
|
||||||
"proxy.#0.host": "localhost",
|
"proxy.#0.host": "localhost",
|
||||||
},
|
},
|
||||||
}, "")
|
}, types.DockerProviderConfig{})
|
||||||
_, err = p.routesFromContainerLabels(c)
|
_, err = p.routesFromContainerLabels(c)
|
||||||
expect.ErrorIs(t, ErrAliasRefIndexOutOfRange, err)
|
expect.ErrorIs(t, ErrAliasRefIndexOutOfRange, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,13 +69,13 @@ func NewFileProvider(filename string) (p *Provider, err error) {
|
|||||||
return p, err
|
return p, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDockerProvider(name string, dockerHost string) *Provider {
|
func NewDockerProvider(name string, dockerCfg types.DockerProviderConfig) *Provider {
|
||||||
if dockerHost == common.DockerHostFromEnv {
|
if dockerCfg.URL == common.DockerHostFromEnv {
|
||||||
dockerHost = env.GetEnvString("DOCKER_HOST", client.DefaultDockerHost)
|
dockerCfg.URL = env.GetEnvString("DOCKER_HOST", client.DefaultDockerHost)
|
||||||
}
|
}
|
||||||
|
|
||||||
p := newProvider(provider.ProviderTypeDocker)
|
p := newProvider(provider.ProviderTypeDocker)
|
||||||
p.ProviderImpl = DockerProviderImpl(name, dockerHost)
|
p.ProviderImpl = DockerProviderImpl(name, dockerCfg)
|
||||||
p.watcher = p.NewWatcher()
|
p.watcher = p.NewWatcher()
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,9 @@ func NewAgentProvider(cfg *agent.AgentConfig) *Provider {
|
|||||||
p := newProvider(provider.ProviderTypeAgent)
|
p := newProvider(provider.ProviderTypeAgent)
|
||||||
agent := &AgentProvider{
|
agent := &AgentProvider{
|
||||||
AgentConfig: cfg,
|
AgentConfig: cfg,
|
||||||
docker: DockerProviderImpl(cfg.Name, cfg.FakeDockerHost()),
|
docker: DockerProviderImpl(cfg.Name, types.DockerProviderConfig{
|
||||||
|
URL: cfg.FakeDockerHost(),
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
p.ProviderImpl = agent
|
p.ProviderImpl = agent
|
||||||
p.watcher = p.NewWatcher()
|
p.watcher = p.NewWatcher()
|
||||||
|
|||||||
@@ -391,7 +391,7 @@ func (r *Route) start(parent task.Parent) gperr.Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if cont := r.ContainerInfo(); cont != nil {
|
if cont := r.ContainerInfo(); cont != nil {
|
||||||
docker.SetDockerHostByContainerID(cont.ContainerID, cont.DockerHost)
|
docker.SetDockerCfgByContainerID(cont.ContainerID, cont.DockerCfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !excluded {
|
if !excluded {
|
||||||
@@ -406,7 +406,7 @@ func (r *Route) start(parent task.Parent) gperr.Error {
|
|||||||
|
|
||||||
func (r *Route) Finish(reason any) {
|
func (r *Route) Finish(reason any) {
|
||||||
if cont := r.ContainerInfo(); cont != nil {
|
if cont := r.ContainerInfo(); cont != nil {
|
||||||
docker.DeleteDockerHostByContainerID(cont.ContainerID)
|
docker.DeleteDockerCfgByContainerID(cont.ContainerID)
|
||||||
}
|
}
|
||||||
r.FinishAndWait(reason)
|
r.FinishAndWait(reason)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ type (
|
|||||||
|
|
||||||
PortMapping = map[int]container.Port
|
PortMapping = map[int]container.Port
|
||||||
Container struct {
|
Container struct {
|
||||||
DockerHost string `json:"docker_host"`
|
DockerCfg DockerProviderConfig `json:"docker_cfg"`
|
||||||
Image *ContainerImage `json:"image"`
|
Image *ContainerImage `json:"image"`
|
||||||
ContainerName string `json:"container_name"`
|
ContainerName string `json:"container_name"`
|
||||||
ContainerID string `json:"container_id"`
|
ContainerID string `json:"container_id"`
|
||||||
|
|
||||||
State container.ContainerState `json:"state"`
|
State container.ContainerState `json:"state"`
|
||||||
|
|
||||||
|
|||||||
82
internal/types/docker_provider_config.go
Normal file
82
internal/types/docker_provider_config.go
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/yusing/godoxy/internal/common"
|
||||||
|
"github.com/yusing/godoxy/internal/serialization"
|
||||||
|
gperr "github.com/yusing/goutils/errs"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DockerProviderConfig struct {
|
||||||
|
URL string `json:"url,omitempty"`
|
||||||
|
TLS *DockerTLSConfig `json:"tls,omitempty"`
|
||||||
|
} // @name DockerProviderConfig
|
||||||
|
|
||||||
|
type DockerProviderConfigDetailed struct {
|
||||||
|
Scheme string `json:"scheme,omitempty" validate:"required,oneof=http https tls"`
|
||||||
|
Host string `json:"host,omitempty" validate:"required,hostname|ip"`
|
||||||
|
Port int `json:"port,omitempty" validate:"required,min=1,max=65535"`
|
||||||
|
TLS *DockerTLSConfig `json:"tls" validate:"omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DockerTLSConfig struct {
|
||||||
|
CAFile string `json:"ca_file,omitempty" validate:"required"`
|
||||||
|
CertFile string `json:"cert_file,omitempty" validate:"required"`
|
||||||
|
KeyFile string `json:"key_file,omitempty" validate:"required"`
|
||||||
|
} // @name DockerTLSConfig
|
||||||
|
|
||||||
|
func (cfg *DockerProviderConfig) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(cfg.URL)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *DockerProviderConfig) Parse(value string) error {
|
||||||
|
u, err := url.Parse(value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch u.Scheme {
|
||||||
|
case "http", "https", "tls":
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid scheme: %s", u.Scheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.URL = u.String()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *DockerProviderConfig) UnmarshalMap(m map[string]any) gperr.Error {
|
||||||
|
var tmp DockerProviderConfigDetailed
|
||||||
|
var err = serialization.MapUnmarshalValidate(m, &tmp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.URL = fmt.Sprintf("%s://%s", tmp.Scheme, net.JoinHostPort(tmp.Host, strconv.Itoa(tmp.Port)))
|
||||||
|
cfg.TLS = tmp.TLS
|
||||||
|
if cfg.TLS != nil {
|
||||||
|
if err := checkFilesOk(cfg.TLS.CAFile, cfg.TLS.CertFile, cfg.TLS.KeyFile); err != nil {
|
||||||
|
return gperr.Wrap(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkFilesOk(files ...string) error {
|
||||||
|
if common.IsTest {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var errs gperr.Builder
|
||||||
|
for _, file := range files {
|
||||||
|
if _, err := os.Stat(file); err != nil {
|
||||||
|
errs.Add(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errs.Error()
|
||||||
|
}
|
||||||
122
internal/types/docker_provider_config_test.go
Normal file
122
internal/types/docker_provider_config_test.go
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/yusing/godoxy/internal/serialization"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDockerProviderConfigUnmarshalMap(t *testing.T) {
|
||||||
|
t.Run("string", func(t *testing.T) {
|
||||||
|
var cfg map[string]*DockerProviderConfig
|
||||||
|
err := serialization.UnmarshalValidateYAML([]byte("test: http://localhost:2375"), &cfg)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, &DockerProviderConfig{URL: "http://localhost:2375"}, cfg["test"])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("detailed", func(t *testing.T) {
|
||||||
|
var cfg map[string]*DockerProviderConfig
|
||||||
|
err := serialization.UnmarshalValidateYAML([]byte(`
|
||||||
|
test:
|
||||||
|
scheme: http
|
||||||
|
host: localhost
|
||||||
|
port: 2375
|
||||||
|
tls:
|
||||||
|
ca_file: /etc/ssl/ca.crt
|
||||||
|
cert_file: /etc/ssl/cert.crt
|
||||||
|
key_file: /etc/ssl/key.crt`), &cfg)
|
||||||
|
assert.Error(t, err, os.ErrNotExist)
|
||||||
|
assert.Equal(t, &DockerProviderConfig{URL: "http://localhost:2375", TLS: &DockerTLSConfig{CAFile: "/etc/ssl/ca.crt", CertFile: "/etc/ssl/cert.crt", KeyFile: "/etc/ssl/key.crt"}}, cfg["test"])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDockerProviderConfigValidation(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
yamlStr string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{name: "valid url", yamlStr: "test: http://localhost:2375", wantErr: false},
|
||||||
|
{name: "invalid url", yamlStr: "test: ftp://localhost/2375", wantErr: true},
|
||||||
|
{name: "valid scheme", yamlStr: `
|
||||||
|
test:
|
||||||
|
scheme: http
|
||||||
|
host: localhost
|
||||||
|
port: 2375
|
||||||
|
`, wantErr: false},
|
||||||
|
{name: "invalid scheme", yamlStr: `
|
||||||
|
test:
|
||||||
|
scheme: invalid
|
||||||
|
host: localhost
|
||||||
|
port: 2375
|
||||||
|
`, wantErr: true},
|
||||||
|
{name: "valid host (ipv4)", yamlStr: `
|
||||||
|
test:
|
||||||
|
scheme: http
|
||||||
|
host: 127.0.0.1
|
||||||
|
port: 2375
|
||||||
|
`, wantErr: false},
|
||||||
|
{name: "valid host (ipv6)", yamlStr: `
|
||||||
|
test:
|
||||||
|
scheme: http
|
||||||
|
host: ::1
|
||||||
|
port: 2375
|
||||||
|
`, wantErr: false},
|
||||||
|
{name: "valid host (hostname)", yamlStr: `
|
||||||
|
test:
|
||||||
|
scheme: http
|
||||||
|
host: example.com
|
||||||
|
port: 2375
|
||||||
|
`, wantErr: false},
|
||||||
|
{name: "invalid host", yamlStr: `
|
||||||
|
test:
|
||||||
|
scheme: http
|
||||||
|
host: invalid:1234
|
||||||
|
port: 2375
|
||||||
|
`, wantErr: true},
|
||||||
|
{name: "valid port", yamlStr: `
|
||||||
|
test:
|
||||||
|
scheme: http
|
||||||
|
host: localhost
|
||||||
|
port: 2375
|
||||||
|
`, wantErr: false},
|
||||||
|
{name: "invalid port", yamlStr: `
|
||||||
|
test:
|
||||||
|
scheme: http
|
||||||
|
host: localhost
|
||||||
|
port: 65536
|
||||||
|
`, wantErr: true},
|
||||||
|
{name: "valid tls", yamlStr: `
|
||||||
|
test:
|
||||||
|
scheme: tls
|
||||||
|
host: localhost
|
||||||
|
port: 2375
|
||||||
|
tls:
|
||||||
|
ca_file: /etc/ssl/ca.crt
|
||||||
|
cert_file: /etc/ssl/cert.crt
|
||||||
|
key_file: /etc/ssl/key.crt
|
||||||
|
`, wantErr: false},
|
||||||
|
{name: "invalid tls (missing cert file and key file)", yamlStr: `
|
||||||
|
test:
|
||||||
|
scheme: tls
|
||||||
|
host: localhost
|
||||||
|
port: 2375
|
||||||
|
tls:
|
||||||
|
ca_file: /etc/ssl/ca.crt
|
||||||
|
`, wantErr: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
var cfg map[string]*DockerProviderConfig
|
||||||
|
err := serialization.UnmarshalValidateYAML([]byte(test.yamlStr), &cfg)
|
||||||
|
if test.wantErr {
|
||||||
|
assert.Error(t, err)
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,9 +38,9 @@ type (
|
|||||||
ContainerSignal string // @name ContainerSignal
|
ContainerSignal string // @name ContainerSignal
|
||||||
|
|
||||||
DockerConfig struct {
|
DockerConfig struct {
|
||||||
DockerHost string `json:"docker_host" validate:"required"`
|
DockerCfg DockerProviderConfig `json:"docker_cfg" validate:"required"`
|
||||||
ContainerID string `json:"container_id" validate:"required"`
|
ContainerID string `json:"container_id" validate:"required"`
|
||||||
ContainerName string `json:"container_name" validate:"required"`
|
ContainerName string `json:"container_name" validate:"required"`
|
||||||
} // @name DockerConfig
|
} // @name DockerConfig
|
||||||
ProxmoxConfig struct {
|
ProxmoxConfig struct {
|
||||||
Node string `json:"node" validate:"required"`
|
Node string `json:"node" validate:"required"`
|
||||||
|
|||||||
@@ -10,12 +10,15 @@ import (
|
|||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/yusing/godoxy/internal/docker"
|
"github.com/yusing/godoxy/internal/docker"
|
||||||
|
"github.com/yusing/godoxy/internal/types"
|
||||||
"github.com/yusing/godoxy/internal/watcher/events"
|
"github.com/yusing/godoxy/internal/watcher/events"
|
||||||
gperr "github.com/yusing/goutils/errs"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
DockerWatcher string
|
DockerWatcher struct {
|
||||||
|
cfg types.DockerProviderConfig
|
||||||
|
}
|
||||||
DockerListOptions = dockerEvents.ListOptions
|
DockerListOptions = dockerEvents.ListOptions
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -55,8 +58,10 @@ func DockerFilterContainerNameID(nameOrID string) filters.KeyValuePair {
|
|||||||
return filters.Arg("container", nameOrID)
|
return filters.Arg("container", nameOrID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDockerWatcher(host string) DockerWatcher {
|
func NewDockerWatcher(dockerCfg types.DockerProviderConfig) DockerWatcher {
|
||||||
return DockerWatcher(host)
|
return DockerWatcher{
|
||||||
|
cfg: dockerCfg,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w DockerWatcher) Events(ctx context.Context) (<-chan Event, <-chan gperr.Error) {
|
func (w DockerWatcher) Events(ctx context.Context) (<-chan Event, <-chan gperr.Error) {
|
||||||
@@ -68,7 +73,7 @@ func (w DockerWatcher) EventsWithOptions(ctx context.Context, options DockerList
|
|||||||
errCh := make(chan gperr.Error)
|
errCh := make(chan gperr.Error)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
client, err := docker.NewClient(string(w))
|
client, err := docker.NewClient(w.cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errCh <- gperr.Wrap(err, "docker watcher: failed to initialize client")
|
errCh <- gperr.Wrap(err, "docker watcher: failed to initialize client")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ func NewMonitor(r types.Route) types.HealthMonCheck {
|
|||||||
}
|
}
|
||||||
if r.IsDocker() {
|
if r.IsDocker() {
|
||||||
cont := r.ContainerInfo()
|
cont := r.ContainerInfo()
|
||||||
client, err := docker.NewClient(cont.DockerHost)
|
client, err := docker.NewClient(cont.DockerCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return mon
|
return mon
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user