sshpoke/internal/docker/convert.go

128 lines
3.8 KiB
Go

package docker
import (
"net"
"strconv"
"strings"
"github.com/Neur0toxine/sshpoke/internal/config"
"github.com/Neur0toxine/sshpoke/internal/logger"
"github.com/Neur0toxine/sshpoke/pkg/dto"
"github.com/Neur0toxine/sshpoke/pkg/smarttypes"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/events"
"github.com/docker/docker/api/types/network"
"github.com/mitchellh/mapstructure"
)
type labelsConfig struct {
Enable smarttypes.BoolStr `mapstructure:"sshpoke.enable"`
Network string `mapstructure:"sshpoke.network"`
Server string `mapstructure:"sshpoke.server"`
Port string `mapstructure:"sshpoke.port"`
RemoteHost string `mapstructure:"sshpoke.remote_host"`
}
func actorEnabled(actor events.Actor) smarttypes.BoolStr {
label, ok := actor.Attributes["sshpoke.enable"]
if !ok {
return smarttypes.AsBoolStr(false)
}
return smarttypes.BoolStr(label)
}
func populateLabelsFromConfig(labels *labelsConfig, config *config.ServiceLabels) {
if labels.Enable.Bool() != config.Enable.Bool() {
labels.Enable = smarttypes.AsBoolStr(config.Enable.Bool())
}
if labels.Server != config.Server {
labels.Server = config.Server
}
if labels.Network != config.Network {
labels.Network = config.Network
}
if labels.Port != config.Port {
labels.Port = config.Port
}
if labels.RemoteHost != config.RemoteHost {
labels.RemoteHost = config.RemoteHost
}
}
func dockerContainerToInternal(
container types.Container, configLabels *config.ServiceLabels, defaultServer string) (result dto.Container, ok bool) {
var labels labelsConfig
if err := mapstructure.Decode(container.Labels, &labels); err != nil {
logger.Sugar.Debugf("skipping container %s because configuration is invalid: %s", container.ID, err)
return result, false
}
if configLabels != nil {
populateLabelsFromConfig(&labels, configLabels)
}
if !labels.Enable.Bool() {
logger.Sugar.Debugf("skipping container %s because sshpoke is not enabled for it", container.ID)
return result, false
}
if labels.Server == "" {
if defaultServer == "" {
logger.Sugar.Debugf("skipping container %s because 'sshpoke.server' is not defined", container.ID)
return result, false
}
labels.Server = defaultServer
}
if container.NetworkSettings == nil ||
container.NetworkSettings.Networks == nil ||
len(container.NetworkSettings.Networks) == 0 {
logger.Sugar.Debugf("skipping container %s because network settings are empty", container.ID)
return result, false
}
var ip net.IP
if len(container.NetworkSettings.Networks) == 1 {
ip = net.ParseIP(getKeyVal(container.NetworkSettings.Networks).IPAddress)
} else {
if labels.Network == "" {
logger.Sugar.Debugf("container %s has %d networks and 'sshpoke.network' label is not specified",
container.ID, len(container.NetworkSettings.Networks))
return result, false
}
ntwrk, exists := container.NetworkSettings.Networks[labels.Network]
if !exists {
logger.Sugar.Debugf("container %s does not have network %s", container.ID, labels.Network)
return result, false
}
ip = net.ParseIP(ntwrk.IPAddress)
}
port, err := strconv.Atoi(labels.Port)
if err != nil {
logger.Sugar.Debugf("skipping container %s because 'sshpoke.port' is not numeric", container.ID)
return result, false
}
return dto.Container{
ID: container.ID,
Names: convertNames(container.Names),
IP: ip,
Port: uint16(port),
Server: labels.Server,
RemoteHost: labels.RemoteHost,
}, true
}
func convertNames(src []string) []string {
if len(src) == 0 {
return nil
}
dst := make([]string, len(src))
for i := 0; i < len(src); i++ {
dst[i] = strings.TrimLeft(src[i], "/")
}
return dst
}
func getKeyVal(m map[string]*network.EndpointSettings) *network.EndpointSettings {
for _, v := range m {
return v
}
return nil
}