Skip to content
This repository has been archived by the owner on Nov 1, 2023. It is now read-only.

JobResult Table Re-design - Improved task- and machine- granularity #3539

Merged
Merged
Show file tree
Hide file tree
Changes from 99 commits
Commits
Show all changes
115 commits
Select commit Hold shift + click to select a range
c69deed
Release 8.7.1 (hotfix) (#3459)
AdamL-Microsoft Aug 29, 2023
c8986aa
Revert "Release 8.7.1 (hotfix) (#3459)" (#3468)
AdamL-Microsoft Aug 30, 2023
7b40402
Redo 8.7.1 (#3469)
AdamL-Microsoft Aug 30, 2023
d999603
Support custom ado fields that mark work items as duplicate (#3467)
kananb Aug 30, 2023
b2435b1
Update readme with archive message (#3408)
mgreisen Aug 31, 2023
b913074
Bump tokio from 1.30.0 to 1.32.0 in /src/proxy-manager (#3425)
dependabot[bot] Aug 31, 2023
14ab36e
Bump tokio from 1.30.0 to 1.32.0 in /src/agent (#3424)
dependabot[bot] Aug 31, 2023
f141050
Remove unnecessary method argument (#3473)
kananb Sep 1, 2023
d4319d2
Bump elsa from 1.8.1 to 1.9.0 in /src/agent (#3411)
dependabot[bot] Sep 4, 2023
93b16ec
Bump tempfile from 3.7.1 to 3.8.0 in /src/agent (#3437)
dependabot[bot] Sep 5, 2023
7f7ab37
Bump tempfile from 3.7.1 to 3.8.0 in /src/proxy-manager (#3436)
dependabot[bot] Sep 5, 2023
b2e6a07
Updating requirements.txt to accept >= onefuzztypes. (#3477)
nharper285 Sep 5, 2023
aa9c9ea
Bump notify from 6.0.1 to 6.1.1 in /src/agent (#3435)
dependabot[bot] Sep 5, 2023
74475cc
Bump azure_* crates (#3478)
Porges Sep 5, 2023
64699ed
Release 8.8.0 (#3466)
AdamL-Microsoft Sep 6, 2023
a3fb480
Bump clap from 4.3.21 to 4.4.2 in /src/agent (#3484)
dependabot[bot] Sep 6, 2023
59c52d6
Bump gimli from 0.27.3 to 0.28.0 in /src/agent (#3414)
dependabot[bot] Sep 6, 2023
dd9e266
Bump clap from 4.3.21 to 4.4.2 in /src/proxy-manager (#3474)
dependabot[bot] Sep 6, 2023
6e2cb14
Bump winreg from 0.50.0 to 0.51.0 in /src/agent (#3434)
dependabot[bot] Sep 6, 2023
d2d57a8
Starting integration tests (#3438)
tevoinea Sep 7, 2023
830b479
Fix sed checks for CLI versioning (#3486)
nharper285 Sep 7, 2023
896329d
Bump bytes from 1.4.0 to 1.5.0 in /src/agent (#3488)
dependabot[bot] Sep 10, 2023
d34138d
Improve area/iteration path validation (#3489)
kananb Sep 11, 2023
d009476
Improve handling of unexpected breakpoints (#3493)
tevoinea Sep 13, 2023
18f2b4a
Update azure_* crates (#3503)
Porges Sep 13, 2023
9ede0de
Fuzz coverage recording (#3322)
tevoinea Sep 14, 2023
cde6a19
Reporting coverage on task start up (#3502)
nharper285 Sep 14, 2023
1fb1563
Remove feature flag from heartbeat metrics. (#3505)
nharper285 Sep 14, 2023
c7a9827
Update archive notice. (#3507)
mgreisen Sep 15, 2023
58da7b4
Add onefuzz service version to job created events (#3504)
kananb Sep 20, 2023
60766e6
Tevoinea/add version checking in local tasks (#3517)
tevoinea Sep 21, 2023
e3c4a40
Create directories if they don't exist in the template (#3522)
tevoinea Sep 21, 2023
d1ccb1e
Support for retention policies on containers (#3501)
Porges Sep 26, 2023
7efea43
Bump rayon from 1.7.0 to 1.8.0 in /src/agent (#3520)
dependabot[bot] Sep 26, 2023
f3b7e20
Bump insta from 1.31.0 to 1.32.0 in /src/agent (#3521)
dependabot[bot] Sep 26, 2023
d2ba170
Disable `repro` and `debug` VM CLI commands. (#3494)
nharper285 Sep 27, 2023
2c8ecc9
Make modules case insenstive on windows (#3527)
tevoinea Sep 28, 2023
e12b41e
Update windows interceptor list (#3528)
tevoinea Sep 28, 2023
552df45
Template creation command (#3531)
tevoinea Sep 28, 2023
e3b1e0e
Terminate process on timeout in windows for the coverage task (#3529)
chkeita Sep 29, 2023
434a435
Ignore regression update when the work item is in some states (#3532)
chkeita Oct 2, 2023
16fd614
Updating IterationCount to be Task-based.
nharper285 Oct 2, 2023
a344bad
Changing to machine_id based
nharper285 Oct 2, 2023
19c7dbb
Fixing repro event name.
nharper285 Oct 3, 2023
645a029
Merge branch 'microsoft:main' into user/noharper/task-based-iterations
nharper285 Oct 3, 2023
69cc939
Updating iteration pr.
nharper285 Oct 3, 2023
74235dc
Merge branch 'main' into user/noharper/task-based-iterations
nharper285 Oct 3, 2023
1b77a85
Single entry results.
nharper285 Oct 4, 2023
ba8c144
Merge branch 'user/noharper/task-based-iterations' of https://github.…
nharper285 Oct 4, 2023
0ba78d1
Retry.
nharper285 Oct 4, 2023
f691c99
trying with unique guid.
nharper285 Oct 4, 2023
0a78fd1
Generic string type.
nharper285 Oct 4, 2023
806388d
putting it back.
nharper285 Oct 4, 2023
5fc9f07
removing old update code.
nharper285 Oct 4, 2023
a7373c5
removing comment.
nharper285 Oct 4, 2023
1320f87
Merge branch 'main' into user/noharper/task-based-iterations
nharper285 Oct 4, 2023
5d3b6f4
Attempting to partition on task_id, machine_id, and event type.
nharper285 Oct 4, 2023
55bd218
Merge branch 'user/noharper/task-based-iterations' of https://github.…
nharper285 Oct 4, 2023
ea37e7f
Using replace and update.
nharper285 Oct 4, 2023
810bdac
Add logging statement.
nharper285 Oct 5, 2023
251ad2a
UPdating such that we query.
nharper285 Oct 5, 2023
20d219a
Merge branch 'main' into user/noharper/task-based-iterations
nharper285 Oct 5, 2023
95566fb
Merge branch 'main' into user/noharper/task-based-iterations
nharper285 Oct 9, 2023
a6bb6d1
attempting to try update.
nharper285 Oct 9, 2023
52505a3
Merge branch 'user/noharper/task-based-iterations' of https://github.…
nharper285 Oct 9, 2023
19adb42
Trying different update mechanism.
nharper285 Oct 9, 2023
55915ac
Merge branch 'main' into user/noharper/task-based-iterations
nharper285 Oct 9, 2023
0163d3c
Merge branch 'main' into user/noharper/task-based-iterations
nharper285 Oct 9, 2023
e19c99f
Checking previous value.
nharper285 Oct 10, 2023
ab8d96d
giMerge branch 'user/noharper/task-based-iterations' of https://githu…
nharper285 Oct 10, 2023
49cc61d
Merge branch 'main' into user/noharper/task-based-iterations
nharper285 Oct 10, 2023
ffde6cd
cleanup.
nharper285 Oct 10, 2023
ac4405a
Merge branch 'user/noharper/task-based-iterations' of https://github.…
nharper285 Oct 10, 2023
5415864
Removing old model.
nharper285 Oct 10, 2023
2537295
Case guard for better readability.
nharper285 Oct 10, 2023
469e4ee
Fix import ordering.
nharper285 Oct 10, 2023
1253ba8
Removing duplicate code.
nharper285 Oct 10, 2023
2bff2aa
accidentally didn't include update.
nharper285 Oct 10, 2023
3241f8a
Constructing the wrong way.
nharper285 Oct 11, 2023
713b83d
Moving back to standard switch.
nharper285 Oct 11, 2023
4f8b428
Merge branch 'main' into user/noharper/task-based-iterations
nharper285 Oct 11, 2023
64aaefe
Removing old code.
nharper285 Oct 11, 2023
58bce28
gitMerge branch 'user/noharper/task-based-iterations' of https://gith…
nharper285 Oct 11, 2023
7c4c41a
Removing more old code.
nharper285 Oct 11, 2023
8f55702
Using constants.
nharper285 Oct 11, 2023
6ada755
Merge branch 'main' into user/noharper/task-based-iterations
nharper285 Oct 12, 2023
af27dd2
Merge branch 'main' into user/noharper/task-based-iterations
nharper285 Oct 12, 2023
d9b85cc
Addressing comments.
nharper285 Oct 13, 2023
42b8fc8
Merge branch 'user/noharper/task-based-iterations' of https://github.…
nharper285 Oct 13, 2023
b7d94a7
Corrected.
nharper285 Oct 13, 2023
ba71418
Updating.
nharper285 Oct 13, 2023
ec29522
Comment.
nharper285 Oct 16, 2023
773765e
Replacing with Update to deal with edge cases.
nharper285 Oct 16, 2023
6077e64
Using timestamp.
nharper285 Oct 17, 2023
44ec109
Adding CreatedAt field.
nharper285 Oct 17, 2023
09bc214
Comparing timestamps.
nharper285 Oct 17, 2023
00fdd2d
Merge branch 'main' into user/noharper/task-based-iterations
nharper285 Oct 17, 2023
85b88a1
Setting propery.
nharper285 Oct 17, 2023
813e702
Merge branch 'user/noharper/task-based-iterations' of https://github.…
nharper285 Oct 17, 2023
b7bccfa
Merge branch 'main' into user/noharper/task-based-iterations
nharper285 Oct 18, 2023
c45bcd4
Merge branch 'main' into user/noharper/task-based-iterations
nharper285 Oct 18, 2023
5983596
Merge branch 'main' into user/noharper/task-based-iterations
nharper285 Oct 24, 2023
ba2be61
Adding check for CreatedAt.
nharper285 Oct 24, 2023
4e9dfb8
Merge branch 'user/noharper/task-based-iterations' of https://github.…
nharper285 Oct 24, 2023
52c1156
Making created_at optional.
nharper285 Oct 24, 2023
42d30f7
Trying again.
nharper285 Oct 24, 2023
ad83ea5
Merge branch 'main' into user/noharper/task-based-iterations
nharper285 Oct 24, 2023
7109c62
Merge branch 'main' into user/noharper/task-based-iterations
nharper285 Oct 24, 2023
50ef2f8
Remove.
nharper285 Oct 25, 2023
c9859e8
Add log statement.
nharper285 Oct 25, 2023
53c5c32
Remove function handle.:
nharper285 Oct 25, 2023
9b5c40f
Updating
nharper285 Oct 25, 2023
a3537ba
Concat names
nharper285 Oct 25, 2023
4d5c87d
Set version.
nharper285 Oct 25, 2023
99818f9
Merge branch 'main' into user/noharper/task-based-iterations
nharper285 Oct 26, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/ApiService/ApiService/Functions/QueueJobResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public async Async.Task Run([QueueTrigger("job-result", Connection = "AzureWebJo
return;
}

var jobResult = await _context.JobResultOperations.CreateOrUpdate(job.JobId, jobResultType, value);
var jobResult = await _context.JobResultOperations.CreateOrUpdate(job.JobId, jr.TaskId, jr.MachineId, jr.CreatedAt, jobResultType, value);
if (!jobResult.IsOk) {
_log.LogError("failed to create or update with job result {JobId}", job.JobId);
}
Expand Down
47 changes: 16 additions & 31 deletions src/ApiService/ApiService/OneFuzzTypes/Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,6 @@ public enum HeartbeatType {
TaskAlive,
}

[SkipRename]
public enum JobResultType {
NewCrashingInput,
NoReproCrashingInput,
NewReport,
NewUniqueReport,
NewRegressionReport,
NewCoverage,
NewCrashDump,
CoverageData,
RuntimeStats,
}

public record HeartbeatData(HeartbeatType Type);

public record TaskHeartbeatEntry(
Expand All @@ -54,12 +41,13 @@ public record TaskHeartbeatEntry(
Guid MachineId,
HeartbeatData[] Data);

public record JobResultData(JobResultType Type);
public record JobResultData(string Type);

public record TaskJobResultEntry(
Guid TaskId,
Guid? JobId,
Guid MachineId,
DateTime CreatedAt,
JobResultData Data,
Dictionary<string, double> Value
);
Expand Down Expand Up @@ -918,26 +906,23 @@ public record SecretAddress<T>(Uri Url) : ISecret<T> {
public record SecretData<T>(ISecret<T> Secret) {
}

[SkipRename]
public enum JobResultType {
CoverageData,
RuntimeStats,
}

public record JobResult(
nharper285 marked this conversation as resolved.
Show resolved Hide resolved
[PartitionKey][RowKey] Guid JobId,
stishkin marked this conversation as resolved.
Show resolved Hide resolved
[PartitionKey] Guid JobId,
[RowKey] string TaskIdMachineIdMetric,
Guid TaskId,
Guid MachineId,
DateTime CreatedAt,
string Project,
string Name,
double NewCrashingInput = 0,
double NoReproCrashingInput = 0,
double NewReport = 0,
double NewUniqueReport = 0,
double NewRegressionReport = 0,
double NewCrashDump = 0,
double InstructionsCovered = 0,
double TotalInstructions = 0,
double CoverageRate = 0,
double IterationCount = 0
) : EntityBase() {
public JobResult(Guid JobId, string Project, string Name) : this(
JobId: JobId,
Project: Project,
Name: Name, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) { }
}
string Type,
Dictionary<string, double> MetricValue
) : EntityBase();

public record JobConfig(
string Project,
Expand Down
118 changes: 49 additions & 69 deletions src/ApiService/ApiService/onefuzzlib/JobResultOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,99 +2,79 @@
using Microsoft.Extensions.Logging;
using Polly;
namespace Microsoft.OneFuzz.Service;
using System.Net;

public interface IJobResultOperations : IOrm<JobResult> {

Async.Task<JobResult?> GetJobResult(Guid jobId);
Async.Task<OneFuzzResultVoid> CreateOrUpdate(Guid jobId, JobResultType resultType, Dictionary<string, double> resultValue);
Async.Task<JobResult?> GetJobResult(Guid jobId, Guid taskId, Guid machineId, string metricType);
stishkin marked this conversation as resolved.
Show resolved Hide resolved
Async.Task<JobResult?> GetJobResults(Guid jobId);
Async.Task<OneFuzzResultVoid> CreateOrUpdate(Guid jobId, Guid taskId, Guid machineId, DateTime createdAt, string resultType, Dictionary<string, double> resultValue);

}
public class JobResultOperations : Orm<JobResult>, IJobResultOperations {

const string COVERAGE_DATA = "CoverageData";
const string RUNTIME_STATS = "RuntimeStats";

public JobResultOperations(ILogger<JobResultOperations> log, IOnefuzzContext context)
: base(log, context) {
}

public async Async.Task<JobResult?> GetJobResult(Guid jobId) {
return await SearchByPartitionKeys(new[] { jobId.ToString() }).SingleOrDefaultAsync();
public async Async.Task<JobResult?> GetJobResult(Guid jobId, Guid taskId, Guid machineId, string metricType) {
var data = QueryAsync(Query.SingleEntity(jobId.ToString(), string.Concat(taskId, machineId, metricType)));
nharper285 marked this conversation as resolved.
Show resolved Hide resolved
return await data.FirstOrDefaultAsync();
}

private JobResult UpdateResult(JobResult result, JobResultType type, Dictionary<string, double> resultValue) {

var newResult = result;
double newValue;
switch (type) {
case JobResultType.NewCrashingInput:
newValue = result.NewCrashingInput + resultValue["count"];
newResult = result with { NewCrashingInput = newValue };
break;
case JobResultType.NewReport:
newValue = result.NewReport + resultValue["count"];
newResult = result with { NewReport = newValue };
break;
case JobResultType.NewUniqueReport:
newValue = result.NewUniqueReport + resultValue["count"];
newResult = result with { NewUniqueReport = newValue };
break;
case JobResultType.NewRegressionReport:
newValue = result.NewRegressionReport + resultValue["count"];
newResult = result with { NewRegressionReport = newValue };
break;
case JobResultType.NewCrashDump:
newValue = result.NewCrashDump + resultValue["count"];
newResult = result with { NewCrashDump = newValue };
break;
case JobResultType.CoverageData:
double newCovered = resultValue["covered"];
double newTotalCovered = resultValue["features"];
double newCoverageRate = resultValue["rate"];
newResult = result with { InstructionsCovered = newCovered, TotalInstructions = newTotalCovered, CoverageRate = newCoverageRate };
break;
case JobResultType.RuntimeStats:
double newTotalIterations = resultValue["total_count"];
newResult = result with { IterationCount = newTotalIterations };
break;
default:
_logTracer.LogWarning($"Invalid Field {type}.");
break;
}
_logTracer.LogInformation($"Attempting to log new result: {newResult}");
return newResult;
public async Async.Task<JobResult?> GetJobResults(Guid jobId) {
var data = QueryAsync(Query.PartitionKey(jobId.ToString()));
return await data.FirstOrDefaultAsync();
nharper285 marked this conversation as resolved.
Show resolved Hide resolved
}

private async Async.Task<bool> TryUpdate(Job job, JobResultType resultType, Dictionary<string, double> resultValue) {
private async Async.Task<bool> TryUpdate(Job job, Guid taskId, Guid machineId, DateTime createdAt, string resultType, Dictionary<string, double> resultValue) {
var jobId = job.JobId;
var taskIdMachineIdMetric = string.Concat(taskId, machineId, resultType);
nharper285 marked this conversation as resolved.
Show resolved Hide resolved

var jobResult = await GetJobResult(jobId);
var oldEntry = await GetJobResult(jobId, taskId, machineId, resultType);
stishkin marked this conversation as resolved.
Show resolved Hide resolved

if (jobResult == null) {
_logTracer.LogInformation("Creating new JobResult for Job {JobId}", jobId);

var entry = new JobResult(JobId: jobId, Project: job.Config.Project, Name: job.Config.Name);

jobResult = UpdateResult(entry, resultType, resultValue);

var r = await Insert(jobResult);
if (!r.IsOk) {
throw new InvalidOperationException($"failed to insert job result {jobResult.JobId}");
if (oldEntry == null) {
_logTracer.LogInformation($"attempt to insert new job result {taskId} and taskId+machineId+metricType {taskIdMachineIdMetric}");
var newEntry = new JobResult(JobId: jobId, TaskIdMachineIdMetric: taskIdMachineIdMetric, TaskId: taskId, MachineId: machineId, CreatedAt: createdAt, Project: job.Config.Project, Name: job.Config.Name, resultType, resultValue);
var result = await Insert(newEntry);
if (!result.IsOk) {
throw new InvalidOperationException($"failed to insert job result with taskId {taskId} and taskId+machineId+metricType {taskIdMachineIdMetric}");
}
_logTracer.LogInformation("created job result {JobId}", jobResult.JobId);
} else {
_logTracer.LogInformation("Updating existing JobResult entry for Job {JobId}", jobId);

jobResult = UpdateResult(jobResult, resultType, resultValue);
return true;
}

var r = await Update(jobResult);
if (!r.IsOk) {
throw new InvalidOperationException($"failed to insert job result {jobResult.JobId}");
}
_logTracer.LogInformation("updated job result {JobId}", jobResult.JobId);
ResultVoid<(HttpStatusCode Status, string Reason)> r;
switch (resultType) {
case COVERAGE_DATA:
case RUNTIME_STATS:
if (oldEntry.CreatedAt < createdAt) {
oldEntry = oldEntry with { MetricValue = resultValue };
nharper285 marked this conversation as resolved.
Show resolved Hide resolved
r = await Update(oldEntry);
if (!r.IsOk) {
throw new InvalidOperationException($"failed to replace job result with taskId {taskId} and machineId+metricType {taskIdMachineIdMetric}");
}
}
nharper285 marked this conversation as resolved.
Show resolved Hide resolved
break;
default:
_logTracer.LogInformation($"attempt to update job result {taskId} and taskId+machineId+metricType {taskIdMachineIdMetric}");
oldEntry.MetricValue["count"]++;
oldEntry = oldEntry with { MetricValue = oldEntry.MetricValue };
r = await Update(oldEntry);
if (!r.IsOk) {
throw new InvalidOperationException($"failed to update job result with taskId {taskId} and machineId+metricType {taskIdMachineIdMetric}");
}
break;
}


return true;

}

public async Async.Task<OneFuzzResultVoid> CreateOrUpdate(Guid jobId, JobResultType resultType, Dictionary<string, double> resultValue) {
public async Async.Task<OneFuzzResultVoid> CreateOrUpdate(Guid jobId, Guid taskId, Guid machineId, DateTime createdAt, string resultType, Dictionary<string, double> resultValue) {

var job = await _context.JobOperations.Get(jobId);
if (job == null) {
Expand All @@ -106,7 +86,7 @@ public async Async.Task<OneFuzzResultVoid> CreateOrUpdate(Guid jobId, JobResultT
_logTracer.LogInformation("attempt to update job result {JobId}", job.JobId);
var policy = Policy.Handle<InvalidOperationException>().WaitAndRetryAsync(50, _ => new TimeSpan(0, 0, 5));
await policy.ExecuteAsync(async () => {
success = await TryUpdate(job, resultType, resultValue);
success = await TryUpdate(job, taskId, machineId, createdAt, resultType, resultValue);
_logTracer.LogInformation("attempt {success}", success);
});
return OneFuzzResultVoid.Ok;
Expand Down
2 changes: 2 additions & 0 deletions src/agent/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion src/agent/onefuzz-result/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ license = "MIT"
[dependencies]
anyhow = { version = "1.0", features = ["backtrace"] }
async-trait = "0.1"
chrono = { version = "0.4", default-features = false, features = [
"clock",
"std",
"serde"
] }
reqwest = "0.11"
serde = "1.0"
storage-queue = { path = "../storage-queue" }
uuid = { version = "1.4", features = ["serde", "v4"] }
onefuzz-telemetry = { path = "../onefuzz-telemetry" }
log = "0.4"

6 changes: 5 additions & 1 deletion src/agent/onefuzz-result/src/job_result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

use anyhow::Result;
use async_trait::async_trait;
use chrono::DateTime;
pub use chrono::Utc;
use onefuzz_telemetry::warn;
use reqwest::Url;
use serde::{self, Deserialize, Serialize};
Expand Down Expand Up @@ -32,6 +34,7 @@ struct JobResult {
job_id: Uuid,
machine_id: Uuid,
machine_name: String,
created_at: DateTime<Utc>,
data: JobResultData,
value: HashMap<String, f64>,
}
Expand Down Expand Up @@ -103,7 +106,7 @@ impl JobResultSender for TaskJobResultClient {
let job_id = self.context.state.job_id;
let machine_id = self.context.state.machine_id;
let machine_name = self.context.state.machine_name.clone();

let created_at = chrono::Utc::now();
let _ = self
.context
.queue_client
Expand All @@ -112,6 +115,7 @@ impl JobResultSender for TaskJobResultClient {
job_id,
machine_id,
machine_name,
created_at,
data,
value,
})
Expand Down
Loading