1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-05 13:55:21 +02:00

fix(gke): port metrics to the backend EE-5447 (#9041)

This commit is contained in:
Dakota Walsh 2023-07-24 12:16:29 +12:00 committed by GitHub
parent e996d29d52
commit 704d70c99b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 441 additions and 247 deletions

View file

@ -1,114 +0,0 @@
import angular from 'angular';
import PortainerError from 'Portainer/error';
import { KubernetesCommonParams } from 'Kubernetes/models/common/params';
class KubernetesMetricsService {
/* @ngInject */
constructor($async, KubernetesMetrics) {
this.$async = $async;
this.KubernetesMetrics = KubernetesMetrics;
this.capabilitiesAsync = this.capabilitiesAsync.bind(this);
this.getPodAsync = this.getPodAsync.bind(this);
this.getNodeAsync = this.getNodeAsync.bind(this);
this.getPodsAsync = this.getPodsAsync.bind(this);
this.getNodesAsync = this.getNodesAsync.bind(this);
}
/**
* GET
*/
async capabilitiesAsync(endpointID) {
try {
await this.KubernetesMetrics().capabilities({ endpointId: endpointID }).$promise;
} catch (err) {
throw new PortainerError('Unable to retrieve metrics', err);
}
}
capabilities(endpointID) {
return this.$async(this.capabilitiesAsync, endpointID);
}
/**
* Stats of Node
*
* @param {string} nodeName
*/
async getNodeAsync(nodeName) {
try {
const params = new KubernetesCommonParams();
params.id = nodeName;
const data = await this.KubernetesMetrics().getNode(params).$promise;
return data;
} catch (err) {
throw new PortainerError('Unable to retrieve node stats', err);
}
}
getNode(nodeName) {
return this.$async(this.getNodeAsync, nodeName);
}
/**
* Stats
*
* @param {string} namespace
* @param {string} podName
*/
async getPodAsync(namespace, podName) {
try {
const params = new KubernetesCommonParams();
params.id = podName;
const data = await this.KubernetesMetrics(namespace).getPod(params).$promise;
return data;
} catch (err) {
throw new PortainerError('Unable to retrieve pod stats', err);
}
}
getPod(namespace, podName) {
return this.$async(this.getPodAsync, namespace, podName);
}
/**
* Stats of Nodes in cluster
*
* @param {string} endpointID
*/
async getNodesAsync(endpointID) {
try {
const data = await this.KubernetesMetrics().getNodes({ endpointId: endpointID }).$promise;
return data;
} catch (err) {
throw new PortainerError('Unable to retrieve nodes stats', err);
}
}
getNodes(endpointID) {
return this.$async(this.getNodesAsync, endpointID);
}
/**
* Stats of Pods in a namespace
*
* @param {string} namespace
*/
async getPodsAsync(namespace) {
try {
const data = await this.KubernetesMetrics(namespace).getPods().$promise;
return data;
} catch (err) {
throw new PortainerError('Unable to retrieve pod stats', err);
}
}
getPods(namespace) {
return this.$async(this.getPodsAsync, namespace);
}
}
export default KubernetesMetricsService;
angular.module('portainer.kubernetes').service('KubernetesMetricsService', KubernetesMetricsService);

View file

@ -1,39 +0,0 @@
angular.module('portainer.kubernetes').factory('KubernetesMetrics', [
'$resource',
'API_ENDPOINT_ENDPOINTS',
'EndpointProvider',
function KubernetesMetrics($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider) {
'use strict';
return function (namespace) {
const url = API_ENDPOINT_ENDPOINTS + '/:endpointId/kubernetes/apis/metrics.k8s.io/v1beta1';
const podUrl = `${url}${namespace ? '/namespaces/:namespace' : ''}/pods/:id`;
return $resource(
url,
{
endpointId: EndpointProvider.endpointID,
namespace: namespace,
},
{
capabilities: { method: 'GET' },
getPod: {
method: 'GET',
url: podUrl,
},
getNode: {
method: 'GET',
url: `${url}/nodes/:id`,
},
getPods: {
method: 'GET',
url: `${url}/namespaces/:namespace/pods`,
},
getNodes: {
method: 'GET',
url: `${url}/nodes`,
},
}
);
};
},
]);

View file

@ -4,10 +4,11 @@ import _ from 'lodash-es';
import filesizeParser from 'filesize-parser';
import KubernetesResourceReservationHelper from 'Kubernetes/helpers/resourceReservationHelper';
import KubernetesPodConverter from 'Kubernetes/pod/converter';
import { getMetricsForPod } from '@/react/kubernetes/services/service.ts';
class KubernetesApplicationStatsController {
/* @ngInject */
constructor($async, $state, $interval, $document, Notifications, KubernetesPodService, KubernetesNodeService, KubernetesMetricsService, ChartService) {
constructor($async, $state, $interval, $document, Notifications, KubernetesPodService, KubernetesNodeService, ChartService) {
this.$async = $async;
this.$state = $state;
this.$interval = $interval;
@ -15,7 +16,6 @@ class KubernetesApplicationStatsController {
this.Notifications = Notifications;
this.KubernetesPodService = KubernetesPodService;
this.KubernetesNodeService = KubernetesNodeService;
this.KubernetesMetricsService = KubernetesMetricsService;
this.ChartService = ChartService;
this.onInit = this.onInit.bind(this);
@ -84,7 +84,7 @@ class KubernetesApplicationStatsController {
getStats() {
return this.$async(async () => {
try {
const stats = await this.KubernetesMetricsService.getPod(this.state.transition.namespace, this.state.transition.podName);
const stats = await getMetricsForPod(this.$state.params.endpointId, this.state.transition.namespace, this.state.transition.podName);
const container = _.find(stats.containers, { name: this.state.transition.containerName });
if (container) {
const memory = filesizeParser(container.usage.memory);
@ -126,7 +126,7 @@ class KubernetesApplicationStatsController {
};
try {
await this.KubernetesMetricsService.getPod(this.state.transition.namespace, this.state.transition.podName);
await getMetricsForPod(this.$state.params.endpointId, this.state.transition.namespace, this.state.transition.podName);
} catch (error) {
this.state.getMetrics = false;
this.state.viewReady = true;

View file

@ -3,27 +3,17 @@ import _ from 'lodash-es';
import filesizeParser from 'filesize-parser';
import KubernetesResourceReservationHelper from 'Kubernetes/helpers/resourceReservationHelper';
import { KubernetesResourceReservation } from 'Kubernetes/models/resource-reservation/models';
import { getMetricsForAllNodes } from '@/react/kubernetes/services/service.ts';
class KubernetesClusterController {
/* @ngInject */
constructor(
$async,
$state,
Authentication,
Notifications,
LocalStorage,
KubernetesNodeService,
KubernetesMetricsService,
KubernetesApplicationService,
KubernetesEndpointService
) {
constructor($async, $state, Notifications, LocalStorage, Authentication, KubernetesNodeService, KubernetesApplicationService, KubernetesEndpointService) {
this.$async = $async;
this.$state = $state;
this.Authentication = Authentication;
this.Notifications = Notifications;
this.LocalStorage = LocalStorage;
this.KubernetesNodeService = KubernetesNodeService;
this.KubernetesMetricsService = KubernetesMetricsService;
this.KubernetesApplicationService = KubernetesApplicationService;
this.KubernetesEndpointService = KubernetesEndpointService;
@ -108,7 +98,7 @@ class KubernetesClusterController {
async getResourceUsage(endpointId) {
try {
const nodeMetrics = await this.KubernetesMetricsService.getNodes(endpointId);
const nodeMetrics = await getMetricsForAllNodes(endpointId);
const resourceUsageList = nodeMetrics.items.map((i) => i.usage);
const clusterResourceUsage = resourceUsageList.reduce((total, u) => {
total.CPU += KubernetesResourceReservationHelper.parseCPU(u.cpu);

View file

@ -9,6 +9,7 @@ import { KubernetesNodeTaintEffects, KubernetesNodeAvailabilities } from 'Kubern
import KubernetesFormValidationHelper from 'Kubernetes/helpers/formValidationHelper';
import { KubernetesNodeHelper } from 'Kubernetes/node/helper';
import { confirmUpdateNode } from '@/react/kubernetes/cluster/NodeView/ConfirmUpdateNode';
import { getMetricsForNode } from '@/react/kubernetes/services/service.ts';
class KubernetesNodeController {
/* @ngInject */
@ -22,7 +23,6 @@ class KubernetesNodeController {
KubernetesPodService,
KubernetesApplicationService,
KubernetesEndpointService,
KubernetesMetricsService,
Authentication
) {
this.$async = $async;
@ -34,7 +34,6 @@ class KubernetesNodeController {
this.KubernetesPodService = KubernetesPodService;
this.KubernetesApplicationService = KubernetesApplicationService;
this.KubernetesEndpointService = KubernetesEndpointService;
this.KubernetesMetricsService = KubernetesMetricsService;
this.Authentication = Authentication;
this.onInit = this.onInit.bind(this);
@ -300,7 +299,7 @@ class KubernetesNodeController {
async getNodeUsageAsync() {
try {
const nodeName = this.$transition$.params().name;
const node = await this.KubernetesMetricsService.getNode(nodeName);
const node = await getMetricsForNode(this.$state.params.endpointId, nodeName);
this.resourceUsage = new KubernetesResourceReservation();
this.resourceUsage.CPU = KubernetesResourceReservationHelper.parseCPU(node.usage.cpu);
this.resourceUsage.Memory = KubernetesResourceReservationHelper.megaBytesValue(node.usage.memory);

View file

@ -3,17 +3,17 @@ import moment from 'moment';
import filesizeParser from 'filesize-parser';
import KubernetesResourceReservationHelper from 'Kubernetes/helpers/resourceReservationHelper';
import { PORTAINER_FADEOUT } from '@/constants';
import { getMetricsForNode } from '@/react/kubernetes/services/service.ts';
class KubernetesNodeStatsController {
/* @ngInject */
constructor($async, $state, $interval, $document, Notifications, KubernetesNodeService, KubernetesMetricsService, ChartService) {
constructor($async, $state, $interval, $document, Notifications, KubernetesNodeService, ChartService) {
this.$async = $async;
this.$state = $state;
this.$interval = $interval;
this.$document = $document;
this.Notifications = Notifications;
this.KubernetesNodeService = KubernetesNodeService;
this.KubernetesMetricsService = KubernetesMetricsService;
this.ChartService = ChartService;
this.onInit = this.onInit.bind(this);
@ -79,7 +79,7 @@ class KubernetesNodeStatsController {
getStats() {
return this.$async(async () => {
try {
const stats = await this.KubernetesMetricsService.getNode(this.state.transition.nodeName);
const stats = await getMetricsForNode(this.$state.params.endpointId, this.state.transition.nodeName);
if (stats) {
const memory = filesizeParser(stats.usage.memory);
const cpu = KubernetesResourceReservationHelper.parseCPU(stats.usage.cpu);
@ -111,7 +111,7 @@ class KubernetesNodeStatsController {
};
try {
const nodeMetrics = await this.KubernetesMetricsService.getNode(this.state.transition.nodeName);
const nodeMetrics = await getMetricsForNode(this.$state.params.endpointId, this.state.transition.nodeName);
if (nodeMetrics) {
const node = await this.KubernetesNodeService.get(this.state.transition.nodeName);

View file

@ -11,23 +11,13 @@ import { buildConfirmButton } from '@@/modals/utils';
import { confirm } from '@@/modals/confirm';
import { getIsRBACEnabled } from '@/react/kubernetes/cluster/getIsRBACEnabled';
import { ModalType } from '@@/modals/Modal/types';
import { getMetricsForAllNodes } from '@/react/kubernetes/services/service.ts';
class KubernetesConfigureController {
/* #region CONSTRUCTOR */
/* @ngInject */
constructor(
$async,
$state,
$scope,
Notifications,
KubernetesStorageService,
EndpointService,
EndpointProvider,
KubernetesResourcePoolService,
KubernetesIngressService,
KubernetesMetricsService
) {
constructor($async, $state, $scope, Notifications, KubernetesStorageService, EndpointService, EndpointProvider, KubernetesResourcePoolService, KubernetesIngressService) {
this.$async = $async;
this.$state = $state;
this.$scope = $scope;
@ -37,7 +27,6 @@ class KubernetesConfigureController {
this.EndpointProvider = EndpointProvider;
this.KubernetesResourcePoolService = KubernetesResourcePoolService;
this.KubernetesIngressService = KubernetesIngressService;
this.KubernetesMetricsService = KubernetesMetricsService;
this.IngressClassTypes = KubernetesIngressClassTypes;
@ -192,24 +181,26 @@ class KubernetesConfigureController {
}
enableMetricsServer() {
if (this.formValues.UseServerMetrics) {
this.state.metrics.userClick = true;
this.state.metrics.pending = true;
this.KubernetesMetricsService.capabilities(this.endpoint.Id)
.then(() => {
return this.$async(async () => {
if (this.formValues.UseServerMetrics) {
this.state.metrics.userClick = true;
this.state.metrics.pending = true;
try {
await getMetricsForAllNodes(this.endpoint.Id);
this.state.metrics.isServerRunning = true;
this.state.metrics.pending = false;
this.state.metrics.userClick = false;
this.formValues.UseServerMetrics = true;
})
.catch(() => {
} catch (_) {
this.state.metrics.isServerRunning = false;
this.state.metrics.pending = false;
this.formValues.UseServerMetrics = false;
});
} else {
this.state.metrics.userClick = false;
this.formValues.UseServerMetrics = false;
}
}
} else {
this.state.metrics.userClick = false;
this.formValues.UseServerMetrics = false;
}
});
}
async configureAsync() {

View file

@ -16,6 +16,7 @@ import { FeatureId } from '@/react/portainer/feature-flags/enums';
import { updateIngressControllerClassMap, getIngressControllerClassMap } from '@/react/kubernetes/cluster/ingressClass/utils';
import { confirmUpdate } from '@@/modals/confirm';
import { confirmUpdateNamespace } from '@/react/kubernetes/namespaces/ItemView/ConfirmUpdateNamespace';
import { getMetricsForAllNodes, getMetricsForAllPods } from '@/react/kubernetes/services/service.ts';
class KubernetesResourcePoolController {
/* #region CONSTRUCTOR */
@ -28,8 +29,6 @@ class KubernetesResourcePoolController {
Notifications,
LocalStorage,
EndpointService,
KubernetesNodeService,
KubernetesMetricsService,
KubernetesResourceQuotaService,
KubernetesResourcePoolService,
KubernetesEventService,
@ -47,8 +46,6 @@ class KubernetesResourcePoolController {
Notifications,
LocalStorage,
EndpointService,
KubernetesNodeService,
KubernetesMetricsService,
KubernetesResourceQuotaService,
KubernetesResourcePoolService,
KubernetesEventService,
@ -322,7 +319,7 @@ class KubernetesResourcePoolController {
async getResourceUsage(namespace) {
try {
const namespaceMetrics = await this.KubernetesMetricsService.getPods(namespace);
const namespaceMetrics = await getMetricsForAllPods(this.$state.params.endpointId, namespace);
// extract resource usage of all containers within each pod of the namespace
const containerResourceUsageList = namespaceMetrics.items.flatMap((i) => i.containers.map((c) => c.usage));
const namespaceResourceUsage = containerResourceUsageList.reduce((total, u) => {
@ -369,7 +366,7 @@ class KubernetesResourcePoolController {
const name = this.$state.params.id;
const [nodes, pools] = await Promise.all([this.KubernetesNodeService.get(), this.KubernetesResourcePoolService.get('', { getQuota: true })]);
const [nodes, pools] = await Promise.all([getMetricsForAllNodes, this.KubernetesResourcePoolService.get('', { getQuota: true })]);
this.ingressControllers = [];
if (this.state.ingressAvailabilityPerNamespace) {