mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-17 20:38:06 +00:00
Validate scriban from cli (#2800)
* Add validate scriban endpoint to cli * missed a file * Lint -- I miss C# * docs
This commit is contained in:
@ -330,9 +330,7 @@ If webhook is set to have Event Grid message format then the payload will look a
|
||||
},
|
||||
"required": [
|
||||
"job_id",
|
||||
"task",
|
||||
"containers",
|
||||
"tags"
|
||||
"task"
|
||||
],
|
||||
"title": "TaskConfig",
|
||||
"type": "object"
|
||||
@ -2239,9 +2237,7 @@ If webhook is set to have Event Grid message format then the payload will look a
|
||||
},
|
||||
"required": [
|
||||
"job_id",
|
||||
"task",
|
||||
"containers",
|
||||
"tags"
|
||||
"task"
|
||||
],
|
||||
"title": "TaskConfig",
|
||||
"type": "object"
|
||||
@ -2969,9 +2965,7 @@ If webhook is set to have Event Grid message format then the payload will look a
|
||||
},
|
||||
"required": [
|
||||
"job_id",
|
||||
"task",
|
||||
"containers",
|
||||
"tags"
|
||||
"task"
|
||||
],
|
||||
"title": "TaskConfig",
|
||||
"type": "object"
|
||||
@ -3490,9 +3484,7 @@ If webhook is set to have Event Grid message format then the payload will look a
|
||||
},
|
||||
"required": [
|
||||
"job_id",
|
||||
"task",
|
||||
"containers",
|
||||
"tags"
|
||||
"task"
|
||||
],
|
||||
"title": "TaskConfig",
|
||||
"type": "object"
|
||||
@ -3954,9 +3946,7 @@ If webhook is set to have Event Grid message format then the payload will look a
|
||||
},
|
||||
"required": [
|
||||
"job_id",
|
||||
"task",
|
||||
"containers",
|
||||
"tags"
|
||||
"task"
|
||||
],
|
||||
"title": "TaskConfig",
|
||||
"type": "object"
|
||||
@ -4392,9 +4382,7 @@ If webhook is set to have Event Grid message format then the payload will look a
|
||||
},
|
||||
"required": [
|
||||
"job_id",
|
||||
"task",
|
||||
"containers",
|
||||
"tags"
|
||||
"task"
|
||||
],
|
||||
"title": "TaskConfig",
|
||||
"type": "object"
|
||||
@ -4857,9 +4845,7 @@ If webhook is set to have Event Grid message format then the payload will look a
|
||||
},
|
||||
"required": [
|
||||
"job_id",
|
||||
"task",
|
||||
"containers",
|
||||
"tags"
|
||||
"task"
|
||||
],
|
||||
"title": "TaskConfig",
|
||||
"type": "object"
|
||||
@ -6606,9 +6592,7 @@ If webhook is set to have Event Grid message format then the payload will look a
|
||||
},
|
||||
"required": [
|
||||
"job_id",
|
||||
"task",
|
||||
"containers",
|
||||
"tags"
|
||||
"task"
|
||||
],
|
||||
"title": "TaskConfig",
|
||||
"type": "object"
|
||||
|
@ -529,6 +529,7 @@ class Containers(Endpoint):
|
||||
) -> None:
|
||||
to_download: Dict[str, str] = {}
|
||||
for task in tasks:
|
||||
if task.config.containers is not None:
|
||||
for container in task.config.containers:
|
||||
info = self.onefuzz.containers.get(container.name)
|
||||
name = os.path.join(container.type.name, container.name)
|
||||
@ -1099,8 +1100,13 @@ class JobContainers(Endpoint):
|
||||
containers = set()
|
||||
tasks = self.onefuzz.tasks.list(job_id=job_id, state=[])
|
||||
for task in tasks:
|
||||
if task.config.containers is not None:
|
||||
containers.update(
|
||||
set(x.name for x in task.config.containers if x.type == container_type)
|
||||
set(
|
||||
x.name
|
||||
for x in task.config.containers
|
||||
if x.type == container_type
|
||||
)
|
||||
)
|
||||
|
||||
results: Dict[str, List[str]] = {}
|
||||
@ -1133,6 +1139,7 @@ class JobContainers(Endpoint):
|
||||
containers = set()
|
||||
to_delete = set()
|
||||
for task in self.onefuzz.jobs.tasks.list(job_id=job.job_id):
|
||||
if task.config.containers is not None:
|
||||
for container in task.config.containers:
|
||||
containers.add(container.name)
|
||||
if container.type not in SAFE_TO_REMOVE:
|
||||
@ -1713,6 +1720,17 @@ class InstanceConfigCmd(Endpoint):
|
||||
)
|
||||
|
||||
|
||||
class ValidateScriban(Endpoint):
|
||||
"""Interact with Validate Scriban"""
|
||||
|
||||
endpoint = "ValidateScriban"
|
||||
|
||||
def post(
|
||||
self, req: requests.TemplateValidationPost
|
||||
) -> responses.TemplateValidationResponse:
|
||||
return self._req_model("POST", responses.TemplateValidationResponse, data=req)
|
||||
|
||||
|
||||
class Command:
|
||||
def __init__(self, onefuzz: "Onefuzz", logger: logging.Logger):
|
||||
self.onefuzz = onefuzz
|
||||
@ -1803,6 +1821,7 @@ class Onefuzz:
|
||||
self.webhooks = Webhooks(self)
|
||||
self.tools = Tools(self)
|
||||
self.instance_config = InstanceConfigCmd(self)
|
||||
self.validate_scriban = ValidateScriban(self)
|
||||
|
||||
if self._backend.is_feature_enabled(PreviewFeature.job_templates.name):
|
||||
self.job_templates = JobTemplates(self)
|
||||
|
@ -18,9 +18,11 @@ from azure.applicationinsights import ApplicationInsightsDataClient
|
||||
from azure.applicationinsights.models import QueryBody
|
||||
from azure.identity import AzureCliCredential
|
||||
from azure.storage.blob import ContainerClient
|
||||
from onefuzztypes import models, requests
|
||||
from onefuzztypes.enums import ContainerType, TaskType
|
||||
from onefuzztypes.models import BlobRef, Job, NodeAssignment, Report, Task, TaskConfig
|
||||
from onefuzztypes.primitives import Container, Directory, PoolName
|
||||
from onefuzztypes.responses import TemplateValidationResponse
|
||||
|
||||
from onefuzz.api import UUID_EXPANSION, Command, Onefuzz
|
||||
|
||||
@ -721,6 +723,7 @@ class DebugNotification(Command):
|
||||
def _get_container(
|
||||
self, task: Task, container_type: ContainerType
|
||||
) -> Optional[Container]:
|
||||
if task.config.containers is not None:
|
||||
for container in task.config.containers:
|
||||
if container.type == container_type:
|
||||
return container.name
|
||||
@ -731,6 +734,13 @@ class DebugNotification(Command):
|
||||
_, netloc, _, _, _, _ = urlparse(sas_url)
|
||||
return netloc.split(".")[0]
|
||||
|
||||
def template(
|
||||
self, template: str, context: Optional[models.TemplateRenderContext]
|
||||
) -> TemplateValidationResponse:
|
||||
"""Validate scriban rendering of notification config"""
|
||||
req = requests.TemplateValidationPost(template=template, context=context)
|
||||
return self.onefuzz.validate_scriban.post(req)
|
||||
|
||||
def job(
|
||||
self,
|
||||
job_id: UUID_EXPANSION,
|
||||
|
@ -115,6 +115,7 @@ class Status(Command):
|
||||
|
||||
containers: DefaultDict[ContainerType, Set[Container]] = defaultdict(set)
|
||||
for task in tasks:
|
||||
if task.config.containers is not None:
|
||||
for container in task.config.containers:
|
||||
if container.type not in containers:
|
||||
containers[container.type] = set()
|
||||
|
@ -68,6 +68,7 @@ class Top:
|
||||
|
||||
for task in self.onefuzz.tasks.list(job_id=job.job_id):
|
||||
self.cache.add_task(task)
|
||||
if task.config.containers is not None:
|
||||
for container in task.config.containers:
|
||||
self.add_container(container.name)
|
||||
|
||||
|
@ -63,7 +63,11 @@ class Template(Command):
|
||||
self.onefuzz.tasks.delete(task.task_id)
|
||||
|
||||
if stop_notifications:
|
||||
container_names = [x.name for x in task.config.containers]
|
||||
container_names = (
|
||||
[x.name for x in task.config.containers]
|
||||
if task.config.containers is not None
|
||||
else []
|
||||
)
|
||||
notifications = self.onefuzz.notifications.list(
|
||||
container=container_names
|
||||
)
|
||||
|
@ -7,7 +7,7 @@ from datetime import datetime
|
||||
from typing import Any, Dict, Generic, List, Optional, TypeVar, Union
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
from pydantic import BaseModel, Field, root_validator, validator
|
||||
from pydantic import AnyHttpUrl, BaseModel, Field, root_validator, validator
|
||||
from pydantic.dataclasses import dataclass
|
||||
|
||||
from ._monkeypatch import _check_hotfix
|
||||
@ -193,8 +193,8 @@ class TaskConfig(BaseModel):
|
||||
task: TaskDetails
|
||||
vm: Optional[TaskVm]
|
||||
pool: Optional[TaskPool]
|
||||
containers: List[TaskContainers]
|
||||
tags: Dict[str, str]
|
||||
containers: Optional[List[TaskContainers]]
|
||||
tags: Optional[Dict[str, str]]
|
||||
debug: Optional[List[TaskDebugFlag]]
|
||||
colocate: Optional[bool]
|
||||
|
||||
@ -870,6 +870,18 @@ class ApiAccessRule(BaseModel):
|
||||
allowed_groups: List[UUID]
|
||||
|
||||
|
||||
class TemplateRenderContext(BaseModel):
|
||||
report: Report
|
||||
task: TaskConfig
|
||||
job: JobConfig
|
||||
report_url: AnyHttpUrl
|
||||
input_url: AnyHttpUrl
|
||||
target_url: AnyHttpUrl
|
||||
report_container: Container
|
||||
report_filename: str
|
||||
repro_cmd: str
|
||||
|
||||
|
||||
Endpoint = str
|
||||
# json dumps doesn't support UUID as dictionary key
|
||||
PrincipalID = str
|
||||
|
@ -20,7 +20,12 @@ from .enums import (
|
||||
TaskState,
|
||||
)
|
||||
from .events import EventType
|
||||
from .models import AutoScaleConfig, InstanceConfig, NotificationConfig
|
||||
from .models import (
|
||||
AutoScaleConfig,
|
||||
InstanceConfig,
|
||||
NotificationConfig,
|
||||
TemplateRenderContext,
|
||||
)
|
||||
from .primitives import Container, PoolName, Region
|
||||
from .webhooks import WebhookMessageFormat
|
||||
|
||||
@ -252,4 +257,9 @@ class InstanceConfigUpdate(BaseModel):
|
||||
config: InstanceConfig
|
||||
|
||||
|
||||
class TemplateValidationPost(BaseModel):
|
||||
template: str
|
||||
context: Optional[TemplateRenderContext]
|
||||
|
||||
|
||||
_check_hotfix()
|
||||
|
@ -9,7 +9,7 @@ from uuid import UUID
|
||||
from pydantic import BaseModel
|
||||
|
||||
from .enums import VmState
|
||||
from .models import Forward, NodeCommandEnvelope
|
||||
from .models import Forward, NodeCommandEnvelope, TemplateRenderContext
|
||||
from .primitives import Region
|
||||
|
||||
|
||||
@ -84,3 +84,8 @@ class PendingNodeCommand(BaseResponse):
|
||||
class CanSchedule(BaseResponse):
|
||||
allowed: bool
|
||||
work_stopped: bool
|
||||
|
||||
|
||||
class TemplateValidationResponse(BaseResponse):
|
||||
rendered_template: str
|
||||
available_context: TemplateRenderContext
|
||||
|
Reference in New Issue
Block a user