mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-16 20:08:09 +00:00
can schedule endpoint (#41)
* can_schedule endpoint * fixing condition * sorting imports
This commit is contained in:
58
src/api-service/__app__/agent_can_schedule/__init__.py
Normal file
58
src/api-service/__app__/agent_can_schedule/__init__.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# Licensed under the MIT License.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import azure.functions as func
|
||||||
|
from onefuzztypes.enums import ErrorCode, TaskState
|
||||||
|
from onefuzztypes.models import Error, NodeCommand, StopNodeCommand
|
||||||
|
from onefuzztypes.requests import CanScheduleRequest
|
||||||
|
from onefuzztypes.responses import CanSchedule
|
||||||
|
|
||||||
|
from ..onefuzzlib.agent_authorization import verify_token
|
||||||
|
from ..onefuzzlib.pools import Node, NodeMessage
|
||||||
|
from ..onefuzzlib.request import not_ok, ok, parse_uri
|
||||||
|
from ..onefuzzlib.tasks.main import Task
|
||||||
|
|
||||||
|
|
||||||
|
def post(req: func.HttpRequest) -> func.HttpResponse:
|
||||||
|
request = parse_uri(CanScheduleRequest, req)
|
||||||
|
if isinstance(request, Error):
|
||||||
|
return not_ok(request, context="CanScheduleRequest")
|
||||||
|
|
||||||
|
node = Node.get_by_machine_id(request.machine_id)
|
||||||
|
if not node:
|
||||||
|
return not_ok(
|
||||||
|
Error(code=ErrorCode.UNABLE_TO_FIND, errors=["unable to find node"]),
|
||||||
|
context=request.machine_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
allowed = True
|
||||||
|
work_stopped = False
|
||||||
|
if node.is_outdated:
|
||||||
|
logging.info(
|
||||||
|
"received can_schedule request from outdated node '%s' version '%s'",
|
||||||
|
node.machine_id,
|
||||||
|
node.version,
|
||||||
|
)
|
||||||
|
allowed = False
|
||||||
|
stop_message = NodeMessage(
|
||||||
|
agent_id=node.machine_id, message=NodeCommand(stop=StopNodeCommand()),
|
||||||
|
)
|
||||||
|
stop_message.save()
|
||||||
|
|
||||||
|
task = Task.get_by_task_id(request.task_id)
|
||||||
|
|
||||||
|
work_stopped = isinstance(task, Error) or (task.state != TaskState.scheduled)
|
||||||
|
return ok(CanSchedule(allowed=allowed, work_stopped=work_stopped))
|
||||||
|
|
||||||
|
|
||||||
|
def main(req: func.HttpRequest) -> func.HttpResponse:
|
||||||
|
if req.method == "POST":
|
||||||
|
m = post
|
||||||
|
else:
|
||||||
|
raise Exception("invalid method")
|
||||||
|
|
||||||
|
return verify_token(req, m)
|
20
src/api-service/__app__/agent_can_schedule/function.json
Normal file
20
src/api-service/__app__/agent_can_schedule/function.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"scriptFile": "__init__.py",
|
||||||
|
"bindings": [
|
||||||
|
{
|
||||||
|
"authLevel": "anonymous",
|
||||||
|
"type": "httpTrigger",
|
||||||
|
"direction": "in",
|
||||||
|
"name": "req",
|
||||||
|
"methods": [
|
||||||
|
"post"
|
||||||
|
],
|
||||||
|
"route": "agents/can_schedule"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "http",
|
||||||
|
"direction": "out",
|
||||||
|
"name": "$return"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -33,6 +33,7 @@ from onefuzztypes.models import (
|
|||||||
from onefuzztypes.primitives import PoolName, Region
|
from onefuzztypes.primitives import PoolName, Region
|
||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
|
|
||||||
|
from .__version__ import __version__
|
||||||
from .azure.auth import build_auth
|
from .azure.auth import build_auth
|
||||||
from .azure.creds import get_fuzz_storage
|
from .azure.creds import get_fuzz_storage
|
||||||
from .azure.image import get_os
|
from .azure.image import get_os
|
||||||
@ -138,6 +139,9 @@ class Node(BASE_NODE, ORMMixin):
|
|||||||
node.state = NodeState.done
|
node.state = NodeState.done
|
||||||
node.save()
|
node.save()
|
||||||
|
|
||||||
|
def is_outdated(self) -> bool:
|
||||||
|
return self.version != __version__
|
||||||
|
|
||||||
|
|
||||||
class NodeTasks(BASE_NODE_TASK, ORMMixin):
|
class NodeTasks(BASE_NODE_TASK, ORMMixin):
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -178,7 +182,7 @@ class NodeMessage(ORMMixin):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def key_fields(cls) -> Tuple[str, str]:
|
def key_fields(cls) -> Tuple[str, str]:
|
||||||
return ("agent_id", "create_date")
|
return ("agent_id", "message_id")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_messages(
|
def get_messages(
|
||||||
|
@ -398,6 +398,7 @@ class Node(BaseModel):
|
|||||||
state: NodeState = Field(default=NodeState.init)
|
state: NodeState = Field(default=NodeState.init)
|
||||||
scaleset_id: Optional[UUID] = None
|
scaleset_id: Optional[UUID] = None
|
||||||
tasks: Optional[List[Tuple[UUID, NodeTaskState]]] = None
|
tasks: Optional[List[Tuple[UUID, NodeTaskState]]] = None
|
||||||
|
version: str = Field(default="1.0.0")
|
||||||
|
|
||||||
|
|
||||||
class ScalesetSummary(BaseModel):
|
class ScalesetSummary(BaseModel):
|
||||||
|
@ -197,3 +197,8 @@ class ReproGet(BaseRequest):
|
|||||||
|
|
||||||
class ProxyReset(BaseRequest):
|
class ProxyReset(BaseRequest):
|
||||||
region: Region
|
region: Region
|
||||||
|
|
||||||
|
|
||||||
|
class CanScheduleRequest(BaseRequest):
|
||||||
|
machine_id: UUID
|
||||||
|
task_id: UUID
|
||||||
|
@ -58,3 +58,8 @@ class AgentRegistration(BaseResponse):
|
|||||||
|
|
||||||
class PendingNodeCommand(BaseResponse):
|
class PendingNodeCommand(BaseResponse):
|
||||||
envelope: Optional[NodeCommandEnvelope]
|
envelope: Optional[NodeCommandEnvelope]
|
||||||
|
|
||||||
|
|
||||||
|
class CanSchedule(BaseResponse):
|
||||||
|
allowed: bool
|
||||||
|
work_stopped: bool
|
||||||
|
Reference in New Issue
Block a user