1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Fix getting allowed resources, don't display workloads overview if no resources are allowed

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2021-06-17 09:53:39 -04:00
parent 55d3e996cb
commit 439c469ce6
4 changed files with 32 additions and 24 deletions

View File

@ -519,20 +519,25 @@ export class Cluster implements ClusterModel, ClusterState {
return getClusterResources(await this.getProxyKubeconfig());
}, 60 * 1000); // 1min
private isAllowedCheckers = new ExtendedObservableMap<string, () => Promise<Map<string, boolean>>>();
private isAllowedCheckers = new ExtendedObservableMap<string, () => Promise<Set<string>>>();
private async getIsAllowedResourcesInNamespace(namespace: string): Promise<Map<string, boolean>> {
private async getIsAllowedResourcesInNamespace(namespace: string): Promise<Set<string>> {
console.log("getIsAllowedResourcesInNamespace", Date.now());
const groups = await this.getApiResourceMap();
const isAllowed = new Map<string, boolean>();
const isAllowed = new Set<string>();
for (const group of groups.values()) {
for (const versions of group.values()) {
for (const resource of versions.keys()) {
isAllowed.set(resource, await this.canI({
name: resource,
const canList = await this.canI({
resource,
namespace,
verb: "list",
}));
});
if (canList) {
isAllowed.add(resource);
}
}
}
}
@ -540,7 +545,7 @@ export class Cluster implements ClusterModel, ClusterState {
return isAllowed;
}
async getIsAllowedResources(namespace: string): Promise<Map<string, boolean>> {
async getIsAllowedResources(namespace: string): Promise<Set<string>> {
return this.isAllowedCheckers.getOrInsert(
namespace,
() => asyncThrottle(
@ -566,7 +571,7 @@ export class Cluster implements ClusterModel, ClusterState {
const accessReview = await this.canIApiLimit(() => authApi.createSelfSubjectAccessReview({
apiVersion: "authorization.k8s.io/v1",
kind: "SelfSubjectAccessReview",
spec: { resourceAttributes }
spec: { resourceAttributes },
}));
return accessReview.body.status.allowed;

View File

@ -119,19 +119,19 @@ export function initIpcMainHandlers() {
?.getApiResourceMap();
});
ipcMainHandle(ClusterResourceIsAllowedChannel, async (event, clusterId: ClusterId, namespaces: string[]): Promise<[string, boolean][]> => {
ipcMainHandle(ClusterResourceIsAllowedChannel, async (event, clusterId: ClusterId, namespaces: string[]): Promise<string[]> => {
const cluster = ClusterStore.getInstance().getById(clusterId);
if (!cluster) {
return [];
}
const isAllowed = new Map<string, boolean>();
const isAllowed = new Set<string>();
await Promise.all(
namespaces.map(async namespace => {
for (const [resource, canList] of await cluster.getIsAllowedResources(namespace)) {
isAllowed.set(resource, Boolean(isAllowed.get(resource)) || canList);
for (const resource of await cluster.getIsAllowedResources(namespace)) {
isAllowed.add(resource);
}
})
);

View File

@ -19,7 +19,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import { action, makeObservable, observable, ObservableMap, reaction } from "mobx";
import { action, makeObservable, observable, reaction } from "mobx";
import type { ClusterId } from "../../common/cluster-store";
import { ClusterResourceIsAllowedChannel, ClusterGetResourcesChannel, requestMain } from "../../common/ipc";
import { Disposer, Singleton } from "../utils";
@ -31,7 +31,7 @@ type NamespaceName = string;
type ResourceName = string;
export class AllowedResources extends Singleton {
protected allowedResourceMap = new ObservableMap<ResourceName, boolean>();
protected allowedResources = observable.set<ResourceName>();
@observable public resources: ApiResourceMap;
/**
@ -65,9 +65,10 @@ export class AllowedResources extends Singleton {
);
}
@action
private async refresh(namespaces: NamespaceName[]) {
try {
this.allowedResourceMap.replace(await requestMain(ClusterResourceIsAllowedChannel, this.clusterId, namespaces));
this.allowedResources.replace(await requestMain(ClusterResourceIsAllowedChannel, this.clusterId, namespaces));
} catch (error) {
console.error("[ALLOWED-RESOURCES]: failed to refresh", error, { namespaces });
Notifications.error("Failed to refresh allowed resources");
@ -81,7 +82,7 @@ export class AllowedResources extends Singleton {
* @returns `true` if the resource exists; is cluster scoped and can be listed, or is namespaced and can be listed in at least one of the namespaces
*/
isAllowed(name: ResourceName): boolean {
return this.allowedResourceMap.get(name) ?? false;
return this.allowedResources.has(name);
}
}

View File

@ -39,14 +39,7 @@ import * as routes from "../../../common/routes";
@observer
export class Workloads extends React.Component {
@computed static get tabRoutes(): TabLayoutRoute[] {
const tabs: TabLayoutRoute[] = [
{
title: "Overview",
component: WorkloadsOverview,
url: routes.overviewURL(),
routePath: routes.overviewRoute.path.toString()
}
];
const tabs: TabLayoutRoute[] = [];
if (isAllowedResource("pods")) {
tabs.push({
@ -111,6 +104,15 @@ export class Workloads extends React.Component {
});
}
if (tabs.length > 0) {
tabs.unshift({
title: "Overview",
component: WorkloadsOverview,
url: routes.overviewURL(),
routePath: routes.overviewRoute.path.toString()
});
}
return tabs;
}