Skip to content

Commit

Permalink
Include direct web container access in GetAllURLs(), resolves #796 (#890
Browse files Browse the repository at this point in the history
)

* Report direct web container URL by inspecting container ports.

* Use correct method for getting Docker IP, create dockerutils.GetDockerIP() for shared code.

* Add TestGetAllURLs().
  • Loading branch information
andrewfrench committed May 30, 2018
1 parent 881ed26 commit 4fff979
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 11 deletions.
42 changes: 31 additions & 11 deletions pkg/ddevapp/ddevapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@ package ddevapp

import (
"fmt"
"golang.org/x/crypto/ssh/terminal"
"net/url"
"os"
"path/filepath"
"strconv"

"golang.org/x/crypto/ssh/terminal"

"strings"

osexec "os/exec"

"os/user"

"runtime"

"github.com/drud/ddev/pkg/appimport"
"github.com/drud/ddev/pkg/appports"
"github.com/drud/ddev/pkg/archive"
Expand All @@ -25,7 +27,6 @@ import (
"github.com/fsouza/go-dockerclient"
"github.com/lextoumbourou/goodhosts"
"github.com/mattn/go-shellwords"
"runtime"
)

const containerWaitTimeout = 61
Expand Down Expand Up @@ -928,6 +929,8 @@ func (app *DdevApp) GetHTTPSURL() string {
// GetAllURLs returns an array of all the URLs for the project
func (app *DdevApp) GetAllURLs() []string {
var URLs []string

// Get configured URLs
for _, name := range app.GetHostnames() {
httpPort := ""
httpsPort := ""
Expand All @@ -939,6 +942,27 @@ func (app *DdevApp) GetAllURLs() []string {
}
URLs = append(URLs, "http://"+name+httpPort, "https://"+name+httpsPort)
}

// Get direct address of web container
dockerIP, err := dockerutil.GetDockerIP()
if err != nil {
util.Error("Unable to get Docker IP: %v", err)
return URLs
}

webContainer, err := app.FindContainerByType("web")
if err != nil {
util.Error("Unable to find web container for app: %s, err %v", app.Name, err)
return URLs
}

for _, p := range webContainer.Ports {
if p.PrivatePort == 80 {
URLs = append(URLs, fmt.Sprintf("http://%s:%d", dockerIP, p.PublicPort))
break
}
}

return URLs
}

Expand All @@ -949,15 +973,11 @@ func (app *DdevApp) HostName() string {

// AddHostsEntries will add the site URL to the host's /etc/hosts.
func (app *DdevApp) AddHostsEntries() error {
dockerIP := "127.0.0.1"
dockerHostRawURL := os.Getenv("DOCKER_HOST")
if dockerHostRawURL != "" {
dockerHostURL, err := url.Parse(dockerHostRawURL)
if err != nil {
return fmt.Errorf("failed to parse $DOCKER_HOST: %v, err: %v", dockerHostRawURL, err)
}
dockerIP = dockerHostURL.Hostname()
dockerIP, err := dockerutil.GetDockerIP()
if err != nil {
return fmt.Errorf("could not get Docker IP: %v", err)
}

hosts, err := goodhosts.NewHosts()
if err != nil {
util.Failed("could not open hostfile. %s", err)
Expand Down
67 changes: 67 additions & 0 deletions pkg/ddevapp/ddevapp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1130,6 +1130,73 @@ func TestMultipleComposeFiles(t *testing.T) {
assert.Contains(err.Error(), "failed to load any docker-compose.*y*l files")
}

// TestGetAllURLs ensures the GetAllURLs function returns the expected number of URLs,
// and that one of them is the direct web container address.
func TestGetAllURLs(t *testing.T) {
assert := asrt.New(t)

for _, site := range TestSites {
runTime := testcommon.TimeTrack(time.Now(), fmt.Sprintf("%s GetAllURLs", site.Name))

testcommon.ClearDockerEnv()
app := new(ddevapp.DdevApp)

err := app.Init(site.Dir)
assert.NoError(err)

// Add some additional hostnames
app.AdditionalHostnames = []string{
fmt.Sprintf("sub1.%s", site.Name),
fmt.Sprintf("sub2.%s", site.Name),
fmt.Sprintf("sub3.%s", site.Name),
}

err = app.WriteConfig()
assert.NoError(err)

err = app.Start()
assert.NoError(err)

urls := app.GetAllURLs()

// Convert URLs to map[string]bool
urlMap := make(map[string]bool)
for _, u := range urls {
urlMap[u] = true
}

// We expect two URLs for each hostname (http/https) and one direct web container address.
expectedNumUrls := (2 * len(app.GetHostnames())) + 1
assert.Equal(len(urlMap), expectedNumUrls, "Unexpected number of URLs returned: %d", len(urlMap))

// Ensure urlMap contains direct address of the web container
webContainer, err := app.FindContainerByType("web")
assert.NoError(err)

dockerIP, err := dockerutil.GetDockerIP()
assert.NoError(err)

// Find HTTP port of web container
var port docker.APIPort
for _, p := range webContainer.Ports {
if p.PrivatePort == 80 {
port = p
break
}
}

expectedDirectAddress := fmt.Sprintf("http://%s:%d", dockerIP, port.PublicPort)
exists := urlMap[expectedDirectAddress]

assert.True(exists, "URL list for app: %s does not contain direct web container address: %s", app.Name, expectedDirectAddress)

err = app.Stop()
assert.NoError(err)

runTime()
}
}

// constructContainerName builds a container name given the type (web/db/dba) and the app
func constructContainerName(containerType string, app *ddevapp.DdevApp) (string, error) {
container, err := app.FindContainerByType(containerType)
Expand Down
19 changes: 19 additions & 0 deletions pkg/dockerutil/dockerutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"strings"
"time"

"net/url"

"github.com/Masterminds/semver"
"github.com/drud/ddev/pkg/output"
"github.com/drud/ddev/pkg/util"
Expand Down Expand Up @@ -382,3 +384,20 @@ func CheckForHTTPS(container docker.APIContainers) bool {
}
return false
}

// GetDockerIP returns either the default Docker IP address (127.0.0.1)
// or the value as configured by $DOCKER_HOST.
func GetDockerIP() (string, error) {
dockerIP := "127.0.0.1"
dockerHostRawURL := os.Getenv("DOCKER_HOST")
if dockerHostRawURL != "" {
dockerHostURL, err := url.Parse(dockerHostRawURL)
if err != nil {
return "", fmt.Errorf("failed to parse $DOCKER_HOST: %v, err: %v", dockerHostRawURL, err)
}

dockerIP = dockerHostURL.Hostname()
}

return dockerIP, nil
}

0 comments on commit 4fff979

Please sign in to comment.