Skip to content

Commit

Permalink
fix: adjust GPU quota for launchpad (#5041)
Browse files Browse the repository at this point in the history
* fix: adjust GPU quota for launchpad

* fix select style

* update launchpad

* getMonitorData
  • Loading branch information
zjy365 authored Sep 6, 2024
1 parent 4a17349 commit 4ec1134
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const AdapterChartData: Record<
const newDataArray = data.data.result.map((item) => {
let name = item.metric.pod;
let xData = item.values.map((value) => value[0]);
let yData = item.values.map((value) => (parseFloat(value[1]) * 100).toFixed(2));
let yData = item.values.map((value) => parseFloat(value[1]).toFixed(2));
return {
name: name,
xData: xData,
Expand All @@ -27,7 +27,7 @@ const AdapterChartData: Record<
const newDataArray = data.data.result.map((item) => {
let name = item.metric.pod;
let xData = item.values.map((value) => value[0]);
let yData = item.values.map((value) => (parseFloat(value[1]) * 100).toFixed(2));
let yData = item.values.map((value) => parseFloat(value[1]).toFixed(2));
return {
name: name,
xData: xData,
Expand All @@ -40,7 +40,7 @@ const AdapterChartData: Record<
const newDataArray = data.data.result.map((item) => {
let name = item.metric.pod;
let xData = item.values.map((value) => value[0]);
let yData = item.values.map((value) => (parseFloat(value[1]) * 100).toFixed(2));
let yData = item.values.map((value) => parseFloat(value[1]).toFixed(2));
return {
name: name,
xData: xData,
Expand All @@ -53,7 +53,7 @@ const AdapterChartData: Record<
const newDataArray = data.data.result.map((item) => {
let name = item.metric.pod;
let xData = item.values.map((value) => value[0]);
let yData = item.values.map((value) => (parseFloat(value[1]) * 100).toFixed(2));
let yData = item.values.map((value) => parseFloat(value[1]).toFixed(2));
return {
name: name,
xData: xData,
Expand All @@ -66,7 +66,7 @@ const AdapterChartData: Record<
const newDataArray = data.data.result.map((item) => {
let name = item.metric.pod;
let xData = item.values.map((value) => value[0]);
let yData = item.values.map((value) => (parseFloat(value[1]) * 100).toFixed(2));
let yData = item.values.map((value) => parseFloat(value[1]).toFixed(2));
return {
name: name,
xData: xData,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { AppConfigType, FileMangerType, FormSliderListType } from '@/types'
import { readFileSync } from 'fs';
import * as yaml from 'js-yaml';
import type { NextApiRequest, NextApiResponse } from 'next';
import { getGpuNode } from './resourcePrice';

// todo make response type to be more specific and clear.
export type Response = {
Expand All @@ -24,7 +25,8 @@ export const defaultAppConfig: AppConfigType = {
},
common: {
guideEnabled: false,
apiEnabled: false
apiEnabled: false,
gpuEnabled: false
},
launchpad: {
ingressTlsSecretName: 'wildcard-cert',
Expand Down Expand Up @@ -66,6 +68,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const res: any = yaml.load(readFileSync(filename, 'utf-8'));
console.log(res);
global.AppConfig = res;
const gpuNodes = await getGpuNode();
global.AppConfig.common.gpuEnabled = gpuNodes.length > 0;
}
jsonRes<Response>(res, {
data: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { authSession } from '@/services/backend/auth';
import { getK8s } from '@/services/backend/kubernetes';
import { jsonRes } from '@/services/backend/response';
import { authSession } from '@/services/backend/auth';
import { UserQuotaItemType } from '@/types/user';
import Decimal from 'decimal.js';
import type { NextApiRequest, NextApiResponse } from 'next';

async function getAmount(req: NextApiRequest): Promise<{
data?: {
Expand Down Expand Up @@ -65,6 +65,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
});

const quota = await getUserQuota();
const gpuEnabled = global.AppConfig.common.gpuEnabled;
const filteredQuota = gpuEnabled ? quota : quota.filter((item) => item.type !== 'gpu');

let balance = '0';
try {
Expand All @@ -84,7 +86,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
quota: UserQuotaItemType[];
}>(res, {
data: {
quota,
quota: filteredQuota,
balance
}
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { getK8s } from '@/services/backend/kubernetes';
import { getK8s, K8sApiDefault } from '@/services/backend/kubernetes';
import { jsonRes } from '@/services/backend/response';
import { authSession } from '@/services/backend/auth';
import { CoreV1Api } from '@kubernetes/client-node';
Expand Down Expand Up @@ -43,26 +43,19 @@ export const valuationMap: Record<string, number> = {
'services.nodeports': 1000
};

const gpuCrName = 'node-gpu-info';
const gpuCrNS = 'node-system';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
// source price
const { applyYamlList, k8sCustomObjects, k8sCore, namespace } = await getK8s({
kubeconfig: await authSession(req.headers)
});

const gpuEnabled = global.AppConfig.common.gpuEnabled;
const [priceResponse, gpuNodes] = await Promise.all([
getResourcePrice(),
getGpuNode({ k8sCore })
gpuEnabled ? getGpuNode() : Promise.resolve([])
]);

const data: userPriceType = {
cpu: countSourcePrice(priceResponse, 'cpu'),
memory: countSourcePrice(priceResponse, 'memory'),
storage: countSourcePrice(priceResponse, 'storage'),
gpu: countGpuSource(priceResponse, gpuNodes)
gpu: gpuEnabled ? countGpuSource(priceResponse, gpuNodes) : undefined
};

jsonRes<userPriceType>(res, {
Expand All @@ -75,9 +68,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
}

/* get gpu nodes by configmap. */
async function getGpuNode({ k8sCore }: { k8sCore: CoreV1Api }) {
export async function getGpuNode() {
const gpuCrName = 'node-gpu-info';
const gpuCrNS = 'node-system';

try {
const { body } = await k8sCore.readNamespacedConfigMap(gpuCrName, gpuCrNS);
const kc = K8sApiDefault();
const { body } = await kc.makeApiClient(CoreV1Api).readNamespacedConfigMap(gpuCrName, gpuCrNS);
const gpuMap = body?.data?.gpu;
if (!gpuMap || !body?.data?.alias) return [];
const alias = (JSON.parse(body?.data?.alias) || {}) as Record<string, string>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,9 +353,11 @@ const Form = ({
</Box>
))}
</Box>
<Box mt={3} overflow={'hidden'}>
<QuotaBox />
</Box>
{userSourcePrice && (
<Box mt={3} overflow={'hidden'}>
<QuotaBox />
</Box>
)}
{userSourcePrice && (
<Box mt={3} overflow={'hidden'}>
<PriceBox
Expand Down Expand Up @@ -670,22 +672,21 @@ const Form = ({
key={item.value}
label={hasInventory ? '' : t('Under Stock')}
>
<Box
<Center
mr={2}
w={'32px'}
h={'32px'}
lineHeight={'32px'}
textAlign={'center'}
borderRadius={'md'}
border={'1px solid'}
bg={'myWhite.500'}
bg={'white'}
{...(getValues('gpu.amount') === item.value
? {
borderColor: 'brightBlue.600',
boxShadow: '0px 0px 4px #A8DBFF'
borderColor: 'brightBlue.500',
boxShadow: '0px 0px 0px 2.4px rgba(33, 155, 244, 0.15)'
}
: {
borderColor: 'myGray.200'
borderColor: 'grayModern.200',
bgColor: 'grayModern.100'
})}
{...(hasInventory
? {
Expand All @@ -703,7 +704,7 @@ const Form = ({
})}
>
{item.label}
</Box>
</Center>
</MyTooltip>
);
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ import type { V1Deployment, V1StatefulSet } from '@kubernetes/client-node';
import { UserQuotaItemType } from '@/types/user';
import { memoryFormatToMi, cpuFormatToM } from '@/utils/tools';

export function K8sApiDefault(): k8s.KubeConfig {
const kc = new k8s.KubeConfig();
kc.loadFromDefault();
return kc;
}

export function CheckIsInCluster(): [boolean, string] {
if (
process.env.KUBERNETES_SERVICE_HOST !== undefined &&
Expand Down
1 change: 1 addition & 0 deletions frontend/providers/applaunchpad/src/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export type AppConfigType = {
common: {
guideEnabled: boolean;
apiEnabled: boolean;
gpuEnabled: boolean;
};
launchpad: {
ingressTlsSecretName: string;
Expand Down
64 changes: 39 additions & 25 deletions frontend/providers/template/src/components/Select/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import {
MenuItem,
Button,
useDisclosure,
useOutsideClick
useOutsideClick,
MenuButton,
Flex
} from '@chakra-ui/react';
import type { ButtonProps } from '@chakra-ui/react';
import { ChevronDownIcon } from '@chakra-ui/icons';
Expand All @@ -22,10 +24,21 @@ interface Props extends ButtonProps {
value: string;
}[];
onchange?: (val: string) => void;
isInvalid?: boolean;
}

const MySelect = (
{ placeholder, value, defaultValue, width = 'auto', list, onchange, ...props }: Props,
{
placeholder,
value,
defaultValue,
width = 'auto',
list,
onchange,
isInvalid,
height,
...props
}: Props,
selectRef: any
) => {
const ref = useRef<HTMLButtonElement>(null);
Expand Down Expand Up @@ -64,39 +77,41 @@ const MySelect = (
isOpen ? onClose() : onOpen();
}}
>
<Button
ref={ref}
<MenuButton
as={Button}
rightIcon={<ChevronDownIcon />}
width={width}
px={3}
variant={'base'}
height={height}
ref={ref}
display={'flex'}
alignItems={'center'}
justifyContent={'space-between'}
justifyContent={'center'}
border={'1px solid #E8EBF0'}
borderRadius={'md'}
fontSize={'12px'}
fontWeight={'400'}
variant={'outline'}
_hover={{
borderColor: 'brightBlue.300',
bg: 'grayModern.50'
}}
_active={{
transform: ''
}}
{...(isOpen
? {
boxShadow: '0px 0px 4px #A8DBFF',
borderColor: 'myBlue.600'
boxShadow: '0px 0px 0px 2.4px rgba(33, 155, 244, 0.15)',
borderColor: 'brightBlue.500',
bg: '#FFF'
}
: { borderColor: '#DEE0E2' })}
: {
bg: '#F7F8FA',
borderColor: isInvalid ? 'red' : ''
})}
{...props}
>
{activeMenu ? (
<>
{!!activeMenu.icon && <MyIcon mr={2} name={activeMenu.icon as IconType} w={'18px'} />}
<Box>{activeMenu.label}</Box>
</>
) : (
<>
<Box>{placeholder}</Box>
</>
)}

<Box flex={1} />
<ChevronDownIcon />
</Button>
<Flex justifyContent={'flex-start'}>{activeMenu ? activeMenu.label : placeholder}</Flex>
</MenuButton>

<MenuList
minW={(() => {
Expand All @@ -114,7 +129,6 @@ const MySelect = (
'0px 2px 4px rgba(161, 167, 179, 0.25), 0px 0px 1px rgba(121, 141, 159, 0.25);'
}
zIndex={99}
transform={'translateY(35px) !important'}
>
{list.map((item) => (
<MenuItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,6 @@ const Form = ({
<Box maxW={'300px'} ml={'20px'} w={'100%'}>
<MySelect
w={'100%'}
bg={'transparent'}
borderRadius={'2px'}
defaultValue={getValues(item.key) || item.default}
list={item.options?.map((option) => {
return {
Expand Down

0 comments on commit 4ec1134

Please sign in to comment.