Skip to content

Commit 8843792

Browse files
committed
fix: show PDisk/VDisk pages for previous backend versions
1 parent 0a55408 commit 8843792

File tree

9 files changed

+140
-39
lines changed

9 files changed

+140
-39
lines changed

src/components/PDiskInfo/PDiskInfo.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import {Flex} from '@gravity-ui/uikit';
22

33
import {getPDiskPagePath} from '../../routes';
44
import {selectIsUserAllowedToMakeChanges} from '../../store/reducers/authentication/authentication';
5-
import {useDiskPagesAvailable} from '../../store/reducers/capabilities/hooks';
65
import {valueIsDefined} from '../../utils';
76
import {formatBytes} from '../../utils/bytesParsers';
87
import {cn} from '../../utils/cn';
@@ -191,12 +190,11 @@ export function PDiskInfo<T extends PreparedPDisk>({
191190
className,
192191
}: PDiskInfoProps<T>) {
193192
const isUserAllowedToMakeChanges = useTypedSelector(selectIsUserAllowedToMakeChanges);
194-
const diskPagesAvailable = useDiskPagesAvailable();
195193

196194
const [generalInfo, statusInfo, spaceInfo, additionalInfo] = getPDiskInfo({
197195
pDisk,
198196
nodeId,
199-
withPDiskPageLink: withPDiskPageLink && diskPagesAvailable,
197+
withPDiskPageLink,
200198
isUserAllowedToMakeChanges,
201199
});
202200

src/components/VDiskInfo/VDiskInfo.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import React from 'react';
22

33
import {getVDiskPagePath} from '../../routes';
44
import {selectIsUserAllowedToMakeChanges} from '../../store/reducers/authentication/authentication';
5-
import {useDiskPagesAvailable} from '../../store/reducers/capabilities/hooks';
65
import {valueIsDefined} from '../../utils';
76
import {cn} from '../../utils/cn';
87
import {formatStorageValuesToGb, stringifyVdiskId} from '../../utils/dataFormatters/dataFormatters';
@@ -36,7 +35,6 @@ export function VDiskInfo<T extends PreparedVDisk>({
3635
withTitle,
3736
...infoViewerProps
3837
}: VDiskInfoProps<T>) {
39-
const diskPagesAvailable = useDiskPagesAvailable();
4038
const isUserAllowedToMakeChanges = useTypedSelector(selectIsUserAllowedToMakeChanges);
4139

4240
const {
@@ -154,7 +152,7 @@ export function VDiskInfo<T extends PreparedVDisk>({
154152
if (diskParamsDefined) {
155153
const links: React.ReactNode[] = [];
156154

157-
if (withVDiskPageLink && diskPagesAvailable) {
155+
if (withVDiskPageLink) {
158156
const vDiskPagePath = getVDiskPagePath(VDiskSlotId, PDiskId, NodeId);
159157
links.push(
160158
<LinkWithIcon

src/containers/Node/Node.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ import {ResponseError} from '../../components/Errors/ResponseError';
1010
import {FullNodeViewer} from '../../components/FullNodeViewer/FullNodeViewer';
1111
import {Loader} from '../../components/Loader';
1212
import routes, {createHref, parseQuery} from '../../routes';
13-
import {useDiskPagesAvailable} from '../../store/reducers/capabilities/hooks';
13+
import {
14+
useCapabilitiesLoaded,
15+
useDiskPagesAvailable,
16+
} from '../../store/reducers/capabilities/hooks';
1417
import {setHeaderBreadcrumbs} from '../../store/reducers/header/header';
1518
import {nodeApi} from '../../store/reducers/node/node';
1619
import type {AdditionalNodesProps} from '../../types/additionalProps';
@@ -52,6 +55,7 @@ export function Node(props: NodeProps) {
5255
);
5356
const loading = isFetching && currentData === undefined;
5457
const node = currentData;
58+
const capabilitiesLoaded = useCapabilitiesLoaded();
5559
const isDiskPagesAvailable = useDiskPagesAvailable();
5660

5761
const {activeTabVerified, nodeTabs} = React.useMemo(() => {
@@ -149,7 +153,7 @@ export function Node(props: NodeProps) {
149153
}
150154
};
151155

152-
if (loading) {
156+
if (loading || !capabilitiesLoaded) {
153157
return <Loader size="l" />;
154158
}
155159

src/containers/PDiskPage/PDiskPage.tsx

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {PageMetaWithAutorefresh} from '../../components/PageMeta/PageMeta';
1717
import {getPDiskPagePath} from '../../routes';
1818
import {api} from '../../store/reducers/api';
1919
import {selectIsUserAllowedToMakeChanges} from '../../store/reducers/authentication/authentication';
20+
import {useDiskPagesAvailable} from '../../store/reducers/capabilities/hooks';
2021
import {setHeaderBreadcrumbs} from '../../store/reducers/header/header';
2122
import {pDiskApi} from '../../store/reducers/pdisk/pdisk';
2223
import type {EDecommitStatus} from '../../types/api/pdisk';
@@ -61,6 +62,7 @@ export function PDiskPage() {
6162
const dispatch = useTypedDispatch();
6263

6364
const isUserAllowedToMakeChanges = useTypedSelector(selectIsUserAllowedToMakeChanges);
65+
const newDiskApiAvailable = useDiskPagesAvailable();
6466

6567
const [{nodeId, pDiskId, activeTab}] = useQueryParams({
6668
activeTab: StringParam,
@@ -87,7 +89,9 @@ export function PDiskPage() {
8789

8890
const handleRestart = async (isRetry?: boolean) => {
8991
if (pDiskParamsDefined) {
90-
const response = await window.api.restartPDisk({nodeId, pDiskId, force: isRetry});
92+
const response = await window.api[
93+
newDiskApiAvailable ? 'restartPDisk' : 'restartPDiskOld'
94+
]({nodeId, pDiskId, force: isRetry});
9195

9296
if (response?.result === false) {
9397
const err = {
@@ -188,13 +192,15 @@ export function PDiskPage() {
188192
<Icon data={ArrowRotateLeft} />
189193
{pDiskPageKeyset('restart-pdisk-button')}
190194
</ButtonWithConfirmDialog>
191-
<DecommissionButton
192-
decommission={DecommitStatus}
193-
onConfirmAction={handleDecommissionChange}
194-
onConfirmActionSuccess={handleAfterAction}
195-
buttonDisabled={!pDiskParamsDefined || !isUserAllowedToMakeChanges}
196-
popoverDisabled={isUserAllowedToMakeChanges}
197-
/>
195+
{newDiskApiAvailable ? (
196+
<DecommissionButton
197+
decommission={DecommitStatus}
198+
onConfirmAction={handleDecommissionChange}
199+
onConfirmActionSuccess={handleAfterAction}
200+
buttonDisabled={!pDiskParamsDefined || !isUserAllowedToMakeChanges}
201+
popoverDisabled={isUserAllowedToMakeChanges}
202+
/>
203+
) : null}
198204
</div>
199205
);
200206
};

src/containers/VDiskPage/VDiskPage.tsx

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {PageMetaWithAutorefresh} from '../../components/PageMeta/PageMeta';
1414
import {VDiskInfo} from '../../components/VDiskInfo/VDiskInfo';
1515
import {api} from '../../store/reducers/api';
1616
import {selectIsUserAllowedToMakeChanges} from '../../store/reducers/authentication/authentication';
17+
import {useDiskPagesAvailable} from '../../store/reducers/capabilities/hooks';
1718
import {setHeaderBreadcrumbs} from '../../store/reducers/header/header';
1819
import {vDiskApi} from '../../store/reducers/vdisk/vdisk';
1920
import {valueIsDefined} from '../../utils';
@@ -33,6 +34,7 @@ export function VDiskPage() {
3334
const dispatch = useTypedDispatch();
3435

3536
const isUserAllowedToMakeChanges = useTypedSelector(selectIsUserAllowedToMakeChanges);
37+
const newDiskApiAvailable = useDiskPagesAvailable();
3638

3739
const [{nodeId, pDiskId, vDiskSlotId}] = useQueryParams({
3840
nodeId: StringParam,
@@ -68,24 +70,22 @@ export function VDiskPage() {
6870

6971
const handleEvictVDisk = async (isRetry?: boolean) => {
7072
if (vDiskIdParamsDefined) {
71-
return window.api
72-
.evictVDisk({
73-
groupId: GroupID,
74-
groupGeneration: GroupGeneration,
75-
failRealmIdx: Ring,
76-
failDomainIdx: Domain,
77-
vDiskIdx: VDisk,
78-
force: isRetry,
79-
})
80-
.then((response) => {
81-
if (response?.result === false) {
82-
const err = {
83-
statusText: response.error,
84-
retryPossible: response.forceRetryPossible,
85-
};
86-
throw err;
87-
}
88-
});
73+
return window.api[newDiskApiAvailable ? 'evictVDisk' : 'evictVDiskOld']({
74+
groupId: GroupID,
75+
groupGeneration: GroupGeneration,
76+
failRealmIdx: Ring,
77+
failDomainIdx: Domain,
78+
vDiskIdx: VDisk,
79+
force: isRetry,
80+
}).then((response) => {
81+
if (response?.result === false) {
82+
const err = {
83+
statusText: response.error,
84+
retryPossible: response.forceRetryPossible,
85+
};
86+
throw err;
87+
}
88+
});
8989
}
9090

9191
return undefined;

src/services/api.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ import {
5858
DEV_ENABLE_TRACING_FOR_ALL_REQUESTS,
5959
SECOND_IN_MS,
6060
} from '../utils/constants';
61+
import {createPDiskDeveloperUILink} from '../utils/developerUI/developerUI';
6162
import {isAxiosError} from '../utils/response';
6263
import type {Nullable} from '../utils/typecheckers';
6364

@@ -629,6 +630,45 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
629630
{concurrentId, requestConfig: {signal}},
630631
);
631632
}
633+
evictVDiskOld({
634+
groupId,
635+
groupGeneration,
636+
failRealmIdx,
637+
failDomainIdx,
638+
vDiskIdx,
639+
}: {
640+
groupId: string | number;
641+
groupGeneration: string | number;
642+
failRealmIdx: string | number;
643+
failDomainIdx: string | number;
644+
vDiskIdx: string | number;
645+
}) {
646+
// BSC Id is constant for all ydb clusters
647+
const BSC_TABLET_ID = '72057594037932033';
648+
649+
return this.post(
650+
this.getPath(`/tablets/app?TabletID=${BSC_TABLET_ID}&exec=1`),
651+
{
652+
Command: {
653+
ReassignGroupDisk: {
654+
GroupId: groupId,
655+
GroupGeneration: groupGeneration,
656+
FailRealmIdx: failRealmIdx,
657+
FailDomainIdx: failDomainIdx,
658+
VDiskIdx: vDiskIdx,
659+
},
660+
},
661+
},
662+
{},
663+
{
664+
headers: {
665+
// This handler requires exactly this string
666+
// Automatic headers may not suit
667+
Accept: 'application/json',
668+
},
669+
},
670+
);
671+
}
632672
evictVDisk({
633673
groupId,
634674
groupGeneration,
@@ -661,6 +701,26 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
661701
},
662702
);
663703
}
704+
705+
restartPDiskOld({nodeId, pDiskId}: {nodeId: number | string; pDiskId: number | string}) {
706+
const pDiskPath = createPDiskDeveloperUILink({
707+
nodeId,
708+
pDiskId,
709+
host: this.getPath(''),
710+
});
711+
712+
return this.post<ModifyDiskResponse>(
713+
pDiskPath,
714+
'restartPDisk=',
715+
{},
716+
{
717+
headers: {
718+
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
719+
},
720+
},
721+
);
722+
}
723+
664724
restartPDisk({
665725
nodeId,
666726
pDiskId,

src/store/reducers/capabilities/capabilities.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {createSelector} from '@reduxjs/toolkit';
22

33
import type {Capability} from '../../../types/api/capabilities';
4-
import type {RootState} from '../../defaultStore';
4+
import type {AppDispatch, RootState} from '../../defaultStore';
55

66
import {api} from './../api';
77

@@ -23,10 +23,23 @@ export const capabilitiesApi = api.injectEndpoints({
2323
overrideExisting: 'throw',
2424
});
2525

26-
const selectCapabilities = capabilitiesApi.endpoints.getClusterCapabilities.select(undefined);
26+
export const selectCapabilities =
27+
capabilitiesApi.endpoints.getClusterCapabilities.select(undefined);
2728

2829
export const selectCapabilityVersion = createSelector(
2930
(state: RootState) => state,
3031
(_state: RootState, capability: Capability) => capability,
3132
(state, capability) => selectCapabilities(state).data?.Capabilities?.[capability],
3233
);
34+
35+
export async function queryCapability(
36+
capability: Capability,
37+
{dispatch, getState}: {dispatch: AppDispatch; getState: () => RootState},
38+
) {
39+
const thunk = capabilitiesApi.util.getRunningQueryThunk('getClusterCapabilities', undefined);
40+
await dispatch(thunk);
41+
const capabilityVersion =
42+
capabilitiesApi.endpoints.getClusterCapabilities.select(undefined)(getState() as any).data
43+
?.Capabilities?.[capability] || 0;
44+
return capabilityVersion;
45+
}

src/store/reducers/pdisk/pdisk.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import type {TPDiskInfoResponse} from '../../../types/api/pdisk';
12
import {getPDiskId} from '../../../utils/disks/helpers';
23
import {api} from '../api';
4+
import {queryCapability} from '../capabilities/capabilities';
35

46
import {preparePDiskDataResponse} from './utils';
57

@@ -11,10 +13,30 @@ interface PDiskParams {
1113
export const pDiskApi = api.injectEndpoints({
1214
endpoints: (build) => ({
1315
getPdiskInfo: build.query({
14-
queryFn: async ({nodeId, pDiskId}: PDiskParams, {signal}) => {
16+
queryFn: async ({nodeId, pDiskId}: PDiskParams, {signal, getState, dispatch}) => {
17+
const newApiAvailable =
18+
(await queryCapability('/pdisk/info', {getState: getState as any, dispatch})) >
19+
0;
20+
21+
let diskInfoPromise: Promise<TPDiskInfoResponse>;
22+
if (newApiAvailable) {
23+
diskInfoPromise = window.api.getPDiskInfo({nodeId, pDiskId}, {signal});
24+
} else {
25+
diskInfoPromise = window.api
26+
.getNodeWhiteboardPDiskInfo({nodeId, pDiskId}, {signal})
27+
.then((result) => {
28+
if (result.PDiskStateInfo) {
29+
return {
30+
Whiteboard: {PDisk: result.PDiskStateInfo[0]},
31+
};
32+
}
33+
return {};
34+
});
35+
}
36+
1537
try {
1638
const response = await Promise.all([
17-
window.api.getPDiskInfo({nodeId, pDiskId}, {signal}),
39+
diskInfoPromise,
1840
window.api.getNodeInfo(nodeId, {signal}),
1941
]);
2042
const data = preparePDiskDataResponse(response);

src/store/reducers/pdisk/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ export function preparePDiskDataResponse([pdiskResponse = {}, nodeResponse]: [
9090

9191
const diskSlots: PDiskData['SlotItems'] = [...vdisksSlots, ...emptySlots];
9292

93-
if (logSlot) {
93+
if (logSlot && diskSlots.length > 0) {
9494
diskSlots.unshift(logSlot);
9595
}
9696

0 commit comments

Comments
 (0)