feat: worker_config
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import SealInput from '@/components/seal-form/seal-input';
|
||||
import SealTextArea from '@/components/seal-form/seal-textarea';
|
||||
import { PageActionType } from '@/config/types';
|
||||
import CollapsePanel from '@/pages/_components/collapse-panel';
|
||||
import { json2Yaml, yaml2Json } from '@/pages/backends/config';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Form } from 'antd';
|
||||
import React, { forwardRef, useEffect, useImperativeHandle } from 'react';
|
||||
@@ -9,6 +11,7 @@ import {
|
||||
ClusterFormData as FormData,
|
||||
ClusterListItem as ListItem
|
||||
} from '../config/types';
|
||||
import AdvanceConfig from '../step-forms/advance-config';
|
||||
import CloudProvider from './cloud-provider-form';
|
||||
|
||||
type AddModalProps = {
|
||||
@@ -23,12 +26,27 @@ const ClusterForm: React.FC<AddModalProps> = forwardRef(
|
||||
({ action, provider, currentData, credentialList, onFinish }, ref) => {
|
||||
const [form] = Form.useForm();
|
||||
const intl = useIntl();
|
||||
const [activeKey, setActiveKey] = React.useState<string[]>([]);
|
||||
const advanceConfigRef = React.useRef<any>(null);
|
||||
|
||||
const handleOnCollapseChange = (keys: string | string[]) => {
|
||||
setActiveKey(Array.isArray(keys) ? keys : [keys]);
|
||||
if (currentData && advanceConfigRef.current) {
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (currentData) {
|
||||
form.setFieldsValue(currentData);
|
||||
|
||||
if (advanceConfigRef.current) {
|
||||
const workerConfigYaml = json2Yaml({
|
||||
worker_config: currentData.worker_config || {}
|
||||
});
|
||||
advanceConfigRef.current?.setYamlValue(workerConfigYaml);
|
||||
}
|
||||
}
|
||||
}, [currentData]);
|
||||
}, [currentData, advanceConfigRef.current]);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
resetFields: () => {
|
||||
@@ -44,7 +62,15 @@ const ClusterForm: React.FC<AddModalProps> = forwardRef(
|
||||
return form.getFieldsValue();
|
||||
},
|
||||
validateFields: async () => {
|
||||
return await form.validateFields();
|
||||
const values = await form.validateFields();
|
||||
const workerConfig = yaml2Json(
|
||||
advanceConfigRef.current?.getYamlValue()
|
||||
);
|
||||
|
||||
return {
|
||||
...values,
|
||||
...workerConfig
|
||||
};
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -91,6 +117,24 @@ const ClusterForm: React.FC<AddModalProps> = forwardRef(
|
||||
label={intl.formatMessage({ id: 'common.table.description' })}
|
||||
></SealTextArea>
|
||||
</Form.Item>
|
||||
<CollapsePanel
|
||||
accordion={false}
|
||||
activeKey={activeKey}
|
||||
onChange={handleOnCollapseChange}
|
||||
items={[
|
||||
{
|
||||
key: 'advanceConfig',
|
||||
label: intl.formatMessage({ id: 'resources.form.advanced' }),
|
||||
forceRender: true,
|
||||
children: (
|
||||
<AdvanceConfig
|
||||
action={action}
|
||||
ref={advanceConfigRef}
|
||||
></AdvanceConfig>
|
||||
)
|
||||
}
|
||||
]}
|
||||
></CollapsePanel>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ export interface ClusterListItem {
|
||||
name: string;
|
||||
display_name: string;
|
||||
description: string;
|
||||
worker_config: Record<string, any>;
|
||||
provider: ProviderType;
|
||||
credential_id: number;
|
||||
zone: string;
|
||||
@@ -74,5 +75,7 @@ export interface ClusterFormData {
|
||||
credential_id: number;
|
||||
zone: string;
|
||||
region: string;
|
||||
server_url?: string;
|
||||
worker_config?: Record<string, any>;
|
||||
worker_pools?: NodePoolFormData[];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"worker_config": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"debug": {
|
||||
"type": "boolean",
|
||||
"description": "Enable debug mode"
|
||||
},
|
||||
"cache_dir": {
|
||||
"type": "string",
|
||||
"description": "Cache directory path"
|
||||
},
|
||||
"log_dir": {
|
||||
"type": "string",
|
||||
"description": "Log directory path"
|
||||
},
|
||||
"bin_dir": {
|
||||
"type": "string",
|
||||
"description": "Binary directory path"
|
||||
},
|
||||
"system_default_container_registry": {
|
||||
"type": "string",
|
||||
"description": "Default container registry"
|
||||
},
|
||||
"image_name_override": {
|
||||
"type": "string",
|
||||
"description": "Override image name"
|
||||
},
|
||||
"image_repo": {
|
||||
"type": "string",
|
||||
"description": "Container image repository"
|
||||
},
|
||||
"gateway_mode": {
|
||||
"type": "string",
|
||||
"description": "Gateway mode",
|
||||
"enum": ["worker", "gateway", "disabled"]
|
||||
},
|
||||
"gateway_kubeconfig": {
|
||||
"type": "string",
|
||||
"description": "Path to kubeconfig used by gateway"
|
||||
},
|
||||
"gateway_concurrency": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Gateway concurrency limit"
|
||||
},
|
||||
"service_discovery_name": {
|
||||
"type": "string",
|
||||
"description": "Service discovery name"
|
||||
},
|
||||
"namespace": {
|
||||
"type": "string",
|
||||
"description": "Kubernetes namespace"
|
||||
},
|
||||
"huggingface_token": {
|
||||
"type": "string",
|
||||
"description": "Hugging Face access token"
|
||||
},
|
||||
"disable_worker_metrics": {
|
||||
"type": "boolean",
|
||||
"description": "Disable worker metrics collection"
|
||||
},
|
||||
"worker_port": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535,
|
||||
"description": "Worker service port"
|
||||
},
|
||||
"worker_metrics_port": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535,
|
||||
"description": "Worker metrics port"
|
||||
},
|
||||
"service_port_range": {
|
||||
"type": "string",
|
||||
"pattern": "^\\d+-\\d+$",
|
||||
"description": "Service port range, e.g. 30000-31000"
|
||||
},
|
||||
"ray_port_range": {
|
||||
"type": "string",
|
||||
"pattern": "^\\d+-\\d+$",
|
||||
"description": "Ray port range, e.g. 20000-20100"
|
||||
},
|
||||
"resources": {
|
||||
"type": "object",
|
||||
"description": "Additional resource definitions",
|
||||
"additionalProperties": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"pipx_path": {
|
||||
"type": "string",
|
||||
"description": "pipx installation path"
|
||||
},
|
||||
"tools_download_base_url": {
|
||||
"type": "string",
|
||||
"description": "Base URL for downloading tools"
|
||||
},
|
||||
"enable_hf_transfer": {
|
||||
"type": "boolean",
|
||||
"description": "Enable Hugging Face transfer acceleration"
|
||||
},
|
||||
"enable_hf_xet": {
|
||||
"type": "boolean",
|
||||
"description": "Enable Hugging Face Xet support"
|
||||
},
|
||||
"proxy_mode": {
|
||||
"type": "string",
|
||||
"enum": ["worker", "system", "disabled"],
|
||||
"description": "Proxy mode"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
export default `# This is a template for worker_config.
|
||||
|
||||
worker_config:
|
||||
debug: true
|
||||
|
||||
# directories
|
||||
cache_dir:
|
||||
log_dir:
|
||||
bin_dir:
|
||||
|
||||
# container & image
|
||||
system_default_container_registry:
|
||||
image_repo: gpustack/worker
|
||||
image_name_override: ""
|
||||
|
||||
# gateway
|
||||
gateway_mode:
|
||||
gateway_concurrency: 0
|
||||
gateway_kubeconfig: ""
|
||||
|
||||
# service & networking
|
||||
service_discovery_name:
|
||||
namespace: default
|
||||
worker_port:
|
||||
worker_metrics_port:
|
||||
service_port_range:
|
||||
ray_port_range:
|
||||
|
||||
# resources
|
||||
resources:
|
||||
gpu:
|
||||
count:
|
||||
type:
|
||||
cpu:
|
||||
limit:
|
||||
memory:
|
||||
limit:
|
||||
|
||||
# huggingface
|
||||
huggingface_token: ""
|
||||
enable_hf_transfer: true
|
||||
enable_hf_xet: true
|
||||
|
||||
# metrics
|
||||
disable_worker_metrics: false
|
||||
|
||||
# tools & runtime
|
||||
pipx_path:
|
||||
tools_download_base_url:
|
||||
|
||||
# proxy
|
||||
proxy_mode: worker
|
||||
`;
|
||||
@@ -0,0 +1,75 @@
|
||||
import SealInput from '@/components/seal-form/seal-input';
|
||||
import { PageActionType } from '@/config/types';
|
||||
import YamlEditor from '@/pages/_components/yaml-editor';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Form } from 'antd';
|
||||
import React, { forwardRef, useImperativeHandle } from 'react';
|
||||
import { ClusterFormData as FormData } from '../config/types';
|
||||
import schema from '../config/worker-config.json';
|
||||
import yamlTemplate from '../config/yaml-template';
|
||||
|
||||
const ClusterAdvanceConfig: React.FC<{ action: PageActionType; ref?: any }> =
|
||||
forwardRef(({ action }, ref) => {
|
||||
const [form] = Form.useForm();
|
||||
const intl = useIntl();
|
||||
const editorRef = React.useRef<any>(null);
|
||||
const [fileContent, setFileContent] = React.useState<string>('');
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
getYamlValue: () => {
|
||||
return editorRef.current?.getValue();
|
||||
},
|
||||
setYamlValue: (values: any) => {
|
||||
console.log('setYamlValue:', values, editorRef.current);
|
||||
editorRef.current?.setValue(values);
|
||||
}
|
||||
}));
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item<FormData>
|
||||
name="server_url"
|
||||
rules={[
|
||||
{
|
||||
required: false,
|
||||
message: ''
|
||||
}
|
||||
]}
|
||||
>
|
||||
<SealInput.Input
|
||||
label={intl.formatMessage({ id: 'clusters.create.serverUrl' })}
|
||||
required={false}
|
||||
trim={true}
|
||||
></SealInput.Input>
|
||||
</Form.Item>
|
||||
<Form.Item<FormData>
|
||||
hidden
|
||||
name="worker_config"
|
||||
rules={[
|
||||
{
|
||||
required: false,
|
||||
message: ''
|
||||
}
|
||||
]}
|
||||
>
|
||||
<SealInput.TextArea
|
||||
required={false}
|
||||
trim={false}
|
||||
></SealInput.TextArea>
|
||||
</Form.Item>
|
||||
<YamlEditor
|
||||
ref={editorRef}
|
||||
title={`${intl.formatMessage({ id: 'clusters.create.workerConfig' })} YAML`}
|
||||
value={fileContent}
|
||||
height={300}
|
||||
onUpload={(content) => {
|
||||
setFileContent(content);
|
||||
}}
|
||||
schema={schema}
|
||||
placeholder={yamlTemplate}
|
||||
></YamlEditor>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export default ClusterAdvanceConfig;
|
||||
Reference in New Issue
Block a user