mirror of https://github.com/portainer/portainer
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>pull/4029/head
parent
b09b1b1691
commit
1b3e2c8f69
@ -0,0 +1,19 @@
|
||||
import * as _ from 'lodash-es';
|
||||
import { KubernetesIngressRule } from './models';
|
||||
|
||||
export class KubernetesIngressConverter {
|
||||
static apiToModel(data) {
|
||||
const rules = _.flatMap(data.spec.rules, (rule) => {
|
||||
return _.map(rule.http.paths, (path) => {
|
||||
const ingRule = new KubernetesIngressRule();
|
||||
ingRule.ServiceName = path.backend.serviceName;
|
||||
ingRule.Host = rule.host;
|
||||
ingRule.IP = data.status.loadBalancer.ingress ? data.status.loadBalancer.ingress[0].ip : undefined;
|
||||
ingRule.Port = path.backend.servicePort;
|
||||
ingRule.Path = path.path;
|
||||
return ingRule;
|
||||
});
|
||||
});
|
||||
return rules;
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
import * as _ from 'lodash-es';
|
||||
|
||||
export class KubernetesIngressHelper {
|
||||
static findSBoundServiceIngressesRules(ingressRules, service) {
|
||||
return _.filter(ingressRules, (r) => r.ServiceName === service.metadata.name);
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
/**
|
||||
* KubernetesIngressRule Model
|
||||
*/
|
||||
const _KubernetesIngressRule = Object.freeze({
|
||||
ServiceName: '',
|
||||
Host: '',
|
||||
IP: '',
|
||||
Port: '',
|
||||
Path: '',
|
||||
});
|
||||
|
||||
export class KubernetesIngressRule {
|
||||
constructor() {
|
||||
Object.assign(this, JSON.parse(JSON.stringify(_KubernetesIngressRule)));
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
import { rawResponse } from 'Kubernetes/rest/response/transform';
|
||||
|
||||
angular.module('portainer.kubernetes').factory('KubernetesIngresses', [
|
||||
'$resource',
|
||||
'API_ENDPOINT_ENDPOINTS',
|
||||
'EndpointProvider',
|
||||
function KubernetesIngressesFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) {
|
||||
'use strict';
|
||||
return function (namespace) {
|
||||
const url = API_ENDPOINT_ENDPOINTS + '/:endpointId/kubernetes/apis/networking.k8s.io/v1beta1' + (namespace ? '/namespaces/:namespace' : '') + '/ingresses/:id/:action';
|
||||
return $resource(
|
||||
url,
|
||||
{
|
||||
endpointId: EndpointProvider.endpointID,
|
||||
namespace: namespace,
|
||||
},
|
||||
{
|
||||
get: {
|
||||
method: 'GET',
|
||||
timeout: 15000,
|
||||
ignoreLoadingBar: true,
|
||||
},
|
||||
getYaml: {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Accept: 'application/yaml',
|
||||
},
|
||||
transformResponse: rawResponse,
|
||||
ignoreLoadingBar: true,
|
||||
},
|
||||
create: { method: 'POST' },
|
||||
update: { method: 'PUT' },
|
||||
patch: {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/json-patch+json',
|
||||
},
|
||||
},
|
||||
rollback: {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/json-patch+json',
|
||||
},
|
||||
},
|
||||
delete: { method: 'DELETE' },
|
||||
}
|
||||
);
|
||||
};
|
||||
},
|
||||
]);
|
@ -0,0 +1,54 @@
|
||||
import * as _ from 'lodash-es';
|
||||
import angular from 'angular';
|
||||
import PortainerError from 'Portainer/error';
|
||||
import { KubernetesCommonParams } from 'Kubernetes/models/common/params';
|
||||
import { KubernetesIngressConverter } from './converter';
|
||||
|
||||
class KubernetesIngressService {
|
||||
/* @ngInject */
|
||||
constructor($async, KubernetesIngresses) {
|
||||
this.$async = $async;
|
||||
this.KubernetesIngresses = KubernetesIngresses;
|
||||
|
||||
this.getAsync = this.getAsync.bind(this);
|
||||
this.getAllAsync = this.getAllAsync.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET
|
||||
*/
|
||||
async getAsync(namespace, name) {
|
||||
try {
|
||||
const params = new KubernetesCommonParams();
|
||||
params.id = name;
|
||||
const [raw, yaml] = await Promise.all([this.KubernetesIngresses(namespace).get(params).$promise, this.KubernetesIngresses(namespace).getYaml(params).$promise]);
|
||||
const res = {
|
||||
Raw: KubernetesIngressConverter.apiToModel(raw),
|
||||
Yaml: yaml.data,
|
||||
};
|
||||
return res;
|
||||
} catch (err) {
|
||||
throw new PortainerError('Unable to retrieve Ingress', err);
|
||||
}
|
||||
}
|
||||
|
||||
async getAllAsync(namespace) {
|
||||
try {
|
||||
const data = await this.KubernetesIngresses(namespace).get().$promise;
|
||||
const res = _.reduce(data.items, (arr, item) => _.concat(arr, KubernetesIngressConverter.apiToModel(item)), []);
|
||||
return res;
|
||||
} catch (err) {
|
||||
throw new PortainerError('Unable to retrieve Ingresses', err);
|
||||
}
|
||||
}
|
||||
|
||||
get(namespace, name) {
|
||||
if (name) {
|
||||
return this.$async(this.getAsync, namespace, name);
|
||||
}
|
||||
return this.$async(this.getAllAsync, namespace);
|
||||
}
|
||||
}
|
||||
|
||||
export default KubernetesIngressService;
|
||||
angular.module('portainer.kubernetes').service('KubernetesIngressService', KubernetesIngressService);
|
Loading…
Reference in new issue