add status job commands
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
-from typing import List, Optional
+from collections import defaultdict
+from typing import DefaultDict, List, Optional, Set
from uuid import UUID
-from ..api import Command
+from onefuzztypes.enums import ContainerType, JobState
+from onefuzztypes.primitives import Container
+
+from ..api import UUID_EXPANSION, Command
from .cache import JobFilter
from .raw import raw
from .top import Top
+def short(value: UUID) -> str:
+ return str(value).split("-")[0]
+
+
class Status(Command):
""" Monitor status of Onefuzz Instance """
+ def project(
+ self,
+ *,
+ project: str,
+ name: str,
+ build: Optional[str] = None,
+ all_jobs: Optional[bool] = False,
+ ) -> None:
+ job_state = JobState.available()
+ if all_jobs:
+ job_state = [x for x in JobState]
+
+ for job in self.onefuzz.jobs.list(job_state=job_state):
+ if job.config.project != project:
+ continue
+ if job.config.name != name:
+ continue
+ if build is not None and job.config.build != build:
+ continue
+
+ self.job(job.job_id)
+
+ def job(self, job_id: UUID_EXPANSION) -> None:
+ job = self.onefuzz.jobs.get(job_id)
+
+ print(f"job: {job.job_id}")
+ print(
+ f"project:{job.config.project} name:{job.config.name} build:{job.config.build}"
+ )
+ print("\ntasks:")
+
+ tasks = self.onefuzz.tasks.list(job_id=job.job_id, state=[])
+ with_errors = []
+ for task in tasks:
+ if task.error:
+ with_errors.append(task)
+ continue
+ print(
+ f"{short(task.task_id)} "
+ f"target:{task.config.task.target_exe} "
+ f"state:{task.state.name} "
+ f"type:{task.config.task.type.name}"
+ )
+
+ if with_errors:
+ print("\ntasks with errors:")
+ entries = []
+ for task in with_errors:
+ if not task.error:
+ continue
+
+ errors = "\n".join([x.strip() for x in task.error.errors])
+
+ message = (
+ f"{short(task.task_id)} type:{task.config.task.type.name} "
+ f"target:{task.config.task.target_exe}"
+ f"\nerror:\n{errors}"
+ )
+ entries.append(message)
+ print("\n\n".join(entries))
+
+ containers: DefaultDict[ContainerType, Set[Container]] = defaultdict(set)
+ for task in tasks:
+ for container in task.config.containers:
+ if container.type not in containers:
+ containers[container.type] = set()
+ containers[container.type].add(container.name)
+
+ print("\ncontainers:")
+ for container_type in containers:
+ for container_name in containers[container_type]:
+ try:
+ count = len(
+ self.onefuzz.containers.files.list(container_name).files
+ )
+ print(
+ f"{container_type.name:<15} count:{count:<5} name:{container_name}"
+ )
+ except Exception:
+ print(
+ f"{container_type.name:<15} INACCESSIBLE CONTAINER name:{container_name}"
+ )
+
def raw(self) -> None:
""" Raw status update stream """
raw(self.onefuzz, self.logger)
