diff --git a/plugins/dynamix.docker.manager/include/CreateDocker.php b/plugins/dynamix.docker.manager/include/CreateDocker.php index 1ac35defa..1805e149c 100644 --- a/plugins/dynamix.docker.manager/include/CreateDocker.php +++ b/plugins/dynamix.docker.manager/include/CreateDocker.php @@ -381,8 +381,8 @@ function xmlToCommand($xml, $create_paths=false) { global $var; global $docroot; $xml = xmlToVar($xml); - $cmdName = (strlen($xml['Name'])) ? '--name='.escapeshellarg($xml['Name']) : ''; - $cmdPrivileged = (strtolower($xml['Privileged']) == 'true') ? '--privileged=true' : ''; + $cmdName = strlen($xml['Name']) ? '--name='.escapeshellarg($xml['Name']) : ''; + $cmdPrivileged = strtolower($xml['Privileged'])=='true' ? '--privileged=true' : ''; $cmdNetwork = '--net='.escapeshellarg(strtolower($xml['Network'])); $cmdMyIP = $xml['MyIP'] ? '--ip='.escapeshellarg($xml['MyIP']) : ''; $Volumes = ['']; @@ -434,9 +434,7 @@ function xmlToCommand($xml, $create_paths=false) { $xml['ExtraParams'], escapeshellarg($xml['Repository']), $xml['PostArgs']); - - $cmd = trim(preg_replace('/\s+/', ' ', $cmd)); - return [$cmd, $xml['Name'], $xml['Repository']]; + return [preg_replace('/\s+/', ' ', $cmd), $xml['Name'], $xml['Repository']]; } function execCommand($command) { @@ -532,11 +530,10 @@ function getUsedIPs() { ## ## CREATE CONTAINER ## - if (isset($_POST['contName'])) { - $postXML = postToXML($_POST, true); - $dry_run = ($_POST['dryRun'] == "true") ? true : false; + $dry_run = $_POST['dryRun']=='true' ? true : false; + $existing = $_POST['existingContainer'] ?? false; $create_paths = $dry_run ? false : true; // Get the command line @@ -547,10 +544,8 @@ if (isset($_POST['contName'])) { // Saving the generated configuration file. $userTmplDir = $dockerManPaths['templates-user']; - if (!is_dir($userTmplDir)) { - mkdir($userTmplDir, 0777, true); - } - if (!empty($Name)) { + if (!is_dir($userTmplDir)) mkdir($userTmplDir, 0777, true); + if ($Name) { $filename = sprintf('%s/my-%s.xml', $userTmplDir, $Name); file_put_contents($filename, $postXML); } @@ -591,7 +586,6 @@ if (isset($_POST['contName'])) { } // Remove old container if renamed - $existing = isset($_POST['existingContainer']) ? $_POST['existingContainer'] : false; if ($existing && $DockerClient->doesContainerExist($existing)) { // determine if the container is still running $oldContainerDetails = $DockerClient->getContainerDetails($existing); @@ -605,6 +599,8 @@ if (isset($_POST['contName'])) { // force kill container if still running after 10 seconds removeContainer($existing); + // remove old template + @unlink("$userTmplDir/my-$existing.xml"); } if ($startContainer) { diff --git a/plugins/dynamix.docker.manager/include/DockerClient.php b/plugins/dynamix.docker.manager/include/DockerClient.php index aa83dfbb2..1752b55a8 100644 --- a/plugins/dynamix.docker.manager/include/DockerClient.php +++ b/plugins/dynamix.docker.manager/include/DockerClient.php @@ -1,6 +1,7 @@ verbose) echo $m."\n"; } - public function download_url($url, $path = "", $bg = false) { exec("curl --max-time 60 --silent --insecure --location --fail ".($path ? " -o ".escapeshellarg($path) : "")." ".escapeshellarg($url)." ".($bg ? ">/dev/null 2>&1 &" : "2>/dev/null"), $out, $exit_code); return ($exit_code === 0) ? implode("\n", $out) : false; } - public function listDir($root, $ext = null) { $iter = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($root, @@ -68,7 +67,6 @@ class DockerTemplates { return $paths; } - public function getTemplates($type) { global $dockerManPaths; $tmpls = []; @@ -90,7 +88,6 @@ class DockerTemplates { return $tmpls; } - private function removeDir($path) { if (is_dir($path)) { $files = array_diff(scandir($path), ['.', '..']); @@ -104,11 +101,10 @@ class DockerTemplates { return false; } - public function downloadTemplates($Dest = null, $Urls = null) { global $dockerManPaths; - $Dest = ($Dest) ? $Dest : $dockerManPaths['templates-storage']; - $Urls = ($Urls) ? $Urls : $dockerManPaths['template-repos']; + $Dest = $Dest ?: $dockerManPaths['templates-storage']; + $Urls = $Urls ?: $dockerManPaths['template-repos']; $repotemplates = []; $output = []; $tmp_dir = "/tmp/tmp-".mt_rand(); @@ -129,10 +125,10 @@ class DockerTemplates { $github_api = ['url' => '']; foreach ($github_api_regexes as $api_regex) { if (preg_match($api_regex, $url, $matches)) { - $github_api['user'] = (isset($matches[1])) ? $matches[1] : ""; - $github_api['repo'] = (isset($matches[2])) ? $matches[2] : ""; - $github_api['branch'] = (isset($matches[3])) ? $matches[3] : "master"; - $github_api['path'] = (isset($matches[4])) ? $matches[4] : ""; + $github_api['user'] = $matches[1] ?? ""; + $github_api['repo'] = $matches[2] ?? ""; + $github_api['branch'] = $matches[3] ?? "master"; + $github_api['path'] = $matches[4] ?? ""; $github_api['url'] = sprintf("https://github.com/%s/%s/archive/%s.tar.gz", $github_api['user'], $github_api['repo'], $github_api['branch']); break; } @@ -151,10 +147,10 @@ class DockerTemplates { ]; foreach ($custom_api_regexes as $api_regex) { if (preg_match($api_regex, $url, $matches)) { - $github_api['user'] = (isset($matches[1])) ? $matches[1] : ""; - $github_api['repo'] = (isset($matches[2])) ? $matches[2] : ""; - $github_api['branch'] = (isset($matches[3])) ? $matches[3] : "master"; - $github_api['path'] = (isset($matches[4])) ? $matches[4] : ""; + $github_api['user'] = $matches[1] ?? ""; + $github_api['repo'] = $matches[2] ?? ""; + $github_api['branch'] = $matches[3] ?? "master"; + $github_api['path'] = $matches[4] ?? ""; $github_api['url'] = sprintf("https://".$parse['host']."/%s/%s/repository/archive.tar.gz?ref=%s", $github_api['user'], $github_api['repo'], $github_api['branch']); break; } @@ -213,7 +209,6 @@ class DockerTemplates { return $output; } - public function getTemplateValue($Repository, $field, $scope = "all") { foreach ($this->getTemplates($scope) as $file) { $doc = new DOMDocument(); @@ -228,7 +223,6 @@ class DockerTemplates { return null; } - public function getUserTemplate($Container) { foreach ($this->getTemplates("user") as $file) { $doc = new DOMDocument('1.0', 'utf-8'); @@ -241,11 +235,9 @@ class DockerTemplates { return false; } - public function getControlURL($name) { global $eth0; $DockerClient = new DockerClient(); - $Repository = ""; foreach ($DockerClient->getDockerContainers() as $ct) { if ($ct['Name'] == $name) { @@ -254,12 +246,10 @@ class DockerTemplates { break; } } - $WebUI = $this->getTemplateValue($Repository, "WebUI"); $myIP = $this->getTemplateValue($Repository, "MyIP"); $network = $this->getTemplateValue($Repository, "Network"); if (!$myIP && preg_match('%^(br|eth|bond)[0-9]%',$network)) { - $name = $this->getTemplateValue($Repository, "Name"); $myIP = exec("docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $name"); } if (preg_match("%\[IP\]%", $WebUI)) { @@ -279,7 +269,6 @@ class DockerTemplates { return $WebUI; } - public function removeContainerInfo($container) { global $dockerManPaths; @@ -290,7 +279,6 @@ class DockerTemplates { } } - public function removeImageInfo($image) { global $dockerManPaths; $image = DockerUtil::ensureImageTag($image); @@ -302,57 +290,33 @@ class DockerTemplates { } } - public function getAllInfo($reload = false) { global $dockerManPaths; $DockerClient = new DockerClient(); $DockerUpdate = new DockerUpdate(); $DockerUpdate->verbose = $this->verbose; $new_info = []; - $info = DockerUtil::loadJSON($dockerManPaths['webui-info']); - - $autostart_file = $dockerManPaths['autostart-file']; - $allAutoStart = @file($autostart_file, FILE_IGNORE_NEW_LINES); - if ($allAutoStart === false) $allAutoStart = []; + $allAutoStart = @file($dockerManPaths['autostart-file'], FILE_IGNORE_NEW_LINES) ?: []; foreach ($DockerClient->getDockerContainers() as $ct) { $name = $ct['Name']; $image = $ct['Image']; - $tmp = is_array($info[$name]) ? $info[$name] : []; - + $tmp = $info[$name] ?? []; $tmp['running'] = $ct['Running']; $tmp['autostart'] = in_array($name, $allAutoStart); - - if (!$tmp['icon'] || $reload) { - $icon = $this->getIcon($image); - $tmp['icon'] = $icon ?: null; - } - $WebUI = $this->getControlURL($name); - $tmp['url'] = $WebUI ?: null; - - $Registry = $this->getTemplateValue($image, "Registry"); - $tmp['registry'] = ($Registry) ? $Registry : null; - - $Support = $this->getTemplateValue($image, "Support"); - $tmp['Support'] = ($Support) ? $Support : null; - - $Project = $this->getTemplateValue($image, "Project"); - $tmp['Project'] = ($Project) ? $Project : null; - + if (!$tmp['icon'] || $reload) $tmp['icon'] = $this->getIcon($image) ?: null; + $tmp['url'] = $this->getControlURL($name) ?: null; + $tmp['registry'] = $this->getTemplateValue($image, "Registry") ?: null; + $tmp['Support'] = $this->getTemplateValue($image, "Support") ?: null; + $tmp['Project'] = $this->getTemplateValue($image, "Project") ?: null; if (!$tmp['updated'] || $reload) { if ($reload) $DockerUpdate->reloadUpdateStatus($image); $vs = $DockerUpdate->getUpdateStatus($image); $tmp['updated'] = ($vs === null) ? null : (($vs === true) ? 'true' : 'false'); } - - if (!$tmp['template'] || $reload) { - $tmp['template'] = $this->getUserTemplate($name); - } - - if ($reload) { - $DockerUpdate->updateUserTemplate($name); - } + if (!$tmp['template'] || $reload) $tmp['template'] = $this->getUserTemplate($name); + if ($reload) $DockerUpdate->updateUserTemplate($name); $this->debug("\n$name"); foreach ($tmp as $c => $d) $this->debug(sprintf(" %-10s: %s", $c, $d)); @@ -362,7 +326,6 @@ class DockerTemplates { return $new_info; } - public function getIcon($Repository) { global $docroot, $dockerManPaths; @@ -383,7 +346,6 @@ class DockerTemplates { } } - ###################################### ## DOCKERUPDATE CLASS ## ###################################### @@ -394,23 +356,19 @@ class DockerUpdate{ if ($this->verbose) echo $m."\n"; } - private function xml_encode($string) { return htmlspecialchars($string, ENT_XML1, 'UTF-8'); } - private function xml_decode($string) { return strval(html_entity_decode($string, ENT_XML1, 'UTF-8')); } - public function download_url($url, $path = "", $bg = false) { exec("curl --max-time 30 --silent --insecure --location --fail ".($path ? " -o ".escapeshellarg($path) : "")." ".escapeshellarg($url)." ".($bg ? ">/dev/null 2>&1 &" : "2>/dev/null"), $out, $exit_code); return ($exit_code === 0) ? implode("\n", $out) : false; } - public function download_url_and_headers($url, $headers = [], $path = "", $bg = false) { $strHeaders = ''; foreach ($headers as $header) { @@ -420,7 +378,6 @@ class DockerUpdate{ return ($exit_code === 0) ? implode("\n", $out) : false; } - // DEPRECATED: Only used for Docker Index V1 type update checks public function getRemoteVersion($image) { list($strRepo, $strTag) = explode(':', DockerUtil::ensureImageTag($image)); @@ -430,7 +387,6 @@ class DockerUpdate{ return ($apiContent === false) ? null : substr(json_decode($apiContent, true)[0]['id'], 0, 8); } - public function getRemoteVersionV2($image) { list($strRepo, $strTag) = explode(':', DockerUtil::ensureImageTag($image)); @@ -473,14 +429,12 @@ class DockerUpdate{ return $strDigest; } - // DEPRECATED: Only used for Docker Index V1 type update checks public function getLocalVersion($image) { $DockerClient = new DockerClient(); return substr($DockerClient->getImageID($image), 0, 8); } - public function getUpdateStatus($image) { global $dockerManPaths; $image = DockerUtil::ensureImageTag($image); @@ -496,7 +450,6 @@ class DockerUpdate{ return null; } - public function reloadUpdateStatus($image = null) { global $dockerManPaths; $DockerClient = new DockerClient(); @@ -519,7 +472,6 @@ class DockerUpdate{ DockerUtil::saveJSON($dockerManPaths['update-status'], $updateStatus); } - public function setUpdateStatus($image, $version) { global $dockerManPaths; $image = DockerUtil::ensureImageTag($image); @@ -533,7 +485,6 @@ class DockerUpdate{ DockerUtil::saveJSON($dockerManPaths['update-status'], $updateStatus); } - public function updateUserTemplate($Container) { $changed = false; $DockerTemplates = new DockerTemplates(); @@ -636,7 +587,6 @@ class DockerUpdate{ } } - ###################################### ## DOCKERCLIENT CLASS ## ###################################### @@ -646,14 +596,12 @@ class DockerClient { private $allImagesCache = null; - private function build_sorter($key) { return function ($a, $b) use ($key) { return strnatcmp(strtolower($a[$key]), strtolower($b[$key])); }; } - public function humanTiming($time) { $time = time() - $time; // to get the time since that moment $tokens = [ @@ -668,11 +616,10 @@ class DockerClient { foreach ($tokens as $unit => $text) { if ($time < $unit) continue; $numberOfUnits = floor($time / $unit); - return $numberOfUnits.' '.$text.(($numberOfUnits>1)?'s':'').' ago'; + return $numberOfUnits.' '.$text.(($numberOfUnits==1)?'':'s').' ago'; } } - public function formatBytes($size) { if ($size == 0) return '0 B'; $base = log($size) / log(1024); @@ -680,7 +627,6 @@ class DockerClient { return round(pow(1024, $base - floor($base)), 0) .' '. $suffix[floor($base)]; } - public function getDockerJSON($url, $method = "GET", &$code = null, $callback = null, $unchunk = false) { $fp = stream_socket_client('unix:///var/run/docker.sock', $errno, $errstr); @@ -713,7 +659,6 @@ class DockerClient { return $data; } - function doesContainerExist($container) { foreach ($this->getDockerContainers() as $ct) { if ($ct['Name'] == $container) { @@ -723,7 +668,6 @@ class DockerClient { return false; } - function doesImageExist($image) { foreach ($this->getDockerImages() as $img) { if (strpos($img['Tags'][0], $image) !== false) { @@ -733,24 +677,20 @@ class DockerClient { return false; } - public function getInfo() { $info = $this->getDockerJSON("/info"); $version = $this->getDockerJSON("/version"); return array_merge($info, $version); } - public function getContainerLog($id, $callback, $tail = null, $since = null) { $this->getDockerJSON("/containers/${id}/logs?stderr=1&stdout=1&tail=".urlencode($tail)."&since=".urlencode($since), "GET", $code, $callback, true); } - public function getContainerDetails($id) { return $this->getDockerJSON("/containers/${id}/json"); } - public function startContainer($id) { $this->getDockerJSON("/containers/${id}/start", "POST", $code); $this->allContainersCache = null; // flush cache @@ -763,7 +703,6 @@ class DockerClient { return (array_key_exists($code, $codes)) ? $codes[$code] : 'Error code '.$code; } - public function stopContainer($id) { $this->getDockerJSON("/containers/${id}/stop?t=10", "POST", $code); $this->allContainersCache = null; // flush cache @@ -776,7 +715,6 @@ class DockerClient { return (array_key_exists($code, $codes)) ? $codes[$code] : 'Error code '.$code; } - public function restartContainer($id) { $this->getDockerJSON("/containers/${id}/restart?t=10", "POST", $code); $this->allContainersCache = null; // flush cache @@ -788,7 +726,6 @@ class DockerClient { return (array_key_exists($code, $codes)) ? $codes[$code] : 'Error code '.$code; } - public function removeContainer($id) { global $docroot, $dockerManPaths; // Purge cached container information @@ -819,14 +756,12 @@ class DockerClient { return (array_key_exists($code, $codes)) ? $codes[$code] : 'Error code '.$code; } - public function pullImage($image, $callback = null) { $ret = $this->getDockerJSON("/images/create?fromImage=".urlencode($image), "POST", $code, $callback); $this->allImagesCache = null; // flush cache return $ret; } - public function removeImage($id) { global $dockerManPaths; $image = $this->getImageName($id); @@ -851,12 +786,10 @@ class DockerClient { return (array_key_exists($code, $codes)) ? $codes[$code] : 'Error code '.$code; } - private function getImageDetails($id) { return $this->getDockerJSON("/images/${id}/json"); } - public function getDockerContainers() { // Return cached values if (is_array($this->allContainersCache)) { @@ -871,21 +804,21 @@ class DockerClient { $c["Image"] = DockerUtil::ensureImageTag($obj['Image']); $c["ImageId"] = substr(str_replace('sha256:', '', $details["Image"]), 0, 12); $c["Name"] = substr($details['Name'], 1); - $c["Status"] = $obj['Status'] ? $obj['Status'] : "None"; + $c["Status"] = $obj['Status'] ?: "None"; $c["Running"] = $details["State"]["Running"]; $c["Cmd"] = $obj['Command']; $c["Id"] = substr($obj['Id'], 0, 12); $c['Volumes'] = $details["HostConfig"]['Binds']; $c["Created"] = $this->humanTiming($obj['Created']); $c["NetworkMode"] = $details['HostConfig']['NetworkMode']; - $c["BaseImage"] = isset($obj["Labels"]["BASEIMAGE"]) ? $obj["Labels"]["BASEIMAGE"] : false; + $c["BaseImage"] = $obj["Labels"]["BASEIMAGE"] ?? false; $c["Ports"] = []; if ($c["NetworkMode"] != 'host' && !empty($details['HostConfig']['PortBindings'])) { foreach ($details['HostConfig']['PortBindings'] as $port => $value) { list($PrivatePort, $Type) = explode("/", $port); $c["Ports"][] = [ - 'IP' => empty($value[0]['HostIP']) ? '0.0.0.0' : $value[0]['HostIP'], + 'IP' => $value[0]['HostIP'] ?? '0.0.0.0', 'PrivatePort' => $PrivatePort, 'PublicPort' => $value[0]['HostPort'], 'Type' => $Type @@ -899,7 +832,6 @@ class DockerClient { return $this->allContainersCache; } - public function getContainerID($Container) { foreach ($this->getDockerContainers() as $ct) { if (preg_match("%" . preg_quote($Container, "%") . "%", $ct["Name"])) { @@ -909,7 +841,6 @@ class DockerClient { return null; } - public function getImageID($Image) { if ( ! strpos($Image,":") ) { $Image .= ":latest"; @@ -943,7 +874,6 @@ class DockerClient { return $out; } - public function getDockerImages() { // Return cached values if (is_array($this->allImagesCache)) { @@ -958,7 +888,7 @@ class DockerClient { $c["ParentId"] = substr(str_replace('sha256:', '', $obj['ParentId']), 0, 12); $c["Size"] = $this->formatBytes($obj['Size']); $c["VirtualSize"] = $this->formatBytes($obj['VirtualSize']); - $c["Tags"] = isset($obj['RepoTags']) ? array_map("htmlspecialchars", $obj['RepoTags']) : array(); + $c["Tags"] = array_map("htmlspecialchars", $obj['RepoTags'] ?? []); $c["Repository"] = vsprintf('%1$s/%2$s', preg_split("#[:\/]#", DockerUtil::ensureImageTag($obj['RepoTags'][0]))); $c["usedBy"] = $this->usedBy($c["Id"]); @@ -967,14 +897,12 @@ class DockerClient { return $this->allImagesCache; } - public function flushCaches() { $this->allContainersCache = null; $this->allImagesCache = null; } } - ###################################### ## DOCKERUTIL CLASS ## ###################################### @@ -999,7 +927,6 @@ class DockerUtil { return trim($strRepo).':'.trim($strTag); } - public static function loadJSON($path) { $objContent = (is_file($path)) ? json_decode(file_get_contents($path), true) : []; if (empty($objContent)) $objContent = []; @@ -1007,12 +934,10 @@ class DockerUtil { return $objContent; } - public static function saveJSON($path, $content) { if (!is_dir(dirname($path))) @mkdir(dirname($path), 0755, true); return file_put_contents($path, json_encode($content, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); } - } ?> diff --git a/plugins/dynamix.docker.manager/include/DockerContainers.php b/plugins/dynamix.docker.manager/include/DockerContainers.php index 75f7f4f30..c9aa9ae2c 100644 --- a/plugins/dynamix.docker.manager/include/DockerContainers.php +++ b/plugins/dynamix.docker.manager/include/DockerContainers.php @@ -113,15 +113,16 @@ foreach ($all_containers as $ct) { } foreach ($DockerClient->getDockerImages() as $image) { if (count($image['usedBy'])) continue; - $menu[] = sprintf("addDockerImageContext('%s','%s');",$image['Id'],implode(', ',$image['Tags'])); + $id = $image['Id']; + $menu[] = sprintf("addDockerImageContext('%s','%s');",$id,implode(',',$image['Tags'])); echo "
";
echo "