Code reuse on determining docker container address

This commit is contained in:
Nikola Petkanski
2024-07-16 03:34:41 +03:00
parent 0edcaeec72
commit de59891641
4 changed files with 67 additions and 53 deletions
+8 -16
View File
@@ -7,9 +7,9 @@ namespace Testcontainer\Container;
use Symfony\Component\Process\Process; use Symfony\Component\Process\Process;
use Testcontainer\Exception\ContainerNotReadyException; use Testcontainer\Exception\ContainerNotReadyException;
use Testcontainer\Registry; use Testcontainer\Registry;
use Testcontainer\Trait\DockerContainerAwareTrait;
use Testcontainer\Wait\WaitForNothing; use Testcontainer\Wait\WaitForNothing;
use Testcontainer\Wait\WaitInterface; use Testcontainer\Wait\WaitInterface;
use UnexpectedValueException;
/** /**
* @phpstan-type ContainerInspectSingleNetwork array<int, array{'NetworkSettings': array{'IPAddress': string}}> * @phpstan-type ContainerInspectSingleNetwork array<int, array{'NetworkSettings': array{'IPAddress': string}}>
@@ -18,6 +18,8 @@ use UnexpectedValueException;
*/ */
class Container class Container
{ {
use DockerContainerAwareTrait;
private string $id; private string $id;
private ?string $entryPoint = null; private ?string $entryPoint = null;
@@ -259,20 +261,10 @@ class Container
public function getAddress(): string public function getAddress(): string
{ {
if (is_string($this->network)) { return $this->getContainerAddress(
$containerAddress = $this->inspectedData[0]['NetworkSettings']['Networks'][$this->network]['IPAddress'] ?? null; containerId: $this->id,
networkName: $this->network,
if (is_string($containerAddress)) { inspectedData: $this->inspectedData
return $containerAddress; );
}
}
$containerAddress = $this->inspectedData[0]['NetworkSettings']['IPAddress'] ?? null;
if (is_string($containerAddress)) {
return $containerAddress;
}
throw new UnexpectedValueException('Unable to find container IP address');
} }
} }
+50
View File
@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace Testcontainer\Trait;
use JsonException;
use Symfony\Component\Process\Process;
use UnexpectedValueException;
/**
* @phpstan-import-type ContainerInspect from \Testcontainer\Container\Container
*/
trait DockerContainerAwareTrait
{
/**
* @param string $containerId
* @param string|null $networkName
* @param ContainerInspect|null $inspectedData
* @return string
*
* @throws JsonException
*/
protected function getContainerAddress(string $containerId, ?string $networkName = null, ?array $inspectedData = null): string
{
if (! is_array($inspectedData)) {
$process = new Process(['docker', 'inspect', $containerId]);
$process->mustRun();
/** @var ContainerInspect $inspectedData */
$inspectedData = json_decode($process->getOutput(), true, 512, JSON_THROW_ON_ERROR);
}
if (is_string($networkName)) {
$containerAddress = $inspectedData[0]['NetworkSettings']['Networks'][$networkName]['IPAddress'] ?? null;
if (is_string($containerAddress)) {
return $containerAddress;
}
}
$containerAddress = $inspectedData[0]['NetworkSettings']['IPAddress'] ?? null;
if (is_string($containerAddress)) {
return $containerAddress;
}
throw new UnexpectedValueException('Unable to find container IP address');
}
}
+5 -12
View File
@@ -4,14 +4,13 @@ declare(strict_types=1);
namespace Testcontainer\Wait; namespace Testcontainer\Wait;
use Symfony\Component\Process\Process;
use Testcontainer\Exception\ContainerNotReadyException; use Testcontainer\Exception\ContainerNotReadyException;
use Testcontainer\Trait\DockerContainerAwareTrait;
/**
* @phpstan-import-type ContainerInspect from \Testcontainer\Container\Container
*/
class WaitForHttp implements WaitInterface class WaitForHttp implements WaitInterface
{ {
use DockerContainerAwareTrait;
public const METHOD_GET = 'GET'; public const METHOD_GET = 'GET';
public const METHOD_POST = 'POST'; public const METHOD_POST = 'POST';
public const METHOD_PUT = 'PUT'; public const METHOD_PUT = 'PUT';
@@ -59,16 +58,10 @@ class WaitForHttp implements WaitInterface
public function wait(string $id): void public function wait(string $id): void
{ {
$process = new Process(['docker', 'inspect', $id]); $containerAddress = $this->getContainerAddress(containerId: $id);
$process->mustRun();
/** @var ContainerInspect $data */
$data = json_decode($process->getOutput(), true);
$ip = $data[0]['NetworkSettings']['IPAddress'];
$ch = curl_init(); $ch = curl_init();
curl_setopt($ch, CURLOPT_URL, sprintf('http://%s:%d%s', $ip, $this->port, $this->path)); curl_setopt($ch, CURLOPT_URL, sprintf('http://%s:%d%s', $containerAddress, $this->port, $this->path));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->method); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->method);
curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_HEADER, true);
+4 -25
View File
@@ -6,14 +6,13 @@ namespace Testcontainer\Wait;
use JsonException; use JsonException;
use RuntimeException; use RuntimeException;
use Symfony\Component\Process\Process;
use Testcontainer\Exception\ContainerNotReadyException; use Testcontainer\Exception\ContainerNotReadyException;
use Testcontainer\Trait\DockerContainerAwareTrait;
/**
* @phpstan-import-type ContainerInspect from \Testcontainer\Container\Container
*/
final class WaitForTcpPortOpen implements WaitInterface final class WaitForTcpPortOpen implements WaitInterface
{ {
use DockerContainerAwareTrait;
public function __construct(private readonly int $port) public function __construct(private readonly int $port)
{ {
} }
@@ -28,28 +27,8 @@ final class WaitForTcpPortOpen implements WaitInterface
*/ */
public function wait(string $id): void public function wait(string $id): void
{ {
if (@fsockopen($this->findContainerAddress($id), $this->port) === false) { if (@fsockopen($this->getContainerAddress($id), $this->port) === false) {
throw new ContainerNotReadyException($id, new RuntimeException('Unable to connect to container TCP port')); throw new ContainerNotReadyException($id, new RuntimeException('Unable to connect to container TCP port'));
} }
} }
/**
* @throws JsonException
*/
private function findContainerAddress(string $id): string
{
$process = new Process(['docker', 'inspect', $id]);
$process->mustRun();
/** @var ContainerInspect $data */
$data = json_decode($process->getOutput(), true, 512, JSON_THROW_ON_ERROR);
$containerAddress = $data[0]['NetworkSettings']['IPAddress'] ?? null;
if (! is_string($containerAddress)) {
throw new ContainerNotReadyException($id, new RuntimeException('Unable to find container IP address'));
}
return $containerAddress;
}
} }