1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-23 15:29:42 +02:00

feat(kubernetes): add ingress details (#4013)

* feat(kubernetes): add ingress details

* fix(kubernetes): fix broken ingress generated links + ignore IP retrieval/display info on missing LB ingress ip

* refactor(kubernetes): each ingress rule in apps port mappings has now its own row

* feat(kubernetes): remove protocol column and concat it to container port

* feat(kubernetes): edit display of ingress rules in application details

* feat(kubernetes): minor UI update

Co-authored-by: Anthony Lapenna <lapenna.anthony@gmail.com>
This commit is contained in:
xAt0mZ 2020-07-14 22:45:19 +02:00 committed by GitHub
parent b09b1b1691
commit 1b3e2c8f69
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 450 additions and 137 deletions

View file

@ -96,15 +96,13 @@
</a>
</th>
<th>
<a ng-click="$ctrl.changeOrderBy('Protocol')">
Protocol
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Protocol' && !$ctrl.state.reverseOrder"></i>
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Protocol' && $ctrl.state.reverseOrder"></i>
</a>
HTTP route
</th>
</tr>
</thead>
<tbody>
<!-- main rows -->
<!-- dir-paginate-start track by $index -->
<tr
dir-paginate-start="item in ($ctrl.state.filteredDataSet = ($ctrl.dataset | filter:$ctrl.state.textFilter | filter: $ctrl.isDisplayed | orderBy:$ctrl.state.orderBy:$ctrl.state.reverseOrder | itemsPerPage: $ctrl.state.paginatedItemLimit: $ctrl.tableKey))"
ng-class="{ active: item.Checked }"
@ -112,40 +110,87 @@
ng-click="$ctrl.expandItem(item, !item.Expanded)"
pagination-id="$ctrl.tableKey"
>
<!-- expandable -->
<td>
<a ng-if="$ctrl.itemCanExpand(item)">
<i ng-class="{ 'fas fa-angle-down': item.Expanded, 'fas fa-angle-right': !item.Expanded }" class="space-right" aria-hidden="true"></i>
</a>
</td>
<!-- Application -->
<td>
<a ui-sref="kubernetes.applications.application({ name: item.Name, namespace: item.ResourcePool })">{{ item.Name }}</a>
<span class="label label-info image-tag label-margins" ng-if="$ctrl.isSystemNamespace(item)">system</span>
<span class="label label-primary image-tag label-margins" ng-if="!$ctrl.isSystemNamespace(item) && $ctrl.isExternalApplication(item)">external</span>
</td>
<!-- Publishing mode -->
<td>
<span ng-if="item.ServiceType === 'LoadBalancer'">
<!-- LB -->
<span ng-if="item.ServiceType === $ctrl.KubernetesServiceTypes.LOAD_BALANCER">
<span> <i class="fa fa-project-diagram" aria-hidden="true" style="margin-right: 2px;"></i> Load balancer </span>
<span class="text-muted small" style="margin-left: 5px;">
<span ng-if="item.LoadBalancerIPAddress">{{ item.LoadBalancerIPAddress }}</span>
<span ng-if="!item.LoadBalancerIPAddress">pending</span>
</span>
</span>
<span ng-if="item.ServiceType === 'ClusterIP'"> <i class="fa fa-list-alt" aria-hidden="true" style="margin-right: 2px;"></i> Internal </span>
<span ng-if="item.ServiceType === 'NodePort'"> <i class="fa fa-list" aria-hidden="true" style="margin-right: 2px;"></i> Cluster </span>
<!-- Internal -->
<span ng-if="item.ServiceType === $ctrl.KubernetesServiceTypes.CLUSTER_IP">
<i class="fa fa-list-alt" aria-hidden="true" style="margin-right: 2px;"></i> Internal
</span>
<!-- Cluster -->
<span ng-if="item.ServiceType === $ctrl.KubernetesServiceTypes.NODE_PORT"> <i class="fa fa-list" aria-hidden="true" style="margin-right: 2px;"></i> Cluster </span>
</td>
<td ng-if="!$ctrl.itemCanExpand(item)">
{{ item.Ports[0].Port }}
<a ng-if="item.LoadBalancerIPAddress" ng-href="http://{{ item.LoadBalancerIPAddress }}:{{ item.Ports[0].Port }}" target="_blank" style="margin-left: 5px;">
<!-- Exposed port -->
<td>
<span ng-if="!$ctrl.itemCanExpand(item)">
{{ item.Ports[0].Port }}
<a ng-if="item.LoadBalancerIPAddress" ng-href="http://{{ item.LoadBalancerIPAddress }}:{{ item.Ports[0].Port }}" target="_blank" style="margin-left: 5px;">
<i class="fa fa-external-link-alt" aria-hidden="true"></i> access
</a>
</span>
</td>
<!-- Container port -->
<td>
<span ng-if="!$ctrl.itemCanExpand(item)"> {{ item.Ports[0].TargetPort }}/{{ item.Ports[0].Protocol }} </span>
</td>
<!-- HTTP route -->
<td>
<span ng-if="!$ctrl.itemCanExpand(item)">
<span ng-if="!$ctrl.portHasIngressRules(item.Ports[0])">-</span>
<span ng-if="$ctrl.portHasIngressRules(item.Ports[0])">
<span
ng-if="!$ctrl.ruleCanBeDisplayed(item.Ports[0].IngressRules[0])"
class="text-muted"
tooltip-append-to-body="true"
tooltip-placement="bottom"
tooltip-class="portainer-tooltip"
uib-tooltip="Ingress controller IP address not available yet"
style="cursor: pointer;"
>pending
</span>
<span ng-if="$ctrl.ruleCanBeDisplayed(item.Ports[0].IngressRules[0])">
<a ng-href="{{ $ctrl.buildIngressRuleURL(item.Ports[0].IngressRules[0]) }}" target="_blank">
{{ $ctrl.buildIngressRuleURL(item.Ports[0].IngressRules[0]) | stripprotocol }}
</a>
</span>
</span>
</span>
</td>
</tr>
<!-- sub rows -->
<tr ng-show="item.Expanded" ng-repeat-start="port in item.Ports" ng-style="{ background: item.Highlighted ? '#d5e8f3' : '#f5f5f5' }">
<td ng-if="!$ctrl.portHasIngressRules(port)"></td>
<td ng-if="!$ctrl.portHasIngressRules(port)">-</td>
<td ng-if="!$ctrl.portHasIngressRules(port)">-</td>
<td ng-if="!$ctrl.portHasIngressRules(port)">
{{ port.Port }}
<a ng-if="item.LoadBalancerIPAddress" ng-href="http://{{ item.LoadBalancerIPAddress }}:{{ port.Port }}" target="_blank" style="margin-left: 5px;">
<i class="fa fa-external-link-alt" aria-hidden="true"></i> access
</a>
</td>
<td ng-if="!$ctrl.itemCanExpand(item)">{{ item.Ports[0].TargetPort }}</td>
<td ng-if="!$ctrl.itemCanExpand(item)">{{ item.Ports[0].Protocol }}</td>
<td ng-if="$ctrl.itemCanExpand(item)"></td>
<td ng-if="$ctrl.itemCanExpand(item)"></td>
<td ng-if="$ctrl.itemCanExpand(item)"></td>
<td ng-if="!$ctrl.portHasIngressRules(port)">{{ port.TargetPort }}/{{ port.Protocol }}</td>
<td ng-if="!$ctrl.portHasIngressRules(port)">-</td>
</tr>
<tr dir-paginate-end ng-show="item.Expanded" ng-repeat="port in item.Ports" ng-style="{ background: item.Highlighted ? '#d5e8f3' : '#f5f5f5' }">
<tr ng-show="item.Expanded" ng-repeat-end ng-repeat="rule in port.IngressRules" ng-style="{ background: item.Highlighted ? '#d5e8f3' : '#f5f5f5' }">
<td></td>
<td>-</td>
<td>-</td>
@ -155,12 +200,31 @@
<i class="fa fa-external-link-alt" aria-hidden="true"></i> access
</a>
</td>
<td>{{ port.TargetPort }}</td>
<td>{{ port.Protocol }}</td>
<td>{{ port.TargetPort }}/{{ port.Protocol }}</td>
<td>
<span
ng-if="!$ctrl.ruleCanBeDisplayed(rule)"
class="text-muted"
tooltip-append-to-body="true"
tooltip-placement="bottom"
tooltip-class="portainer-tooltip"
uib-tooltip="Ingress controller IP address not available yet"
style="cursor: pointer;"
>pending
</span>
<span ng-if="$ctrl.ruleCanBeDisplayed(rule)">
<a ng-href="{{ $ctrl.buildIngressRuleURL(rule) }}" target="_blank">
{{ $ctrl.buildIngressRuleURL(rule) | stripprotocol }}
</a>
</span>
</td>
</tr>
<tr dir-paginate-end></tr>
<!-- no dataset -->
<tr ng-if="!$ctrl.dataset">
<td colspan="6" class="text-center text-muted">Loading...</td>
</tr>
<!-- no values in filtered dataset -->
<tr ng-if="$ctrl.state.filteredDataSet.length === 0">
<td colspan="6" class="text-center text-muted">No application port mapping available.</td>
</tr>

View file

@ -1,6 +1,7 @@
import _ from 'lodash-es';
import { KubernetesApplicationDeploymentTypes } from 'Kubernetes/models/application/models';
import KubernetesApplicationHelper from 'Kubernetes/helpers/application';
import { KubernetesServiceTypes } from 'Kubernetes/models/service/models';
angular.module('portainer.docker').controller('KubernetesApplicationsPortsDatatableController', [
'$scope',
@ -16,6 +17,7 @@ angular.module('portainer.docker').controller('KubernetesApplicationsPortsDatata
});
var ctrl = this;
this.KubernetesServiceTypes = KubernetesServiceTypes;
this.settings = Object.assign(this.settings, {
showSystem: false,
@ -49,7 +51,20 @@ angular.module('portainer.docker').controller('KubernetesApplicationsPortsDatata
};
this.itemCanExpand = function (item) {
return item.Ports.length > 1;
return item.Ports.length > 1 || item.Ports[0].IngressRules.length > 1;
};
this.buildIngressRuleURL = function (rule) {
const hostname = rule.Host ? rule.Host : rule.IP;
return 'http://' + hostname + rule.Path;
};
this.portHasIngressRules = function (port) {
return port.IngressRules.length > 0;
};
this.ruleCanBeDisplayed = function (rule) {
return !rule.Host && !rule.IP ? false : true;
};
this.hasExpandableItems = function () {