2019-03-21 07:46:49 +02:00
import _ from 'lodash-es' ;
2021-06-14 18:59:07 +12:00
2023-05-31 10:08:41 +07:00
import * as envVarsUtils from '@/react/components/form-components/EnvironmentVariablesFieldset/utils' ;
2020-04-15 02:46:34 +03:00
import { PorImageRegistryModel } from 'Docker/models/porImageRegistry' ;
2021-06-14 18:59:07 +12:00
2023-02-14 13:49:41 +05:30
import { confirmDestructive } from '@@/modals/confirm' ;
2022-11-13 10:10:18 +02:00
import { FeatureId } from '@/react/portainer/feature-flags/enums' ;
2023-02-14 13:49:41 +05:30
import { buildConfirmButton } from '@@/modals/utils' ;
2019-03-21 07:46:49 +02:00
import { ContainerCapabilities , ContainerCapability } from '../../../models/containerCapabilities' ;
import { AccessControlFormData } from '../../../../portainer/components/accessControlForm/porAccessControlFormModel' ;
import { ContainerDetailsViewModel } from '../../../models/container' ;
2021-11-30 11:01:09 +13:00
import './createcontainer.css' ;
2019-10-15 18:13:57 +09:00
angular . module ( 'portainer.docker' ) . controller ( 'CreateContainerController' , [
2020-04-11 00:54:53 +03:00
'$q' ,
2019-10-15 18:13:57 +09:00
'$scope' ,
'$async' ,
'$state' ,
'$timeout' ,
'$transition$' ,
'$filter' ,
2023-03-03 14:47:10 +13:00
'$analytics' ,
2019-10-15 18:13:57 +09:00
'Container' ,
'ContainerHelper' ,
2020-04-11 00:54:53 +03:00
'Image' ,
2019-10-15 18:13:57 +09:00
'ImageHelper' ,
'Volume' ,
'NetworkService' ,
'ResourceControlService' ,
'Authentication' ,
'Notifications' ,
'ContainerService' ,
'ImageService' ,
'FormValidator' ,
'RegistryService' ,
'SystemService' ,
2023-03-03 14:47:10 +13:00
'SettingsService' ,
2019-10-15 18:13:57 +09:00
'PluginService' ,
'HttpRequestHelper' ,
2021-02-09 10:09:06 +02:00
'endpoint' ,
2017-10-04 08:39:59 +02:00
function (
2020-04-11 00:54:53 +03:00
$q ,
$scope ,
$async ,
$state ,
2019-10-15 18:13:57 +09:00
$timeout ,
$transition$ ,
2020-04-11 00:54:53 +03:00
$filter ,
2023-03-03 14:47:10 +13:00
$analytics ,
2019-10-15 18:13:57 +09:00
Container ,
ContainerHelper ,
2020-04-11 00:54:53 +03:00
Image ,
2019-10-15 18:13:57 +09:00
ImageHelper ,
2020-04-11 00:54:53 +03:00
Volume ,
2019-10-15 18:13:57 +09:00
NetworkService ,
ResourceControlService ,
Authentication ,
Notifications ,
ContainerService ,
ImageService ,
FormValidator ,
RegistryService ,
SystemService ,
2023-03-03 14:47:10 +13:00
SettingsService ,
2019-10-15 18:13:57 +09:00
PluginService ,
2021-02-09 10:09:06 +02:00
HttpRequestHelper ,
endpoint
2020-04-11 00:54:53 +03:00
) {
2018-08-18 09:27:24 +01:00
$scope . create = create ;
2021-11-30 11:01:09 +13:00
$scope . update = update ;
2021-03-24 20:27:32 +02:00
$scope . endpoint = endpoint ;
2022-02-14 21:51:43 +08:00
$scope . containerWebhookFeature = FeatureId . CONTAINER _WEBHOOK ;
2016-07-06 12:19:09 +12:00
$scope . formValues = {
2016-10-20 16:43:09 +13:00
alwaysPull : true ,
2022-07-18 11:02:14 +12:00
GPU : {
enabled : false ,
useSpecific : false ,
2022-08-11 09:05:27 +12:00
selectedGPUs : [ 'all' ] ,
2022-07-18 11:02:14 +12:00
capabilities : [ 'compute' , 'utility' ] ,
} ,
2016-07-06 12:19:09 +12:00
Console : 'none' ,
2016-10-27 19:55:44 +13:00
Volumes : [ ] ,
2020-08-20 04:02:25 +03:00
NetworkContainer : null ,
2017-02-15 19:48:40 -02:00
Labels : [ ] ,
2017-04-16 09:57:47 +02:00
ExtraHosts : [ ] ,
2018-01-06 10:53:03 +00:00
MacAddress : '' ,
2017-04-25 21:32:27 +01:00
IPv4 : '' ,
2017-07-12 09:51:51 +02:00
IPv6 : '' ,
2020-01-24 17:49:28 +03:00
DnsPrimary : '' ,
DnsSecondary : '' ,
2017-10-04 08:39:59 +02:00
AccessControlData : new AccessControlFormData ( ) ,
CpuLimit : 0 ,
MemoryLimit : 0 ,
2018-05-06 09:15:57 +02:00
MemoryReservation : 0 ,
2022-08-30 09:22:27 +12:00
ShmSize : 64 ,
2020-08-07 14:10:40 +12:00
CmdMode : 'default' ,
EntrypointMode : 'default' ,
2021-06-14 18:59:07 +12:00
Env : [ ] ,
2018-08-09 10:40:06 +02:00
NodeName : null ,
2018-10-28 04:00:56 +01:00
capabilities : [ ] ,
2021-04-12 09:40:45 +02:00
Sysctls : [ ] ,
2018-10-28 04:00:56 +01:00
LogDriverName : '' ,
2019-11-27 23:36:39 +01:00
LogDriverOpts : [ ] ,
RegistryModel : new PorImageRegistryModel ( ) ,
2020-04-11 00:54:53 +03:00
} ;
2018-06-02 08:44:18 +02:00
$scope . extraNetworks = { } ;
2020-04-11 00:54:53 +03:00
2017-05-23 20:56:10 +02:00
$scope . state = {
2017-11-12 20:27:28 +01:00
formValidationError : '' ,
2017-11-12 22:39:12 +01:00
actionInProgress : false ,
2020-08-07 14:10:40 +12:00
mode : '' ,
2021-03-24 20:27:32 +02:00
pullImageValidity : true ,
2021-11-30 11:01:09 +13:00
settingUnlimitedResources : false ,
2020-04-11 00:54:53 +03:00
} ;
2022-07-20 08:39:44 +08: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 18:59:07 +12:00
$scope . handleEnvVarChange = handleEnvVarChange ;
function handleEnvVarChange ( value ) {
$scope . formValues . Env = value ;
}
2017-10-04 08:39:59 +02:00
$scope . refreshSlider = function ( ) {
$timeout ( function ( ) {
$scope . $broadcast ( 'rzSliderForceRender' ) ;
2020-04-11 00:54:53 +03:00
} ) ;
} ;
2019-03-21 07:46:49 +02:00
2020-08-07 14:10:40 +12:00
$scope . onImageNameChange = function ( ) {
$scope . formValues . CmdMode = 'default' ;
$scope . formValues . EntrypointMode = 'default' ;
} ;
2021-03-24 20:27:32 +02:00
$scope . setPullImageValidity = setPullImageValidity ;
function setPullImageValidity ( validity ) {
if ( ! validity ) {
$scope . formValues . alwaysPull = false ;
}
$scope . state . pullImageValidity = validity ;
}
2019-10-15 18:13:57 +09:00
$scope . config = {
Image : '' ,
2017-04-25 21:32:27 +01:00
Env : [ ] ,
2020-04-11 00:54:53 +03:00
Cmd : '' ,
2018-01-06 10:53:03 +00:00
MacAddress : '' ,
2017-04-25 21:32:27 +01:00
ExposedPorts : { } ,
2020-08-07 14:10:40 +12:00
Entrypoint : '' ,
2020-01-24 17:49:28 +03:00
HostConfig : {
2017-10-04 08:39:59 +02:00
RestartPolicy : {
2018-08-09 10:40:06 +02:00
Name : 'no' ,
2020-04-11 00:54:53 +03:00
} ,
2018-10-28 04:00:56 +01:00
PortBindings : [ ] ,
PublishAllPorts : false ,
2019-11-27 23:36:39 +01:00
Binds : [ ] ,
2017-11-12 22:39:12 +01:00
AutoRemove : false ,
2017-10-04 08:39:59 +02:00
NetworkMode : 'bridge' ,
2016-10-27 19:55:44 +13:00
Privileged : false ,
2020-04-15 03:09:42 +02:00
Init : false ,
2020-08-20 04:02:25 +03:00
Runtime : null ,
2016-08-17 19:03:36 +12:00
ExtraHosts : [ ] ,
2016-07-06 12:19:09 +12:00
Devices : [ ] ,
2022-07-18 11:02:14 +12:00
DeviceRequests : [ ] ,
2018-08-09 10:40:06 +02:00
CapAdd : [ ] ,
2016-07-06 12:19:09 +12:00
CapDrop : [ ] ,
2021-04-12 09:40:45 +02:00
Sysctls : { } ,
2016-07-06 12:19:09 +12:00
} ,
2017-04-25 21:32:27 +01:00
NetworkingConfig : {
2016-07-06 12:19:09 +12:00
EndpointsConfig : { } ,
2018-10-28 04:00:56 +01:00
} ,
2016-07-06 12:19:09 +12:00
Labels : { } ,
} ;
2020-01-24 17:49:28 +03:00
2017-04-25 21:32:27 +01:00
$scope . addVolume = function ( ) {
$scope . formValues . Volumes . push ( { name : '' , containerPath : '' , readOnly : false , type : 'volume' } ) ;
} ;
2020-01-24 17:49:28 +03:00
2019-11-29 09:21:23 +13:00
$scope . removeVolume = function ( index ) {
$scope . formValues . Volumes . splice ( index , 1 ) ;
} ;
2017-04-25 21:32:27 +01:00
2016-07-06 12:19:09 +12:00
$scope . addPortBinding = function ( ) {
2020-01-24 17:49:28 +03:00
$scope . config . HostConfig . PortBindings . push ( { hostPort : '' , containerPort : '' , protocol : 'tcp' } ) ;
2020-04-11 00:54:53 +03:00
} ;
2016-07-06 12:19:09 +12:00
$scope . removePortBinding = function ( index ) {
$scope . config . HostConfig . PortBindings . splice ( index , 1 ) ;
2020-04-11 00:54:53 +03:00
} ;
2016-12-25 21:33:14 +01:00
$scope . addLabel = function ( ) {
$scope . formValues . Labels . push ( { name : '' , value : '' } ) ;
2020-04-11 00:54:53 +03:00
} ;
2016-12-25 21:33:14 +01:00
$scope . removeLabel = function ( index ) {
2020-01-24 17:49:28 +03:00
$scope . formValues . Labels . splice ( index , 1 ) ;
2020-04-11 00:54:53 +03:00
} ;
2017-02-15 19:48:40 -02:00
$scope . addExtraHost = function ( ) {
$scope . formValues . ExtraHosts . push ( { value : '' } ) ;
2020-04-11 00:54:53 +03:00
} ;
2017-02-15 19:48:40 -02:00
$scope . removeExtraHost = function ( index ) {
$scope . formValues . ExtraHosts . splice ( index , 1 ) ;
2020-04-11 00:54:53 +03:00
} ;
2017-04-16 09:57:47 +02:00
$scope . addDevice = function ( ) {
2020-01-24 17:49:28 +03:00
$scope . config . HostConfig . Devices . push ( { pathOnHost : '' , pathInContainer : '' } ) ;
2020-04-11 00:54:53 +03:00
} ;
2017-04-16 09:57:47 +02:00
$scope . removeDevice = function ( index ) {
2020-01-24 17:49:28 +03:00
$scope . config . HostConfig . Devices . splice ( index , 1 ) ;
2020-04-11 00:54:53 +03:00
} ;
2022-07-18 11:02:14 +12:00
$scope . onGpuChange = function ( values ) {
return $async ( async ( ) => {
$scope . formValues . GPU = values ;
} ) ;
} ;
2021-04-12 09:40:45 +02:00
$scope . addSysctl = function ( ) {
$scope . formValues . Sysctls . push ( { name : '' , value : '' } ) ;
} ;
$scope . removeSysctl = function ( index ) {
$scope . formValues . Sysctls . splice ( index , 1 ) ;
} ;
2020-01-24 17:49:28 +03:00
$scope . addLogDriverOpt = function ( ) {
$scope . formValues . LogDriverOpts . push ( { name : '' , value : '' } ) ;
2020-04-11 00:54:53 +03:00
} ;
2018-10-28 04:00:56 +01:00
$scope . removeLogDriverOpt = function ( index ) {
$scope . formValues . LogDriverOpts . splice ( index , 1 ) ;
2020-04-11 00:54:53 +03:00
} ;
2020-01-24 17:49:28 +03:00
$scope . fromContainerMultipleNetworks = false ;
2020-04-11 00:54:53 +03:00
2020-01-24 17:49:28 +03:00
function prepareImageConfig ( config ) {
const imageConfig = ImageHelper . createImageConfigForContainer ( $scope . formValues . RegistryModel ) ;
2019-11-27 23:36:39 +01:00
config . Image = imageConfig . fromImage ;
2020-01-24 17:49:28 +03:00
}
2020-04-11 00:54:53 +03:00
2020-01-24 17:49:28 +03:00
function preparePortBindings ( config ) {
const bindings = ContainerHelper . preparePortBindings ( config . HostConfig . PortBindings ) ;
2020-07-27 02:58:33 +05:30
config . ExposedPorts = { } ;
2020-01-24 17:49:28 +03:00
_ . forEach ( bindings , ( _ , key ) => ( config . ExposedPorts [ key ] = { } ) ) ;
2016-07-06 12:19:09 +12:00
config . HostConfig . PortBindings = bindings ;
2020-01-24 17:49:28 +03:00
}
2017-02-15 19:48:40 -02:00
function prepareConsole ( config ) {
var value = $scope . formValues . Console ;
var openStdin = true ;
2016-07-06 12:19:09 +12:00
var tty = true ;
2017-02-15 19:48:40 -02:00
if ( value === 'tty' ) {
openStdin = false ;
} else if ( value === 'interactive' ) {
2016-07-06 12:19:09 +12:00
tty = false ;
2017-02-15 19:48:40 -02:00
} else if ( value === 'none' ) {
openStdin = false ;
2016-07-06 12:19:09 +12:00
tty = false ;
2017-02-15 19:48:40 -02:00
}
config . OpenStdin = openStdin ;
2016-07-06 12:19:09 +12:00
config . Tty = tty ;
2016-11-16 01:52:05 +00:00
}
2020-08-07 14:10:40 +12: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 ;
}
}
2016-12-25 21:33:14 +01:00
function prepareEnvironmentVariables ( config ) {
2021-06-14 18:59:07 +12:00
config . Env = envVarsUtils . convertToArrayOfStrings ( $scope . formValues . Env ) ;
2020-04-11 00:54:53 +03:00
}
2019-11-24 19:25:30 -05:00
function prepareVolumes ( config ) {
2016-07-06 12:19:09 +12:00
var binds = [ ] ;
var volumes = { } ;
2020-04-11 00:54:53 +03:00
2016-07-06 12:19:09 +12:00
$scope . formValues . Volumes . forEach ( function ( volume ) {
2019-11-24 19:25:30 -05:00
var name = volume . name ;
2016-07-06 12:19:09 +12:00
var containerPath = volume . containerPath ;
if ( name && containerPath ) {
2019-11-24 19:25:30 -05:00
var bind = name + ':' + containerPath ;
volumes [ containerPath ] = { } ;
2016-07-06 12:19:09 +12:00
if ( volume . readOnly ) {
2019-11-24 19:25:30 -05:00
bind += ':ro' ;
2020-04-11 00:54:53 +03:00
}
2016-07-06 12:19:09 +12:00
binds . push ( bind ) ;
2019-11-24 19:25:30 -05:00
}
2020-04-11 00:54:53 +03:00
} ) ;
2016-07-06 12:19:09 +12:00
config . HostConfig . Binds = binds ;
config . Volumes = volumes ;
2020-04-11 00:54:53 +03:00
}
2016-11-16 01:52:05 +00:00
function prepareNetworkConfig ( config ) {
var mode = config . HostConfig . NetworkMode ;
var container = $scope . formValues . NetworkContainer ;
var containerName = container ;
if ( container && typeof container === 'object' ) {
2023-02-09 17:18:19 +13:00
containerName = container . Names [ 0 ] ;
2020-04-11 00:54:53 +03:00
}
2016-11-16 01:52:05 +00:00
var networkMode = mode ;
if ( containerName ) {
networkMode += ':' + containerName ;
2017-08-13 12:17:41 +02:00
config . Hostname = '' ;
2020-04-11 00:54:53 +03:00
}
2016-11-16 01:52:05 +00:00
config . HostConfig . NetworkMode = networkMode ;
2018-01-06 10:53:03 +00:00
config . MacAddress = $scope . formValues . MacAddress ;
2020-04-11 00:54:53 +03:00
2019-11-29 09:21:23 +13:00
config . NetworkingConfig . EndpointsConfig [ networkMode ] = {
2017-04-25 21:32:27 +01:00
IPAMConfig : {
IPv4Address : $scope . formValues . IPv4 ,
IPv6Address : $scope . formValues . IPv6 ,
2020-04-11 00:54:53 +03:00
} ,
} ;
2019-11-29 09:21:23 +13:00
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 ) ;
2020-04-11 00:54:53 +03:00
} ) ;
2016-12-25 21:33:14 +01:00
}
2017-05-23 20:56:10 +02:00
2017-04-16 09:57:47 +02:00
var dnsServers = [ ] ;
2020-02-12 03:23:56 +13:00
if ( $scope . formValues . DnsPrimary ) {
dnsServers . push ( $scope . formValues . DnsPrimary ) ;
2020-04-11 00:54:53 +03:00
}
2020-01-24 17:49:28 +03:00
if ( $scope . formValues . DnsSecondary ) {
2020-02-12 03:23:56 +13:00
dnsServers . push ( $scope . formValues . DnsSecondary ) ;
2020-04-11 00:54:53 +03:00
}
2017-04-16 09:57:47 +02:00
config . HostConfig . Dns = dnsServers ;
2020-04-11 00:54:53 +03:00
2020-08-07 14:10:08 +12:00
config . HostConfig . ExtraHosts = _ . map (
_ . filter ( $scope . formValues . ExtraHosts , ( v ) => v . value ) ,
'value'
) ;
2020-04-11 00:54:53 +03:00
}
2017-04-16 09:57:47 +02:00
function prepareLabels ( config ) {
var labels = { } ;
2018-10-28 04:00:56 +01:00
$scope . formValues . Labels . forEach ( function ( label ) {
2019-11-24 19:25:30 -05:00
if ( label . name ) {
if ( label . value ) {
labels [ label . name ] = label . value ;
2020-04-11 00:54:53 +03:00
} else {
2019-11-24 19:25:30 -05:00
labels [ label . name ] = '' ;
2020-04-11 00:54:53 +03:00
}
2017-04-16 09:57:47 +02:00
}
} ) ;
2017-05-23 20:56:10 +02:00
config . Labels = labels ;
2017-10-04 08:39:59 +02:00
}
2020-04-11 00:54:53 +03:00
2017-10-04 08:39:59 +02:00
function prepareDevices ( config ) {
var path = [ ] ;
config . HostConfig . Devices . forEach ( function ( p ) {
2017-04-16 09:57:47 +02:00
if ( p . pathOnHost ) {
if ( p . pathInContainer === '' ) {
2017-05-23 20:56:10 +02:00
p . pathInContainer = p . pathOnHost ;
2020-04-11 00:54:53 +03:00
}
2017-10-04 08:39:59 +02:00
path . push ( { PathOnHost : p . pathOnHost , PathInContainer : p . pathInContainer , CgroupPermissions : 'rwm' } ) ;
2020-04-11 00:54:53 +03:00
}
2017-10-04 08:39:59 +02:00
} ) ;
config . HostConfig . Devices = path ;
}
2020-04-11 00:54:53 +03:00
2021-04-12 09:40:45 +02: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 ;
}
2017-10-04 08:39:59 +02:00
function prepareResources ( config ) {
2022-08-30 09:22:27 +12:00
// Shared Memory Size - Round to 0.125
if ( $scope . formValues . ShmSize >= 0 ) {
var shmSize = ( Math . round ( $scope . formValues . ShmSize * 8 ) / 8 ) . toFixed ( 3 ) ;
shmSize *= 1024 * 1024 ;
config . HostConfig . ShmSize = shmSize ;
}
2017-10-04 08:39:59 +02:00
// Memory Limit - Round to 0.125
2020-08-04 11:14:59 +12:00
if ( $scope . formValues . MemoryLimit >= 0 ) {
var memoryLimit = ( Math . round ( $scope . formValues . MemoryLimit * 8 ) / 8 ) . toFixed ( 3 ) ;
memoryLimit *= 1024 * 1024 ;
2017-10-04 08:39:59 +02:00
config . HostConfig . Memory = memoryLimit ;
2020-04-11 00:54:53 +03:00
}
2020-08-04 11:14:59 +12:00
2017-10-04 08:39:59 +02:00
// Memory Resevation - Round to 0.125
2020-08-04 11:14:59 +12:00
if ( $scope . formValues . MemoryReservation >= 0 ) {
var memoryReservation = ( Math . round ( $scope . formValues . MemoryReservation * 8 ) / 8 ) . toFixed ( 3 ) ;
memoryReservation *= 1024 * 1024 ;
2017-10-04 08:39:59 +02:00
config . HostConfig . MemoryReservation = memoryReservation ;
2020-04-11 00:54:53 +03:00
}
2020-08-04 11:14:59 +12:00
2017-10-04 08:39:59 +02:00
// CPU Limit
2020-08-04 11:14:59 +12:00
if ( $scope . formValues . CpuLimit >= 0 ) {
2017-10-04 08:39:59 +02:00
config . HostConfig . NanoCpus = $scope . formValues . CpuLimit * 1000000000 ;
2020-04-11 00:54:53 +03:00
}
2017-10-04 08:39:59 +02:00
}
2020-04-11 00:54:53 +03:00
2018-10-28 04:00:56 +01: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 ;
2020-04-11 00:54:53 +03:00
}
} ) ;
2018-10-28 04:00:56 +01:00
if ( Object . keys ( logOpts ) . length !== 0 && logOpts . constructor === Object ) {
config . HostConfig . LogConfig . Config = logOpts ;
}
}
}
}
2020-04-11 00:54:53 +03:00
2018-08-09 10:40:06 +02: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 ;
} ) ;
2020-04-11 00:54:53 +03:00
2018-08-09 10:40:06 +02:00
var getCapName = function ( item ) {
return item . capability ;
} ;
config . HostConfig . CapAdd = allowed . map ( getCapName ) ;
config . HostConfig . CapDrop = notAllowed . map ( getCapName ) ;
}
2020-04-11 00:54:53 +03:00
2022-07-18 11:02:14 +12:00
function prepareGPUOptions ( config ) {
const driver = 'nvidia' ;
const gpuOptions = $scope . formValues . GPU ;
2022-08-11 09:05:27 +12:00
const existingDeviceRequest = _ . find ( $scope . config . HostConfig . DeviceRequests , { Driver : driver } ) ;
2022-07-18 11:02:14 +12:00
if ( existingDeviceRequest ) {
_ . pullAllBy ( config . HostConfig . DeviceRequests , [ existingDeviceRequest ] , 'Driver' ) ;
}
if ( ! gpuOptions . enabled ) {
return ;
}
2022-08-11 09:05:27 +12:00
const deviceRequest = {
2022-07-18 11:02:14 +12:00
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 ?
} ;
2022-08-11 09:05:27 +12:00
if ( gpuOptions . useSpecific ) {
deviceRequest . DeviceIDs = gpuOptions . selectedGPUs ;
deviceRequest . Count = 0 ;
}
2022-07-18 11:02:14 +12:00
deviceRequest . Capabilities = [ gpuOptions . capabilities ] ;
2023-05-24 09:21:21 +12:00
if ( config . HostConfig . DeviceRequests ) {
config . HostConfig . DeviceRequests . push ( deviceRequest ) ;
} else {
config . HostConfig . DeviceRequests = [ deviceRequest ] ;
}
2022-07-18 11:02:14 +12:00
}
2016-07-06 12:19:09 +12:00
function prepareConfiguration ( ) {
var config = angular . copy ( $scope . config ) ;
2020-08-07 14:10:40 +12:00
prepareCmd ( config ) ;
prepareEntrypoint ( config ) ;
2016-11-16 01:52:05 +00:00
prepareNetworkConfig ( config ) ;
2016-07-08 15:31:09 +12:00
prepareImageConfig ( config ) ;
2016-07-06 12:19:09 +12:00
preparePortBindings ( config ) ;
prepareConsole ( config ) ;
prepareEnvironmentVariables ( config ) ;
prepareVolumes ( config ) ;
2016-12-25 21:33:14 +01:00
prepareLabels ( config ) ;
2017-04-16 09:57:47 +02:00
prepareDevices ( config ) ;
2017-10-04 08:39:59 +02:00
prepareResources ( config ) ;
2018-10-28 04:00:56 +01:00
prepareLogDriver ( config ) ;
2018-08-09 10:40:06 +02:00
prepareCapabilities ( config ) ;
2021-04-12 09:40:45 +02:00
prepareSysctls ( config ) ;
2022-07-18 11:02:14 +12:00
prepareGPUOptions ( config ) ;
2016-07-06 12:19:09 +12:00
return config ;
}
2020-04-11 00:54:53 +03:00
2018-08-22 18:33:06 +03:00
function loadFromContainerCmd ( ) {
2017-08-13 12:17:41 +02:00
if ( $scope . config . Cmd ) {
$scope . config . Cmd = ContainerHelper . commandArrayToString ( $scope . config . Cmd ) ;
2020-08-07 14:10:40 +12: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-11 00:54:53 +03:00
}
}
2018-08-22 18:33:06 +03:00
function loadFromContainerPortBindings ( ) {
2019-10-15 18:13:57 +09:00
const bindings = ContainerHelper . sortAndCombinePorts ( $scope . config . HostConfig . PortBindings ) ;
2017-08-13 12:17:41 +02:00
$scope . config . HostConfig . PortBindings = bindings ;
}
2020-04-11 00:54:53 +03:00
2017-08-13 12:17:41 +02: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 ) ;
2020-04-11 00:54:53 +03:00
}
2017-08-13 12:17:41 +02:00
}
}
2017-11-23 16:02:40 +01:00
$scope . resetNetworkConfig = function ( ) {
$scope . config . NetworkingConfig = {
EndpointsConfig : { } ,
2020-04-11 00:54:53 +03:00
} ;
2017-11-23 16:02:40 +01:00
} ;
2017-08-13 12:17:41 +02: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' ;
2020-04-11 00:54:53 +03:00
}
2017-08-13 12:17:41 +02: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 ) {
2019-11-27 09:19:22 +13:00
if ( $scope . runningContainers [ c ] . Id == netContainer ) {
2017-08-13 12:17:41 +02:00
$scope . formValues . NetworkContainer = $scope . runningContainers [ c ] ;
2020-04-11 00:54:53 +03:00
}
2017-08-13 12:17:41 +02: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 ;
2020-04-11 00:54:53 +03:00
}
2017-08-13 12:17:41 +02:00
if ( d . NetworkSettings . Networks [ $scope . config . HostConfig . NetworkMode ] . IPAMConfig . IPv6Address ) {
$scope . formValues . IPv6 = d . NetworkSettings . Networks [ $scope . config . HostConfig . NetworkMode ] . IPAMConfig . IPv6Address ;
2020-04-11 00:54:53 +03:00
}
2017-08-13 12:17:41 +02:00
}
2020-04-11 00:54:53 +03:00
}
2017-08-13 12:17:41 +02:00
$scope . config . NetworkingConfig . EndpointsConfig [ $scope . config . HostConfig . NetworkMode ] = d . NetworkSettings . Networks [ $scope . config . HostConfig . NetworkMode ] ;
2019-10-03 04:37:34 +02:00
if ( Object . keys ( d . NetworkSettings . Networks ) . length > 1 ) {
2018-06-02 08:44:18 +02:00
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 ] ] ;
2020-04-11 00:54:53 +03:00
}
2017-08-13 12:17:41 +02:00
$scope . formValues . MacAddress = d . Config . MacAddress ;
2020-04-11 00:54:53 +03:00
2020-02-12 03:23:56 +13:00
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 12:17:41 +02:00
}
}
2018-08-20 20:55:12 +02:00
2020-02-12 03:23:56 +13:00
// ExtraHosts
if ( $scope . config . HostConfig . ExtraHosts ) {
var extraHosts = $scope . config . HostConfig . ExtraHosts ;
2018-05-06 09:15:57 +02:00
for ( var i = 0 ; i < extraHosts . length ; i ++ ) {
2020-02-12 03:23:56 +13:00
var host = extraHosts [ i ] ;
$scope . formValues . ExtraHosts . push ( { value : host } ) ;
2020-04-11 00:54:53 +03:00
}
2018-05-06 09:15:57 +02:00
$scope . config . HostConfig . ExtraHosts = [ ] ;
2020-02-12 03:23:56 +13:00
}
}
2017-08-13 12:17:41 +02:00
2018-08-22 18:33:06 +03:00
function loadFromContainerEnvironmentVariables ( ) {
2021-06-14 18:59:07 +12:00
$scope . formValues . Env = envVarsUtils . parseArrayOfStrings ( $scope . config . Env ) ;
2017-08-13 12:17:41 +02:00
}
2018-08-22 18:33:06 +03:00
function loadFromContainerLabels ( ) {
2017-08-13 12:17:41 +02:00
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 ] } ) ;
2020-04-11 00:54:53 +03:00
}
2017-08-13 12:17:41 +02:00
}
}
2018-08-22 18:33:06 +03:00
function loadFromContainerConsole ( ) {
2017-08-13 12:17:41 +02:00
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-10-04 08:39:59 +02:00
2018-08-09 10:40:06 +02: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 } ) ;
2020-04-11 00:54:53 +03:00
}
}
2018-08-09 10:40:06 +02:00
$scope . config . HostConfig . Devices = path ;
}
2019-01-22 21:28:44 +01:00
2022-07-18 11:02:14 +12: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 ;
2022-08-11 09:05:27 +12:00
} else {
$scope . formValues . GPU . selectedGPUs = [ 'all' ] ;
2022-07-18 11:02:14 +12:00
}
// 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 09:40:45 +02: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 ] } ) ;
}
}
}
2019-01-22 21:28:44 +01:00
function loadFromContainerImageConfig ( ) {
2021-07-14 11:15:21 +02:00
RegistryService . retrievePorRegistryModelFromRepository ( $scope . config . Image , endpoint . Id )
2019-11-27 23:36:39 +01:00
. then ( ( model ) => {
2019-01-22 21:28:44 +01:00
$scope . formValues . RegistryModel = model ;
2020-04-11 00:54:53 +03:00
} )
2019-01-22 21:28:44 +01:00
. catch ( function error ( err ) {
2021-10-14 09:42:10 -03:00
Notifications . error ( 'Failure' , err , 'Unable to retrieve registry' ) ;
2020-04-11 00:54:53 +03:00
} ) ;
2019-01-22 21:28:44 +01:00
}
function loadFromContainerResources ( d ) {
if ( d . HostConfig . NanoCpus ) {
$scope . formValues . CpuLimit = d . HostConfig . NanoCpus / 1000000000 ;
2020-04-11 00:54:53 +03:00
}
2017-10-04 08:39:59 +02:00
if ( d . HostConfig . Memory ) {
$scope . formValues . MemoryLimit = d . HostConfig . Memory / 1024 / 1024 ;
2020-04-11 00:54:53 +03:00
}
2017-10-04 08:39:59 +02:00
if ( d . HostConfig . MemoryReservation ) {
2019-01-22 21:28:44 +01:00
$scope . formValues . MemoryReservation = d . HostConfig . MemoryReservation / 1024 / 1024 ;
}
2022-08-30 09:22:27 +12:00
if ( d . HostConfig . ShmSize ) {
$scope . formValues . ShmSize = d . HostConfig . ShmSize / 1024 / 1024 ;
}
2019-01-22 21:28:44 +01:00
}
2017-08-13 12:17:41 +02:00
function loadFromContainerCapabilities ( d ) {
2018-08-20 21:06:30 +02:00
if ( d . HostConfig . CapAdd ) {
2019-01-16 02:34:28 +02:00
d . HostConfig . CapAdd . forEach ( function ( cap ) {
$scope . formValues . capabilities . push ( new ContainerCapability ( cap , true ) ) ;
2017-05-23 20:56:10 +02:00
} ) ;
2017-06-01 10:14:55 +02:00
}
2018-05-06 09:15:57 +02:00
if ( d . HostConfig . CapDrop ) {
2017-10-04 08:39:59 +02:00
d . HostConfig . CapDrop . forEach ( function ( cap ) {
2017-09-26 05:36:51 +02:00
$scope . formValues . capabilities . push ( new ContainerCapability ( cap , false ) ) ;
2018-10-28 04:00:56 +01:00
} ) ;
2017-05-23 20:56:10 +02:00
}
2018-08-18 09:27:24 +01:00
function hasCapability ( item ) {
return item . capability === cap . capability ;
2020-04-11 00:54:53 +03:00
}
2018-08-18 09:27:24 +01:00
var capabilities = new ContainerCapabilities ( ) ;
for ( var i = 0 ; i < capabilities . length ; i ++ ) {
2019-01-22 21:28:44 +01:00
var cap = capabilities [ i ] ;
2018-08-18 09:27:24 +01:00
if ( ! _ . find ( $scope . formValues . capabilities , hasCapability ) ) {
$scope . formValues . capabilities . push ( cap ) ;
}
2020-04-11 00:54:53 +03:00
}
2018-08-18 09:27:24 +01:00
2019-01-17 21:59:43 +02:00
$scope . formValues . capabilities . sort ( function ( a , b ) {
return a . capability < b . capability ? - 1 : 1 ;
2020-04-11 00:54:53 +03:00
} ) ;
2019-01-17 21:59:43 +02:00
}
2018-08-18 09:27:24 +01:00
function loadFromContainerSpec ( ) {
// Get container
Container . get ( { id : $transition$ . params ( ) . from } )
. $promise . then ( function success ( d ) {
var fromContainer = new ContainerDetailsViewModel ( d ) ;
2022-12-15 21:27:18 +13:00
if ( fromContainer . ResourceControl ) {
if ( fromContainer . ResourceControl . Public ) {
$scope . formValues . AccessControlData . AccessControlEnabled = false ;
}
// When the container is create by duplicate/edit, the access permission
// shouldn't be copied
fromContainer . ResourceControl . UserAccesses = [ ] ;
fromContainer . ResourceControl . TeamAccesses = [ ] ;
2018-08-18 09:27:24 +01:00
}
2022-12-15 21:27:18 +13:00
2017-08-13 12:17:41 +02:00
$scope . fromContainer = fromContainer ;
2020-08-07 14:10:40 +12:00
$scope . state . mode = 'duplicate' ;
2019-01-17 21:59:43 +02:00
$scope . config = ContainerHelper . configFromContainer ( fromContainer . Model ) ;
2017-08-13 12:17:41 +02:00
loadFromContainerCmd ( d ) ;
2020-08-07 14:10:40 +12:00
loadFromContainerEntrypoint ( d ) ;
2019-01-16 02:34:28 +02:00
loadFromContainerLogging ( d ) ;
2017-08-13 12:17:41 +02:00
loadFromContainerPortBindings ( d ) ;
loadFromContainerVolumes ( d ) ;
2019-01-17 21:59:43 +02:00
loadFromContainerNetworkConfig ( d ) ;
2018-01-06 10:53:03 +00:00
loadFromContainerEnvironmentVariables ( d ) ;
2017-08-13 12:17:41 +02:00
loadFromContainerLabels ( d ) ;
loadFromContainerConsole ( d ) ;
loadFromContainerDevices ( d ) ;
2022-07-18 11:02:14 +12:00
loadFromContainerDeviceRequests ( d ) ;
2017-08-13 12:17:41 +02:00
loadFromContainerImageConfig ( d ) ;
2019-01-17 21:59:43 +02:00
loadFromContainerResources ( d ) ;
2018-08-09 10:40:06 +02:00
loadFromContainerCapabilities ( d ) ;
2021-04-12 09:40:45 +02:00
loadFromContainerSysctls ( d ) ;
2018-08-18 09:27:24 +01:00
} )
. catch ( function error ( err ) {
Notifications . error ( 'Failure' , err , 'Unable to retrieve container' ) ;
2017-08-13 12:17:41 +02:00
} ) ;
2018-08-18 09:27:24 +01:00
}
2017-05-23 20:56:10 +02:00
2018-08-18 09:27:24 +01:00
function loadFromContainerLogging ( config ) {
var logConfig = config . HostConfig . LogConfig ;
$scope . formValues . LogDriverName = logConfig . Type ;
2017-11-12 22:39:12 +01:00
$scope . formValues . LogDriverOpts = _ . map ( logConfig . Config , function ( value , name ) {
2018-08-20 20:55:12 +02:00
return {
2018-12-20 17:37:35 +02:00
name : name ,
2019-01-16 02:34:28 +02:00
value : value ,
2020-04-11 00:54:53 +03:00
} ;
2019-01-17 21:59:43 +02:00
} ) ;
}
2020-07-27 00:31:14 +03:00
async function initView ( ) {
2019-01-17 21:59:43 +02:00
var nodeName = $transition$ . params ( ) . nodeName ;
$scope . formValues . NodeName = nodeName ;
HttpRequestHelper . setPortainerAgentTargetHeader ( nodeName ) ;
2020-04-11 00:54:53 +03:00
2020-07-28 10:08:15 +03:00
$scope . isAdmin = Authentication . isAdmin ( ) ;
$scope . showDeviceMapping = await shouldShowDevices ( ) ;
2021-04-12 09:40:45 +02:00
$scope . showSysctls = await shouldShowSysctls ( ) ;
2020-07-28 10:08:15 +03:00
$scope . areContainerCapabilitiesEnabled = await checkIfContainerCapabilitiesEnabled ( ) ;
2020-08-11 08:41:37 +03:00
$scope . isAdminOrEndpointAdmin = Authentication . isAdmin ( ) ;
2020-07-28 10:08:15 +03:00
2017-06-01 10:14:55 +02:00
Volume . query (
2020-04-11 00:54:53 +03:00
{ } ,
2017-06-01 10:14:55 +02:00
function ( d ) {
2020-07-27 02:58:33 +05:30
$scope . availableVolumes = d . Volumes . sort ( ( vol1 , vol2 ) => {
return vol1 . Name . localeCompare ( vol2 . Name ) ;
} ) ;
2020-04-11 00:54:53 +03:00
} ,
2019-01-17 21:59:43 +02:00
function ( e ) {
Notifications . error ( 'Failure' , e , 'Unable to retrieve volumes' ) ;
2020-04-11 00:54:53 +03:00
}
) ;
2017-08-11 09:46:55 +02:00
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-28 00:52:54 +03:00
. then ( function success ( networks ) {
2019-01-17 21:59:43 +02:00
networks . push ( { Name : 'container' } ) ;
2020-07-28 00:52:54 +03:00
$scope . availableNetworks = networks . sort ( ( a , b ) => a . Name . localeCompare ( b . Name ) ) ;
2020-04-11 00:54:53 +03:00
2017-08-11 09:46:55 +02:00
if ( _ . find ( networks , { Name : 'nat' } ) ) {
2019-01-17 21:59:43 +02:00
$scope . config . HostConfig . NetworkMode = 'nat' ;
2020-04-11 00:54:53 +03:00
}
2019-01-17 21:59:43 +02:00
} )
. catch ( function error ( err ) {
Notifications . error ( 'Failure' , err , 'Unable to retrieve networks' ) ;
} ) ;
Container . query (
2020-04-11 00:54:53 +03:00
{ } ,
2019-01-17 21:59:43 +02:00
function ( d ) {
var containers = d ;
$scope . runningContainers = containers ;
2022-08-30 14:52:24 +02:00
$scope . gpuUseAll = _ . get ( $scope , 'endpoint.Snapshots[0].GpuUseAll' , false ) ;
$scope . gpuUseList = _ . get ( $scope , 'endpoint.Snapshots[0].GpuUseList' , [ ] ) ;
2019-01-17 21:59:43 +02:00
if ( $transition$ . params ( ) . from ) {
2017-08-13 12:17:41 +02:00
loadFromContainerSpec ( ) ;
2020-04-11 00:54:53 +03:00
} else {
2019-01-17 21:59:43 +02:00
$scope . fromContainer = { } ;
2020-07-28 10:08:15 +03:00
$scope . formValues . capabilities = $scope . areContainerCapabilitiesEnabled ? new ContainerCapabilities ( ) : [ ] ;
2020-04-11 00:54:53 +03:00
}
} ,
2019-01-17 21:59:43 +02:00
function ( e ) {
Notifications . error ( 'Failure' , e , 'Unable to retrieve running containers' ) ;
}
2020-04-11 00:54:53 +03:00
) ;
2017-10-04 08:39:59 +02:00
SystemService . info ( )
2017-09-26 05:36:51 +02:00
. then ( function success ( data ) {
2020-02-26 04:31:59 +01:00
$scope . availableRuntimes = data . Runtimes ? Object . keys ( data . Runtimes ) : [ ] ;
2017-10-04 08:39:59 +02:00
$scope . state . sliderMaxCpu = 32 ;
if ( data . NCPU ) {
$scope . state . sliderMaxCpu = data . NCPU ;
2020-04-11 00:54:53 +03:00
}
2017-10-04 08:39:59 +02:00
$scope . state . sliderMaxMemory = 32768 ;
if ( data . MemTotal ) {
$scope . state . sliderMaxMemory = Math . floor ( data . MemTotal / 1000 / 1000 ) ;
2020-04-11 00:54:53 +03:00
}
} )
2017-09-26 05:36:51 +02:00
. catch ( function error ( err ) {
2017-10-04 08:39:59 +02:00
Notifications . error ( 'Failure' , err , 'Unable to retrieve engine details' ) ;
2020-04-11 00:54:53 +03:00
} ) ;
2021-02-09 10:09:06 +02:00
$scope . allowBindMounts = $scope . isAdminOrEndpointAdmin || endpoint . SecuritySettings . allowBindMountsForRegularUsers ;
$scope . allowPrivilegedMode = endpoint . SecuritySettings . allowPrivilegedModeForRegularUsers ;
2020-04-11 00:54:53 +03:00
2018-10-28 04:00:56 +01:00
PluginService . loggingPlugins ( apiVersion < 1.25 ) . then ( function success ( loggingDrivers ) {
$scope . availableLoggingDrivers = loggingDrivers ;
2019-01-17 21:59:43 +02:00
} ) ;
}
function validateForm ( accessControlData , isAdmin ) {
$scope . state . formValidationError = '' ;
2017-05-23 20:56:10 +02:00
var error = '' ;
2019-01-17 21:59:43 +02:00
error = FormValidator . validateAccessControl ( accessControlData , isAdmin ) ;
2020-04-11 00:54:53 +03:00
2019-01-17 21:59:43 +02:00
if ( error ) {
$scope . state . formValidationError = error ;
return false ;
}
return true ;
2018-08-18 09:27:24 +01:00
}
2021-11-30 11:01:09 +13: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 ;
2022-08-10 17:07:35 +12:00
Notifications . success ( 'Success' , 'Limits updated' ) ;
2021-11-30 11:01:09 +13:00
}
} 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 ;
}
2018-08-18 09:27:24 +01:00
function create ( ) {
var oldContainer = null ;
HttpRequestHelper . setPortainerAgentTargetHeader ( $scope . formValues . NodeName ) ;
return findCurrentContainer ( ) . then ( setOldContainer ) . then ( confirmCreateContainer ) . then ( startCreationProcess ) . catch ( notifyOnError ) . finally ( final ) ;
2020-04-11 00:54:53 +03:00
2018-08-18 09:27:24 +01:00
function final ( ) {
$scope . state . actionInProgress = false ;
}
function setOldContainer ( container ) {
oldContainer = container ;
return container ;
2020-04-11 00:54:53 +03:00
}
2018-08-18 09:27:24 +01:00
function findCurrentContainer ( ) {
return Container . query ( { all : 1 , filters : { name : [ '^/' + $scope . config . name + '$' ] } } )
2019-10-15 18:13:57 +09:00
. $promise . then ( function onQuerySuccess ( containers ) {
2016-07-06 12:19:09 +12:00
if ( ! containers . length ) {
2020-04-11 00:54:53 +03:00
return ;
}
2018-08-18 09:27:24 +01:00
return containers [ 0 ] ;
2020-04-11 00:54:53 +03:00
} )
2018-08-18 09:27:24 +01:00
. catch ( notifyOnError ) ;
function notifyOnError ( err ) {
2017-08-13 12:17:41 +02:00
Notifications . error ( 'Failure' , err , 'Unable to retrieve containers' ) ;
2020-04-11 00:54:53 +03:00
}
}
2018-08-18 09:27:24 +01:00
function startCreationProcess ( confirmed ) {
if ( ! confirmed ) {
return $q . when ( ) ;
2020-04-11 00:54:53 +03:00
}
2018-08-18 09:27:24 +01:00
if ( ! validateAccessControl ( ) ) {
return $q . when ( ) ;
2020-04-11 00:54:53 +03:00
}
2018-08-18 09:27:24 +01:00
$scope . state . actionInProgress = true ;
return pullImageIfNeeded ( )
2018-12-20 17:37:35 +02:00
. then ( stopAndRenameContainer )
2018-08-18 09:27:24 +01:00
. then ( createNewContainer )
. then ( applyResourceControl )
. then ( connectToExtraNetworks )
. then ( removeOldContainer )
2019-01-17 21:59:43 +02:00
. then ( onSuccess )
. catch ( onCreationProcessFail ) ;
2020-04-11 00:54:53 +03:00
}
2019-01-17 21:59:43 +02:00
function onCreationProcessFail ( error ) {
2018-08-18 09:27:24 +01:00
var deferred = $q . defer ( ) ;
2019-01-17 21:59:43 +02:00
removeNewContainer ( )
2018-08-18 09:27:24 +01:00
. then ( restoreOldContainerName )
2019-11-13 12:41:42 +13:00
. then ( function ( ) {
2018-08-18 09:27:24 +01:00
deferred . reject ( error ) ;
2020-04-11 00:54:53 +03:00
} )
2017-09-26 05:36:51 +02:00
. catch ( function ( restoreError ) {
2018-08-18 09:27:24 +01:00
deferred . reject ( restoreError ) ;
2020-04-11 00:54:53 +03:00
} ) ;
2018-08-18 09:27:24 +01:00
return deferred . promise ;
2020-04-11 00:54:53 +03:00
}
2018-08-18 09:27:24 +01:00
function removeNewContainer ( ) {
return findCurrentContainer ( ) . then ( function onContainerLoaded ( container ) {
if ( container && ( ! oldContainer || container . Id !== oldContainer . Id ) ) {
return ContainerService . remove ( container , true ) ;
}
} ) ;
2020-04-11 00:54:53 +03:00
}
2018-08-18 09:27:24 +01:00
2019-10-15 18:13:57 +09:00
function restoreOldContainerName ( ) {
2018-08-18 09:27:24 +01:00
if ( ! oldContainer ) {
2020-04-11 00:54:53 +03:00
return ;
}
2023-02-09 17:18:19 +13:00
return ContainerService . renameContainer ( oldContainer . Id , oldContainer . Names [ 0 ] ) ;
2018-08-18 09:27:24 +01:00
}
2018-12-20 17:37:35 +02:00
function confirmCreateContainer ( container ) {
2018-08-18 09:27:24 +01:00
if ( ! container ) {
return $q . when ( true ) ;
2020-04-11 00:54:53 +03:00
}
2018-08-18 09:27:24 +01:00
return showConfirmationModal ( ) ;
2020-04-11 00:54:53 +03:00
2019-10-15 18:13:57 +09:00
function showConfirmationModal ( ) {
2018-08-18 09:27:24 +01:00
var deferred = $q . defer ( ) ;
2020-04-11 00:54:53 +03:00
2023-02-14 13:49:41 +05:30
confirmDestructive ( {
title : 'Are you sure?' ,
2018-08-18 09:27:24 +01:00
message : 'A container with the same name already exists. Portainer can automatically remove it and re-create one. Do you want to replace it?' ,
2023-02-14 13:49:41 +05:30
confirmButton : buildConfirmButton ( 'Replace' , 'danger' ) ,
} ) . then ( function onConfirm ( confirmed ) {
deferred . resolve ( confirmed ) ;
2020-04-11 00:54:53 +03:00
} ) ;
2018-08-18 09:27:24 +01:00
return deferred . promise ;
2020-04-11 00:54:53 +03:00
}
2018-08-18 09:27:24 +01:00
}
function stopAndRenameContainer ( ) {
if ( ! oldContainer ) {
return $q . when ( ) ;
2020-04-11 00:54:53 +03:00
}
2018-08-18 09:27:24 +01:00
return stopContainerIfNeeded ( oldContainer ) . then ( renameContainer ) ;
}
function stopContainerIfNeeded ( oldContainer ) {
if ( oldContainer . State !== 'running' ) {
return $q . when ( ) ;
2020-04-11 00:54:53 +03:00
}
2018-08-18 09:27:24 +01:00
return ContainerService . stopContainer ( oldContainer . Id ) ;
}
function renameContainer ( ) {
2023-02-09 17:18:19 +13:00
return ContainerService . renameContainer ( oldContainer . Id , oldContainer . Names [ 0 ] + '-old' ) ;
2018-08-18 09:27:24 +01:00
}
function pullImageIfNeeded ( ) {
2019-10-15 18:13:57 +09:00
return $q . when ( $scope . formValues . alwaysPull && ImageService . pullImage ( $scope . formValues . RegistryModel , true ) ) ;
2018-08-18 09:27:24 +01:00
}
2017-05-23 20:56:10 +02:00
2018-08-18 09:27:24 +01:00
function createNewContainer ( ) {
2019-11-13 12:41:42 +13:00
return $async ( async ( ) => {
const config = prepareConfiguration ( ) ;
return await ContainerService . createAndStartContainer ( config ) ;
} ) ;
2020-04-11 00:54:53 +03:00
}
2019-11-13 12:41:42 +13:00
2023-03-03 14:47:10 +13:00
async function sendAnalytics ( ) {
const publicSettings = await SettingsService . publicSettings ( ) ;
const analyticsAllowed = publicSettings . EnableTelemetry ;
const image = ` ${ $scope . formValues . RegistryModel . Registry . URL } / ${ $scope . formValues . RegistryModel . Image } ` ;
if ( analyticsAllowed && $scope . formValues . GPU . enabled ) {
$analytics . eventTrack ( 'gpuContainerCreated' , {
category : 'docker' ,
metadata : { gpu : $scope . formValues . GPU , containerImage : image } ,
} ) ;
}
}
2019-11-13 12:41:42 +13:00
function applyResourceControl ( newContainer ) {
const userId = Authentication . getUserDetails ( ) . ID ;
const resourceControl = newContainer . Portainer . ResourceControl ;
const containerId = newContainer . Id ;
2017-06-05 07:55:18 +02:00
const accessControlData = $scope . formValues . AccessControlData ;
2018-08-18 09:27:24 +01:00
return ResourceControlService . applyResourceControl ( userId , accessControlData , resourceControl ) . then ( function onApplyResourceControlSuccess ( ) {
return containerId ;
} ) ;
}
2019-11-28 09:35:14 +13:00
function connectToExtraNetworks ( newContainerId ) {
2019-11-29 09:21:23 +13:00
if ( ! $scope . extraNetworks ) {
return $q . when ( ) ;
}
2020-04-11 00:54:53 +03:00
2019-11-28 09:35:14 +13:00
var connectionPromises = _ . forOwn ( $scope . extraNetworks , function ( network , networkName ) {
2019-11-29 09:21:23 +13:00
if ( _ . has ( network , 'Aliases' ) ) {
var aliases = _ . filter ( network . Aliases , ( o ) => {
return ! _ . startsWith ( $scope . fromContainer . Id , o ) ;
2020-04-11 00:54:53 +03:00
} ) ;
}
2019-11-29 09:21:23 +13:00
return NetworkService . connectContainer ( networkName , newContainerId , aliases ) ;
2019-11-28 09:35:14 +13:00
} ) ;
2018-08-18 09:27:24 +01:00
return $q . all ( connectionPromises ) ;
}
2020-04-11 00:54:53 +03:00
2018-08-18 09:27:24 +01:00
function removeOldContainer ( ) {
var deferred = $q . defer ( ) ;
if ( ! oldContainer ) {
deferred . resolve ( ) ;
2020-04-11 00:54:53 +03:00
return ;
}
2018-08-18 09:27:24 +01:00
ContainerService . remove ( oldContainer , true ) . then ( notifyOnRemoval ) . catch ( notifyOnRemoveError ) ;
return deferred . promise ;
function notifyOnRemoval ( ) {
Notifications . success ( 'Container Removed' , oldContainer . Id ) ;
deferred . resolve ( ) ;
2020-04-11 00:54:53 +03:00
}
2018-08-18 09:27:24 +01:00
function notifyOnRemoveError ( err ) {
deferred . reject ( { msg : 'Unable to remove container' , err : err } ) ;
2020-04-11 00:54:53 +03:00
}
2018-08-18 09:27:24 +01:00
}
function notifyOnError ( err ) {
Notifications . error ( 'Failure' , err , 'Unable to create container' ) ;
}
function validateAccessControl ( ) {
var accessControlData = $scope . formValues . AccessControlData ;
2019-05-24 18:04:58 +12:00
return validateForm ( accessControlData , $scope . isAdmin ) ;
2018-08-18 09:27:24 +01:00
}
2023-03-03 14:47:10 +13:00
async function onSuccess ( ) {
await sendAnalytics ( ) ;
2022-08-10 17:07:35 +12:00
Notifications . success ( 'Success' , 'Container successfully created' ) ;
2018-08-18 09:27:24 +01:00
$state . go ( 'docker.containers' , { } , { reload : true } ) ;
2020-04-11 00:54:53 +03:00
}
2018-08-18 09:27:24 +01:00
}
2017-05-23 20:56:10 +02:00
2020-07-28 10:08:15 +03:00
async function shouldShowDevices ( ) {
2021-02-09 10:09:06 +02:00
return endpoint . SecuritySettings . allowDeviceMappingForRegularUsers || Authentication . isAdmin ( ) ;
2020-07-28 10:08:15 +03:00
}
2021-04-12 09:40:45 +02:00
async function shouldShowSysctls ( ) {
2021-05-12 03:29:35 +03:00
return endpoint . SecuritySettings . allowSysctlSettingForRegularUsers || Authentication . isAdmin ( ) ;
2021-04-12 09:40:45 +02:00
}
2020-07-28 10:08:15 +03:00
async function checkIfContainerCapabilitiesEnabled ( ) {
2021-02-09 10:09:06 +02:00
return endpoint . SecuritySettings . allowContainerCapabilitiesForRegularUsers || Authentication . isAdmin ( ) ;
2020-07-29 12:10:46 +03:00
}
2017-05-23 20:56:10 +02:00
initView ( ) ;
2016-07-06 12:19:09 +12:00
} ,
] ) ;