add Timestamp to multiple models (#796)

Expose the Azure storage table's "Timestamp" for the models where Timestamp should be user-accessible and remove the Timestamp field from models that did not sign up for it.

The behavior where Timestamp is only set by Azure Storage is kept.
This commit is contained in:
bmc-msft
2021-04-13 15:03:25 -04:00
committed by GitHub
parent 39464dc606
commit 470e95c833
5 changed files with 19 additions and 8 deletions

View File

@ -37,7 +37,7 @@ from onefuzztypes.enums import (
) )
from onefuzztypes.models import Error, SecretData from onefuzztypes.models import Error, SecretData
from onefuzztypes.primitives import Container, PoolName, Region from onefuzztypes.primitives import Container, PoolName, Region
from pydantic import BaseModel, Field from pydantic import BaseModel
from typing_extensions import Protocol from typing_extensions import Protocol
from .azure.table import get_client from .azure.table import get_client
@ -219,8 +219,9 @@ class ModelMixin(BaseModel):
return result return result
# NOTE: if you want to include Timestamp in a model that uses ORMMixin,
# it must be maintained as part of the model.
class ORMMixin(ModelMixin): class ORMMixin(ModelMixin):
Timestamp: Optional[datetime] = Field(alias="Timestamp")
etag: Optional[str] etag: Optional[str]
@classmethod @classmethod
@ -257,7 +258,7 @@ class ORMMixin(ModelMixin):
return None return None
def export_exclude(self) -> Optional[MappingIntStrAny]: def export_exclude(self) -> Optional[MappingIntStrAny]:
return {"etag": ..., "Timestamp": ...} return {"etag": ...}
def telemetry_include(self) -> Optional[MappingIntStrAny]: def telemetry_include(self) -> Optional[MappingIntStrAny]:
return {} return {}

View File

@ -42,6 +42,7 @@ PROXY_LOG_PREFIX = "scaleset-proxy: "
# This isn't intended to ever be shared to the client, hence not being in # This isn't intended to ever be shared to the client, hence not being in
# onefuzztypes # onefuzztypes
class Proxy(ORMMixin): class Proxy(ORMMixin):
timestamp: Optional[datetime.datetime] = Field(alias="Timestamp")
region: Region region: Region
state: VmState = Field(default=VmState.init) state: VmState = Field(default=VmState.init)
auth: Authentication = Field(default_factory=build_auth) auth: Authentication = Field(default_factory=build_auth)
@ -179,12 +180,12 @@ class Proxy(ORMMixin):
) )
return False return False
elif not self.heartbeat and self.Timestamp and self.Timestamp < ten_minutes_ago: elif not self.heartbeat and self.timestamp and self.timestamp < ten_minutes_ago:
logging.error( logging.error(
PROXY_LOG_PREFIX + "no heartbeat in the last 10 minutes: " PROXY_LOG_PREFIX + "no heartbeat in the last 10 minutes: "
"%s timestamp: %s compared_to:%s", "%s timestamp: %s compared_to:%s",
self.region, self.region,
self.Timestamp, self.timestamp,
ten_minutes_ago, ten_minutes_ago,
) )
return False return False

View File

@ -17,12 +17,12 @@ class TaskEvent(BASE_TASK_EVENT, ORMMixin):
@classmethod @classmethod
def get_summary(cls, task_id: UUID) -> List[TaskEventSummary]: def get_summary(cls, task_id: UUID) -> List[TaskEventSummary]:
events = cls.search(query={"task_id": [task_id]}) events = cls.search(query={"task_id": [task_id]})
# handle None case of Optional[e.Timestamp], which shouldn't happen # handle None case of Optional[e.timestamp], which shouldn't happen
events.sort(key=lambda e: e.Timestamp or datetime.datetime.max) events.sort(key=lambda e: e.timestamp or datetime.datetime.max)
return [ return [
TaskEventSummary( TaskEventSummary(
timestamp=e.Timestamp, timestamp=e.timestamp,
event_data=get_event_data(e.event_data), event_data=get_event_data(e.event_data),
event_type=get_event_type(e.event_data), event_type=get_event_type(e.event_data),
) )

View File

@ -535,6 +535,7 @@ class JobTaskInfo(BaseModel):
class Job(BaseModel): class Job(BaseModel):
timestamp: Optional[datetime] = Field(alias="Timestamp")
job_id: UUID = Field(default_factory=uuid4) job_id: UUID = Field(default_factory=uuid4)
state: JobState = Field(default=JobState.init) state: JobState = Field(default=JobState.init)
config: JobConfig config: JobConfig
@ -557,6 +558,7 @@ class NodeHeartbeatEntry(BaseModel):
class Node(BaseModel): class Node(BaseModel):
timestamp: Optional[datetime] = Field(alias="Timestamp")
pool_name: PoolName pool_name: PoolName
machine_id: UUID machine_id: UUID
state: NodeState = Field(default=NodeState.init) state: NodeState = Field(default=NodeState.init)
@ -620,6 +622,7 @@ class AutoScaleConfig(BaseModel):
class Pool(BaseModel): class Pool(BaseModel):
timestamp: Optional[datetime] = Field(alias="Timestamp")
name: PoolName name: PoolName
pool_id: UUID = Field(default_factory=uuid4) pool_id: UUID = Field(default_factory=uuid4)
os: OS os: OS
@ -647,6 +650,7 @@ class ScalesetNodeState(BaseModel):
class Scaleset(BaseModel): class Scaleset(BaseModel):
timestamp: Optional[datetime] = Field(alias="Timestamp")
pool_name: PoolName pool_name: PoolName
scaleset_id: UUID = Field(default_factory=uuid4) scaleset_id: UUID = Field(default_factory=uuid4)
state: ScalesetState = Field(default=ScalesetState.init) state: ScalesetState = Field(default=ScalesetState.init)
@ -676,6 +680,7 @@ class NotificationConfig(BaseModel):
class Repro(BaseModel): class Repro(BaseModel):
timestamp: Optional[datetime] = Field(alias="Timestamp")
vm_id: UUID = Field(default_factory=uuid4) vm_id: UUID = Field(default_factory=uuid4)
task_id: UUID task_id: UUID
config: ReproConfig config: ReproConfig
@ -795,6 +800,7 @@ class NodeCommandEnvelope(BaseModel):
class TaskEvent(BaseModel): class TaskEvent(BaseModel):
timestamp: Optional[datetime] = Field(alias="Timestamp")
task_id: UUID task_id: UUID
machine_id: UUID machine_id: UUID
event_data: WorkerEvent event_data: WorkerEvent
@ -813,6 +819,7 @@ class NodeAssignment(BaseModel):
class Task(BaseModel): class Task(BaseModel):
timestamp: Optional[datetime] = Field(alias="Timestamp")
job_id: UUID job_id: UUID
task_id: UUID = Field(default_factory=uuid4) task_id: UUID = Field(default_factory=uuid4)
state: TaskState = Field(default=TaskState.init) state: TaskState = Field(default=TaskState.init)

View File

@ -3,6 +3,7 @@
# Copyright (c) Microsoft Corporation. # Copyright (c) Microsoft Corporation.
# Licensed under the MIT License. # Licensed under the MIT License.
from datetime import datetime
from typing import List, Optional from typing import List, Optional
from uuid import UUID, uuid4 from uuid import UUID, uuid4
@ -17,6 +18,7 @@ class WebhookMessage(EventMessage):
class WebhookMessageLog(WebhookMessage): class WebhookMessageLog(WebhookMessage):
timestamp: Optional[datetime] = Field(alias="Timestamp")
state: WebhookMessageState = Field(default=WebhookMessageState.queued) state: WebhookMessageState = Field(default=WebhookMessageState.queued)
try_count: int = Field(default=0) try_count: int = Field(default=0)