$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
require_once "$docroot/webGui/include/Helpers.php";
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
// add translations
$_SERVER['REQUEST_URI'] = 'docker';
require_once "$docroot/webGui/include/Translations.php";
$DockerClient = new DockerClient();
$DockerTemplates = new DockerTemplates();
$containers = $DockerClient->getDockerContainers();
$images = $DockerClient->getDockerImages();
$user_prefs = $dockerManPaths['user-prefs'];
$autostart_file = $dockerManPaths['autostart-file'];
if (!$containers && !$images) {
echo "
";
if ($template && empty($composestack)) {
$appname = "".htmlspecialchars($name)." ";
} else {
$appname = htmlspecialchars($name);
}
echo "$image $appname "._($status).(!empty($composestack) ? ' Compose Stack: '.$composestack : '')." ";
echo ""._('Container ID').": $id
";
if ($ct['BaseImage']) echo "
".htmlspecialchars($ct['BaseImage'])."
";
echo _('By').": ";
$registry = $info['registry'];
['strRepo' => $author, 'strTag' => $version] = DockerUtil::parseImageTag($ct['Image']);
if ($registry) {
echo "
".htmlspecialchars(compress($author,24))." ";
} else {
echo htmlspecialchars(compress($author,24));
}
echo "
";
switch ($updateStatus) {
case 0:
if ($ct['Manager'] == "dockerman") {
echo " "._('up-to-date')." ";
echo "";
} elseif (!empty($composestack)) {
echo " "._("Compose")."
";
} else {
echo " "._("3rd Party")."
";
}
break;
case 1:
echo " "._('update ready')."
";
if ($ct['Manager'] == "dockerman") {
echo " "._('apply update')." ";
} elseif (!empty($composestack)) {
echo " Compose
";
} else {
echo " 3rd Party
";
}
break;
case 2:
echo " "._('rebuild ready')."
";
echo " "._('rebuilding')." ";
break;
default:
if ($ct['Manager'] == "dockerman") {
echo " "._('not available')." ";
echo "";
} elseif (!empty($composestack)) {
echo " "._("Compose")."
";
} else {
echo " "._("3rd Party")."
";
}
break;
}
// Check if Tailscale for container is enabled by checking if TShostname is set
$TS_status = '';
if (!empty($TShostname)) {
if ($running) {
// Get stats from container and check if they are not empty
$TSstats = tailscale_stats($name);
if (!empty($TSstats)) {
// Construct TSinfo from TSstats
$TSinfo = '';
if (!$TSstats["Self"]["Online"]) {
$TSinfo .= ""._("Online").": ❌ "._("Please check the logs")."!
";
} else {
$TS_version = explode('-', $TSstats["Version"])[0];
if (!empty($TS_version)) {
if (!empty($TS_latest_version)) {
if (version_compare($TS_version, $TS_latest_version, '<')) {
$TSinfo .= ""._("Tailscale").": v".$TS_version." ➔ v".$TS_latest_version." "._("available")."!
";
} else {
$TSinfo .= ""._("Tailscale").": v".$TS_version."
";
}
} else {
$TSinfo .= "".("Tailscale").": v".$TS_version."
";
}
}
$TSinfo .= ""._("Online").": ✅
";
$TS_DNSName = $TSstats["Self"]["DNSName"];
$TS_HostNameActual = substr($TS_DNSName, 0, strpos($TS_DNSName, '.'));
if (strcasecmp($TS_HostNameActual, $TShostname) !== 0 && !empty($TS_DNSName)) {
$TSinfo .= ""._("Hostname").": "._("Real Hostname")." ➔ ".$TS_HostNameActual."
";
} else {
$TSinfo .= ""._("Hostname").": ".$TShostname."
";
}
// Map region relay code to cleartext region if TS_derp_list is available
if (!empty($TS_derp_list)) {
foreach ($TS_derp_list['Regions'] as $region) {
if ($region['RegionCode'] === $TSstats["Self"]["Relay"]) {
$TSregion = $region['RegionName'];
break;
}
}
if (!empty($TSregion)) {
$TSinfo .= ""._("DERP Relay").": ".$TSregion."
";
} else {
$TSinfo .= ""._("DERP Relay").": ".$TSstats["Self"]["Relay"]."
";
}
} else {
$TSinfo .= ""._("DERP Relay").": ".$TSstats["Self"]["Relay"]."
";
}
if (!empty($TSstats["Self"]["TailscaleIPs"])) {
$TSinfo .= ""._("Addresses").": ".implode(" ", $TSstats["Self"]["TailscaleIPs"])."
";
}
if (!empty($TSstats["Self"]["PrimaryRoutes"])) {
$TSinfo .= ""._("Routes").": ".implode(" ", $TSstats["Self"]["PrimaryRoutes"])."
";
}
if ($TSstats["Self"]["ExitNodeOption"]) {
$TSinfo .= ""._("Is Exit Node").": ✅
";
} else {
if (!empty($TSstats["ExitNodeStatus"])) {
$TS_exit_node_status = ($TSstats["ExitNodeStatus"]["Online"]) ? "✅" : "❌";
$TSinfo .= ""._("Exit Node").": ".strstr($TSstats["ExitNodeStatus"]["TailscaleIPs"][0], '/', true)." | Status: ".$TS_exit_node_status ."
";
} else {
$TSinfo .= ""._("Is Exit Node").": ❌
";
}
}
if (!empty($TSwebGui)) {
$TSinfo .= ""._("URL").": ".$TSwebGui."
";
}
if (!empty($TSstats["Self"]["KeyExpiry"])) {
$TS_expiry = new DateTime($TSstats["Self"]["KeyExpiry"]);
$current_Date = new DateTime();
$TS_expiry_formatted = $TS_expiry->format('Y-m-d');
$TS_expiry_diff = $current_Date->diff($TS_expiry);
if ($TS_expiry_diff->invert) {
$TSinfo .= ""._("Key Expiry").": ❌ "._("Expired! Renew/Disable key expiry!")."
";
} else {
$TSinfo .= ""._("Key Expiry").": ".$TS_expiry_formatted." (".$TS_expiry_diff->days." days)
";
}
}
}
// Display TSinfo if data was fetched correctly
$TS_status = " ";
} else {
// Display message to refresh page if Tailscale in the container wasn't maybe ready to get the data
$TS_status = " ";
}
} else {
// Display message that container isn't running
$TS_status = " ";
}
}
echo " ".compress(_($version),12,0)."
";
echo " ".implode(' ',$networks).$TS_status." ";
echo " ".implode(' ',$network_ips)." ";
echo "".implode(' ',$ports_internal)." ";
echo "".implode(' ',$ports_external)." ";
echo "".implode(' ',$paths)." ";
echo "0%
";
echo "0 / 0 ";
if (empty($composestack)) {
if ($ct['Manager'] == "dockerman") {
echo " ";
} else {
echo " 3rd Party";
}
} else {
echo " Compose";
}
echo ""._('wait')." ";
echo "".htmlspecialchars(str_replace('Up',_('Uptime').':',my_lang_log($ct['Status'])))."
"._('Created').": ".htmlspecialchars(my_lang_time($ct['Created']))."
";
}
foreach ($images as $image) {
if (count($image['usedBy'])) continue;
$id = $image['Id'];
$menu = sprintf("onclick=\"addDockerImageContext('%s','%s')\"", $id, implode(',',$image['Tags']));
echo "