mirror of
https://github.com/unraid/webgui.git
synced 2026-05-09 05:41:17 -05:00
Docker: added container vpn network support
This commit is contained in:
@@ -37,6 +37,7 @@ th.load{width:140px}
|
||||
input.wait{width:24px;margin:0 4px;padding:0 5px;border:none;box-shadow:none;background-color:transparent}
|
||||
table tbody td{line-height:normal}
|
||||
</style>
|
||||
<div class="spinner fixed" style="display:none"></div>
|
||||
<div id="iframe-popup" style="display:none;-webkit-overflow-scrolling:touch;"></div>
|
||||
<span class="status" style="margin-top:<?=$width?>px"><span><input type="checkbox" class="advancedview"></span></span>
|
||||
<table id="docker_containers" class="tablesorter shift">
|
||||
@@ -101,7 +102,7 @@ var sortableHelper = function(e,i){
|
||||
function loadlist() {
|
||||
$.get('/plugins/dynamix.docker.manager/include/DockerContainers.php',function(d) {
|
||||
var data = d.split(/\0/);
|
||||
$('div.spinner').hide('slow').remove();
|
||||
$('div.spinner').hide('slow');
|
||||
$('#docker_list').html(data[0]).sortable({helper:sortableHelper,items:'tr.sortable',cursor:'move',axis:'y',containment:'parent',cancel:'span.docker_readmore,input',delay:100,opacity:0.5,zIndex:9999,
|
||||
update:function(e,ui){
|
||||
var row = $('#docker_list').find('tr:first');
|
||||
@@ -131,11 +132,15 @@ function loadlist() {
|
||||
if ($.cookie('docker_listview_mode')=='advanced') {$('.advanced').show(); $('.basic').hide();}
|
||||
context.init({preventDoubleContext:false,left:true,above:false});
|
||||
$('input[type=button]').prop('disabled',false).show('slow');
|
||||
var update = false;
|
||||
for (var i=0,ct; ct=docker[i]; i++) if (ct.update=='false') {update = true; break;};
|
||||
if (!update) $('input#updateAll').prop('disabled',true);
|
||||
var update = false, rebuild = false;
|
||||
for (var i=0,ct; ct=docker[i]; i++) {
|
||||
if (ct.update==0) update = true;
|
||||
if (ct.update==2) rebuild = true;
|
||||
}
|
||||
listview();
|
||||
if (data[2]==1) {$('#busy').show(); setTimeout(loadlist,5000);} else if ($('#busy').is(':visible')) {$('#busy').hide(); setTimeout(loadlist,3000);}
|
||||
if (!update) $('input#updateAll').prop('disabled',true);
|
||||
if (rebuild) rebuildAll();
|
||||
});
|
||||
}
|
||||
function sizes() {
|
||||
@@ -153,6 +158,7 @@ watchDocker.on('message', function(data){
|
||||
}
|
||||
});
|
||||
$(function() {
|
||||
$('div.spinner').html(unraid_logo);
|
||||
$('.advancedview').switchButton({labels_placement:'left', on_label:'Advanced View', off_label:'Basic View', checked:$.cookie('docker_listview_mode')=='advanced'});
|
||||
$('.advancedview').change(function(){
|
||||
$('.advanced').toggle('slow');
|
||||
|
||||
@@ -156,11 +156,14 @@ if (isset($_POST['contName'])) {
|
||||
##########################
|
||||
|
||||
if ($_GET['updateContainer']){
|
||||
readfile("$docroot/plugins/dynamix.docker.manager/log.htm");
|
||||
@flush();
|
||||
$echo = $_GET['mute'] ? false : true;
|
||||
if ($echo) {
|
||||
readfile("$docroot/plugins/dynamix.docker.manager/log.htm");
|
||||
@flush();
|
||||
}
|
||||
foreach ($_GET['ct'] as $value) {
|
||||
$tmpl = $DockerTemplates->getUserTemplate(urldecode($value));
|
||||
if (!$tmpl) {
|
||||
if ($echo && !$tmpl) {
|
||||
echo "<script>addLog('<p>Configuration not found. Was this container created using this plugin?</p>');</script>";
|
||||
@flush();
|
||||
continue;
|
||||
@@ -169,27 +172,23 @@ if ($_GET['updateContainer']){
|
||||
list($cmd, $Name, $Repository) = xmlToCommand($tmpl);
|
||||
$Registry = getXmlVal($xml, "Registry");
|
||||
$oldImageID = $DockerClient->getImageID($Repository);
|
||||
// Pull image
|
||||
if (!pullImage($Name, $Repository)) continue;
|
||||
// pull image
|
||||
if ($echo) if (!pullImage($Name, $Repository)) continue;
|
||||
$oldContainerInfo = $DockerClient->getContainerDetails($Name);
|
||||
// determine if the container is still running
|
||||
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
|
||||
$cmd = str_replace('/docker create ', '/docker run -d ', $cmd);
|
||||
// attempt graceful stop of container first
|
||||
stopContainer($Name);
|
||||
stopContainer($Name, $echo);
|
||||
}
|
||||
// force kill container if still running after 10 seconds
|
||||
if (!$_GET['communityApplications']) {
|
||||
removeContainer($Name);
|
||||
}
|
||||
execCommand($cmd);
|
||||
if (!$_GET['communityApplications']) removeContainer($Name, $echo);
|
||||
execCommand($cmd, $echo);
|
||||
$DockerClient->flushCaches();
|
||||
$newImageID = $DockerClient->getImageID($Repository);
|
||||
if ($oldImageID && $oldImageID != $newImageID) {
|
||||
// remove old orphan image since it's no longer used by this container
|
||||
removeImage($oldImageID);
|
||||
}
|
||||
// remove old orphan image since it's no longer used by this container
|
||||
if ($oldImageID && $oldImageID != $newImageID) removeImage($oldImageID, $echo);
|
||||
}
|
||||
echo '<div style="text-align:center"><button type="button" onclick="window.parent.jQuery(\'#iframe-popup\').dialog(\'close\')">Done</button></div><br>';
|
||||
goto END;
|
||||
@@ -381,11 +380,11 @@ button[type=button]{margin:0 20px 0 0}
|
||||
}
|
||||
return newConfig.prop('outerHTML');
|
||||
}
|
||||
|
||||
|
||||
function escapeQuote(string) {
|
||||
return string.replace(new RegExp('"','g'),""");
|
||||
}
|
||||
|
||||
|
||||
function makeAllocations(container,current) {
|
||||
var html = [];
|
||||
for (var i=0,ct; ct=container[i]; i++) {
|
||||
@@ -556,20 +555,19 @@ button[type=button]{margin:0 20px 0 0}
|
||||
}
|
||||
|
||||
function prepareConfig(form) {
|
||||
var types = [], values = [], targets = [];
|
||||
var types = [], values = [], targets = [], vcpu = [];
|
||||
if ($('select[name="contNetwork"]').val()=='host') {
|
||||
$(form).find('input[name="confType[]"]').each(function(){types.push($(this).val());});
|
||||
$(form).find('input[name="confValue[]"]').each(function(){values.push($(this));});
|
||||
$(form).find('input[name="confTarget[]"]').each(function(){targets.push($(this));});
|
||||
for (var i=0; i < types.length; i++) if (types[i]=='Port') $(targets[i]).val($(values[i]).val());
|
||||
}
|
||||
var vcpu = [];
|
||||
$(form).find('input[id^="box"]').each(function(){if ($(this).prop('checked')) vcpu.push($('#'+$(this).prop('id').replace('box','cpu')).text());});
|
||||
form.contCPUset.value = vcpu.join(',');
|
||||
}
|
||||
|
||||
function makeName(type) {
|
||||
i = $("#configLocation input[name^='confType'][value='"+type+"']").length+1;
|
||||
var i = $("#configLocation input[name^='confType'][value='"+type+"']").length+1;
|
||||
return "Host "+type.replace('Variable','Key')+" "+i;
|
||||
}
|
||||
|
||||
|
||||
@@ -845,7 +845,7 @@ class DockerClient {
|
||||
$c['CPUset'] = $info['HostConfig']['CpusetCpus'];
|
||||
$c['BaseImage'] = $ct['Labels']['BASEIMAGE'] ?? false;
|
||||
$c['Ports'] = [];
|
||||
if ($id) $c['NetworkMode'] = $net.str_replace('/',':',DockerUtil::docker("inspect --format='{{.Name}}' $id")?:'/???');
|
||||
if ($id) $c['NetworkMode'] = $net.str_replace('/',':',DockerUtil::ctMap($id)?:'/???');
|
||||
if ($driver[$c['NetworkMode']]=='bridge') {
|
||||
$ports = &$info['HostConfig']['PortBindings'];
|
||||
$nat = true;
|
||||
@@ -969,5 +969,8 @@ class DockerUtil {
|
||||
exec('cat /sys/devices/system/cpu/*/topology/thread_siblings_list|sort -nu', $cpus);
|
||||
return $cpus;
|
||||
}
|
||||
public static function ctMap($ct, $type='Name') {
|
||||
return static::docker("inspect --format='{{.$type}}' $ct");
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -51,7 +51,7 @@ foreach ($containers as $ct) {
|
||||
$running = $info['running'] ? 1 : 0;
|
||||
$paused = $info['paused'] ? 1 : 0;
|
||||
$is_autostart = $info['autostart'] ? 'true':'false';
|
||||
$updateStatus = ($info['updated']=='true'||$info['updated']=='undef') && strpos($ct['NetworkMode'],':???')===false ? 'true':'false';
|
||||
$updateStatus = strpos($ct['NetworkMode'],':???')!==false ? 2 : ($info['updated']=='true' ? 1 : ($info['updated']=='undef' ? 3 : 0));
|
||||
$template = $info['template'];
|
||||
$shell = $info['shell'];
|
||||
$webGui = html_entity_decode($info['url']);
|
||||
@@ -59,11 +59,11 @@ foreach ($containers as $ct) {
|
||||
$project = html_entity_decode($info['Project']);
|
||||
$registry = html_entity_decode($info['registry']);
|
||||
$menu[] = sprintf("addDockerContainerContext('%s','%s','%s',%s,%s,%s,%s,'%s','%s','%s','%s','%s','%s');", addslashes($name), addslashes($ct['ImageId']), addslashes($template), $running, $paused, $updateStatus, $is_autostart, addslashes($webGui), $shell, $id, addslashes($support), addslashes($project),addslashes($registry));
|
||||
$docker[] = "docker.push({name:'$name',id:'$id',state:$running,pause:$paused,update:'$updateStatus'});";
|
||||
$docker[] = "docker.push({name:'$name',id:'$id',state:$running,pause:$paused,update:$updateStatus});";
|
||||
$shape = $running ? ($paused ? 'pause' : 'play') : 'square';
|
||||
$status = $running ? ($paused ? 'paused' : 'started') : 'stopped';
|
||||
$color = $status=='started' ? 'green-text' : ($status=='paused' ? 'orange-text' : 'red-text');
|
||||
$update = $updateStatus=='false' ? 'blue-text' : '';
|
||||
$update = $updateStatus==0 ? 'blue-text' : '';
|
||||
$icon = $info['icon'] ?: '/plugins/dynamix.docker.manager/images/question.png';
|
||||
$image = substr($icon,-4)=='.png' ? "<img src='$icon?".filemtime("$docroot{$info['icon']}")."' class='img'>" : (substr($icon,0,5)=='icon-' ? "<i class='$icon img'></i>" : "<i class='fa fa-$icon img'></i>");
|
||||
$wait = var_split($autostart[array_search($name,$names)],1);
|
||||
@@ -97,15 +97,23 @@ foreach ($containers as $ct) {
|
||||
echo htmlspecialchars($author);
|
||||
}
|
||||
echo "</span></td><td class='updatecolumn'>";
|
||||
if ($updateStatus=='false') {
|
||||
switch ($updateStatus) {
|
||||
case 0:
|
||||
echo "<div class='advanced'><span class='orange-text' style='white-space:nowrap;'><i class='fa fa-flash fa-fw'></i> update ready</span></div>";
|
||||
echo "<a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> apply update</span></a>";
|
||||
} elseif ($updateStatus=='true') {
|
||||
break;
|
||||
case 1:
|
||||
echo "<span class='green-text' style='white-space:nowrap;'><i class='fa fa-check fa-fw'></i> up-to-date</span>";
|
||||
echo "<div class='advanced'><a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> force update</span></a></div>";
|
||||
} else {
|
||||
break;
|
||||
case 2:
|
||||
echo "<div class='advanced'><span class='orange-text' style='white-space:nowrap;'><i class='fa fa-flash fa-fw'></i> rebuild ready</span></div>";
|
||||
echo "<a class='exec'><span style='white-space:nowrap;'><i class='fa fa-recycle fa-fw'></i> rebuilding</span></a>";
|
||||
break;
|
||||
default:
|
||||
echo "<span class='orange-text' style='white-space:nowrap;'><i class='fa fa-warning'></i> not available</span>";
|
||||
echo "<div class='advanced'><a class='exec' onclick=\"updateContainer('".addslashes(htmlspecialchars($name))."');\"><span style='white-space:nowrap;'><i class='fa fa-cloud-download fa-fw'></i> force update</span></a></div>";
|
||||
break;
|
||||
}
|
||||
echo "<div class='advanced'><i class='fa fa-info-circle fa-fw'></i> $version</div></td>";
|
||||
echo "<td>{$ct['NetworkMode']}</td>";
|
||||
|
||||
@@ -7,8 +7,8 @@ function addDockerContainerContext(container, image, template, started, paused,
|
||||
opts.push({text:'Console', icon:'fa-terminal', action:function(e){e.preventDefault(); dockerTerminal(container,shell);}});
|
||||
opts.push({divider:true});
|
||||
}
|
||||
if (!update) {
|
||||
opts.push({text:'Update', icon:'fa-arrow-down', action:function(e){e.preventDefault(); execUpContainer(container);}});
|
||||
if (update==0) {
|
||||
opts.push({text:'Update', icon:'fa-cloud-download', action:function(e){e.preventDefault(); execUpContainer(container);}});
|
||||
opts.push({divider:true});
|
||||
}
|
||||
if (started) {
|
||||
@@ -58,8 +58,8 @@ function dockerTerminal(container,shell) {
|
||||
}
|
||||
function execUpContainer(container) {
|
||||
var title = 'Updating the container: '+container;
|
||||
var address = '/plugins/dynamix.docker.manager/include/CreateDocker.php?updateContainer=true&ct[]='+encodeURIComponent(container);
|
||||
popupWithIframe(title, address, true, 'loadlist');
|
||||
var cmd = '/plugins/dynamix.docker.manager/include/CreateDocker.php?updateContainer=true&ct[]='+encodeURIComponent(container);
|
||||
popupWithIframe(title, cmd, true, 'loadlist');
|
||||
}
|
||||
function popupWithIframe(title, cmd, reload, func) {
|
||||
pauseEvents();
|
||||
@@ -126,6 +126,7 @@ function rmContainer(container, image, id) {
|
||||
showLoaderOnConfirm:true
|
||||
},function(c){
|
||||
if (!c) {setTimeout(loadlist,0); return;}
|
||||
$('div.spinner').show('slow');
|
||||
if ($('#removeimagechk').prop('checked')) {
|
||||
eventControl({action:'remove_all', container:id, name:container, image:image},'loadlist');
|
||||
} else {
|
||||
@@ -145,6 +146,7 @@ function rmImage(image, imageName) {
|
||||
showLoaderOnConfirm:true
|
||||
},function(c){
|
||||
if (!c) {setTimeout(loadlist,0); return;}
|
||||
$('div.spinner').show('slow');
|
||||
eventControl({action:'remove_image', image:image},'loadlist');
|
||||
});
|
||||
}
|
||||
@@ -190,12 +192,18 @@ function checkAll() {
|
||||
}
|
||||
function updateAll() {
|
||||
$('input[type=button]').prop('disabled',true);
|
||||
$('#docker_list').append("<div class='spinner fixed'></div>");
|
||||
$('div.spinner').html(unraid_logo).show('slow');
|
||||
var list = '';
|
||||
for (var i=0,ct; ct=docker[i]; i++) if (ct.update=='false') list += '&ct[]='+encodeURI(ct.name);
|
||||
var address = '/plugins/dynamix.docker.manager/include/CreateDocker.php?updateContainer=true'+list;
|
||||
popupWithIframe('Updating all Containers', address, true, 'loadlist');
|
||||
$('div.spinner').show('slow');
|
||||
var ct = '';
|
||||
for (var i=0,d; d=docker[i]; i++) if (d.update==0) ct += '&ct[]='+encodeURI(d.name);
|
||||
var cmd = '/plugins/dynamix.docker.manager/include/CreateDocker.php?updateContainer=true'+ct;
|
||||
popupWithIframe('Updating all Containers', cmd, true, 'loadlist');
|
||||
}
|
||||
function rebuildAll() {
|
||||
$('input[type=button]').prop('disabled',true);
|
||||
$('div.spinner').show('slow');
|
||||
var ct = [];
|
||||
for (var i=0,d; d=docker[i]; i++) if (d.update==2) ct.push(encodeURI(d.name));
|
||||
$.get('/plugins/dynamix.docker.manager/include/CreateDocker.php',{updateContainer:true,mute:true,ct},function(){loadlist();});
|
||||
}
|
||||
function containerLogs(container, id) {
|
||||
var height = 600;
|
||||
|
||||
Reference in New Issue
Block a user