The following patch adapts the logic of the merge strategy existing and last win for service ports. In the past, the complete object has been replaced based on the merge strategy. This behavior has been adapted, that each port should now considered individually per strategy. Both strategies now focus on the src port of the host system. With a last-win, the dest port of the container is overwritten with an existing src port. ```diff service: my-app: ports: - - 0.0.0.0:8080:80 + - 0.0.0.0:8080:8080 - 0.0.0.0:8443:8443 ``` The situation is different with the existing win strategy. There, the destination port can no longer be changed once there is a connection with a sourc port.
2145 lines
56 KiB
Go
2145 lines
56 KiB
Go
package dockerCompose
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
environmentDelimiter string = "="
|
|
labelDelimiter string = "="
|
|
volumeDelimiter string = ":"
|
|
portDelimiter string = ":"
|
|
portProtocolDelimiter string = "/"
|
|
)
|
|
|
|
type Config struct {
|
|
Networks map[string]*Network `json:"networks,omitempty" yaml:"networks,omitempty"`
|
|
Secrets map[string]*Secret `json:"secrets,omitempty" yaml:"secrets,omitempty"`
|
|
Services map[string]*Service `json:"services,omitempty" yaml:"services,omitempty"`
|
|
Version string `json:"version,omitempty" yaml:"version,omitempty"`
|
|
Volumes map[string]*Volume `json:"volumes,omitempty" yaml:"volumes,omitempty"`
|
|
}
|
|
|
|
// Equal returns true if the passed equalable is equal
|
|
func (c *Config) Equal(equalable Equalable) bool {
|
|
config, ok := equalable.(*Config)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
switch {
|
|
case c == nil && config == nil:
|
|
return true
|
|
case c != nil && config == nil:
|
|
fallthrough
|
|
case c == nil && config != nil:
|
|
return false
|
|
default:
|
|
return EqualStringMap(c.Networks, config.Networks) &&
|
|
EqualStringMap(c.Secrets, config.Secrets) &&
|
|
EqualStringMap(c.Services, config.Services) &&
|
|
c.Version == config.Version &&
|
|
EqualStringMap(c.Volumes, config.Volumes)
|
|
}
|
|
}
|
|
|
|
// ExistsNetwork returns true if a network with the passed named exists.
|
|
func (c *Config) ExistsNetwork(name string) bool {
|
|
return ExistsInMap(c.Networks, name)
|
|
}
|
|
|
|
// ExistsSecret returns true if a secret with the passed named exists.
|
|
func (c *Config) ExistsSecret(name string) bool {
|
|
return ExistsInMap(c.Secrets, name)
|
|
}
|
|
|
|
// ExistsService returns true if a service with the passed named exists.
|
|
func (c *Config) ExistsService(name string) bool {
|
|
return ExistsInMap(c.Services, name)
|
|
}
|
|
|
|
// ExistsVolumes returns true if a volume with the passed named exists.
|
|
func (c *Config) ExistsVolume(name string) bool {
|
|
return ExistsInMap(c.Volumes, name)
|
|
}
|
|
|
|
// Merge adds only a missing network, secret, service and volume.
|
|
func (c *Config) Merge(config *Config) {
|
|
for name, network := range config.Networks {
|
|
if !c.ExistsNetwork(name) {
|
|
c.Networks[name] = network
|
|
}
|
|
}
|
|
|
|
for name, secret := range config.Secrets {
|
|
if !c.ExistsSecret(name) {
|
|
c.Secrets[name] = secret
|
|
}
|
|
}
|
|
|
|
for name, service := range config.Services {
|
|
if !c.ExistsService(name) {
|
|
c.Services[name] = service
|
|
}
|
|
}
|
|
|
|
for name, volume := range config.Volumes {
|
|
if !c.ExistsVolume(name) {
|
|
c.Volumes[name] = volume
|
|
}
|
|
}
|
|
}
|
|
|
|
// MergeLastWin merges a config and overwrite already existing properties
|
|
func (c *Config) MergeExistingWin(config *Config) {
|
|
switch {
|
|
case c == nil && config == nil:
|
|
fallthrough
|
|
case c != nil && config == nil:
|
|
return
|
|
|
|
// WARN: It's not possible to change the memory pointer c *Config
|
|
// to a new initialized config without returning the Config
|
|
// it self.
|
|
//
|
|
// case c == nil && config != nil:
|
|
// c = NewConfig()
|
|
// fallthrough
|
|
|
|
default:
|
|
c.mergeExistingWinNetworks(config.Networks)
|
|
c.mergeExistingWinSecrets(config.Secrets)
|
|
c.mergeExistingWinServices(config.Services)
|
|
c.mergeExistingWinVersion(config.Version)
|
|
c.mergeExistingWinVolumes(config.Volumes)
|
|
}
|
|
}
|
|
|
|
// MergeLastWin merges a config and overwrite already existing properties
|
|
func (c *Config) MergeLastWin(config *Config) {
|
|
switch {
|
|
case c == nil && config == nil:
|
|
fallthrough
|
|
case c != nil && config == nil:
|
|
return
|
|
|
|
// WARN: It's not possible to change the memory pointer c *Config
|
|
// to a new initialized config without returning the Config
|
|
// it self.
|
|
//
|
|
// case c == nil && config != nil:
|
|
// c = NewConfig()
|
|
// fallthrough
|
|
|
|
default:
|
|
c.mergeLastWinNetworks(config.Networks)
|
|
c.mergeLastWinSecrets(config.Secrets)
|
|
c.mergeLastWinServices(config.Services)
|
|
c.mergeLastWinVersion(config.Version)
|
|
c.mergeLastWinVolumes(config.Volumes)
|
|
}
|
|
}
|
|
|
|
func (c *Config) mergeExistingWinVersion(version string) {
|
|
if len(c.Version) <= 0 {
|
|
c.Version = version
|
|
}
|
|
}
|
|
|
|
func (c *Config) mergeExistingWinNetworks(networks map[string]*Network) {
|
|
for networkName, network := range networks {
|
|
if network == nil {
|
|
continue
|
|
}
|
|
|
|
if c.ExistsNetwork(networkName) {
|
|
c.Networks[networkName].MergeExistingWin(network)
|
|
} else {
|
|
c.Networks[networkName] = network
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *Config) mergeExistingWinSecrets(secrets map[string]*Secret) {
|
|
for secretName, secret := range secrets {
|
|
if secret == nil {
|
|
continue
|
|
}
|
|
|
|
if c.ExistsNetwork(secretName) {
|
|
c.Secrets[secretName].MergeExistingWin(secret)
|
|
} else {
|
|
c.Secrets[secretName] = secret
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *Config) mergeExistingWinServices(services map[string]*Service) {
|
|
for serviceName, service := range services {
|
|
if service == nil {
|
|
continue
|
|
}
|
|
|
|
if c.ExistsService(serviceName) {
|
|
c.Services[serviceName].MergeExistingWin(service)
|
|
} else {
|
|
c.Services[serviceName] = service
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *Config) mergeExistingWinVolumes(volumes map[string]*Volume) {
|
|
for volumeName, volume := range volumes {
|
|
if volume == nil {
|
|
continue
|
|
}
|
|
|
|
if c.ExistsNetwork(volumeName) {
|
|
c.Volumes[volumeName].MergeExistingWin(volume)
|
|
} else {
|
|
c.Volumes[volumeName] = volume
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *Config) mergeLastWinVersion(version string) {
|
|
if c.Version != version {
|
|
c.Version = version
|
|
}
|
|
}
|
|
|
|
func (c *Config) mergeLastWinNetworks(networks map[string]*Network) {
|
|
for networkName, network := range networks {
|
|
if network == nil {
|
|
continue
|
|
}
|
|
|
|
if c.ExistsNetwork(networkName) {
|
|
c.Networks[networkName].MergeLastWin(network)
|
|
} else {
|
|
c.Networks[networkName] = network
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *Config) mergeLastWinSecrets(secrets map[string]*Secret) {
|
|
for secretName, secret := range secrets {
|
|
if secret == nil {
|
|
continue
|
|
}
|
|
|
|
if c.ExistsNetwork(secretName) {
|
|
c.Secrets[secretName].MergeLastWin(secret)
|
|
} else {
|
|
c.Secrets[secretName] = secret
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *Config) mergeLastWinServices(services map[string]*Service) {
|
|
for serviceName, service := range services {
|
|
if service == nil {
|
|
continue
|
|
}
|
|
|
|
if c.ExistsService(serviceName) {
|
|
c.Services[serviceName].MergeLastWin(service)
|
|
} else {
|
|
c.Services[serviceName] = service
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *Config) mergeLastWinVolumes(volumes map[string]*Volume) {
|
|
for volumeName, volume := range volumes {
|
|
if volume == nil {
|
|
continue
|
|
}
|
|
|
|
if c.ExistsNetwork(volumeName) {
|
|
c.Volumes[volumeName].MergeLastWin(volume)
|
|
} else {
|
|
c.Volumes[volumeName] = volume
|
|
}
|
|
}
|
|
}
|
|
|
|
func NewConfig() *Config {
|
|
return &Config{
|
|
Services: make(map[string]*Service),
|
|
Networks: make(map[string]*Network),
|
|
Secrets: make(map[string]*Secret),
|
|
Volumes: make(map[string]*Volume),
|
|
}
|
|
}
|
|
|
|
type Network struct {
|
|
External bool `json:"external,omitempty" yaml:"external,omitempty"`
|
|
Driver string `json:"driver,omitempty" yaml:"driver,omitempty"`
|
|
IPAM *NetworkIPAM `json:"ipam,omitempty" yaml:"ipam,omitempty"`
|
|
}
|
|
|
|
// Equal returns true if the passed equalable is equal
|
|
func (n *Network) Equal(equalable Equalable) bool {
|
|
network, ok := equalable.(*Network)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
switch {
|
|
case n == nil && network == nil:
|
|
return true
|
|
case n != nil && network == nil:
|
|
fallthrough
|
|
case n == nil && network != nil:
|
|
return false
|
|
default:
|
|
return n.External == network.External &&
|
|
n.Driver == network.Driver &&
|
|
n.IPAM.Equal(network.IPAM)
|
|
}
|
|
}
|
|
|
|
func (n *Network) MergeExistingWin(network *Network) {
|
|
switch {
|
|
case n == nil && network == nil:
|
|
fallthrough
|
|
case n != nil && network == nil:
|
|
return
|
|
|
|
// WARN: It's not possible to change the memory pointer n *Network
|
|
// to a new initialized network without returning the Network
|
|
// it self.
|
|
//
|
|
// case n == nil && network != nil:
|
|
// c = NewCNetwork()
|
|
// fallthrough
|
|
|
|
default:
|
|
n.mergeExistingWinIPAM(network.IPAM)
|
|
}
|
|
}
|
|
|
|
func (n *Network) MergeLastWin(network *Network) {
|
|
switch {
|
|
case n == nil && network == nil:
|
|
fallthrough
|
|
case n != nil && network == nil:
|
|
return
|
|
|
|
// WARN: It's not possible to change the memory pointer n *Network
|
|
// to a new initialized network without returning the Network
|
|
// it self.
|
|
//
|
|
// case n == nil && network != nil:
|
|
// c = NewCNetwork()
|
|
// fallthrough
|
|
|
|
default:
|
|
n.mergeLastWinIPAM(network.IPAM)
|
|
}
|
|
}
|
|
|
|
func (n *Network) mergeExistingWinIPAM(networkIPAM *NetworkIPAM) {
|
|
if !n.IPAM.Equal(networkIPAM) {
|
|
n.IPAM.MergeExistingWin(networkIPAM)
|
|
}
|
|
}
|
|
|
|
func (n *Network) mergeLastWinIPAM(networkIPAM *NetworkIPAM) {
|
|
if !n.IPAM.Equal(networkIPAM) {
|
|
n.IPAM.MergeLastWin(networkIPAM)
|
|
}
|
|
}
|
|
|
|
func NewNetwork() *Network {
|
|
return &Network{
|
|
External: false,
|
|
IPAM: new(NetworkIPAM),
|
|
}
|
|
}
|
|
|
|
type NetworkIPAM struct {
|
|
Configs []*NetworkIPAMConfig `json:"config,omitempty" yaml:"config,omitempty"`
|
|
}
|
|
|
|
// Equal returns true if the passed equalable is equal
|
|
func (nIPAM *NetworkIPAM) Equal(equalable Equalable) bool {
|
|
networkIPAM, ok := equalable.(*NetworkIPAM)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
switch {
|
|
case nIPAM == nil && networkIPAM == nil:
|
|
return true
|
|
case nIPAM != nil && networkIPAM == nil:
|
|
fallthrough
|
|
case nIPAM == nil && networkIPAM != nil:
|
|
return false
|
|
default:
|
|
return Equal(nIPAM.Configs, networkIPAM.Configs)
|
|
}
|
|
}
|
|
|
|
func (nIPAM *NetworkIPAM) MergeExistingWin(networkIPAM *NetworkIPAM) {
|
|
switch {
|
|
case nIPAM == nil && networkIPAM == nil:
|
|
fallthrough
|
|
case nIPAM != nil && networkIPAM == nil:
|
|
return
|
|
|
|
// WARN: It's not possible to change the memory pointer n *NetworkIPAM
|
|
// to a new initialized networkIPAM without returning the NetworkIPAM
|
|
// it self.
|
|
//
|
|
// case nIPAM == nil && networkIPAM != nil:
|
|
// c = NewNetworkIPAM()
|
|
// fallthrough
|
|
|
|
default:
|
|
nIPAM.mergeExistingWinConfig(networkIPAM.Configs)
|
|
}
|
|
}
|
|
|
|
func (nIPAM *NetworkIPAM) MergeLastWin(networkIPAM *NetworkIPAM) {
|
|
switch {
|
|
case nIPAM == nil && networkIPAM == nil:
|
|
fallthrough
|
|
case nIPAM != nil && networkIPAM == nil:
|
|
return
|
|
|
|
// WARN: It's not possible to change the memory pointer n *NetworkIPAM
|
|
// to a new initialized networkIPAM without returning the NetworkIPAM
|
|
// it self.
|
|
//
|
|
// case nIPAM == nil && networkIPAM != nil:
|
|
// c = NewNetworkIPAM()
|
|
// fallthrough
|
|
|
|
default:
|
|
nIPAM.mergeLastWinConfig(networkIPAM.Configs)
|
|
}
|
|
}
|
|
|
|
func (nIPAM *NetworkIPAM) mergeExistingWinConfig(networkIPAMConfigs []*NetworkIPAMConfig) {
|
|
for _, networkIPAMConfig := range networkIPAMConfigs {
|
|
if !existsInSlice(nIPAM.Configs, networkIPAMConfig) {
|
|
nIPAM.Configs = append(nIPAM.Configs, networkIPAMConfig)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (nIPAM *NetworkIPAM) mergeLastWinConfig(networkIPAMConfigs []*NetworkIPAMConfig) {
|
|
for _, networkIPAMConfig := range networkIPAMConfigs {
|
|
if !existsInSlice(nIPAM.Configs, networkIPAMConfig) {
|
|
nIPAM.Configs = append(nIPAM.Configs, networkIPAMConfig)
|
|
}
|
|
}
|
|
}
|
|
|
|
func NewNetworkIPAM() *NetworkIPAM {
|
|
return &NetworkIPAM{
|
|
Configs: make([]*NetworkIPAMConfig, 0),
|
|
}
|
|
}
|
|
|
|
type NetworkIPAMConfig struct {
|
|
Subnet string `json:"subnet,omitempty" yaml:"subnet,omitempty"`
|
|
}
|
|
|
|
// Equal returns true if the passed equalable is equal
|
|
func (nIPAMConfig *NetworkIPAMConfig) Equal(equalable Equalable) bool {
|
|
networkIPAMConfig, ok := equalable.(*NetworkIPAMConfig)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
switch {
|
|
case nIPAMConfig == nil && networkIPAMConfig == nil:
|
|
return true
|
|
case nIPAMConfig != nil && networkIPAMConfig == nil:
|
|
fallthrough
|
|
case nIPAMConfig == nil && networkIPAMConfig != nil:
|
|
return false
|
|
default:
|
|
return nIPAMConfig.Subnet == networkIPAMConfig.Subnet
|
|
}
|
|
}
|
|
|
|
func NewNetworkIPAMConfig() *NetworkIPAMConfig {
|
|
return &NetworkIPAMConfig{}
|
|
}
|
|
|
|
type Secret struct {
|
|
File string `json:"file,omitempty" yaml:"file,omitempty"`
|
|
}
|
|
|
|
// Equal returns true if the passed equalable is equal
|
|
func (s *Secret) Equal(equalable Equalable) bool {
|
|
secret, ok := equalable.(*Secret)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
switch {
|
|
case s == nil && secret == nil:
|
|
return true
|
|
case s != nil && secret == nil:
|
|
fallthrough
|
|
case s == nil && secret != nil:
|
|
return false
|
|
default:
|
|
return s.File == secret.File
|
|
}
|
|
}
|
|
|
|
// MergeExistingWin merges adds or overwrite the attributes of the passed secret
|
|
// with the existing one.
|
|
func (s *Secret) MergeExistingWin(secret *Secret) {
|
|
if len(s.File) <= 0 {
|
|
s.File = secret.File
|
|
}
|
|
}
|
|
|
|
// MergeLastWin merges adds or overwrite the attributes of the passed secret
|
|
// with the existing one.
|
|
func (s *Secret) MergeLastWin(secret *Secret) {
|
|
if !s.Equal(secret) {
|
|
s.File = secret.File
|
|
}
|
|
}
|
|
|
|
func NewSecret() *Secret {
|
|
return &Secret{}
|
|
}
|
|
|
|
type Service struct {
|
|
CapabilitiesAdd []string `json:"cap_add,omitempty" yaml:"cap_add,omitempty"`
|
|
CapabilitiesDrop []string `json:"cap_drop,omitempty" yaml:"cap_drop,omitempty"`
|
|
DependsOn []string `json:"depends_on,omitempty" yaml:"depends_on,omitempty"`
|
|
Deploy *ServiceDeploy `json:"deploy,omitempty" yaml:"deploy,omitempty"`
|
|
Environments []string `json:"environment,omitempty" yaml:"environment,omitempty"`
|
|
ExtraHosts []string `json:"extra_hosts,omitempty" yaml:"extra_hosts,omitempty"`
|
|
Image string `json:"image,omitempty" yaml:"image,omitempty"`
|
|
Labels []string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
|
Networks map[string]*ServiceNetwork `json:"networks,omitempty" yaml:"networks,omitempty"`
|
|
Ports []Port `json:"ports,omitempty" yaml:"ports,omitempty"`
|
|
Secrets []string `json:"secrets,omitempty" yaml:"secrets,omitempty"`
|
|
ULimits *ServiceULimits `json:"ulimits,omitempty" yaml:"ulimits,omitempty"`
|
|
Volumes []string `json:"volumes,omitempty" yaml:"volumes,omitempty"`
|
|
}
|
|
|
|
// ExistsEnvironment returns true if the passed name of environment variable is
|
|
// already present.
|
|
func (s *Service) ExistsEnvironment(name string) bool {
|
|
for _, environment := range s.Environments {
|
|
key, _ := splitStringInKeyValue(environment, environmentDelimiter)
|
|
if key == name {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// ExistsLabel returns true if the passed label name is already present.
|
|
func (s *Service) ExistsLabel(name string) bool {
|
|
for _, label := range s.Labels {
|
|
key, _ := splitStringInKeyValue(label, labelDelimiter)
|
|
if key == name {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// ExistsPort returns true if the port definition is already present. The port defines a mapping between the host system
|
|
// port and the container port. It is also possible to specify the individual ip address of the host system or the
|
|
// container. Additionally, the protocol can be specified as suffix.
|
|
//
|
|
// // Example
|
|
// s := new(Service)
|
|
// b := s.ExistsPort("80:80")
|
|
// b = s.ExistsPort("0.0.0.0:80:80/tcp")
|
|
// b = s.ExistsPort("0.0.0.0:80:80/tcp")
|
|
// b = s.ExistsPort("192.168.178.10:80:172.25.18.20:80/tcp")
|
|
func (s *Service) ExistsPort(port string) bool {
|
|
for _, p := range s.Ports {
|
|
if string(p) == port {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// ExistsVolume returns true if the volume definition is already present.
|
|
func (s *Service) ExistsVolume(src string, dest string, perm string) bool {
|
|
for _, volume := range s.Volumes {
|
|
s, d, p := splitStringInVolume(volume)
|
|
if s == src && d == dest && p == perm {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// ExistsDestinationVolume returns true if the volume definition is already present.
|
|
func (s *Service) ExistsDestinationVolume(dest string) bool {
|
|
for _, volume := range s.Volumes {
|
|
_, d, _ := splitStringInVolume(volume)
|
|
if d == dest {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// ExistsSourceVolume returns true if the volume definition is already present.
|
|
func (s *Service) ExistsSourceVolume(src string) bool {
|
|
for _, volume := range s.Volumes {
|
|
s, _, _ := splitStringInVolume(volume)
|
|
if s == src {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// Equal returns true if the passed equalable is equal
|
|
func (s *Service) Equal(equalable Equalable) bool {
|
|
service, ok := equalable.(*Service)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
switch {
|
|
case s == nil && service == nil:
|
|
return true
|
|
case s != nil && service == nil:
|
|
fallthrough
|
|
case s == nil && service != nil:
|
|
return false
|
|
default:
|
|
return equalSlice(s.CapabilitiesAdd, service.CapabilitiesAdd) &&
|
|
equalSlice(s.CapabilitiesDrop, service.CapabilitiesDrop) &&
|
|
equalSlice(s.DependsOn, service.DependsOn) &&
|
|
s.Deploy.Equal(service.Deploy) &&
|
|
equalSlice(s.Environments, service.Environments) &&
|
|
equalSlice(s.ExtraHosts, service.ExtraHosts) &&
|
|
s.Image == service.Image &&
|
|
equalSlice(s.Labels, service.Labels) &&
|
|
EqualStringMap(s.Networks, service.Networks) &&
|
|
equalSlice(s.Ports, service.Ports) &&
|
|
equalSlice(s.Secrets, service.Secrets) &&
|
|
s.ULimits.Equal(service.ULimits) &&
|
|
equalSlice(s.Volumes, service.Volumes)
|
|
}
|
|
}
|
|
|
|
func (s *Service) MergeExistingWin(service *Service) {
|
|
switch {
|
|
case s == nil && service == nil:
|
|
fallthrough
|
|
case s != nil && service == nil:
|
|
return
|
|
|
|
// WARN: It's not possible to change the memory pointer s *Service
|
|
// to a new initialized service without returning the Service
|
|
// it self.
|
|
//
|
|
// case s == nil && service != nil:
|
|
// s = NewService()
|
|
// fallthrough
|
|
|
|
default:
|
|
s.mergeExistingWinCapabilitiesAdd(service.CapabilitiesAdd)
|
|
s.mergeExistingWinCapabilitiesDrop(service.CapabilitiesDrop)
|
|
s.mergeExistingWinDependsOn(service.DependsOn)
|
|
s.mergeExistingWinDeploy(service.Deploy)
|
|
s.mergeExistingWinEnvironments(service.Environments)
|
|
s.mergeExistingWinExtraHosts(service.ExtraHosts)
|
|
s.mergeExistingWinImage(service.Image)
|
|
s.mergeExistingWinLabels(service.Labels)
|
|
s.mergeExistingWinNetworks(service.Networks)
|
|
s.mergeExistingWinPorts(service.Ports)
|
|
s.mergeExistingWinSecrets(service.Secrets)
|
|
s.mergeExistingWinULimits(service.ULimits)
|
|
s.mergeExistingWinVolumes(service.Volumes)
|
|
}
|
|
}
|
|
|
|
// MergeLastWin merges adds or overwrite the attributes of the passed secret
|
|
// with the existing one.
|
|
func (s *Service) MergeLastWin(service *Service) {
|
|
switch {
|
|
case s == nil && service == nil:
|
|
fallthrough
|
|
case s != nil && service == nil:
|
|
return
|
|
|
|
// WARN: It's not possible to change the memory pointer s *Service
|
|
// to a new initialized service without returning the Service
|
|
// it self.
|
|
//
|
|
// case s == nil && service != nil:
|
|
// s = NewService()
|
|
// fallthrough
|
|
|
|
default:
|
|
s.mergeLastWinCapabilitiesAdd(service.CapabilitiesAdd)
|
|
s.mergeLastWinCapabilitiesDrop(service.CapabilitiesDrop)
|
|
s.mergeLastWinDependsOn(service.DependsOn)
|
|
s.mergeLastWinDeploy(service.Deploy)
|
|
s.mergeLastWinEnvironments(service.Environments)
|
|
s.mergeLastWinExtraHosts(service.ExtraHosts)
|
|
s.mergeLastWinImage(service.Image)
|
|
s.mergeLastWinLabels(service.Labels)
|
|
s.mergeLastWinNetworks(service.Networks)
|
|
s.mergeLastWinPorts(service.Ports)
|
|
s.mergeLastWinSecrets(service.Secrets)
|
|
s.mergeLastWinULimits(service.ULimits)
|
|
s.mergeLastWinVolumes(service.Volumes)
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeExistingWinCapabilitiesAdd(capabilitiesAdd []string) {
|
|
for _, capabilityAdd := range capabilitiesAdd {
|
|
if !existsInSlice(s.CapabilitiesAdd, capabilityAdd) && len(capabilityAdd) > 0 {
|
|
s.CapabilitiesAdd = append(s.CapabilitiesAdd, capabilityAdd)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeExistingWinCapabilitiesDrop(capabilitiesDrop []string) {
|
|
for _, capabilityDrop := range capabilitiesDrop {
|
|
if !existsInSlice(s.CapabilitiesAdd, capabilityDrop) && len(capabilityDrop) > 0 {
|
|
s.CapabilitiesDrop = append(s.CapabilitiesDrop, capabilityDrop)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeExistingWinDependsOn(dependsOn []string) {
|
|
for _, depOn := range dependsOn {
|
|
if !existsInSlice(s.DependsOn, depOn) && len(depOn) > 0 {
|
|
s.DependsOn = append(s.DependsOn, depOn)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeExistingWinDeploy(deploy *ServiceDeploy) {
|
|
switch {
|
|
case s.Deploy == nil && deploy != nil:
|
|
s.Deploy = deploy
|
|
case s.Deploy != nil && deploy == nil:
|
|
fallthrough
|
|
case s.Deploy == nil && deploy == nil:
|
|
return
|
|
default:
|
|
s.Deploy.MergeExistingWin(deploy)
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeExistingWinEnvironments(environments []string) {
|
|
switch {
|
|
case s.Environments == nil && environments != nil:
|
|
s.Environments = environments
|
|
case s.Environments != nil && environments == nil:
|
|
fallthrough
|
|
case s.Environments == nil && environments == nil:
|
|
return
|
|
default:
|
|
for _, environment := range environments {
|
|
if len(environment) <= 0 {
|
|
continue
|
|
}
|
|
|
|
key, value := splitStringInKeyValue(environment, environmentDelimiter)
|
|
if !s.ExistsEnvironment(key) {
|
|
s.SetEnvironment(key, value)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeExistingWinImage(image string) {
|
|
switch {
|
|
case len(s.Image) == 0 && len(image) != 0:
|
|
s.Image = image
|
|
case len(s.Image) != 0 && len(image) == 0:
|
|
fallthrough
|
|
case len(s.Image) == 0 && len(image) == 0:
|
|
fallthrough
|
|
default:
|
|
return
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeExistingWinExtraHosts(extraHosts []string) {
|
|
for _, extraHost := range extraHosts {
|
|
if !existsInSlice(s.ExtraHosts, extraHost) && len(extraHost) > 0 {
|
|
s.ExtraHosts = append(s.ExtraHosts, extraHost)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeExistingWinLabels(labels []string) {
|
|
switch {
|
|
case s.Labels == nil && labels != nil:
|
|
s.Labels = labels
|
|
case s.Labels != nil && labels == nil:
|
|
fallthrough
|
|
case s.Labels == nil && labels == nil:
|
|
return
|
|
default:
|
|
for _, label := range labels {
|
|
if len(label) <= 0 {
|
|
continue
|
|
}
|
|
|
|
key, value := splitStringInKeyValue(label, labelDelimiter)
|
|
if !s.ExistsLabel(key) {
|
|
s.SetLabel(key, value)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeExistingWinNetworks(networks map[string]*ServiceNetwork) {
|
|
switch {
|
|
case s.Networks == nil && networks != nil:
|
|
s.Networks = networks
|
|
case s.Networks != nil && networks == nil:
|
|
fallthrough
|
|
case s.Networks == nil && networks == nil:
|
|
return
|
|
default:
|
|
for name, network := range networks {
|
|
if _, exists := s.Networks[name]; exists {
|
|
s.Networks[name].MergeExistingWin(network)
|
|
} else {
|
|
s.Networks[name] = network
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeExistingWinPorts(ports []Port) {
|
|
switch {
|
|
case s.Ports == nil && ports != nil:
|
|
s.Ports = ports
|
|
case s.Ports != nil && ports == nil:
|
|
fallthrough
|
|
case s.Ports == nil && ports == nil:
|
|
return
|
|
default:
|
|
LOOP:
|
|
for i := range ports {
|
|
if len(ports[i]) <= 0 {
|
|
continue LOOP
|
|
}
|
|
|
|
newPort := Port(ports[i])
|
|
|
|
for j := range s.Ports {
|
|
existingPort := Port(s.Ports[j])
|
|
switch {
|
|
case newPort.existsSrcIP() && existingPort.existsSrcIP() &&
|
|
newPort.getSrc() == existingPort.getSrc():
|
|
continue LOOP
|
|
case !newPort.existsSrcIP() && existingPort.existsSrcIP() &&
|
|
newPort.getSrcPort() == existingPort.getSrcPort():
|
|
continue LOOP
|
|
case newPort.existsSrcIP() && !existingPort.existsSrcIP() &&
|
|
newPort.getSrcPort() == existingPort.getSrcPort():
|
|
continue LOOP
|
|
case !newPort.existsSrcIP() && !existingPort.existsSrcIP() &&
|
|
newPort.getSrcPort() == existingPort.getSrcPort():
|
|
continue LOOP
|
|
}
|
|
}
|
|
|
|
s.Ports = append(s.Ports, ports[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeExistingWinSecrets(secrets []string) {
|
|
for _, secret := range secrets {
|
|
if !existsInSlice(s.Secrets, secret) && len(secret) > 0 {
|
|
s.Secrets = append(s.Secrets, secret)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeExistingWinULimits(uLimits *ServiceULimits) {
|
|
switch {
|
|
case s.ULimits == nil && uLimits != nil:
|
|
s.ULimits = uLimits
|
|
case s.ULimits != nil && uLimits == nil:
|
|
fallthrough
|
|
case s.ULimits == nil && uLimits == nil:
|
|
return
|
|
default:
|
|
s.ULimits.MergeExistingWin(uLimits)
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeExistingWinVolumes(volumes []string) {
|
|
switch {
|
|
case s.Volumes == nil && volumes != nil:
|
|
s.Volumes = volumes
|
|
case s.Volumes != nil && volumes == nil:
|
|
fallthrough
|
|
case s.Volumes == nil && volumes == nil:
|
|
return
|
|
default:
|
|
for _, volume := range volumes {
|
|
src, dest, perm := splitStringInVolume(volume)
|
|
if !s.ExistsDestinationVolume(dest) {
|
|
s.SetVolume(src, dest, perm)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeLastWinCapabilitiesAdd(capabilitiesAdd []string) {
|
|
for _, capabilityAdd := range capabilitiesAdd {
|
|
if len(capabilityAdd) <= 0 {
|
|
continue
|
|
}
|
|
|
|
if !existsInSlice(s.CapabilitiesAdd, capabilityAdd) {
|
|
s.CapabilitiesAdd = append(s.CapabilitiesAdd, capabilityAdd)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeLastWinCapabilitiesDrop(capabilitiesDrop []string) {
|
|
for _, capabilityDrop := range capabilitiesDrop {
|
|
if len(capabilityDrop) <= 0 {
|
|
continue
|
|
}
|
|
|
|
if !existsInSlice(s.CapabilitiesDrop, capabilityDrop) {
|
|
s.CapabilitiesDrop = append(s.CapabilitiesDrop, capabilityDrop)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeLastWinDependsOn(dependsOn []string) {
|
|
for _, dep := range dependsOn {
|
|
if len(dep) <= 0 {
|
|
continue
|
|
}
|
|
|
|
if !existsInSlice(s.DependsOn, dep) {
|
|
s.DependsOn = append(s.DependsOn, dep)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeLastWinDeploy(deploy *ServiceDeploy) {
|
|
switch {
|
|
case s.Deploy == nil && deploy != nil:
|
|
s.Deploy = deploy
|
|
case s.Deploy != nil && deploy == nil:
|
|
fallthrough
|
|
case s.Deploy == nil && deploy == nil:
|
|
return
|
|
default:
|
|
s.Deploy.MergeLastWin(deploy)
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeLastWinEnvironments(environments []string) {
|
|
switch {
|
|
case s.Environments == nil && environments != nil:
|
|
s.Environments = environments
|
|
case s.Environments != nil && environments == nil:
|
|
fallthrough
|
|
case s.Environments == nil && environments == nil:
|
|
return
|
|
default:
|
|
for _, environment := range environments {
|
|
if len(environment) <= 0 {
|
|
continue
|
|
}
|
|
|
|
key, value := splitStringInKeyValue(environment, environmentDelimiter)
|
|
s.SetEnvironment(key, value)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeLastWinImage(image string) {
|
|
switch {
|
|
case len(s.Image) == 0 && len(image) != 0:
|
|
s.Image = image
|
|
case len(s.Image) != 0 && len(image) == 0:
|
|
fallthrough
|
|
case len(s.Image) == 0 && len(image) == 0:
|
|
return
|
|
default:
|
|
if s.Image != image {
|
|
s.Image = image
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeLastWinExtraHosts(extraHosts []string) {
|
|
for _, extraHost := range extraHosts {
|
|
if len(extraHost) <= 0 {
|
|
continue
|
|
}
|
|
|
|
if !existsInSlice(s.ExtraHosts, extraHost) {
|
|
s.ExtraHosts = append(s.ExtraHosts, extraHost)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeLastWinLabels(labels []string) {
|
|
switch {
|
|
case s.Labels == nil && labels != nil:
|
|
s.Labels = labels
|
|
case s.Labels != nil && labels == nil:
|
|
fallthrough
|
|
case s.Labels == nil && labels == nil:
|
|
return
|
|
default:
|
|
for _, label := range labels {
|
|
if len(label) <= 0 {
|
|
continue
|
|
}
|
|
|
|
key, value := splitStringInKeyValue(label, labelDelimiter)
|
|
s.SetLabel(key, value)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeLastWinNetworks(networks map[string]*ServiceNetwork) {
|
|
switch {
|
|
case s.Networks == nil && networks != nil:
|
|
s.Networks = networks
|
|
case s.Networks != nil && networks == nil:
|
|
fallthrough
|
|
case s.Networks == nil && networks == nil:
|
|
return
|
|
default:
|
|
for name, network := range networks {
|
|
if _, exists := s.Networks[name]; exists {
|
|
s.Networks[name].MergeLastWin(network)
|
|
} else {
|
|
s.Networks[name] = network
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeLastWinPorts(ports []Port) {
|
|
switch {
|
|
case s.Ports == nil && ports != nil:
|
|
s.Ports = ports
|
|
case s.Ports != nil && ports == nil:
|
|
fallthrough
|
|
case s.Ports == nil && ports == nil:
|
|
return
|
|
default:
|
|
for i := range ports {
|
|
if len(ports[i]) <= 0 {
|
|
continue
|
|
}
|
|
s.SetPort(string(ports[i]))
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeLastWinSecrets(secrets []string) {
|
|
for _, secret := range secrets {
|
|
if len(secret) <= 0 {
|
|
continue
|
|
}
|
|
|
|
if !existsInSlice(s.Secrets, secret) {
|
|
s.Secrets = append(s.Secrets, secret)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeLastWinULimits(uLimits *ServiceULimits) {
|
|
switch {
|
|
case s.ULimits == nil && uLimits != nil:
|
|
s.ULimits = uLimits
|
|
case s.ULimits != nil && uLimits == nil:
|
|
fallthrough
|
|
case s.ULimits == nil && uLimits == nil:
|
|
return
|
|
default:
|
|
s.ULimits.MergeLastWin(uLimits)
|
|
}
|
|
}
|
|
|
|
func (s *Service) mergeLastWinVolumes(volumes []string) {
|
|
switch {
|
|
case s.Volumes == nil && volumes != nil:
|
|
s.Volumes = volumes
|
|
case s.Volumes != nil && volumes == nil:
|
|
fallthrough
|
|
case s.Volumes == nil && volumes == nil:
|
|
return
|
|
default:
|
|
for _, volume := range volumes {
|
|
if len(volume) <= 0 {
|
|
continue
|
|
}
|
|
|
|
src, dest, perm := splitStringInVolume(volume)
|
|
s.SetVolume(src, dest, perm)
|
|
}
|
|
}
|
|
}
|
|
|
|
// RemoveEnvironment remove all found environment variable from the internal
|
|
// slice matching by the passed name.
|
|
func (s *Service) RemoveEnvironment(name string) {
|
|
environments := make([]string, 0)
|
|
for _, environment := range s.Environments {
|
|
key, value := splitStringInKeyValue(environment, environmentDelimiter)
|
|
if key != name {
|
|
environments = append(environments, fmt.Sprintf("%s%s%s", key, environmentDelimiter, value))
|
|
}
|
|
}
|
|
s.Environments = environments
|
|
}
|
|
|
|
// RemoveLabel remove all found labels from the internal slice matching by the passed name.
|
|
func (s *Service) RemoveLabel(name string) {
|
|
labels := make([]string, 0)
|
|
for _, label := range s.Labels {
|
|
key, value := splitStringInKeyValue(label, labelDelimiter)
|
|
if key != name {
|
|
labels = append(labels, fmt.Sprintf("%s%s%s", key, labelDelimiter, value))
|
|
}
|
|
}
|
|
s.Labels = labels
|
|
}
|
|
|
|
// RemovePortByDst remove all found ports from the internal slice matching by the passed destination. The destination
|
|
// can contains only the destination port, but also the destination ip address.
|
|
//
|
|
// // Example
|
|
// s := new(Service)
|
|
// s.RemovePortByDst("8080")
|
|
// s.RemovePortByDst("172.25.18.20:8080")
|
|
func (s *Service) RemovePortByDst(dest string) {
|
|
ports := make([]Port, 0)
|
|
for _, port := range s.Ports {
|
|
switch {
|
|
case port.getDst() == dest:
|
|
continue
|
|
default:
|
|
ports = append(ports, port)
|
|
}
|
|
}
|
|
s.Ports = ports
|
|
}
|
|
|
|
// RemovePortBySrc remove all found ports from the internal slice matching by the passed source. The source can contains
|
|
// only the source port, but also the source ip address.
|
|
//
|
|
// // Example
|
|
// s := new(Service)
|
|
// s.RemovePortBySrc("8080")
|
|
// s.RemovePortBySrc("192.168.178.10:8080")
|
|
func (s *Service) RemovePortBySrc(src string) {
|
|
ports := make([]Port, 0)
|
|
for _, port := range s.Ports {
|
|
switch {
|
|
case port.getSrc() == src:
|
|
continue
|
|
default:
|
|
ports = append(ports, port)
|
|
}
|
|
}
|
|
s.Ports = ports
|
|
}
|
|
|
|
// RemoveVolume remove all found volumes from the internal slice matching by the dest path.
|
|
func (s *Service) RemoveVolume(dest string) {
|
|
volumes := make([]string, 0)
|
|
for _, volume := range s.Volumes {
|
|
srcPath, destPath, perm := splitStringInVolume(volume)
|
|
|
|
switch {
|
|
case destPath == dest && len(perm) <= 0:
|
|
s.Volumes = append(s.Volumes, fmt.Sprintf("%s%s%s", srcPath, volumeDelimiter, destPath))
|
|
case destPath == dest && len(perm) > 0:
|
|
s.Volumes = append(s.Volumes, fmt.Sprintf("%s%s%s%s%s", srcPath, volumeDelimiter, destPath, volumeDelimiter, perm))
|
|
}
|
|
}
|
|
s.Volumes = volumes
|
|
}
|
|
|
|
// SetEnvironment add or overwrite an existing environment variable.
|
|
func (s *Service) SetEnvironment(name string, value string) {
|
|
s.RemoveEnvironment(name)
|
|
s.Environments = append(s.Environments, fmt.Sprintf("%s%s%s", name, environmentDelimiter, value))
|
|
}
|
|
|
|
// SetLabel add or overwrite an existing label.
|
|
func (s *Service) SetLabel(name string, value string) {
|
|
s.RemoveLabel(name)
|
|
s.Labels = append(s.Labels, fmt.Sprintf("%s%s%s", name, labelDelimiter, value))
|
|
}
|
|
|
|
// SetPort add or overwrite an existing source port.
|
|
//
|
|
// // Example
|
|
// s := new(Service)
|
|
// s.SetPort("0.0.0.0:443:172.25.18.20:8443/tcp") // Add new port
|
|
// s.SetPort("0.0.0.0:443:10.254.611.66:443/tcp") // Overwrite port determined by source port
|
|
func (s *Service) SetPort(port string) {
|
|
newPort := Port(port)
|
|
s.RemovePortBySrc(newPort.getSrc())
|
|
s.Ports = append(s.Ports, newPort)
|
|
}
|
|
|
|
// SetVolume add or overwrite an existing volume.
|
|
func (s *Service) SetVolume(src string, dest string, perm string) {
|
|
s.RemoveVolume(dest)
|
|
if len(perm) <= 0 {
|
|
s.Volumes = append(s.Volumes, fmt.Sprintf("%s%s%s", src, volumeDelimiter, dest))
|
|
} else {
|
|
s.Volumes = append(s.Volumes, fmt.Sprintf("%s%s%s%s%s", src, volumeDelimiter, dest, volumeDelimiter, perm))
|
|
}
|
|
}
|
|
|
|
// NewService returns an empty initialized Service.
|
|
func NewService() *Service {
|
|
return &Service{
|
|
CapabilitiesAdd: make([]string, 0),
|
|
CapabilitiesDrop: make([]string, 0),
|
|
Deploy: new(ServiceDeploy),
|
|
Environments: make([]string, 0),
|
|
ExtraHosts: make([]string, 0),
|
|
Labels: make([]string, 0),
|
|
Networks: make(map[string]*ServiceNetwork),
|
|
Ports: make([]Port, 0),
|
|
Secrets: make([]string, 0),
|
|
ULimits: new(ServiceULimits),
|
|
Volumes: make([]string, 0),
|
|
}
|
|
}
|
|
|
|
type ServiceDeploy struct {
|
|
Resources *ServiceDeployResources `json:"resources" yaml:"resources"`
|
|
}
|
|
|
|
// Equal returns true if the passed equalable is equal
|
|
func (sd *ServiceDeploy) Equal(equalable Equalable) bool {
|
|
serviceDeploy, ok := equalable.(*ServiceDeploy)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
switch {
|
|
case sd == nil && serviceDeploy == nil:
|
|
return true
|
|
case sd != nil && serviceDeploy == nil:
|
|
fallthrough
|
|
case sd == nil && serviceDeploy != nil:
|
|
return false
|
|
default:
|
|
return sd.Resources.Equal(serviceDeploy.Resources)
|
|
}
|
|
}
|
|
|
|
// MergeExistingWin merges adds or overwrite the attributes of the passed
|
|
// serviceDeploy with the existing one.
|
|
func (sd *ServiceDeploy) MergeExistingWin(serviceDeploy *ServiceDeploy) {
|
|
switch {
|
|
case sd == nil && serviceDeploy == nil:
|
|
fallthrough
|
|
case sd != nil && serviceDeploy == nil:
|
|
return
|
|
|
|
// WARN: It's not possible to change the memory pointer sd *ServiceDeploy
|
|
// to a new initialized serviceDeploy without returning the ServiceDeploy
|
|
// it self.
|
|
//
|
|
// case sd == nil && serviceDeploy != nil:
|
|
// sd = NewServiceDeploy()
|
|
// fallthrough
|
|
|
|
default:
|
|
sd.mergeExistingWinDeployResources(serviceDeploy.Resources)
|
|
}
|
|
}
|
|
|
|
// MergeLastWin merges adds or overwrite the attributes of the passed
|
|
// serviceDeploy with the existing one.
|
|
func (sd *ServiceDeploy) MergeLastWin(serviceDeploy *ServiceDeploy) {
|
|
switch {
|
|
case sd == nil && serviceDeploy == nil:
|
|
fallthrough
|
|
case sd != nil && serviceDeploy == nil:
|
|
return
|
|
|
|
// WARN: It's not possible to change the memory pointer sd *ServiceDeploy
|
|
// to a new initialized serviceDeploy without returning the ServiceDeploy
|
|
// it self.
|
|
//
|
|
// case sd == nil && serviceDeploy != nil:
|
|
// sd = NewServiceDeploy()
|
|
// fallthrough
|
|
|
|
default:
|
|
sd.mergeLastWinDeployResources(serviceDeploy.Resources)
|
|
}
|
|
}
|
|
|
|
func (sd *ServiceDeploy) mergeExistingWinDeployResources(resources *ServiceDeployResources) {
|
|
switch {
|
|
case sd.Resources == nil && resources != nil:
|
|
sd.Resources = resources
|
|
case sd.Resources != nil && resources == nil:
|
|
fallthrough
|
|
case sd.Resources == nil && resources == nil:
|
|
return
|
|
default:
|
|
sd.Resources.MergeExistingWin(resources)
|
|
}
|
|
}
|
|
|
|
func (sd *ServiceDeploy) mergeLastWinDeployResources(resources *ServiceDeployResources) {
|
|
switch {
|
|
case sd.Resources == nil && resources != nil:
|
|
sd.Resources = resources
|
|
case sd.Resources != nil && resources == nil:
|
|
fallthrough
|
|
case sd.Resources == nil && resources == nil:
|
|
return
|
|
default:
|
|
sd.Resources.MergeLastWin(resources)
|
|
}
|
|
}
|
|
|
|
func NewServiceDeploy() *ServiceDeploy {
|
|
return &ServiceDeploy{
|
|
Resources: new(ServiceDeployResources),
|
|
}
|
|
}
|
|
|
|
type ServiceDeployResources struct {
|
|
Limits *ServiceDeployResourcesLimits `json:"limits,omitempty" yaml:"limits,omitempty"`
|
|
Reservations *ServiceDeployResourcesLimits `json:"reservations,omitempty" yaml:"reservations,omitempty"`
|
|
}
|
|
|
|
// Equal returns true if the passed equalable is equal
|
|
func (sdr *ServiceDeployResources) Equal(equalable Equalable) bool {
|
|
serviceDeployResources, ok := equalable.(*ServiceDeployResources)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
switch {
|
|
case sdr == nil && serviceDeployResources == nil:
|
|
return true
|
|
case sdr != nil && serviceDeployResources == nil:
|
|
fallthrough
|
|
case sdr == nil && serviceDeployResources != nil:
|
|
return false
|
|
default:
|
|
return sdr.Limits.Equal(serviceDeployResources.Limits) &&
|
|
sdr.Reservations.Equal(serviceDeployResources.Reservations)
|
|
}
|
|
}
|
|
|
|
// MergeExistingWin adds only attributes of the passed serviceDeployResources if
|
|
// they are not already exists.
|
|
func (sdr *ServiceDeployResources) MergeExistingWin(serviceDeployResources *ServiceDeployResources) {
|
|
switch {
|
|
case sdr == nil && serviceDeployResources == nil:
|
|
fallthrough
|
|
case sdr != nil && serviceDeployResources == nil:
|
|
return
|
|
|
|
// WARN: It's not possible to change the memory pointer sdr *ServiceDeployResources
|
|
// to a new initialized serviceDeployResources without returning the
|
|
// serviceDeployResources it self.
|
|
case sdr == nil && serviceDeployResources != nil:
|
|
sdr = NewServiceDeployResources()
|
|
fallthrough
|
|
default:
|
|
sdr.mergeExistingWinLimits(serviceDeployResources.Limits)
|
|
sdr.mergeExistingWinReservations(serviceDeployResources.Reservations)
|
|
}
|
|
}
|
|
|
|
// MergeLastWin merges adds or overwrite the attributes of the passed
|
|
// serviceDeployResources with the existing one.
|
|
func (sdr *ServiceDeployResources) MergeLastWin(serviceDeployResources *ServiceDeployResources) {
|
|
switch {
|
|
case sdr == nil && serviceDeployResources == nil:
|
|
fallthrough
|
|
case sdr != nil && serviceDeployResources == nil:
|
|
return
|
|
|
|
// WARN: It's not possible to change the memory pointer sdr *ServiceDeployResources
|
|
// to a new initialized serviceDeployResources without returning the
|
|
// serviceDeployResources it self.
|
|
case sdr == nil && serviceDeployResources != nil:
|
|
sdr = NewServiceDeployResources()
|
|
fallthrough
|
|
default:
|
|
sdr.mergeLastWinLimits(serviceDeployResources.Limits)
|
|
sdr.mergeLastWinReservations(serviceDeployResources.Reservations)
|
|
}
|
|
}
|
|
|
|
func (sdr *ServiceDeployResources) mergeExistingWinLimits(limits *ServiceDeployResourcesLimits) {
|
|
switch {
|
|
case sdr.Limits == nil && limits != nil:
|
|
sdr.Limits = limits
|
|
case sdr.Limits != nil && limits == nil:
|
|
fallthrough
|
|
case sdr.Limits == nil && limits == nil:
|
|
return
|
|
default:
|
|
sdr.Limits.MergeExistingWin(limits)
|
|
}
|
|
}
|
|
|
|
func (sdr *ServiceDeployResources) mergeExistingWinReservations(reservations *ServiceDeployResourcesLimits) {
|
|
switch {
|
|
case sdr.Reservations == nil && reservations != nil:
|
|
sdr.Reservations = reservations
|
|
case sdr.Reservations != nil && reservations == nil:
|
|
fallthrough
|
|
case sdr.Reservations == nil && reservations == nil:
|
|
return
|
|
default:
|
|
sdr.Reservations.MergeExistingWin(reservations)
|
|
}
|
|
}
|
|
|
|
func (sdr *ServiceDeployResources) mergeLastWinLimits(limits *ServiceDeployResourcesLimits) {
|
|
switch {
|
|
case sdr.Limits == nil && limits != nil:
|
|
sdr.Limits = limits
|
|
case sdr.Limits != nil && limits == nil:
|
|
fallthrough
|
|
case sdr.Limits == nil && limits == nil:
|
|
return
|
|
default:
|
|
sdr.Limits.MergeLastWin(limits)
|
|
}
|
|
}
|
|
|
|
func (sdr *ServiceDeployResources) mergeLastWinReservations(reservations *ServiceDeployResourcesLimits) {
|
|
switch {
|
|
case sdr.Reservations == nil && reservations != nil:
|
|
sdr.Reservations = reservations
|
|
case sdr.Reservations != nil && reservations == nil:
|
|
fallthrough
|
|
case sdr.Reservations == nil && reservations == nil:
|
|
return
|
|
default:
|
|
sdr.Reservations.MergeLastWin(reservations)
|
|
}
|
|
}
|
|
|
|
func NewServiceDeployResources() *ServiceDeployResources {
|
|
return &ServiceDeployResources{
|
|
Limits: new(ServiceDeployResourcesLimits),
|
|
Reservations: new(ServiceDeployResourcesLimits),
|
|
}
|
|
}
|
|
|
|
type ServiceDeployResourcesLimits struct {
|
|
CPUs string `json:"cpus,omitempty" yaml:"cpus,omitempty"`
|
|
Memory string `json:"memory,omitempty" yaml:"memory,omitempty"`
|
|
}
|
|
|
|
// Equal returns true if the passed equalable is equal
|
|
func (sdrl *ServiceDeployResourcesLimits) Equal(equalable Equalable) bool {
|
|
serviceDeployResourcesLimits, ok := equalable.(*ServiceDeployResourcesLimits)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
switch {
|
|
case sdrl == nil && serviceDeployResourcesLimits == nil:
|
|
return true
|
|
case sdrl != nil && serviceDeployResourcesLimits == nil:
|
|
fallthrough
|
|
case sdrl == nil && serviceDeployResourcesLimits != nil:
|
|
return false
|
|
default:
|
|
return sdrl.CPUs == serviceDeployResourcesLimits.CPUs &&
|
|
sdrl.Memory == serviceDeployResourcesLimits.Memory
|
|
}
|
|
}
|
|
|
|
// MergeExistingWin adds only attributes of the passed serviceDeployResourcesLimits
|
|
// if they are not already exists.
|
|
func (sdrl *ServiceDeployResourcesLimits) MergeExistingWin(serviceDeployResourcesLimits *ServiceDeployResourcesLimits) {
|
|
switch {
|
|
case sdrl == nil && serviceDeployResourcesLimits == nil:
|
|
fallthrough
|
|
case sdrl != nil && serviceDeployResourcesLimits == nil:
|
|
return
|
|
|
|
// WARN: It's not possible to change the memory pointer sdrl *ServiceDeployResourcesLimits
|
|
// to a new initialized serviceDeployResourcesLimits without returning the
|
|
// serviceDeployResourcesLimits it self.
|
|
//
|
|
// case sdrl == nil && serviceDeployResourcesLimits != nil:
|
|
// sdrl = NewServiceDeployResourcesLimits()
|
|
// fallthrough
|
|
|
|
default:
|
|
sdrl.mergeExistingWinCPUs(serviceDeployResourcesLimits.CPUs)
|
|
sdrl.mergeExistingWinMemory(serviceDeployResourcesLimits.Memory)
|
|
}
|
|
}
|
|
|
|
// MergeLastWin merges adds or overwrite the attributes of the passed
|
|
// serviceDeployResourcesLimits with the existing one.
|
|
func (sdrl *ServiceDeployResourcesLimits) MergeLastWin(serviceDeployResourcesLimits *ServiceDeployResourcesLimits) {
|
|
switch {
|
|
case sdrl == nil && serviceDeployResourcesLimits == nil:
|
|
fallthrough
|
|
case sdrl != nil && serviceDeployResourcesLimits == nil:
|
|
return
|
|
|
|
// WARN: It's not possible to change the memory pointer sdrl *ServiceDeployResourcesLimits
|
|
// to a new initialized serviceDeployResourcesLimits without returning the
|
|
// serviceDeployResourcesLimits it self.
|
|
//
|
|
// case sdrl == nil && serviceDeployResourcesLimits != nil:
|
|
// sdrl = NewServiceDeployResourcesLimits()
|
|
// fallthrough
|
|
|
|
default:
|
|
sdrl.mergeLastWinCPUs(serviceDeployResourcesLimits.CPUs)
|
|
sdrl.mergeLastWinMemory(serviceDeployResourcesLimits.Memory)
|
|
}
|
|
}
|
|
|
|
func (sdrl *ServiceDeployResourcesLimits) mergeExistingWinCPUs(cpus string) {
|
|
if len(sdrl.CPUs) <= 0 {
|
|
sdrl.CPUs = cpus
|
|
}
|
|
}
|
|
|
|
func (sdrl *ServiceDeployResourcesLimits) mergeExistingWinMemory(memory string) {
|
|
if len(sdrl.Memory) <= 0 {
|
|
sdrl.Memory = memory
|
|
}
|
|
}
|
|
|
|
func (sdrl *ServiceDeployResourcesLimits) mergeLastWinCPUs(cpus string) {
|
|
if sdrl.CPUs != cpus {
|
|
sdrl.CPUs = cpus
|
|
}
|
|
}
|
|
|
|
func (sdrl *ServiceDeployResourcesLimits) mergeLastWinMemory(memory string) {
|
|
if sdrl.Memory != memory {
|
|
sdrl.Memory = memory
|
|
}
|
|
}
|
|
|
|
func NewServiceDeployResourcesLimits() *ServiceDeployResourcesLimits {
|
|
return &ServiceDeployResourcesLimits{}
|
|
}
|
|
|
|
type ServiceNetwork struct {
|
|
Aliases []string `json:"aliases,omitempty" yaml:"aliases,omitempty"`
|
|
}
|
|
|
|
// Equal returns true if the passed equalable is equal
|
|
func (sn *ServiceNetwork) Equal(equalable Equalable) bool {
|
|
serviceNetwork, ok := equalable.(*ServiceNetwork)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
switch {
|
|
case sn == nil && serviceNetwork == nil:
|
|
return true
|
|
case sn != nil && serviceNetwork == nil:
|
|
fallthrough
|
|
case sn == nil && serviceNetwork != nil:
|
|
return false
|
|
default:
|
|
return equalSlice(sn.Aliases, serviceNetwork.Aliases)
|
|
}
|
|
}
|
|
|
|
// MergeExistingWin adds only attributes of the passed
|
|
// serviceNetwork if they are undefined.
|
|
func (sn *ServiceNetwork) MergeExistingWin(serviceNetwork *ServiceNetwork) {
|
|
switch {
|
|
case sn == nil && serviceNetwork == nil:
|
|
fallthrough
|
|
case sn != nil && serviceNetwork == nil:
|
|
return
|
|
|
|
// WARN: It's not possible to change the memory pointer sn *ServiceNetwork to a new
|
|
// initialized ServiceNetwork without returning the serviceNetwork it self.
|
|
//
|
|
// case l == nil && serviceULimits != nil:
|
|
// l = NewServiceULimits()
|
|
// fallthrough
|
|
|
|
case sn == nil && serviceNetwork != nil:
|
|
sn = NewServiceNetwork()
|
|
fallthrough
|
|
default:
|
|
sn.mergeExistingWinAliases(serviceNetwork.Aliases)
|
|
}
|
|
}
|
|
|
|
// MergeLastWin merges adds or overwrite the attributes of the passed
|
|
// serviceNetwork with the existing one.
|
|
func (sn *ServiceNetwork) MergeLastWin(serviceNetwork *ServiceNetwork) {
|
|
switch {
|
|
case sn == nil && serviceNetwork == nil:
|
|
fallthrough
|
|
case sn != nil && serviceNetwork == nil:
|
|
return
|
|
|
|
// WARN: It's not possible to change the memory pointer sn *ServiceNetwork to a new
|
|
// initialized ServiceNetwork without returning the serviceNetwork it self.
|
|
//
|
|
// case l == nil && serviceULimits != nil:
|
|
// l = NewServiceULimits()
|
|
// fallthrough
|
|
|
|
case sn == nil && serviceNetwork != nil:
|
|
sn = NewServiceNetwork()
|
|
fallthrough
|
|
default:
|
|
sn.mergeLastWinAliases(serviceNetwork.Aliases)
|
|
}
|
|
}
|
|
|
|
func (sn *ServiceNetwork) mergeExistingWinAliases(aliases []string) {
|
|
for _, alias := range aliases {
|
|
if !existsInSlice(sn.Aliases, alias) && len(alias) > 0 {
|
|
sn.Aliases = append(sn.Aliases, alias)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (sn *ServiceNetwork) mergeLastWinAliases(aliases []string) {
|
|
for _, alias := range aliases {
|
|
if !existsInSlice(sn.Aliases, alias) && len(alias) > 0 {
|
|
sn.Aliases = append(sn.Aliases, alias)
|
|
}
|
|
}
|
|
}
|
|
|
|
func NewServiceNetwork() *ServiceNetwork {
|
|
return &ServiceNetwork{
|
|
Aliases: make([]string, 0),
|
|
}
|
|
}
|
|
|
|
type ServiceULimits struct {
|
|
NProc uint `json:"nproc,omitempty" yaml:"nproc,omitempty"`
|
|
NoFile *ServiceULimitsNoFile `json:"nofile,omitempty" yaml:"nofile,omitempty"`
|
|
}
|
|
|
|
// Equal returns true if the passed equalable is equal
|
|
func (l *ServiceULimits) Equal(equalable Equalable) bool {
|
|
serviceULimits, ok := equalable.(*ServiceULimits)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
switch {
|
|
case l == nil && serviceULimits == nil:
|
|
return true
|
|
case l != nil && serviceULimits == nil:
|
|
fallthrough
|
|
case l == nil && serviceULimits != nil:
|
|
return false
|
|
default:
|
|
return l.NProc == serviceULimits.NProc &&
|
|
l.NoFile.Equal(serviceULimits.NoFile)
|
|
}
|
|
}
|
|
|
|
// MergeExistingWin adds only the attributes of the passed ServiceULimits they are
|
|
// undefined.
|
|
func (l *ServiceULimits) MergeExistingWin(serviceULimits *ServiceULimits) {
|
|
switch {
|
|
case l == nil && serviceULimits == nil:
|
|
fallthrough
|
|
case l != nil && serviceULimits == nil:
|
|
return
|
|
|
|
// WARN: It's not possible to change the memory pointer l *ServiceULimits to a new
|
|
// initialized ServiceULimits without returning the serviceULimits it self.
|
|
//
|
|
// case l == nil && serviceULimits != nil:
|
|
// l = NewServiceULimits()
|
|
// fallthrough
|
|
|
|
default:
|
|
l.mergeExistingWinNProc(serviceULimits.NProc)
|
|
l.mergeExistingWinNoFile(serviceULimits.NoFile)
|
|
}
|
|
}
|
|
|
|
// MergeLastWin merges adds or overwrite the attributes of the passed
|
|
// ServiceULimits with the existing one.
|
|
func (l *ServiceULimits) MergeLastWin(serviceULimits *ServiceULimits) {
|
|
switch {
|
|
case l == nil && serviceULimits == nil:
|
|
fallthrough
|
|
case l != nil && serviceULimits == nil:
|
|
return
|
|
|
|
// WARN: It's not possible to change the memory pointer l *ServiceULimits to a new
|
|
// initialized ServiceULimits without returning the serviceULimits it self.
|
|
//
|
|
// case l == nil && serviceULimits != nil:
|
|
// l = NewServiceULimits()
|
|
// fallthrough
|
|
|
|
default:
|
|
l.mergeLastWinNProc(serviceULimits.NProc)
|
|
l.mergeLastWinNoFile(serviceULimits.NoFile)
|
|
}
|
|
}
|
|
|
|
func (l *ServiceULimits) mergeExistingWinNProc(nproc uint) {
|
|
if l.NProc != nproc {
|
|
return
|
|
}
|
|
l.NProc = nproc
|
|
}
|
|
|
|
func (l *ServiceULimits) mergeExistingWinNoFile(noFile *ServiceULimitsNoFile) {
|
|
if !l.NoFile.Equal(noFile) {
|
|
l.NoFile.MergeExistingWin(noFile)
|
|
}
|
|
}
|
|
|
|
func (l *ServiceULimits) mergeLastWinNProc(nproc uint) {
|
|
if l.NProc != nproc {
|
|
l.NProc = nproc
|
|
}
|
|
}
|
|
|
|
func (l *ServiceULimits) mergeLastWinNoFile(noFile *ServiceULimitsNoFile) {
|
|
if !l.NoFile.Equal(noFile) {
|
|
l.NoFile.MergeLastWin(noFile)
|
|
}
|
|
}
|
|
|
|
func NewServiceULimits() *ServiceULimits {
|
|
return &ServiceULimits{
|
|
NoFile: new(ServiceULimitsNoFile),
|
|
}
|
|
}
|
|
|
|
type ServiceULimitsNoFile struct {
|
|
Hard uint `json:"hard" yaml:"hard"`
|
|
Soft uint `json:"soft" yaml:"soft"`
|
|
}
|
|
|
|
// Equal returns true if the passed equalable is equal
|
|
func (nf *ServiceULimitsNoFile) Equal(equalable Equalable) bool {
|
|
serviceULimitsNoFile, ok := equalable.(*ServiceULimitsNoFile)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
switch {
|
|
case nf == nil && serviceULimitsNoFile == nil:
|
|
return true
|
|
case nf != nil && serviceULimitsNoFile == nil:
|
|
fallthrough
|
|
case nf == nil && serviceULimitsNoFile != nil:
|
|
return false
|
|
default:
|
|
return nf.Hard == serviceULimitsNoFile.Hard &&
|
|
nf.Soft == serviceULimitsNoFile.Soft
|
|
}
|
|
}
|
|
|
|
// MergeExistingWin adds only the attributes of the passed ServiceULimits they are
|
|
// undefined.
|
|
func (nf *ServiceULimitsNoFile) MergeExistingWin(serviceULimitsNoFile *ServiceULimitsNoFile) {
|
|
switch {
|
|
case nf == nil && serviceULimitsNoFile == nil:
|
|
fallthrough
|
|
case nf != nil && serviceULimitsNoFile == nil:
|
|
return
|
|
|
|
// WARN: It's not possible to change the memory pointer nf *ServiceULimitsNoFile
|
|
// to a new initialized ServiceULimitsNoFile without returning the serviceULimitsNoFile
|
|
// it self.
|
|
//
|
|
// case nf == nil && serviceULimitsNoFile != nil:
|
|
// nf = NewServiceULimitsNoFile()
|
|
// fallthrough
|
|
|
|
default:
|
|
nf.mergeExistingWinHard(serviceULimitsNoFile.Hard)
|
|
nf.mergeExistingWinSoft(serviceULimitsNoFile.Soft)
|
|
}
|
|
}
|
|
|
|
// MergeLastWin merges adds or overwrite the attributes of the passed
|
|
// ServiceULimitsNoFile with the existing one.
|
|
func (nf *ServiceULimitsNoFile) MergeLastWin(serviceULimitsNoFile *ServiceULimitsNoFile) {
|
|
switch {
|
|
case nf == nil && serviceULimitsNoFile == nil:
|
|
fallthrough
|
|
case nf != nil && serviceULimitsNoFile == nil:
|
|
return
|
|
|
|
// WARN: It's not possible to change the memory pointer nf *ServiceULimitsNoFile
|
|
// to a new initialized ServiceULimitsNoFile without returning the serviceULimitsNoFile
|
|
// it self.
|
|
//
|
|
// case nf == nil && serviceULimitsNoFile != nil:
|
|
// nf = NewServiceULimitsNoFile()
|
|
// fallthrough
|
|
|
|
default:
|
|
nf.mergeLastWinHard(serviceULimitsNoFile.Hard)
|
|
nf.mergeLastWinSoft(serviceULimitsNoFile.Soft)
|
|
}
|
|
}
|
|
|
|
func (nf *ServiceULimitsNoFile) mergeExistingWinHard(hard uint) {
|
|
if nf.Hard != hard {
|
|
return
|
|
}
|
|
nf.Hard = hard
|
|
}
|
|
|
|
func (nf *ServiceULimitsNoFile) mergeExistingWinSoft(soft uint) {
|
|
if nf.Soft != soft {
|
|
return
|
|
}
|
|
nf.Soft = soft
|
|
}
|
|
|
|
func (nf *ServiceULimitsNoFile) mergeLastWinHard(hard uint) {
|
|
if nf.Hard != hard {
|
|
nf.Hard = hard
|
|
}
|
|
}
|
|
|
|
func (nf *ServiceULimitsNoFile) mergeLastWinSoft(soft uint) {
|
|
if nf.Soft != soft {
|
|
nf.Soft = soft
|
|
}
|
|
}
|
|
|
|
func NewServiceULimitsNoFile() *ServiceULimitsNoFile {
|
|
return &ServiceULimitsNoFile{}
|
|
}
|
|
|
|
type Volume struct {
|
|
External bool `json:"external,omitempty" yaml:"external,omitempty"`
|
|
}
|
|
|
|
// Equal returns true if the passed equalable is equal
|
|
func (v *Volume) Equal(equalable Equalable) bool {
|
|
volume, ok := equalable.(*Volume)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
switch {
|
|
case v == nil && volume == nil:
|
|
return true
|
|
case v != nil && volume == nil:
|
|
fallthrough
|
|
case v == nil && volume != nil:
|
|
return false
|
|
default:
|
|
return v.External == volume.External
|
|
}
|
|
}
|
|
|
|
// MergeExistingWin adds only the attributes of the passed Volume they are
|
|
// undefined.
|
|
func (v *Volume) MergeExistingWin(volume *Volume) {
|
|
switch {
|
|
case v == nil && volume == nil:
|
|
fallthrough
|
|
case v != nil && volume == nil:
|
|
return
|
|
|
|
// WARN: It's not possible to change the memory pointer v *Volume to a new
|
|
// initialized Volume without returning the volume it self.
|
|
//
|
|
// case v == nil && volume != nil:
|
|
// v = NewVolume()
|
|
// fallthrough
|
|
|
|
default:
|
|
v.mergeExistingWinExternal(volume.External)
|
|
}
|
|
}
|
|
|
|
func (v *Volume) MergeLastWin(volume *Volume) {
|
|
switch {
|
|
case v == nil && volume == nil:
|
|
fallthrough
|
|
case v != nil && volume == nil:
|
|
return
|
|
|
|
// WARN: It's not possible to change the memory pointer v *Volume to a new
|
|
// initialized Volume without returning the volume it self.
|
|
//
|
|
// case v == nil && volume != nil:
|
|
// v = NewVolume()
|
|
// fallthrough
|
|
|
|
default:
|
|
v.mergeLastWinExternal(volume.External)
|
|
}
|
|
}
|
|
|
|
func (v *Volume) mergeExistingWinExternal(_ bool) {
|
|
if v.External {
|
|
return
|
|
}
|
|
v.External = true
|
|
}
|
|
|
|
func (v *Volume) mergeLastWinExternal(external bool) {
|
|
if v.External != external {
|
|
v.External = external
|
|
}
|
|
}
|
|
|
|
func NewVolume() *Volume {
|
|
return &Volume{
|
|
External: false,
|
|
}
|
|
}
|
|
|
|
// existsInSlice returns true when the passed comparable K exists in slice of
|
|
// comparables []K.
|
|
func existsInSlice[K comparable](comparables []K, k K) bool {
|
|
for _, c := range comparables {
|
|
if c == k {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func equalSlice[K comparable](sliceA []K, sliceB []K) bool {
|
|
equalFunc := func(sliceA []K, sliceB []K) bool {
|
|
LOOP:
|
|
for i := range sliceA {
|
|
for j := range sliceB {
|
|
if sliceA[i] == sliceB[j] {
|
|
continue LOOP
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
return equalFunc(sliceA, sliceB) && equalFunc(sliceB, sliceA)
|
|
}
|
|
|
|
func splitStringInKeyValue(s, sep string) (string, string) {
|
|
key := strings.Split(s, sep)[0]
|
|
value := strings.TrimPrefix(s, fmt.Sprintf("%s%s", key, sep))
|
|
return key, value
|
|
}
|
|
|
|
// splitStringInPortMapping parses a string and returns the src, dest port including an optional protocol.
|
|
//
|
|
// // Example
|
|
// s, d, p := splitStringInPortMapping("80:80/tcp")
|
|
// // Output: "80" "80" "tcp"
|
|
// s, d, p := splitStringInPortMapping("0.0.0.0:80:80/tcp")
|
|
// // Output: "0.0.0.0:80" "80" "tcp"
|
|
//
|
|
// Deprecated: Instead of using the splitStringInPortMapping function, use the method of the type Port{}.
|
|
func splitStringInPortMapping(s string) (string, string, string) {
|
|
p := Port(s)
|
|
|
|
var src string
|
|
switch {
|
|
case p.existsSrcIP() && p.existsSrcPort():
|
|
src = fmt.Sprintf("%s:%s", p.getSrcIP(), p.getSrcPort())
|
|
case !p.existsSrcIP():
|
|
src = p.getSrcPort()
|
|
}
|
|
|
|
var dst string
|
|
switch {
|
|
case p.existsDstIP() && p.existsDstPort():
|
|
dst = fmt.Sprintf("%s:%s", p.getDstIP(), p.getDstPort())
|
|
case !p.existsDstIP():
|
|
dst = p.getDstPort()
|
|
}
|
|
|
|
return src, dst, p.getProtocol()
|
|
}
|
|
|
|
func splitStringInVolume(s string) (string, string, string) {
|
|
parts := strings.Split(s, volumeDelimiter)
|
|
src := parts[0]
|
|
dest := parts[1]
|
|
if len(parts) == 3 && len(parts[2]) > 0 {
|
|
perm := parts[2]
|
|
return src, dest, perm
|
|
}
|
|
return src, dest, ""
|
|
}
|
|
|
|
var (
|
|
regExpPort = regexp.MustCompile(`^((?<srcIP>([\d]{1,3}\.){3}[\d]{1,3}):)?(?<srcPort>[\d]{1,5}):((?<dstIP>([\d]{1,3}\.){3}[\d]{1,3}):)?(?<dstPort>[\d]{1,5})(\/(?<protocol>[a-z]*))?$`)
|
|
)
|
|
|
|
type Port string
|
|
|
|
// existsDstPort returns true, if the port string contains a trailing destination port definition.
|
|
func (p Port) existsDstPort() bool {
|
|
return len(p.getDstPort()) > 0
|
|
}
|
|
|
|
// existsDstIP returns true, if the port string contains a trailing destination ip definition.
|
|
func (p Port) existsDstIP() bool {
|
|
return len(p.getDstIP()) > 0
|
|
}
|
|
|
|
// existsProtocol returns true, if the port string contains a protocol definition.
|
|
func (p Port) existsProtocol() bool {
|
|
return len(p.getProtocol()) > 0
|
|
}
|
|
|
|
// existsSrcIP returns true, if the port string contains a leading src ip definition.
|
|
func (p Port) existsSrcIP() bool {
|
|
return len(p.getSrcIP()) > 0
|
|
}
|
|
|
|
// existsSrcPort returns true, if the port string contains a leading src port definition.
|
|
func (p Port) existsSrcPort() bool {
|
|
return len(p.getSrcPort()) > 0
|
|
}
|
|
|
|
// getDst returns the concatenation of the destination ip and port. If the destination ip is empty, only the port will
|
|
// be returned.
|
|
func (p Port) getDst() string {
|
|
switch {
|
|
case p.existsDstIP():
|
|
return fmt.Sprintf("%s%s%s", p.getDstIP(), portDelimiter, p.getDstPort())
|
|
default:
|
|
return p.getDstPort()
|
|
}
|
|
}
|
|
|
|
// getSrcIP returns the destination ip, if the port string contains a destination ip definition.
|
|
func (p Port) getDstIP() string {
|
|
matches := regExpPort.FindStringSubmatch(string(p))
|
|
i := regExpPort.SubexpIndex("dstIP")
|
|
|
|
switch {
|
|
case len(matches) <= 0:
|
|
return ""
|
|
case i < 0:
|
|
return ""
|
|
}
|
|
|
|
return matches[i]
|
|
}
|
|
|
|
// getSrcPort returns the destination port, if the port string contains an destination port definition.
|
|
func (p Port) getDstPort() string {
|
|
matches := regExpPort.FindStringSubmatch(string(p))
|
|
i := regExpPort.SubexpIndex("dstPort")
|
|
|
|
switch {
|
|
case len(matches) <= 0:
|
|
return ""
|
|
case i < 0:
|
|
return ""
|
|
}
|
|
|
|
return matches[i]
|
|
}
|
|
|
|
// getProtocol returns the protocol, if the port string contains a protocol definition.
|
|
func (p Port) getProtocol() string {
|
|
matches := regExpPort.FindStringSubmatch(string(p))
|
|
i := regExpPort.SubexpIndex("protocol")
|
|
|
|
switch {
|
|
case len(matches) <= 0:
|
|
return ""
|
|
case i < 0:
|
|
return ""
|
|
}
|
|
|
|
return matches[i]
|
|
}
|
|
|
|
// getSrc returns the concatenation of the source ip and port. If the source ip is empty, only the port will be
|
|
// returned.
|
|
func (p Port) getSrc() string {
|
|
switch {
|
|
case p.existsSrcIP():
|
|
return fmt.Sprintf("%s%s%s", p.getSrcIP(), portDelimiter, p.getSrcPort())
|
|
default:
|
|
return p.getSrcPort()
|
|
}
|
|
}
|
|
|
|
// getSrcIP returns the source ip, if the port string contains an src ip definition.
|
|
func (p Port) getSrcIP() string {
|
|
matches := regExpPort.FindStringSubmatch(string(p))
|
|
i := regExpPort.SubexpIndex("srcIP")
|
|
|
|
switch {
|
|
case len(matches) <= 0:
|
|
return ""
|
|
case i < 0:
|
|
return ""
|
|
}
|
|
|
|
return matches[i]
|
|
}
|
|
|
|
// getSrcPort returns the source port, if the port string contains an src port definition.
|
|
func (p Port) getSrcPort() string {
|
|
matches := regExpPort.FindStringSubmatch(string(p))
|
|
i := regExpPort.SubexpIndex("srcPort")
|
|
|
|
switch {
|
|
case len(matches) <= 0:
|
|
return ""
|
|
case i < 0:
|
|
return ""
|
|
}
|
|
|
|
return matches[i]
|
|
}
|