Skip to content

Commit

Permalink
BUG: Cluster info can be accessed without authorization in the auth m…
Browse files Browse the repository at this point in the history
…ode (#1731)

Co-authored-by: yiboyasss <[email protected]>
  • Loading branch information
ChengjieLi28 and yiboyasss authored Jun 28, 2024
1 parent 2a64f4b commit 8feac94
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 37 deletions.
27 changes: 24 additions & 3 deletions xinference/api/restful_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,13 +247,34 @@ def serve(self, logging_conf: Optional[dict] = None):
methods=["GET"],
)
self._router.add_api_route(
"/v1/cluster/info", self.get_cluster_device_info, methods=["GET"]
"/v1/cluster/info",
self.get_cluster_device_info,
methods=["GET"],
dependencies=(
[Security(self._auth_service, scopes=["admin"])]
if self.is_authenticated()
else None
),
)
self._router.add_api_route(
"/v1/cluster/version", self.get_cluster_version, methods=["GET"]
"/v1/cluster/version",
self.get_cluster_version,
methods=["GET"],
dependencies=(
[Security(self._auth_service, scopes=["admin"])]
if self.is_authenticated()
else None
),
)
self._router.add_api_route(
"/v1/cluster/devices", self._get_devices_count, methods=["GET"]
"/v1/cluster/devices",
self._get_devices_count,
methods=["GET"],
dependencies=(
[Security(self._auth_service, scopes=["models:list"])]
if self.is_authenticated()
else None
),
)
self._router.add_api_route("/v1/address", self.get_address, methods=["GET"])

Expand Down
6 changes: 3 additions & 3 deletions xinference/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ def setup():
local_cluster_proc = run_test_cluster_in_subprocess(
supervisor_addr, TEST_LOGGING_CONF
)
if not cluster_health_check(supervisor_addr, max_attempts=10, sleep_interval=3):
if not cluster_health_check(supervisor_addr, max_attempts=10, sleep_interval=5):
raise RuntimeError("Cluster is not available after multiple attempts")

port = xo.utils.get_next_port()
Expand Down Expand Up @@ -226,7 +226,7 @@ def setup_with_file_logging():
local_cluster_proc = run_test_cluster_in_subprocess(
supervisor_addr, TEST_FILE_LOGGING_CONF
)
if not cluster_health_check(supervisor_addr, max_attempts=3, sleep_interval=3):
if not cluster_health_check(supervisor_addr, max_attempts=10, sleep_interval=5):
raise RuntimeError("Cluster is not available after multiple attempts")

port = xo.utils.get_next_port()
Expand Down Expand Up @@ -258,7 +258,7 @@ def setup_with_auth():
local_cluster_proc = run_test_cluster_in_subprocess(
supervisor_addr, TEST_LOGGING_CONF
)
if not cluster_health_check(supervisor_addr, max_attempts=10, sleep_interval=3):
if not cluster_health_check(supervisor_addr, max_attempts=10, sleep_interval=5):
raise RuntimeError("Cluster is not available after multiple attempts")

user1 = User(
Expand Down
18 changes: 0 additions & 18 deletions xinference/core/tests/test_restful_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1255,21 +1255,3 @@ def test_launch_model_by_version(setup):
# delete again
url = f"{endpoint}/v1/models/test_orca"
requests.delete(url)


@pytest.mark.skipif(bool(os.environ.get("GITHUB_ACTIONS")), reason="Skip windows")
def test_cluster_info(setup):
endpoint, _ = setup
url = f"{endpoint}/v1/cluster/info"

response = requests.get(url)
assert response.status_code == 200
result = response.json()
assert isinstance(result, list)
assert len(result) == 2
assert result[0]["node_type"] == "Supervisor"
assert result[0]["gpu_count"] == 0
assert result[0]["gpu_vram_total"] == 0
assert result[1]["node_type"] == "Worker"
assert result[1]["gpu_count"] == 0
assert result[1]["gpu_vram_total"] == 0
45 changes: 33 additions & 12 deletions xinference/web/ui/src/scenes/cluster_info/nodeInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Grid from '@mui/material/Unstable_Grid2'
import PropTypes from 'prop-types'
import React from 'react'

import fetcher from '../../components/fetcher'
import { toReadableSize } from '../../components/utils'
import { StyledTableCell, StyledTableRow } from './style'

Expand All @@ -21,26 +22,46 @@ class NodeInfo extends React.Component {
}

refreshInfo() {
fetch(`${this.endpoint}/v1/cluster/info?detailed=true`, { method: 'GET' })
.then((res) => res.json())
fetcher(`${this.endpoint}/v1/cluster/info?detailed=true`, { method: 'GET' })
.then((res) => {
const { state } = this
state['info'] = res
this.setState(state)
if (!res.ok) {
res.json().then((errorData) => {
if (errorData.detail === 'Not enough permissions') {
console.log('Not enough permissions')
// window.history.back();
}
})
}
if (res.ok) {
res.json().then((data) => {
const { state } = this
state['info'] = data
this.setState(state)
})
}
})
.catch((err) => {
console.error('Error:', err)
})

if (JSON.stringify(this.state.version) === '{}') {
fetch(`${this.endpoint}/v1/cluster/version`, {
fetcher(`${this.endpoint}/v1/cluster/version`, {
method: 'GET',
})
.then((res) => res.json())
.then((res) => {
const { state } = this
state['version'] = {
release: 'v' + res['version'],
commit: res['full-revisionid'],
if (res.ok) {
res.json().then((data) => {
const { state } = this
state['version'] = {
release: 'v' + data['version'],
commit: data['full-revisionid'],
}
this.setState(state)
})
}
this.setState(state)
})
.catch((err) => {
console.error('Error:', err)
})
}
}
Expand Down
3 changes: 2 additions & 1 deletion xinference/web/ui/src/scenes/launch_model/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useNavigate } from 'react-router-dom'

import { ApiContext } from '../../components/apiContext'
import ErrorMessageSnackBar from '../../components/errorMessageSnackBar'
import fetcher from '../../components/fetcher'
import Title from '../../components/Title'
import LaunchCustom from './launchCustom'
import LaunchLLM from './launchLLM'
Expand Down Expand Up @@ -43,7 +44,7 @@ const LaunchModel = () => {
}

if (gpuAvailable === -1) {
fetch(endPoint + '/v1/cluster/devices', {
fetcher(endPoint + '/v1/cluster/devices', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Expand Down

0 comments on commit 8feac94

Please sign in to comment.