mirror of
https://github.com/nextcloud/all-in-one.git
synced 2025-12-20 06:26:57 +00:00
Improuve Container States
Signed-off-by: Jean-Yves <7360784+docjyJ@users.noreply.github.com>
This commit is contained in:
parent
a1bc150612
commit
4798489435
7 changed files with 156 additions and 132 deletions
|
|
@ -5,6 +5,7 @@ namespace AIO\Container;
|
||||||
use AIO\Data\ConfigurationManager;
|
use AIO\Data\ConfigurationManager;
|
||||||
use AIO\Docker\DockerActionManager;
|
use AIO\Docker\DockerActionManager;
|
||||||
use AIO\ContainerDefinitionFetcher;
|
use AIO\ContainerDefinitionFetcher;
|
||||||
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
|
|
||||||
readonly class Container {
|
readonly class Container {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
|
@ -112,20 +113,13 @@ readonly class Container {
|
||||||
return $this->volumes;
|
return $this->volumes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetRunningState() : ContainerState {
|
/** @throws GuzzleException */
|
||||||
return $this->dockerActionManager->GetContainerRunningState($this);
|
public function GetContainerState() : ContainerState {
|
||||||
|
return $this->dockerActionManager->GetContainerState($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetRestartingState() : ContainerState {
|
public function GetUpdateState() : UpdateState {
|
||||||
return $this->dockerActionManager->GetContainerRestartingState($this);
|
return $this->dockerActionManager->GetUpdateState($this);
|
||||||
}
|
|
||||||
|
|
||||||
public function GetUpdateState() : VersionState {
|
|
||||||
return $this->dockerActionManager->GetContainerUpdateState($this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function GetStartingState() : ContainerState {
|
|
||||||
return $this->dockerActionManager->GetContainerStartingState($this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,35 @@
|
||||||
|
|
||||||
namespace AIO\Container;
|
namespace AIO\Container;
|
||||||
|
|
||||||
enum ContainerState: string {
|
enum ContainerState {
|
||||||
case ImageDoesNotExist = 'image_does_not_exist';
|
case DoesNotExist;
|
||||||
case NotRestarting = 'not_restarting';
|
case Restarting;
|
||||||
case Restarting = 'restarting';
|
case Healthy;
|
||||||
case Running = 'running';
|
case Starting;
|
||||||
case Starting = 'starting';
|
case Stopped;
|
||||||
case Stopped = 'stopped';
|
case Unhealthy;
|
||||||
|
|
||||||
|
public function isStopped(): bool {
|
||||||
|
return $this == self::Stopped;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isStarting(): bool {
|
||||||
|
return $this == self::Starting;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isRestarting(): bool {
|
||||||
|
return $this == self::Restarting;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isHealthy(): bool {
|
||||||
|
return $this == self::Healthy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isUnhealthy(): bool {
|
||||||
|
return $this == self::Unhealthy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isRunning(): bool {
|
||||||
|
return $this->isHealthy() || $this->isUnhealthy() || $this->isStarting() || $this->isRestarting();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
php/src/Container/UpdateState.php
Normal file
12
php/src/Container/UpdateState.php
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace AIO\Container;
|
||||||
|
|
||||||
|
enum UpdateState {
|
||||||
|
case Outdated;
|
||||||
|
case Latest;
|
||||||
|
|
||||||
|
public function isUpdatableAvailable(): bool {
|
||||||
|
return $this == self::Outdated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace AIO\Container;
|
|
||||||
|
|
||||||
enum VersionState: string {
|
|
||||||
case Different = 'different';
|
|
||||||
case Equal = 'equal';
|
|
||||||
}
|
|
||||||
|
|
@ -5,6 +5,7 @@ namespace AIO\Controller;
|
||||||
use AIO\Container\ContainerState;
|
use AIO\Container\ContainerState;
|
||||||
use AIO\ContainerDefinitionFetcher;
|
use AIO\ContainerDefinitionFetcher;
|
||||||
use AIO\Docker\DockerActionManager;
|
use AIO\Docker\DockerActionManager;
|
||||||
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
use Psr\Http\Message\ResponseInterface as Response;
|
use Psr\Http\Message\ResponseInterface as Response;
|
||||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||||
use AIO\Data\ConfigurationManager;
|
use AIO\Data\ConfigurationManager;
|
||||||
|
|
@ -19,6 +20,7 @@ readonly class DockerController {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @throws GuzzleException */
|
||||||
private function PerformRecursiveContainerStart(string $id, bool $pullImage = true) : void {
|
private function PerformRecursiveContainerStart(string $id, bool $pullImage = true) : void {
|
||||||
$container = $this->containerDefinitionFetcher->GetContainerById($id);
|
$container = $this->containerDefinitionFetcher->GetContainerById($id);
|
||||||
|
|
||||||
|
|
@ -28,7 +30,7 @@ readonly class DockerController {
|
||||||
|
|
||||||
// Don't start if container is already running
|
// Don't start if container is already running
|
||||||
// This is expected to happen if a container is defined in depends_on of multiple containers
|
// This is expected to happen if a container is defined in depends_on of multiple containers
|
||||||
if ($container->GetRunningState() === ContainerState::Running) {
|
if ($container->GetContainerState()->isRunning()) {
|
||||||
error_log('Not starting ' . $id . ' because it was already started.');
|
error_log('Not starting ' . $id . ' because it was already started.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -240,6 +242,7 @@ readonly class DockerController {
|
||||||
$this->PerformRecursiveContainerStop($id);
|
$this->PerformRecursiveContainerStop($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @throws GuzzleException */
|
||||||
public function StartDomaincheckContainer() : void
|
public function StartDomaincheckContainer() : void
|
||||||
{
|
{
|
||||||
# Don't start if domain is already set
|
# Don't start if domain is already set
|
||||||
|
|
@ -254,10 +257,10 @@ readonly class DockerController {
|
||||||
$domaincheckContainer = $this->containerDefinitionFetcher->GetContainerById($id);
|
$domaincheckContainer = $this->containerDefinitionFetcher->GetContainerById($id);
|
||||||
$apacheContainer = $this->containerDefinitionFetcher->GetContainerById(self::TOP_CONTAINER);
|
$apacheContainer = $this->containerDefinitionFetcher->GetContainerById(self::TOP_CONTAINER);
|
||||||
// Don't start if apache is already running
|
// Don't start if apache is already running
|
||||||
if ($apacheContainer->GetRunningState() === ContainerState::Running) {
|
if ($apacheContainer->GetContainerState()->isRunning()) {
|
||||||
return;
|
return;
|
||||||
// Don't start if domaincheck is already running
|
// Don't start if domaincheck is already running
|
||||||
} elseif ($domaincheckContainer->GetRunningState() === ContainerState::Running) {
|
} elseif ($domaincheckContainer->GetContainerState()->isRunning()) {
|
||||||
$domaincheckWasStarted = apcu_fetch($cacheKey);
|
$domaincheckWasStarted = apcu_fetch($cacheKey);
|
||||||
// Start domaincheck again when 10 minutes are over by not returning here
|
// Start domaincheck again when 10 minutes are over by not returning here
|
||||||
if($domaincheckWasStarted !== false && is_string($domaincheckWasStarted)) {
|
if($domaincheckWasStarted !== false && is_string($domaincheckWasStarted)) {
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,13 @@
|
||||||
namespace AIO\Docker;
|
namespace AIO\Docker;
|
||||||
|
|
||||||
use AIO\Container\Container;
|
use AIO\Container\Container;
|
||||||
use AIO\Container\VersionState;
|
use AIO\Container\UpdateState;
|
||||||
use AIO\Container\ContainerState;
|
use AIO\Container\ContainerState;
|
||||||
use AIO\Data\ConfigurationManager;
|
use AIO\Data\ConfigurationManager;
|
||||||
|
use AssertionError;
|
||||||
|
use Exception;
|
||||||
use GuzzleHttp\Client;
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
use GuzzleHttp\Exception\RequestException;
|
use GuzzleHttp\Exception\RequestException;
|
||||||
use AIO\ContainerDefinitionFetcher;
|
use AIO\ContainerDefinitionFetcher;
|
||||||
use http\Env\Response;
|
use http\Env\Response;
|
||||||
|
|
@ -35,50 +38,7 @@ readonly class DockerActionManager {
|
||||||
return $container->GetContainerName() . ':' . $tag;
|
return $container->GetContainerName() . ':' . $tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetContainerRunningState(Container $container) : ContainerState
|
public function GetUpdateState(Container $container): UpdateState {
|
||||||
{
|
|
||||||
$url = $this->BuildApiUrl(sprintf('containers/%s/json', urlencode($container->GetIdentifier())));
|
|
||||||
try {
|
|
||||||
$response = $this->guzzleClient->get($url);
|
|
||||||
} catch (RequestException $e) {
|
|
||||||
if ($e->getCode() === 404) {
|
|
||||||
return ContainerState::ImageDoesNotExist;
|
|
||||||
}
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
|
|
||||||
$responseBody = json_decode((string)$response->getBody(), true);
|
|
||||||
|
|
||||||
if ($responseBody['State']['Running'] === true) {
|
|
||||||
return ContainerState::Running;
|
|
||||||
} else {
|
|
||||||
return ContainerState::Stopped;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function GetContainerRestartingState(Container $container) : ContainerState
|
|
||||||
{
|
|
||||||
$url = $this->BuildApiUrl(sprintf('containers/%s/json', urlencode($container->GetIdentifier())));
|
|
||||||
try {
|
|
||||||
$response = $this->guzzleClient->get($url);
|
|
||||||
} catch (RequestException $e) {
|
|
||||||
if ($e->getCode() === 404) {
|
|
||||||
return ContainerState::ImageDoesNotExist;
|
|
||||||
}
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
|
|
||||||
$responseBody = json_decode((string)$response->getBody(), true);
|
|
||||||
|
|
||||||
if ($responseBody['State']['Restarting'] === true) {
|
|
||||||
return ContainerState::Restarting;
|
|
||||||
} else {
|
|
||||||
return ContainerState::NotRestarting;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function GetContainerUpdateState(Container $container) : VersionState
|
|
||||||
{
|
|
||||||
$tag = $container->GetImageTag();
|
$tag = $container->GetImageTag();
|
||||||
if ($tag === '%AIO_CHANNEL%') {
|
if ($tag === '%AIO_CHANNEL%') {
|
||||||
$tag = $this->GetCurrentChannel();
|
$tag = $this->GetCurrentChannel();
|
||||||
|
|
@ -86,28 +46,49 @@ readonly class DockerActionManager {
|
||||||
|
|
||||||
$runningDigests = $this->GetRepoDigestsOfContainer($container->GetIdentifier());
|
$runningDigests = $this->GetRepoDigestsOfContainer($container->GetIdentifier());
|
||||||
if ($runningDigests === null) {
|
if ($runningDigests === null) {
|
||||||
return VersionState::Different;
|
return UpdateState::Outdated;
|
||||||
}
|
}
|
||||||
$remoteDigest = $this->dockerHubManager->GetLatestDigestOfTag($container->GetContainerName(), $tag);
|
$remoteDigest = $this->dockerHubManager->GetLatestDigestOfTag($container->GetContainerName(), $tag);
|
||||||
if ($remoteDigest === null) {
|
if ($remoteDigest === null) {
|
||||||
return VersionState::Equal;
|
return UpdateState::Latest;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($runningDigests as $runningDigest) {
|
return in_array($remoteDigest, $runningDigests, true) ? UpdateState::Latest : UpdateState::Outdated;
|
||||||
if ($runningDigest === $remoteDigest) {
|
|
||||||
return VersionState::Equal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return VersionState::Different;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetContainerStartingState(Container $container) : ContainerState
|
/** @throws GuzzleException */
|
||||||
{
|
public function GetContainerState(Container $container): ContainerState {
|
||||||
$runningState = $this->GetContainerRunningState($container);
|
$url = $this->BuildApiUrl(sprintf('containers/%s/json', urlencode($container->GetIdentifier())));
|
||||||
if ($runningState === ContainerState::Stopped || $runningState === ContainerState::ImageDoesNotExist) {
|
try {
|
||||||
return $runningState;
|
$response = $this->guzzleClient->get($url);
|
||||||
|
} catch (GuzzleException $e) {
|
||||||
|
if ($e->getCode() === 404) {
|
||||||
|
return ContainerState::DoesNotExist;
|
||||||
|
}
|
||||||
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$body = json_decode($response->getBody()->getContents(), true);
|
||||||
|
assert(is_array($body));
|
||||||
|
assert(is_array($body['State']));
|
||||||
|
|
||||||
|
$state = match ($body['State']['Status']) {
|
||||||
|
'running' => ContainerState::Healthy,
|
||||||
|
'created' => ContainerState::Starting,
|
||||||
|
'restarting' => ContainerState::Restarting,
|
||||||
|
'paused', 'removing', 'exited', 'dead' => ContainerState::Stopped,
|
||||||
|
default => throw new AssertionError()
|
||||||
|
};
|
||||||
|
|
||||||
|
if ($state->isHealthy() && is_array($body['State']['Health'])) {
|
||||||
|
$state = match ($body['State']['Health']['Status']) {
|
||||||
|
'starting' => ContainerState::Starting,
|
||||||
|
'unhealthy' => ContainerState::Unhealthy,
|
||||||
|
default => $state,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($state->isHealthy()) {
|
||||||
$containerName = $container->GetIdentifier();
|
$containerName = $container->GetIdentifier();
|
||||||
$internalPort = $container->GetInternalPort();
|
$internalPort = $container->GetInternalPort();
|
||||||
if ($internalPort === '%APACHE_PORT%') {
|
if ($internalPort === '%APACHE_PORT%') {
|
||||||
|
|
@ -115,19 +96,17 @@ readonly class DockerActionManager {
|
||||||
} elseif ($internalPort === '%TALK_PORT%') {
|
} elseif ($internalPort === '%TALK_PORT%') {
|
||||||
$internalPort = $this->configurationManager->GetTalkPort();
|
$internalPort = $this->configurationManager->GetTalkPort();
|
||||||
}
|
}
|
||||||
|
if (is_numeric($internalPort)) {
|
||||||
if ($internalPort !== "" && $internalPort !== 'host') {
|
$connection = @fsockopen($containerName, intval($internalPort), $errno, $errstr, 0.2);
|
||||||
$connection = @fsockopen($containerName, (int)$internalPort, $errno, $errstr, 0.2);
|
|
||||||
if ($connection) {
|
if ($connection) {
|
||||||
fclose($connection);
|
fclose($connection);
|
||||||
return ContainerState::Running;
|
|
||||||
} else {
|
} else {
|
||||||
return ContainerState::Starting;
|
$state = ContainerState::Starting;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return ContainerState::Running;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return $state;
|
||||||
|
}
|
||||||
|
|
||||||
public function DeleteContainer(Container $container) : void {
|
public function DeleteContainer(Container $container) : void {
|
||||||
$url = $this->BuildApiUrl(sprintf('containers/%s?v=true', urlencode($container->GetIdentifier())));
|
$url = $this->BuildApiUrl(sprintf('containers/%s?v=true', urlencode($container->GetIdentifier())));
|
||||||
|
|
@ -167,7 +146,7 @@ readonly class DockerActionManager {
|
||||||
try {
|
try {
|
||||||
$this->guzzleClient->post($url);
|
$this->guzzleClient->post($url);
|
||||||
} catch (RequestException $e) {
|
} catch (RequestException $e) {
|
||||||
throw new \Exception("Could not start container " . $container->GetIdentifier() . ": " . $e->getMessage());
|
throw new Exception("Could not start container " . $container->GetIdentifier() . ": " . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -404,7 +383,7 @@ readonly class DockerActionManager {
|
||||||
} else {
|
} else {
|
||||||
$secret = $this->configurationManager->GetSecret($out[1]);
|
$secret = $this->configurationManager->GetSecret($out[1]);
|
||||||
if ($secret === "") {
|
if ($secret === "") {
|
||||||
throw new \Exception("The secret " . $out[1] . " is empty. Cannot substitute its value. Please check if it is defined in secrets of containers.json.");
|
throw new Exception("The secret " . $out[1] . " is empty. Cannot substitute its value. Please check if it is defined in secrets of containers.json.");
|
||||||
}
|
}
|
||||||
$replacements[1] = $secret;
|
$replacements[1] = $secret;
|
||||||
}
|
}
|
||||||
|
|
@ -573,7 +552,7 @@ readonly class DockerActionManager {
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
} catch (RequestException $e) {
|
} catch (RequestException $e) {
|
||||||
throw new \Exception("Could not create container " . $container->GetIdentifier() . ": " . $e->getMessage());
|
throw new Exception("Could not create container " . $container->GetIdentifier() . ": " . $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -609,17 +588,16 @@ readonly class DockerActionManager {
|
||||||
$this->guzzleClient->post($url);
|
$this->guzzleClient->post($url);
|
||||||
} catch (RequestException $e) {
|
} catch (RequestException $e) {
|
||||||
if ($imageIsThere === false) {
|
if ($imageIsThere === false) {
|
||||||
throw new \Exception("Could not pull image " . $imageName . ". Please run 'sudo docker exec -it nextcloud-aio-mastercontainer docker pull " . $imageName . "' in order to find out why it failed.");
|
throw new Exception("Could not pull image " . $imageName . ". Please run 'sudo docker exec -it nextcloud-aio-mastercontainer docker pull " . $imageName . "' in order to find out why it failed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function isContainerUpdateAvailable(string $id) : string
|
private function isContainerUpdateAvailable(string $id): string {
|
||||||
{
|
|
||||||
$container = $this->containerDefinitionFetcher->GetContainerById($id);
|
$container = $this->containerDefinitionFetcher->GetContainerById($id);
|
||||||
|
|
||||||
$updateAvailable = "";
|
$updateAvailable = "";
|
||||||
if ($container->GetUpdateState() === VersionState::Different) {
|
if ($container->GetUpdateState() === UpdateState::Outdated) {
|
||||||
$updateAvailable = '1';
|
$updateAvailable = '1';
|
||||||
}
|
}
|
||||||
foreach ($container->GetDependsOn() as $dependency) {
|
foreach ($container->GetDependsOn() as $dependency) {
|
||||||
|
|
@ -718,7 +696,7 @@ readonly class DockerActionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
} catch (\Exception $e) {
|
} catch (Exception $e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -747,7 +725,7 @@ readonly class DockerActionManager {
|
||||||
$tag = 'latest';
|
$tag = 'latest';
|
||||||
}
|
}
|
||||||
return $tag;
|
return $tag;
|
||||||
} catch (\Exception $e) {
|
} catch (Exception $e) {
|
||||||
error_log('Could not get current channel ' . $e->getMessage());
|
error_log('Could not get current channel ' . $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -778,9 +756,9 @@ readonly class DockerActionManager {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function sendNotification(Container $container, string $subject, string $message, string $file = '/notify.sh') : void
|
/** @throws GuzzleException */
|
||||||
{
|
public function sendNotification(Container $container, string $subject, string $message, string $file = '/notify.sh'): void {
|
||||||
if ($this->GetContainerStartingState($container) === ContainerState::Running) {
|
if ($this->GetContainerState($container)->isHealthy()) {
|
||||||
|
|
||||||
$containerName = $container->GetIdentifier();
|
$containerName = $container->GetIdentifier();
|
||||||
|
|
||||||
|
|
@ -867,7 +845,7 @@ readonly class DockerActionManager {
|
||||||
} catch (RequestException $e) {
|
} catch (RequestException $e) {
|
||||||
// 409 is undocumented and gets thrown if the network already exists.
|
// 409 is undocumented and gets thrown if the network already exists.
|
||||||
if ($e->getCode() !== 409) {
|
if ($e->getCode() !== 409) {
|
||||||
throw new \Exception("Could not create the nextcloud-aio network: " . $e->getMessage());
|
throw new Exception("Could not create the nextcloud-aio network: " . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -961,19 +939,24 @@ readonly class DockerActionManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws GuzzleException
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
public function isLoginAllowed(): bool {
|
public function isLoginAllowed(): bool {
|
||||||
$id = 'nextcloud-aio-apache';
|
$id = 'nextcloud-aio-apache';
|
||||||
$apacheContainer = $this->containerDefinitionFetcher->GetContainerById($id);
|
$apacheContainer = $this->containerDefinitionFetcher->GetContainerById($id);
|
||||||
if ($this->GetContainerStartingState($apacheContainer) === ContainerState::Running) {
|
if ($this->GetContainerState($apacheContainer)->isRunning()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @throws GuzzleException */
|
||||||
public function isBackupContainerRunning(): bool {
|
public function isBackupContainerRunning(): bool {
|
||||||
$id = 'nextcloud-aio-borgbackup';
|
$id = 'nextcloud-aio-borgbackup';
|
||||||
$backupContainer = $this->containerDefinitionFetcher->GetContainerById($id);
|
$backupContainer = $this->containerDefinitionFetcher->GetContainerById($id);
|
||||||
if ($this->GetContainerRunningState($backupContainer) === ContainerState::Running) {
|
if ($this->GetContainerState($backupContainer)->isRunning()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -991,7 +974,7 @@ readonly class DockerActionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
return str_replace('T', ' ', (string)$imageOutput['Created']);
|
return str_replace('T', ' ', (string)$imageOutput['Created']);
|
||||||
} catch (\Exception $e) {
|
} catch (Exception $e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,19 +41,20 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% for container in containers %}
|
{% for container in containers %}
|
||||||
{% if container.GetDisplayName() != '' and container.GetRunningState().value == 'running' %}
|
{% set runingState = container.GetContainerState() %}
|
||||||
|
{% if container.GetDisplayName() != '' and runingState.isRunning() %}
|
||||||
{% set isAnyRunning = true %}
|
{% set isAnyRunning = true %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if container.GetDisplayName() != '' and container.GetRestartingState().value == 'restarting' %}
|
{% if container.GetDisplayName() != '' and runingState.isRestarting() %}
|
||||||
{% set isAnyRestarting = true %}
|
{% set isAnyRestarting = true %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if container.GetIdentifier() == 'nextcloud-aio-watchtower' and container.GetRunningState().value == 'running' %}
|
{% if container.GetIdentifier() == 'nextcloud-aio-watchtower' and container.GetContainerState().isRunning() %}
|
||||||
{% set isWatchtowerRunning = true %}
|
{% set isWatchtowerRunning = true %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if container.GetIdentifier() == 'nextcloud-aio-domaincheck' and container.GetRunningState().value == 'running' %}
|
{% if container.GetIdentifier() == 'nextcloud-aio-domaincheck' and container.GetContainerState().isRunning() %}
|
||||||
{% set isDomaincheckRunning = true %}
|
{% set isDomaincheckRunning = true %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if container.GetIdentifier() == 'nextcloud-aio-apache' and container.GetStartingState().value == 'starting' %}
|
{% if container.GetIdentifier() == 'nextcloud-aio-apache' and runingState.isStarting() %}
|
||||||
{% set isApacheStarting = true %}
|
{% set isApacheStarting = true %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
@ -262,14 +263,29 @@
|
||||||
{% for container in containers %}
|
{% for container in containers %}
|
||||||
{% if container.GetDisplayName() != '' %}
|
{% if container.GetDisplayName() != '' %}
|
||||||
<li>
|
<li>
|
||||||
{% if container.GetStartingState().value == 'starting' %}
|
{% set runningState = container.GetContainerState() %}
|
||||||
|
{% if runningState.isStarting() %}
|
||||||
<span class="status running"></span>
|
<span class="status running"></span>
|
||||||
<span>{{ container.GetDisplayName() }} (<a href="/api/docker/logs?id={{ container.GetIdentifier() }}" target="_blank" rel="noopener">Starting</a>)
|
<span>{{ container.GetDisplayName() }} (<a href="/api/docker/logs?id={{ container.GetIdentifier() }}" target="_blank" rel="noopener">Starting</a>)
|
||||||
{% if container.GetDocumentation() != '' %}
|
{% if container.GetDocumentation() != '' %}
|
||||||
(<a href="{{ container.GetDocumentation() }}">docs</a>)
|
(<a href="{{ container.GetDocumentation() }}">docs</a>)
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</span>
|
</span>
|
||||||
{% elseif container.GetRunningState().value == 'running' %}
|
{% elseif runningState.isUnhealthy() %}
|
||||||
|
<span class="status running"></span>
|
||||||
|
<span>{{ container.GetDisplayName() }} (<a href="/api/docker/logs?id={{ container.GetIdentifier() }}" target="_blank" rel="noopener">Unhealthy</a>)
|
||||||
|
{% if container.GetDocumentation() != '' %}
|
||||||
|
(<a href="{{ container.GetDocumentation() }}">docs</a>)
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
{% elseif runningState.isRestarting() %}
|
||||||
|
<span class="status running"></span>
|
||||||
|
<span>{{ container.GetDisplayName() }} (<a href="/api/docker/logs?id={{ container.GetIdentifier() }}" target="_blank" rel="noopener">Restarting</a>)
|
||||||
|
{% if container.GetDocumentation() != '' %}
|
||||||
|
(<a href="{{ container.GetDocumentation() }}">docs</a>)
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
{% elseif runningState.isHealthy() %}
|
||||||
<span class="status success"></span>
|
<span class="status success"></span>
|
||||||
<span>{{ container.GetDisplayName() }} (<a href="/api/docker/logs?id={{ container.GetIdentifier() }}" target="_blank" rel="noopener">Running</a>)
|
<span>{{ container.GetDisplayName() }} (<a href="/api/docker/logs?id={{ container.GetIdentifier() }}" target="_blank" rel="noopener">Running</a>)
|
||||||
{% if container.GetDocumentation() != '' %}
|
{% if container.GetDocumentation() != '' %}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue