#!/usr/bin/php -q 'http://localhost/pub/docker?buffer_length=1', CURLOPT_UNIX_SOCKET_PATH => '/var/run/nginx.socket', CURLOPT_POST => 1, CURLOPT_RETURNTRANSFER => true ]); foreach ($messages as $message) { curl_setopt($com, CURLOPT_POSTFIELDS, $message); curl_exec($com); } curl_close($com); } function stopContainer_nchan($name) { global $DockerClient; $waitID = mt_rand(); write("

","addLog\0
"._('Stopping container').": ".htmlspecialchars($name)."

"._('Please wait')."
","show_Wait\0$waitID"); $retval = $DockerClient->stopContainer($name); $out = ($retval === true) ? _('Successfully stopped container').": $name" : _('Error').": ".$retval; write("stop_Wait\0$waitID","addLog\0".htmlspecialchars($out).""); } function removeContainer_nchan($name) { global $DockerClient; $waitID = mt_rand(); write("

","addLog\0
"._('Removing container').": ".htmlspecialchars($name)."

"._('Please wait')."
","show_Wait\0$waitID"); $retval = $DockerClient->removeContainer($name); $out = ($retval === true) ? _('Successfully removed container').": $name" : _('Error').": ".$retval; write("stop_Wait\0$waitID","addLog\0".htmlspecialchars($out).""); } function removeImage_nchan($image) { global $DockerClient; $waitID = mt_rand(); write("

","addLog\0
"._('Removing orphan image').": ".htmlspecialchars($image)."

"._('Please wait')."
","show_Wait\0$waitID"); $retval = $DockerClient->removeImage($image); $out = ($retval === true) ? _('Successfully removed orphan image').": $image" : _('Error').": ".$retval; write("stop_Wait\0$waitID","addLog\0".htmlspecialchars($out).""); } function pullImage_nchan($name, $image) { global $DockerClient, $DockerTemplates, $DockerUpdate; $waitID = mt_rand(); if (!preg_match("/:\S+$/", $image)) $image .= ":latest"; write("

","addLog\0
"._('Pulling image').": ".htmlspecialchars($image)."

"._('Please wait')."
","show_Wait\0$waitID"); $alltotals = []; $laststatus = []; $strError = ''; $DockerClient->pullImage($image, function ($line) use (&$alltotals, &$laststatus, &$waitID, &$strError, $image, $DockerClient, $DockerUpdate) { $cnt = json_decode($line, true); $id = $cnt['id'] ?? ''; $status = $cnt['status'] ?? ''; if (isset($cnt['error'])) $strError = $cnt['error']; if ($waitID !== false) { write("stop_Wait\0$waitID"); $waitID = false; } if (empty($status)) return; if (!empty($id)) { if (!empty($cnt['progressDetail']) && !empty($cnt['progressDetail']['total'])) { $alltotals[$id] = $cnt['progressDetail']['total']; } if (empty($laststatus[$id])) { $laststatus[$id] = ''; } switch ($status) { case 'Waiting': // Omit break; case 'Downloading': if ($laststatus[$id] != $status) { write("addToID\0$id\0".htmlspecialchars($status)); } $total = $cnt['progressDetail']['total']; $current = $cnt['progressDetail']['current']; if ($total > 0) { $percentage = round(($current / $total) * 100); write("progress\0$id\0 ".$percentage."% "._('of')." ".$DockerClient->formatBytes($total)); } else { // Docker must not know the total download size (http-chunked or something?) // just show the current download progress without the percentage $alltotals[$id] = $current; write("progress\0$id\0".$DockerClient->formatBytes($current)); } break; default: if ($laststatus[$id] == "Downloading") { write("progress\0$id\0 100% "._('of')." ".$DockerClient->formatBytes($alltotals[$id])); } if ($laststatus[$id] != $status) { write("addToID\0".($id=='latest'?mt_rand():$id)."\0".htmlspecialchars($status)); } break; } $laststatus[$id] = $status; } else { if (strpos($status, 'Status: ') === 0) { write("addLog\0".htmlspecialchars($status)); } if (strpos($status, 'Digest: ') === 0) { $DockerUpdate->setUpdateStatus($image, substr($status,8)); } } }); write("addLog\0
"._('TOTAL DATA PULLED').": ".$DockerClient->formatBytes(array_sum($alltotals))); if (!empty($strError)) { write("addLog\0
"._('Error').": ".htmlspecialchars($strError).""); return false; } return true; } function execCommand_nchan($command) { $waitID = mt_rand(); [$cmd,$args] = explode(' ',$command,2); write("

","addLog\0
"._('Command execution')."".basename($cmd).' '.str_replace(" -","
  -",htmlspecialchars($args))."
"._('Please wait')."

","show_Wait\0$waitID"); $proc = popen("$command 2>&1",'r'); while ($out = fgets($proc)) { $out = preg_replace("%[\t\n\x0B\f\r]+%", '',$out); write("addLog\0".htmlspecialchars($out)); } $retval = pclose($proc); $out = $retval ? _('The command failed').'.' : _('The command finished successfully').'!'; write("stop_Wait\0$waitID","addLog\0
$out"); return $retval===0; } $style = [""; write(implode($style)."

"); foreach (explode('*',rawurldecode($argv[1])) as $value) { $tmpl = $DockerTemplates->getUserTemplate($value); if (!$tmpl) { write("addLog\0"._('Configuration not found').". "._('Was this container created using this plugin')."?"); continue; } $xml = file_get_contents($tmpl); [$cmd, $Name, $Repository] = xmlToCommand($tmpl); $Registry = getXmlVal($xml, "Registry"); $TS_Enabled = getXmlVal($xml, "TailscaleEnabled"); $oldImageID = $DockerClient->getImageID($Repository); // pull image if (!pullImage_nchan($Name, $Repository)) continue; $oldContainerInfo = $DockerClient->getContainerDetails($Name); // determine if the container is still running $startContainer = false; if (!empty($oldContainerInfo) && !empty($oldContainerInfo['State']) && !empty($oldContainerInfo['State']['Running'])) { // since container was already running, put it back it to a running state after update $startContainer = true; // attempt graceful stop of container first stopContainer_nchan($Name); } if ( ($argv[2]??null) == "ca_docker_run_override" ) $startContainer = true; if ( $startContainer ) $cmd = str_replace('/docker create ', '/docker run -d ', $cmd); // force kill container if still running after 10 seconds if (empty($_GET['communityApplications'])) removeContainer_nchan($Name); // Extract real Entrypoint and Cmd from container for Tailscale if ($TS_Enabled == 'true') { // Create preliminary base container but don't run it exec("/usr/local/emhttp/plugins/dynamix.docker.manager/scripts/docker create --name '" . escapeshellarg($Name) . "' '" . escapeshellarg($Repository) . "'"); // Get Entrypoint and Cmd from docker inspect $containerInfo = $DockerClient->getContainerDetails($Name); $ts_env = isset($containerInfo['Config']['Entrypoint']) ? '-e ORG_ENTRYPOINT="' . implode(' ', $containerInfo['Config']['Entrypoint']) . '" ' : ''; $ts_env .= isset($containerInfo['Config']['Cmd']) ? '-e ORG_CMD="' . implode(' ', $containerInfo['Config']['Cmd']) . '" ' : ''; // Insert Entrypoint and Cmd to docker command $cmd = str_replace('-l net.unraid.docker.managed=dockerman', $ts_env . '-l net.unraid.docker.managed=dockerman' , $cmd); // Remove preliminary container exec("/usr/local/emhttp/plugins/dynamix.docker.manager/scripts/docker rm '" . escapeshellarg($Name) . "'"); } execCommand_nchan($cmd); if ($startContainer) addRoute($Name); // add route for remote WireGuard access $DockerClient->flushCaches(); $newImageID = $DockerClient->getImageID($Repository); // remove old orphan image since it's no longer used by this container if ($oldImageID && $oldImageID != $newImageID) removeImage_nchan($oldImageID); } write('_DONE_',''); ?>