getDockerContainers(); if ( ! $all_containers) { return FALSE; } foreach ($all_containers as $ct) { if ($ct['Name'] == $container){ return True; break; } } return False; } function trimLine($text){ return preg_replace("/([\n^])[\s]+/", '$1', $text); } function pullImage($image) { if (! preg_match("/:[\w]*$/i", $image)) $image .= ":latest"; readfile("/usr/local/emhttp/plugins/dynamix.docker.manager/log.htm"); echo ''; echo ""; @flush(); $fp = stream_socket_client('unix:///var/run/docker.sock', $errno, $errstr); if ($fp === false) { echo "Couldn't create socket: [$errno] $errstr"; return NULL; } $out="POST /images/create?fromImage=$image HTTP/1.1\r\nConnection: Close\r\n\r\n"; fwrite($fp, $out); $cid = ""; $cstatus=""; $alltotals = []; while (!feof($fp)) { $cnt = json_decode( fgets($fp, 5000), TRUE ); $id = ( isset( $cnt['id'] )) ? $cnt['id'] : ""; if ($id != $cid && strlen($id)) { $cid = $id; $cstatus = ""; echo ""; @flush(); } $status = ( isset( $cnt['status'] )) ? $cnt['status'] : ""; if ($status != $cstatus && strlen($status)) { if ( isset($cnt['progressDetail']['total']) && $cnt['progressDetail']['total'] > 0 ) { $alltotals[$cnt['id']] = $cnt['progressDetail']['total']; } $cstatus = $status; echo ""; @flush(); } if ($status == "Downloading") { $total = $cnt['progressDetail']['total']; $current = $cnt['progressDetail']['current']; $alltotals[$cnt['id']] = $cnt['progressDetail']['current']; if ($total > 0) { $percentage = round(($current/$total) * 100); echo "\n"; } else { // Docker must not know the total download size (http-chunked or something?) // just show the current download progress without the percentage echo "\n"; } @flush(); } } echo "\n"; } function sizeToHuman($size) { $units = ['B','KB','MB','GB']; $unitsIndex = 0; while ($size > 1024 && (($unitsIndex+1) < count($units))) { $size /= 1024; $unitsIndex++; } return ceil($size) . " " . $units[$unitsIndex]; } function xmlToCommand($xmlFile){ global $var; $doc = new DOMDocument(); $doc->loadXML($xmlFile); $Name = $doc->getElementsByTagName( "Name" )->item(0)->nodeValue; $cmdName = (strlen($Name)) ? '--name="' . $Name . '"' : ""; $Privileged = $doc->getElementsByTagName( "Privileged" )->item(0)->nodeValue; $cmdPrivileged = (strtolower($Privileged) == 'true') ? '--privileged="true"' : ""; $Repository = $doc->getElementsByTagName( "Repository" )->item(0)->nodeValue; $Mode = $doc->getElementsByTagName( "Mode" )->item(0)->nodeValue; $cmdMode = '--net="'.strtolower($Mode).'"'; $BindTime = $doc->getElementsByTagName( "BindTime" )->item(0)->nodeValue; // $cmdBindTime = (strtolower($BindTime) == "true") ? '"/etc/localtime":"/etc/localtime":ro' : ''; $cmdBindTime = (strtolower($BindTime) == "true") ? 'TZ="' . $var['timeZone'] . '"' : ''; $Ports = array(''); foreach($doc->getElementsByTagName('Port') as $port){ $ContainerPort = $port->getElementsByTagName( "ContainerPort" )->item(0)->nodeValue; if (! strlen($ContainerPort)){ continue; } $HostPort = $port->getElementsByTagName( "HostPort" )->item(0)->nodeValue; $Protocol = $port->getElementsByTagName( "Protocol" )->item(0)->nodeValue; $Ports[] = sprintf("%s:%s/%s", $HostPort, $ContainerPort, $Protocol); } $Volumes = array(''); foreach($doc->getElementsByTagName('Volume') as $volume){ $ContainerDir = $volume->getElementsByTagName( "ContainerDir" )->item(0)->nodeValue; if (! strlen($ContainerDir)){ continue; } $HostDir = $volume->getElementsByTagName( "HostDir" )->item(0)->nodeValue; $DirMode = $volume->getElementsByTagName( "Mode" )->item(0)->nodeValue; $Volumes[] = sprintf( '"%s":"%s":%s', $HostDir, $ContainerDir, $DirMode); } // if (strlen($cmdBindTime)) { // $Volumes[] = $cmdBindTime; // } $Variables = array(''); foreach($doc->getElementsByTagName('Variable') as $variable){ $VariableName = $variable->getElementsByTagName( "Name" )->item(0)->nodeValue; if (! strlen($VariableName)){ continue; } $VariableValue = $variable->getElementsByTagName( "Value" )->item(0)->nodeValue; $Variables[] = sprintf('%s="%s"', $VariableName, $VariableValue); } if (strlen($cmdBindTime)) { $Variables[] = $cmdBindTime; } $templateExtraParams = ''; if ( $doc->getElementsByTagName( "ExtraParams" )->length > 0 ) { $templateExtraParams = $doc->getElementsByTagName( "ExtraParams" )->item(0)->nodeValue; } $cmd = sprintf('/plugins/dynamix.docker.manager/scripts/docker run -d %s %s %s %s %s %s %s %s', $cmdName, $cmdMode, $cmdPrivileged, implode(' -e ', $Variables), implode(' -p ', $Ports), implode(' -v ', $Volumes), $templateExtraParams, $Repository); $cmd = preg_replace('/\s+/', ' ', $cmd); return array($cmd, $Name, $Repository); } function addElement($doc, $el, $elName, $elVal){ $node = $el->appendChild($doc->createElement($elName)); $node->appendChild($doc->createTextNode($elVal)); return $node; } function postToXML($post, $setOwnership = FALSE){ global $DockerUpdate; $doc = new DOMDocument('1.0', 'utf-8'); $doc->preserveWhiteSpace = false; $doc->formatOutput = true; $root = $doc->createElement('Container'); $root = $doc->appendChild($root); $docName = $root->appendChild($doc->createElement('Name')); if ( isset( $post[ 'Description' ] )) addElement($doc, $root, 'Description', $post[ 'Description' ]); if ( isset( $post[ 'Registry' ] )) addElement($doc, $root, 'Registry', $post[ 'Registry' ]); $docRepository = $root->appendChild($doc->createElement('Repository')); $BindTime = $root->appendChild($doc->createElement('BindTime')); $Privileged = $root->appendChild($doc->createElement('Privileged')); $Environment = $root->appendChild($doc->createElement('Environment')); $docNetworking = $root->appendChild($doc->createElement('Networking')); $Data = $root->appendChild($doc->createElement('Data')); $Version = $root->appendChild($doc->createElement('Version')); $Mode = $docNetworking->appendChild($doc->createElement('Mode')); $Publish = $docNetworking->appendChild($doc->createElement('Publish')); $Name = preg_replace('/\s+/', '', $post["containerName"]); // Editor Values if ( isset( $post[ 'WebUI' ] )) addElement($doc, $root, 'WebUI', $post[ 'WebUI' ]); if ( isset( $post[ 'Banner' ] )) addElement($doc, $root, 'Banner', $post[ 'Banner' ]); if ( isset( $post[ 'Icon' ] )) addElement($doc, $root, 'Icon', $post[ 'Icon' ]); if ( isset( $post[ 'ExtraParams' ] )) addElement($doc, $root, 'ExtraParams', $post[ 'ExtraParams' ]); $docName->appendChild($doc->createTextNode($Name)); $docRepository->appendChild($doc->createTextNode($post["Repository"])); $BindTime->appendChild($doc->createTextNode((strtolower($post["BindTime"]) == 'on') ? 'true' : 'false')); $Privileged->appendChild($doc->createTextNode((strtolower($post["Privileged"]) == 'on') ? 'true' : 'false')); $Mode->appendChild($doc->createTextNode(strtolower($post["NetworkType"]))); for ($i = 0; $i < count($post["hostPort"]); $i++){ if (! strlen($post["containerPort"][$i])) { continue; } $protocol = $post["portProtocol"][$i]; $Port = $Publish->appendChild($doc->createElement('Port')); $HostPort = $Port->appendChild($doc->createElement('HostPort')); $ContainerPort = $Port->appendChild($doc->createElement('ContainerPort')); $Protocol = $Port->appendChild($doc->createElement('Protocol')); $HostPort->appendChild($doc->createTextNode(trim($post["hostPort"][$i]))); $ContainerPort->appendChild($doc->createTextNode($post["containerPort"][$i])); $Protocol->appendChild($doc->createTextNode($protocol)); } for ($i = 0; $i < count($post["VariableName"]); $i++){ if (! strlen($post["VariableName"][$i])) { continue; } $Variable = $Environment->appendChild($doc->createElement('Variable')); $VariableName = $Variable->appendChild($doc->createElement('Name')); $VariableValue = $Variable->appendChild($doc->createElement('Value')); $VariableName->appendChild($doc->createTextNode(trim($post["VariableName"][$i]))); $VariableValue->appendChild($doc->createTextNode(trim($post["VariableValue"][$i]))); } for ($i = 0; $i < count($post["hostPath"]); $i++){ if (! strlen($post["hostPath"][$i])) { continue; } if (! strlen($post["containerPath"][$i])) { continue; } $tmpMode = $post["hostWritable"][$i]; if ($setOwnership){ prepareDir($post["hostPath"][$i]); } $Volume = $Data->appendChild($doc->createElement('Volume')); $HostDir = $Volume->appendChild($doc->createElement('HostDir')); $ContainerDir = $Volume->appendChild($doc->createElement('ContainerDir')); $DirMode = $Volume->appendChild($doc->createElement('Mode')); $HostDir->appendChild($doc->createTextNode($post["hostPath"][$i])); $ContainerDir->appendChild($doc->createTextNode($post["containerPath"][$i])); $DirMode->appendChild($doc->createTextNode($tmpMode)); } $currentVersion = $DockerUpdate->getRemoteVersion($post["Registry"], $post["Repository"]); $Version->appendChild($doc->createTextNode($currentVersion)); return $doc->saveXML(); } if ($_POST){ $postXML = postToXML($_POST, TRUE); // Get the command line list($cmd, $Name, $Repository) = xmlToCommand($postXML); // Saving the generated configuration file. $userTmplDir = $dockerManPaths['templates-user']; if(is_dir($userTmplDir) === FALSE){ mkdir($userTmplDir, 0777, true); } if(strlen($Name)) { $filename = sprintf('%s/my-%s.xml', $userTmplDir, $Name); file_put_contents($filename, $postXML); } // Pull image pullImage($Repository); // Remove existing container if (ContainerExist($Name)){ $_GET['cmd'] = "/plugins/dynamix.docker.manager/scripts/docker rm -f $Name"; include($dockerManPaths['plugin'] . "/include/Exec.php"); } // Remove old container if renamed $existing = isset($_POST['existingContainer']) ? $_POST['existingContainer'] : FALSE; if ($existing && ContainerExist($existing)){ $_GET['cmd'] = "/plugins/dynamix.docker.manager/scripts/docker rm -f $existing"; include($dockerManPaths['plugin'] . "/include/Exec.php"); } // Injecting the command in $_GET variable and executing. $_GET['cmd'] = $cmd; include($dockerManPaths['plugin'] . "/include/Exec.php"); $DockerTemplates->removeInfo($Name); $DockerUpdate->syncVersions($Name); echo '

'; die(); } if ($_GET['updateContainer']){ foreach ($_GET['ct'] as $value) { $Name = urldecode($value); $tmpl = $DockerTemplates->getUserTemplate($Name); if (! $tmpl){ echo 'Configuration not found. Was this container created using this plugin?'; continue; } $doc = new DOMDocument('1.0', 'utf-8'); $doc->preserveWhiteSpace = false; $doc->load( $tmpl ); $doc->formatOutput = TRUE; $Repository = $doc->getElementsByTagName( "Repository" )->item(0)->nodeValue; $Registry = $doc->getElementsByTagName( "Registry" )->item(0)->nodeValue; readfile("/usr/local/emhttp/plugins/dynamix.docker.manager/log.htm"); echo ""; @flush(); $CurrentVersion = $DockerUpdate->getRemoteVersion($Registry, $Repository); if ($CurrentVersion){ if ( $doc->getElementsByTagName( "Version" )->length == 0 ) { $root = $doc->getElementsByTagName( "Container" )->item(0); $Version = $root->appendChild($doc->createElement('Version')); } else { $Version = $doc->getElementsByTagName( "Version" )->item(0); } $Version->nodeValue = $CurrentVersion; file_put_contents($tmpl, $doc->saveXML()); } $oldContainerID = $DockerClient->getImageID($Repository); list($cmd, $Name, $Repository) = xmlToCommand($doc->saveXML()); // Pull image flush(); pullImage($Repository); $_GET['cmd'] = "/plugins/dynamix.docker.manager/scripts/docker rm -f $Name"; include($dockerManPaths['plugin'] . "/include/Exec.php"); $_GET['cmd'] = $cmd; include($dockerManPaths['plugin'] . "/include/Exec.php"); $DockerTemplates->removeInfo($Name); $newContainerID = $DockerClient->getImageID($Repository); if ( $oldContainerID and $oldContainerID != $newContainerID){ $_GET['cmd'] = sprintf("/plugins/dynamix.docker.manager/scripts/docker rmi %s", $oldContainerID); include($dockerManPaths['plugin'] . "/include/Exec.php"); } $DockerTemplates->removeInfo($Name); $DockerUpdate->syncVersions($Name); } echo '

'; die(); } if($_GET['rmTemplate']){ unlink($_GET['rmTemplate']); } if($_GET['xmlTemplate']){ list($xmlType, $xmlTemplate) = split(':', urldecode($_GET['xmlTemplate'])); if(is_file($xmlTemplate)){ $doc = new DOMDocument(); $doc->load($xmlTemplate); $templateRepository = $doc->getElementsByTagName( "Repository" )->item(0)->nodeValue; $templateName = $doc->getElementsByTagName( "Name" )->item(0)->nodeValue; $Registry = $doc->getElementsByTagName( "Registry" )->item(0)->nodeValue; $templatePrivileged = (strtolower($doc->getElementsByTagName( "Privileged" )->item(0)->nodeValue) == 'true') ? 'checked' : ""; $templateMode = $doc->getElementsByTagName( "Mode" )->item(0)->nodeValue;; $readonly = ($xmlType == 'default') ? 'readonly="readonly"' : ''; $required = ($xmlType == 'default') ? 'required' : ''; $disabled = ($xmlType == 'default') ? 'disabled="disabled"' : ''; if ( $doc->getElementsByTagName( "Description" )->length > 0 ) { $templateDescription = $doc->getElementsByTagName( "Description" )->item(0)->nodeValue; } else { $templateDescription = $DockerTemplates->getTemplateValue($templateRepository, "Description", "default"); } if ( $doc->getElementsByTagName( "Registry" )->length > 0 ) { $templateRegistry = $doc->getElementsByTagName( "Registry" )->item(0)->nodeValue; } else { $templateRegistry = $DockerTemplates->getTemplateValue($templateRepository, "Registry", "default"); } if ( $doc->getElementsByTagName( "WebUI" )->length > 0 ) { $templateWebUI = $doc->getElementsByTagName( "WebUI" )->item(0)->nodeValue; } else { $templateWebUI = $DockerTemplates->getTemplateValue($templateRepository, "WebUI", "default"); } if ( $doc->getElementsByTagName( "Banner" )->length > 0 ) { $templateBanner = $doc->getElementsByTagName( "Banner" )->item(0)->nodeValue; } else { $templateBanner = $DockerTemplates->getTemplateValue($templateRepository, "Banner", "default"); } if ( $doc->getElementsByTagName( "Icon" )->length > 0 ) { $templateIcon = $doc->getElementsByTagName( "Icon" )->item(0)->nodeValue; } else { $templateIcon = $DockerTemplates->getTemplateValue($templateRepository, "Icon", "default"); } if ( $doc->getElementsByTagName( "ExtraParams" )->length > 0 ) { $templateExtraParams = $doc->getElementsByTagName( "ExtraParams" )->item(0)->nodeValue; } else { $templateExtraParams = $DockerTemplates->getTemplateValue($templateRepository, "ExtraParams", "default"); } $templateDescription = stripslashes($templateDescription); $templateRegistry = stripslashes($templateRegistry); $templateWebUI = stripslashes($templateWebUI); $templateBanner = stripslashes($templateBanner); $templateIcon = stripslashes($templateIcon); $templateExtraParams = stripslashes($templateExtraParams); $templateDescBox = preg_replace('/\[/', '<', $templateDescription); $templateDescBox = preg_replace('/\]/', '>', $templateDescBox); $templatePorts = ''; $row = ' '; $i = 1; foreach($doc->getElementsByTagName('Port') as $port){ $j = $i + 100; $ContainerPort = $port->getElementsByTagName( "ContainerPort" )->item(0)->nodeValue; if (! strlen($ContainerPort)){ continue; } $HostPort = $port->getElementsByTagName( "HostPort" )->item(0)->nodeValue; $Protocol = $port->getElementsByTagName( "Protocol" )->item(0)->nodeValue; $select = ($Protocol == 'udp') ? 'selected' : ''; $templatePorts .= sprintf($row, $j, htmlspecialchars($ContainerPort), $readonly, htmlspecialchars($HostPort), $required, $select, $j, $disabled); $i++; } $templateVolumes = ''; $row = '
'; $i = 1; foreach($doc->getElementsByTagName('Volume') as $volume){ $j = $i + 100; $ContainerDir = $volume->getElementsByTagName( "ContainerDir" )->item(0)->nodeValue; if (! strlen($ContainerDir)){ continue; } $HostDir = $volume->getElementsByTagName( "HostDir" )->item(0)->nodeValue; $Mode = $volume->getElementsByTagName( "Mode" )->item(0)->nodeValue; $Mode = ($Mode == "ro") ? "selected" : ''; $templateVolumes .= sprintf($row, $j, htmlspecialchars($ContainerDir), $j, $readonly, $j, htmlspecialchars($HostDir), $j, $required, $j, $Mode, $j, $disabled); $i++; } $templateVariables = ''; $row = ' '; $i = 1; foreach($doc->getElementsByTagName('Variable') as $variable){ $j = $i + 100; $VariableName = $variable->getElementsByTagName( "Name" )->item(0)->nodeValue; if (! strlen($VariableName)){ continue; } $VariableValue = $variable->getElementsByTagName( "Value" )->item(0)->nodeValue; $templateVariables .= sprintf($row, $j, htmlspecialchars($VariableName), $readonly, htmlspecialchars($VariableValue), $required, $j, $disabled); $i++; } } } $showAdditionalInfo = true; ?>
\n"; endif; else:?>
Template: "; }?>
Description:

Container Page: " . htmlspecialchars($Registry) . ""; } ?>
Name:
Network type:
Volume Mappings
Container volume: Host path: Access:

Applications can be given read and write access to your data by mapping a directory path from the container to a directory path on the host. When looking at the volume mappings section, the Container volume represents the path from the container that will be mapped. The Host path represents the path the Container volume will map to on your unRAID system. All applications should require at least one volume mapping to store application metadata (e.g., media libraries, application settings, user profile data, etc.). Clicking inside these fields provides a "picker" that will let you navigate to where the mapping should point. Additional mappings can be manually created by clicking the Add Path button. Most applications will need you to specify additional mappings in order for the application to interact with other data on the system (e.g., with Plex Media Server, you should specify an additional mapping to give it access to your media files). It is important that when naming Container volumes that you specify a path that won’t conflict with already existing folders present in the container. If unfamiliar with Linux, using a prefix such as "unraid_" for the volume name is a safe bet (e.g., "/unraid_media" is a valid Container volume name).

Port Mappings
Container port: Host port: Protocol:

When the network type is set to Bridge, you will be given the option of customizing what ports the container will use. While applications may be configured to talk to a specific port by default, we can remap those to different ports on our host with Docker. This means that while three different apps may all want to use port 8000, we can map each app to a unique port on the host (e.g., 8000, 8001, and 8002). When the network type is set to Host, the container will be allowed to use any available port on your system. Additional port mappings can be created, similar to Volumes, although this is not typically necessary when working with templates as port mappings should already be specified.

>
Extra Parameters

If you wish to append additional commands to your Docker container at run-time, you can specify them here. For example, if you wish to pin an application to live on a specific CPU core, you can enter "--cpuset=0" in this field. Change 0 to the core # on your system (starting with 0). You can pin multiple cores by separation with a comma or a range of cores by separation with a dash. For all possible Docker run-time commands, see here: https://docs.docker.com/reference/run/

style="display:none">
Additional Fields
Docker Hub URL:
WebUI:
Banner:
Icon:
Description: