Skip to content

Commit

Permalink
connect to additional networks on container start
Browse files Browse the repository at this point in the history
  • Loading branch information
whimbree committed May 27, 2023
1 parent 0fd7626 commit bc9a1b4
Showing 1 changed file with 71 additions and 10 deletions.
81 changes: 71 additions & 10 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@ import (
"github.com/docker/docker/api/types"
containerType "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/client"
)

const DEPENDHEAL_ENABLE_ALL_ENVAR = "DEPENDHEAL_ENABLE_ALL"

type ContainerData struct {
ID string
Name string
Labels map[string]string
ID string
Name string
Labels map[string]string
Networks []string
}

type RestartContext struct {
Expand All @@ -40,7 +42,7 @@ func restartChild(cli *client.Client, ctx context.Context, restartContext Restar
if err := cli.ContainerRestart(ctx, restartContext.containerID, containerType.StopOptions{}); err == nil {
break
}
_ = fmt.Errorf("Error when restarting container: %s, attempt: %d\n", restartContext.containerName, i+1)
_ = fmt.Errorf("error when restarting container: %s, attempt: %d\n", restartContext.containerName, i+1)
}
}

Expand All @@ -50,6 +52,10 @@ func restartChildren(cli *client.Client, ctx context.Context, RestartContexts []
}
}

func connectNetwork(cli *client.Client, ctx context.Context, networkID, containerID string) {
go cli.NetworkConnect(ctx, networkID, containerID, &network.EndpointSettings{})
}

func isContainerUnhealthy(cli *client.Client, ctx context.Context, containerID string) (bool, error) {
containerJSON, err := cli.ContainerInspect(ctx, containerID)
if err != nil {
Expand All @@ -67,6 +73,29 @@ func delayedRestart(cli *client.Client, ctx context.Context, restartContext Rest
restartChild(cli, ctx, restartContext)
}

func getNetworkNameIDMapping(cli *client.Client, ctx context.Context) map[string]string {
// Create a mapping between networkName and networkID
networkNameIDMapping := make(map[string]string)
networks, _ := cli.NetworkList(ctx, types.NetworkListOptions{})
for _, network := range networks {
fmt.Printf("Network: %s, id: %s\n", network.Name, network.ID)
networkNameIDMapping[network.Name] = network.ID
}
return networkNameIDMapping
}

func parseCommaSeperatedList(stringList string) []string {
var returnList []string
splitStringList := strings.Split(stringList, ",")
for _, item := range splitStringList {
item = strings.TrimSpace(item)
if len(item) != 0 {
returnList = append(returnList, item)
}
}
return returnList
}

func main() {
cli, err := client.NewClientWithOpts(client.WithHost("unix:///var/run/docker.sock"))
if err != nil {
Expand All @@ -86,7 +115,7 @@ func main() {
if enable_all_envar, ok := os.LookupEnv(DEPENDHEAL_ENABLE_ALL_ENVAR); ok {
enable_all, err = strconv.ParseBool(enable_all_envar)
if err != nil {
_ = fmt.Errorf("Expected boolean for environment variable %s, provided %s", DEPENDHEAL_ENABLE_ALL_ENVAR, enable_all_envar)
_ = fmt.Errorf("expected boolean for environment variable %s, provided %s", DEPENDHEAL_ENABLE_ALL_ENVAR, enable_all_envar)
}
}
if enable_all {
Expand All @@ -99,11 +128,16 @@ func main() {
for _, container := range containers {
if enable_all || hasLabel(container.Labels, "dependheal.enable", "true") {
name := strings.TrimPrefix(container.Names[0], "/")
fmt.Printf("Watching container: %s\n", name)
watchedContainers[container.ID] = ContainerData{container.ID, name, container.Labels}
// Encode dependheal.networks = network1, network2, ...
var networks []string
if networklabel, ok := container.Labels["dependheal.networks"]; ok {
networks = parseCommaSeperatedList(networklabel)
}
fmt.Printf("Watching container: %s networks: %v\n", name, networks)
watchedContainers[container.ID] = ContainerData{container.ID, name, container.Labels, networks}
isUnhealthy, err := isContainerUnhealthy(cli, ctx, container.ID)
if err != nil {
_ = fmt.Errorf("Checking health status of %s failed", name)
_ = fmt.Errorf("checking health status of %s failed", name)
continue
}
if isUnhealthy {
Expand All @@ -119,6 +153,18 @@ func main() {
go delayedRestart(cli, ctx, restartContext, timeout)
}

networkNameIDMapping := getNetworkNameIDMapping(cli, ctx)

// Make sure every container is connected to its networks
for _, container := range watchedContainers {
for _, network := range container.Networks {
if networkID, ok := networkNameIDMapping[network]; ok {
fmt.Printf("Connecting container: %s to network: %s\n", container.Name, network)
connectNetwork(cli, ctx, networkID, container.ID)
}
}
}

// Listen for Docker events and act on them
eventFilter := filters.NewArgs()
eventFilter.Add("type", "container")
Expand All @@ -137,11 +183,26 @@ func main() {
case event := <-eventChan:
if event.Type == "container" {
if event.Action == "start" {
// Update networkName -> networkID mapping
networkNameIDMapping = getNetworkNameIDMapping(cli, ctx)
// Check if started container has dependheal.enable = true
if enable_all || hasLabel(event.Actor.Attributes, "dependheal.enable", "true") {
parentContainer := ContainerData{event.Actor.ID, event.Actor.Attributes["name"], event.Actor.Attributes}
fmt.Printf("Container started: %s\n", parentContainer.Name)
// Encode dependheal.networks = network1, network2, ...
var networks []string
if networklabel, ok := event.Actor.Attributes["dependheal.networks"]; ok {
networks = parseCommaSeperatedList(networklabel)
}
parentContainer := ContainerData{event.Actor.ID, event.Actor.Attributes["name"], event.Actor.Attributes, networks}
watchedContainers[parentContainer.ID] = parentContainer
fmt.Printf("Container started: %s networks: %v\n", parentContainer.Name, parentContainer.Networks)

// Make sure container is connected to its networks
for _, network := range parentContainer.Networks {
if networkID, ok := networkNameIDMapping[network]; ok {
fmt.Printf("Connecting container: %s to network: %s\n", parentContainer.Name, network)
connectNetwork(cli, ctx, networkID, parentContainer.ID)
}
}

children := make([]RestartContext, 0)
childrenOnHealthy := make([]RestartContext, 0)
Expand Down

0 comments on commit bc9a1b4

Please sign in to comment.