Skip to content

Commit f98003e

Browse files
authored
sync(*): master to develop
sync(*): master to develop
2 parents 7578d0d + 8497a15 commit f98003e

14 files changed

Lines changed: 482 additions & 31 deletions

packages/manager/apps/pci-block-storage/public/translations/common/Messages_de_DE.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
"pci_projects_project_storages_blocks_encryption_unavailable": "Verschlüsselung nicht verfügbar",
2727
"pci_projects_project_storages_blocks_guaranteed": "garantiert",
2828
"pci_projects_project_storages_blocks_up_to": "bis zu",
29+
"pci_projects_project_storages_blocks_iops_base_range": "Basis von {{min}} IOPS zwischen {{minSize}} {{sizeUnit}} und {{maxSize}} {{sizeUnit}}",
30+
"pci_projects_project_storages_blocks_bandwidth_base_range": "Basis von {{min}} {{unit}} zwischen {{minSize}} {{sizeUnit}} und {{maxSize}} {{sizeUnit}}",
2931
"pci_projects_project_storages_blocks_guides_header": "Guides",
3032
"pci_projects_project_storages_blocks_guides_all_block_storage_guides": "Alle Guides zu Block Storage",
3133
"pci_projects_project_storages_blocks_guides_first_steps_with_volumes": "Erste Schritte mit Volumes",

packages/manager/apps/pci-block-storage/public/translations/common/Messages_en_GB.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
"pci_projects_project_storages_blocks_encryption_unavailable": "Encryption not available",
2727
"pci_projects_project_storages_blocks_guaranteed": "guaranteed",
2828
"pci_projects_project_storages_blocks_up_to": "up to",
29+
"pci_projects_project_storages_blocks_iops_base_range": "Base of {{min}} IOPS between {{minSize}} {{sizeUnit}} and {{maxSize}} {{sizeUnit}}",
30+
"pci_projects_project_storages_blocks_bandwidth_base_range": "Base of {{min}} {{unit}} between {{minSize}} {{sizeUnit}} and {{maxSize}} {{sizeUnit}}",
2931
"pci_projects_project_storages_blocks_guides_header": "Guides",
3032
"pci_projects_project_storages_blocks_guides_all_block_storage_guides": "All block storage guides",
3133
"pci_projects_project_storages_blocks_guides_first_steps_with_volumes": "Getting started with volumes",

packages/manager/apps/pci-block-storage/public/translations/common/Messages_es_ES.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
"pci_projects_project_storages_blocks_encryption_unavailable": "Cifrado no disponible",
2727
"pci_projects_project_storages_blocks_guaranteed": "garantizada",
2828
"pci_projects_project_storages_blocks_up_to": "hasta",
29+
"pci_projects_project_storages_blocks_iops_base_range": "Base de {{min}} IOPS entre {{minSize}} {{sizeUnit}} y {{maxSize}} {{sizeUnit}}",
30+
"pci_projects_project_storages_blocks_bandwidth_base_range": "Base de {{min}} {{unit}} entre {{minSize}} {{sizeUnit}} y {{maxSize}} {{sizeUnit}}",
2931
"pci_projects_project_storages_blocks_guides_header": "Guías",
3032
"pci_projects_project_storages_blocks_guides_all_block_storage_guides": "Todas las guías del block storage",
3133
"pci_projects_project_storages_blocks_guides_first_steps_with_volumes": "Primeros pasos con los volúmenes",

packages/manager/apps/pci-block-storage/public/translations/common/Messages_fr_CA.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
"pci_projects_project_storages_blocks_encryption_unavailable": "Chiffrement indisponible",
2828
"pci_projects_project_storages_blocks_guaranteed": "garantie",
2929
"pci_projects_project_storages_blocks_up_to": "jusqu'à",
30+
"pci_projects_project_storages_blocks_iops_base_range": "Base de {{min}} IOPS entre {{minSize}} {{sizeUnit}} et {{maxSize}} {{sizeUnit}}",
31+
"pci_projects_project_storages_blocks_bandwidth_base_range": "Base de {{min}} {{unit}} entre {{minSize}} {{sizeUnit}} et {{maxSize}} {{sizeUnit}}",
3032
"pci_projects_project_storages_blocks_guides_header": "Guides",
3133
"pci_projects_project_storages_blocks_guides_all_block_storage_guides": "Tous les guides block storage",
3234
"pci_projects_project_storages_blocks_guides_first_steps_with_volumes": "Premiers pas avec les volumes"

packages/manager/apps/pci-block-storage/public/translations/common/Messages_fr_FR.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
"pci_projects_project_storages_blocks_encryption_unavailable": "Chiffrement indisponible",
2828
"pci_projects_project_storages_blocks_guaranteed": "garantie",
2929
"pci_projects_project_storages_blocks_up_to": "jusqu'à",
30+
"pci_projects_project_storages_blocks_iops_base_range": "Base de {{min}} IOPS entre {{minSize}} {{sizeUnit}} et {{maxSize}} {{sizeUnit}}",
31+
"pci_projects_project_storages_blocks_bandwidth_base_range": "Base de {{min}} {{unit}} entre {{minSize}} {{sizeUnit}} et {{maxSize}} {{sizeUnit}}",
3032
"pci_projects_project_storages_blocks_guides_header": "Guides",
3133
"pci_projects_project_storages_blocks_guides_all_block_storage_guides": "Tous les guides block storage",
3234
"pci_projects_project_storages_blocks_guides_first_steps_with_volumes": "Premiers pas avec les volumes"

packages/manager/apps/pci-block-storage/public/translations/common/Messages_it_IT.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
"pci_projects_project_storages_blocks_encryption_unavailable": "Crittografia non disponibile",
2727
"pci_projects_project_storages_blocks_guaranteed": "garantita",
2828
"pci_projects_project_storages_blocks_up_to": "fino a",
29+
"pci_projects_project_storages_blocks_iops_base_range": "Base di {{min}} IOPS tra {{minSize}} {{sizeUnit}} e {{maxSize}} {{sizeUnit}}",
30+
"pci_projects_project_storages_blocks_bandwidth_base_range": "Base di {{min}} {{unit}} tra {{minSize}} {{sizeUnit}} e {{maxSize}} {{sizeUnit}}",
2931
"pci_projects_project_storages_blocks_guides_header": "Guide",
3032
"pci_projects_project_storages_blocks_guides_all_block_storage_guides": "Tutte le guide Block Storage",
3133
"pci_projects_project_storages_blocks_guides_first_steps_with_volumes": "Iniziare a utilizzare i volumi",

packages/manager/apps/pci-block-storage/public/translations/common/Messages_pl_PL.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
"pci_projects_project_storages_blocks_encryption_unavailable": "Szyfrowanie niedostępne",
2727
"pci_projects_project_storages_blocks_guaranteed": "o gwarantowanej przepustowości",
2828
"pci_projects_project_storages_blocks_up_to": "do",
29+
"pci_projects_project_storages_blocks_iops_base_range": "Podstawa {{min}} IOPS między {{minSize}} {{sizeUnit}} a {{maxSize}} {{sizeUnit}}",
30+
"pci_projects_project_storages_blocks_bandwidth_base_range": "Podstawa {{min}} {{unit}} między {{minSize}} {{sizeUnit}} a {{maxSize}} {{sizeUnit}}",
2931
"pci_projects_project_storages_blocks_guides_header": "Przewodniki",
3032
"pci_projects_project_storages_blocks_guides_all_block_storage_guides": "Przewodniki dotyczące block storage",
3133
"pci_projects_project_storages_blocks_guides_first_steps_with_volumes": "Pierwsze kroki z wolumenami",

packages/manager/apps/pci-block-storage/public/translations/common/Messages_pt_PT.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
"pci_projects_project_storages_blocks_encryption_unavailable": "Encriptação indisponível",
2727
"pci_projects_project_storages_blocks_guaranteed": "garantida",
2828
"pci_projects_project_storages_blocks_up_to": "até",
29+
"pci_projects_project_storages_blocks_iops_base_range": "Base de {{min}} IOPS entre {{minSize}} {{sizeUnit}} e {{maxSize}} {{sizeUnit}}",
30+
"pci_projects_project_storages_blocks_bandwidth_base_range": "Base de {{min}} {{unit}} entre {{minSize}} {{sizeUnit}} e {{maxSize}} {{sizeUnit}}",
2931
"pci_projects_project_storages_blocks_guides_header": "Manuais",
3032
"pci_projects_project_storages_blocks_guides_all_block_storage_guides": "Todos os guias Block Storage",
3133
"pci_projects_project_storages_blocks_guides_first_steps_with_volumes": "Introdução aos volumes",
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
// Copyright (c) OVH SAS
3+
4+
import { describe, expect, it } from 'vitest';
5+
import { applyHardcodedSpecOverrides } from './catalog-spec-overrides';
6+
import { TVolumeCatalog, TVolumePricing } from './catalog';
7+
8+
const makePricing = (
9+
overrides: Partial<TVolumePricing['specs']['volume']['iops']> = {},
10+
bandwidthOverrides: Partial<
11+
NonNullable<TVolumePricing['specs']['bandwidth']>
12+
> | null = {},
13+
): TVolumePricing =>
14+
({
15+
price: 0,
16+
regions: [],
17+
showAvailabilityZones: false,
18+
interval: 'hour',
19+
areIOPSDynamic: true,
20+
isBandwidthDynamic: true,
21+
specs: {
22+
name: 'spec',
23+
maxAttachedInstances: 1,
24+
bandwidth:
25+
bandwidthOverrides === null
26+
? null
27+
: {
28+
guaranteed: false,
29+
level: 1,
30+
max: 1000,
31+
...bandwidthOverrides,
32+
},
33+
volume: {
34+
iops: {
35+
level: 1,
36+
max: 10000,
37+
guaranteed: false,
38+
unit: 'u',
39+
maxUnit: 'u',
40+
...overrides,
41+
},
42+
capacity: { max: 4000 },
43+
},
44+
},
45+
} as TVolumePricing);
46+
47+
const makeCatalog = (
48+
modelName: string,
49+
pricings: TVolumePricing[],
50+
): TVolumeCatalog =>
51+
(({
52+
filters: { deployment: [], region: [] },
53+
regions: [],
54+
models: [
55+
{
56+
name: modelName,
57+
tags: [],
58+
filters: {},
59+
pricings,
60+
},
61+
],
62+
} as unknown) as TVolumeCatalog);
63+
64+
describe('applyHardcodedSpecOverrides', () => {
65+
it('injects iops min and bandwidth min on high-speed-gen2 when not guaranteed', () => {
66+
const catalog = makeCatalog('high-speed-gen2', [makePricing()]);
67+
68+
const result = applyHardcodedSpecOverrides(catalog);
69+
70+
const pricing = result.models[0].pricings[0];
71+
expect(pricing.specs.volume.iops.min).toBe(3000);
72+
expect(pricing.specs.bandwidth?.min).toBe(50);
73+
});
74+
75+
it('injects iops min and bandwidth min on high-speed-gen2-luks when not guaranteed', () => {
76+
const catalog = makeCatalog('high-speed-gen2-luks', [makePricing()]);
77+
78+
const result = applyHardcodedSpecOverrides(catalog);
79+
80+
const pricing = result.models[0].pricings[0];
81+
expect(pricing.specs.volume.iops.min).toBe(3000);
82+
expect(pricing.specs.bandwidth?.min).toBe(50);
83+
});
84+
85+
it('does not override iops or bandwidth when the spec is guaranteed', () => {
86+
const catalog = makeCatalog('high-speed-gen2', [
87+
makePricing({ guaranteed: true }, { guaranteed: true }),
88+
]);
89+
90+
const result = applyHardcodedSpecOverrides(catalog);
91+
92+
const pricing = result.models[0].pricings[0];
93+
expect(pricing.specs.volume.iops.min).toBeUndefined();
94+
expect(pricing.specs.bandwidth?.min).toBeUndefined();
95+
});
96+
97+
it('does not override when the API already returned a positive min', () => {
98+
const catalog = makeCatalog('high-speed-gen2', [
99+
makePricing({ min: 9999 }, { min: 999 }),
100+
]);
101+
102+
const result = applyHardcodedSpecOverrides(catalog);
103+
104+
const pricing = result.models[0].pricings[0];
105+
expect(pricing.specs.volume.iops.min).toBe(9999);
106+
expect(pricing.specs.bandwidth?.min).toBe(999);
107+
});
108+
109+
it('overrides when the API returned a non-positive min (0 or null)', () => {
110+
const catalog = makeCatalog('high-speed-gen2', [
111+
makePricing({ min: 0 }, { min: null }),
112+
]);
113+
114+
const result = applyHardcodedSpecOverrides(catalog);
115+
116+
const pricing = result.models[0].pricings[0];
117+
expect(pricing.specs.volume.iops.min).toBe(3000);
118+
expect(pricing.specs.bandwidth?.min).toBe(50);
119+
});
120+
121+
it('leaves non-overridden models untouched', () => {
122+
const catalog = makeCatalog('classic', [makePricing()]);
123+
124+
const result = applyHardcodedSpecOverrides(catalog);
125+
126+
const pricing = result.models[0].pricings[0];
127+
expect(pricing.specs.volume.iops.min).toBeUndefined();
128+
expect(pricing.specs.bandwidth?.min).toBeUndefined();
129+
});
130+
131+
it('handles a null bandwidth spec without throwing', () => {
132+
const catalog = makeCatalog('high-speed-gen2', [makePricing({}, null)]);
133+
134+
const result = applyHardcodedSpecOverrides(catalog);
135+
136+
const pricing = result.models[0].pricings[0];
137+
expect(pricing.specs.volume.iops.min).toBe(3000);
138+
expect(pricing.specs.bandwidth).toBeNull();
139+
});
140+
});
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
// Copyright (c) OVH SAS
3+
4+
// TEMPORARY — hard-coded overrides for gen2 / gen2-luks volume specs.
5+
// /cloud/project/{id}/catalog/volume will eventually return a `min` value on
6+
// iops and bandwidth specs for these models. Until then, we inject the values
7+
// client-side here so the rest of the app can consume the catalog as if `min`
8+
// were always provided.
9+
//
10+
// The override never replaces a positive `min` already returned by the API:
11+
// once the catalog ships its own value the patch becomes inert, and removal
12+
// becomes purely cosmetic.
13+
//
14+
// To remove: delete this file and the call in catalog.ts:getVolumeCatalog.
15+
16+
import { TVolumeCatalog } from './catalog';
17+
18+
const HARDCODED_IOPS_MIN = 3000;
19+
const HARDCODED_BANDWIDTH_MIN = 50; // MiB/s
20+
const OVERRIDDEN_MODEL_NAMES = ['high-speed-gen2', 'high-speed-gen2-luks'];
21+
22+
const hasPositiveMin = (value: number | null | undefined): boolean =>
23+
typeof value === 'number' && value > 0;
24+
25+
export const applyHardcodedSpecOverrides = (
26+
catalog: TVolumeCatalog,
27+
): TVolumeCatalog => {
28+
catalog.models
29+
.filter((model) => OVERRIDDEN_MODEL_NAMES.includes(model.name))
30+
.forEach((model) => {
31+
model.pricings.forEach((pricing) => {
32+
const iops = pricing.specs.volume.iops;
33+
if (iops && !iops.guaranteed && !hasPositiveMin(iops.min)) {
34+
iops.min = HARDCODED_IOPS_MIN;
35+
}
36+
const bandwidth = pricing.specs.bandwidth;
37+
if (
38+
bandwidth &&
39+
!bandwidth.guaranteed &&
40+
!hasPositiveMin(bandwidth.min)
41+
) {
42+
bandwidth.min = HARDCODED_BANDWIDTH_MIN;
43+
}
44+
});
45+
});
46+
return catalog;
47+
};

0 commit comments

Comments
 (0)