1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-09 15:55:23 +02:00

move service account isSystem to server

This commit is contained in:
testA113 2024-10-05 23:36:30 +13:00
parent 6bc6471562
commit ee180ed08f
6 changed files with 39 additions and 49 deletions

View file

@ -4,13 +4,17 @@ import (
"errors" "errors"
"net/http" "net/http"
"time" "time"
"k8s.io/apimachinery/pkg/types"
) )
type ( type (
K8sServiceAccount struct { K8sServiceAccount struct {
Name string `json:"name"` Name string `json:"name"`
UID types.UID `json:"uid"`
Namespace string `json:"namespace"` Namespace string `json:"namespace"`
CreationDate time.Time `json:"creationDate"` CreationDate time.Time `json:"creationDate"`
IsSystem bool `json:"isSystem"`
} }
// K8sServiceAcountDeleteRequests is a mapping of namespace names to a slice of service account names. // K8sServiceAcountDeleteRequests is a mapping of namespace names to a slice of service account names.

View file

@ -53,18 +53,20 @@ func (kcl *KubeClient) fetchServiceAccounts(namespace string) ([]models.K8sServi
results := make([]models.K8sServiceAccount, 0) results := make([]models.K8sServiceAccount, 0)
for _, serviceAccount := range serviceAccounts.Items { for _, serviceAccount := range serviceAccounts.Items {
results = append(results, parseServiceAccount(serviceAccount)) results = append(results, kcl.parseServiceAccount(serviceAccount))
} }
return results, nil return results, nil
} }
// parseServiceAccount converts a corev1.ServiceAccount object to a models.K8sServiceAccount object. // parseServiceAccount converts a corev1.ServiceAccount object to a models.K8sServiceAccount object.
func parseServiceAccount(serviceAccount corev1.ServiceAccount) models.K8sServiceAccount { func (kcl *KubeClient) parseServiceAccount(serviceAccount corev1.ServiceAccount) models.K8sServiceAccount {
return models.K8sServiceAccount{ return models.K8sServiceAccount{
Name: serviceAccount.Name, Name: serviceAccount.Name,
UID: serviceAccount.UID,
Namespace: serviceAccount.Namespace, Namespace: serviceAccount.Namespace,
CreationDate: serviceAccount.CreationTimestamp.Time, CreationDate: serviceAccount.CreationTimestamp.Time,
IsSystem: kcl.isSystemServiceAccount(serviceAccount.Namespace),
} }
} }
@ -84,6 +86,10 @@ func (kcl *KubeClient) GetPortainerUserServiceAccount(tokenData *portainer.Token
return serviceAccount, nil return serviceAccount, nil
} }
func (kcl *KubeClient) isSystemServiceAccount(namespace string) bool {
return kcl.isSystemNamespace(namespace)
}
// DeleteServices processes a K8sServiceDeleteRequest by deleting each service // DeleteServices processes a K8sServiceDeleteRequest by deleting each service
// in its given namespace. // in its given namespace.
func (kcl *KubeClient) DeleteServiceAccounts(reqs kubernetes.K8sServiceAccountDeleteRequests) error { func (kcl *KubeClient) DeleteServiceAccounts(reqs kubernetes.K8sServiceAccountDeleteRequests) error {
@ -101,7 +107,7 @@ func (kcl *KubeClient) DeleteServiceAccounts(reqs kubernetes.K8sServiceAccountDe
return err return err
} }
if kcl.isSystemNamespace(sa.Namespace) { if kcl.isSystemServiceAccount(sa.Namespace) {
return fmt.Errorf("cannot delete system service account %q", namespace+"/"+serviceName) return fmt.Errorf("cannot delete system service account %q", namespace+"/"+serviceName)
} }

View file

@ -6,13 +6,11 @@ import { useEnvironmentId } from '@/react/hooks/useEnvironmentId';
import { Authorized } from '@/react/hooks/useUser'; import { Authorized } from '@/react/hooks/useUser';
import { notifyError, notifySuccess } from '@/portainer/services/notifications'; import { notifyError, notifySuccess } from '@/portainer/services/notifications';
import { SystemResourceDescription } from '@/react/kubernetes/datatables/SystemResourceDescription'; import { SystemResourceDescription } from '@/react/kubernetes/datatables/SystemResourceDescription';
import { useNamespacesQuery } from '@/react/kubernetes/namespaces/queries/useNamespacesQuery';
import { import {
DefaultDatatableSettings, DefaultDatatableSettings,
TableSettings as KubeTableSettings, TableSettings as KubeTableSettings,
} from '@/react/kubernetes/datatables/DefaultDatatableSettings'; } from '@/react/kubernetes/datatables/DefaultDatatableSettings';
import { CreateFromManifestButton } from '@/react/kubernetes/components/CreateFromManifestButton'; import { CreateFromManifestButton } from '@/react/kubernetes/components/CreateFromManifestButton';
import { isSystemNamespace } from '@/react/kubernetes/namespaces/queries/useIsSystemNamespace';
import { useKubeStore } from '@/react/kubernetes/datatables/default-kube-datatable-store'; import { useKubeStore } from '@/react/kubernetes/datatables/default-kube-datatable-store';
import { Datatable, TableSettingsMenu } from '@@/datatables'; import { Datatable, TableSettingsMenu } from '@@/datatables';
@ -24,7 +22,7 @@ import {
import { ServiceAccount } from '../types'; import { ServiceAccount } from '../types';
import { getColumns } from './columns'; import { columns } from './columns';
import { useDeleteServiceAccountsMutation } from './queries/useDeleteServiceAccountsMutation'; import { useDeleteServiceAccountsMutation } from './queries/useDeleteServiceAccountsMutation';
import { useGetAllServiceAccountsQuery } from './queries/useGetAllServiceAccountsQuery'; import { useGetAllServiceAccountsQuery } from './queries/useGetAllServiceAccountsQuery';
@ -42,22 +40,15 @@ export function ServiceAccountsDatatable() {
...filteredColumnsSettings(set), ...filteredColumnsSettings(set),
}) })
); );
const namespacesQuery = useNamespacesQuery(environmentId);
const namespaces = namespacesQuery.data;
const serviceAccountsQuery = useGetAllServiceAccountsQuery(environmentId, { const serviceAccountsQuery = useGetAllServiceAccountsQuery(environmentId, {
refetchInterval: tableState.autoRefreshRate * 1000, refetchInterval: tableState.autoRefreshRate * 1000,
enabled: namespacesQuery.isSuccess,
}); });
const columns = getColumns(namespaces);
const filteredServiceAccounts = useMemo( const filteredServiceAccounts = useMemo(
() => () =>
tableState.showSystemResources tableState.showSystemResources
? serviceAccountsQuery.data ? serviceAccountsQuery.data
: serviceAccountsQuery.data?.filter( : serviceAccountsQuery.data?.filter((sa) => !sa.isSystem),
(sa) => !isSystemNamespace(sa.namespace, namespaces) [serviceAccountsQuery.data, tableState.showSystemResources]
),
[namespaces, serviceAccountsQuery.data, tableState.showSystemResources]
); );
return ( return (
@ -69,10 +60,8 @@ export function ServiceAccountsDatatable() {
emptyContentLabel="No service accounts found" emptyContentLabel="No service accounts found"
title="Service Accounts" title="Service Accounts"
titleIcon={User} titleIcon={User}
getRowId={(row) => `${row.namespace}-${row.name}`} getRowId={(row) => row.uid}
isRowSelectable={(row) => isRowSelectable={(row) => !row.original.isSystem}
!isSystemNamespace(row.original.namespace, namespaces)
}
renderTableActions={(selectedRows) => ( renderTableActions={(selectedRows) => (
<TableActions selectedItems={selectedRows} /> <TableActions selectedItems={selectedRows} />
)} )}

View file

@ -1,9 +1,5 @@
import { PortainerNamespace } from '@/react/kubernetes/namespaces/types';
import { name } from './name'; import { name } from './name';
import { namespace } from './namespace'; import { namespace } from './namespace';
import { created } from './created'; import { created } from './created';
export function getColumns(namespaces?: PortainerNamespace[]) { export const columns = [name, namespace, created];
return [name(namespaces), namespace, created];
}

View file

@ -1,30 +1,23 @@
import { isSystemNamespace } from '@/react/kubernetes/namespaces/queries/useIsSystemNamespace';
import { PortainerNamespace } from '@/react/kubernetes/namespaces/types';
import { SystemBadge } from '@@/Badge/SystemBadge'; import { SystemBadge } from '@@/Badge/SystemBadge';
import { columnHelper } from './helper'; import { columnHelper } from './helper';
export function name(namespaces?: PortainerNamespace[]) { export const name = columnHelper.accessor(
return columnHelper.accessor( (row) => {
(row) => { let result = row.name;
let result = row.name; if (row.isSystem) {
if (isSystemNamespace(row.namespace, namespaces)) { result += ' system';
result += ' system';
}
return result;
},
{
header: 'Name',
id: 'name',
cell: ({ row }) => (
<div className="flex gap-2">
<div>{row.original.name}</div>
{isSystemNamespace(row.original.namespace, namespaces) && (
<SystemBadge />
)}
</div>
),
} }
); return result;
} },
{
header: 'Name',
id: 'name',
cell: ({ row }) => (
<div className="flex gap-2">
<div>{row.original.name}</div>
{row.original.isSystem && <SystemBadge />}
</div>
),
}
);

View file

@ -1,5 +1,7 @@
export type ServiceAccount = { export type ServiceAccount = {
name: string; name: string;
uid: string;
namespace: string; namespace: string;
creationDate: string; creationDate: string;
isSystem: boolean;
}; };