1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-04 13:25:26 +02:00

feat(k8s/applications): expose applications via ingress (#4136)

* feat(k8s/endpoint): expose ingress controllers on endpoints

* feat(k8s/applications): add ability to expose applications over ingress - missing RP and app edits

* feat(k8s/application): add validation for ingress routes

* feat(k8s/resource-pools): edit available ingress classes

* fix(k8s/ingress): var name refactor was partially applied

* feat(kubernetes): double validation on RP edit

* feat(k8s/application): app edit ingress update + formvalidation + UI rework

* feat(k8s/ingress): dictionary for default annotations on ingress creation

* fix(k8s/application): temporary fix + TODO dev notice

* feat(k8s/application): select default ingress of selected resource pool

* feat(k8s/ingress): revert ingressClassName removal

* feat(k8s/ingress): admins can now add an host to ingress in a resource pool

* feat(k8s/resource-pool): list applications using RP ingresses

* feat(k8s/configure): minor UI update

* feat(k8s/configure): minor UI update

* feat(k8s/configure): minor UI update

* feat(k8s/configure): minor UI update

* feat(k8s/configure): minor UI update

* fix(k8s/ingresses): remove host if undefined

* feat(k8s/resource-pool): remove the activate ingresses switch

* fix(k8s/resource-pool): edditing an ingress host was deleting all the routes of the ingress

* feat(k8s/application): prevent app deploy if no ports to publish and publishing type not internal

* feat(k8s/ingress): minor UI update

* fix(k8s/ingress): allow routes without prepending /

* feat(k8s/application): add form validation on ingress route

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
This commit is contained in:
xAt0mZ 2020-08-13 01:30:23 +02:00 committed by GitHub
parent 201c3ac143
commit f91d3f1ca3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 1595 additions and 443 deletions

View file

@ -16,7 +16,7 @@
<rd-widget>
<rd-widget-body>
<form class="form-horizontal" name="kubernetesApplicationCreationForm" autocomplete="off">
<!-- name -->
<!-- #region NAME FIELD -->
<div class="form-group">
<label for="application_name" class="col-sm-1 control-label text-left">Name</label>
<div class="col-sm-11">
@ -48,9 +48,9 @@
>
</div>
</div>
<!-- !name -->
<!-- #endregion -->
<!-- image -->
<!-- #region IMAGE FIELD -->
<div class="form-group">
<label for="container_image" class="col-sm-1 control-label text-left">Image</label>
<div class="col-sm-11">
@ -64,13 +64,12 @@
</div>
</div>
</div>
<!-- !image -->
<!-- #endregion -->
<div class="col-sm-12 form-section-title">
Resource pool
</div>
<!-- resource-pool -->
<!-- #region RESOURCE POOL -->
<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">
@ -91,12 +90,12 @@
resource pool.
</div>
</div>
<!-- !resource-pool -->
<!-- #endregion -->
<div class="col-sm-12 form-section-title">
Stack
</div>
<!-- #region STACK -->
<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>
@ -105,7 +104,6 @@
</div>
</div>
<!-- stack -->
<div class="form-group">
<label for="stack_name" class="col-sm-1 control-label text-left">Stack</label>
<div class="col-sm-11">
@ -121,13 +119,12 @@
/>
</div>
</div>
<!-- !stack -->
<!-- #endregion -->
<div class="col-sm-12 form-section-title">
Environment
</div>
<!-- environment-variables -->
<!-- #region ENVIRONMENT VARIABLES -->
<div class="form-group">
<div class="col-sm-12">
<label class="control-label text-left">Environment variables</label>
@ -146,7 +143,7 @@
name="environment_variable_name_{{ $index }}"
class="form-control"
ng-model="envVar.Name"
ng-change="ctrl.onChangeEnvironmentName($index)"
ng-change="ctrl.onChangeEnvironmentName()"
ng-pattern="/^[a-zA-Z]([-_a-zA-Z0-9]*[a-zA-Z0-9])?$/"
placeholder="foo"
required
@ -155,7 +152,9 @@
<div
class="small text-warning"
style="margin-top: 5px;"
ng-show="kubernetesApplicationCreationForm['environment_variable_name_' + $index].$invalid || ctrl.state.duplicateEnvironmentVariables[$index] !== undefined"
ng-show="
kubernetesApplicationCreationForm['environment_variable_name_' + $index].$invalid || ctrl.state.duplicates.environmentVariables.refs[$index] !== undefined
"
>
<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>
@ -164,7 +163,7 @@
character, and end with an alphanumeric character (e.g. 'my-var', or 'MY_VAR123').</p
>
</ng-messages>
<p ng-if="ctrl.state.duplicateEnvironmentVariables[$index] !== undefined"
<p ng-if="ctrl.state.duplicates.environmentVariables.refs[$index] !== undefined"
><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> This environment variable is already defined.</p
>
</div>
@ -177,22 +176,21 @@
<div class="input-group col-sm-2 input-group-sm">
<button ng-if="!envVar.NeedsDeletion" class="btn btn-sm btn-danger" type="button" ng-click="ctrl.removeEnvironmentVariable($index)">
<i class="fa fa-times" aria-hidden="true"></i>
<i class="fa fa-trash-alt" aria-hidden="true"></i>
</button>
<button ng-if="envVar.NeedsDeletion" class="btn btn-sm btn-primary" type="button" ng-click="ctrl.restoreEnvironmentVariable($index)">
Restore
<i class="fa fa-trash-restore" aria-hidden="true"></i>
</button>
</div>
</div>
</div>
</div>
<!-- !environment-variables -->
<!-- #endregion -->
<div class="col-sm-12 form-section-title">
Configurations
</div>
<!-- configurations -->
<!-- #region CONFIGURATIONS -->
<div class="form-group">
<div class="col-sm-12">
<label class="control-label text-left">Configurations</label>
@ -231,7 +229,7 @@
<button class="btn btn-sm btn-primary" type="button" ng-if="config.Overriden" ng-click="ctrl.resetConfiguration(index)">
<i class="fa fa-undo" aria-hidden="true"></i> Auto
</button>
<button class="btn btn-sm btn-danger" type="button" ng-click="ctrl.removeConfiguration(index)"> <i class="fa fa-trash" aria-hidden="true"></i> Remove </button>
<button class="btn btn-sm btn-danger" type="button" ng-click="ctrl.removeConfiguration(index)"> <i class="fa fa-trash-alt" aria-hidden="true"></i> Remove </button>
</div>
<!-- no-override -->
<div class="col-sm-12" style="margin-top: 10px;" ng-if="config.SelectedConfiguration && !config.Overriden">
@ -277,13 +275,13 @@
style="margin-top: 5px;"
ng-show="
kubernetesApplicationCreationForm['overriden_key_path_' + index + '_' + keyIndex].$invalid ||
ctrl.state.duplicateConfigurationPaths[index + '_' + keyIndex] !== undefined
ctrl.state.duplicates.configurationPaths.refs[index + '_' + keyIndex] !== undefined
"
>
<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>
<p ng-if="ctrl.state.duplicateConfigurationPaths[index + '_' + keyIndex] !== undefined"
<p ng-if="ctrl.state.duplicates.configurationPaths.refs[index + '_' + keyIndex] !== undefined"
><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> This path is already used.</p
>
</div>
@ -302,12 +300,12 @@
<!-- !has-override -->
</div>
<!-- !config-element -->
<!-- !configurations -->
<!-- #endregion -->
<div class="col-sm-12 form-section-title">
Persisting data
</div>
<!-- #region PERSISTED FOLDERS -->
<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>
@ -315,7 +313,6 @@
</div>
</div>
<!-- persisted folders -->
<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>
@ -333,7 +330,7 @@
class="form-control"
name="persisted_folder_path_{{ $index }}"
ng-model="persistedFolder.ContainerPath"
ng-change="ctrl.onChangePersistedFolderPath($index)"
ng-change="ctrl.onChangePersistedFolderPath()"
ng-disabled="ctrl.isEditAndExistingPersistedFolder($index)"
placeholder="/data"
required
@ -360,7 +357,7 @@
uib-btn-radio="false"
ng-change="ctrl.useExistingVolume($index)"
ng-disabled="ctrl.availableVolumes.length === 0 || ctrl.application.ApplicationType === ctrl.ApplicationTypes.STATEFULSET"
>Use an existing volume</label
>Existing volume</label
>
</span>
</div>
@ -422,10 +419,10 @@
<div class="input-group col-sm-1 input-group-sm">
<div style="vertical-align: top;" ng-if="!ctrl.isEditAndStatefulSet()" ng-if="!ctrl.state.useExistingVolume[$index]">
<button ng-if="!persistedFolder.NeedsDeletion" class="btn btn-sm btn-danger" type="button" ng-click="ctrl.removePersistedFolder($index)">
<i class="fa fa-times" aria-hidden="true"></i>
<i class="fa fa-trash-alt" aria-hidden="true"></i>
</button>
<button ng-if="persistedFolder.NeedsDeletion" class="btn btn-sm btn-primary" type="button" ng-click="ctrl.restorePersistedFolder($index)">
Restore
<i class="fa fa-trash-restore" aria-hidden="true"></i>
</button>
</div>
</div>
@ -434,22 +431,22 @@
<div
ng-show="
kubernetesApplicationCreationForm['persisted_folder_path_' + $index].$invalid ||
ctrl.state.duplicatePersistedFolderPaths[$index] !== undefined ||
ctrl.state.duplicates.persistedFolders.refs[$index] !== undefined ||
kubernetesApplicationCreationForm['persisted_folder_size_' + $index].$invalid ||
kubernetesApplicationCreationForm['existing_volumes_' + $index].$invalid ||
ctrl.state.duplicateExistingVolumes[$index] !== undefined
ctrl.state.duplicates.existingVolumes.refs[$index] !== undefined
"
>
<div class="input-group col-sm-3 input-group-sm">
<div
class="small text-warning"
style="margin-top: 5px;"
ng-show="kubernetesApplicationCreationForm['persisted_folder_path_' + $index].$invalid || ctrl.state.duplicatePersistedFolderPaths[$index] !== undefined"
ng-show="kubernetesApplicationCreationForm['persisted_folder_path_' + $index].$invalid || ctrl.state.duplicates.persistedFolders.refs[$index] !== undefined"
>
<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>
<p ng-if="ctrl.state.duplicatePersistedFolderPaths[$index] !== undefined"
<p ng-if="ctrl.state.duplicates.persistedFolders.refs[$index] !== undefined"
><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> This path is already defined.</p
>
</div>
@ -466,12 +463,12 @@
</div>
<div
class="small text-warning"
ng-show="kubernetesApplicationCreationForm['existing_volumes_' + $index].$invalid || ctrl.state.duplicateExistingVolumes[$index] !== undefined"
ng-show="kubernetesApplicationCreationForm['existing_volumes_' + $index].$invalid || ctrl.state.duplicates.existingVolumes.refs[$index] !== undefined"
>
<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>
<p ng-if="ctrl.state.duplicateExistingVolumes[$index] !== undefined"
<p ng-if="ctrl.state.duplicates.existingVolumes.refs[$index] !== undefined"
><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> This volume is already used.</p
>
</div>
@ -483,8 +480,9 @@
</div>
</div>
</div>
<!-- !persisted folders -->
<!-- #endregion -->
<!-- #region DATA ACCESS POLICY -->
<div ng-if="ctrl.showDataAccessPolicySection()">
<div class="form-group">
<div class="col-sm-12">
@ -579,11 +577,12 @@
</div>
<!-- !access policy options -->
</div>
<!-- #endregion -->
<div class="col-sm-12 form-section-title">
Resource reservations
</div>
<!-- #region RESOURCE RESERVATIONS -->
<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>
@ -668,11 +667,12 @@
</div>
</div>
<!-- !cpu-limit-input -->
<!-- #endregion -->
<div class="col-sm-12 form-section-title">
Deployment
</div>
<!-- #region DEPLOYMENT -->
<div class="form-group">
<div class="col-sm-12 small text-muted">
Select how you want to deploy your application inside the cluster.
@ -775,8 +775,9 @@
>. You will not be able to scale that application.
</div>
</div>
<!-- #endregion -->
<!-- auto scaling -->
<!-- #region AUTO SCALING -->
<div class="col-sm-12 form-section-title" ng-if="ctrl.formValues.DeploymentType !== ctrl.ApplicationDeploymentTypes.GLOBAL">
Auto-scaling
</div>
@ -884,12 +885,12 @@
</div>
</div>
</div>
<!-- !auto scaling -->
<!-- #endregion -->
<div class="col-sm-12 form-section-title">
Publishing the application
</div>
<!-- #region PUBLISHING OPTIONS -->
<div class="form-group">
<div class="col-sm-12 small text-muted">
Select how you want to publish your application.
@ -899,9 +900,36 @@
<!-- publishing options -->
<div class="form-group" style="margin-bottom: 0;">
<div class="boxselector_wrapper">
<div>
<input type="radio" id="publishing_internal" ng-value="ctrl.ApplicationPublishingTypes.INTERNAL" ng-model="ctrl.formValues.PublishingType" />
<label for="publishing_internal">
<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;"
>
<div class="boxselector_header">
<i class="fa fa-list-alt" aria-hidden="true" style="margin-right: 2px;"></i>
Internal
@ -909,9 +937,37 @@
<p>Internal communications inside the cluster only</p>
</label>
</div>
<div>
<input type="radio" id="publishing_cluster" ng-value="ctrl.ApplicationPublishingTypes.CLUSTER" ng-model="ctrl.formValues.PublishingType" />
<label for="publishing_cluster">
<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;"
>
<div class="boxselector_header">
<i class="fa fa-list" aria-hidden="true" style="margin-right: 2px;"></i>
Cluster
@ -919,9 +975,74 @@
<p>Publish this application via a port on all nodes of the cluster</p>
</label>
</div>
<div ng-if="ctrl.publishViaLoadBalancerEnabled()">
<input type="radio" id="publishing_loadbalancer" ng-value="ctrl.ApplicationPublishingTypes.LOAD_BALANCER" ng-model="ctrl.formValues.PublishingType" />
<label for="publishing_loadbalancer">
<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;"
>
<div class="boxselector_header">
<i class="fa fa-project-diagram" aria-hidden="true" style="margin-right: 2px;"></i>
Load balancer
@ -931,9 +1052,9 @@
</div>
</div>
</div>
<!-- !publishing options -->
<!-- #endregion -->
<!-- published ports -->
<!-- #region PUBLISHED PORTS -->
<div class="form-group">
<div class="col-sm-12" style="margin-top: 5px;">
<label class="control-label text-left">Published ports</label>
@ -951,8 +1072,12 @@
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>
<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>
<div class="col-sm-12 form-inline" style="margin-top: 10px;">
<!-- #region INPUTS -->
<div
ng-repeat-start="publishedPort in ctrl.formValues.PublishedPorts"
style="margin-top: 2px;"
@ -960,9 +1085,9 @@
tooltip-placement="bottom"
tooltip-class="portainer-tooltip"
tooltip-enable="ctrl.disableLoadBalancerEdit()"
uib-tooltip="Edition is not allowed while the Load Balancer is in Pending state"
uib-tooltip="Edition is not allowed while the Load Balancer is in 'Pending' state"
>
<div class="col-sm-4 input-group input-group-sm">
<div class="col-sm-3 input-group input-group-sm" ng-class="{ striked: publishedPort.NeedsDeletion }">
<span class="input-group-addon">container port</span>
<input
type="number"
@ -972,12 +1097,20 @@
placeholder="80"
ng-min="1"
ng-max="65535"
required
ng-disabled="ctrl.disableLoadBalancerEdit()"
ng-required="!publishedPort.NeedsDeletion"
ng-change="ctrl.onChangePortMappingContainerPort()"
ng-disabled="ctrl.disableLoadBalancerEdit() || ctrl.isEditAndNotNewPublishedPort($index)"
/>
</div>
<div class="input-group input-group-sm col-sm-4" ng-if="ctrl.formValues.PublishingType === ctrl.ApplicationPublishingTypes.CLUSTER">
<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)
"
>
<span class="input-group-addon">node port</span>
<input
name="published_node_port_{{ $index }}"
@ -987,10 +1120,19 @@
placeholder="30080"
ng-min="30000"
ng-max="32767"
ng-change="ctrl.onChangePortMappingNodePort()"
ng-disabled="ctrl.disableLoadBalancerEdit() || ctrl.isEditAndNotNewPublishedPort($index)"
/>
</div>
<div class="col-sm-4 input-group input-group-sm" ng-if="ctrl.formValues.PublishingType === ctrl.ApplicationPublishingTypes.LOAD_BALANCER">
<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)
"
>
<span class="input-group-addon">load balancer port</span>
<input
type="number"
@ -1001,69 +1143,206 @@
value="8080"
ng-min="1"
ng-max="65535"
required
ng-disabled="ctrl.disableLoadBalancerEdit()"
ng-required="!publishedPort.NeedsDeletion"
ng-change="ctrl.onChangePortMappingLoadBalancerPort()"
ng-disabled="ctrl.disableLoadBalancerEdit() || ctrl.isEditAndNotNewPublishedPort($index)"
/>
</div>
<div class="input-group col-sm-3 input-group-sm">
<div class="btn-group btn-group-sm">
<label class="btn btn-primary" ng-model="publishedPort.Protocol" uib-btn-radio="'TCP'" ng-disabled="ctrl.disableLoadBalancerEdit()">TCP</label>
<label class="btn btn-primary" ng-model="publishedPort.Protocol" uib-btn-radio="'UDP'" ng-disabled="ctrl.disableLoadBalancerEdit()">UDP</label>
<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"
placeholder="foo"
ng-required="!publishedPort.NeedsDeletion"
ng-change="ctrl.onChangePortMappingIngressRoute()"
ng-pattern="/^\/?([a-zA-Z0-9]+[a-zA-Z0-9-/_]*[a-zA-Z0-9]|[a-zA-Z0-9]+)$/"
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'"
ng-change="ctrl.onChangePortMappingContainerPort()"
ng-disabled="ctrl.isProtocolOptionDisabled($index, 'TCP')"
>TCP</label
>
<label
class="btn btn-primary"
ng-model="publishedPort.Protocol"
uib-btn-radio="'UDP'"
ng-change="ctrl.onChangePortMappingContainerPort()"
ng-disabled="ctrl.isProtocolOptionDisabled($index, 'UDP')"
>UDP</label
>
</div>
<button class="btn btn-sm btn-danger" type="button" ng-click="ctrl.removePublishedPort($index)" ng-if="!ctrl.disableLoadBalancerEdit()">
<i class="fa fa-times" aria-hidden="true"></i>
<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>
</button>
</div>
</div>
<!-- #endregion -->
<!-- #region VALIDATION -->
<div
ng-repeat-end
ng-if="
ng-show="
kubernetesApplicationCreationForm['container_port_' + $index].$invalid ||
kubernetesApplicationCreationForm['published_node_port_' + $index].$invalid ||
kubernetesApplicationCreationForm['load_balancer_port_' + $index].$invalid
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)
"
>
<div class="col-sm-4 input-group input-group-sm">
<div class="small text-warning" style="margin-top: 5px;" ng-if="kubernetesApplicationCreationForm['container_port_' + $index].$invalid">
<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
"
>
<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>
<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>
</div>
</div>
<div class="input-group input-group-sm col-sm-4" 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">
<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
"
>
<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>
<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-4 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">
<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>
</div>
</div>
<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
"
>
<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>
<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>
</div>
</div>
<div class="input-group col-sm-1 input-group-sm"> </div>
</div>
<!-- #endregion -->
</div>
</div>
<!-- !published ports -->
<!-- #endregion -->
<div class="col-sm-12 form-section-title">
Actions
</div>
<!-- #region ACTIONS -->
<div class="form-group">
<div class="col-sm-12">
<button
@ -1083,10 +1362,12 @@
type="button"
class="btn btn-sm btn-default"
ui-sref="kubernetes.applications.application({ name: ctrl.application.Name, namespace: ctrl.application.ResourcePool })"
>Cancel</button
>
Cancel
</button>
</div>
</div>
<!-- #endregion -->
</form>
</rd-widget-body>
</rd-widget>