Skip to content

Commit

Permalink
add: warning when maximum resources to allocate is not enough to the …
Browse files Browse the repository at this point in the history
…minimum required resources in selected image (#2700)

### TL;DR

Added resource allocation warning for insufficient resources and implemented end-to-end test for resource policy modification.

### What changed?

- Added a new warning message for insufficient resource allocation in the session launcher
- Implemented logic to check if minimum resource values exceed maximum values
- Added an end-to-end test for modifying resource policy as a superadmin
- Updated the DynamicUnitInputNumberWithSlider component to handle cases where minimum values exceed maximum values
- Added translations for the new warning message across multiple languages

### How to test?

1. Log in as a superadmin and navigate to the resource policy page
2. Modify the resource limits (CPU, memory) to zero
3. Go to the session start page and check for the warning message in the resource allocation section
4. Run the new end-to-end test to ensure the resource policy modification works as expected

### Why make this change?

This change improves the user experience by providing clear feedback when allocatable resources fall below the minimum required resources for a selected image. It also ensures that the system handles cases where resource limits are set incorrectly, preventing potential errors or unexpected behavior during session creation.

### Screenshot(s)
| After | Before |
|------|--------|
| ![Screenshot 2024-09-10 at 6.01.58 PM.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/Dgoz5XqHffJdivyccymr/cf70c2e0-af19-4fd9-8c42-b93f64690529.png) | ![Screenshot 2024-09-10 at 2.27.27 PM.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/Dgoz5XqHffJdivyccymr/f370f7dd-c598-4814-ab46-900adda87a9a.png) |

---

<!--
Please precisely, concisely, and concretely describe what this PR changes, the rationale behind codes,
and how it affects the users and other developers.
-->

**Checklist:** (if applicable)

- [ ] Mention to the original issue
- [ ] Documentation
- [ ] Minium required manager version
- [ ] Specific setting for review (eg., KB link, endpoint or how to setup)
- [ ] Minimum requirements to check during review
- [ ] Test case(s) to demonstrate the difference of before/after
  • Loading branch information
lizable committed Sep 25, 2024
1 parent 9b7c75e commit 9821f06
Show file tree
Hide file tree
Showing 24 changed files with 173 additions and 28 deletions.
50 changes: 49 additions & 1 deletion e2e/session.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { createSession, deleteSession, loginAsUser } from './test-util';
import {
createSession,
deleteSession,
loginAsAdmin,
loginAsUser,
navigateTo,
} from './test-util';
import { test, expect } from '@playwright/test';

test.describe('Sessions ', () => {
Expand All @@ -9,3 +15,45 @@ test.describe('Sessions ', () => {
await deleteSession(page, sessionName);
});
});

test.describe('Restrict resource policy and see resource warning message', () => {
test('superadmin to modify keypair resource policy', async ({ page }) => {
await loginAsAdmin(page);

// go to resource policy page
await navigateTo(page, 'resource-policy');

// modify resource limit (cpu, memory) to zero
await page
.getByRole('table')
.getByRole('button', { name: 'setting' })
.click();
await page.locator('.ant-checkbox-input').first().uncheck();
await page.getByLabel('CPU(optional)').click();
await page.getByLabel('CPU(optional)').fill('0');
await page
.locator(
'div:nth-child(2) > div > div > .ant-checkbox-wrapper > span:nth-child(2)',
)
.first()
.uncheck();
await page.getByLabel('Memory(optional)').click();
await page.getByLabel('Memory(optional)').fill('0');
await page.getByRole('button', { name: 'OK' }).click();

// go back to session page and see message in resource allocation section
await navigateTo(page, 'session/start');

await page.getByRole('button', { name: 'Next right' }).click();
const notEnoughCPUResourceMsg = await page
.locator('#resource_cpu_help')
.getByText('Allocatable resources falls')
.textContent();
const notEnoughRAMResourceMsg = await page
.getByText('Allocatable resources falls')
.nth(1)
.textContent();

expect(notEnoughCPUResourceMsg).toEqual(notEnoughRAMResourceMsg);
});
});
32 changes: 26 additions & 6 deletions react/src/components/DynamicUnitInputNumberWithSlider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import DynamicUnitInputNumber, {
DynamicUnitInputNumberProps,
} from './DynamicUnitInputNumber';
import Flex from './Flex';
import { isMinOversMaxValue } from './ResourceAllocationFormItems';
import { Slider, theme } from 'antd';
import { SliderMarks } from 'antd/es/slider';
import _ from 'lodash';
Expand Down Expand Up @@ -69,7 +70,10 @@ const DynamicUnitInputNumberWithSlider: React.FC<
min={min}
max={max}
units={units}
value={value}
// set value to 0mib when min value overs max value
value={
isMinOversMaxValue(_.parseInt(min), _.parseInt(max)) ? '0m' : value
}
onChange={(nextValue) => {
setValue(nextValue);
}}
Expand Down Expand Up @@ -143,7 +147,15 @@ const DynamicUnitInputNumberWithSlider: React.FC<
}}
step={step}
// min={minGiB.number} // DO NOT use min, because slider left should be 0
value={valueGiB?.number}
// set value to 0 when min value overs max value
value={
isMinOversMaxValue(
minGiB?.number as number,
maxGiB?.number as number,
)
? 0
: valueGiB?.number
}
tooltip={{
formatter: (value = 0) => {
return value < 1
Expand Down Expand Up @@ -176,8 +188,12 @@ const DynamicUnitInputNumberWithSlider: React.FC<
color: token.colorTextSecondary,
},
// if 0, without unit
label:
minGiB.number === 0
label: isMinOversMaxValue(
minGiB?.number as number,
maxGiB?.number as number,
)
? undefined
: minGiB.number === 0
? minGiB.number
: minGiB.number >= 1
? minGiB.number + 'g'
Expand All @@ -195,8 +211,12 @@ const DynamicUnitInputNumberWithSlider: React.FC<
style: {
color: token.colorTextSecondary,
},
label:
maxGiB.number === 0
label: isMinOversMaxValue(
minGiB?.number as number,
maxGiB?.number as number,
)
? undefined
: maxGiB.number === 0
? maxGiB.number
: maxGiB.number >= 1
? maxGiB.number + 'g'
Expand Down
56 changes: 56 additions & 0 deletions react/src/components/ResourceAllocationFormItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ export const RESOURCE_ALLOCATION_INITIAL_FORM_VALUES = {
enabledAutomaticShmem: true,
};

export const isMinOversMaxValue = (min: number, max: number) => {
return min >= max;
};

export interface ResourceAllocationFormValue {
resource: {
cpu: number;
Expand Down Expand Up @@ -487,6 +491,20 @@ const ResourceAllocationFormItems: React.FC<
{
warningOnly: true,
validator: async (rule, value: number) => {
if (
_.isNumber(resourceLimits.cpu?.min) &&
_.isNumber(resourceLimits.cpu?.max) &&
isMinOversMaxValue(
resourceLimits.cpu?.min,
resourceLimits.cpu?.max,
)
) {
return Promise.reject(
t(
'session.launcher.InsufficientAllocationOfResourcesWarning',
),
);
}
if (showRemainingWarning) {
if (
_.isNumber(remaining.cpu) &&
Expand Down Expand Up @@ -652,6 +670,18 @@ const ResourceAllocationFormItems: React.FC<
{
warningOnly: true,
validator: async (rule, value: string) => {
if (
compareNumberWithUnits(
resourceLimits.mem?.min as string,
resourceLimits.mem?.max as string,
) > 0
) {
return Promise.reject(
t(
'session.launcher.InsufficientAllocationOfResourcesWarning',
),
);
}
if (showRemainingWarning) {
if (
!_.isElement(value) &&
Expand Down Expand Up @@ -918,6 +948,32 @@ const ResourceAllocationFormItems: React.FC<
{
warningOnly: true,
validator: async (rule: any, value: number) => {
if (
_.isNumber(
resourceLimits.accelerators[
currentAcceleratorType
]?.min,
) &&
_.isNumber(
resourceLimits.accelerators[
currentAcceleratorType
]?.max,
) &&
isMinOversMaxValue(
resourceLimits.accelerators[
currentAcceleratorType
]?.min,
resourceLimits.accelerators[
currentAcceleratorType
]?.max,
)
) {
return Promise.reject(
t(
'session.launcher.InsufficientAllocationOfResourcesWarning',
),
);
}
if (showRemainingWarning) {
if (
_.isNumber(
Expand Down
3 changes: 2 additions & 1 deletion resources/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,8 @@
"ProxyDirectTCPNotSupported": "Eine direkte Proxy-TCP-Verbindung wird noch nicht unterstützt",
"InvalidPortFormat": "Das Format der Anschlussnummer ist falsch.",
"DuplicatedPort": "Es gibt doppelte Anschlüsse.",
"FolderAliasOverlappingToAutoMount": "Es existiert ein Auto-Mount-Ordner mit demselben Namen."
"FolderAliasOverlappingToAutoMount": "Es existiert ein Auto-Mount-Ordner mit demselben Namen.",
"InsufficientAllocationOfResourcesWarning": "Die zuweisbaren Ressourcen liegen unter der im ausgewählten Bild erforderlichen Mindestressource."
},
"Preparing": "Vorbereitung...",
"PreparingSession": "Sitzung vorbereiten...",
Expand Down
3 changes: 2 additions & 1 deletion resources/i18n/el.json
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,8 @@
"ProxyDirectTCPNotSupported": "Η απευθείας σύνδεση TCP μεσολάβησης δεν υποστηρίζεται ακόμη",
"InvalidPortFormat": "Η μορφή του αριθμού θύρας είναι λανθασμένη.",
"DuplicatedPort": "Υπάρχουν διπλές θύρες.",
"FolderAliasOverlappingToAutoMount": "Υπάρχει ένας φάκελος αυτόματης προσάρτησης με το ίδιο όνομα."
"FolderAliasOverlappingToAutoMount": "Υπάρχει ένας φάκελος αυτόματης προσάρτησης με το ίδιο όνομα.",
"InsufficientAllocationOfResourcesWarning": "Οι κατανεμητέοι πόροι πέφτουν κάτω από τον ελάχιστο απαιτούμενο πόρο στην επιλεγμένη εικόνα."
},
"Preparing": "Προετοιμασία ...",
"PreparingSession": "Προετοιμασία συνεδρίας ...",
Expand Down
3 changes: 2 additions & 1 deletion resources/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,8 @@
"ProxyDirectTCPNotSupported": "Proxy direct TCP connection is not supported yet",
"InvalidPortFormat": "The port number format is incorrect.",
"DuplicatedPort": "There are duplicate ports.",
"FolderAliasOverlappingToAutoMount": "An auto-mount folder with the same name exists."
"FolderAliasOverlappingToAutoMount": "An auto-mount folder with the same name exists.",
"InsufficientAllocationOfResourcesWarning": "Allocatable resources falls below the minimum resource required in the selected image."
},
"Preparing": "Preparing...",
"PreparingSession": "Preparing session...",
Expand Down
3 changes: 2 additions & 1 deletion resources/i18n/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -1296,7 +1296,8 @@
"ProxyDirectTCPNotSupported": "La conexión TCP directa de proxy aún no es compatible",
"InvalidPortFormat": "El formato del número de puerto es incorrecto.",
"DuplicatedPort": "Hay puertos duplicados.",
"FolderAliasOverlappingToAutoMount": "Existe una carpeta de montaje automático con el mismo nombre."
"FolderAliasOverlappingToAutoMount": "Existe una carpeta de montaje automático con el mismo nombre.",
"InsufficientAllocationOfResourcesWarning": "Los recursos asignables están por debajo del recurso mínimo requerido en la imagen seleccionada."
},
"ExpiresAfter": "Tiempo restante",
"CPU": "CPU",
Expand Down
3 changes: 2 additions & 1 deletion resources/i18n/fi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1293,7 +1293,8 @@
"ProxyDirectTCPNotSupported": "Välityspalvelimen suoraa TCP-yhteyttä ei tueta vielä",
"InvalidPortFormat": "Porttinumeron muoto on virheellinen.",
"DuplicatedPort": "Portteja on päällekkäin.",
"FolderAliasOverlappingToAutoMount": "Samanniminen automaattinen kiinnityskansio on olemassa."
"FolderAliasOverlappingToAutoMount": "Samanniminen automaattinen kiinnityskansio on olemassa.",
"InsufficientAllocationOfResourcesWarning": "Allokoitavat resurssit jäävät alle valitussa kuvassa vaaditun vähimmäisresurssin."
},
"ExpiresAfter": "Jäljellä oleva aika",
"CPU": "CPU",
Expand Down
3 changes: 2 additions & 1 deletion resources/i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,8 @@
"ProxyDirectTCPNotSupported": "La connexion TCP directe par proxy n'est pas encore prise en charge",
"InvalidPortFormat": "Le format du numéro de port est incorrect.",
"DuplicatedPort": "Il y a des ports en double.",
"FolderAliasOverlappingToAutoMount": "Il existe un dossier de montage automatique portant le même nom."
"FolderAliasOverlappingToAutoMount": "Il existe un dossier de montage automatique portant le même nom.",
"InsufficientAllocationOfResourcesWarning": "Les ressources allouables sont inférieures à la ressource minimale requise dans l'image sélectionnée."
},
"Preparing": "En train de préparer...",
"PreparingSession": "Séance de préparation...",
Expand Down
3 changes: 2 additions & 1 deletion resources/i18n/id.json
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,8 @@
"ProxyDirectTCPNotSupported": "Koneksi TCP langsung proxy belum didukung",
"InvalidPortFormat": "Format nomor port salah.",
"DuplicatedPort": "Terdapat port ganda.",
"FolderAliasOverlappingToAutoMount": "Folder pemasangan otomatis dengan nama yang sama tersedia."
"FolderAliasOverlappingToAutoMount": "Folder pemasangan otomatis dengan nama yang sama tersedia.",
"InsufficientAllocationOfResourcesWarning": "Sumber daya yang dapat dialokasikan berada di bawah sumber daya minimum yang diperlukan pada gambar yang dipilih."
},
"Preparing": "Mempersiapkan...",
"PreparingSession": "Mempersiapkan sesi...",
Expand Down
3 changes: 2 additions & 1 deletion resources/i18n/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,8 @@
"ProxyDirectTCPNotSupported": "La connessione TCP diretta proxy non è ancora supportata",
"InvalidPortFormat": "Il formato del numero di porta non è corretto.",
"DuplicatedPort": "Ci sono porte duplicate.",
"FolderAliasOverlappingToAutoMount": "Esiste una cartella di montaggio automatico con lo stesso nome."
"FolderAliasOverlappingToAutoMount": "Esiste una cartella di montaggio automatico con lo stesso nome.",
"InsufficientAllocationOfResourcesWarning": "Le risorse assegnabili sono inferiori alla risorsa minima richiesta nell'immagine selezionata."
},
"Preparing": "Preparazione...",
"PreparingSession": "Preparazione della sessione...",
Expand Down
3 changes: 2 additions & 1 deletion resources/i18n/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,8 @@
"ProxyDirectTCPNotSupported": "プロキシ直接 TCP 接続はまだサポートされていません",
"InvalidPortFormat": "ポート番号の形式が正しくない。",
"DuplicatedPort": "ポートが重複している。",
"FolderAliasOverlappingToAutoMount": "同名の自動マウントフォルダが存在する。"
"FolderAliasOverlappingToAutoMount": "同名の自動マウントフォルダが存在する。",
"InsufficientAllocationOfResourcesWarning": "割り当て可能なリソースが、選択したイメージに必要な最小リソースを下回ります。"
},
"Preparing": "準備...",
"PreparingSession": "セッションの準備...",
Expand Down
3 changes: 2 additions & 1 deletion resources/i18n/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,8 @@
"ProxyDirectTCPNotSupported": "프록시 직접 TCP 연결은 아직 지원되지 않습니다.",
"InvalidPortFormat": "포트 형식이 올바르지 않습니다.",
"DuplicatedPort": "중복된 포트가 있습니다.",
"FolderAliasOverlappingToAutoMount": "동일한 이름의 자동 마운트 폴더가 존재합니다."
"FolderAliasOverlappingToAutoMount": "동일한 이름의 자동 마운트 폴더가 존재합니다.",
"InsufficientAllocationOfResourcesWarning": "할당 가능한 자원이 선택된 이미지에서 요구되는 최소 자원보다 부족합니다."
},
"Preparing": "준비중...",
"PreparingSession": "세션 준비중...",
Expand Down
3 changes: 2 additions & 1 deletion resources/i18n/mn.json
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,8 @@
"ProxyDirectTCPNotSupported": "Прокси шууд TCP холболт хараахан дэмжигдээгүй байна",
"InvalidPortFormat": "Портын дугаарын формат буруу байна.",
"DuplicatedPort": "Давхардсан портууд байна.",
"FolderAliasOverlappingToAutoMount": "Ижил нэртэй автоматаар холбох хавтас байна."
"FolderAliasOverlappingToAutoMount": "Ижил нэртэй автоматаар холбох хавтас байна.",
"InsufficientAllocationOfResourcesWarning": "Хуваарилах нөөц нь сонгосон зурагт шаардагдах хамгийн бага нөөцөөс доогуур байна."
},
"Preparing": "Бэлтгэж байна ...",
"PreparingSession": "Session бэлтгэж байна ...",
Expand Down
3 changes: 2 additions & 1 deletion resources/i18n/ms.json
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,8 @@
"ProxyDirectTCPNotSupported": "Sambungan TCP langsung proksi belum disokong lagi",
"InvalidPortFormat": "Format nombor port tidak betul.",
"DuplicatedPort": "Terdapat port pendua.",
"FolderAliasOverlappingToAutoMount": "Folder auto-lekap dengan nama yang sama wujud."
"FolderAliasOverlappingToAutoMount": "Folder auto-lekap dengan nama yang sama wujud.",
"InsufficientAllocationOfResourcesWarning": "Sumber yang boleh diperuntukkan berada di bawah sumber minimum yang diperlukan dalam imej yang dipilih."
},
"Preparing": "Menyiapkan ...",
"PreparingSession": "Menyiapkan sesi ...",
Expand Down
3 changes: 2 additions & 1 deletion resources/i18n/pl.json
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,8 @@
"ProxyDirectTCPNotSupported": "Bezpośrednie połączenie proxy TCP nie jest jeszcze obsługiwane",
"InvalidPortFormat": "Format numeru portu jest nieprawidłowy.",
"DuplicatedPort": "Istnieją zduplikowane porty.",
"FolderAliasOverlappingToAutoMount": "Istnieje folder automatycznego montażu o tej samej nazwie."
"FolderAliasOverlappingToAutoMount": "Istnieje folder automatycznego montażu o tej samej nazwie.",
"InsufficientAllocationOfResourcesWarning": "Zasoby, które można przydzielić, są mniejsze niż minimalne zasoby wymagane w wybranym obrazie."
},
"Preparing": "Przygotowuję...",
"PreparingSession": "Przygotowuję sesję...",
Expand Down
3 changes: 2 additions & 1 deletion resources/i18n/pt-BR.json
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,8 @@
"ProxyDirectTCPNotSupported": "A conexão TCP direta do proxy ainda não é suportada",
"InvalidPortFormat": "O formato do número da porta está incorreto.",
"DuplicatedPort": "Existem portas duplicadas.",
"FolderAliasOverlappingToAutoMount": "Existe uma pasta de montagem automática com o mesmo nome."
"FolderAliasOverlappingToAutoMount": "Existe uma pasta de montagem automática com o mesmo nome.",
"InsufficientAllocationOfResourcesWarning": "Os recursos alocáveis ​​ficam abaixo do recurso mínimo exigido na imagem selecionada."
},
"Preparing": "Preparando...",
"PreparingSession": "Preparando sessão ...",
Expand Down
3 changes: 2 additions & 1 deletion resources/i18n/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,8 @@
"ProxyDirectTCPNotSupported": "A conexão TCP direta do proxy ainda não é suportada",
"InvalidPortFormat": "O formato do número da porta está incorreto.",
"DuplicatedPort": "Existem portas duplicadas.",
"FolderAliasOverlappingToAutoMount": "Existe uma pasta de montagem automática com o mesmo nome."
"FolderAliasOverlappingToAutoMount": "Existe uma pasta de montagem automática com o mesmo nome.",
"InsufficientAllocationOfResourcesWarning": "Os recursos alocáveis ​​ficam abaixo do recurso mínimo exigido na imagem selecionada."
},
"Preparing": "Preparando...",
"PreparingSession": "Preparando sessão ...",
Expand Down
Loading

0 comments on commit 9821f06

Please sign in to comment.