From aec8f4794279a41303f20ddf5414f6aae4d146e0 Mon Sep 17 00:00:00 2001 From: Reinhard Dietl Date: Tue, 19 Dec 2023 12:14:09 +0100 Subject: [PATCH] Allow Docker image name to contain custom registry with a port specification. --- .../include/DockerClient.php | 54 +++++++++++++++---- .../include/DockerContainers.php | 2 +- 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/emhttp/plugins/dynamix.docker.manager/include/DockerClient.php b/emhttp/plugins/dynamix.docker.manager/include/DockerClient.php index 0007b0d7a..cce7b1bbc 100644 --- a/emhttp/plugins/dynamix.docker.manager/include/DockerClient.php +++ b/emhttp/plugins/dynamix.docker.manager/include/DockerClient.php @@ -428,7 +428,7 @@ class DockerUpdate{ // DEPRECATED: Only used for Docker Index V1 type update checks public function getRemoteVersion($image) { - [$strRepo, $strTag] = array_pad(explode(':', DockerUtil::ensureImageTag($image)),2,''); + extract(DockerUtil::parseImageTag($image)); $apiUrl = sprintf('http://index.docker.io/v1/repositories/%s/tags/%s', $strRepo, $strTag); //$this->debug("API URL: $apiUrl"); $apiContent = $this->download_url($apiUrl); @@ -436,7 +436,7 @@ class DockerUpdate{ } public function getRemoteVersionV2($image) { - [$strRepo, $strTag] = array_pad(explode(':', DockerUtil::ensureImageTag($image)),2,''); + extract(DockerUtil::parseImageTag($image)); /* * Step 1: Check whether or not the image is in a private registry, get corresponding auth data and generate manifest url */ @@ -980,7 +980,7 @@ class DockerClient { $c['Size'] = $this->formatBytes($ct['Size']); $c['VirtualSize'] = $this->formatBytes($ct['VirtualSize']); $c['Tags'] = array_map('htmlspecialchars', $ct['RepoTags'] ?? []); - $c['Repository'] = vsprintf('%1$s/%2$s', preg_split("#[:\/]#", DockerUtil::ensureImageTag($ct['RepoTags'][0]??''))); + $c['Repository'] = DockerUtil::parseImageTag($ct['RepoTags'][0]??'')['strRepo']; $c['usedBy'] = $this->usedBy($c['Id']); $this::$imagesCache[$c['Id']] = $c; } @@ -993,18 +993,50 @@ class DockerClient { ################################## class DockerUtil { - public static function ensureImageTag($image) { - [$strRepo, $strTag] = array_map('trim', array_pad(explode(':', $image.':'),2,'')); - if (strpos($strRepo, 'sha256:') === 0) { + public static function ensureImageTag($image): string + { + extract(static::parseImageTag($image)); + + return "$strRepo:$strTag"; + } + + public static function parseImageTag($image): array + { + if (strpos($image, 'sha256:') === 0) { // sha256 was provided instead of actual repo name so truncate it for display: - $strRepo = substr($strRepo, 7, 12); - } elseif (strpos($strRepo, '/') === false) { - // Prefix library/ if there's no author (maybe a Docker offical image?) - $strRepo = "library/$strRepo"; + $strRepo = substr($image, 7, 12); + } elseif (strpos($image, '/') === false) { + return static::parseImageTag('library/' . $image); + } else { + $parsedImage = static::splitImage($image); + if (!empty($parsedImage)) { + $strRepo = $parsedImage['strRepo']; + $strTag = $parsedImage['strTag']; + } else { + // Unprocessable input + $strRepo = $image; + } } + // Add :latest tag to image if it's absent if (empty($strTag)) $strTag = 'latest'; - return "$strRepo:$strTag"; + + return array_map('trim', ['strRepo' => $strRepo, 'strTag' => $strTag]); + } + + private static function splitImage($image): ?array + { + if (false === preg_match('@^(.+/)*([^/:]+)(:[^:/]*)*$@', $image, $newSections) || count($newSections) < 3) { + return null; + } else { + [, $strRepo, $image, $strTag] = array_merge($newSections, ['']); + $strTag = str_replace(':','',$strTag??''); + + return [ + 'strRepo' => $strRepo . $image, + 'strTag' => $strTag, + ]; + } } public static function loadJSON($path) { diff --git a/emhttp/plugins/dynamix.docker.manager/include/DockerContainers.php b/emhttp/plugins/dynamix.docker.manager/include/DockerContainers.php index 400898dd6..9caf1fc20 100644 --- a/emhttp/plugins/dynamix.docker.manager/include/DockerContainers.php +++ b/emhttp/plugins/dynamix.docker.manager/include/DockerContainers.php @@ -110,7 +110,7 @@ foreach ($containers as $ct) { if ($ct['BaseImage']) echo "".htmlspecialchars($ct['BaseImage'])."
"; echo _('By').": "; $registry = $info['registry']; - [$author,$version] = my_explode(':',$ct['Image']); + ['strRepo' => $author, 'strTag' => $version] = DockerUtil::parseImageTag($ct['Image']); if ($registry) { echo "".htmlspecialchars(compress($author,24)).""; } else {