diff --git a/docs/webhook_events.md b/docs/webhook_events.md index 06d51997c..25f690c58 100644 --- a/docs/webhook_events.md +++ b/docs/webhook_events.md @@ -800,6 +800,11 @@ Each event will be submitted via HTTP POST to the user provided URL. }, "AutoScaleConfig": { "properties": { + "ephemeral_os_disks": { + "default": false, + "title": "Ephemeral Os Disks", + "type": "boolean" + }, "image": { "title": "Image", "type": "string" @@ -3764,6 +3769,11 @@ Each event will be submitted via HTTP POST to the user provided URL. }, "AutoScaleConfig": { "properties": { + "ephemeral_os_disks": { + "default": false, + "title": "Ephemeral Os Disks", + "type": "boolean" + }, "image": { "title": "Image", "type": "string" diff --git a/src/api-service/__app__/onefuzzlib/autoscale.py b/src/api-service/__app__/onefuzzlib/autoscale.py index 253878d61..b7aeff69c 100644 --- a/src/api-service/__app__/onefuzzlib/autoscale.py +++ b/src/api-service/__app__/onefuzzlib/autoscale.py @@ -75,6 +75,7 @@ def scale_up(pool: Pool, scalesets: List[Scaleset], nodes_needed: int) -> None: region=autoscale_config.region, size=max_nodes_scaleset, spot_instances=autoscale_config.spot_instances, + ephemeral_os_disks=autoscale_config.ephemeral_os_disks, tags={"pool": pool.name}, ) nodes_needed -= max_nodes_scaleset diff --git a/src/api-service/__app__/onefuzzlib/azure/vmss.py b/src/api-service/__app__/onefuzzlib/azure/vmss.py index 81e2bbc15..2434515ec 100644 --- a/src/api-service/__app__/onefuzzlib/azure/vmss.py +++ b/src/api-service/__app__/onefuzzlib/azure/vmss.py @@ -208,6 +208,7 @@ def create_vmss( image: str, network_id: str, spot_instances: bool, + ephemeral_os_disks: bool, extensions: List[Any], password: str, ssh_public_key: str, @@ -259,7 +260,9 @@ def create_vmss( }, "virtual_machine_profile": { "priority": "Regular", - "storage_profile": {"image_reference": image_ref}, + "storage_profile": { + "image_reference": image_ref, + }, "os_profile": { "computer_name_prefix": "node", "admin_username": "onefuzz", @@ -300,6 +303,13 @@ def create_vmss( }, } + if ephemeral_os_disks: + params["virtual_machine_profile"]["storage_profile"]["os_disk"] = { + "diffDiskSettings": {"option": "Local"}, + "caching": "ReadOnly", + "createOption": "FromImage", + } + if spot_instances: # Setting max price to -1 means it won't be evicted because of # price. diff --git a/src/api-service/__app__/onefuzzlib/workers/scalesets.py b/src/api-service/__app__/onefuzzlib/workers/scalesets.py index a07859c1c..4907111c9 100644 --- a/src/api-service/__app__/onefuzzlib/workers/scalesets.py +++ b/src/api-service/__app__/onefuzzlib/workers/scalesets.py @@ -82,6 +82,7 @@ class Scaleset(BASE_SCALESET, ORMMixin): region: Region, size: int, spot_instances: bool, + ephemeral_os_disks: bool, tags: Dict[str, str], client_id: Optional[UUID] = None, client_object_id: Optional[UUID] = None, @@ -93,6 +94,7 @@ class Scaleset(BASE_SCALESET, ORMMixin): region=region, size=size, spot_instances=spot_instances, + ephemeral_os_disks=ephemeral_os_disks, auth=build_auth(), client_id=client_id, client_object_id=client_object_id, @@ -237,6 +239,7 @@ class Scaleset(BASE_SCALESET, ORMMixin): self.image, network_id, self.spot_instances, + self.ephemeral_os_disks, extensions, self.auth.password, self.auth.public_key, diff --git a/src/api-service/__app__/scaleset/__init__.py b/src/api-service/__app__/scaleset/__init__.py index b62175ed9..5404729ff 100644 --- a/src/api-service/__app__/scaleset/__init__.py +++ b/src/api-service/__app__/scaleset/__init__.py @@ -92,6 +92,7 @@ def post(req: func.HttpRequest) -> func.HttpResponse: region=region, size=request.size, spot_instances=request.spot_instances, + ephemeral_os_disks=request.ephemeral_os_disks, tags=request.tags, ) # don't return auths during create, only 'get' with include_auth diff --git a/src/cli/onefuzz/api.py b/src/cli/onefuzz/api.py index 707a18fca..2c441b86a 100644 --- a/src/cli/onefuzz/api.py +++ b/src/cli/onefuzz/api.py @@ -1279,6 +1279,7 @@ class Scaleset(Endpoint): vm_sku: Optional[str] = "Standard_D2s_v3", region: Optional[primitives.Region] = None, spot_instances: bool = False, + ephemeral_os_disks: bool = True, tags: Optional[Dict[str, str]] = None, ) -> models.Scaleset: self.logger.debug("create scaleset") @@ -1305,6 +1306,7 @@ class Scaleset(Endpoint): region=region, size=size, spot_instances=spot_instances, + ephemeral_os_disks=ephemeral_os_disks, tags=tags, ), ) diff --git a/src/pytypes/onefuzztypes/models.py b/src/pytypes/onefuzztypes/models.py index c72c08187..3ed5e4dbd 100644 --- a/src/pytypes/onefuzztypes/models.py +++ b/src/pytypes/onefuzztypes/models.py @@ -586,6 +586,7 @@ class AutoScaleConfig(BaseModel): 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) @@ -654,6 +655,7 @@ class Scaleset(BaseModel): region: Region size: int spot_instances: bool + ephemeral_os_disks: bool = Field(default=False) needs_config_update: bool = Field(default=False) error: Optional[Error] nodes: Optional[List[ScalesetNodeState]] diff --git a/src/pytypes/onefuzztypes/requests.py b/src/pytypes/onefuzztypes/requests.py index 9511cf9c3..39c5922de 100644 --- a/src/pytypes/onefuzztypes/requests.py +++ b/src/pytypes/onefuzztypes/requests.py @@ -176,6 +176,7 @@ class ScalesetCreate(BaseRequest): region: Optional[Region] size: int spot_instances: bool + ephemeral_os_disks: bool tags: Dict[str, str] @validator("size", allow_reuse=True)