dashboard/shell/models/networking.k8s.io.ingress.js

210 lines
5.3 KiB
JavaScript

import { SECRET, SERVICE } from '@shell/config/types';
import isUrl from 'is-url';
import { get } from '@shell/utils/object';
import isEmpty from 'lodash/isEmpty';
import SteveModel from '@shell/plugins/steve/steve-class';
function tlsHosts(spec) {
const tls = spec.tls || [];
return tls.flatMap((tls) => tls.hosts || []);
}
function isTlsHost(spec, host) {
return tlsHosts(spec).includes(host);
}
export function ingressFullPath(resource, rule, path = {}) {
const spec = resource.spec;
const hostValue = rule.host || '';
const pathValue = path.path || '';
let protocol = '';
if (hostValue) {
protocol = isTlsHost(spec, hostValue) ? 'https://' : 'http://';
}
return `${ protocol }${ hostValue }${ pathValue }`;
}
export default class Ingress extends SteveModel {
get tlsHosts() {
return tlsHosts(this.spec);
}
get isTlsHost() {
return (host) => isTlsHost(this.spec, host);
}
targetTo(workloads, serviceName) {
if (!serviceName) {
return null;
}
const isTargetsWorkload = serviceName.startsWith('ingress-');
const id = `${ this.namespace }/${ serviceName }`;
if (isTargetsWorkload) {
// Need to expose workloadId's and fetch specific ones in IngressTarget?
const workload = workloads.find((w) => w.id === (id));
return workload?.detailLocation || '';
} else {
return {
name: 'c-cluster-product-resource-namespace-id',
params: {
resource: SERVICE,
id: serviceName,
namespace: this.namespace,
}
};
}
}
createRulesForListPage(workloads, certificates) {
const rules = this.spec.rules || [];
return rules.flatMap((rule) => {
const paths = rule?.http?.paths || [];
return paths.map((path) => this.createPathForListPage(workloads, rule, path, certificates));
});
}
createPathForListPage(workloads, rule, path, certificates) {
const serviceName = get(path?.backend, this.serviceNamePath);
const fullPath = this.fullPath(rule, path);
return {
// isUrl thinks urls which contain '*' are valid so I'm adding an additional check for '*'
isUrl: isUrl(fullPath) && !fullPath.includes('*'),
pathType: path.pathType,
fullPath,
serviceName,
serviceTargetTo: this.targetTo(workloads, serviceName),
certs: this.certLinks(rule, certificates),
targetLink: this.targetLink(workloads, serviceName),
port: get(path?.backend, this.servicePortPath)
};
}
fullPath(rule, path) {
return ingressFullPath(this, rule, path);
}
certLink(cert, certificates = []) {
const secretName = cert.secretName || this.t('ingress.rulesAndCertificates.defaultCertificate');
let to;
if (cert.secretName && certificates.includes(secretName)) {
to = {
name: 'c-cluster-product-resource-namespace-id',
params: {
resource: SECRET,
id: secretName
}
};
}
return {
to,
text: secretName,
options: { internal: true }
};
}
certLinks(rule, certificates) {
const certs = this.spec.tls || [];
const matchingCerts = certs.filter((cert) => {
const hosts = cert.hosts || [];
return hosts.includes(rule.host);
});
return matchingCerts.map((cert) => this.certLink(cert, certificates));
}
targetLink(workloads, serviceName) {
return {
to: this.targetTo(workloads, serviceName),
text: serviceName,
options: { internal: true }
};
}
createDefaultService(workloads) {
const backend = get(this.spec, this.defaultBackendPath);
const serviceName = get(backend, this.serviceNamePath);
if ( !serviceName ) {
return null;
}
return {
name: serviceName,
targetTo: this.targetTo(workloads, serviceName)
};
}
get cache() {
if (!this.cacheObject) {
this.cacheObject = {};
}
return this.cacheObject;
}
get showPathType() {
if (!this.cache.showPathType) {
this.cache.showPathType = this.$rootGetters['cluster/pathExistsInSchema'](this.type, 'spec.rules.http.paths.pathType');
}
return this.cache.showPathType;
}
get useNestedBackendField() {
if (!this.cache.useNestedBackendField) {
this.cache.useNestedBackendField = this.$rootGetters['cluster/pathExistsInSchema'](this.type, 'spec.rules.http.paths.backend.service.name');
}
return this.cache.useNestedBackendField;
}
get serviceNamePath() {
const nestedPath = 'service.name';
const flatPath = 'serviceName';
return this.useNestedBackendField ? nestedPath : flatPath;
}
get servicePortPath() {
const nestedPath = 'service.port.number';
const flatPath = 'servicePort';
return this.useNestedBackendField ? nestedPath : flatPath;
}
get defaultBackendPath() {
const defaultBackend = this.$rootGetters['cluster/pathExistsInSchema'](this.type, 'spec.defaultBackend');
return defaultBackend ? 'defaultBackend' : 'backend';
}
get hasDefaultBackend() {
return !isEmpty(this.spec[this.defaultBackendPath]);
}
get details() {
const out = this._details;
if (this.spec?.ingressClassName) {
out.push({
label: this.t('ingress.ingressClass.label'),
content: this.spec.ingressClassName,
});
}
return out;
}
}