Skip to content

Commit c8d7f60

Browse files
committed
ARTESCA-14896: Add attachHardwareVolume in Metalk8sLocalVolumeProvider
1 parent 8bf7b3d commit c8d7f60

File tree

2 files changed

+133
-0
lines changed

2 files changed

+133
-0
lines changed

ui/src/services/k8s/Metalk8sLocalVolumeProvider.test.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,4 +273,91 @@ describe('Metalk8sLocalVolumeProvider', () => {
273273
);
274274
});
275275
});
276+
277+
describe('attachHardwareVolume', () => {
278+
it('should attach hardware volumes', async () => {
279+
//S
280+
(mockCoreV1Api.listNode as jest.Mock).mockResolvedValue({
281+
body: {
282+
apiVersion: 'v1',
283+
kind: 'NodeList',
284+
items: [
285+
{
286+
metadata: {
287+
name: 'test-node',
288+
},
289+
status: {
290+
addresses: [{ type: 'InternalIP', address: '192.168.1.100' }],
291+
},
292+
},
293+
],
294+
},
295+
});
296+
(
297+
mockVolumeClient.createMetalk8sV1alpha1Volume as jest.Mock
298+
).mockResolvedValue({
299+
body: {},
300+
});
301+
//E
302+
await provider.attachHardwareVolume([
303+
{
304+
IP: '192.168.1.100',
305+
devicePath: '/dev/sda',
306+
storageClassName: 'hdd-ext4',
307+
},
308+
]);
309+
//V
310+
expect(
311+
mockVolumeClient.createMetalk8sV1alpha1Volume,
312+
).toHaveBeenCalledWith({
313+
apiVersion: 'storage.metalk8s.scality.com/v1alpha1',
314+
kind: 'Volume',
315+
metadata: {
316+
name: 'storage-data-192.168.1.100-/dev/sda',
317+
labels: {
318+
'xcore.scality.com/volume-type': 'data',
319+
},
320+
},
321+
spec: {
322+
nodeName: 'test-node',
323+
rawBlockDevice: { devicePath: '/dev/sda' },
324+
storageClassName: 'hdd-ext4',
325+
},
326+
});
327+
});
328+
329+
it('should raise an error if volume creation fails', async () => {
330+
//S
331+
(
332+
mockVolumeClient.createMetalk8sV1alpha1Volume as jest.Mock
333+
).mockRejectedValue(new Error('Failed to create volume'));
334+
//E+V
335+
await expect(
336+
provider.attachHardwareVolume([
337+
{
338+
IP: '192.168.1.100',
339+
devicePath: '/dev/sda',
340+
storageClassName: 'hdd-ext4',
341+
},
342+
]),
343+
).rejects.toThrow('Failed to create volume');
344+
});
345+
346+
it('should raise an error if node retrieval fails', async () => {
347+
//S
348+
(mockCoreV1Api.listNode as jest.Mock).mockRejectedValue(
349+
new Error('Failed to fetch nodes'),
350+
);
351+
//E+V
352+
await expect(
353+
provider.attachHardwareVolume([
354+
{
355+
IP: '192.168.1.100',
356+
devicePath: '/dev/sda',
357+
storageClassName: 'hdd-ext4',
358+
},
359+
]),
360+
).rejects.toThrow('Failed to fetch nodes');
361+
});
362+
});
276363
});

ui/src/services/k8s/Metalk8sLocalVolumeProvider.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,50 @@ export default class Metalk8sLocalVolumeProvider {
129129
}
130130
}
131131
};
132+
133+
public attachHardwareVolume = async (
134+
hardwareVolumes: {
135+
IP: string;
136+
devicePath: string;
137+
storageClassName: string;
138+
}[],
139+
): Promise<void> => {
140+
const nodes = await this.k8sClient.listNode();
141+
if (isError(nodes)) {
142+
throw new Error(`Failed to fetch nodes: ${nodes.error}`);
143+
}
144+
145+
for (const hardwareVolume of hardwareVolumes) {
146+
const nodeName = nodes.body.items.find((node) =>
147+
node.status.addresses.find(
148+
(address) =>
149+
address.type === 'InternalIP' &&
150+
address.address === hardwareVolume.IP,
151+
),
152+
)?.metadata.name;
153+
if (!nodeName) {
154+
throw new Error(`Failed to find node for IP ${hardwareVolume.IP}`);
155+
}
156+
157+
const volume = await this.volumeClient.createMetalk8sV1alpha1Volume({
158+
apiVersion: 'storage.metalk8s.scality.com/v1alpha1',
159+
kind: 'Volume',
160+
metadata: {
161+
// It will be change to serial number in the future
162+
name: `storage-data-${hardwareVolume.IP}-${hardwareVolume.devicePath}`,
163+
labels: {
164+
'xcore.scality.com/volume-type': 'data',
165+
},
166+
},
167+
spec: {
168+
nodeName: nodeName,
169+
rawBlockDevice: { devicePath: hardwareVolume.devicePath },
170+
storageClassName: hardwareVolume.storageClassName,
171+
},
172+
});
173+
if (isError(volume)) {
174+
throw new Error(`Failed to create metalk8s volume: ${volume.error}`);
175+
}
176+
}
177+
};
132178
}

0 commit comments

Comments
 (0)