Skip to content

Commit

Permalink
Handle fetching from inventory for users that don't have permissions …
Browse files Browse the repository at this point in the history
…to list all namespaces

Reference: #1293

Handle providers fetching from inventory for users with limited namespace roles, who can only list their namespaces content
and don't have get permissions to all namespaces.

Before the fix, when those users tried to fetch providers inventory data, regarldess to
current namespace, the "inventory server is not reachable" error was always displayed.

After this fix, those users will not fetch all namepsaces but only
ones which they allow to list. So the fetching should now succeed and no
error should be displayed.

Signed-off-by: Sharon Gratch <sgratch@redhat.com>
  • Loading branch information
sgratch committed Aug 29, 2024
1 parent 5a496fa commit cc5f48d
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { useEffect, useRef, useState } from 'react';

import { ProviderInventory, ProvidersInventoryList } from '@kubev2v/types';
import { consoleFetchJSON } from '@openshift-console/dynamic-plugin-sdk';
import {
ProviderInventory,
ProviderModel,
ProvidersInventoryList,
V1beta1Provider,
} from '@kubev2v/types';
import { consoleFetchJSON, k8sGet, useFlag } from '@openshift-console/dynamic-plugin-sdk';

import { getInventoryApiUrl, hasObjectChangedInGivenFields } from '../utils/helpers';

Expand All @@ -12,9 +17,11 @@ const INVENTORY_TYPES: string[] = ['openshift', 'openstack', 'ovirt', 'vsphere',
/**
* Configuration parameters for useProvidersInventoryList hook.
* @interface
* @property {string} namespace - namespace for fetching inventory's providers data for. Used only for users with limited namespaces privileges.
* @property {number} interval - Polling interval in milliseconds.
*/
interface UseInventoryParams {
namespace?: string;
interval?: number; // Polling interval in milliseconds
}

Expand All @@ -32,29 +39,34 @@ interface UseInventoryResult {
}

/**
* A React hook to fetch and maintain an up-to-date list of providers' inventory data.
* A React hook to fetch and maintain an up-to-date list of providers' inventory data, belongs to a given namespace or to all namespaces
* (based on the namespace parameter).
* For users with limited namespaces privileges, only the given namespace's providers inventory data are fetched.
* It fetches data on mount and then at the specified interval.
*
* @param {UseInventoryParams} params - Configuration parameters for the hook.
* @param {string} namespace - namespace to fetch providers' inventory data for. if set to null, then fetch for all namespaces.
* @param {number} [params.interval=10000] - Interval (in milliseconds) to fetch new data at.
*
* @returns {UseInventoryResult} result - Contains the inventory data, the loading state, and the error state.
*/
export const useProvidersInventoryList = ({
namespace = null,
interval = 20000,
}: UseInventoryParams): UseInventoryResult => {
const [inventory, setInventory] = useState<ProvidersInventoryList | null>(null);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<Error | null>(null);
const oldDataRef = useRef(null);
const oldErrorRef = useRef(null);
const canList: boolean = useFlag('CAN_LIST_NS');

useEffect(() => {
const fetchData = async () => {
try {
const newInventory: ProvidersInventoryList = await consoleFetchJSON(
getInventoryApiUrl(`providers?detail=1`),
);
const newInventory: ProvidersInventoryList = canList
? await consoleFetchJSON(getInventoryApiUrl(`providers?detail=1`)) // Fetch all providers
: await getInventoryByNamespace(namespace); // Fetch single namespace's providers

updateInventoryIfChanged(newInventory, DEFAULT_FIELDS_TO_COMPARE);
handleError(null);
Expand All @@ -67,7 +79,66 @@ export const useProvidersInventoryList = ({

const intervalId = setInterval(fetchData, interval);
return () => clearInterval(intervalId);
}, [interval]);
}, [interval, namespace]);

/**
* Fetching providers list by namespace.
*
* @param {string} namespace to fetch providers by.
* @returns {Promise<V1beta1Provider[]>} providers list by namespace.
*/
const k8sGetProviders = async (namespace: string): Promise<V1beta1Provider[]> => {
type K8sListResponse<T> = {
items: T[];
};
const providersList = await k8sGet({ model: ProviderModel, ns: namespace });

return (providersList as K8sListResponse<V1beta1Provider>)?.items;
};

/**
* For users with limited namespaces privileges, fetch only the given namespace's providers.
*
* @param {string} namespace namespace to fetch providers' inventory data for.
* @returns {void}
*/
const getInventoryByNamespace = async (namespace: string): Promise<ProvidersInventoryList> => {
const newInventory: ProvidersInventoryList = {
openshift: [],
openstack: [],
ovirt: [],
vsphere: [],
ova: [],
};

const providers = await k8sGetProviders(namespace);

const readyProviders = providers?.filter(
(provider: V1beta1Provider) => provider.status.phase === 'Ready',
);

const inventoryProviderURL = (provider: V1beta1Provider) =>
`providers/${provider.spec.type}/${provider.metadata.uid}`;

const allPromises = Promise.all(
readyProviders.map(async (provider) => {
return await consoleFetchJSON(getInventoryApiUrl(inventoryProviderURL(provider)));
}),
)
.then((newInventoryProviders) => {
newInventoryProviders.map((newInventoryProvider) =>
newInventory[newInventoryProvider.type].push(newInventoryProvider),
);

return newInventory;
})
.catch(() => {
// throw error;
return null;
});

return allPromises;
};

/**
* Handles any errors thrown when trying to fetch the inventory.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ const ProvidersListPage: React.FC<{
inventory,
loading: inventoryLoading,
error: inventoryError,
} = useProvidersInventoryList({});
} = useProvidersInventoryList({ namespace });

const permissions = useGetDeleteAndEditAccessReview({
model: ProviderModel,
Expand Down

0 comments on commit cc5f48d

Please sign in to comment.