From b61c471f17109fa726be261ede2d2b8942d1a80e Mon Sep 17 00:00:00 2001 From: Brian Caswell Date: Wed, 7 Jul 2021 16:12:25 -0400 Subject: [PATCH 1/2] use the built-in size validators Using the built-in size validators means the documentation includes the min/max values --- docs/webhook_events.md | 56 ++++++++++++++++++ src/pytypes/onefuzztypes/models.py | 88 ++++------------------------ src/pytypes/onefuzztypes/requests.py | 34 ++--------- 3 files changed, 72 insertions(+), 106 deletions(-) diff --git a/docs/webhook_events.md b/docs/webhook_events.md index 0f10a122ce..9dc79c7599 100644 --- a/docs/webhook_events.md +++ b/docs/webhook_events.md @@ -359,6 +359,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "boolean" }, "check_retry_count": { + "minimum": 0, "title": "Check Retry Count", "type": "integer" }, @@ -367,6 +368,8 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "string" }, "duration": { + "maximum": 168, + "minimum": 1, "title": "Duration", "type": "integer" }, @@ -471,6 +474,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "boolean" }, "target_timeout": { + "minimum": 1, "title": "Target Timeout", "type": "integer" }, @@ -532,6 +536,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "properties": { "count": { "default": 1, + "minimum": 0, "title": "Count", "type": "integer" }, @@ -707,6 +712,8 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "string" }, "duration": { + "maximum": 168, + "minimum": 1, "title": "Duration", "type": "integer" }, @@ -863,6 +870,8 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "string" }, "duration": { + "maximum": 168, + "minimum": 1, "title": "Duration", "type": "integer" }, @@ -1221,11 +1230,16 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "string" }, "max_size": { + "default": 1000, + "maximum": 1000, + "minimum": 0, "title": "Max Size", "type": "integer" }, "min_size": { "default": 0, + "maximum": 1000, + "minimum": 0, "title": "Min Size", "type": "integer" }, @@ -1944,6 +1958,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "boolean" }, "check_retry_count": { + "minimum": 0, "title": "Check Retry Count", "type": "integer" }, @@ -1952,6 +1967,8 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "string" }, "duration": { + "maximum": 168, + "minimum": 1, "title": "Duration", "type": "integer" }, @@ -2056,6 +2073,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "boolean" }, "target_timeout": { + "minimum": 1, "title": "Target Timeout", "type": "integer" }, @@ -2117,6 +2135,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "properties": { "count": { "default": 1, + "minimum": 0, "title": "Count", "type": "integer" }, @@ -2651,6 +2670,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "boolean" }, "check_retry_count": { + "minimum": 0, "title": "Check Retry Count", "type": "integer" }, @@ -2659,6 +2679,8 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "string" }, "duration": { + "maximum": 168, + "minimum": 1, "title": "Duration", "type": "integer" }, @@ -2763,6 +2785,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "boolean" }, "target_timeout": { + "minimum": 1, "title": "Target Timeout", "type": "integer" }, @@ -2824,6 +2847,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "properties": { "count": { "default": 1, + "minimum": 0, "title": "Count", "type": "integer" }, @@ -3149,6 +3173,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "boolean" }, "check_retry_count": { + "minimum": 0, "title": "Check Retry Count", "type": "integer" }, @@ -3157,6 +3182,8 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "string" }, "duration": { + "maximum": 168, + "minimum": 1, "title": "Duration", "type": "integer" }, @@ -3261,6 +3288,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "boolean" }, "target_timeout": { + "minimum": 1, "title": "Target Timeout", "type": "integer" }, @@ -3322,6 +3350,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "properties": { "count": { "default": 1, + "minimum": 0, "title": "Count", "type": "integer" }, @@ -3592,6 +3621,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "boolean" }, "check_retry_count": { + "minimum": 0, "title": "Check Retry Count", "type": "integer" }, @@ -3600,6 +3630,8 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "string" }, "duration": { + "maximum": 168, + "minimum": 1, "title": "Duration", "type": "integer" }, @@ -3704,6 +3736,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "boolean" }, "target_timeout": { + "minimum": 1, "title": "Target Timeout", "type": "integer" }, @@ -3765,6 +3798,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "properties": { "count": { "default": 1, + "minimum": 0, "title": "Count", "type": "integer" }, @@ -4009,6 +4043,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "boolean" }, "check_retry_count": { + "minimum": 0, "title": "Check Retry Count", "type": "integer" }, @@ -4017,6 +4052,8 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "string" }, "duration": { + "maximum": 168, + "minimum": 1, "title": "Duration", "type": "integer" }, @@ -4121,6 +4158,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "boolean" }, "target_timeout": { + "minimum": 1, "title": "Target Timeout", "type": "integer" }, @@ -4196,6 +4234,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "properties": { "count": { "default": 1, + "minimum": 0, "title": "Count", "type": "integer" }, @@ -4453,6 +4492,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "boolean" }, "check_retry_count": { + "minimum": 0, "title": "Check Retry Count", "type": "integer" }, @@ -4461,6 +4501,8 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "string" }, "duration": { + "maximum": 168, + "minimum": 1, "title": "Duration", "type": "integer" }, @@ -4565,6 +4607,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "boolean" }, "target_timeout": { + "minimum": 1, "title": "Target Timeout", "type": "integer" }, @@ -4626,6 +4669,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "properties": { "count": { "default": 1, + "minimum": 0, "title": "Count", "type": "integer" }, @@ -4732,11 +4776,16 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "string" }, "max_size": { + "default": 1000, + "maximum": 1000, + "minimum": 0, "title": "Max Size", "type": "integer" }, "min_size": { "default": 0, + "maximum": 1000, + "minimum": 0, "title": "Min Size", "type": "integer" }, @@ -5562,6 +5611,8 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "string" }, "duration": { + "maximum": 168, + "minimum": 1, "title": "Duration", "type": "integer" }, @@ -5926,6 +5977,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "boolean" }, "check_retry_count": { + "minimum": 0, "title": "Check Retry Count", "type": "integer" }, @@ -5934,6 +5986,8 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "string" }, "duration": { + "maximum": 168, + "minimum": 1, "title": "Duration", "type": "integer" }, @@ -6038,6 +6092,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "type": "boolean" }, "target_timeout": { + "minimum": 1, "title": "Target Timeout", "type": "integer" }, @@ -6113,6 +6168,7 @@ Each event will be submitted via HTTP POST to the user provided URL. "properties": { "count": { "default": 1, + "minimum": 0, "title": "Count", "type": "integer" }, diff --git a/src/pytypes/onefuzztypes/models.py b/src/pytypes/onefuzztypes/models.py index a16b8fd0bf..bc805e4bf2 100644 --- a/src/pytypes/onefuzztypes/models.py +++ b/src/pytypes/onefuzztypes/models.py @@ -119,30 +119,18 @@ class JobConfig(BaseModel): project: str name: str build: str - duration: int - - @validator("duration", allow_reuse=True) - def check_duration(cls, value: int) -> int: - if value < ONE_HOUR or value > SEVEN_DAYS: - raise ValueError("invalid duration") - return value + duration: int = Field(ge=ONE_HOUR, le=SEVEN_DAYS) class ReproConfig(BaseModel): container: Container path: str - duration: int - - @validator("duration", allow_reuse=True) - def check_duration(cls, value: int) -> int: - if value < ONE_HOUR or value > SEVEN_DAYS: - raise ValueError("invalid duration") - return value + duration: int = Field(ge=ONE_HOUR, le=SEVEN_DAYS) class TaskDetails(BaseModel): type: TaskType - duration: int + duration: int = Field(ge=ONE_HOUR, le=SEVEN_DAYS) target_exe: Optional[str] target_env: Optional[Dict[str, str]] target_options: Optional[List[str]] @@ -150,7 +138,7 @@ class TaskDetails(BaseModel): target_options_merge: Optional[bool] check_asan_log: Optional[bool] check_debugger: Optional[bool] = Field(default=True) - check_retry_count: Optional[int] + check_retry_count: Optional[int] = Field(ge=0) check_fuzzer_help: Optional[bool] expect_crash_on_failure: Optional[bool] rename_output: Optional[bool] @@ -168,33 +156,13 @@ class TaskDetails(BaseModel): stats_file: Optional[str] stats_format: Optional[StatsFormat] reboot_after_setup: Optional[bool] - target_timeout: Optional[int] + target_timeout: Optional[int] = Field(ge=1) ensemble_sync_delay: Optional[int] preserve_existing_outputs: Optional[bool] report_list: Optional[List[str]] minimized_stack_depth: Optional[int] coverage_filter: Optional[str] - @validator("check_retry_count", allow_reuse=True) - def validate_check_retry_count(cls, value: int) -> int: - if value is not None: - if value < 0: - raise ValueError("invalid check_retry_count") - return value - - @validator("target_timeout", allow_reuse=True) - def check_target_timeout(cls, value: Optional[int]) -> Optional[int]: - if value is not None: - if value < 1: - raise ValueError("invalid target_timeout") - return value - - @validator("duration", allow_reuse=True) - def check_duration(cls, value: int) -> int: - if value < ONE_HOUR or value > SEVEN_DAYS: - raise ValueError("invalid duration") - return value - class TaskPool(BaseModel): count: int @@ -205,16 +173,10 @@ class TaskVm(BaseModel): region: Region sku: str image: str - count: int = Field(default=1) + count: int = Field(default=1, ge=0) spot_instances: bool = Field(default=False) reboot_after_setup: Optional[bool] - @validator("count", allow_reuse=True) - def check_count(cls, value: int) -> int: - if value <= 0: - raise ValueError("invalid count") - return value - class TaskContainers(BaseModel): type: ContainerType @@ -607,6 +569,7 @@ class NodeCommandEnvelope(BaseModel): class Node(BaseModel): timestamp: Optional[datetime] = Field(alias="Timestamp") pool_name: PoolName + pool_id: Optional[UUID] machine_id: UUID state: NodeState = Field(default=NodeState.init) scaleset_id: Optional[UUID] = None @@ -632,43 +595,20 @@ class NodeTasks(BaseModel): class AutoScaleConfig(BaseModel): image: str - max_size: Optional[int] # max size of pool - min_size: int = Field(default=0) # min size of pool + max_size: int = Field(default=1000, le=1000, ge=0) # max size of pool + min_size: int = Field(default=0, le=1000, ge=0) # min size of pool region: Optional[Region] scaleset_size: int # Individual scaleset size spot_instances: bool = Field(default=False) ephemeral_os_disks: bool = Field(default=False) vm_sku: str - @validator("scaleset_size", allow_reuse=True) - def check_scaleset_size(cls, value: int) -> int: - if value < 1 or value > 1000: - raise ValueError("invalid scaleset size") - return value - @root_validator() def check_data(cls, values: Any) -> Any: - if ( - "max_size" in values - and values.get("max_size") - and values.get("min_size") > values.get("max_size") - ): + if values['min_size'] <= values['max_size']: raise ValueError("The pool min_size is greater than max_size") return values - @validator("max_size", allow_reuse=True) - def check_max_size(cls, value: Optional[int]) -> Optional[int]: - if value and value < 1: - raise ValueError("Autoscale sizes are not defined properly") - return value - - @validator("min_size", allow_reuse=True) - def check_min_size(cls, value: int) -> int: - if value < 0 or value > 1000: - raise ValueError("Invalid pool min_size") - return value - - class Pool(BaseModel): timestamp: Optional[datetime] = Field(alias="Timestamp") name: PoolName @@ -706,7 +646,7 @@ class Scaleset(BaseModel): vm_sku: str image: str region: Region - size: int + size: int = Field(ge=0) spot_instances: bool ephemeral_os_disks: bool = Field(default=False) needs_config_update: bool = Field(default=False) @@ -716,12 +656,6 @@ class Scaleset(BaseModel): client_object_id: Optional[UUID] tags: Dict[str, str] = Field(default_factory=lambda: {}) - @validator("size", allow_reuse=True) - def check_size(cls, value: int) -> int: - if value < 0: - raise ValueError("Invalid scaleset size") - return value - class NotificationConfig(BaseModel): config: NotificationTemplate diff --git a/src/pytypes/onefuzztypes/requests.py b/src/pytypes/onefuzztypes/requests.py index 8180b1b24e..c226dd10e8 100644 --- a/src/pytypes/onefuzztypes/requests.py +++ b/src/pytypes/onefuzztypes/requests.py @@ -6,7 +6,7 @@ from typing import Any, Dict, List, Optional from uuid import UUID -from pydantic import AnyHttpUrl, BaseModel, Field, root_validator, validator +from pydantic import AnyHttpUrl, BaseModel, Field, root_validator from ._monkeypatch import _check_hotfix from .consts import ONE_HOUR, SEVEN_DAYS @@ -58,13 +58,7 @@ class TaskSearch(BaseRequest): class TaskResize(TaskGet): - count: int - - @validator("count", allow_reuse=True) - def check_count(cls, value: int) -> int: - if value <= 0: - raise ValueError("invalid count") - return value + count: int = Field(ge=1) class NodeCommandGet(BaseRequest): @@ -128,13 +122,7 @@ class ProxyCreate(BaseRequest): scaleset_id: UUID machine_id: UUID dst_port: int - duration: int - - @validator("duration", allow_reuse=True) - def check_duration(cls, value: int) -> int: - if value < ONE_HOUR or value > SEVEN_DAYS: - raise ValueError("invalid duration") - return value + duration: int = Field(ge=ONE_HOUR, le=SEVEN_DAYS) class ProxyDelete(BaseRequest): @@ -172,13 +160,7 @@ class ScalesetStop(BaseRequest): class ScalesetUpdate(BaseRequest): scaleset_id: UUID - size: Optional[int] - - @validator("size", allow_reuse=True) - def check_optional_size(cls, value: Optional[int]) -> Optional[int]: - if value is not None and value < 0: - raise ValueError("invalid size") - return value + size: Optional[int] = Field(ge=1) class ScalesetCreate(BaseRequest): @@ -186,17 +168,11 @@ class ScalesetCreate(BaseRequest): vm_sku: str image: str region: Optional[Region] - size: int + size: int = Field(ge=1) spot_instances: bool ephemeral_os_disks: bool = Field(default=False) tags: Dict[str, str] - @validator("size", allow_reuse=True) - def check_size(cls, value: int) -> int: - if value <= 0: - raise ValueError("invalid size") - return value - class ContainerGet(BaseRequest): name: Container From fa40b76908574e9374e8652228b6e066360679f4 Mon Sep 17 00:00:00 2001 From: Brian Caswell Date: Wed, 7 Jul 2021 16:15:53 -0400 Subject: [PATCH 2/2] lint --- src/pytypes/onefuzztypes/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pytypes/onefuzztypes/models.py b/src/pytypes/onefuzztypes/models.py index bc805e4bf2..06d4a603f8 100644 --- a/src/pytypes/onefuzztypes/models.py +++ b/src/pytypes/onefuzztypes/models.py @@ -605,10 +605,11 @@ class AutoScaleConfig(BaseModel): @root_validator() def check_data(cls, values: Any) -> Any: - if values['min_size'] <= values['max_size']: + if values["min_size"] <= values["max_size"]: raise ValueError("The pool min_size is greater than max_size") return values + class Pool(BaseModel): timestamp: Optional[datetime] = Field(alias="Timestamp") name: PoolName