Skip to content

Commit

Permalink
Merge pull request #25 from cego/dest-network-detach
Browse files Browse the repository at this point in the history
Attach/detach to network
  • Loading branch information
staal0 authored Apr 3, 2024
2 parents 1e9d52d + 061dba9 commit 00e9aba
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 8 deletions.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
# Container manager
Used to ensure that containers is running.
Used to ensure that containers listed in config.yml is running and
is connected to Docker networks.

- Start/stop containers listed in config.yml
- Add to network listed in config.yml
- Detach from network if it is not being used (attachAllNetwork only)

See config.example.yaml for configutation example.
100 changes: 93 additions & 7 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import (
var Build string

const (
appName = "container-manager"
appName string = "container-manager"
)

var (
Expand Down Expand Up @@ -190,7 +190,16 @@ func NewManager(l *logrus.Logger) (*manager, error) {
}

func (m *manager) run(config *Config) {
networkNames, err := m.getNetworkNames()
// Create a list of container-manager containers
containerNames := []string{}
for _, c := range config.Containers {
if c.AttachAllNetwork {
containerNames = append(containerNames, c.Name)
}
}

// Returns a list of networks with more than 0 containers attached
networkNames, err := m.getNetworkNames(containerNames)
if err != nil {
m.l.Error(err)
return
Expand Down Expand Up @@ -253,9 +262,31 @@ func (m *manager) ensureContainer(config Container, networks []string) error {

m.l.WithField("name", config.Name).Debugf("Networks expected: %s", networks)
m.l.WithField("name", config.Name).Debugf("Networks current: %s", networkNames)

if !reflect.DeepEqual(networks, networkNames) {
m.l.WithField("name", config.Name).Debugf("Network config differ, recreate %s", config.Name)
reCreate = true
m.l.WithField("name", config.Name).Debugf("Network config differ, attach/detach %s", config.Name)

// New networks attach
for _, network := range networks {
// Inspect each network to get attached containers
attached, err := m.cli.NetworkInspect(m.ctx, network, types.NetworkInspectOptions{})
if err != nil {
m.l.Error(err)
}

// If container is not already attached to network
if !containerInNetworks(config.Name, attached) {
m.attachNetwork(network, config.Name)
}
}

m.l.WithField("name", config.Name).Debugf("Network detach diff: %s\n", difference(networkNames, networks))

// Old networks detach
for _, network := range difference(networkNames, networks) {
// Detach from network diff
m.detachNetwork(network, config.Name)
}
}

volumesExpected := make([]string, len(config.Volumes))
Expand Down Expand Up @@ -442,7 +473,7 @@ func (m *manager) stopContainers(config *Config) {
}
}

func (m *manager) getNetworkNames() ([]string, error) {
func (m *manager) getNetworkNames(containerNames []string) ([]string, error) {
names := []string{}

networks, err := m.cli.NetworkList(m.ctx, types.NetworkListOptions{})
Expand All @@ -451,8 +482,18 @@ func (m *manager) getNetworkNames() ([]string, error) {
}

for _, network := range networks {
if (network.Attachable || network.Scope == "local") && !containsString(ignoredNetworkNames, network.Name) {
names = append(names, network.Name)
// Inspect each network to get attached containers
attached, err := m.cli.NetworkInspect(m.ctx, network.Name, types.NetworkInspectOptions{})
if err != nil {
return nil, err
}
for _, endpoint := range attached.Containers {
if !containsString(containerNames, endpoint.Name) &&
(network.Attachable || network.Scope == "local") &&
!containsString(ignoredNetworkNames, network.Name) {
names = append(names, network.Name)
break
}
}
}

Expand All @@ -461,6 +502,51 @@ func (m *manager) getNetworkNames() ([]string, error) {
return names, nil
}

// validate if a container is in a given network
func containerInNetworks(containerName string, attached types.NetworkResource) bool {
for _, c := range attached.Containers {
if containerName == c.Name {
return true
}
}
return false
}

// difference returns the elements in `a` that aren't in `b`.
func difference(a, b []string) []string {
mb := make(map[string]struct{}, len(b))
for _, x := range b {
mb[x] = struct{}{}
}
var diff []string
for _, x := range a {
if _, found := mb[x]; !found {
diff = append(diff, x)
}
}
return diff
}

// detach from network from container
func (m *manager) detachNetwork(network string, container string) {
err := m.cli.NetworkDisconnect(m.ctx, network, container, true)

m.l.Debugf("Detaching %s from network %s\n", container, network)

if err != nil {
m.l.Error(err)
}
}

// attach from network from container
func (m *manager) attachNetwork(network string, container string) {
err := m.cli.NetworkConnect(m.ctx, network, container, nil)
if err != nil {
m.l.Error(err)
}
m.l.Debugf("Attaching %s to network %s\n", container, network)
}

func containsString(strings []string, s string) bool {
for _, a := range strings {
if s == a {
Expand Down

0 comments on commit 00e9aba

Please sign in to comment.