gitlab.com/postgres-ai/database-lab/v3@v3.0.3/pkg/util/networks/networks.go (about) 1 /* 2 2021 © Postgres.ai 3 */ 4 5 // Package networks describes custom network elements. 6 package networks 7 8 import ( 9 "context" 10 "fmt" 11 12 "github.com/docker/docker/api/types" 13 "github.com/docker/docker/api/types/network" 14 "github.com/docker/docker/client" 15 16 "gitlab.com/postgres-ai/database-lab/v3/pkg/log" 17 ) 18 19 const ( 20 // DLEApp contains name of the Database Lab Engine network. 21 DLEApp = "DLE" 22 23 // InternalType contains name of the internal network type. 24 InternalType = "internal" 25 26 // networkPrefix defines a distinctive prefix for internal DLE networks. 27 networkPrefix = "dle_network_" 28 ) 29 30 // Setup creates a new internal Docker network and connects container to it. 31 func Setup(ctx context.Context, dockerCLI *client.Client, instanceID, containerName string) (string, error) { 32 networkName := getNetworkName(instanceID) 33 34 log.Dbg("Discovering internal network:", networkName) 35 36 networkResource, err := dockerCLI.NetworkInspect(ctx, networkName, types.NetworkInspectOptions{}) 37 if err == nil { 38 if !hasContainerConnected(networkResource, containerName) { 39 if err := dockerCLI.NetworkConnect(ctx, networkResource.ID, containerName, &network.EndpointSettings{}); err != nil { 40 return "", err 41 } 42 43 log.Dbg(fmt.Sprintf("Container %s has been connected to %s", containerName, networkName)) 44 } 45 46 return networkResource.ID, nil 47 } 48 49 log.Dbg("Internal network not found:", err.Error()) 50 log.Dbg("Creating a new internal network:", networkName) 51 52 internalNetwork, err := dockerCLI.NetworkCreate(ctx, networkName, types.NetworkCreate{ 53 Labels: map[string]string{ 54 "instance": instanceID, 55 "app": DLEApp, 56 "type": InternalType, 57 }, 58 Attachable: true, 59 Internal: true, 60 CheckDuplicate: true, 61 }) 62 if err != nil { 63 return "", err 64 } 65 66 log.Dbg("A new internal network has been created:", internalNetwork.ID) 67 68 if err := dockerCLI.NetworkConnect(ctx, internalNetwork.ID, containerName, &network.EndpointSettings{}); err != nil { 69 return "", err 70 } 71 72 return internalNetwork.ID, nil 73 } 74 75 // Stop disconnect all containers from the network and removes it. 76 func Stop(dockerCLI *client.Client, internalNetworkID, containerName string) { 77 log.Dbg("Disconnecting DLE container from the internal network:", containerName) 78 79 if err := dockerCLI.NetworkDisconnect(context.Background(), internalNetworkID, containerName, true); err != nil { 80 log.Errf(err.Error()) 81 return 82 } 83 84 log.Dbg("DLE container has been disconnected from the internal network:", containerName) 85 86 networkInspect, err := dockerCLI.NetworkInspect(context.Background(), internalNetworkID, types.NetworkInspectOptions{}) 87 if err != nil { 88 log.Errf(err.Error()) 89 return 90 } 91 92 if len(networkInspect.Containers) == 0 { 93 log.Dbg("No containers connected to the internal network. Removing network:", internalNetworkID) 94 95 if err := dockerCLI.NetworkRemove(context.Background(), internalNetworkID); err != nil { 96 log.Errf(err.Error()) 97 return 98 } 99 100 log.Dbg("The internal network has been removed:", internalNetworkID) 101 } 102 } 103 104 // Connect connects a container to an internal Docker network. 105 func Connect(ctx context.Context, dockerCLI *client.Client, instanceID, containerID string) error { 106 networkName := getNetworkName(instanceID) 107 108 log.Dbg("Discovering internal network:", networkName) 109 110 networkResource, err := dockerCLI.NetworkInspect(ctx, networkName, types.NetworkInspectOptions{}) 111 if err != nil { 112 return fmt.Errorf("internal network not found: %w", err) 113 } 114 115 if !hasContainerConnected(networkResource, containerID) { 116 if err := dockerCLI.NetworkConnect(ctx, networkResource.ID, containerID, &network.EndpointSettings{}); err != nil { 117 return err 118 } 119 120 log.Dbg(fmt.Sprintf("Container %s has been connected to %s", instanceID, networkName)) 121 } 122 123 return nil 124 } 125 126 // Reconnect connects a container to internal Docker network. 127 func Reconnect(ctx context.Context, dockerCLI *client.Client, instanceID, containerID string) error { 128 log.Dbg(fmt.Sprintf("Reconnect container %s to internal network", containerID)) 129 130 networkName := getNetworkName(instanceID) 131 132 log.Dbg("Discovering internal network:", networkName) 133 134 networkResource, err := dockerCLI.NetworkInspect(ctx, networkName, types.NetworkInspectOptions{}) 135 if err != nil { 136 return fmt.Errorf("internal network not found: %w", err) 137 } 138 139 log.Dbg(fmt.Sprintf("Disconnecting container %s from internal network", containerID)) 140 141 if err := dockerCLI.NetworkDisconnect(context.Background(), networkName, containerID, true); err != nil { 142 return err 143 } 144 145 log.Dbg(fmt.Sprintf("Container %s has been disconnected from internal network", containerID)) 146 147 if err := dockerCLI.NetworkConnect(ctx, networkResource.ID, containerID, &network.EndpointSettings{}); err != nil { 148 return err 149 } 150 151 log.Dbg(fmt.Sprintf("Container %s has been connected to %s", instanceID, networkName)) 152 153 return nil 154 } 155 156 func hasContainerConnected(networkResource types.NetworkResource, containerID string) bool { 157 for _, container := range networkResource.Containers { 158 if container.Name == containerID { 159 return true 160 } 161 } 162 163 return false 164 } 165 166 func getNetworkName(instanceID string) string { 167 return networkPrefix + instanceID 168 }