2020-07-05 23:21:03 +00:00
< kubernetes-view-header ng-if = "!ctrl.state.isEdit" title = "Create application" state = "kubernetes.applications.new" view-ready = "ctrl.state.viewReady" >
< a ui-sref = "kubernetes.applications" > Applications< / a > > Create an application
< / kubernetes-view-header >
< kubernetes-view-header ng-if = "ctrl.state.isEdit" title = "Edit application" state = "kubernetes.applications.application.edit" view-ready = "ctrl.state.viewReady" >
< a ui-sref = "kubernetes.resourcePools" > Resource pools< / a > >
< a ui-sref = "kubernetes.resourcePools.resourcePool({ id: ctrl.application.ResourcePool })" > {{ ctrl.application.ResourcePool }}< / a > >
< a ui-sref = "kubernetes.applications" > Applications< / a > >
< a ui-sref = "kubernetes.applications.application({ name: ctrl.application.Name, namespace: ctrl.application.ResourcePool })" > {{ ctrl.application.Name }}< / a > > Edit
< / kubernetes-view-header >
< kubernetes-view-loading view-ready = "ctrl.state.viewReady" > < / kubernetes-view-loading >
< div ng-if = "ctrl.state.viewReady" >
< div class = "row" >
< div class = "col-xs-12" >
< rd-widget >
< rd-widget-body >
< form class = "form-horizontal" name = "kubernetesApplicationCreationForm" autocomplete = "off" >
2020-08-12 23:30:23 +00:00
<!-- #region NAME FIELD -->
2020-07-05 23:21:03 +00:00
< div class = "form-group" >
< label for = "application_name" class = "col-sm-1 control-label text-left" > Name< / label >
< div class = "col-sm-11" >
< input
type="text"
class="form-control"
name="application_name"
ng-model="ctrl.formValues.Name"
ng-change="ctrl.onChangeName()"
placeholder="my-app"
ng-pattern="/^[a-z]([-a-z0-9]*[a-z0-9])?$/"
auto-focus
required
ng-disabled="ctrl.state.isEdit"
/>
< / div >
< / div >
< div class = "form-group" ng-show = "kubernetesApplicationCreationForm.application_name.$invalid || ctrl.state.alreadyExists" >
< div class = "col-sm-12 small text-warning" >
< div ng-messages = "kubernetesApplicationCreationForm.application_name.$error" >
< p ng-message = "required" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > This field is required.< / p >
< p ng-message = "pattern"
>< i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > This field must consist of lower case alphanumeric characters or '-', start with an alphabetic
character, and end with an alphanumeric character (e.g. 'my-name', or 'abc-123').< /p
>
< / div >
< p ng-if = "ctrl.state.alreadyExists"
>< i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > An application with the same name already exists inside the selected resource pool.< /p
>
< / div >
< / div >
2020-08-12 23:30:23 +00:00
<!-- #endregion -->
2020-07-05 23:21:03 +00:00
2020-08-12 23:30:23 +00:00
<!-- #region IMAGE FIELD -->
2020-07-05 23:21:03 +00:00
< div class = "form-group" >
< label for = "container_image" class = "col-sm-1 control-label text-left" > Image< / label >
< div class = "col-sm-11" >
2020-08-13 23:27:10 +00:00
< input
type="text"
class="form-control"
name="container_image"
ng-model="ctrl.formValues.Image"
placeholder="nginx:latest"
required
ng-disabled="ctrl.formValues.Containers.length > 1"
/>
2020-07-05 23:21:03 +00:00
< / div >
< / div >
< div class = "form-group" ng-show = "kubernetesApplicationCreationForm.container_image.$invalid" >
< div class = "col-sm-12 small text-warning" >
< div ng-messages = "kubernetesApplicationCreationForm.container_image.$error" >
< p ng-message = "required" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > This field is required.< / p >
< / div >
< / div >
< / div >
2020-08-12 23:30:23 +00:00
<!-- #endregion -->
2020-07-05 23:21:03 +00:00
< div class = "col-sm-12 form-section-title" >
Resource pool
< / div >
2020-08-12 23:30:23 +00:00
<!-- #region RESOURCE POOL -->
2020-07-05 23:21:03 +00:00
< div class = "form-group" >
< label for = "resource-pool-selector" class = "col-sm-1 control-label text-left" > Resource pool< / label >
< div class = "col-sm-11" >
< select
class="form-control"
id="resource-pool-selector"
ng-model="ctrl.formValues.ResourcePool"
ng-options="resourcePool.Namespace.Name for resourcePool in ctrl.resourcePools"
ng-change="ctrl.onResourcePoolSelectionChange()"
ng-disabled="ctrl.state.isEdit"
>< / select >
< / div >
< / div >
< div class = "form-group" ng-if = "ctrl.state.resourcePoolHasQuota && ctrl.resourceQuotaCapacityExceeded()" >
2021-01-13 03:13:27 +00:00
< div class = "col-sm-12 small text-danger" >
< i class = "fa fa-exclamation-circle red-icon" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
2020-07-05 23:21:03 +00:00
This resource pool has exhausted its resource capacity and you will not be able to deploy the application. Contact your administrator to expand the capacity of the
resource pool.
< / div >
< / div >
2020-08-12 23:30:23 +00:00
<!-- #endregion -->
2020-07-05 23:21:03 +00:00
< div class = "col-sm-12 form-section-title" >
Stack
< / div >
2020-08-12 23:30:23 +00:00
<!-- #region STACK -->
2020-07-05 23:21:03 +00:00
< div class = "form-group" >
< div class = "col-sm-12 small text-muted" >
< i class = "fa fa-info-circle blue-icon" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
Portainer can automatically bundle multiple applications inside a stack. Enter a name of a new stack or select an existing stack in the list. Leave empty to use the
application name.
< / div >
< / div >
< div class = "form-group" >
< label for = "stack_name" class = "col-sm-1 control-label text-left" > Stack< / label >
< div class = "col-sm-11" >
< input
type="text"
class="form-control"
placeholder="myStack"
ng-model="ctrl.formValues.StackName"
name="stack_name"
uib-typeahead="stack for stack in ctrl.stacks | filter:$viewValue | limitTo:7"
typeahead-show-hint="true"
typeahead-min-length="0"
/>
< / div >
< / div >
2020-08-12 23:30:23 +00:00
<!-- #endregion -->
2020-07-05 23:21:03 +00:00
< div class = "col-sm-12 form-section-title" >
Environment
< / div >
2020-08-12 23:30:23 +00:00
<!-- #region ENVIRONMENT VARIABLES -->
2020-07-05 23:21:03 +00:00
< div class = "form-group" >
< div class = "col-sm-12" >
< label class = "control-label text-left" > Environment variables< / label >
2020-08-13 23:27:10 +00:00
< span ng-if = "ctrl.formValues.Containers.length <= 1" class = "label label-default interactive" style = "margin-left: 10px;" ng-click = "ctrl.addEnvironmentVariable()" >
2020-07-05 23:21:03 +00:00
< i class = "fa fa-plus-circle" aria-hidden = "true" > < / i > add environment variable
< / span >
< / div >
< div class = "col-sm-12 form-inline" style = "margin-top: 10px;" >
< div ng-repeat = "envVar in ctrl.formValues.EnvironmentVariables" style = "margin-top: 2px;" >
< div class = "col-sm-4 input-group input-group-sm" style = "vertical-align: top;" >
< div class = "input-group col-sm-12 input-group-sm" ng-class = "{ striked: envVar.NeedsDeletion }" >
< span class = "input-group-addon" > name< / span >
< input
type="text"
name="environment_variable_name_{{ $index }}"
class="form-control"
ng-model="envVar.Name"
2020-08-12 23:30:23 +00:00
ng-change="ctrl.onChangeEnvironmentName()"
2020-08-10 22:56:54 +00:00
ng-pattern="/^[a-zA-Z]([-_a-zA-Z0-9]*[a-zA-Z0-9])?$/"
2020-07-05 23:21:03 +00:00
placeholder="foo"
2020-08-13 23:27:10 +00:00
ng-disabled="ctrl.formValues.Containers.length > 1"
2020-07-05 23:21:03 +00:00
required
/>
< / div >
< div
class="small text-warning"
style="margin-top: 5px;"
2020-08-12 23:30:23 +00:00
ng-show="
kubernetesApplicationCreationForm['environment_variable_name_' + $index].$invalid || ctrl.state.duplicates.environmentVariables.refs[$index] !== undefined
"
2020-07-05 23:21:03 +00:00
>
< ng-messages for = "kubernetesApplicationCreationForm['environment_variable_name_' + $index].$error" >
< p ng-message = "required" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Environment variable name is required.< / p >
2020-08-10 22:56:54 +00:00
< p ng-message = "pattern"
>< i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > This field must consist alphanumeric characters, '-' or '_', start with an alphabetic
character, and end with an alphanumeric character (e.g. 'my-var', or 'MY_VAR123').< /p
>
2020-07-05 23:21:03 +00:00
< / ng-messages >
2020-08-12 23:30:23 +00:00
< p ng-if = "ctrl.state.duplicates.environmentVariables.refs[$index] !== undefined"
2020-07-05 23:21:03 +00:00
>< i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > This environment variable is already defined.< /p
>
< / div >
< / div >
< div class = "input-group col-sm-4 input-group-sm" ng-class = "{ striked: envVar.NeedsDeletion }" >
< span class = "input-group-addon" > value< / span >
2020-08-13 23:27:10 +00:00
< input
type="text"
name="environment_variable_value_{{ $index }}"
class="form-control"
ng-model="envVar.Value"
placeholder="bar"
ng-disabled="ctrl.formValues.Containers.length > 1"
/>
2020-07-05 23:21:03 +00:00
< / div >
2020-08-13 23:27:10 +00:00
< div class = "input-group col-sm-2 input-group-sm" ng-if = "ctrl.formValues.Containers.length <= 1" >
2020-07-05 23:21:03 +00:00
< button ng-if = "!envVar.NeedsDeletion" class = "btn btn-sm btn-danger" type = "button" ng-click = "ctrl.removeEnvironmentVariable($index)" >
2020-08-12 23:30:23 +00:00
< i class = "fa fa-trash-alt" aria-hidden = "true" > < / i >
2020-07-05 23:21:03 +00:00
< / button >
< button ng-if = "envVar.NeedsDeletion" class = "btn btn-sm btn-primary" type = "button" ng-click = "ctrl.restoreEnvironmentVariable($index)" >
2020-08-12 23:30:23 +00:00
< i class = "fa fa-trash-restore" aria-hidden = "true" > < / i >
2020-07-05 23:21:03 +00:00
< / button >
< / div >
< / div >
< / div >
< / div >
2020-08-12 23:30:23 +00:00
<!-- #endregion -->
2020-07-05 23:21:03 +00:00
< div class = "col-sm-12 form-section-title" >
Configurations
< / div >
2020-08-12 23:30:23 +00:00
<!-- #region CONFIGURATIONS -->
2020-07-05 23:21:03 +00:00
< div class = "form-group" >
< div class = "col-sm-12" >
< label class = "control-label text-left" > Configurations< / label >
2020-08-13 23:27:10 +00:00
< span class = "label label-default interactive" style = "margin-left: 10px;" ng-click = "ctrl.addConfiguration()" ng-if = "ctrl.formValues.Containers.length <= 1" >
2020-07-05 23:21:03 +00:00
< i class = "fa fa-plus-circle" aria-hidden = "true" > < / i > add configuration
< / span >
< / div >
< div class = "col-sm-12 small text-muted" style = "margin-top: 15px;" ng-if = "ctrl.formValues.Configurations.length" >
< i class = "fa fa-info-circle blue-icon" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
Portainer will automatically expose all the keys of a configuration as environment variables. This behavior can be overriden to filesystem mounts for each key via
the override button.
< / div >
< / div >
<!-- config - element -->
< div class = "form-group" ng-repeat = "(index, config) in ctrl.formValues.Configurations" >
< label for = "stack_name" class = "col-md-1 col-sm-2 control-label text-left" > Configuration< / label >
< div class = "col-sm-5" >
< select
class="form-control"
ng-model="config.SelectedConfiguration"
ng-options="c as c.Name for c in ctrl.configurations"
ng-change="ctrl.resetConfiguration(index)"
2020-08-13 23:27:10 +00:00
ng-disabled="ctrl.formValues.Containers.length > 1"
2020-07-05 23:21:03 +00:00
>< / select >
< / div >
< div class = "col-sm-6" style = "margin-top: 2px;" >
< button
class="btn btn-sm btn-primary"
type="button"
ng-if="!config.Overriden"
ng-click="ctrl.overrideConfiguration(index)"
2020-08-13 23:27:10 +00:00
ng-disabled="!config.SelectedConfiguration || ctrl.formValues.Containers.length > 1"
2020-07-05 23:21:03 +00:00
>
< i class = "fa fa-list" aria-hidden = "true" > < / i > Override
< / button >
2020-08-13 23:27:10 +00:00
< button
class="btn btn-sm btn-primary"
type="button"
ng-if="config.Overriden"
ng-click="ctrl.resetConfiguration(index)"
ng-disabled="ctrl.formValues.Containers.length > 1"
>
2020-07-05 23:21:03 +00:00
< i class = "fa fa-undo" aria-hidden = "true" > < / i > Auto
< / button >
2020-08-14 04:56:56 +00:00
< button class = "btn btn-sm btn-danger" type = "button" ng-click = "ctrl.removeConfiguration(index)" ng-if = "ctrl.formValues.Containers.length <= 1" >
< i class = "fa fa-trash-alt" aria-hidden = "true" > < / i > Remove
< / button >
2020-07-05 23:21:03 +00:00
< / div >
<!-- no - override -->
< div class = "col-sm-12" style = "margin-top: 10px;" ng-if = "config.SelectedConfiguration && !config.Overriden" >
< div class = "col-md-1 col-sm-2" > < / div >
< div class = "col-md-11 col-sm-10 small text-muted" style = "padding-left: 5px;" >
The following keys will be loaded from the < code > {{ config.SelectedConfiguration.Name }}< / code > configuration as environment variables:
< span ng-repeat = "(key, _) in config.SelectedConfiguration.Data" >
< code > {{ key }}< /code
>{{ $last ? '' : ', ' }}
< / span >
< / div >
< / div >
<!-- !no - override -->
<!-- has - override -->
< div class = "col-sm-12 form-inline" style = "margin-top: 10px;" ng-if = "config.Overriden" >
< div ng-repeat = "(keyIndex, overridenKey) in config.OverridenKeys" style = "margin-top: 2px;" >
< div class = "col-md-1 col-sm-2" style = "margin-left: 3px;" style = "vertical-align: top;" > < / div >
< div class = "input-group col-sm-3 input-group-sm" style = "vertical-align: top;" >
< span class = "input-group-addon" > configuration key< / span >
< input type = "text" class = "form-control" ng-value = "overridenKey.Key" disabled / >
< / div >
< div
class="col-sm-3 input-group input-group-sm"
style="vertical-align: top;"
ng-if="overridenKey.Type === ctrl.ApplicationConfigurationFormValueOverridenKeyTypes.FILESYSTEM"
>
< div class = "input-group col-sm-12 input-group-sm" >
< span class = "input-group-addon" > path on disk< / span >
< input
type="text"
class="form-control"
ng-model="overridenKey.Path"
placeholder="/etc/myapp/conf.d"
name="overriden_key_path_{{ index }}_{{ keyIndex }}"
2020-08-13 23:27:10 +00:00
ng-disabled="ctrl.formValues.Containers.length > 1"
2020-07-05 23:21:03 +00:00
required
ng-change="ctrl.onChangeConfigurationPath()"
/>
< / div >
< div
class="small text-warning"
style="margin-top: 5px;"
ng-show="
kubernetesApplicationCreationForm['overriden_key_path_' + index + '_' + keyIndex].$invalid ||
2020-08-12 23:30:23 +00:00
ctrl.state.duplicates.configurationPaths.refs[index + '_' + keyIndex] !== undefined
2020-07-05 23:21:03 +00:00
"
>
< ng-messages for = "kubernetesApplicationCreationForm['overriden_key_path_' + index + '_' + keyIndex].$error" >
< p ng-message = "required" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Path is required.< / p >
< / ng-messages >
2020-08-12 23:30:23 +00:00
< p ng-if = "ctrl.state.duplicates.configurationPaths.refs[index + '_' + keyIndex] !== undefined"
2020-07-05 23:21:03 +00:00
>< i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > This path is already used.< /p
>
< / div >
< / div >
< div class = "input-group col-sm-3 btn-group btn-group-sm" style = "vertical-align: top;" >
< label class = "btn btn-primary" ng-model = "overridenKey.Type" uib-btn-radio = "ctrl.ApplicationConfigurationFormValueOverridenKeyTypes.ENVIRONMENT" >
< i class = "fa fa-list" aria-hidden = "true" > < / i > Environment
< / label >
< label class = "btn btn-primary" ng-model = "overridenKey.Type" uib-btn-radio = "ctrl.ApplicationConfigurationFormValueOverridenKeyTypes.FILESYSTEM" >
< i class = "fa fa-file" aria-hidden = "true" > < / i > Filesystem
< / label >
< / div >
< / div >
< / div >
<!-- !has - override -->
< / div >
<!-- !config - element -->
2020-08-12 23:30:23 +00:00
<!-- #endregion -->
2020-07-05 23:21:03 +00:00
< div class = "col-sm-12 form-section-title" >
Persisting data
< / div >
2020-08-12 23:30:23 +00:00
<!-- #region PERSISTED FOLDERS -->
2020-07-05 23:21:03 +00:00
< div class = "form-group" ng-if = "!ctrl.storageClassAvailable()" >
< div class = "col-sm-12 small text-muted" >
< i class = "fa fa-exclamation-circle orange-icon" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
No storage option is available to persist data, contact your administrator to enable a storage option.
< / div >
< / div >
< div class = "form-group" ng-if = "ctrl.storageClassAvailable()" >
< div class = "col-sm-12" style = "margin-top: 5px;" >
< label class = "control-label text-left" > Persisted folders< / label >
2020-08-13 23:27:10 +00:00
< span
class="label label-default interactive"
style="margin-left: 10px;"
ng-click="ctrl.addPersistedFolder()"
ng-if="!ctrl.isEditAndStatefulSet() & & ctrl.formValues.Containers.length < = 1"
>
2020-07-05 23:21:03 +00:00
< i class = "fa fa-plus-circle" aria-hidden = "true" > < / i > add persisted folder
< / span >
< / div >
2020-08-07 04:40:24 +00:00
< div class = "col-sm-12 form-inline" style = "margin-top: 10px;" ng-repeat = "persistedFolder in ctrl.formValues.PersistedFolders" >
< div style = "margin-top: 2px;" >
2020-07-05 23:21:03 +00:00
< div class = "input-group col-sm-3 input-group-sm" ng-class = "{ striked: persistedFolder.NeedsDeletion }" >
< span class = "input-group-addon" > path in container< / span >
< input
type="text"
class="form-control"
name="persisted_folder_path_{{ $index }}"
ng-model="persistedFolder.ContainerPath"
2020-08-12 23:30:23 +00:00
ng-change="ctrl.onChangePersistedFolderPath()"
2020-08-13 23:27:10 +00:00
ng-disabled="ctrl.isEditAndExistingPersistedFolder($index) || ctrl.formValues.Containers.length > 1"
2020-07-05 23:21:03 +00:00
placeholder="/data"
required
/>
< / div >
2020-08-07 04:40:24 +00:00
< div class = "input-group col-sm-2 input-group-sm" >
< span
class="btn-group btn-group-sm"
ng-class="{ striked: persistedFolder.NeedsDeletion }"
2020-08-13 23:27:10 +00:00
ng-if="
!ctrl.isEditAndExistingPersistedFolder($index) & &
ctrl.application.ApplicationType !== ctrl.ApplicationTypes.STATEFULSET & &
ctrl.formValues.Containers.length < = 1
"
2020-08-07 04:40:24 +00:00
>
< label
class="btn btn-primary"
ng-model="persistedFolder.UseNewVolume"
uib-btn-radio="true"
ng-change="ctrl.useNewVolume($index)"
ng-disabled="ctrl.isEditAndExistingPersistedFolder($index)"
>New volume< /label
>
< label
class="btn btn-primary"
ng-model="persistedFolder.UseNewVolume"
uib-btn-radio="false"
ng-change="ctrl.useExistingVolume($index)"
ng-disabled="ctrl.availableVolumes.length === 0 || ctrl.application.ApplicationType === ctrl.ApplicationTypes.STATEFULSET"
2020-08-12 23:30:23 +00:00
>Existing volume< /label
2020-08-07 04:40:24 +00:00
>
< / span >
< / div >
2020-08-15 22:31:43 +00:00
< div class = "input-group col-sm-3 input-group-sm" ng-class = "{ striked: persistedFolder.NeedsDeletion }" ng-if = "persistedFolder.UseNewVolume" >
2020-07-05 23:21:03 +00:00
< span class = "input-group-addon" > requested size< / span >
< input
type="number"
class="form-control"
name="persisted_folder_size_{{ $index }}"
ng-model="persistedFolder.Size"
placeholder="20"
ng-min="0"
required
2020-08-13 23:27:10 +00:00
ng-disabled="ctrl.isEditAndExistingPersistedFolder($index) || ctrl.formValues.Containers.length > 1"
2020-07-05 23:21:03 +00:00
/>
< span class = "input-group-addon" style = "padding: 0;" >
< select
ng-model="persistedFolder.SizeUnit"
ng-style="{ width: '100%', height: '100%', cursor: ctrl.isEditAndExistingPersistedFolder($index) ? 'not-allowed' : 'auto' }"
ng-options="unit for unit in ctrl.state.availableSizeUnits"
2020-08-13 23:27:10 +00:00
ng-disabled="ctrl.isEditAndExistingPersistedFolder($index) || ctrl.formValues.Containers.length > 1"
2020-07-05 23:21:03 +00:00
>< / select >
< / span >
< / div >
2020-08-07 04:40:24 +00:00
< div
2020-08-15 22:31:43 +00:00
class="input-group col-sm-2 input-group-sm"
2020-08-07 04:40:24 +00:00
ng-class="{ striked: persistedFolder.NeedsDeletion }"
style="vertical-align: top;"
ng-if="persistedFolder.UseNewVolume"
>
2020-07-05 23:21:03 +00:00
< span class = "input-group-addon" > storage< / span >
< select
ng-if="ctrl.hasMultipleStorageClassesAvailable()"
class="form-control"
ng-model="persistedFolder.StorageClass"
ng-options="storageClass as storageClass.Name for storageClass in ctrl.storageClasses"
2020-08-13 23:27:10 +00:00
ng-disabled="ctrl.state.isEdit || ctrl.formValues.Containers.length > 1"
2020-07-05 23:21:03 +00:00
>< / select >
< input ng-if = "!ctrl.hasMultipleStorageClassesAvailable()" type = "text" class = "form-control" disabled ng-model = "persistedFolder.StorageClass.Name" / >
< / div >
2020-08-07 04:40:24 +00:00
< div class = "input-group col-sm-5 input-group-sm" ng-if = "!persistedFolder.UseNewVolume" ng-class = "{ striked: persistedFolder.NeedsDeletion }" >
< span class = "input-group-addon" > volume< / span >
< select
class="form-control"
name="existing_volumes_{{ $index }}"
ng-model="ctrl.formValues.PersistedFolders[$index].ExistingVolume"
ng-options="vol as vol.PersistentVolumeClaim.Name for vol in ctrl.availableVolumes"
ng-change="ctrl.onChangeExistingVolumeSelection()"
2020-08-13 23:27:10 +00:00
ng-disabled="ctrl.isEditAndExistingPersistedFolder($index) || ctrl.formValues.Containers.length > 1"
2020-08-07 04:40:24 +00:00
required
>
< option selected disabled hidden value = "" > Select a volume< / option >
< / select >
< / div >
< div class = "input-group col-sm-1 input-group-sm" >
2020-08-13 23:27:10 +00:00
< div style = "vertical-align: top;" ng-if = "!ctrl.isEditAndStatefulSet() && !ctrl.state.useExistingVolume[$index] && ctrl.formValues.Containers.length <= 1" >
2020-08-07 04:40:24 +00:00
< button ng-if = "!persistedFolder.NeedsDeletion" class = "btn btn-sm btn-danger" type = "button" ng-click = "ctrl.removePersistedFolder($index)" >
2020-08-12 23:30:23 +00:00
< i class = "fa fa-trash-alt" aria-hidden = "true" > < / i >
2020-08-07 04:40:24 +00:00
< / button >
< button ng-if = "persistedFolder.NeedsDeletion" class = "btn btn-sm btn-primary" type = "button" ng-click = "ctrl.restorePersistedFolder($index)" >
2020-08-12 23:30:23 +00:00
< i class = "fa fa-trash-restore" aria-hidden = "true" > < / i >
2020-08-07 04:40:24 +00:00
< / button >
< / div >
2020-07-05 23:21:03 +00:00
< / div >
< / div >
< div
ng-show="
kubernetesApplicationCreationForm['persisted_folder_path_' + $index].$invalid ||
2020-08-12 23:30:23 +00:00
ctrl.state.duplicates.persistedFolders.refs[$index] !== undefined ||
2020-08-07 04:40:24 +00:00
kubernetesApplicationCreationForm['persisted_folder_size_' + $index].$invalid ||
kubernetesApplicationCreationForm['existing_volumes_' + $index].$invalid ||
2020-08-12 23:30:23 +00:00
ctrl.state.duplicates.existingVolumes.refs[$index] !== undefined
2020-07-05 23:21:03 +00:00
"
>
< div class = "input-group col-sm-3 input-group-sm" >
< div
class="small text-warning"
style="margin-top: 5px;"
2020-08-12 23:30:23 +00:00
ng-show="kubernetesApplicationCreationForm['persisted_folder_path_' + $index].$invalid || ctrl.state.duplicates.persistedFolders.refs[$index] !== undefined"
2020-07-05 23:21:03 +00:00
>
< ng-messages for = "kubernetesApplicationCreationForm['persisted_folder_path_' + $index].$error" >
< p ng-message = "required" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Path is required.< / p >
< / ng-messages >
2020-08-12 23:30:23 +00:00
< p ng-if = "ctrl.state.duplicates.persistedFolders.refs[$index] !== undefined"
2020-07-05 23:21:03 +00:00
>< i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > This path is already defined.< /p
>
< / div >
< / div >
2020-08-07 04:40:24 +00:00
< div class = "input-group col-sm-2 input-group-sm" > < / div >
< div class = "input-group col-sm-2 input-group-sm" >
2020-07-05 23:21:03 +00:00
< div class = "small text-warning" style = "margin-top: 5px;" ng-show = "kubernetesApplicationCreationForm['persisted_folder_size_' + $index].$invalid" >
< ng-messages for = "kubernetesApplicationCreationForm['persisted_folder_size_' + $index].$error" >
< p ng-message = "required" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Size is required.< / p >
< p ng-message = "min" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > This value must be greater than zero.< / p >
< / ng-messages >
< / div >
2020-08-07 04:40:24 +00:00
< div
class="small text-warning"
2020-08-12 23:30:23 +00:00
ng-show="kubernetesApplicationCreationForm['existing_volumes_' + $index].$invalid || ctrl.state.duplicates.existingVolumes.refs[$index] !== undefined"
2020-08-07 04:40:24 +00:00
>
< ng-messages for = "kubernetesApplicationCreationForm['existing_volumes_' + $index].$error" >
< p ng-message = "required" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Volume is required.< / p >
< / ng-messages >
2020-08-12 23:30:23 +00:00
< p ng-if = "ctrl.state.duplicates.existingVolumes.refs[$index] !== undefined"
2020-08-07 04:40:24 +00:00
>< i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > This volume is already used.< /p
>
< / div >
2020-07-05 23:21:03 +00:00
< / div >
< div class = "input-group col-sm-3 input-group-sm" > < / div >
< div class = "input-group col-sm-1 input-group-sm" > < / div >
< / div >
< / div >
< / div >
2020-08-12 23:30:23 +00:00
<!-- #endregion -->
2020-07-05 23:21:03 +00:00
2020-08-12 23:30:23 +00:00
<!-- #region DATA ACCESS POLICY -->
2020-07-05 23:21:03 +00:00
< div ng-if = "ctrl.showDataAccessPolicySection()" >
< div class = "form-group" >
< div class = "col-sm-12" >
< label class = "control-label text-left" > Data access policy< / label >
< / div >
< / div >
< div class = "form-group" >
< div class = "col-sm-12 small text-muted" >
Specify how the data will be used across instances.
< / div >
< / div >
<!-- access policy options -->
< div class = "form-group" style = "margin-bottom: 0;" >
< div class = "boxselector_wrapper" >
< div ng-if = "!ctrl.state.isEdit || (ctrl.state.isEdit && ctrl.formValues.DataAccessPolicy === ctrl.ApplicationDataAccessPolicies.SHARED)" >
< input
type="radio"
id="data_access_shared"
ng-value="ctrl.ApplicationDataAccessPolicies.SHARED"
ng-model="ctrl.formValues.DataAccessPolicy"
ng-change="ctrl.resetDeploymentType()"
/>
< label for = "data_access_shared" >
< div class = "boxselector_header" >
< i class = "fa fa-cube" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
Shared
< / div >
< p > All the instances of this application will use the same data< / p >
< / label >
< / div >
< div style = "color: #767676;" ng-if = "ctrl.state.isEdit && ctrl.formValues.DataAccessPolicy === ctrl.ApplicationDataAccessPolicies.ISOLATED" >
< input type = "radio" id = "data_access_shared" disabled / >
< label
for="data_access_shared"
tooltip-append-to-body="true"
tooltip-placement="bottom"
tooltip-class="portainer-tooltip"
uib-tooltip="Changing the data access policy is not allowed"
style="cursor: pointer; border-color: #767676;"
>
< div class = "boxselector_header" >
< i class = "fa fa-cube" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
Shared
< / div >
< p > All the instances of this application will use the same data< / p >
< / label >
< / div >
2020-08-07 04:40:24 +00:00
< div
ng-if="
(!ctrl.state.isEdit & & !ctrl.state.PersistedFoldersUseExistingVolumes) ||
(ctrl.state.isEdit & & ctrl.formValues.DataAccessPolicy === ctrl.ApplicationDataAccessPolicies.ISOLATED)
"
>
2020-07-05 23:21:03 +00:00
< input
type="radio"
id="data_access_isolated"
ng-value="ctrl.ApplicationDataAccessPolicies.ISOLATED"
ng-model="ctrl.formValues.DataAccessPolicy"
ng-change="ctrl.resetDeploymentType()"
/>
< label for = "data_access_isolated" >
< div class = "boxselector_header" >
< i class = "fa fa-cubes" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
Isolated
< / div >
< p > Every instance of this application will use their own data< / p >
< / label >
< / div >
2020-08-07 04:40:24 +00:00
< div
style="color: #767676;"
ng-if="(ctrl.state.isEdit & & ctrl.formValues.DataAccessPolicy === ctrl.ApplicationDataAccessPolicies.SHARED) || ctrl.state.PersistedFoldersUseExistingVolumes"
>
2020-07-05 23:21:03 +00:00
< input type = "radio" id = "data_access_isolated" disabled / >
< label
for="data_access_isolated"
tooltip-append-to-body="true"
tooltip-placement="bottom"
tooltip-class="portainer-tooltip"
uib-tooltip="Changing the data access policy is not allowed"
style="cursor: pointer; border-color: #767676;"
>
< div class = "boxselector_header" >
< i class = "fa fa-cubes" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
Isolated
< / div >
< p > Every instance of this application will use their own data< / p >
< / label >
< / div >
< / div >
< / div >
<!-- !access policy options -->
< / div >
2020-08-12 23:30:23 +00:00
<!-- #endregion -->
2020-07-05 23:21:03 +00:00
< div class = "col-sm-12 form-section-title" >
Resource reservations
< / div >
2020-08-12 23:30:23 +00:00
<!-- #region RESOURCE RESERVATIONS -->
2020-07-05 23:21:03 +00:00
< div class = "form-group" ng-if = "!ctrl.state.resourcePoolHasQuota" >
< div class = "col-sm-12 small text-muted" >
< i class = "fa fa-info-circle blue-icon" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
Resource reservations are applied per instance of the application.
< / div >
< / div >
< div class = "form-group" ng-if = "ctrl.state.resourcePoolHasQuota && !ctrl.resourceQuotaCapacityExceeded()" >
< div class = "col-sm-12 small text-muted" >
< i class = "fa fa-info-circle blue-icon" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
A resource quota is set on this resource pool, you must specify resource reservations. Resource reservations are applied per instance of the application. Maximums
are inherited from the resource pool quota.
< / div >
< / div >
< div class = "form-group" ng-if = "ctrl.state.resourcePoolHasQuota && ctrl.resourceQuotaCapacityExceeded()" >
2021-01-13 03:13:27 +00:00
< div class = "col-sm-12 small text-danger" >
< i class = "fa fa-exclamation-circle red-icon" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
2020-07-05 23:21:03 +00:00
This resource pool has exhausted its resource capacity and you will not be able to deploy the application. Contact your administrator to expand the capacity of the
resource pool.
< / div >
< / div >
<!-- memory - limit - input -->
2020-08-13 23:27:10 +00:00
< div
class="form-group"
ng-if="(!ctrl.state.resourcePoolHasQuota || (ctrl.state.resourcePoolHasQuota & & !ctrl.resourceQuotaCapacityExceeded())) & & ctrl.formValues.Containers.length < = 1"
>
2020-07-05 23:21:03 +00:00
< label for = "memory-limit" class = "col-sm-3 col-lg-2 control-label text-left" style = "margin-top: 20px;" >
Memory
< portainer-tooltip
position="bottom"
message="An instance of this application will reserve this amount of memory. If the instance memory usage exceeds the reservation, it might be subject to OOM."
>
< / portainer-tooltip >
< / label >
< div class = "col-sm-3" >
< slider model = "ctrl.formValues.MemoryLimit" floor = "ctrl.state.sliders.memory.min" ceil = "ctrl.state.sliders.memory.max" step = "128" > < / slider >
< / div >
< div class = "col-sm-2" >
< input
name="memory_limit"
ng-model="ctrl.formValues.MemoryLimit"
type="number"
min="{{ ctrl.state.sliders.memory.min }}"
max="{{ ctrl.state.sliders.memory.max }}"
class="form-control"
id="memory-limit"
required
/>
< / div >
< div class = "col-sm-4" >
< p class = "small text-muted" style = "margin-top: 7px;" >
Maximum memory usage (< b > MB< / b > )
< / p >
< / div >
< / div >
< div class = "form-group" ng-show = "kubernetesApplicationCreationForm.memory_limit.$invalid" >
< div class = "col-sm-12 small text-warning" >
< div ng-messages = "kubernetesApplicationCreationForm.memory_limit.$error" >
< p
>< i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Value must be between {{ ctrl.state.sliders.memory.min }} and {{ ctrl.state.sliders.memory.max }}
< / p >
< / div >
< / div >
< / div >
<!-- !memory - limit - input -->
<!-- cpu - limit - input -->
2020-08-13 23:27:10 +00:00
< div
class="form-group"
ng-if="(!ctrl.state.resourcePoolHasQuota || (ctrl.state.resourcePoolHasQuota & & !ctrl.resourceQuotaCapacityExceeded())) & & ctrl.formValues.Containers.length < = 1"
>
2020-07-05 23:21:03 +00:00
< label for = "cpu-limit" class = "col-sm-3 col-lg-2 control-label text-left" style = "margin-top: 20px;" >
CPU
< portainer-tooltip
position="bottom"
message="An instance of this application will reserve this amount of CPU. If the instance CPU usage exceeds the reservation, it might be subject to CPU throttling."
>
< / portainer-tooltip >
< / label >
< div class = "col-sm-5" >
< slider model = "ctrl.formValues.CpuLimit" floor = "ctrl.state.sliders.cpu.min" ceil = "ctrl.state.sliders.cpu.max" step = "0.10" precision = "2" > < / slider >
< / div >
< div class = "col-sm-4" style = "margin-top: 20px;" >
< p class = "small text-muted" >
Maximum CPU usage
< / p >
< / div >
< / div >
<!-- !cpu - limit - input -->
2020-08-12 23:30:23 +00:00
<!-- #endregion -->
2020-07-05 23:21:03 +00:00
< div class = "col-sm-12 form-section-title" >
Deployment
< / div >
2020-08-12 23:30:23 +00:00
<!-- #region DEPLOYMENT -->
2020-07-05 23:21:03 +00:00
< div class = "form-group" >
< div class = "col-sm-12 small text-muted" >
Select how you want to deploy your application inside the cluster.
< / div >
< / div >
<!-- deployment options -->
< div class = "form-group" style = "margin-bottom: 0;" >
< div class = "boxselector_wrapper" >
< div >
< input type = "radio" id = "deployment_replicated" ng-value = "ctrl.ApplicationDeploymentTypes.REPLICATED" ng-model = "ctrl.formValues.DeploymentType" / >
< label for = "deployment_replicated" >
< div class = "boxselector_header" >
< i class = "fa fa-cube" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
Replicated
< / div >
< p > Run one or multiple instances of this container< / p >
< / label >
< / div >
< div style = "color: #767676;" ng-if = "!ctrl.supportGlobalDeployment()" >
< input type = "radio" id = "deployment_global" disabled / >
< label
for="deployment_global"
tooltip-append-to-body="true"
tooltip-placement="bottom"
tooltip-class="portainer-tooltip"
uib-tooltip="The storage or access policy used for persisted folders cannot be used with this option"
style="cursor: pointer; border-color: #767676;"
>
< div class = "boxselector_header" >
< i class = "fa fa-cubes" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
Global
< / div >
< p > Deploy an instance of this container on each node of the cluster< / p >
< / label >
< / div >
< div ng-if = "ctrl.supportGlobalDeployment()" >
2020-08-04 22:08:11 +00:00
< input
type="radio"
id="deployment_global"
ng-value="ctrl.ApplicationDeploymentTypes.GLOBAL"
ng-model="ctrl.formValues.DeploymentType"
ng-click="ctrl.unselectAutoScaler()"
/>
2020-07-05 23:21:03 +00:00
< label for = "deployment_global" >
< div class = "boxselector_header" >
< i class = "fa fa-cubes" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
Global
< / div >
< p > Deploy an instance of this container on each node of the cluster< / p >
< / label >
< / div >
< / div >
< / div >
<!-- !deployment options -->
<!-- replica count -->
< div class = "form-group form-inline" ng-if = "ctrl.formValues.DeploymentType === ctrl.ApplicationDeploymentTypes.REPLICATED" >
< div class = "col-sm-12" >
< label class = "control-label text-left" >
Instance count
< / label >
< input
type="number"
2020-12-13 04:22:46 +00:00
name="replica_count"
2020-07-05 23:21:03 +00:00
class="form-control"
min="1"
max="9999"
placeholder="1"
style="margin-left: 20px;"
ng-model="ctrl.formValues.ReplicaCount"
ng-disabled="!ctrl.supportScalableReplicaDeployment()"
2020-12-13 04:22:46 +00:00
ng-change="ctrl.onChangeVolumeRequestedSize()"
required
2020-07-05 23:21:03 +00:00
/>
< / div >
< / div >
2020-12-13 04:22:46 +00:00
< div class = "form-group" ng-if = "kubernetesApplicationCreationForm['replica_count'].$invalid" >
< div class = "col-sm-12 small text-warning" >
< ng-messages for = "kubernetesApplicationCreationForm['replica_count'].$error" >
< p ng-message = "required" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Instance count is required.< / p >
< p ng-message = "min" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Instance count must be greater than 0.< / p >
< / ng-messages >
< / div >
< / div >
2020-07-05 23:21:03 +00:00
<!-- !replica count -->
< div
class="form-group"
ng-if="!ctrl.resourceReservationsOverflow() & & ctrl.formValues.ReplicaCount > 1 & & (ctrl.formValues.CpuLimit !== 0 || ctrl.formValues.MemoryLimit !== 0)"
>
< div class = "col-sm-12 small text-muted" >
< i class = "fa fa-info-circle blue-icon" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
This application will reserve the following resources: < b > {{ ctrl.formValues.CpuLimit * ctrl.formValues.ReplicaCount | kubernetesApplicationCPUValue }} CPU< / b > and
< b > {{ ctrl.formValues.MemoryLimit * ctrl.formValues.ReplicaCount }} MB< / b > of memory.
< / div >
< / div >
< div class = "form-group" ng-if = "ctrl.resourceReservationsOverflow()" >
2021-01-13 03:13:27 +00:00
< div class = "col-sm-12 small text-danger" >
< i class = "fa fa-exclamation-circle red-icon" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
2020-07-05 23:21:03 +00:00
This application would exceed available resources. Please review resource reservations or the instance count.
< / div >
< / div >
< div class = "form-group" ng-if = "!ctrl.supportScalableReplicaDeployment()" >
< div class = "col-sm-12 small text-muted" >
< i class = "fa fa-exclamation-circle orange-icon" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
The following storage option(s) do not support concurrent access from multiples instances: < code > {{ ctrl.getNonScalableStorage() }}< /code
>. You will not be able to scale that application.
< / div >
< / div >
2020-08-12 23:30:23 +00:00
<!-- #endregion -->
2020-07-05 23:21:03 +00:00
2020-08-12 23:30:23 +00:00
<!-- #region AUTO SCALING -->
2020-08-04 22:08:11 +00:00
< div class = "col-sm-12 form-section-title" ng-if = "ctrl.formValues.DeploymentType !== ctrl.ApplicationDeploymentTypes.GLOBAL" >
Auto-scaling
< / div >
< div class = "form-group" ng-if = "ctrl.formValues.DeploymentType !== ctrl.ApplicationDeploymentTypes.GLOBAL && ctrl.state.useServerMetrics" >
< div class = "col-sm-12" >
< label for = "enable_auto_scaling" class = "control-label text-left" >
Enable auto scaling for this application
< / label >
< label class = "switch" style = "margin-left: 20px;" >
< input type = "checkbox" class = "form-control" name = "enable_auto_scaling" ng-model = "ctrl.formValues.AutoScaler.IsUsed" / >
< i > < / i >
< / label >
< / div >
< / div >
< div class = "form-group" ng-if = "ctrl.formValues.DeploymentType !== ctrl.ApplicationDeploymentTypes.GLOBAL && !ctrl.state.useServerMetrics" >
< div class = "col-sm-12 small text-muted" >
< p ng-if = "!ctrl.isAdmin" >
This feature is currently disabled and must be enabled by an administrator user.
< / p >
< p ng-if = "ctrl.isAdmin" >
Server metrics features must be enabled in the
< a ui-sref = "portainer.endpoints.endpoint.kubernetesConfig({id: ctrl.endpoint.Id})" class = "ctrl.isAdmin" > endpoint configuration view< / a > .
< / p >
< / div >
< / div >
2020-08-14 04:56:56 +00:00
< div class = "form-inline" ng-if = "ctrl.formValues.DeploymentType !== ctrl.ApplicationDeploymentTypes.GLOBAL && ctrl.formValues.AutoScaler.IsUsed" >
2020-08-04 22:08:11 +00:00
< table class = "table" style = "margin-bottom: 0px;" >
< tbody >
< tr class = "small" >
< td style = "width: 33%; border: none; padding: 2px 0 2px 0;" > Minimum instances< / td >
< td style = "width: 33%; border: none; padding: 2px 0 2px 0;" > Maximum instances< / td >
< td style = "width: 33%; border: none; padding: 2px 0 2px 0;" >
Target CPU usage (< b > %< / b > )
< portainer-tooltip position = "bottom" message = "The autoscaler will ensure enough instances are running to maintain an average CPU usage across all instances." >
< / portainer-tooltip >
< / td >
< / tr >
< tr >
< td style = "padding: 8px 5px 5px 0; border: none;" >
< div class = "input-group input-group-sm" style = "width: 100%;" >
< input
type="number"
class="form-control"
name="auto_scaler_min"
min="0"
ng-max="ctrl.formValues.AutoScaler.MaxReplicas"
ng-model="ctrl.formValues.AutoScaler.MinReplicas"
required
/>
< / div >
< div class = "input-group input-group-sm" ng-show = "kubernetesApplicationCreationForm['auto_scaler_min'].$invalid" >
< div class = "small text-warning" style = "margin-top: 5px;" >
< ng-messages for = "kubernetesApplicationCreationForm['auto_scaler_min'].$error" >
< p ng-message = "required" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Minimum instances is required.< / p >
< p ng-message = "min" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Minimum instances must be greater than 0.< / p >
< p ng-message = "max" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Minimum instances must be smaller than maximum instances.< / p >
< / ng-messages >
< / div >
< / div >
< / td >
< td style = "padding: 8px 5px 5px 0; border: none;" >
< div class = "input-group input-group-sm" style = "width: 100%;" >
< input
type="number"
class="form-control"
name="auto_scaler_max"
ng-min="ctrl.formValues.AutoScaler.MinReplicas"
ng-model="ctrl.formValues.AutoScaler.MaxReplicas"
/>
< / div >
< div class = "input-group input-group-sm" ng-show = "kubernetesApplicationCreationForm['auto_scaler_max'].$invalid || ctrl.autoScalerOverflow()" >
< div class = "small text-warning" style = "margin-top: 5px;" >
< ng-messages for = "kubernetesApplicationCreationForm['auto_scaler_max'].$error" >
< p ng-message = "required" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Maximum instances is required.< / p >
< p ng-message = "min" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Maximum instances must be greater than minimum instances.< / p >
< / ng-messages >
< / div >
< / div >
< / td >
< td style = "padding: 8px 5px 5px 0; border: none;" >
< div class = "input-group input-group-sm" style = "width: 100%;" >
< input type = "number" class = "form-control" name = "auto_scaler_cpu" ng-model = "ctrl.formValues.AutoScaler.TargetCPUUtilization" min = "1" max = "100" required / >
< / div >
< div class = "input-group input-group-sm" ng-show = "kubernetesApplicationCreationForm['auto_scaler_cpu'].$invalid" >
< div class = "small text-warning" style = "margin-top: 5px;" >
< ng-messages for = "kubernetesApplicationCreationForm['auto_scaler_cpu'].$error" >
< p ng-message = "required" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Target CPU usage is required.< / p >
< p ng-message = "min" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Target CPU usage must be greater than 0.< / p >
< p ng-message = "max" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Target CPU usage must be smaller than 100.< / p >
< / ng-messages >
< / div >
< / div >
< / td >
< / tr >
< / tbody >
< / table >
< div class = "form-group" ng-if = "ctrl.autoScalerOverflow()" style = "margin-bottom: 10px;" >
2021-01-13 03:13:27 +00:00
< div class = "col-sm-12 small text-danger" >
< i class = "fa fa-exclamation-circle red-icon" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
2020-08-04 22:08:11 +00:00
This application would exceed available resources. Please review resource reservations or the maximum instance count of the auto-scaling policy.
< / div >
< / div >
< / div >
2020-08-12 23:30:23 +00:00
<!-- #endregion -->
2020-08-04 22:08:11 +00:00
2020-08-13 23:56:53 +00:00
< div ng-if = "ctrl.formValues.DeploymentType === ctrl.ApplicationDeploymentTypes.REPLICATED" >
< div class = "col-sm-12 form-section-title" >
Placement preferences and constraints
< / div >
2020-08-15 00:09:43 +00:00
<!-- #region PLACEMENTS -->
2020-08-13 23:56:53 +00:00
< div class = "form-group" >
2020-08-15 00:09:43 +00:00
< div class = "col-sm-12" >
2020-08-13 23:56:53 +00:00
< label class = "control-label text-left" > Placement rules< / label >
< span class = "label label-default interactive" style = "margin-left: 10px;" ng-click = "ctrl.addPlacement()" >
< i class = "fa fa-plus-circle" aria-hidden = "true" > < / i > add rule
< / span >
< / div >
2020-08-15 00:09:43 +00:00
< div class = "col-sm-12 small text-muted" ng-if = "ctrl.formValues.Placements.length > 0" style = "margin-top: 10px;" >
< i class = "fa fa-info-circle blue-icon" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
2020-08-15 22:11:56 +00:00
Deploy this application on nodes that respect < b > ALL< / b > of the following placement rules. Placement rules are based on node labels.
2020-08-15 00:09:43 +00:00
< / div >
2020-08-13 23:56:53 +00:00
< div class = "col-sm-12 form-inline" style = "margin-top: 10px;" >
2020-08-15 22:11:56 +00:00
< div ng-repeat-start = "placement in ctrl.formValues.Placements" style = "margin-top: 2px;" >
2020-08-13 23:56:53 +00:00
< div class = "col-sm-5 input-group" ng-class = "{ striked: placement.NeedsDeletion }" >
< select
class="form-control"
ng-model="placement.Label"
ng-options="label as (label.Key | kubernetesNodeLabelHumanReadbleText) for label in ctrl.nodesLabels"
2020-08-15 22:11:56 +00:00
ng-change="ctrl.onChangePlacementLabel($index)"
2020-08-13 23:56:53 +00:00
ng-disabled="ctrl.isEditAndNotNewPlacement($index)"
>
< / select >
< / div >
< div class = "col-sm-5 input-group" ng-class = "{ striked: placement.NeedsDeletion }" >
< select
class="form-control"
ng-model="placement.Value"
ng-options="value for value in placement.Label.Values"
ng-disabled="ctrl.isEditAndNotNewPlacement($index)"
>
< / select >
< / div >
< div class = "col-sm-1 input-group" >
< button ng-if = "!placement.NeedsDeletion" class = "btn btn-sm btn-danger" type = "button" ng-click = "ctrl.removePlacement($index)" >
< i class = "fa fa-trash-alt" aria-hidden = "true" > < / i >
< / button >
< button ng-if = "placement.NeedsDeletion" class = "btn btn-sm btn-primary" type = "button" ng-click = "ctrl.restorePlacement($index)" >
< i class = "fa fa-trash-restore" aria-hidden = "true" > < / i >
< / button >
< / div >
< / div >
2020-08-15 22:11:56 +00:00
< div ng-repeat-end ng-show = "ctrl.state.duplicates.placements.refs[$index] !== undefined" >
< div class = "col-sm-5 input-group" >
< div class = "small text-warning" style = "margin-top: 5px;" ng-if = "ctrl.state.duplicates.placements.refs[$index] !== undefined" >
< p ng-if = "ctrl.state.duplicates.placements.refs[$index] !== undefined" >
< i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > This label is already defined.
< / p >
< / div >
< / div >
< / div >
2020-08-13 23:56:53 +00:00
< / div >
< / div >
< div ng-if = "ctrl.showPlacementPolicySection()" >
< div class = "form-group" >
< div class = "col-sm-12" >
< label class = "control-label text-left" > Placement policy< / label >
< / div >
< / div >
< div class = "form-group" >
< div class = "col-sm-12 small text-muted" >
Specify the policy associated to the placement rules.
< / div >
< / div >
<!-- placement policy options -->
< div class = "form-group" style = "margin-bottom: 0;" ng-if = "ctrl.formValues.Placements.length" >
< div class = "boxselector_wrapper" >
< div >
< input type = "radio" id = "placement_soft" ng-value = "ctrl.ApplicationPlacementTypes.PREFERRED" ng-model = "ctrl.formValues.PlacementType" / >
< label for = "placement_soft" >
< div class = "boxselector_header" >
< i class = "fa fa-list" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
Preferred
< / div >
< p > Schedule this application on nodes that match the rules if possible< / p >
< / label >
< / div >
< div >
< input type = "radio" id = "placement_hard" ng-value = "ctrl.ApplicationPlacementTypes.MANDATORY" ng-model = "ctrl.formValues.PlacementType" / >
< label for = "placement_hard" >
< div class = "boxselector_header" >
< i class = "fa fa-tasks" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
Mandatory
< / div >
2020-08-15 00:05:50 +00:00
< p > Schedule this application < b > ONLY< / b > on nodes that match < b > ALL< / b > Rules< / p >
2020-08-13 23:56:53 +00:00
< / label >
< / div >
< / div >
< / div >
<!-- !placement policy options -->
< / div >
<!-- #endregion -->
< / div >
2020-07-05 23:21:03 +00:00
< div class = "col-sm-12 form-section-title" >
Publishing the application
< / div >
2020-08-12 23:30:23 +00:00
<!-- #region PUBLISHING OPTIONS -->
2020-07-05 23:21:03 +00:00
< div class = "form-group" >
< div class = "col-sm-12 small text-muted" >
Select how you want to publish your application.
< / div >
< / div >
<!-- publishing options -->
< div class = "form-group" style = "margin-bottom: 0;" >
< div class = "boxselector_wrapper" >
2020-08-12 23:30:23 +00:00
< div ng-style = "{ color: ctrl.isPublishingTypeEditDisabled() ? '#767676' : '' }" >
< input
type="radio"
id="publishing_internal"
ng-value="ctrl.ApplicationPublishingTypes.INTERNAL"
ng-model="ctrl.formValues.PublishingType"
ng-change="ctrl.onChangePublishedPorts()"
ng-disabled="ctrl.isPublishingTypeEditDisabled()"
/>
< label
for="publishing_internal"
ng-if="
!ctrl.isPublishingTypeEditDisabled() || (ctrl.isPublishingTypeEditDisabled() & & ctrl.formValues.PublishingType === ctrl.ApplicationPublishingTypes.INTERNAL)
"
>
< div class = "boxselector_header" >
< i class = "fa fa-list-alt" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
Internal
< / div >
< p > Internal communications inside the cluster only< / p >
< / label >
< label
for="publishing_internal"
ng-if="ctrl.isPublishingTypeEditDisabled() & & ctrl.formValues.PublishingType !== ctrl.ApplicationPublishingTypes.INTERNAL"
tooltip-append-to-body="true"
tooltip-placement="bottom"
tooltip-class="portainer-tooltip"
uib-tooltip="Changing the publishing mode is not allowed until you delete all previously existing ports"
style="cursor: pointer; border-color: #767676;"
>
2020-07-05 23:21:03 +00:00
< div class = "boxselector_header" >
< i class = "fa fa-list-alt" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
Internal
< / div >
< p > Internal communications inside the cluster only< / p >
< / label >
< / div >
2020-08-12 23:30:23 +00:00
< div ng-style = "{ color: ctrl.isPublishingTypeEditDisabled() ? '#767676' : '' }" >
< input
type="radio"
id="publishing_cluster"
ng-value="ctrl.ApplicationPublishingTypes.CLUSTER"
ng-model="ctrl.formValues.PublishingType"
ng-change="ctrl.onChangePublishedPorts()"
ng-disabled="ctrl.isPublishingTypeEditDisabled()"
/>
< label
for="publishing_cluster"
ng-if="
!ctrl.isPublishingTypeEditDisabled() || (ctrl.isPublishingTypeEditDisabled() & & ctrl.formValues.PublishingType === ctrl.ApplicationPublishingTypes.CLUSTER)
"
>
< div class = "boxselector_header" >
< i class = "fa fa-list" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
Cluster
< / div >
< p > Publish this application via a port on all nodes of the cluster< / p >
< / label >
< label
for="publishing_cluster"
ng-if="ctrl.isPublishingTypeEditDisabled() & & ctrl.formValues.PublishingType !== ctrl.ApplicationPublishingTypes.CLUSTER"
tooltip-append-to-body="true"
tooltip-placement="bottom"
tooltip-class="portainer-tooltip"
uib-tooltip="Changing the publishing mode is not allowed until you delete all previously existing ports"
style="cursor: pointer; border-color: #767676;"
>
2020-07-05 23:21:03 +00:00
< div class = "boxselector_header" >
< i class = "fa fa-list" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
Cluster
< / div >
< p > Publish this application via a port on all nodes of the cluster< / p >
< / label >
< / div >
2020-08-12 23:30:23 +00:00
< div ng-if = "ctrl.publishViaIngressEnabled()" ng-style = "{ color: ctrl.isPublishingTypeEditDisabled() ? '#767676' : '' }" >
< input
type="radio"
id="publishing_ingress"
ng-value="ctrl.ApplicationPublishingTypes.INGRESS"
ng-model="ctrl.formValues.PublishingType"
ng-change="ctrl.onChangePublishedPorts()"
ng-disabled="ctrl.isPublishingTypeEditDisabled()"
/>
< label
for="publishing_ingress"
ng-if="
!ctrl.isPublishingTypeEditDisabled() || (ctrl.isPublishingTypeEditDisabled() & & ctrl.formValues.PublishingType === ctrl.ApplicationPublishingTypes.INGRESS)
"
>
< div class = "boxselector_header" >
< i class = "fa fa-route" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
Ingress
< / div >
< p > Publish this application via a HTTP route< / p >
< / label >
< label
for="publishing_ingress"
ng-if="ctrl.isPublishingTypeEditDisabled() & & ctrl.formValues.PublishingType !== ctrl.ApplicationPublishingTypes.INGRESS"
tooltip-append-to-body="true"
tooltip-placement="bottom"
tooltip-class="portainer-tooltip"
uib-tooltip="Changing the publishing mode is not allowed until you delete all previously existing ports"
style="cursor: pointer; border-color: #767676;"
>
< div class = "boxselector_header" >
< i class = "fa fa-route" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
Ingress
< / div >
< p > Publish this application via a HTTP route< / p >
< / label >
< / div >
< div ng-if = "ctrl.publishViaLoadBalancerEnabled()" ng-style = "{ color: ctrl.isPublishingTypeEditDisabled() ? '#767676' : '' }" >
< input
type="radio"
id="publishing_loadbalancer"
ng-value="ctrl.ApplicationPublishingTypes.LOAD_BALANCER"
ng-model="ctrl.formValues.PublishingType"
ng-change="ctrl.onChangePublishedPorts()"
ng-disabled="ctrl.isPublishingTypeEditDisabled()"
/>
< label
for="publishing_loadbalancer"
ng-if="
!ctrl.isPublishingTypeEditDisabled() ||
(ctrl.isPublishingTypeEditDisabled() & & ctrl.formValues.PublishingType === ctrl.ApplicationPublishingTypes.LOAD_BALANCER)
"
>
< div class = "boxselector_header" >
< i class = "fa fa-project-diagram" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
Load balancer
< / div >
< p > Publish this application via a load balancer< / p >
< / label >
< label
for="publishing_loadbalancer"
ng-if="ctrl.isPublishingTypeEditDisabled() & & ctrl.formValues.PublishingType !== ctrl.ApplicationPublishingTypes.LOAD_BALANCER"
tooltip-append-to-body="true"
tooltip-placement="bottom"
tooltip-class="portainer-tooltip"
uib-tooltip="Changing the publishing mode is not allowed until you delete all previously existing ports"
style="cursor: pointer; border-color: #767676;"
>
2020-07-05 23:21:03 +00:00
< div class = "boxselector_header" >
< i class = "fa fa-project-diagram" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
Load balancer
< / div >
< p > Publish this application via a load balancer< / p >
< / label >
< / div >
< / div >
< / div >
2020-08-12 23:30:23 +00:00
<!-- #endregion -->
2020-07-05 23:21:03 +00:00
2020-08-12 23:30:23 +00:00
<!-- #region PUBLISHED PORTS -->
2020-07-05 23:21:03 +00:00
< div class = "form-group" >
< div class = "col-sm-12" style = "margin-top: 5px;" >
< label class = "control-label text-left" > Published ports< / label >
< span class = "label label-default interactive" style = "margin-left: 10px;" ng-click = "ctrl.addPublishedPort()" ng-if = "!ctrl.disableLoadBalancerEdit()" >
< i class = "fa fa-plus-circle" aria-hidden = "true" > < / i > publish a new port
< / span >
< / div >
< div
class="col-sm-12 small text-muted"
style="margin-top: 15px;"
ng-if="ctrl.formValues.PublishingType === ctrl.ApplicationPublishingTypes.CLUSTER & & ctrl.formValues.PublishedPorts.length > 0"
>
< i class = "fa fa-info-circle blue-icon" aria-hidden = "true" style = "margin-right: 2px;" > < / i >
When publishing a port in cluster mode, the node port is optional. If left empty Kubernetes will use a random port number. If you wish to specify a port, use a port
number inside the default range < code > 30000-32767< / code > .
< / div >
2020-08-12 23:30:23 +00:00
< div ng-if = "ctrl.isNotInternalAndHasNoPublishedPorts()" class = "col-sm-12 small text-muted text-warning" style = "margin-top: 12px;" >
< i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > At least one published port must be defined.
< / div >
2020-07-05 23:21:03 +00:00
< div class = "col-sm-12 form-inline" style = "margin-top: 10px;" >
2020-08-12 23:30:23 +00:00
<!-- #region INPUTS -->
2020-07-05 23:21:03 +00:00
< div
ng-repeat-start="publishedPort in ctrl.formValues.PublishedPorts"
style="margin-top: 2px;"
tooltip-append-to-body="true"
tooltip-placement="bottom"
tooltip-class="portainer-tooltip"
tooltip-enable="ctrl.disableLoadBalancerEdit()"
2020-08-12 23:30:23 +00:00
uib-tooltip="Edition is not allowed while the Load Balancer is in 'Pending' state"
2020-07-05 23:21:03 +00:00
>
2020-08-12 23:30:23 +00:00
< div class = "col-sm-3 input-group input-group-sm" ng-class = "{ striked: publishedPort.NeedsDeletion }" >
2020-07-05 23:21:03 +00:00
< span class = "input-group-addon" > container port< / span >
< input
type="number"
class="form-control"
name="container_port_{{ $index }}"
ng-model="publishedPort.ContainerPort"
placeholder="80"
ng-min="1"
ng-max="65535"
2020-08-12 23:30:23 +00:00
ng-required="!publishedPort.NeedsDeletion"
ng-change="ctrl.onChangePortMappingContainerPort()"
ng-disabled="ctrl.disableLoadBalancerEdit() || ctrl.isEditAndNotNewPublishedPort($index)"
2020-07-05 23:21:03 +00:00
/>
< / div >
2020-08-12 23:30:23 +00:00
< div
class="col-sm-3 input-group input-group-sm"
ng-class="{ striked: publishedPort.NeedsDeletion }"
ng-if="
(publishedPort.IsNew & & ctrl.formValues.PublishingType === ctrl.ApplicationPublishingTypes.CLUSTER) ||
(!publishedPort.IsNew & & ctrl.savedFormValues.PublishingType === ctrl.ApplicationPublishingTypes.CLUSTER)
"
>
2020-07-05 23:21:03 +00:00
< span class = "input-group-addon" > node port< / span >
< input
name="published_node_port_{{ $index }}"
type="number"
class="form-control"
ng-model="publishedPort.NodePort"
placeholder="30080"
ng-min="30000"
ng-max="32767"
2020-08-12 23:30:23 +00:00
ng-change="ctrl.onChangePortMappingNodePort()"
ng-disabled="ctrl.disableLoadBalancerEdit() || ctrl.isEditAndNotNewPublishedPort($index)"
2020-07-05 23:21:03 +00:00
/>
< / div >
2020-08-12 23:30:23 +00:00
< div
class="col-sm-3 input-group input-group-sm"
ng-class="{ striked: publishedPort.NeedsDeletion }"
ng-if="
(publishedPort.IsNew & & ctrl.formValues.PublishingType === ctrl.ApplicationPublishingTypes.LOAD_BALANCER) ||
(!publishedPort.IsNew & & ctrl.savedFormValues.PublishingType === ctrl.ApplicationPublishingTypes.LOAD_BALANCER)
"
>
2020-07-05 23:21:03 +00:00
< span class = "input-group-addon" > load balancer port< / span >
< input
type="number"
class="form-control"
name="load_balancer_port_{{ $index }}"
ng-model="publishedPort.LoadBalancerPort"
placeholder="80"
value="8080"
ng-min="1"
ng-max="65535"
2020-08-12 23:30:23 +00:00
ng-required="!publishedPort.NeedsDeletion"
2021-02-02 09:37:37 +00:00
ng-change="ctrl.onChangePortMappingLoadBalancer()"
2020-08-12 23:30:23 +00:00
ng-disabled="ctrl.disableLoadBalancerEdit() || ctrl.isEditAndNotNewPublishedPort($index)"
2020-07-05 23:21:03 +00:00
/>
< / div >
2020-08-12 23:30:23 +00:00
< div
class="col-sm-3 input-group input-group-sm"
ng-class="{ striked: publishedPort.NeedsDeletion }"
ng-if="
(publishedPort.IsNew & & ctrl.formValues.PublishingType === ctrl.ApplicationPublishingTypes.INGRESS) ||
(!publishedPort.IsNew & & ctrl.savedFormValues.PublishingType === ctrl.ApplicationPublishingTypes.INGRESS)
"
>
< span class = "input-group-addon" > ingress< / span >
< select
class="form-control"
name="ingress_class_{{ $index }}"
ng-model="publishedPort.IngressName"
ng-options="ingress.Name as ingress.Name for ingress in ctrl.filteredIngresses"
ng-required="!publishedPort.NeedsDeletion"
ng-change="ctrl.onChangePortMappingIngress($index)"
ng-disabled="ctrl.disableLoadBalancerEdit() || ctrl.isEditAndNotNewPublishedPort($index)"
>
< option selected disabled hidden value = "" > Select an ingress< / option >
< / select >
< / div >
< div
class="col-sm-3 input-group input-group-sm"
ng-class="{ striked: publishedPort.NeedsDeletion }"
ng-if="
(publishedPort.IsNew & & ctrl.formValues.PublishingType === ctrl.ApplicationPublishingTypes.INGRESS) ||
(!publishedPort.IsNew & & ctrl.savedFormValues.PublishingType === ctrl.ApplicationPublishingTypes.INGRESS)
"
>
< span class = "input-group-addon" > route< / span >
< input
class="form-control"
name="ingress_route_{{ $index }}"
ng-model="publishedPort.IngressRoute"
2020-08-20 00:51:14 +00:00
placeholder="route"
2020-08-12 23:30:23 +00:00
ng-required="!publishedPort.NeedsDeletion"
ng-change="ctrl.onChangePortMappingIngressRoute()"
2020-08-20 00:51:14 +00:00
ng-pattern="/^(\/?[a-zA-Z0-9]+([a-zA-Z0-9-/_]*[a-zA-Z0-9])?|[a-zA-Z0-9]+)|(\/){1}$/"
2020-08-12 23:30:23 +00:00
ng-disabled="ctrl.disableLoadBalancerEdit() || ctrl.isEditAndNotNewPublishedPort($index)"
/>
< / div >
< div class = "input-group col-sm-2 input-group-sm" >
< div class = "btn-group btn-group-sm" ng-class = "{ striked: publishedPort.NeedsDeletion }" >
< label
class="btn btn-primary"
ng-model="publishedPort.Protocol"
uib-btn-radio="'TCP'"
2021-01-15 01:51:36 +00:00
ng-change="ctrl.onChangePortProtocol($index)"
2020-08-12 23:30:23 +00:00
ng-disabled="ctrl.isProtocolOptionDisabled($index, 'TCP')"
>TCP< /label
>
< label
class="btn btn-primary"
ng-model="publishedPort.Protocol"
uib-btn-radio="'UDP'"
2021-01-15 01:51:36 +00:00
ng-change="ctrl.onChangePortProtocol($index)"
2020-08-12 23:30:23 +00:00
ng-disabled="ctrl.isProtocolOptionDisabled($index, 'UDP')"
>UDP< /label
>
2020-07-05 23:21:03 +00:00
< / div >
2020-08-12 23:30:23 +00:00
< button
ng-if="!ctrl.disableLoadBalancerEdit() & & !publishedPort.NeedsDeletion"
class="btn btn-sm btn-danger"
type="button"
ng-click="ctrl.removePublishedPort($index)"
>
< i class = "fa fa-trash-alt" aria-hidden = "true" > < / i >
< / button >
< button
ng-if="publishedPort.NeedsDeletion & & ctrl.formValues.PublishingType === ctrl.savedFormValues.PublishingType"
class="btn btn-sm btn-primary"
type="button"
ng-click="ctrl.restorePublishedPort($index)"
>
< i class = "fa fa-trash-restore" aria-hidden = "true" > < / i >
2020-07-05 23:21:03 +00:00
< / button >
< / div >
< / div >
2020-08-12 23:30:23 +00:00
<!-- #endregion -->
2020-07-05 23:21:03 +00:00
2020-08-12 23:30:23 +00:00
<!-- #region VALIDATION -->
2020-07-05 23:21:03 +00:00
< div
ng-repeat-end
2020-08-12 23:30:23 +00:00
ng-show="
2020-07-05 23:21:03 +00:00
kubernetesApplicationCreationForm['container_port_' + $index].$invalid ||
kubernetesApplicationCreationForm['published_node_port_' + $index].$invalid ||
2020-08-12 23:30:23 +00:00
kubernetesApplicationCreationForm['load_balancer_port_' + $index].$invalid ||
kubernetesApplicationCreationForm['ingress_class_' + $index].$invalid ||
kubernetesApplicationCreationForm['ingress_route_' + $index].$invalid ||
ctrl.state.duplicates.publishedPorts.containerPorts.refs[$index] !== undefined ||
(ctrl.formValues.PublishingType === ctrl.ApplicationPublishingTypes.CLUSTER & & ctrl.state.duplicates.publishedPorts.nodePorts.refs[$index] !== undefined) ||
(ctrl.formValues.PublishingType === ctrl.ApplicationPublishingTypes.INGRESS & & ctrl.state.duplicates.publishedPorts.ingressRoutes.refs[$index] !== undefined) ||
(ctrl.formValues.PublishingType === ctrl.ApplicationPublishingTypes.LOAD_BALANCER & &
ctrl.state.duplicates.publishedPorts.loadBalancerPorts.refs[$index] !== undefined)
2020-07-05 23:21:03 +00:00
"
>
2020-08-12 23:30:23 +00:00
< div class = "col-sm-3 input-group input-group-sm" >
< div
class="small text-warning"
style="margin-top: 5px;"
ng-if="
kubernetesApplicationCreationForm['container_port_' + $index].$invalid || ctrl.state.duplicates.publishedPorts.containerPorts.refs[$index] !== undefined
"
>
2020-07-05 23:21:03 +00:00
< div ng-messages = "kubernetesApplicationCreationForm['container_port_'+$index].$error" >
< p ng-message = "required" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Container port number is required.< / p >
< p ng-message = "min" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Container port number must be inside the range 1-65535.< / p >
< p ng-message = "max" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Container port number must be inside the range 1-65535.< / p >
< / div >
2020-08-12 23:30:23 +00:00
< p ng-if = "ctrl.state.duplicates.publishedPorts.containerPorts.refs[$index] !== undefined" >
< i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > This port is already used.
< / p >
2020-07-05 23:21:03 +00:00
< / div >
< / div >
2020-08-12 23:30:23 +00:00
< div class = "col-sm-3 input-group input-group-sm" ng-if = "ctrl.formValues.PublishingType === ctrl.ApplicationPublishingTypes.CLUSTER" >
< div
class="small text-warning"
style="margin-top: 5px;"
ng-if="
kubernetesApplicationCreationForm['published_node_port_' + $index].$invalid || ctrl.state.duplicates.publishedPorts.nodePorts.refs[$index] !== undefined
"
>
2020-07-05 23:21:03 +00:00
< div ng-messages = "kubernetesApplicationCreationForm['published_node_port_'+$index].$error" >
< p ng-message = "min" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Node port number must be inside the range 30000-32767.< / p >
< p ng-message = "max" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Node port number must be inside the range 30000-32767.< / p >
< / div >
2020-08-12 23:30:23 +00:00
< p ng-if = "ctrl.state.duplicates.publishedPorts.nodePorts.refs[$index] !== undefined" >
< i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > This port is already used.
< / p >
< / div >
< / div >
< div class = "col-sm-3 input-group input-group-sm" ng-if = "ctrl.formValues.PublishingType === ctrl.ApplicationPublishingTypes.INGRESS" >
< div class = "small text-warning" style = "margin-top: 5px;" ng-if = "kubernetesApplicationCreationForm['ingress_class_' + $index].$invalid" >
< div ng-messages = "kubernetesApplicationCreationForm['ingress_class_'+$index].$error" >
< p ng-message = "required" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Ingress selection is required.< / p >
< / div >
< / div >
< / div >
< div class = "col-sm-3 input-group input-group-sm" ng-if = "ctrl.formValues.PublishingType === ctrl.ApplicationPublishingTypes.INGRESS" >
< div
class="small text-warning"
style="margin-top: 5px;"
ng-if="kubernetesApplicationCreationForm['ingress_route_' + $index].$invalid || ctrl.state.duplicates.publishedPorts.ingressRoutes.refs[$index] !== undefined"
>
< div ng-messages = "kubernetesApplicationCreationForm['ingress_route_'+$index].$error" >
< p ng-message = "required" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Route is required.< / p >
< p ng-message = "pattern"
>< i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > This field must consist of alphanumeric characters or the special characters: '-', '_' or
'/'. It must start and end with an alphanumeric character (e.g. 'my-route', or 'route-123').< /p
>
< / div >
< p ng-if = "ctrl.state.duplicates.publishedPorts.ingressRoutes.refs[$index] !== undefined" >
< i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > This route is already used.
< / p >
2020-07-05 23:21:03 +00:00
< / div >
< / div >
2020-08-12 23:30:23 +00:00
< div class = "col-sm-3 input-group input-group-sm" ng-if = "ctrl.formValues.PublishingType === ctrl.ApplicationPublishingTypes.LOAD_BALANCER" >
< div
class="small text-warning"
style="margin-top: 5px;"
ng-if="
kubernetesApplicationCreationForm['load_balancer_port_' + $index].$invalid ||
ctrl.state.duplicates.publishedPorts.loadBalancerPorts.refs[$index] !== undefined
"
>
2020-07-05 23:21:03 +00:00
< div ng-messages = "kubernetesApplicationCreationForm['load_balancer_port_'+$index].$error" >
< p ng-message = "required" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Load balancer port number is required.< / p >
< p ng-message = "min" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Load balancer port number must be inside the range 1-65535.< / p >
< p ng-message = "max" > < i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i > Load balancer port number must be inside the range 1-65535.< / p >
< / div >
2020-08-12 23:30:23 +00:00
< p ng-if = "ctrl.state.duplicates.publishedPorts.loadBalancerPorts.refs[$index] !== undefined" >
< i class = "fa fa-exclamation-triangle" aria-hidden = "true" > < / i >
This port is already used.
< / p >
2020-07-05 23:21:03 +00:00
< / div >
< / div >
< div class = "input-group col-sm-1 input-group-sm" > < / div >
< / div >
2020-08-12 23:30:23 +00:00
<!-- #endregion -->
2020-07-05 23:21:03 +00:00
< / div >
< / div >
2020-08-12 23:30:23 +00:00
<!-- #endregion -->
2020-07-05 23:21:03 +00:00
< div class = "col-sm-12 form-section-title" >
Actions
< / div >
2020-08-12 23:30:23 +00:00
<!-- #region ACTIONS -->
2020-07-05 23:21:03 +00:00
< div class = "form-group" >
< div class = "col-sm-12" >
< button
type="button"
class="btn btn-primary btn-sm"
ng-disabled="!kubernetesApplicationCreationForm.$valid || ctrl.isDeployUpdateButtonDisabled()"
ng-click="ctrl.deployApplication()"
button-spinner="ctrl.state.actionInProgress"
>
< span ng-show = "!ctrl.state.isEdit && !ctrl.state.actionInProgress" > Deploy application< / span >
< span ng-show = "!ctrl.state.isEdit && ctrl.state.actionInProgress" > Deployment in progress...< / span >
< span ng-show = "ctrl.state.isEdit && !ctrl.state.actionInProgress" > Update application< / span >
< span ng-show = "ctrl.state.isEdit && ctrl.state.actionInProgress" > Update in progress...< / span >
< / button >
< button
ng-if="ctrl.state.isEdit & & !ctrl.state.actionInProgress"
type="button"
class="btn btn-sm btn-default"
ui-sref="kubernetes.applications.application({ name: ctrl.application.Name, namespace: ctrl.application.ResourcePool })"
>
2020-08-12 23:30:23 +00:00
Cancel
< / button >
2020-07-05 23:21:03 +00:00
< / div >
< / div >
2020-08-12 23:30:23 +00:00
<!-- #endregion -->
2020-07-05 23:21:03 +00:00
< / form >
< / rd-widget-body >
< / rd-widget >
< / div >
< / div >
< / div >