Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ ARG VARIANT="ubuntu-22.04"
FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT}

# note: keep this in sync with .github/workflows/ci.yml
ARG RUSTVERSION="1.68"
ARG RUSTVERSION="1.69"

# Needed for dotnet7; remove when available in Ubuntu
RUN wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb \
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,8 @@ jobs:
- uses: actions/checkout@v3
- name: Install specific Rust version
uses: dtolnay/rust-toolchain@55c7845fad90d0ae8b2e83715cb900e5e861e8cb # pinned latest master as of 2022-10-08
# note: keep this in sync with .devcontainer/Dockerfile
with:
toolchain: 1.68
toolchain: 1.69 # note: keep this in sync with .devcontainer/Dockerfile
components: clippy, rustfmt, llvm-tools-preview
- name: Setup Rust problem-matchers
uses: r7kamura/rust-problem-matchers@d58b70c4a13c4866d96436315da451d8106f8f08 # pinned to 1.3.0
Expand Down
4 changes: 4 additions & 0 deletions src/ApiService/ApiService/Functions/AgentEvents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ private async Async.Task<HttpResponseData> Post(HttpRequestData req) {
}

if (ev.State == NodeState.Free) {
if (!node.Managed) {
return null;
}

if (node.ReimageRequested || node.DeleteRequested) {
_log.Info($"stopping free node with reset flags: {machineId:Tag:MachineId}");
// discard result: node not used after this point
Expand Down
39 changes: 38 additions & 1 deletion src/ApiService/ApiService/Functions/Pool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ public Pool(ILogTracer log, IEndpointAuthorization auth, IOnefuzzContext context
}

[Function("Pool")]
public Async.Task<HttpResponseData> Run([HttpTrigger(AuthorizationLevel.Anonymous, "GET", "POST", "DELETE")] HttpRequestData req)
public Async.Task<HttpResponseData> Run([HttpTrigger(AuthorizationLevel.Anonymous, "GET", "POST", "DELETE", "PATCH")] HttpRequestData req)
=> _auth.CallIfUser(req, r => r.Method switch {
"GET" => Get(r),
"POST" => Post(r),
"DELETE" => Delete(r),
"PATCH" => Patch(r),
var m => throw new InvalidOperationException("Unsupported HTTP method {m}"),
});

Expand Down Expand Up @@ -71,6 +72,42 @@ private async Task<HttpResponseData> Post(HttpRequestData req) {
return await RequestHandling.Ok(req, await Populate(PoolToPoolResponse(newPool), true));
}


private async Task<HttpResponseData> Patch(HttpRequestData req) {
var request = await RequestHandling.ParseRequest<PoolUpdate>(req);
if (!request.IsOk) {
return await _context.RequestHandling.NotOk(req, request.ErrorV, "PoolUpdate");
}

var answer = await _auth.CheckRequireAdmins(req);
if (!answer.IsOk) {
return await _context.RequestHandling.NotOk(req, answer.ErrorV, "PoolUpdate");
}

var update = request.OkV;
var pool = await _context.PoolOperations.GetByName(update.Name);
if (!pool.IsOk) {
return await _context.RequestHandling.NotOk(
req,
new Error(
Code: ErrorCode.INVALID_REQUEST,
Errors: new string[] { "pool with that name does not exist" }),
"PoolUpdate");
}

var updated = pool.OkV with { ObjectId = update.ObjectId };
var updatePool = await _context.PoolOperations.Update(updated);
if (updatePool.IsOk) {
return await RequestHandling.Ok(req, await Populate(PoolToPoolResponse(updated), true));
} else {
return await _context.RequestHandling.NotOk(req, new Error(
Code: ErrorCode.INVALID_REQUEST,
Errors: new string[] { updatePool.ErrorV.Reason }), "PoolUpdate");
}


}

private async Task<HttpResponseData> Get(HttpRequestData req) {
var request = await RequestHandling.ParseRequest<PoolSearch>(req);
if (!request.IsOk) {
Expand Down
4 changes: 4 additions & 0 deletions src/ApiService/ApiService/OneFuzzTypes/Enums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ public enum ErrorCode {
UNABLE_TO_DOWNLOAD_FILE = 475,
VM_UPDATE_FAILED = 476,
UNSUPPORTED_FIELD_OPERATION = 477,
ADO_VALIDATION_INVALID_PAT = 478,
ADO_VALIDATION_INVALID_FIELDS = 479,
GITHUB_VALIDATION_INVALID_PAT = 480,
GITHUB_VALIDATION_INVALID_REPOSITORY = 481,
}

public enum VmState {
Expand Down
7 changes: 7 additions & 0 deletions src/ApiService/ApiService/OneFuzzTypes/Requests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,13 @@ public record PoolCreate(
[property: Required] Os Os,
[property: Required] Architecture Arch,
[property: Required] bool Managed,
Guid? ObjectId = null,
bool Update = false
) : BaseRequest;


public record PoolUpdate(
[property: Required] PoolName Name,
Guid? ObjectId = null
) : BaseRequest;

Expand Down
7 changes: 4 additions & 3 deletions src/ApiService/ApiService/onefuzzlib/NodeOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -195,12 +195,12 @@ public async Task<CanProcessNewWorkResponse> CanProcessNewWork(Node node) {
return CanProcessNewWorkResponse.NotAllowed("node is set to be deleted");
}

if (node.ReimageRequested) {
if (node.ReimageRequested && node.Managed) {
_ = await Stop(node, done: true);
return CanProcessNewWorkResponse.NotAllowed("node is set to be reimaged");
}

if (await CouldShrinkScaleset(node)) {
if (await CouldShrinkScaleset(node) && node.Managed) {
_ = await SetHalt(node);
return CanProcessNewWorkResponse.NotAllowed("node is scheduled to shrink");
}
Expand Down Expand Up @@ -488,7 +488,8 @@ public bool IsOutdated(Node node) {
}

public bool IsTooOld(Node node) {
return node.ScalesetId != null
return node.Managed
&& node.ScalesetId != null
&& node.InitializedAt != null
&& node.InitializedAt < DateTime.UtcNow - INodeOperations.NODE_REIMAGE_TIME;
}
Expand Down
8 changes: 4 additions & 4 deletions src/ApiService/ApiService/onefuzzlib/notifications/Ado.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ public static async Async.Task<OneFuzzResultVoid> Validate(AdoTemplate config) {
connection = new VssConnection(config.BaseUrl, new VssBasicCredential(string.Empty, token.Value));
await connection.ConnectAsync();
} catch {
return OneFuzzResultVoid.Error(ErrorCode.INVALID_CONFIGURATION, $"Failed to connect to {config.BaseUrl} using the provided token");
return OneFuzzResultVoid.Error(ErrorCode.ADO_VALIDATION_INVALID_PAT, $"Failed to connect to {config.BaseUrl} using the provided token");
}
} else {
return OneFuzzResultVoid.Error(ErrorCode.INVALID_CONFIGURATION, "Auth token is missing or invalid");
return OneFuzzResultVoid.Error(ErrorCode.ADO_VALIDATION_INVALID_PAT, "Auth token is missing or invalid");
}

try {
Expand All @@ -91,15 +91,15 @@ public static async Async.Task<OneFuzzResultVoid> Validate(AdoTemplate config) {

if (!validConfigFields.SetEquals(configFields)) {
var invalidFields = configFields.Except(validConfigFields);
return OneFuzzResultVoid.Error(ErrorCode.INVALID_CONFIGURATION, new[]
return OneFuzzResultVoid.Error(ErrorCode.ADO_VALIDATION_INVALID_FIELDS, new[]
{
$"The following unique fields are not valid fields for this project: {string.Join(',', invalidFields)}",
"You can find the valid fields for your project by following these steps: https://learn.microsoft.com/en-us/azure/devops/boards/work-items/work-item-fields?view=azure-devops#review-fields"
}
);
}
} catch {
return OneFuzzResultVoid.Error(ErrorCode.INVALID_CONFIGURATION, "Failed to query and compare the valid fields for this project");
return OneFuzzResultVoid.Error(ErrorCode.ADO_VALIDATION_INVALID_FIELDS, "Failed to query and compare the valid fields for this project");
}

return OneFuzzResultVoid.Ok;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,16 @@ public static async Async.Task<OneFuzzResultVoid> Validate(GithubIssuesTemplate
gh = GetGitHubClient(auth.Value.User, auth.Value.PersonalAccessToken);
var _ = await gh.User.Get(auth.Value.User);
} catch {
return OneFuzzResultVoid.Error(ErrorCode.INVALID_CONFIGURATION, $"Failed to login to github.com with user {auth.Value.User} and the provided Personal Access Token");
return OneFuzzResultVoid.Error(ErrorCode.GITHUB_VALIDATION_INVALID_PAT, $"Failed to login to github.com with user {auth.Value.User} and the provided Personal Access Token");
}
} else {
return OneFuzzResultVoid.Error(ErrorCode.INVALID_CONFIGURATION, $"GithubAuth is missing or invalid");
return OneFuzzResultVoid.Error(ErrorCode.GITHUB_VALIDATION_INVALID_PAT, $"GithubAuth is missing or invalid");
}

try {
var _ = await gh.Repository.Get(config.Organization, config.Repository);
} catch {
return OneFuzzResultVoid.Error(ErrorCode.INVALID_CONFIGURATION, $"Failed to access repository: {config.Organization}/{config.Repository}");
return OneFuzzResultVoid.Error(ErrorCode.GITHUB_VALIDATION_INVALID_REPOSITORY, $"Failed to access repository: {config.Organization}/{config.Repository}");
}

return OneFuzzResultVoid.Ok;
Expand Down
66 changes: 24 additions & 42 deletions src/agent/Cargo.lock

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

18 changes: 18 additions & 0 deletions src/cli/onefuzz/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1297,6 +1297,24 @@ def create(
),
)

def update(
self,
name: str,
object_id: Optional[UUID] = None,
) -> models.Pool:
"""
Update a worker pool

:param str name: Name of the worker-pool
"""
self.logger.debug("create worker pool")

return self._req_model(
"PATCH",
models.Pool,
data=requests.PoolUpdate(name=name, object_id=object_id),
)

def get_config(self, pool_name: primitives.PoolName) -> models.AgentConfig:
"""Get the agent configuration for the pool"""

Expand Down
1 change: 1 addition & 0 deletions src/pytypes/onefuzztypes/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,7 @@ class Pool(BaseModel):
# intended to be used to pass the information to the CLI when the CLI asks
# for information about what work is in the queue for the pool.
work_queue: Optional[List[WorkSetSummary]]
object_id: Optional[UUID]

# explicitly excluded from Tables
scaleset_summary: Optional[List[ScalesetSummary]]
Expand Down
5 changes: 5 additions & 0 deletions src/pytypes/onefuzztypes/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ class PoolCreate(BaseRequest):
autoscale: Optional[AutoScaleConfig]


class PoolUpdate(BaseRequest):
name: PoolName
object_id: Optional[UUID]


class PoolSearch(BaseRequest):
pool_id: Optional[UUID]
name: Optional[PoolName]
Expand Down