From c856c7e66e3ad29ea0491f1f4951b31deb8279ea Mon Sep 17 00:00:00 2001 From: Emile Date: Sun, 20 Oct 2019 16:53:28 +0200 Subject: functional --- src/docker.go | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 src/docker.go (limited to 'src/docker.go') diff --git a/src/docker.go b/src/docker.go new file mode 100644 index 0000000..e3ff19c --- /dev/null +++ b/src/docker.go @@ -0,0 +1,201 @@ +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" + "github.com/docker/go-connections/nat" +) + +const ( + fixedDockerVersion = "1.38" +) + +var ( + dockerCtx context.Context + dockerCLI *client.Client + currentVpnRemptePort = 1194 +) + +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 := os.Getenv("HOSTNAME") + + // get the vpnRemoteport and increment it + vpnRemotePort := currentVpnRemptePort + log.Println("vpnRemptePort ", currentVpnRemptePort) + currentVpnRemptePort++ + + log.Println("Generating the container config") + + Config := &container.Config{ + Image: "circus-companion:latest", + Cmd: []string{"-username", username, "-accessCode", accesscode, "-sessionSalt", sessionSalt, "-vpnRemoteAddress", vpnRemoteAddress, "-vpnRemotePort", fmt.Sprintf("%d", vpnRemotePort)}, + ExposedPorts: nat.PortSet{ + "8080/tcp": struct{}{}, + }, + // Container labels used by traefik + Labels: map[string]string{ + "traefik.enable": "true", + fmt.Sprintf("traefik.http.routers.%s.entrypoints", username): "web", + fmt.Sprintf("traefik.http.routers.%s.rule", username): fmt.Sprintf("Host(`%s.%s`)", username, os.Getenv("HOSTNAME")), + fmt.Sprintf("traefik.http.middlewares.%s-https-redirect.redirectscheme.scheme", username): "https", + fmt.Sprintf("traefik.http.routers.%s.middlewares", username): fmt.Sprintf("%s-https-redirect", username), + fmt.Sprintf("traefik.http.routers.%s-secure.entrypoints", username): "websecure", + fmt.Sprintf("traefik.http.routers.%s-secure.rule", username): fmt.Sprintf("Host(`%s.%s`)", username, os.Getenv("HOSTNAME")), + fmt.Sprintf("traefik.http.routers.%s-secure.tls", username): "true", + fmt.Sprintf("traefik.http.routers.%s-secure.tls.certresolver", username): "mytlschallenge", + fmt.Sprintf("traefik.http.routers.%s-secure.service", username): fmt.Sprintf("%s", username), + fmt.Sprintf("traefik.http.services.%s.loadbalancer.server.port", username): "8080", + "traefik.docker.network": "circus", + }, + } + + // 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.Errorf("network list err: %s", err) + } + + return networks, nil +} + +// searchDockerNetworkIDFromName returns the docker network ID using the given name +// to find it. +func searchDockerNetworkIDFromName(networks []types.NetworkResource, NetworkNameToFind string) (string, error) { + + for _, network := range networks { + if network.Name == NetworkNameToFind { + return network.ID, nil + } + } + return "", fmt.Errorf("could not find the network id for the network %s: %s", NetworkNameToFind) +} + +// connectContainerToNetwork inserts the container with the given ID into the +// network with the given ID +func connectContainerToNetwork(containerID string, networkID string) { + 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) + } + log.Println("connectContainerToNetwork err: ", err) +} + +func getCircusNetworkID(dockerCtx context.Context, dockerCLI *client.Client) (string, error) { + networks, err := listDockerNetworks(dockerCtx, dockerCLI) + if err != nil { + return "", err + } + + circusNetworkID, err := searchDockerNetworkIDFromName(networks, "circus") + if err != nil { + return "", err + } + return circusNetworkID, nil +} -- cgit 1.4.1