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
12 changes: 10 additions & 2 deletions modules/AgonesAllocator/CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,28 @@ Replace with your Agones Allocator Service URL. This should be the base URL of y

Find this URL from your Agones installation. Refer to the [Agones Allocator Service documentation](https://agones.dev/site/docs/advanced/allocator-service/) for setup instructions.

### Authentication Provider (line 31) - recommended for production
### Authentication Provider (line 31 & line 36) - recommended for production

```csharp
var authProvider = new AnonymousAuthenticationProvider(); // TODO: Replace with required auth of your service
```

```csharp
var handler = new HttpClientHandler
{
// TODO: Implement MTLS or other cert validation here
// ServerCertificateCustomValidationCallback = (_, _, _, _) => throw new NotImplementedException()
};
```

Replace `AnonymousAuthenticationProvider` with your preferred authentication method. For production deployments, consider using:
- mTLS (mutual TLS) authentication - recommended by Agones
- Bearer token authentication
- Custom authentication provider

Refer to the [Agones Allocator Service documentation](https://agones.dev/site/docs/advanced/allocator-service/) for authentication options.

### Allocation Request Configuration (line 41) - optional
### Allocation Request Configuration (line 68) - optional

```csharp
var allocation = await client.Gameserverallocation.PostAsync(new AllocationAllocationRequest
Expand Down
58 changes: 36 additions & 22 deletions modules/AgonesAllocator/Project/AgonesAllocator.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using AgonesAllocatorModule.Client;
using AgonesAllocatorModule.Client.Models;
Expand Down Expand Up @@ -30,7 +31,13 @@ public void Setup(ICloudCodeConfig config)
// TODO: Replace with required auth of your service
var authProvider = new AnonymousAuthenticationProvider();

return new HttpClientRequestAdapter(authProvider)
var handler = new HttpClientHandler
{
// TODO: Implement MTLS or other cert validation here
// ServerCertificateCustomValidationCallback = (_, _, _, _) => throw new NotImplementedException()
};

return new HttpClientRequestAdapter(authProvider, httpClient: new HttpClient(handler))
{
BaseUrl = AllocatorServiceBaseUrl
};
Expand All @@ -43,9 +50,14 @@ public void Setup(ICloudCodeConfig config)
/// </summary>
public class AgonesAllocator(IRequestAdapter requestAdapter, ILogger<AgonesAllocator> logger) : IMatchmakerAllocator
{

[CloudCodeFunction("Matchmaker_AllocateServer")]
public async Task<AllocateResponse> Allocate(IExecutionContext context, AllocateRequest request)
public Task<AllocateResponse> Allocate(IExecutionContext context, AllocateRequest request)
{
return Task.FromResult(new AllocateResponse(AllocateStatus.Created));
}

[CloudCodeFunction("Matchmaker_PollAllocation")]
public async Task<PollResponse> Poll(IExecutionContext context, PollRequest request)
{
var client = new AgonesClient(requestAdapter);

Expand All @@ -62,39 +74,41 @@ public async Task<AllocateResponse> Allocate(IExecutionContext context, Allocate
if (ip == null || port == null)
{
logger.LogError("Allocation did not return a valid IP or Port");
return new AllocateResponse(AllocateStatus.Error)
return new PollResponse(PollStatus.Error)
{
Message = "Allocation did not return a valid IP or Port"
};
}

return new AllocateResponse(AllocateStatus.Created)
return new PollResponse(PollStatus.Allocated)
{
AllocationData = new Dictionary<string, object>
{
{ "ip", ip },
{ "port", port }
}
AssignmentData = AssignmentData.IpPort(ip, port ?? 0)
};
}
catch (Exception e)
catch (ApiException e)
{
logger.LogError(e, "Error creating Agones allocation");

return new AllocateResponse(AllocateStatus.Error)
// Agones was unable to allocate a server but might succeed in the future
// Wait for the next poll to retry
if (e.ResponseStatusCode == 429)
{
Message = $"Error creating Agones allocation: {e}"
};
}
logger.LogWarning(e, "Error creating Agones allocation");
return new PollResponse(PollStatus.Pending);
}

return HandlePollError(e);
}
catch (Exception e)
{
return HandlePollError(e);
}
}

[CloudCodeFunction("Matchmaker_PollAllocation")]
public Task<PollResponse> Poll(IExecutionContext context, PollRequest request)
private PollResponse HandlePollError(Exception e)
{
return Task.FromResult(new PollResponse(PollStatus.Allocated)
logger.LogError(e, "Error creating Agones allocation");
return new PollResponse(PollStatus.Error)
{
AssignmentData = AssignmentData.IpPort((string)request.AllocationData["ip"], (int)request.AllocationData["port"])
});
Message = $"Error creating Agones allocation: {e}"
};
}
}
29 changes: 11 additions & 18 deletions tests/AllocatorTests/AgonesAllocatorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ public AgonesAllocatorTests()

[Test]
public async Task TestAgonesCanAllocate()
{
var allocation = await _allocator.Allocate(_executionContextMock.Object, new AllocateRequest("1234",
new MatchmakingResults(null, "matchId", "poolId", "poolName", "queueName", new())));

Assert.That(allocation.Status, Is.EqualTo(AllocateStatus.Created));
Assert.That(allocation.Message, Is.Null);
}

[Test]
public async Task TestAgonesCanPoll()
{
_requestAdapterMock.Reset();
_requestAdapterMock.Setup(s => s.SerializationWriterFactory.GetSerializationWriter("application/json"))
Expand All @@ -52,25 +62,8 @@ public async Task TestAgonesCanAllocate()
}
});

var allocation = await _allocator.Allocate(_executionContextMock.Object, new AllocateRequest("1234",
new MatchmakingResults(null, "matchId", "poolId", "poolName", "queueName", new())));

Assert.That(allocation.Status, Is.EqualTo(AllocateStatus.Created));
Assert.That(allocation.Message, Is.Null);
Assert.That(allocation.AllocationData, Is.Not.Null);
Assert.That(allocation.AllocationData["ip"], Is.EqualTo("127.0.0.1"));
Assert.That(allocation.AllocationData["port"], Is.EqualTo(1234));
}

[Test]
public async Task TestAgonesCanPoll()
{
var poll = await _allocator.Poll(_executionContextMock.Object, new PollRequest("1234",
new Dictionary<string, object>
{
{ "ip", "127.0.0.1" },
{ "port", 1234 },
}, DateTimeOffset.UtcNow));
new Dictionary<string, object>(), DateTimeOffset.UtcNow));

Assert.That(poll.Status, Is.EqualTo(PollStatus.Allocated));
Assert.That(poll.Message, Is.Null);
Expand Down
Loading