package main import ( "context" "fmt" "log" "os" "time" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/mount" "github.com/docker/docker/api/types/network" "github.com/docker/docker/client" ) const ( fixedDockerVersion = "1.38" ) var ( dockerCtx context.Context dockerCLI *client.Client ) func setupContext() { if dockerCtx == nil { dockerCtx = context.Background() } } func setupDockerCLI() (err error) { os.Setenv("DOCKER_API_VERSION", "1.27") if dockerCLI == nil { dockerCLI, err = client.NewEnvClient() } return err } func spawnCompanion(username string, accesscode string) { log.Println("Spwaning a new companion container") // setup the context and the docker cli connection setupContext() setupDockerCLI() sessionSalt := generateSessionSalt() vpnRemoteAddress := "127.0.0.1" vpnRemotePort := "1193" log.Println("Generating the container config") Config := &container.Config{ Image: "circus-companion:latest", Shell: []string{"/workdir/register", "-username", username, "-accesscode", accesscode, "sessionSalt", sessionSalt, "-vpnRemoteAddress", vpnRemoteAddress, "-vpnRemotePort", vpnRemotePort}, // Container labels used by traefik Labels: map[string]string{ "traefik.enable": "true", "traefik.http.routers.companion.entrypoints": "web", "traefik.http.routers.companion.rule": "Host(`companion.docker.localhost`)", "traefik.http.services.companion.loadbalancer.server.port": "8080", }, } // configure the host // this mounts the docker socket and the companion seed file into the // container HostConfig := &container.HostConfig{ Mounts: []mount.Mount{ { Type: mount.TypeBind, Source: "/var/run/docker.sock", Target: "/var/run/docker.sock", }, { Type: mount.TypeBind, Source: "/etc/companion.json", Target: "/etc/companion.json", }, }, } circusNetworkID, err := getCircusNetworkID(dockerCtx, dockerCLI) NetworkingConfig := &network.NetworkingConfig{ EndpointsConfig: map[string]*network.EndpointSettings{ "circus": { NetworkID: circusNetworkID, }, }, } log.Println("Creating the container") // create the docker container resp, err := dockerCLI.ContainerCreate(dockerCtx, Config, HostConfig, NetworkingConfig, "") if err != nil { panic(err) } log.Println("Container created!") // id of the created container containerID := resp.ID // start the docker container err = dockerCLI.ContainerStart(dockerCtx, containerID, types.ContainerStartOptions{}) if err != nil { fmt.Println(err) } log.Printf("Adding the container (%s) to the circus network", containerID) // get the circus network id circusNetworkID, err = getCircusNetworkID(dockerCtx, dockerCLI) if err != nil { log.Println("error: could not get CircusNetworkID", err) } log.Printf("circus network ID: %s", circusNetworkID) // connect the companion container to the circus network connectContainerToNetwork(containerID, circusNetworkID) log.Println("Container added to the circus network") // Get IP Address of that container inspectJSON, err := dockerCLI.ContainerInspect(dockerCtx, containerID) if err != nil { log.Println("inspectJsonErr: ", err) } fmt.Println("---") fmt.Printf("%#v", inspectJSON.NetworkSettings.Networks) fmt.Printf("companion IP: %#v", inspectJSON.NetworkSettings.Networks["circus"].IPAddress) } func generateSessionSalt() string { return fmt.Sprintf("%d", time.Now().UnixNano()) } // listDockerNetworks lists the docker networks func listDockerNetworks(dockerCtx context.Context, dockerCLI *client.Client) ([]types.NetworkResource, error) { // list the docker networks networks, err := dockerCLI.NetworkList(dockerCtx, types.NetworkListOptions{}) if err != nil { return nil, fmt.Errorln("network list err: ", err) } return networks, nil } // getDockerNetworkIDFromName returns the docker network ID using the given name // to find it. func getDockerNetworkIDFromName(string NetworkNameToFind) (string, error) { for _, network := range networks { if network.Name == NetworkNameToFind { return networkID, nil } } return "", fmt.Errorf("could not find the network id for the network %s: %s", circus, err) } // connectContainerToNetwork inserts the container with the given ID into the // network with the given ID func connectContainerToNetwork(string containerID, string networkID) { err = dockerCLI.NetworkConnect(dockerCtx, networkID, containerID, nil) if err != nil { log.Printf("Could not connect container %s to network %s: %s", containerID[:10], networkID[:10], err) } } func getCircusNetworkID(dockerCtx context.Context, dockerCLI *client.Client) (string, error) { networks, err := listDockerNetworks(dockerCtx, dockerCLI) if err != nil { return "", err } circusNetworkID, err := getDockerNetworkIDFromName("circus") if err != nil { return "", err } return circusNetworkID, nil }