mirror of https://github.com/portainer/portainer
96 lines
3.8 KiB
Go
96 lines
3.8 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
portainer "github.com/portainer/portainer/api"
|
|
"github.com/rs/zerolog/log"
|
|
corev1 "k8s.io/api/core/v1"
|
|
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
)
|
|
|
|
// GetResourceQuotas gets all resource quotas in the current k8s environment(endpoint).
|
|
// if the user is an admin, all resource quotas in all namespaces are fetched.
|
|
// otherwise, namespaces the non-admin user has access to will be used to filter the resource quotas.
|
|
func (kcl *KubeClient) GetResourceQuotas(namespace string) (*[]corev1.ResourceQuota, error) {
|
|
if kcl.IsKubeAdmin {
|
|
return kcl.fetchResourceQuotas(namespace)
|
|
}
|
|
return kcl.fetchResourceQuotasForNonAdmin(namespace)
|
|
}
|
|
|
|
// fetchResourceQuotasForNonAdmin gets the resource quotas in the current k8s environment(endpoint) for a non-admin user.
|
|
// the role of the user must have read access to the resource quotas in the defined namespaces.
|
|
func (kcl *KubeClient) fetchResourceQuotasForNonAdmin(namespace string) (*[]corev1.ResourceQuota, error) {
|
|
log.Debug().Msgf("Fetching resource quotas for non-admin user: %v", kcl.NonAdminNamespaces)
|
|
|
|
if len(kcl.NonAdminNamespaces) == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
resourceQuotas, err := kcl.fetchResourceQuotas(namespace)
|
|
if err != nil && !k8serrors.IsNotFound(err) {
|
|
return nil, err
|
|
}
|
|
|
|
nonAdminNamespaceSet := kcl.buildNonAdminNamespacesMap()
|
|
results := []corev1.ResourceQuota{}
|
|
for _, resourceQuota := range *resourceQuotas {
|
|
if _, exists := nonAdminNamespaceSet[resourceQuota.Namespace]; exists {
|
|
results = append(results, resourceQuota)
|
|
}
|
|
}
|
|
|
|
return &results, nil
|
|
}
|
|
|
|
func (kcl *KubeClient) fetchResourceQuotas(namespace string) (*[]corev1.ResourceQuota, error) {
|
|
resourceQuotas, err := kcl.cli.CoreV1().ResourceQuotas(namespace).List(context.TODO(), metav1.ListOptions{})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("an error occured, failed to list resource quotas for the admin user: %w", err)
|
|
}
|
|
|
|
return &resourceQuotas.Items, nil
|
|
}
|
|
|
|
// GetPortainerResourceQuota gets the resource quota for the portainer namespace.
|
|
// The resource quota is prefixed with "portainer-rq-".
|
|
func (kcl *KubeClient) GetPortainerResourceQuota(namespace string) (*corev1.ResourceQuota, error) {
|
|
return kcl.cli.CoreV1().ResourceQuotas(namespace).Get(context.TODO(), "portainer-rq-"+namespace, metav1.GetOptions{})
|
|
}
|
|
|
|
// GetResourceQuota gets a resource quota in a specific namespace.
|
|
func (kcl *KubeClient) GetResourceQuota(namespace, resourceQuota string) (*corev1.ResourceQuota, error) {
|
|
return kcl.cli.CoreV1().ResourceQuotas(namespace).Get(context.TODO(), resourceQuota, metav1.GetOptions{})
|
|
}
|
|
|
|
// UpdateNamespacesWithResourceQuotas updates the namespaces with the resource quotas.
|
|
// The resource quotas are matched with the namespaces by name.
|
|
func (kcl *KubeClient) UpdateNamespacesWithResourceQuotas(namespaces map[string]portainer.K8sNamespaceInfo, resourceQuotas []corev1.ResourceQuota) []portainer.K8sNamespaceInfo {
|
|
namespacesWithQuota := map[string]portainer.K8sNamespaceInfo{}
|
|
|
|
for _, namespace := range namespaces {
|
|
resourceQuota := kcl.GetResourceQuotaFromNamespace(namespace, resourceQuotas)
|
|
if resourceQuota != nil {
|
|
namespace.ResourceQuota = resourceQuota
|
|
}
|
|
|
|
namespacesWithQuota[namespace.Name] = namespace
|
|
}
|
|
|
|
return kcl.ConvertNamespaceMapToSlice(namespacesWithQuota)
|
|
}
|
|
|
|
// GetResourceQuotaFromNamespace gets the resource quota in a specific namespace where the resource quota's name is prefixed with "portainer-rq-".
|
|
func (kcl *KubeClient) GetResourceQuotaFromNamespace(namespace portainer.K8sNamespaceInfo, resourceQuotas []corev1.ResourceQuota) *corev1.ResourceQuota {
|
|
for _, resourceQuota := range resourceQuotas {
|
|
if resourceQuota.ObjectMeta.Namespace == namespace.Name && resourceQuota.ObjectMeta.Name == "portainer-rq-"+namespace.Name {
|
|
return &resourceQuota
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|