mirror of https://github.com/portainer/portainer
move service account isSystem to server
parent
6bc6471562
commit
ee180ed08f
|
@ -4,13 +4,17 @@ import (
|
|||
"errors"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
type (
|
||||
K8sServiceAccount struct {
|
||||
Name string `json:"name"`
|
||||
UID types.UID `json:"uid"`
|
||||
Namespace string `json:"namespace"`
|
||||
CreationDate time.Time `json:"creationDate"`
|
||||
IsSystem bool `json:"isSystem"`
|
||||
}
|
||||
|
||||
// K8sServiceAcountDeleteRequests is a mapping of namespace names to a slice of service account names.
|
||||
|
|
|
@ -53,18 +53,20 @@ func (kcl *KubeClient) fetchServiceAccounts(namespace string) ([]models.K8sServi
|
|||
|
||||
results := make([]models.K8sServiceAccount, 0)
|
||||
for _, serviceAccount := range serviceAccounts.Items {
|
||||
results = append(results, parseServiceAccount(serviceAccount))
|
||||
results = append(results, kcl.parseServiceAccount(serviceAccount))
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// 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{
|
||||
Name: serviceAccount.Name,
|
||||
UID: serviceAccount.UID,
|
||||
Namespace: serviceAccount.Namespace,
|
||||
CreationDate: serviceAccount.CreationTimestamp.Time,
|
||||
IsSystem: kcl.isSystemServiceAccount(serviceAccount.Namespace),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,6 +86,10 @@ func (kcl *KubeClient) GetPortainerUserServiceAccount(tokenData *portainer.Token
|
|||
return serviceAccount, nil
|
||||
}
|
||||
|
||||
func (kcl *KubeClient) isSystemServiceAccount(namespace string) bool {
|
||||
return kcl.isSystemNamespace(namespace)
|
||||
}
|
||||
|
||||
// DeleteServices processes a K8sServiceDeleteRequest by deleting each service
|
||||
// in its given namespace.
|
||||
func (kcl *KubeClient) DeleteServiceAccounts(reqs kubernetes.K8sServiceAccountDeleteRequests) error {
|
||||
|
@ -101,7 +107,7 @@ func (kcl *KubeClient) DeleteServiceAccounts(reqs kubernetes.K8sServiceAccountDe
|
|||
return err
|
||||
}
|
||||
|
||||
if kcl.isSystemNamespace(sa.Namespace) {
|
||||
if kcl.isSystemServiceAccount(sa.Namespace) {
|
||||
return fmt.Errorf("cannot delete system service account %q", namespace+"/"+serviceName)
|
||||
}
|
||||
|
||||
|
|
|
@ -6,13 +6,11 @@ import { useEnvironmentId } from '@/react/hooks/useEnvironmentId';
|
|||
import { Authorized } from '@/react/hooks/useUser';
|
||||
import { notifyError, notifySuccess } from '@/portainer/services/notifications';
|
||||
import { SystemResourceDescription } from '@/react/kubernetes/datatables/SystemResourceDescription';
|
||||
import { useNamespacesQuery } from '@/react/kubernetes/namespaces/queries/useNamespacesQuery';
|
||||
import {
|
||||
DefaultDatatableSettings,
|
||||
TableSettings as KubeTableSettings,
|
||||
} from '@/react/kubernetes/datatables/DefaultDatatableSettings';
|
||||
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 { Datatable, TableSettingsMenu } from '@@/datatables';
|
||||
|
@ -24,7 +22,7 @@ import {
|
|||
|
||||
import { ServiceAccount } from '../types';
|
||||
|
||||
import { getColumns } from './columns';
|
||||
import { columns } from './columns';
|
||||
import { useDeleteServiceAccountsMutation } from './queries/useDeleteServiceAccountsMutation';
|
||||
import { useGetAllServiceAccountsQuery } from './queries/useGetAllServiceAccountsQuery';
|
||||
|
||||
|
@ -42,22 +40,15 @@ export function ServiceAccountsDatatable() {
|
|||
...filteredColumnsSettings(set),
|
||||
})
|
||||
);
|
||||
const namespacesQuery = useNamespacesQuery(environmentId);
|
||||
const namespaces = namespacesQuery.data;
|
||||
const serviceAccountsQuery = useGetAllServiceAccountsQuery(environmentId, {
|
||||
refetchInterval: tableState.autoRefreshRate * 1000,
|
||||
enabled: namespacesQuery.isSuccess,
|
||||
});
|
||||
|
||||
const columns = getColumns(namespaces);
|
||||
const filteredServiceAccounts = useMemo(
|
||||
() =>
|
||||
tableState.showSystemResources
|
||||
? serviceAccountsQuery.data
|
||||
: serviceAccountsQuery.data?.filter(
|
||||
(sa) => !isSystemNamespace(sa.namespace, namespaces)
|
||||
),
|
||||
[namespaces, serviceAccountsQuery.data, tableState.showSystemResources]
|
||||
: serviceAccountsQuery.data?.filter((sa) => !sa.isSystem),
|
||||
[serviceAccountsQuery.data, tableState.showSystemResources]
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -69,10 +60,8 @@ export function ServiceAccountsDatatable() {
|
|||
emptyContentLabel="No service accounts found"
|
||||
title="Service Accounts"
|
||||
titleIcon={User}
|
||||
getRowId={(row) => `${row.namespace}-${row.name}`}
|
||||
isRowSelectable={(row) =>
|
||||
!isSystemNamespace(row.original.namespace, namespaces)
|
||||
}
|
||||
getRowId={(row) => row.uid}
|
||||
isRowSelectable={(row) => !row.original.isSystem}
|
||||
renderTableActions={(selectedRows) => (
|
||||
<TableActions selectedItems={selectedRows} />
|
||||
)}
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
import { PortainerNamespace } from '@/react/kubernetes/namespaces/types';
|
||||
|
||||
import { name } from './name';
|
||||
import { namespace } from './namespace';
|
||||
import { created } from './created';
|
||||
|
||||
export function getColumns(namespaces?: PortainerNamespace[]) {
|
||||
return [name(namespaces), namespace, created];
|
||||
}
|
||||
export const columns = [name, namespace, created];
|
||||
|
|
|
@ -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 { columnHelper } from './helper';
|
||||
|
||||
export function name(namespaces?: PortainerNamespace[]) {
|
||||
return columnHelper.accessor(
|
||||
(row) => {
|
||||
let result = row.name;
|
||||
if (isSystemNamespace(row.namespace, namespaces)) {
|
||||
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>
|
||||
),
|
||||
export const name = columnHelper.accessor(
|
||||
(row) => {
|
||||
let result = row.name;
|
||||
if (row.isSystem) {
|
||||
result += ' system';
|
||||
}
|
||||
);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
{
|
||||
header: 'Name',
|
||||
id: 'name',
|
||||
cell: ({ row }) => (
|
||||
<div className="flex gap-2">
|
||||
<div>{row.original.name}</div>
|
||||
{row.original.isSystem && <SystemBadge />}
|
||||
</div>
|
||||
),
|
||||
}
|
||||
);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
export type ServiceAccount = {
|
||||
name: string;
|
||||
uid: string;
|
||||
namespace: string;
|
||||
creationDate: string;
|
||||
isSystem: boolean;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue