onefuzz/docs/deprecated/declarative-templates.md
Cheick Keita f13f52ab71
Deprecating the job template feature (#2798)
* deprecating the job template feature

* removing the code

* format
2023-02-08 19:21:03 +00:00

223 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Declarative Job Templates -- Deprecated
Provide the ability to maintain job templates, akin to `onefuzz template
libfuzzer basic` at the service level. The templates include a job
definition, an arbitrary set of tasks, and an arbitrary set of notification
configs. The templates are managed at the service level, with job-submission
time updates using a declarative syntax based on `jsonpatch`.
The SDK makes use of template configs, provided by the service, to
dynamically build Python methods for each template. This process enables the
automatic argument parser generated by type signatures to automatically
create the CLI subcommands for the template.
## User Experience
* On `onefuzz login` (or `onefuzz job_templates refresh`), cache the existing set of templates
* Users can see the supported templates via `onefuzz job_templates submit --help`
* Users can submit jobs via `onefuzz job_templates submit libfuzzer OSNAME project name build pool --target_exe fuzz.exe`
* Template configs are refreshed automatically if they are older than 24 hours.
Future work:
* submitting jobs by config. Not everything is easy to express via argparse,
such as values that begin with `-`. In order to support this, it should be
trivial to expose a method that takes a json file and submits it.
## Admin Experience
Administrators can manage their own templates via `onefuzz job_templates
manage [list,get,update,delete]`.
If the runtime configuration for the template changes, users will need to
refresh their cache to pull the runtime configuration.
## Implementation Details
A declarative job template includes:
* a Job (JobConfig, as used by `onefuzz jobs create`)
* a list of Tasks (TaskConfig, which is used by `onefuzz tasks create`)
* a list of Notifications (NotificationConfig + container type, akin to what is used by `onefuzz notifications create`)
* a list of required and optional form fields used to update the aforementioned JobConfig, TaskConfig, and NotificationConfig entries at runtime.
The form fields allow for 'add' or 'replace' of basic field data using [jsonpatch](http://jsonpatch.com) semantics.
## Example Form Fields
This following field named `target_workers`, which is required to be an `int`,
will optionally (if the request includes it) replace the `target_workers` value
of in the first task in the template.
```python
UserField(
name="target_workers",
required=False,
type=UserFieldType.Int,
help="The number of workers to use for this task",
locations=[
UserFieldLocation(
op=UserFieldOperation.replace,
path="/tasks/0/task/target_workers",
),
],
)
```
## Allowed Data Types
The data types allowed in configuring arbitrary components in the JobTemplate are:
* `bool`
* `int`
* `str`
* `Dict[str, str]`
* `List[str]`
## Referring to Tasks
In existing procedural templates, some tasks require that other tasks are
running before they may be scheduled. For example, in the `libfuzzer`
procedural template, the `libfuzzer_crash_report` task has a `libfuzzer_fuzz`
task prerequisite. This is specified via the prerequisite's `task_id`, which is
a random server-assigned UUID.
In procedural templates, the dependency task is simply created before its
dependent.
To support such a reference in `OnefuzzTemplate`, specify the prerequisite task
by the `u128` representation index in to the list of tasks. Example, to refer
to the first task, use:
```python
TaskConfig(
prereq_tasks=[UUID(int=0)],
...
)
```
## Hardcoded vs Runtime-specified Container Names
To support differentiating _always use "afl-linux" for tools_ vs _ask
what container to use for setup_, if the container name is blank in the
template, it will be provided as part of the `JobTemplateConfig` and in the
resulting `JobTemplateRequest`.
## Specifying Notifications in the Template
The existing templates support adding a notification config on the command
line, via `--notification_config`, but the existing templates themselves do
not include default notifications.
Declarative job templates include optional support to configure notifications
as part of the template, rather than requiring the user provide the
configuration.
Example declarative job template that specifies using the aforementioned
NotificationConfig for the `unique_reports` containers used in the Job.
```python
JobTemplateNotification(
container_type=ContainerType.unique_reports,
notification=NotificationConfig(config=TeamsTemplate(url="https://contoso.com/webhook-url-here")),
)
```
## Differences from Existing Templates
* Declaratively specifying the allowed values for enums, such as StatsFormat,
is not supported. Fields must currently use Str, which evaluates to Enum
value during template rendering, is functional.
* Existing templates automatically differentiate between Windows and Linux
tasks. This does not support differentiating between platforms automatically.
As such, there is a new required parameter to specify the OS.
## From the CLI
```
onefuzz job_templates submit libfuzzer --help
usage: onefuzz job_templates submit libfuzzer [-h] [-v] [--format {json,raw}] [--query QUERY] [--target_exe TARGET_EXE]
[--duration DURATION] [--target_workers TARGET_WORKERS] [--vm_count VM_COUNT]
[--target_options [TARGET_OPTIONS [TARGET_OPTIONS ...]]]
[--target_env str=str [str=str ...]] [--reboot_after_setup]
[--check_retry_count CHECK_RETRY_COUNT] [--target_timeout TARGET_TIMEOUT]
[--tags str=str [str=str ...]] [--readonly_inputs_dir READONLY_INPUTS_DIR]
[--setup_dir SETUP_DIR] [--inputs_dir INPUTS_DIR]
[--container_names ContainerType=str [ContainerType=str ...]]
OS project name build pool_name
positional arguments:
OS Specify the OS to use in the job. accepted OS: windows, linux
project Name of the Project
name Name of the Target
build Name of the Target
pool_name Execute the task on the specified pool
optional arguments:
-h, --help show this help message and exit
-v, --verbose increase output verbosity
--format {json,raw} output format
--query QUERY JMESPath query string. See http://jmespath.org/ for more information and examples.
--target_exe TARGET_EXE
Path to the target executable (default: fuzz.exe)
--duration DURATION Number of hours to execute the task (default: 24)
--target_workers TARGET_WORKERS
Number of instances of the libfuzzer target on each VM
--vm_count VM_COUNT Number of VMs to use for fuzzing (default: 2)
--target_options [TARGET_OPTIONS [TARGET_OPTIONS ...]]
Command line options for the target
--target_env str=str [str=str ...]
Environment variables for the target
--reboot_after_setup After executing the setup script, reboot the VM (Default: False. Sets value to True)
--check_retry_count CHECK_RETRY_COUNT
Number of times to retry a crash to verify reproducability
--target_timeout TARGET_TIMEOUT
Number of seconds to timeout during reproduction
--tags str=str [str=str ...]
User provided metadata for the tasks
--readonly_inputs_dir READONLY_INPUTS_DIR
Local path to the readonly_inputs directory
--setup_dir SETUP_DIR
Local path to the setup directory
--inputs_dir INPUTS_DIR
Local path to the inputs directory
--container_names ContainerType=str [ContainerType=str ...]
custom container names (eg: setup=my-setup-container)
```
## From the SDK
From the perspective of the SDK, this looks _very_ similar to the existing templates. All of the arguments from the request are converted into named arguments with appropriate type signatures.
```
python
Python 3.8.2 (default, Jul 16 2020, 14:00:26)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from onefuzz.api import Onefuzz
>>> a = Onefuzz()
>>> help(a.job_templates.submit.libfuzzer)
Help on method func in module onefuzz.job_templates.main:
func(platform: onefuzztypes.enums.OS, *, project: str, name: str, build: str, pool_name: str, target_exe: <function NewType.<locals>.new_type at 0x7f7909338040> = 'fuzz.exe', duration: int = 24, target_workers: Union[int, NoneType], vm_count: int = 2, target_options: Union[List[str], NoneType], target_env: Union[Dict[str, str], NoneType], reboot_after_setup: bool = False, check_retry_count: Union[int, NoneType], target_timeout: Union[int, NoneType], tags: Union[Dict[str, str], NoneType], readonly_inputs_dir: Union[Directory, NoneType], setup_dir: Union[Directory, NoneType], inputs_dir: Union[Directory, NoneType], container_names: Union[Dict[onefuzztypes.enums.ContainerType, str], NoneType] = None) -> onefuzztypes.models.Job method of onefuzz.job_templates.main.TemplateHandler instance
Launch 'libfuzzer' job
:param Platform platform: Specify the OS to use in the job.
:param str project: Name of the Project
:param str name: Name of the Target
:param str build: Name of the Target
:param str pool_name: Execute the task on the specified pool
:param str target_exe: Path to the target executable
:param int duration: Number of hours to execute the task
:param int target_workers: Number of instances of the libfuzzer target on each VM
:param int vm_count: Number of VMs to use for fuzzing
:param list target_options: Command line options for the target
:param dict target_env: Environment variables for the target
:param bool reboot_after_setup: After executing the setup script, reboot the VM
:param int check_retry_count: Number of times to retry a crash to verify reproducability
:param int target_timeout: Number of seconds to timeout during reproduction
:param dict tags: User provided metadata for the tasks
:param Directory readonly_inputs_dir: Local path to the readonly_inputs directory
:param Directory setup_dir: Local path to the setup directory
:param Directory inputs_dir: Local path to the inputs directory
:param dict container_names: custom container names (eg: setup=my-setup-container)
```