Skip to content

Commit

Permalink
Merge pull request #43 from avast/UseDockerDirectlyOnWindows
Browse files Browse the repository at this point in the history
Improve testing of port accessibility directly on Windows
  • Loading branch information
alenkacz authored Sep 28, 2016
2 parents 69b159c + 30fc542 commit 5a42006
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -103,33 +103,58 @@ class ComposeUp extends DefaultTask {
ServiceHost getServiceHost(String serviceName, Map<String, Object> inspection) {
String dockerHost = System.getenv('DOCKER_HOST')
if (dockerHost) {
logger.debug("'DOCKER_HOST environment variable detected - will be used as hostname of service $serviceName'")
logger.lifecycle("'DOCKER_HOST environment variable detected - will be used as hostname of service $serviceName'")
new ServiceHost(host: dockerHost.toURI().host, type: ServiceHostType.RemoteDockerHost)
} else if (isMac() || isWindows()) {
// If running on Mac OS or Windows, and DOCKER_HOST is not set, we can assume that
// we are using Docker for Mac/Windows, in which case we should connect to localhost
logger.debug("Will use localhost as host of $serviceName")
} else if (isMac()) {
logger.lifecycle("Will use localhost as host of $serviceName")
new ServiceHost(host: 'localhost', type: ServiceHostType.LocalHost)
} else if (isWindows()) {
String ifaceAddress = getWindowsDockerNATAddress()
if (ifaceAddress) {
logger.lifecycle("Will use $ifaceAddress as host of $serviceName because it's address of DockerNAT network interface")
new ServiceHost(host: ifaceAddress, type: ServiceHostType.RemoteDockerHost)
} else {
logger.lifecycle("Will use localhost as host of $serviceName because DockerNAT network interface is not present")
new ServiceHost(host: 'localhost', type: ServiceHostType.LocalHost)
}
} else {
// read gateway of first containers network
String gateway
Map<String, Object> networkSettings = inspection.NetworkSettings
Map<String, Object> networks = networkSettings.Networks
if (networks && networks.every { it.key.toLowerCase().equals("host") }) {
gateway = 'localhost'
logger.debug("Will use $gateway as host of $serviceName because it is using HOST network")
logger.lifecycle("Will use $gateway as host of $serviceName because it is using HOST network")
} else if (networks) {
Map.Entry<String, Object> firstNetworkPair = networks.find()
gateway = firstNetworkPair.value.Gateway
logger.debug("Will use $gateway (network ${firstNetworkPair.key}) as host of $serviceName")
logger.lifecycle("Will use $gateway (network ${firstNetworkPair.key}) as host of $serviceName")
} else { // networks not specified (older Docker versions)
gateway = networkSettings.Gateway
logger.debug("Will use $gateway as host of $serviceName")
logger.lifecycle("Will use $gateway as host of $serviceName")
}
new ServiceHost(host: gateway, type: ServiceHostType.NetworkGateway)
}
}

String getWindowsDockerNATAddress() {
// parse output of netsh - find DockerNAT interface and read its index
new ByteArrayOutputStream().withStream { os ->
project.exec { ExecSpec e ->
e.commandLine 'netsh', 'interface', 'ip', 'show', 'interfaces'
e.standardOutput = os
}
os.toString().trim()
}.readLines()
.findAll { it.toLowerCase().contains('dockernat') }
.collect { it.split().first() }
.flatten()
.collect { NetworkInterface.getByIndex(Integer.parseInt(it)) }
.findAll { it.up && it.getInterfaceAddresses().any() }
.collect { it.getInterfaceAddresses().first().address.hostAddress }
.find()
}

Map<Integer, Integer> getTcpPortsMapping(String serviceName, Map<String, Object> inspection, ServiceHost host) {
Map<Integer, Integer> ports = [:]
inspection.NetworkSettings.Ports.each { String exposedPortWithProtocol, forwardedPortsInfos ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import org.gradle.api.Task
import org.gradle.api.internal.file.TmpDirTemporaryFileProvider
import org.gradle.api.tasks.testing.Test
import org.gradle.testfixtures.ProjectBuilder
import spock.lang.IgnoreIf
import spock.lang.Specification

class DockerComposePluginTest extends Specification {
Expand All @@ -19,7 +20,6 @@ class DockerComposePluginTest extends Specification {
project.extensions.findByName('dockerCompose') instanceof ComposeExtension
}


def "dockerCompose.isRequiredBy() adds dependencies"() {
def project = ProjectBuilder.builder().build()
project.plugins.apply 'docker-compose'
Expand All @@ -31,6 +31,14 @@ class DockerComposePluginTest extends Specification {
task.getFinalizedBy().getDependencies(task).any { it == project.tasks.composeDown }
}

@IgnoreIf({ !System.properties["os.name"].toString().toLowerCase().startsWith('windows') })
def "returns any DockerNAT network interface"() {
def project = ProjectBuilder.builder().build()
when:
project.plugins.apply 'docker-compose'
then:
project.tasks.composeUp.getWindowsDockerNATAddress()
}

def "allows usage from integration test"() {
def projectDir = new TmpDirTemporaryFileProvider().createTemporaryDirectory("gradle", "projectDir")
Expand Down Expand Up @@ -223,6 +231,7 @@ class DockerComposePluginTest extends Specification {
''']
}

@IgnoreIf({ !System.properties['os.name'].toString().toLowerCase().startsWith('windows') && !System.properties['os.name'].toString().toLowerCase().startsWith('macos') })
def "expose localhost as a host for container with HOST networking"() {
def projectDir = new TmpDirTemporaryFileProvider().createTemporaryDirectory("gradle", "projectDir")
new File(projectDir, 'docker-compose.yml') << '''
Expand Down Expand Up @@ -307,5 +316,4 @@ class DockerComposePluginTest extends Specification {
projectDir.deleteOnExit()
}
}

}

0 comments on commit 5a42006

Please sign in to comment.