Skip to content

feat(Tenants): correct links with relative path in balancer #2125

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/components/TenantNameWrapper/TenantNameWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {DefinitionList, Flex} from '@gravity-ui/uikit';

import {getTenantPath} from '../../containers/Tenant/TenantPages';
import type {PreparedTenant} from '../../store/reducers/tenants/types';
import type {AdditionalTenantsProps, NodeAddress} from '../../types/additionalProps';
import type {AdditionalTenantsProps} from '../../types/additionalProps';
import {useIsUserAllowedToMakeChanges} from '../../utils/hooks/useIsUserAllowedToMakeChanges';
import {EntityStatus} from '../EntityStatus/EntityStatus';
import {LinkWithIcon} from '../LinkWithIcon/LinkWithIcon';
Expand All @@ -22,13 +22,13 @@ const getTenantBackend = (
return undefined;
}

let backend: string | NodeAddress | undefined = tenant.MonitoringEndpoint ?? tenant.backend;
let nodeId: string | undefined;
const nodeIds = tenant.NodeIds ?? tenant.sharedNodeIds;
if (!backend && nodeIds && nodeIds.length > 0) {
if (nodeIds && nodeIds.length > 0) {
const index = Math.floor(Math.random() * nodeIds.length);
backend = {NodeId: nodeIds[index]};
nodeId = nodeIds[index].toString();
}
return additionalTenantsProps.prepareTenantBackend(backend);
return additionalTenantsProps.prepareTenantBackend(nodeId);
};

export function TenantNameWrapper({tenant, additionalTenantsProps}: TenantNameWrapperProps) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import {ClipboardButton} from '@gravity-ui/uikit';
import {isNil} from 'lodash';

import {useClusterBaseInfo} from '../../../store/reducers/cluster/cluster';
import type {
AdditionalClusterProps,
AdditionalTenantsProps,
NodeAddress,
} from '../../../types/additionalProps';
import type {AdditionalClusterProps, AdditionalTenantsProps} from '../../../types/additionalProps';
import type {ETenantType} from '../../../types/api/tenant';
import {cn} from '../../../utils/cn';
import {USE_CLUSTER_BALANCER_AS_BACKEND_KEY} from '../../../utils/constants';
Expand All @@ -16,8 +13,8 @@ import type {
GetMonitoringClusterLink,
GetMonitoringLink,
} from '../../../utils/monitoring';
import {getCleanBalancerValue, removeViewerPathname} from '../../../utils/parseBalancer';
import {getBackendFromNodeHost, getBackendFromRawNodeData} from '../../../utils/prepareBackend';
import {getCleanBalancerValue, prepareBackendFromBalancer} from '../../../utils/parseBalancer';
import {getBackendFromBalancerAndNodeId} from '../../../utils/prepareBackend';
import type {Cluster} from '../../Cluster/Cluster';

import './ExtendedCluster.scss';
Expand Down Expand Up @@ -89,27 +86,21 @@ const getAdditionalTenantsProps = ({
}: GetAdditionalTenantsProps) => {
const additionalTenantsProps: AdditionalTenantsProps = {};

additionalTenantsProps.prepareTenantBackend = (
nodeHostOrAddress: string | NodeAddress | undefined,
) => {
// Proxy received from balancer value, so it's necessary
additionalTenantsProps.prepareTenantBackend = (nodeId) => {
// Balancer value is used to create path, so it's necessary
if (!balancer) {
return undefined;
}

if (useClusterBalancerAsBackend) {
return removeViewerPathname(balancer);
return prepareBackendFromBalancer(balancer);
}

if (!nodeHostOrAddress) {
if (isNil(nodeId)) {
return undefined;
}

if (typeof nodeHostOrAddress === 'string') {
return getBackendFromNodeHost(nodeHostOrAddress, balancer);
}

return getBackendFromRawNodeData(nodeHostOrAddress, balancer, true) ?? undefined;
return getBackendFromBalancerAndNodeId(nodeId, balancer) ?? undefined;
};

if (monitoring && getMonitoringLink) {
Expand Down
6 changes: 2 additions & 4 deletions src/store/reducers/tenants/tenants.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {createSlice} from '@reduxjs/toolkit';
import type {PayloadAction} from '@reduxjs/toolkit';

import type {RootState} from '../../defaultStore';
import {api} from '../api';

import type {PreparedTenant, TenantsState} from './types';
Expand All @@ -25,15 +24,14 @@ export default slice.reducer;
export const tenantsApi = api.injectEndpoints({
endpoints: (build) => ({
getTenantsInfo: build.query({
queryFn: async ({clusterName}: {clusterName?: string}, {signal, getState}) => {
queryFn: async ({clusterName}: {clusterName?: string}, {signal}) => {
try {
const response = window.api.meta
? await window.api.meta.getTenants(clusterName, {signal})
: await window.api.viewer.getTenants(clusterName, {signal});
let data: PreparedTenant[];
if (Array.isArray(response.TenantInfo)) {
const {singleClusterMode} = getState() as RootState;
data = prepareTenants(response.TenantInfo, singleClusterMode);
data = prepareTenants(response.TenantInfo);
} else {
data = [];
}
Expand Down
1 change: 0 additions & 1 deletion src/store/reducers/tenants/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import type {ValueOf} from '../../../types/common';
import type {METRIC_STATUS} from './contants';

export interface PreparedTenant extends TTenant {
backend: string | undefined;
sharedTenantName: string | undefined;
sharedNodeIds: number[] | undefined;
controlPlaneName: string;
Expand Down
13 changes: 1 addition & 12 deletions src/store/reducers/tenants/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,6 @@ const getControlPlaneValue = (tenant: TTenant) => {
return controlPlaneName ?? defaultValue;
};

const getTenantBackend = (tenant: TTenant) => {
const node = tenant.Nodes ? tenant.Nodes[0] : {};
const address =
node.Host && node.Endpoints
? node.Endpoints.find((endpoint) => endpoint.Name === 'http-mon')?.Address
: undefined;
return node.Host ? `${node.Host}${address ? address : ''}` : undefined;
};

export interface TenantMetricStats<T = string> {
name: T;
usage?: number;
Expand Down Expand Up @@ -174,9 +165,8 @@ const calculateTenantEntities = (tenant: TTenant) => {
return {nodesCount, groupsCount};
};

export const prepareTenants = (tenants: TTenant[], useNodeAsBackend: boolean): PreparedTenant[] => {
export const prepareTenants = (tenants: TTenant[]): PreparedTenant[] => {
return tenants.map((tenant) => {
const backend = useNodeAsBackend ? getTenantBackend(tenant) : undefined;
const sharedDatabase = tenants.find((item) => item.Id === tenant.ResourceId);
const sharedTenantName = sharedDatabase?.Name;
const sharedNodeIds = sharedDatabase?.NodeIds;
Expand All @@ -187,7 +177,6 @@ export const prepareTenants = (tenants: TTenant[], useNodeAsBackend: boolean): P
return {
...tenant,

backend,
sharedTenantName,
sharedNodeIds,
controlPlaneName,
Expand Down
2 changes: 1 addition & 1 deletion src/types/additionalProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export interface AdditionalClusterProps {
}

export interface AdditionalTenantsProps {
prepareTenantBackend?: (backend: string | NodeAddress | undefined) => string | undefined;
prepareTenantBackend?: (nodeId?: string | number) => string | undefined;
getMonitoringLink?: (name?: string, type?: ETenantType) => string | null;
getLogsLink?: (name?: string) => string | null;
}
Expand Down
4 changes: 1 addition & 3 deletions src/types/api/tenant.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type {EFlag} from './enums';
import type {TMemoryStats, TPoolStats, TSystemStateInfo} from './nodes';
import type {TMemoryStats, TPoolStats} from './nodes';
import type {TTabletStateInfo} from './tablet';

/**
Expand Down Expand Up @@ -45,7 +45,6 @@ export interface TTenant {
StorageAllocatedSize?: string; // Actual database size
/** uint64 */
StorageMinAvailableSize?: string;
Nodes?: TSystemStateInfo[];
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nodes and MonitoringEndpoint requires additional param in endpoint (nodes=true), we don't sent this param and thus never have these fields in response

/** uint64 */
MemoryUsed?: string; // Actual memory consumption
/** uint64 */
Expand All @@ -56,7 +55,6 @@ export interface TTenant {
/** uint64 */
StorageGroups?: string;

MonitoringEndpoint?: string; // additional
ControlPlane?: ControlPlane; // additional

StorageAllocatedLimit?: string;
Expand Down
37 changes: 6 additions & 31 deletions src/utils/__test__/prepareBackend.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {getBackendFromNodeHost, getBackendFromRawNodeData, prepareHost} from '../prepareBackend';
import {getBackendFromBalancerAndNodeId, prepareHost} from '../prepareBackend';

describe('prepareHost', () => {
test('should add u- prefix to cloud din nodes', () => {
Expand All @@ -13,37 +13,12 @@ describe('prepareHost', () => {
expect(prepareHost(commonNodeHost)).toBe(commonNodeHost);
});
});
describe('getBackendFromNodeHost', () => {
test('should prepare correct backend value from node host', () => {
describe('getBackendFromBalancerAndNodeId', () => {
test('should prepare correct backend from balancer and node id', () => {
const balancer = 'https://viewer.ydb.ru:443/dev02.ydb.net:8765';
const nodeHost = 'ydb-dev02-001.search.net:31012';
const result = 'https://viewer.ydb.ru:443/ydb-dev02-001.search.net:31012';
const nodeId = '50016';
const result = 'https://viewer.ydb.ru:443/dev02.ydb.net:8765/node/50016';

expect(getBackendFromNodeHost(nodeHost, balancer)).toBe(result);
});
});
describe('getBackendFromRawNodeData', () => {
test('should prepare correct backend value from raw node data', () => {
const balancer = 'https://viewer.ydb.ru:443/dev02.ydb.net:8765';
const node = {
Host: 'ydb-dev02-000.search.net',
Endpoints: [
{
Name: 'http-mon',
Address: ':8765',
},
{
Name: 'ic',
Address: ':19001',
},
{
Name: 'grpc',
Address: ':2135',
},
],
};
const result = 'https://viewer.ydb.ru:443/ydb-dev02-000.search.net:8765';

expect(getBackendFromRawNodeData(node, balancer)).toBe(result);
expect(getBackendFromBalancerAndNodeId(nodeId, balancer)).toBe(result);
});
});
12 changes: 4 additions & 8 deletions src/utils/additionalProps.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import {backend} from '../store';
import type {AdditionalNodesProps, NodeAddress} from '../types/additionalProps';
import type {AdditionalNodesProps} from '../types/additionalProps';

import {getBackendFromRawNodeData} from './prepareBackend';
import {getBackendFromBalancerAndNodeId} from './prepareBackend';

export const getAdditionalNodesProps = (
balancer = backend,
useClusterBalancerAsBackend?: boolean,
): AdditionalNodesProps => {
export const getAdditionalNodesProps = (balancer = backend): AdditionalNodesProps => {
return {
getNodeRef: (node: NodeAddress = {}) =>
getBackendFromRawNodeData(node, balancer ?? '', useClusterBalancerAsBackend),
getNodeRef: (node) => getBackendFromBalancerAndNodeId(node?.NodeId, balancer ?? ''),
};
};
5 changes: 1 addition & 4 deletions src/utils/hooks/useAdditionalNodesProps.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import {useClusterBaseInfo} from '../../store/reducers/cluster/cluster';
import {getAdditionalNodesProps} from '../additionalProps';
import {USE_CLUSTER_BALANCER_AS_BACKEND_KEY} from '../constants';

import {useSetting} from './useSetting';
import {useTypedSelector} from './useTypedSelector';

/** For multi-cluster version */
export function useAdditionalNodesProps() {
const {balancer} = useClusterBaseInfo();
const [useClusterBalancerAsBackend] = useSetting<boolean>(USE_CLUSTER_BALANCER_AS_BACKEND_KEY);
const singleClusterMode = useTypedSelector((state) => state.singleClusterMode);

const additionalNodesProps = getAdditionalNodesProps(balancer, useClusterBalancerAsBackend);
const additionalNodesProps = getAdditionalNodesProps(balancer);

return singleClusterMode ? undefined : additionalNodesProps;
}
45 changes: 6 additions & 39 deletions src/utils/prepareBackend.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,17 @@
import type {NodeAddress} from '../types/additionalProps';
import {prepareBackendFromBalancer} from './parseBalancer';

import {parseBalancer, removeViewerPathname} from './parseBalancer';

const https = 'https://';
import {valueIsDefined} from '.';

export const prepareHost = (host?: string) => {
// add "u-" prefix to cloud din nodes
return host?.startsWith('vm-') ? `u-${host}` : host;
};

export const getBackendFromNodeHost = (nodeHost: string, balancer: string) => {
const preparedHost = prepareHost(nodeHost);
const proxy = parseBalancer(balancer).proxy;

if (proxy) {
return https + proxy + '/' + preparedHost;
}

return https + preparedHost;
};

/** For multi-cluster version */
export const getBackendFromRawNodeData = (
node: NodeAddress,
balancer: string,
useBalancerAsBackend?: boolean,
) => {
const {Host, Endpoints, NodeId} = node;

if (useBalancerAsBackend && NodeId) {
const preparedBalancer = removeViewerPathname(balancer);
return `${preparedBalancer}/node/${NodeId}`;
}

if (Host && Endpoints) {
const nodePort = Endpoints.find((endpoint) => endpoint.Name === 'http-mon')?.Address;

if (!nodePort || !Host) {
return undefined;
}

const hostWithPort = Host + nodePort;

// Currently this func is used to get link to developerUI for specific node
// It's expected with / at the end (code in embedded version)
return getBackendFromNodeHost(hostWithPort, balancer);
export const getBackendFromBalancerAndNodeId = (nodeId?: string | number, balancer?: string) => {
if (valueIsDefined(nodeId) && valueIsDefined(balancer)) {
const preparedBalancer = prepareBackendFromBalancer(balancer);
return `${preparedBalancer}/node/${nodeId}`;
}

return undefined;
Expand Down
Loading