You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
317 lines
11 KiB
C#
317 lines
11 KiB
C#
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
using HordeServer.Api;
|
|
using HordeServer.Models;
|
|
using HordeServer.Services;
|
|
using HordeServer.Utilities;
|
|
using Microsoft.AspNetCore.Authentication;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|
using Microsoft.Extensions.Options;
|
|
using Microsoft.IdentityModel.Tokens;
|
|
using MongoDB.Bson;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel.DataAnnotations;
|
|
using System.IdentityModel.Tokens.Jwt;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Security.Claims;
|
|
using System.Text.Json;
|
|
using System.Threading.Tasks;
|
|
|
|
using PoolId = HordeServer.Utilities.StringId<HordeServer.Models.IPool>;
|
|
using AgentSoftwareChannelName = HordeServer.Utilities.StringId<HordeServer.Services.AgentSoftwareChannels>;
|
|
|
|
namespace HordeServer.Controllers
|
|
{
|
|
/// <summary>
|
|
/// Controller for the /api/v1/agents endpoint
|
|
/// </summary>
|
|
[ApiController]
|
|
[Authorize]
|
|
[Route("[controller]")]
|
|
public class AgentsController : ControllerBase
|
|
{
|
|
/// <summary>
|
|
/// Singleton instance of the ACL service
|
|
/// </summary>
|
|
AclService AclService;
|
|
|
|
/// <summary>
|
|
/// Singleton instance of the agent service
|
|
/// </summary>
|
|
AgentService AgentService;
|
|
|
|
/// <summary>
|
|
/// The pool service
|
|
/// </summary>
|
|
PoolService PoolService;
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
/// <param name="AclService">The ACL service singleton</param>
|
|
/// <param name="AgentService">The agent service</param>
|
|
/// <param name="PoolService">The pool service</param>
|
|
public AgentsController(AclService AclService, AgentService AgentService, PoolService PoolService)
|
|
{
|
|
this.AclService = AclService;
|
|
this.AgentService = AgentService;
|
|
this.PoolService = PoolService;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Register an agent to perform remote work.
|
|
/// </summary>
|
|
/// <param name="Request">Request parameters</param>
|
|
/// <returns>Information about the registered agent</returns>
|
|
[HttpPost]
|
|
[Route("/api/v1/agents")]
|
|
public async Task<ActionResult<CreateAgentResponse>> CreateAgentAsync([FromBody] CreateAgentRequest Request)
|
|
{
|
|
if(!await AclService.AuthorizeAsync(AclAction.CreateAgent, User))
|
|
{
|
|
return Forbid();
|
|
}
|
|
|
|
AgentSoftwareChannelName? Channel = String.IsNullOrEmpty(Request.Channel) ? (AgentSoftwareChannelName?)null : new AgentSoftwareChannelName(Request.Channel);
|
|
IAgent Agent = await AgentService.CreateAgentAsync(Request.Name, Request.Enabled, Request.Ephemeral, Channel, Request.Pools?.ConvertAll(x => new PoolId(x)));
|
|
|
|
return new CreateAgentResponse(Agent.Id.ToString());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finds the agents matching specified criteria.
|
|
/// </summary>
|
|
/// <param name="Pool">The pool containing the agent</param>
|
|
/// <param name="Index">First result to return</param>
|
|
/// <param name="Count">Number of results to return</param>
|
|
/// <param name="ModifiedAfter">If set, only returns agents modified after this time</param>
|
|
/// <param name="Filter">Filter for the properties to return</param>
|
|
/// <returns>List of matching agents</returns>
|
|
[HttpGet]
|
|
[Route("/api/v1/agents")]
|
|
[ProducesResponseType(typeof(List<GetAgentResponse>), 200)]
|
|
public async Task<ActionResult<List<object>>> FindAgentsAsync([FromQuery] string? Pool = null, [FromQuery] int? Index = null, [FromQuery] int? Count = null, [FromQuery] DateTimeOffset? ModifiedAfter = null, [FromQuery] PropertyFilter? Filter = null)
|
|
{
|
|
GlobalPermissionsCache PermissionsCache = new GlobalPermissionsCache();
|
|
List<IAgent> Agents = await AgentService.FindAgentsAsync(Pool?.ToObjectId(), ModifiedAfter?.UtcDateTime, Index, Count);
|
|
List<IPool> Pools = await PoolService.GetPoolsAsync();
|
|
|
|
List<object> Responses = new List<object>();
|
|
foreach (IAgent Agent in Agents)
|
|
{
|
|
bool bIncludeAcl = await AgentService.AuthorizeAsync(Agent, AclAction.ViewPermissions, User, PermissionsCache);
|
|
List<PoolId> PoolIds = Agent.GetPools(Pools).Select(x => x.Id).ToList();
|
|
Responses.Add(new GetAgentResponse(Agent, PoolIds, bIncludeAcl).ApplyFilter(Filter));
|
|
}
|
|
|
|
return Responses;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieve information about a specific agent
|
|
/// </summary>
|
|
/// <param name="AgentId">Id of the agent to get information about</param>
|
|
/// <param name="Filter">Filter for the properties to return</param>
|
|
/// <returns>Information about the requested agent</returns>
|
|
[HttpGet]
|
|
[Route("/api/v1/agents/{AgentId}")]
|
|
[ProducesResponseType(typeof(GetAgentResponse), 200)]
|
|
public async Task<ActionResult<object>> GetAgentAsync(string AgentId, [FromQuery] PropertyFilter? Filter = null)
|
|
{
|
|
IAgent? Agent = await AgentService.GetAgentAsync(new AgentId(AgentId));
|
|
if (Agent == null)
|
|
{
|
|
return NotFound();
|
|
}
|
|
|
|
List<IPool> Pools = await PoolService.GetPoolsAsync();
|
|
|
|
GlobalPermissionsCache Cache = new GlobalPermissionsCache();
|
|
bool bIncludeAcl = await AgentService.AuthorizeAsync(Agent, AclAction.ViewPermissions, User, Cache);
|
|
List<PoolId> PoolIds = Agent.GetPools(Pools).Select(x => x.Id).ToList();
|
|
return new GetAgentResponse(Agent, PoolIds, bIncludeAcl).ApplyFilter(Filter);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update an agent's properties.
|
|
/// </summary>
|
|
/// <param name="AgentId">Id of the agent to update.</param>
|
|
/// <param name="Update">Properties on the agent to update.</param>
|
|
/// <returns>Http result code</returns>
|
|
[HttpPut]
|
|
[Route("/api/v1/agents/{AgentId}")]
|
|
public async Task<ActionResult> UpdateAgentAsync(string AgentId, [FromBody] UpdateAgentRequest Update)
|
|
{
|
|
IAgent? Agent = await AgentService.GetAgentAsync(new AgentId(AgentId));
|
|
if (Agent == null)
|
|
{
|
|
return NotFound();
|
|
}
|
|
|
|
GlobalPermissionsCache Cache = new GlobalPermissionsCache();
|
|
if (!await AgentService.AuthorizeAsync(Agent, AclAction.UpdateAgent, User, Cache))
|
|
{
|
|
return Forbid();
|
|
}
|
|
if (Update.Acl != null && !await AgentService.AuthorizeAsync(Agent, AclAction.ChangePermissions, User, Cache))
|
|
{
|
|
return Forbid();
|
|
}
|
|
|
|
AgentSoftwareChannelName? Channel = String.IsNullOrEmpty(Update.Channel) ? (AgentSoftwareChannelName?)null : new AgentSoftwareChannelName(Update.Channel);
|
|
await AgentService.UpdateAgentAsync(Agent, Update.Enabled, Update.RequestConform, Update.RequestRestart, Update.RequestShutdown, Channel, Update.Pools?.ConvertAll(x => new PoolId(x)), Acl.Merge(Agent.Acl, Update.Acl), Update.Comment);
|
|
return Ok();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove a registered agent.
|
|
/// </summary>
|
|
/// <param name="AgentId">Id of the agent to delete.</param>
|
|
/// <returns>Http result code</returns>
|
|
[HttpDelete]
|
|
[Route("/api/v1/agents/{AgentId}")]
|
|
public async Task<ActionResult> DeleteAgentAsync(string AgentId)
|
|
{
|
|
IAgent? Agent = await AgentService.GetAgentAsync(new AgentId(AgentId));
|
|
if (Agent == null)
|
|
{
|
|
return NotFound();
|
|
}
|
|
if (!await AgentService.AuthorizeAsync(Agent, AclAction.DeleteAgent, User, null))
|
|
{
|
|
return Forbid();
|
|
}
|
|
|
|
await AgentService.DeleteAgentAsync(Agent);
|
|
return new OkResult();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Find all the sessions of a particular agent
|
|
/// </summary>
|
|
/// <param name="AgentId">Unique id of the agent to find</param>
|
|
/// <param name="StartTime">Start time to include in the search</param>
|
|
/// <param name="FinishTime">Finish time to include in the search</param>
|
|
/// <param name="Index">Index of the first result to return</param>
|
|
/// <param name="Count">Number of results to return</param>
|
|
/// <returns>Sessions </returns>
|
|
[HttpGet]
|
|
[Route("/api/v1/agents/{AgentId}/sessions")]
|
|
public async Task<ActionResult<List<GetAgentSessionResponse>>> FindSessionsAsync(string AgentId, [FromQuery] DateTimeOffset? StartTime, [FromQuery] DateTimeOffset? FinishTime, [FromQuery] int Index = 0, [FromQuery] int Count = 50)
|
|
{
|
|
AgentId AgentIdValue = new AgentId(AgentId);
|
|
|
|
IAgent? Agent = await AgentService.GetAgentAsync(AgentIdValue);
|
|
if (Agent == null)
|
|
{
|
|
return NotFound();
|
|
}
|
|
if (!await AgentService.AuthorizeAsync(Agent, AclAction.ViewSession, User, null))
|
|
{
|
|
return Forbid();
|
|
}
|
|
|
|
List<ISession> Sessions = await AgentService.FindSessionsAsync(AgentIdValue, StartTime?.UtcDateTime, FinishTime?.UtcDateTime, Index, Count);
|
|
return Sessions.ConvertAll(x => new GetAgentSessionResponse(x));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Find all the sessions of a particular agent
|
|
/// </summary>
|
|
/// <param name="AgentId">Unique id of the agent to find</param>
|
|
/// <param name="SessionId">Unique id of the session</param>
|
|
/// <returns>Sessions </returns>
|
|
[HttpGet]
|
|
[Route("/api/v1/agents/{AgentId}/sessions/{SessionId}")]
|
|
public async Task<ActionResult<GetAgentSessionResponse>> GetSessionAsync(string AgentId, string SessionId)
|
|
{
|
|
AgentId AgentIdValue = new AgentId(AgentId);
|
|
|
|
IAgent? Agent = await AgentService.GetAgentAsync(AgentIdValue);
|
|
if (Agent == null)
|
|
{
|
|
return NotFound();
|
|
}
|
|
if (!await AgentService.AuthorizeAsync(Agent, AclAction.ViewSession, User, null))
|
|
{
|
|
return Forbid();
|
|
}
|
|
|
|
ISession? Session = await AgentService.GetSessionAsync(SessionId.ToObjectId());
|
|
if(Session == null || Session.AgentId != AgentIdValue)
|
|
{
|
|
return NotFound();
|
|
}
|
|
|
|
return new GetAgentSessionResponse(Session);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Find all the leases for a particular agent
|
|
/// </summary>
|
|
/// <param name="AgentId">Unique id of the agent to find</param>
|
|
/// <param name="SessionId">The session to query</param>
|
|
/// <param name="StartTime">Start of the time window to consider</param>
|
|
/// <param name="FinishTime">End of the time window to consider</param>
|
|
/// <param name="Index">Index of the first result to return</param>
|
|
/// <param name="Count">Number of results to return</param>
|
|
/// <returns>Sessions </returns>
|
|
[HttpGet]
|
|
[Route("/api/v1/agents/{AgentId}/leases")]
|
|
public async Task<ActionResult<List<GetAgentLeaseResponse>>> FindLeasesAsync(string AgentId, [FromQuery] string? SessionId, [FromQuery] DateTimeOffset? StartTime, [FromQuery] DateTimeOffset? FinishTime, [FromQuery] int Index = 0, [FromQuery] int Count = 1000)
|
|
{
|
|
AgentId AgentIdValue = new AgentId(AgentId);
|
|
|
|
IAgent? Agent = await AgentService.GetAgentAsync(AgentIdValue);
|
|
if (Agent == null)
|
|
{
|
|
return NotFound();
|
|
}
|
|
if (!await AgentService.AuthorizeAsync(Agent, AclAction.ViewLeases, User, null))
|
|
{
|
|
return Forbid();
|
|
}
|
|
|
|
List<ILease> Leases = await AgentService.FindLeasesAsync(AgentIdValue, SessionId?.ToObjectId(), StartTime?.UtcDateTime, FinishTime?.UtcDateTime, Index, Count);
|
|
return Leases.ConvertAll(x => new GetAgentLeaseResponse(x));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get info about a particular lease
|
|
/// </summary>
|
|
/// <param name="AgentId">Unique id of the agent to find</param>
|
|
/// <param name="LeaseId">Unique id of the particular lease</param>
|
|
/// <returns>Lease matching the given id</returns>
|
|
[HttpGet]
|
|
[Route("/api/v1/agents/{AgentId}/leases/{LeaseId}")]
|
|
public async Task<ActionResult<GetAgentLeaseResponse>> GetLeaseAsync(string AgentId, string LeaseId)
|
|
{
|
|
AgentId AgentIdValue = new AgentId(AgentId);
|
|
|
|
IAgent? Agent = await AgentService.GetAgentAsync(AgentIdValue);
|
|
if(Agent == null)
|
|
{
|
|
return NotFound();
|
|
}
|
|
if (!await AclService.AuthorizeAsync(AclAction.ViewLeases, User))
|
|
{
|
|
return Forbid();
|
|
}
|
|
|
|
ObjectId LeaseIdValue = LeaseId.ToObjectId();
|
|
|
|
ILease? Lease = await AgentService.GetLeaseAsync(LeaseIdValue);
|
|
if (Lease == null || Lease.AgentId != AgentIdValue)
|
|
{
|
|
return NotFound();
|
|
}
|
|
|
|
return new GetAgentLeaseResponse(Lease);
|
|
}
|
|
}
|
|
}
|