From 6a67e8142d99014ad861ce474a724c236eb7d79f Mon Sep 17 00:00:00 2001 From: cong meng Date: Tue, 12 Oct 2021 10:37:07 +1300 Subject: [PATCH] fix(frontend) prevent notification showing Object Object EE-1745 (#5778) * fix(frontend) prevent notification showing Object Object EE-1745 * fix(frontend) fix notification args in wrong order EE-1745 * fix(rbac) add metrics rbac for regular users EE-1745 Co-authored-by: Simon Meng --- api/kubernetes/cli/role.go | 5 ++ .../servicesDatatableActionsController.js | 2 +- .../views/services/edit/serviceController.js | 4 +- .../views/cluster/clusterController.js | 4 +- .../views/cluster/node/nodeController.js | 2 +- .../edit/resourcePoolController.js | 2 +- app/portainer/services/notifications.js | 53 ++++++++++--------- .../init/endpoint/initEndpointController.js | 2 +- .../wizard-aci.controller.js | 2 +- .../wizard-docker.controller.js | 2 +- .../wizard-kubernetes.controller.js | 2 +- 11 files changed, 45 insertions(+), 35 deletions(-) diff --git a/api/kubernetes/cli/role.go b/api/kubernetes/cli/role.go index 7c22f1b32..d38fc1136 100644 --- a/api/kubernetes/cli/role.go +++ b/api/kubernetes/cli/role.go @@ -18,6 +18,11 @@ func getPortainerUserDefaultPolicies() []rbacv1.PolicyRule { Resources: []string{"storageclasses"}, APIGroups: []string{"storage.k8s.io"}, }, + { + Verbs: []string{"list"}, + Resources: []string{"namespaces", "pods"}, + APIGroups: []string{"metrics.k8s.io"}, + }, } } diff --git a/app/docker/components/datatables/services-datatable/actions/servicesDatatableActionsController.js b/app/docker/components/datatables/services-datatable/actions/servicesDatatableActionsController.js index 124e931b6..d760390d5 100644 --- a/app/docker/components/datatables/services-datatable/actions/servicesDatatableActionsController.js +++ b/app/docker/components/datatables/services-datatable/actions/servicesDatatableActionsController.js @@ -68,7 +68,7 @@ angular.module('portainer.docker').controller('ServicesDatatableActionsControlle Notifications.success('Service successfully updated', service.Name); }) .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to force update service', service.Name); + Notifications.error('Failure', err, 'Unable to force update service' + service.Name); }) .finally(function final() { --actionCount; diff --git a/app/docker/views/services/edit/serviceController.js b/app/docker/views/services/edit/serviceController.js index 73a4f70be..2bb27171a 100644 --- a/app/docker/views/services/edit/serviceController.js +++ b/app/docker/views/services/edit/serviceController.js @@ -501,7 +501,7 @@ angular.module('portainer.docker').controller('ServiceController', [ ServiceService.update(service, config, 'previous') .then(function (data) { if (data.message && data.message.match(/^rpc error:/)) { - Notifications.error(data.message, 'Error'); + Notifications.error('Failure', data, 'Error'); } else { Notifications.success('Success', 'Service successfully rolled back'); $scope.cancelChanges({}); @@ -550,7 +550,7 @@ angular.module('portainer.docker').controller('ServiceController', [ ServiceService.update(service, config).then( function (data) { if (data.message && data.message.match(/^rpc error:/)) { - Notifications.error(data.message, 'Error'); + Notifications.error('Failure', data, 'Error'); } else { Notifications.success('Service successfully updated', 'Service updated'); } diff --git a/app/kubernetes/views/cluster/clusterController.js b/app/kubernetes/views/cluster/clusterController.js index bf907faa6..e8e8c3adb 100644 --- a/app/kubernetes/views/cluster/clusterController.js +++ b/app/kubernetes/views/cluster/clusterController.js @@ -95,7 +95,7 @@ class KubernetesClusterController { await this.getResourceUsage(this.endpoint.Id); } } catch (err) { - this.Notifications.error('Failure', 'Unable to retrieve applications', err); + this.Notifications.error('Failure', err, 'Unable to retrieve applications'); } finally { this.state.applicationsLoading = false; } @@ -116,7 +116,7 @@ class KubernetesClusterController { }, new KubernetesResourceReservation()); this.resourceUsage = clusterResourceUsage; } catch (err) { - this.Notifications.error('Failure', 'Unable to retrieve cluster resource usage', err); + this.Notifications.error('Failure', err, 'Unable to retrieve cluster resource usage'); } } diff --git a/app/kubernetes/views/cluster/node/nodeController.js b/app/kubernetes/views/cluster/node/nodeController.js index d08b949c5..176be97e9 100644 --- a/app/kubernetes/views/cluster/node/nodeController.js +++ b/app/kubernetes/views/cluster/node/nodeController.js @@ -345,7 +345,7 @@ class KubernetesNodeController { this.resourceUsage.CPU = KubernetesResourceReservationHelper.parseCPU(node.usage.cpu); this.resourceUsage.Memory = KubernetesResourceReservationHelper.megaBytesValue(node.usage.memory); } catch (err) { - this.Notifications.error('Failure', 'Unable to retrieve node resource usage', err); + this.Notifications.error('Failure', err, 'Unable to retrieve node resource usage'); } } diff --git a/app/kubernetes/views/resource-pools/edit/resourcePoolController.js b/app/kubernetes/views/resource-pools/edit/resourcePoolController.js index b2aefdc93..630cd5d8e 100644 --- a/app/kubernetes/views/resource-pools/edit/resourcePoolController.js +++ b/app/kubernetes/views/resource-pools/edit/resourcePoolController.js @@ -361,7 +361,7 @@ class KubernetesResourcePoolController { }, new KubernetesResourceReservation()); this.state.resourceUsage = namespaceResourceUsage; } catch (err) { - this.Notifications.error('Failure', 'Unable to retrieve namespace resource usage', err); + this.Notifications.error('Failure', err, 'Unable to retrieve namespace resource usage'); } } diff --git a/app/portainer/services/notifications.js b/app/portainer/services/notifications.js index 51f98ff5e..e1135e67b 100644 --- a/app/portainer/services/notifications.js +++ b/app/portainer/services/notifications.js @@ -1,5 +1,6 @@ import _ from 'lodash-es'; import toastr from 'toastr'; +import lodash from 'lodash-es'; angular.module('portainer.app').factory('Notifications', [ '$sanitize', @@ -15,31 +16,35 @@ angular.module('portainer.app').factory('Notifications', [ toastr.warning($sanitize(_.escape(text)), $sanitize(title), { timeOut: 6000 }); }; + function pickErrorMsg(e) { + const props = [ + 'err.data.details', + 'err.data.message', + 'data.details', + 'data.message', + 'data.content', + 'data.error', + 'message', + 'err.data[0].message', + 'err.data.err', + 'data.err', + 'msg', + ]; + + let msg = ''; + + lodash.forEach(props, (prop) => { + const val = lodash.get(e, prop); + if (typeof val === 'string') { + msg = msg || val; + } + }); + + return msg; + } + service.error = function (title, e, fallbackText) { - var msg = fallbackText; - if (e.err && e.err.data && e.err.data.details && typeof e.err.data.details === 'string') { - msg = e.err.data.details; - } else if (e.err && e.err.data && e.err.data.message) { - msg = e.err.data.message; - } else if (e.data && e.data.details) { - msg = e.data.details; - } else if (e.data && e.data.message) { - msg = e.data.message; - } else if (e.data && e.data.content) { - msg = e.data.content; - } else if (e.data && e.data.error) { - msg = e.data.error; - } else if (e.message) { - msg = e.message; - } else if (e.err && e.err.data && e.err.data.length > 0 && e.err.data[0].message) { - msg = e.err.data[0].message; - } else if (e.err && e.err.data && e.err.data.err) { - msg = e.err.data.err; - } else if (e.data && e.data.err) { - msg = e.data.err; - } else if (e.msg) { - msg = e.msg; - } + const msg = pickErrorMsg(e) || fallbackText; // eslint-disable-next-line no-console console.error(e); diff --git a/app/portainer/views/init/endpoint/initEndpointController.js b/app/portainer/views/init/endpoint/initEndpointController.js index 510982ac2..b1615a091 100644 --- a/app/portainer/views/init/endpoint/initEndpointController.js +++ b/app/portainer/views/init/endpoint/initEndpointController.js @@ -61,7 +61,7 @@ class InitEndpointController { case PortainerEndpointConnectionTypes.AGENT: return this.createAgentEndpoint(); default: - this.Notifications.error('Failure', 'Unable to determine which action to do to create environment'); + this.Notifications.error('Failure', null, 'Unable to determine which action to do to create environment'); } } diff --git a/app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-aci/wizard-aci.controller.js b/app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-aci/wizard-aci.controller.js index a698d7775..7cac51c62 100644 --- a/app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-aci/wizard-aci.controller.js +++ b/app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-aci/wizard-aci.controller.js @@ -20,7 +20,7 @@ export default class WizardAciController { // Check name is duplicated or not let nameUsed = await this.NameValidator.validateEnvironmentName(name); if (nameUsed) { - this.Notifications.error('Failure', true, 'This name is been used, please try another one'); + this.Notifications.error('Failure', null, 'This name is been used, please try another one'); return; } await this.EndpointService.createAzureEndpoint(name, azureApplicationId, azureTenantId, azureAuthenticationKey, groupId, tagIds); diff --git a/app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-docker/wizard-docker.controller.js b/app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-docker/wizard-docker.controller.js index f11002b3b..961232bb8 100644 --- a/app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-docker/wizard-docker.controller.js +++ b/app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-docker/wizard-docker.controller.js @@ -65,7 +65,7 @@ export default class WizardDockerController { // Check name is duplicated or not const nameUsed = await this.NameValidator.validateEnvironmentName(name); if (nameUsed) { - this.Notifications.error('Failure', true, 'This name is been used, please try another one'); + this.Notifications.error('Failure', null, 'This name is been used, please try another one'); return; } switch (type) { diff --git a/app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-kubernetes/wizard-kubernetes.controller.js b/app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-kubernetes/wizard-kubernetes.controller.js index f84f90e93..62760c844 100644 --- a/app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-kubernetes/wizard-kubernetes.controller.js +++ b/app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-kubernetes/wizard-kubernetes.controller.js @@ -33,7 +33,7 @@ export default class WizardKubernetesController { // Check name is duplicated or not let nameUsed = await this.NameValidator.validateEnvironmentName(name); if (nameUsed) { - this.Notifications.error('Failure', true, 'This name is been used, please try another one'); + this.Notifications.error('Failure', null, 'This name is been used, please try another one'); return; } await this.addRemoteEndpoint(name, creationType, url, publicUrl, groupId, tagIds, tls, tlsSkipVerify, tlsSkipClientVerify, tlsCaFile, tlsCertFile, tlsKeyFile);