mirror of https://github.com/portainer/portainer
58 lines
2.4 KiB
TypeScript
58 lines
2.4 KiB
TypeScript
![]() |
import { useQuery } from '@tanstack/react-query';
|
||
|
import { Pod } from 'kubernetes-types/core/v1';
|
||
|
|
||
|
import { withGlobalError } from '@/react-tools/react-query';
|
||
|
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||
|
|
||
|
import { getNamespaceServices } from '../../services/service';
|
||
|
import type { Application } from '../types';
|
||
|
import { applicationIsKind } from '../utils';
|
||
|
|
||
|
import { queryKeys } from './query-keys';
|
||
|
|
||
|
// useApplicationServices returns a query for services that are related to the application (this doesn't include ingresses)
|
||
|
// Filtering the services by the application selector labels is done in the front end because:
|
||
|
// - The label selector query param in the kubernetes API filters by metadata.labels, but we need to filter the services by spec.selector
|
||
|
// - The field selector query param in the kubernetes API can filter the services by spec.selector, but it doesn't support chaining with 'OR',
|
||
|
// so we can't filter by services with at least one matching label. See: https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/#chained-selectors
|
||
|
export function useApplicationServices(
|
||
|
environmentId: EnvironmentId,
|
||
|
namespace: string,
|
||
|
appName: string,
|
||
|
app?: Application
|
||
|
) {
|
||
|
return useQuery(
|
||
|
queryKeys.applicationServices(environmentId, namespace, appName),
|
||
|
async () => {
|
||
|
if (!app) {
|
||
|
return [];
|
||
|
}
|
||
|
|
||
|
// get the selector labels for the application
|
||
|
const appSelectorLabels = applicationIsKind<Pod>('Pod', app)
|
||
|
? app.metadata?.labels
|
||
|
: app.spec?.template?.metadata?.labels;
|
||
|
|
||
|
// get all services in the namespace and filter them by the application selector labels
|
||
|
const services = await getNamespaceServices(environmentId, namespace);
|
||
|
const filteredServices = services.filter((service) => {
|
||
|
if (service.spec?.selector && appSelectorLabels) {
|
||
|
const serviceSelectorLabels = service.spec.selector;
|
||
|
// include the service if the service selector label matches at least one application selector label
|
||
|
return Object.keys(appSelectorLabels).some(
|
||
|
(key) =>
|
||
|
serviceSelectorLabels[key] &&
|
||
|
serviceSelectorLabels[key] === appSelectorLabels[key]
|
||
|
);
|
||
|
}
|
||
|
return false;
|
||
|
});
|
||
|
return filteredServices;
|
||
|
},
|
||
|
{
|
||
|
...withGlobalError(`Unable to get services for ${appName}`),
|
||
|
enabled: !!app,
|
||
|
}
|
||
|
);
|
||
|
}
|