2019-03-21 05:46:49 +00:00
import _ from 'lodash-es' ;
2021-06-14 06:59:07 +00:00
2020-04-14 23:46:34 +00:00
import { PorImageRegistryModel } from 'Docker/models/porImageRegistry' ;
2021-06-14 06:59:07 +00:00
2021-11-03 10:41:59 +00:00
import * as envVarsUtils from '@/portainer/helpers/env-vars' ;
2022-02-14 13:51:43 +00:00
import { FeatureId } from 'Portainer/feature-flags/enums' ;
2019-03-21 05:46:49 +00:00
import { ContainerCapabilities , ContainerCapability } from '../../../models/containerCapabilities' ;
import { AccessControlFormData } from '../../../../portainer/components/accessControlForm/porAccessControlFormModel' ;
import { ContainerDetailsViewModel } from '../../../models/container' ;
2021-11-29 22:01:09 +00:00
import './createcontainer.css' ;
2020-04-10 21:54:53 +00:00
angular . module ( 'portainer.docker' ) . controller ( 'CreateContainerController' , [
'$q' ,
'$scope' ,
'$async' ,
'$state' ,
'$timeout' ,
'$transition$' ,
'$filter' ,
'Container' ,
'ContainerHelper' ,
'Image' ,
'ImageHelper' ,
'Volume' ,
'NetworkService' ,
'ResourceControlService' ,
'Authentication' ,
'Notifications' ,
'ContainerService' ,
'ImageService' ,
'FormValidator' ,
'ModalService' ,
'RegistryService' ,
'SystemService' ,
'PluginService' ,
'HttpRequestHelper' ,
2021-02-09 08:09:06 +00:00
'endpoint' ,
2020-04-10 21:54:53 +00:00
function (
$q ,
$scope ,
$async ,
$state ,
$timeout ,
$transition$ ,
$filter ,
Container ,
ContainerHelper ,
Image ,
ImageHelper ,
Volume ,
NetworkService ,
ResourceControlService ,
Authentication ,
Notifications ,
ContainerService ,
ImageService ,
FormValidator ,
ModalService ,
RegistryService ,
SystemService ,
PluginService ,
2021-02-09 08:09:06 +00:00
HttpRequestHelper ,
endpoint
2020-04-10 21:54:53 +00:00
) {
$scope . create = create ;
2021-11-29 22:01:09 +00:00
$scope . update = update ;
2021-03-24 18:27:32 +00:00
$scope . endpoint = endpoint ;
2022-02-14 13:51:43 +00:00
$scope . containerWebhookFeature = FeatureId . CONTAINER _WEBHOOK ;
2020-04-10 21:54:53 +00:00
$scope . formValues = {
alwaysPull : true ,
2022-07-17 23:02:14 +00:00
GPU : {
enabled : false ,
useSpecific : false ,
selectedGPUs : [ ] ,
capabilities : [ 'compute' , 'utility' ] ,
} ,
2020-04-10 21:54:53 +00:00
Console : 'none' ,
Volumes : [ ] ,
2020-08-20 01:02:25 +00:00
NetworkContainer : null ,
2020-04-10 21:54:53 +00:00
Labels : [ ] ,
ExtraHosts : [ ] ,
MacAddress : '' ,
IPv4 : '' ,
IPv6 : '' ,
DnsPrimary : '' ,
DnsSecondary : '' ,
AccessControlData : new AccessControlFormData ( ) ,
CpuLimit : 0 ,
MemoryLimit : 0 ,
MemoryReservation : 0 ,
2020-08-07 02:10:40 +00:00
CmdMode : 'default' ,
EntrypointMode : 'default' ,
2021-06-14 06:59:07 +00:00
Env : [ ] ,
2020-04-10 21:54:53 +00:00
NodeName : null ,
capabilities : [ ] ,
2021-04-12 07:40:45 +00:00
Sysctls : [ ] ,
2020-04-10 21:54:53 +00:00
LogDriverName : '' ,
LogDriverOpts : [ ] ,
RegistryModel : new PorImageRegistryModel ( ) ,
} ;
$scope . extraNetworks = { } ;
$scope . state = {
formValidationError : '' ,
actionInProgress : false ,
2020-08-07 02:10:40 +00:00
mode : '' ,
2021-03-24 18:27:32 +00:00
pullImageValidity : true ,
2021-11-29 22:01:09 +00:00
settingUnlimitedResources : false ,
2020-04-10 21:54:53 +00:00
} ;
2022-07-20 00:39:44 +00:00
$scope . onAlwaysPullChange = onAlwaysPullChange ;
$scope . handlePublishAllPortsChange = handlePublishAllPortsChange ;
$scope . handleAutoRemoveChange = handleAutoRemoveChange ;
$scope . handlePrivilegedChange = handlePrivilegedChange ;
$scope . handleInitChange = handleInitChange ;
function onAlwaysPullChange ( checked ) {
return $scope . $evalAsync ( ( ) => {
$scope . formValues . alwaysPull = checked ;
} ) ;
}
function handlePublishAllPortsChange ( checked ) {
return $scope . $evalAsync ( ( ) => {
$scope . config . HostConfig . PublishAllPorts = checked ;
} ) ;
}
function handleAutoRemoveChange ( checked ) {
return $scope . $evalAsync ( ( ) => {
$scope . config . HostConfig . AutoRemove = checked ;
} ) ;
}
function handlePrivilegedChange ( checked ) {
return $scope . $evalAsync ( ( ) => {
$scope . config . HostConfig . Privileged = checked ;
} ) ;
}
function handleInitChange ( checked ) {
return $scope . $evalAsync ( ( ) => {
$scope . config . HostConfig . Init = checked ;
} ) ;
}
2021-06-14 06:59:07 +00:00
$scope . handleEnvVarChange = handleEnvVarChange ;
function handleEnvVarChange ( value ) {
$scope . formValues . Env = value ;
}
2020-04-10 21:54:53 +00:00
$scope . refreshSlider = function ( ) {
$timeout ( function ( ) {
$scope . $broadcast ( 'rzSliderForceRender' ) ;
} ) ;
} ;
2019-03-21 05:46:49 +00:00
2020-08-07 02:10:40 +00:00
$scope . onImageNameChange = function ( ) {
$scope . formValues . CmdMode = 'default' ;
$scope . formValues . EntrypointMode = 'default' ;
} ;
2021-03-24 18:27:32 +00:00
$scope . setPullImageValidity = setPullImageValidity ;
function setPullImageValidity ( validity ) {
if ( ! validity ) {
$scope . formValues . alwaysPull = false ;
}
$scope . state . pullImageValidity = validity ;
}
2020-04-10 21:54:53 +00:00
$scope . config = {
Image : '' ,
Env : [ ] ,
Cmd : '' ,
MacAddress : '' ,
ExposedPorts : { } ,
2020-08-07 02:10:40 +00:00
Entrypoint : '' ,
2020-04-10 21:54:53 +00:00
HostConfig : {
RestartPolicy : {
Name : 'no' ,
} ,
PortBindings : [ ] ,
PublishAllPorts : false ,
Binds : [ ] ,
AutoRemove : false ,
NetworkMode : 'bridge' ,
Privileged : false ,
2020-04-15 01:09:42 +00:00
Init : false ,
2020-08-20 01:02:25 +00:00
Runtime : null ,
2020-04-10 21:54:53 +00:00
ExtraHosts : [ ] ,
Devices : [ ] ,
2022-07-17 23:02:14 +00:00
DeviceRequests : [ ] ,
2020-04-10 21:54:53 +00:00
CapAdd : [ ] ,
CapDrop : [ ] ,
2021-04-12 07:40:45 +00:00
Sysctls : { } ,
2016-07-06 00:19:09 +00:00
} ,
2020-04-10 21:54:53 +00:00
NetworkingConfig : {
EndpointsConfig : { } ,
} ,
Labels : { } ,
} ;
2020-01-24 14:49:28 +00:00
2020-04-10 21:54:53 +00:00
$scope . addVolume = function ( ) {
$scope . formValues . Volumes . push ( { name : '' , containerPath : '' , readOnly : false , type : 'volume' } ) ;
2017-04-25 20:32:27 +00:00
} ;
2020-01-24 14:49:28 +00:00
2020-04-10 21:54:53 +00:00
$scope . removeVolume = function ( index ) {
$scope . formValues . Volumes . splice ( index , 1 ) ;
} ;
2017-04-25 20:32:27 +00:00
2020-04-10 21:54:53 +00:00
$scope . addPortBinding = function ( ) {
$scope . config . HostConfig . PortBindings . push ( { hostPort : '' , containerPort : '' , protocol : 'tcp' } ) ;
} ;
$scope . removePortBinding = function ( index ) {
$scope . config . HostConfig . PortBindings . splice ( index , 1 ) ;
} ;
$scope . addLabel = function ( ) {
$scope . formValues . Labels . push ( { name : '' , value : '' } ) ;
} ;
$scope . removeLabel = function ( index ) {
$scope . formValues . Labels . splice ( index , 1 ) ;
} ;
$scope . addExtraHost = function ( ) {
$scope . formValues . ExtraHosts . push ( { value : '' } ) ;
} ;
$scope . removeExtraHost = function ( index ) {
$scope . formValues . ExtraHosts . splice ( index , 1 ) ;
} ;
$scope . addDevice = function ( ) {
$scope . config . HostConfig . Devices . push ( { pathOnHost : '' , pathInContainer : '' } ) ;
} ;
$scope . removeDevice = function ( index ) {
$scope . config . HostConfig . Devices . splice ( index , 1 ) ;
} ;
2022-07-17 23:02:14 +00:00
$scope . onGpuChange = function ( values ) {
return $async ( async ( ) => {
$scope . formValues . GPU = values ;
} ) ;
} ;
2021-04-12 07:40:45 +00:00
$scope . addSysctl = function ( ) {
$scope . formValues . Sysctls . push ( { name : '' , value : '' } ) ;
} ;
$scope . removeSysctl = function ( index ) {
$scope . formValues . Sysctls . splice ( index , 1 ) ;
} ;
2020-04-10 21:54:53 +00:00
$scope . addLogDriverOpt = function ( ) {
$scope . formValues . LogDriverOpts . push ( { name : '' , value : '' } ) ;
} ;
$scope . removeLogDriverOpt = function ( index ) {
$scope . formValues . LogDriverOpts . splice ( index , 1 ) ;
} ;
$scope . fromContainerMultipleNetworks = false ;
function prepareImageConfig ( config ) {
const imageConfig = ImageHelper . createImageConfigForContainer ( $scope . formValues . RegistryModel ) ;
config . Image = imageConfig . fromImage ;
2020-01-24 14:49:28 +00:00
}
2020-04-10 21:54:53 +00:00
function preparePortBindings ( config ) {
const bindings = ContainerHelper . preparePortBindings ( config . HostConfig . PortBindings ) ;
2020-07-26 21:28:33 +00:00
config . ExposedPorts = { } ;
2020-04-10 21:54:53 +00:00
_ . forEach ( bindings , ( _ , key ) => ( config . ExposedPorts [ key ] = { } ) ) ;
config . HostConfig . PortBindings = bindings ;
2020-01-24 14:49:28 +00:00
}
2020-04-10 21:54:53 +00:00
function prepareConsole ( config ) {
var value = $scope . formValues . Console ;
var openStdin = true ;
var tty = true ;
if ( value === 'tty' ) {
openStdin = false ;
} else if ( value === 'interactive' ) {
tty = false ;
} else if ( value === 'none' ) {
openStdin = false ;
tty = false ;
2017-02-15 21:48:40 +00:00
}
2020-04-10 21:54:53 +00:00
config . OpenStdin = openStdin ;
config . Tty = tty ;
}
2016-11-16 01:52:05 +00:00
2020-08-07 02:10:40 +00:00
function prepareCmd ( config ) {
if ( _ . isEmpty ( config . Cmd ) || $scope . formValues . CmdMode == 'default' ) {
delete config . Cmd ;
} else {
config . Cmd = ContainerHelper . commandStringToArray ( config . Cmd ) ;
}
}
function prepareEntrypoint ( config ) {
if ( $scope . formValues . EntrypointMode == 'default' || ( _ . isEmpty ( config . Cmd ) && _ . isEmpty ( config . Entrypoint ) ) ) {
config . Entrypoint = null ;
}
}
2020-04-10 21:54:53 +00:00
function prepareEnvironmentVariables ( config ) {
2021-06-14 06:59:07 +00:00
config . Env = envVarsUtils . convertToArrayOfStrings ( $scope . formValues . Env ) ;
2020-04-10 21:54:53 +00:00
}
function prepareVolumes ( config ) {
var binds = [ ] ;
var volumes = { } ;
$scope . formValues . Volumes . forEach ( function ( volume ) {
var name = volume . name ;
var containerPath = volume . containerPath ;
if ( name && containerPath ) {
var bind = name + ':' + containerPath ;
volumes [ containerPath ] = { } ;
if ( volume . readOnly ) {
bind += ':ro' ;
}
binds . push ( bind ) ;
2019-11-25 00:25:30 +00:00
}
2020-04-10 21:54:53 +00:00
} ) ;
config . HostConfig . Binds = binds ;
config . Volumes = volumes ;
}
function prepareNetworkConfig ( config ) {
var mode = config . HostConfig . NetworkMode ;
var container = $scope . formValues . NetworkContainer ;
var containerName = container ;
if ( container && typeof container === 'object' ) {
containerName = $filter ( 'trimcontainername' ) ( container . Names [ 0 ] ) ;
}
var networkMode = mode ;
if ( containerName ) {
networkMode += ':' + containerName ;
config . Hostname = '' ;
}
config . HostConfig . NetworkMode = networkMode ;
config . MacAddress = $scope . formValues . MacAddress ;
config . NetworkingConfig . EndpointsConfig [ networkMode ] = {
IPAMConfig : {
IPv4Address : $scope . formValues . IPv4 ,
IPv6Address : $scope . formValues . IPv6 ,
} ,
} ;
if ( networkMode && _ . get ( $scope . config . NetworkingConfig . EndpointsConfig [ networkMode ] , 'Aliases' ) ) {
var aliases = $scope . config . NetworkingConfig . EndpointsConfig [ networkMode ] . Aliases ;
config . NetworkingConfig . EndpointsConfig [ networkMode ] . Aliases = _ . filter ( aliases , ( o ) => {
return ! _ . startsWith ( $scope . fromContainer . Id , o ) ;
} ) ;
2016-12-25 20:33:14 +00:00
}
2017-05-23 18:56:10 +00:00
2020-04-10 21:54:53 +00:00
var dnsServers = [ ] ;
if ( $scope . formValues . DnsPrimary ) {
dnsServers . push ( $scope . formValues . DnsPrimary ) ;
}
if ( $scope . formValues . DnsSecondary ) {
dnsServers . push ( $scope . formValues . DnsSecondary ) ;
}
config . HostConfig . Dns = dnsServers ;
2020-08-07 02:10:08 +00:00
config . HostConfig . ExtraHosts = _ . map (
_ . filter ( $scope . formValues . ExtraHosts , ( v ) => v . value ) ,
'value'
) ;
2020-04-10 21:54:53 +00:00
}
function prepareLabels ( config ) {
var labels = { } ;
$scope . formValues . Labels . forEach ( function ( label ) {
if ( label . name ) {
if ( label . value ) {
labels [ label . name ] = label . value ;
} else {
labels [ label . name ] = '' ;
}
2017-04-16 07:57:47 +00:00
}
2020-04-10 21:54:53 +00:00
} ) ;
config . Labels = labels ;
2017-10-04 06:39:59 +00:00
}
2020-04-10 21:54:53 +00:00
function prepareDevices ( config ) {
var path = [ ] ;
config . HostConfig . Devices . forEach ( function ( p ) {
if ( p . pathOnHost ) {
if ( p . pathInContainer === '' ) {
p . pathInContainer = p . pathOnHost ;
}
path . push ( { PathOnHost : p . pathOnHost , PathInContainer : p . pathInContainer , CgroupPermissions : 'rwm' } ) ;
}
} ) ;
config . HostConfig . Devices = path ;
2017-10-04 06:39:59 +00:00
}
2020-04-10 21:54:53 +00:00
2021-04-12 07:40:45 +00:00
function prepareSysctls ( config ) {
var sysctls = { } ;
$scope . formValues . Sysctls . forEach ( function ( sysctl ) {
if ( sysctl . name && sysctl . value ) {
sysctls [ sysctl . name ] = sysctl . value ;
}
} ) ;
config . HostConfig . Sysctls = sysctls ;
}
2020-04-10 21:54:53 +00:00
function prepareResources ( config ) {
// Memory Limit - Round to 0.125
2020-08-03 23:14:59 +00:00
if ( $scope . formValues . MemoryLimit >= 0 ) {
var memoryLimit = ( Math . round ( $scope . formValues . MemoryLimit * 8 ) / 8 ) . toFixed ( 3 ) ;
memoryLimit *= 1024 * 1024 ;
2020-04-10 21:54:53 +00:00
config . HostConfig . Memory = memoryLimit ;
}
2020-08-03 23:14:59 +00:00
2020-04-10 21:54:53 +00:00
// Memory Resevation - Round to 0.125
2020-08-03 23:14:59 +00:00
if ( $scope . formValues . MemoryReservation >= 0 ) {
var memoryReservation = ( Math . round ( $scope . formValues . MemoryReservation * 8 ) / 8 ) . toFixed ( 3 ) ;
memoryReservation *= 1024 * 1024 ;
2020-04-10 21:54:53 +00:00
config . HostConfig . MemoryReservation = memoryReservation ;
}
2020-08-03 23:14:59 +00:00
2020-04-10 21:54:53 +00:00
// CPU Limit
2020-08-03 23:14:59 +00:00
if ( $scope . formValues . CpuLimit >= 0 ) {
2020-04-10 21:54:53 +00:00
config . HostConfig . NanoCpus = $scope . formValues . CpuLimit * 1000000000 ;
}
2017-10-04 06:39:59 +00:00
}
2020-04-10 21:54:53 +00:00
function prepareLogDriver ( config ) {
var logOpts = { } ;
if ( $scope . formValues . LogDriverName ) {
config . HostConfig . LogConfig = { Type : $scope . formValues . LogDriverName } ;
if ( $scope . formValues . LogDriverName !== 'none' ) {
$scope . formValues . LogDriverOpts . forEach ( function ( opt ) {
if ( opt . name ) {
logOpts [ opt . name ] = opt . value ;
}
} ) ;
if ( Object . keys ( logOpts ) . length !== 0 && logOpts . constructor === Object ) {
config . HostConfig . LogConfig . Config = logOpts ;
2018-10-28 03:00:56 +00:00
}
}
}
}
2020-04-10 21:54:53 +00:00
function prepareCapabilities ( config ) {
var allowed = $scope . formValues . capabilities . filter ( function ( item ) {
return item . allowed === true ;
} ) ;
var notAllowed = $scope . formValues . capabilities . filter ( function ( item ) {
return item . allowed === false ;
} ) ;
var getCapName = function ( item ) {
return item . capability ;
} ;
config . HostConfig . CapAdd = allowed . map ( getCapName ) ;
config . HostConfig . CapDrop = notAllowed . map ( getCapName ) ;
}
2022-07-17 23:02:14 +00:00
function prepareGPUOptions ( config ) {
const driver = 'nvidia' ;
const gpuOptions = $scope . formValues . GPU ;
const existingDeviceRequest = _ . find ( $scope . config . HostConfig . DeviceRequests , function ( o ) {
return o . Driver === driver || o . Capabilities [ 0 ] [ 0 ] === 'gpu' ;
} ) ;
if ( existingDeviceRequest ) {
_ . pullAllBy ( config . HostConfig . DeviceRequests , [ existingDeviceRequest ] , 'Driver' ) ;
}
if ( ! gpuOptions . enabled ) {
return ;
}
const deviceRequest = existingDeviceRequest || {
Driver : driver ,
Count : - 1 ,
DeviceIDs : [ ] , // must be empty if Count != 0 https://github.com/moby/moby/blob/master/daemon/nvidia_linux.go#L50
Capabilities : [ ] , // array of ORed arrays of ANDed capabilites = [ [c1 AND c2] OR [c1 AND c3] ] : https://github.com/moby/moby/blob/master/api/types/container/host_config.go#L272
// Options: { property1: "string", property2: "string" }, // seems to never be evaluated/used in docker API ?
} ;
deviceRequest . DeviceIDs = gpuOptions . selectedGPUs ;
deviceRequest . Count = 0 ;
deviceRequest . Capabilities = [ gpuOptions . capabilities ] ;
config . HostConfig . DeviceRequests . push ( deviceRequest ) ;
}
2020-04-10 21:54:53 +00:00
function prepareConfiguration ( ) {
var config = angular . copy ( $scope . config ) ;
2020-08-07 02:10:40 +00:00
prepareCmd ( config ) ;
prepareEntrypoint ( config ) ;
2020-04-10 21:54:53 +00:00
prepareNetworkConfig ( config ) ;
prepareImageConfig ( config ) ;
preparePortBindings ( config ) ;
prepareConsole ( config ) ;
prepareEnvironmentVariables ( config ) ;
prepareVolumes ( config ) ;
prepareLabels ( config ) ;
prepareDevices ( config ) ;
prepareResources ( config ) ;
prepareLogDriver ( config ) ;
prepareCapabilities ( config ) ;
2021-04-12 07:40:45 +00:00
prepareSysctls ( config ) ;
2022-07-17 23:02:14 +00:00
prepareGPUOptions ( config ) ;
2020-04-10 21:54:53 +00:00
return config ;
}
function loadFromContainerCmd ( ) {
if ( $scope . config . Cmd ) {
$scope . config . Cmd = ContainerHelper . commandArrayToString ( $scope . config . Cmd ) ;
2020-08-07 02:10:40 +00:00
$scope . formValues . CmdMode = 'override' ;
}
}
function loadFromContainerEntrypoint ( ) {
if ( _ . has ( $scope . config , 'Entrypoint' ) ) {
if ( $scope . config . Entrypoint == null ) {
$scope . config . Entrypoint = '' ;
}
$scope . formValues . EntrypointMode = 'override' ;
2020-04-10 21:54:53 +00:00
}
}
function loadFromContainerPortBindings ( ) {
const bindings = ContainerHelper . sortAndCombinePorts ( $scope . config . HostConfig . PortBindings ) ;
$scope . config . HostConfig . PortBindings = bindings ;
2017-08-13 10:17:41 +00:00
}
2020-04-10 21:54:53 +00:00
function loadFromContainerVolumes ( d ) {
for ( var v in d . Mounts ) {
if ( { } . hasOwnProperty . call ( d . Mounts , v ) ) {
var mount = d . Mounts [ v ] ;
var volume = {
type : mount . Type ,
name : mount . Name || mount . Source ,
containerPath : mount . Destination ,
readOnly : mount . RW === false ,
} ;
$scope . formValues . Volumes . push ( volume ) ;
}
2017-08-13 10:17:41 +00:00
}
}
2020-04-10 21:54:53 +00:00
$scope . resetNetworkConfig = function ( ) {
$scope . config . NetworkingConfig = {
EndpointsConfig : { } ,
} ;
2017-11-23 15:02:40 +00:00
} ;
2020-04-10 21:54:53 +00:00
function loadFromContainerNetworkConfig ( d ) {
$scope . config . NetworkingConfig = {
EndpointsConfig : { } ,
} ;
var networkMode = d . HostConfig . NetworkMode ;
if ( networkMode === 'default' ) {
$scope . config . HostConfig . NetworkMode = 'bridge' ;
if ( ! _ . find ( $scope . availableNetworks , { Name : 'bridge' } ) ) {
$scope . config . HostConfig . NetworkMode = 'nat' ;
}
2017-08-13 10:17:41 +00:00
}
2020-04-10 21:54:53 +00:00
if ( $scope . config . HostConfig . NetworkMode . indexOf ( 'container:' ) === 0 ) {
var netContainer = $scope . config . HostConfig . NetworkMode . split ( /^container:/ ) [ 1 ] ;
$scope . config . HostConfig . NetworkMode = 'container' ;
for ( var c in $scope . runningContainers ) {
if ( $scope . runningContainers [ c ] . Id == netContainer ) {
$scope . formValues . NetworkContainer = $scope . runningContainers [ c ] ;
}
2017-08-13 10:17:41 +00:00
}
}
2020-04-10 21:54:53 +00:00
$scope . fromContainerMultipleNetworks = Object . keys ( d . NetworkSettings . Networks ) . length >= 2 ;
if ( d . NetworkSettings . Networks [ $scope . config . HostConfig . NetworkMode ] ) {
if ( d . NetworkSettings . Networks [ $scope . config . HostConfig . NetworkMode ] . IPAMConfig ) {
if ( d . NetworkSettings . Networks [ $scope . config . HostConfig . NetworkMode ] . IPAMConfig . IPv4Address ) {
$scope . formValues . IPv4 = d . NetworkSettings . Networks [ $scope . config . HostConfig . NetworkMode ] . IPAMConfig . IPv4Address ;
}
if ( d . NetworkSettings . Networks [ $scope . config . HostConfig . NetworkMode ] . IPAMConfig . IPv6Address ) {
$scope . formValues . IPv6 = d . NetworkSettings . Networks [ $scope . config . HostConfig . NetworkMode ] . IPAMConfig . IPv6Address ;
}
2017-08-13 10:17:41 +00:00
}
2020-04-10 21:54:53 +00:00
}
$scope . config . NetworkingConfig . EndpointsConfig [ $scope . config . HostConfig . NetworkMode ] = d . NetworkSettings . Networks [ $scope . config . HostConfig . NetworkMode ] ;
if ( Object . keys ( d . NetworkSettings . Networks ) . length > 1 ) {
var firstNetwork = d . NetworkSettings . Networks [ Object . keys ( d . NetworkSettings . Networks ) [ 0 ] ] ;
$scope . config . NetworkingConfig . EndpointsConfig [ $scope . config . HostConfig . NetworkMode ] = firstNetwork ;
$scope . extraNetworks = angular . copy ( d . NetworkSettings . Networks ) ;
delete $scope . extraNetworks [ Object . keys ( d . NetworkSettings . Networks ) [ 0 ] ] ;
}
$scope . formValues . MacAddress = d . Config . MacAddress ;
if ( d . HostConfig . Dns && d . HostConfig . Dns [ 0 ] ) {
$scope . formValues . DnsPrimary = d . HostConfig . Dns [ 0 ] ;
if ( d . HostConfig . Dns [ 1 ] ) {
$scope . formValues . DnsSecondary = d . HostConfig . Dns [ 1 ] ;
2017-08-13 10:17:41 +00:00
}
}
2018-08-20 18:55:12 +00:00
2020-04-10 21:54:53 +00:00
// ExtraHosts
if ( $scope . config . HostConfig . ExtraHosts ) {
var extraHosts = $scope . config . HostConfig . ExtraHosts ;
for ( var i = 0 ; i < extraHosts . length ; i ++ ) {
var host = extraHosts [ i ] ;
$scope . formValues . ExtraHosts . push ( { value : host } ) ;
}
$scope . config . HostConfig . ExtraHosts = [ ] ;
2020-02-11 14:23:56 +00:00
}
}
2017-08-13 10:17:41 +00:00
2020-04-10 21:54:53 +00:00
function loadFromContainerEnvironmentVariables ( ) {
2021-06-14 06:59:07 +00:00
$scope . formValues . Env = envVarsUtils . parseArrayOfStrings ( $scope . config . Env ) ;
2017-08-13 10:17:41 +00:00
}
2020-04-10 21:54:53 +00:00
function loadFromContainerLabels ( ) {
for ( var l in $scope . config . Labels ) {
if ( { } . hasOwnProperty . call ( $scope . config . Labels , l ) ) {
$scope . formValues . Labels . push ( { name : l , value : $scope . config . Labels [ l ] } ) ;
}
2017-08-13 10:17:41 +00:00
}
}
2020-04-10 21:54:53 +00:00
function loadFromContainerConsole ( ) {
if ( $scope . config . OpenStdin && $scope . config . Tty ) {
$scope . formValues . Console = 'both' ;
} else if ( ! $scope . config . OpenStdin && $scope . config . Tty ) {
$scope . formValues . Console = 'tty' ;
} else if ( $scope . config . OpenStdin && ! $scope . config . Tty ) {
$scope . formValues . Console = 'interactive' ;
} else if ( ! $scope . config . OpenStdin && ! $scope . config . Tty ) {
$scope . formValues . Console = 'none' ;
2017-08-13 10:17:41 +00:00
}
}
2017-10-04 06:39:59 +00:00
2020-04-10 21:54:53 +00:00
function loadFromContainerDevices ( ) {
var path = [ ] ;
for ( var dev in $scope . config . HostConfig . Devices ) {
if ( { } . hasOwnProperty . call ( $scope . config . HostConfig . Devices , dev ) ) {
var device = $scope . config . HostConfig . Devices [ dev ] ;
path . push ( { pathOnHost : device . PathOnHost , pathInContainer : device . PathInContainer } ) ;
}
}
$scope . config . HostConfig . Devices = path ;
2018-08-09 08:40:06 +00:00
}
2019-01-22 20:28:44 +00:00
2022-07-17 23:02:14 +00:00
function loadFromContainerDeviceRequests ( ) {
const deviceRequest = _ . find ( $scope . config . HostConfig . DeviceRequests , function ( o ) {
return o . Driver === 'nvidia' || o . Capabilities [ 0 ] [ 0 ] === 'gpu' ;
} ) ;
if ( deviceRequest ) {
$scope . formValues . GPU . enabled = true ;
$scope . formValues . GPU . useSpecific = deviceRequest . Count !== - 1 ;
$scope . formValues . GPU . selectedGPUs = deviceRequest . DeviceIDs || [ ] ;
if ( $scope . formValues . GPU . useSpecific ) {
$scope . formValues . GPU . selectedGPUs = deviceRequest . DeviceIDs ;
}
// we only support a single set of capabilities for now
// UI needs to be reworked in order to support OR combinations of AND capabilities
$scope . formValues . GPU . capabilities = deviceRequest . Capabilities [ 0 ] ;
$scope . formValues . GPU = { ... $scope . formValues . GPU } ;
}
}
2021-04-12 07:40:45 +00:00
function loadFromContainerSysctls ( ) {
for ( var s in $scope . config . HostConfig . Sysctls ) {
if ( { } . hasOwnProperty . call ( $scope . config . HostConfig . Sysctls , s ) ) {
$scope . formValues . Sysctls . push ( { name : s , value : $scope . config . HostConfig . Sysctls [ s ] } ) ;
}
}
}
2020-04-10 21:54:53 +00:00
function loadFromContainerImageConfig ( ) {
2021-07-14 09:15:21 +00:00
RegistryService . retrievePorRegistryModelFromRepository ( $scope . config . Image , endpoint . Id )
2020-04-10 21:54:53 +00:00
. then ( ( model ) => {
$scope . formValues . RegistryModel = model ;
} )
. catch ( function error ( err ) {
2021-10-14 12:42:10 +00:00
Notifications . error ( 'Failure' , err , 'Unable to retrieve registry' ) ;
2020-04-10 21:54:53 +00:00
} ) ;
2019-01-22 20:28:44 +00:00
}
2020-04-10 21:54:53 +00:00
function loadFromContainerResources ( d ) {
if ( d . HostConfig . NanoCpus ) {
$scope . formValues . CpuLimit = d . HostConfig . NanoCpus / 1000000000 ;
}
if ( d . HostConfig . Memory ) {
$scope . formValues . MemoryLimit = d . HostConfig . Memory / 1024 / 1024 ;
}
if ( d . HostConfig . MemoryReservation ) {
$scope . formValues . MemoryReservation = d . HostConfig . MemoryReservation / 1024 / 1024 ;
2019-01-22 20:28:44 +00:00
}
}
2020-04-10 21:54:53 +00:00
function loadFromContainerCapabilities ( d ) {
if ( d . HostConfig . CapAdd ) {
d . HostConfig . CapAdd . forEach ( function ( cap ) {
$scope . formValues . capabilities . push ( new ContainerCapability ( cap , true ) ) ;
} ) ;
}
if ( d . HostConfig . CapDrop ) {
d . HostConfig . CapDrop . forEach ( function ( cap ) {
$scope . formValues . capabilities . push ( new ContainerCapability ( cap , false ) ) ;
} ) ;
}
2017-05-23 18:56:10 +00:00
2020-04-10 21:54:53 +00:00
function hasCapability ( item ) {
return item . capability === cap . capability ;
}
2018-08-18 08:27:24 +00:00
2020-04-10 21:54:53 +00:00
var capabilities = new ContainerCapabilities ( ) ;
for ( var i = 0 ; i < capabilities . length ; i ++ ) {
var cap = capabilities [ i ] ;
if ( ! _ . find ( $scope . formValues . capabilities , hasCapability ) ) {
$scope . formValues . capabilities . push ( cap ) ;
}
}
2018-08-18 08:27:24 +00:00
2020-04-10 21:54:53 +00:00
$scope . formValues . capabilities . sort ( function ( a , b ) {
return a . capability < b . capability ? - 1 : 1 ;
} ) ;
2019-01-17 19:59:43 +00:00
}
2020-04-10 21:54:53 +00:00
function loadFromContainerSpec ( ) {
// Get container
Container . get ( { id : $transition$ . params ( ) . from } )
. $promise . then ( function success ( d ) {
var fromContainer = new ContainerDetailsViewModel ( d ) ;
if ( fromContainer . ResourceControl && fromContainer . ResourceControl . Public ) {
$scope . formValues . AccessControlData . AccessControlEnabled = false ;
2018-08-18 08:27:24 +00:00
}
2020-04-10 21:54:53 +00:00
$scope . fromContainer = fromContainer ;
2020-08-07 02:10:40 +00:00
$scope . state . mode = 'duplicate' ;
2020-04-10 21:54:53 +00:00
$scope . config = ContainerHelper . configFromContainer ( fromContainer . Model ) ;
loadFromContainerCmd ( d ) ;
2020-08-07 02:10:40 +00:00
loadFromContainerEntrypoint ( d ) ;
2020-04-10 21:54:53 +00:00
loadFromContainerLogging ( d ) ;
loadFromContainerPortBindings ( d ) ;
loadFromContainerVolumes ( d ) ;
loadFromContainerNetworkConfig ( d ) ;
loadFromContainerEnvironmentVariables ( d ) ;
loadFromContainerLabels ( d ) ;
loadFromContainerConsole ( d ) ;
loadFromContainerDevices ( d ) ;
2022-07-17 23:02:14 +00:00
loadFromContainerDeviceRequests ( d ) ;
2020-04-10 21:54:53 +00:00
loadFromContainerImageConfig ( d ) ;
loadFromContainerResources ( d ) ;
loadFromContainerCapabilities ( d ) ;
2021-04-12 07:40:45 +00:00
loadFromContainerSysctls ( d ) ;
2018-08-18 08:27:24 +00:00
} )
2020-04-10 21:54:53 +00:00
. catch ( function error ( err ) {
Notifications . error ( 'Failure' , err , 'Unable to retrieve container' ) ;
} ) ;
2018-08-18 08:27:24 +00:00
}
2017-05-23 18:56:10 +00:00
2020-04-10 21:54:53 +00:00
function loadFromContainerLogging ( config ) {
var logConfig = config . HostConfig . LogConfig ;
$scope . formValues . LogDriverName = logConfig . Type ;
$scope . formValues . LogDriverOpts = _ . map ( logConfig . Config , function ( value , name ) {
return {
name : name ,
value : value ,
} ;
} ) ;
2019-01-17 19:59:43 +00:00
}
2020-07-26 21:31:14 +00:00
async function initView ( ) {
2020-04-10 21:54:53 +00:00
var nodeName = $transition$ . params ( ) . nodeName ;
$scope . formValues . NodeName = nodeName ;
HttpRequestHelper . setPortainerAgentTargetHeader ( nodeName ) ;
2020-07-28 07:08:15 +00:00
$scope . isAdmin = Authentication . isAdmin ( ) ;
$scope . showDeviceMapping = await shouldShowDevices ( ) ;
2021-04-12 07:40:45 +00:00
$scope . showSysctls = await shouldShowSysctls ( ) ;
2020-07-28 07:08:15 +00:00
$scope . areContainerCapabilitiesEnabled = await checkIfContainerCapabilitiesEnabled ( ) ;
2020-08-11 05:41:37 +00:00
$scope . isAdminOrEndpointAdmin = Authentication . isAdmin ( ) ;
2020-07-28 07:08:15 +00:00
2020-04-10 21:54:53 +00:00
Volume . query (
{ } ,
function ( d ) {
2020-07-26 21:28:33 +00:00
$scope . availableVolumes = d . Volumes . sort ( ( vol1 , vol2 ) => {
return vol1 . Name . localeCompare ( vol2 . Name ) ;
} ) ;
2020-04-10 21:54:53 +00:00
} ,
function ( e ) {
Notifications . error ( 'Failure' , e , 'Unable to retrieve volumes' ) ;
}
) ;
var provider = $scope . applicationState . endpoint . mode . provider ;
var apiVersion = $scope . applicationState . endpoint . apiVersion ;
NetworkService . networks ( provider === 'DOCKER_STANDALONE' || provider === 'DOCKER_SWARM_MODE' , false , provider === 'DOCKER_SWARM_MODE' && apiVersion >= 1.25 )
2020-07-27 21:52:54 +00:00
. then ( function success ( networks ) {
2020-04-10 21:54:53 +00:00
networks . push ( { Name : 'container' } ) ;
2020-07-27 21:52:54 +00:00
$scope . availableNetworks = networks . sort ( ( a , b ) => a . Name . localeCompare ( b . Name ) ) ;
2020-04-10 21:54:53 +00:00
if ( _ . find ( networks , { Name : 'nat' } ) ) {
$scope . config . HostConfig . NetworkMode = 'nat' ;
}
2019-01-17 19:59:43 +00:00
} )
2020-04-10 21:54:53 +00:00
. catch ( function error ( err ) {
Notifications . error ( 'Failure' , err , 'Unable to retrieve networks' ) ;
2019-01-17 19:59:43 +00:00
} ) ;
2020-04-10 21:54:53 +00:00
Container . query (
{ } ,
function ( d ) {
var containers = d ;
$scope . runningContainers = containers ;
2022-07-17 23:02:14 +00:00
$scope . gpuUseAll = $scope . endpoint . Snapshots [ 0 ] . GpuUseAll ;
$scope . gpuUseList = $scope . endpoint . Snapshots [ 0 ] . GpuUseList ;
2020-04-10 21:54:53 +00:00
if ( $transition$ . params ( ) . from ) {
loadFromContainerSpec ( ) ;
} else {
$scope . fromContainer = { } ;
2020-07-28 07:08:15 +00:00
$scope . formValues . capabilities = $scope . areContainerCapabilitiesEnabled ? new ContainerCapabilities ( ) : [ ] ;
2020-04-10 21:54:53 +00:00
}
} ,
function ( e ) {
Notifications . error ( 'Failure' , e , 'Unable to retrieve running containers' ) ;
2019-01-17 19:59:43 +00:00
}
2020-04-10 21:54:53 +00:00
) ;
SystemService . info ( )
. then ( function success ( data ) {
$scope . availableRuntimes = data . Runtimes ? Object . keys ( data . Runtimes ) : [ ] ;
$scope . state . sliderMaxCpu = 32 ;
if ( data . NCPU ) {
$scope . state . sliderMaxCpu = data . NCPU ;
}
$scope . state . sliderMaxMemory = 32768 ;
if ( data . MemTotal ) {
$scope . state . sliderMaxMemory = Math . floor ( data . MemTotal / 1000 / 1000 ) ;
}
} )
. catch ( function error ( err ) {
Notifications . error ( 'Failure' , err , 'Unable to retrieve engine details' ) ;
} ) ;
2021-02-09 08:09:06 +00:00
$scope . allowBindMounts = $scope . isAdminOrEndpointAdmin || endpoint . SecuritySettings . allowBindMountsForRegularUsers ;
$scope . allowPrivilegedMode = endpoint . SecuritySettings . allowPrivilegedModeForRegularUsers ;
2020-04-10 21:54:53 +00:00
PluginService . loggingPlugins ( apiVersion < 1.25 ) . then ( function success ( loggingDrivers ) {
$scope . availableLoggingDrivers = loggingDrivers ;
2019-01-17 19:59:43 +00:00
} ) ;
}
2020-04-10 21:54:53 +00:00
function validateForm ( accessControlData , isAdmin ) {
$scope . state . formValidationError = '' ;
var error = '' ;
error = FormValidator . validateAccessControl ( accessControlData , isAdmin ) ;
if ( error ) {
$scope . state . formValidationError = error ;
return false ;
2019-01-17 19:59:43 +00:00
}
2020-04-10 21:54:53 +00:00
return true ;
2018-08-18 08:27:24 +00:00
}
2021-11-29 22:01:09 +00:00
$scope . handleResourceChange = handleResourceChange ;
function handleResourceChange ( ) {
$scope . state . settingUnlimitedResources = false ;
if (
( $scope . config . HostConfig . Memory > 0 && $scope . formValues . MemoryLimit === 0 ) ||
( $scope . config . HostConfig . MemoryReservation > 0 && $scope . formValues . MemoryReservation === 0 ) ||
( $scope . config . HostConfig . NanoCpus > 0 && $scope . formValues . CpuLimit === 0 )
) {
$scope . state . settingUnlimitedResources = true ;
}
}
async function updateLimits ( config ) {
try {
if ( $scope . state . settingUnlimitedResources ) {
create ( ) ;
} else {
await ContainerService . updateLimits ( $transition$ . params ( ) . from , config ) ;
$scope . config = config ;
Notifications . success ( 'Limits updated' ) ;
}
} catch ( err ) {
Notifications . error ( 'Failure' , err , 'Update Limits fail' ) ;
}
}
async function update ( ) {
$scope . state . actionInProgress = true ;
var config = angular . copy ( $scope . config ) ;
prepareResources ( config ) ;
await updateLimits ( config ) ;
$scope . state . actionInProgress = false ;
}
2020-04-10 21:54:53 +00:00
function create ( ) {
var oldContainer = null ;
HttpRequestHelper . setPortainerAgentTargetHeader ( $scope . formValues . NodeName ) ;
return findCurrentContainer ( ) . then ( setOldContainer ) . then ( confirmCreateContainer ) . then ( startCreationProcess ) . catch ( notifyOnError ) . finally ( final ) ;
function final ( ) {
$scope . state . actionInProgress = false ;
2018-08-18 08:27:24 +00:00
}
2020-04-10 21:54:53 +00:00
function setOldContainer ( container ) {
oldContainer = container ;
return container ;
}
function findCurrentContainer ( ) {
return Container . query ( { all : 1 , filters : { name : [ '^/' + $scope . config . name + '$' ] } } )
. $promise . then ( function onQuerySuccess ( containers ) {
if ( ! containers . length ) {
return ;
}
return containers [ 0 ] ;
} )
. catch ( notifyOnError ) ;
2018-08-18 08:27:24 +00:00
2020-04-10 21:54:53 +00:00
function notifyOnError ( err ) {
Notifications . error ( 'Failure' , err , 'Unable to retrieve containers' ) ;
}
}
function startCreationProcess ( confirmed ) {
if ( ! confirmed ) {
return $q . when ( ) ;
}
if ( ! validateAccessControl ( ) ) {
return $q . when ( ) ;
}
$scope . state . actionInProgress = true ;
return pullImageIfNeeded ( )
. then ( stopAndRenameContainer )
. then ( createNewContainer )
. then ( applyResourceControl )
. then ( connectToExtraNetworks )
. then ( removeOldContainer )
. then ( onSuccess )
. catch ( onCreationProcessFail ) ;
}
function onCreationProcessFail ( error ) {
2018-08-18 08:27:24 +00:00
var deferred = $q . defer ( ) ;
2020-04-10 21:54:53 +00:00
removeNewContainer ( )
. then ( restoreOldContainerName )
. then ( function ( ) {
deferred . reject ( error ) ;
} )
. catch ( function ( restoreError ) {
deferred . reject ( restoreError ) ;
} ) ;
return deferred . promise ;
}
2018-08-18 08:27:24 +00:00
2020-04-10 21:54:53 +00:00
function removeNewContainer ( ) {
return findCurrentContainer ( ) . then ( function onContainerLoaded ( container ) {
if ( container && ( ! oldContainer || container . Id !== oldContainer . Id ) ) {
return ContainerService . remove ( container , true ) ;
2018-08-18 08:27:24 +00:00
}
} ) ;
2020-04-10 21:54:53 +00:00
}
2018-08-18 08:27:24 +00:00
2020-04-10 21:54:53 +00:00
function restoreOldContainerName ( ) {
if ( ! oldContainer ) {
return ;
}
return ContainerService . renameContainer ( oldContainer . Id , oldContainer . Names [ 0 ] . substring ( 1 ) ) ;
2018-08-18 08:27:24 +00:00
}
2020-04-10 21:54:53 +00:00
function confirmCreateContainer ( container ) {
if ( ! container ) {
return $q . when ( true ) ;
}
return showConfirmationModal ( ) ;
function showConfirmationModal ( ) {
var deferred = $q . defer ( ) ;
ModalService . confirm ( {
title : 'Are you sure ?' ,
message : 'A container with the same name already exists. Portainer can automatically remove it and re-create one. Do you want to replace it?' ,
buttons : {
confirm : {
label : 'Replace' ,
className : 'btn-danger' ,
} ,
} ,
callback : function onConfirm ( confirmed ) {
deferred . resolve ( confirmed ) ;
} ,
} ) ;
return deferred . promise ;
}
2018-08-18 08:27:24 +00:00
}
2020-04-10 21:54:53 +00:00
function stopAndRenameContainer ( ) {
if ( ! oldContainer ) {
return $q . when ( ) ;
}
return stopContainerIfNeeded ( oldContainer ) . then ( renameContainer ) ;
2018-08-18 08:27:24 +00:00
}
2020-04-10 21:54:53 +00:00
function stopContainerIfNeeded ( oldContainer ) {
if ( oldContainer . State !== 'running' ) {
return $q . when ( ) ;
}
return ContainerService . stopContainer ( oldContainer . Id ) ;
}
2018-08-18 08:27:24 +00:00
2020-04-10 21:54:53 +00:00
function renameContainer ( ) {
return ContainerService . renameContainer ( oldContainer . Id , oldContainer . Names [ 0 ] . substring ( 1 ) + '-old' ) ;
}
2018-08-18 08:27:24 +00:00
2020-04-10 21:54:53 +00:00
function pullImageIfNeeded ( ) {
return $q . when ( $scope . formValues . alwaysPull && ImageService . pullImage ( $scope . formValues . RegistryModel , true ) ) ;
}
2017-05-23 18:56:10 +00:00
2020-04-10 21:54:53 +00:00
function createNewContainer ( ) {
return $async ( async ( ) => {
const config = prepareConfiguration ( ) ;
return await ContainerService . createAndStartContainer ( config ) ;
} ) ;
}
2019-11-12 23:41:42 +00:00
2020-04-10 21:54:53 +00:00
function applyResourceControl ( newContainer ) {
const userId = Authentication . getUserDetails ( ) . ID ;
const resourceControl = newContainer . Portainer . ResourceControl ;
const containerId = newContainer . Id ;
const accessControlData = $scope . formValues . AccessControlData ;
2018-08-18 08:27:24 +00:00
2020-04-10 21:54:53 +00:00
return ResourceControlService . applyResourceControl ( userId , accessControlData , resourceControl ) . then ( function onApplyResourceControlSuccess ( ) {
return containerId ;
} ) ;
2018-08-18 08:27:24 +00:00
}
2020-04-10 21:54:53 +00:00
function connectToExtraNetworks ( newContainerId ) {
if ( ! $scope . extraNetworks ) {
return $q . when ( ) ;
2019-11-28 20:21:23 +00:00
}
2020-04-10 21:54:53 +00:00
var connectionPromises = _ . forOwn ( $scope . extraNetworks , function ( network , networkName ) {
if ( _ . has ( network , 'Aliases' ) ) {
var aliases = _ . filter ( network . Aliases , ( o ) => {
return ! _ . startsWith ( $scope . fromContainer . Id , o ) ;
} ) ;
}
return NetworkService . connectContainer ( networkName , newContainerId , aliases ) ;
2019-11-27 20:35:14 +00:00
} ) ;
2018-08-18 08:27:24 +00:00
2020-04-10 21:54:53 +00:00
return $q . all ( connectionPromises ) ;
}
function removeOldContainer ( ) {
var deferred = $q . defer ( ) ;
2018-08-18 08:27:24 +00:00
2020-04-10 21:54:53 +00:00
if ( ! oldContainer ) {
deferred . resolve ( ) ;
return ;
}
2018-08-18 08:27:24 +00:00
2020-04-10 21:54:53 +00:00
ContainerService . remove ( oldContainer , true ) . then ( notifyOnRemoval ) . catch ( notifyOnRemoveError ) ;
2018-08-18 08:27:24 +00:00
2020-04-10 21:54:53 +00:00
return deferred . promise ;
2018-08-18 08:27:24 +00:00
2020-04-10 21:54:53 +00:00
function notifyOnRemoval ( ) {
Notifications . success ( 'Container Removed' , oldContainer . Id ) ;
deferred . resolve ( ) ;
}
2018-08-18 08:27:24 +00:00
2020-04-10 21:54:53 +00:00
function notifyOnRemoveError ( err ) {
deferred . reject ( { msg : 'Unable to remove container' , err : err } ) ;
}
2018-08-18 08:27:24 +00:00
}
2020-04-10 21:54:53 +00:00
function notifyOnError ( err ) {
Notifications . error ( 'Failure' , err , 'Unable to create container' ) ;
2018-08-18 08:27:24 +00:00
}
2020-04-10 21:54:53 +00:00
function validateAccessControl ( ) {
var accessControlData = $scope . formValues . AccessControlData ;
return validateForm ( accessControlData , $scope . isAdmin ) ;
}
2018-08-18 08:27:24 +00:00
2020-04-10 21:54:53 +00:00
function onSuccess ( ) {
Notifications . success ( 'Container successfully created' ) ;
$state . go ( 'docker.containers' , { } , { reload : true } ) ;
}
2018-08-18 08:27:24 +00:00
}
2017-05-23 18:56:10 +00:00
2020-07-28 07:08:15 +00:00
async function shouldShowDevices ( ) {
2021-02-09 08:09:06 +00:00
return endpoint . SecuritySettings . allowDeviceMappingForRegularUsers || Authentication . isAdmin ( ) ;
2020-07-28 07:08:15 +00:00
}
2021-04-12 07:40:45 +00:00
async function shouldShowSysctls ( ) {
2021-05-12 00:29:35 +00:00
return endpoint . SecuritySettings . allowSysctlSettingForRegularUsers || Authentication . isAdmin ( ) ;
2021-04-12 07:40:45 +00:00
}
2020-07-28 07:08:15 +00:00
async function checkIfContainerCapabilitiesEnabled ( ) {
2021-02-09 08:09:06 +00:00
return endpoint . SecuritySettings . allowContainerCapabilitiesForRegularUsers || Authentication . isAdmin ( ) ;
2020-07-29 09:10:46 +00:00
}
2020-04-10 21:54:53 +00:00
initView ( ) ;
} ,
] ) ;