Skip to content

Commit

Permalink
Slice Manager integration corrections (#165)
Browse files Browse the repository at this point in the history
* Added separate route for slices in gateway conf file

Implemented separate endpoints for each slice type

* Implemented remaining endpoints for slicing

* Correct controllers and simplify contracts

* Manage relations between robot and slices

* Correct condition

* Fix compilation errors, rename function

* Last corrections; Create relation when adding new Slice with default location

* Compilation fixes

* Added logger to tests

---------

Co-authored-by: radu-popescu <[email protected]>
  • Loading branch information
Artonus and radu-popescu authored Jun 16, 2023
1 parent 550f40f commit 720f92e
Show file tree
Hide file tree
Showing 25 changed files with 618 additions and 30 deletions.
1 change: 1 addition & 0 deletions src/Common/MessageContracts/ConnectRobotToSliceMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

public record ConnectRobotToSliceMessage : Message
{
public Guid RobotId { get; init; }
public string Location { get; init; }

public string Imsi { get; init; }
Expand Down
3 changes: 2 additions & 1 deletion src/DataAccess/Repositories/Abstract/ICloudRepository.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using System.Collections.Immutable;
using Middleware.Models.Domain;
using Middleware.Models.Dto;

namespace Middleware.DataAccess.Repositories.Abstract
{
public interface ICloudRepository : IBaseRepository<CloudModel>, IRelationRepository
public interface ICloudRepository : IRedisRepository<CloudModel, CloudDto>, IRelationRepository
{
Task<CloudModel> PatchCloudAsync(Guid id, CloudModel patch);

Expand Down
3 changes: 2 additions & 1 deletion src/DataAccess/Repositories/Abstract/IEdgeRepository.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using System.Collections.Immutable;
using Middleware.Models.Domain;
using Middleware.Models.Dto;

namespace Middleware.DataAccess.Repositories.Abstract
{
public interface IEdgeRepository : IBaseRepository<EdgeModel>, IRelationRepository
public interface IEdgeRepository : IRedisRepository<EdgeModel, EdgeDto>, IRelationRepository
{
Task<EdgeModel> PatchEdgeAsync(Guid id, EdgeModel patch);
Task<List<EdgeModel>> GetFreeEdgesIdsAsync(List<EdgeModel> listofEdgesConnectedtoRobot);
Expand Down
3 changes: 2 additions & 1 deletion src/DataAccess/Repositories/Abstract/ISliceRepository.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
using Middleware.Models.Domain.Slice;
using Middleware.Models.Dto.Slice;

namespace Middleware.DataAccess.Repositories.Abstract;

public interface ISliceRepository : IBaseRepository<SliceModel>, IRelationRepository
public interface ISliceRepository : IRedisRepository<SliceModel, SliceDto>, IRelationRepository
{
}
23 changes: 23 additions & 0 deletions src/DataAccess/Repositories/CloudRepository.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
using System.Collections.Immutable;
using System.Linq.Expressions;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using Middleware.Common.Enums;
using Middleware.DataAccess.Repositories.Abstract;
using Middleware.Models.Domain;
using Middleware.Models.Dto;
using Middleware.Models.Enums;
using NReJSON;
using Redis.OM.Searching;
using RedisGraphDotNet.Client;
using StackExchange.Redis;

Expand Down Expand Up @@ -223,5 +226,25 @@ public async Task<ImmutableList<CloudModel>> GetCloudsByOrganizationAsync(string
{
throw new NotImplementedException();
}

public Task DeleteAsync(CloudModel model)
{
throw new NotImplementedException();
}

public Task<List<CloudModel>> FindAsync(Expression<Func<CloudDto, bool>> predicate)
{
throw new NotImplementedException();
}

public Task<CloudModel?> FindSingleAsync(Expression<Func<CloudDto, bool>> predicate)
{
throw new NotImplementedException();
}

public IRedisCollection<CloudDto> FindQuery(Expression<Func<CloudDto, bool>> predicate)
{
throw new NotImplementedException();
}
}
}
22 changes: 22 additions & 0 deletions src/DataAccess/Repositories/EdgeRepository.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
using System.Collections.Immutable;
using System.Linq.Expressions;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using Middleware.Common.Enums;
using Middleware.DataAccess.Repositories.Abstract;
using Middleware.Models.Domain;
using Middleware.Models.Dto;
using Middleware.Models.Enums;
using NReJSON;
using Redis.OM.Searching;
using RedisGraphDotNet.Client;
using StackExchange.Redis;

Expand Down Expand Up @@ -247,5 +250,24 @@ public async Task<bool> CheckIfAddressExists(Uri address)
throw new NotImplementedException();
}

public Task DeleteAsync(EdgeModel model)
{
throw new NotImplementedException();
}

public Task<List<EdgeModel>> FindAsync(Expression<Func<EdgeDto, bool>> predicate)
{
throw new NotImplementedException();
}

public Task<EdgeModel?> FindSingleAsync(Expression<Func<EdgeDto, bool>> predicate)
{
throw new NotImplementedException();
}

public IRedisCollection<EdgeDto> FindQuery(Expression<Func<EdgeDto, bool>> predicate)
{
throw new NotImplementedException();
}
}
}
37 changes: 25 additions & 12 deletions src/Models/Dto/Slice/SliceDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,42 @@ public class SliceDto : Dto
{
public const string Prefix = "Slice";

[Indexed] [RedisIdField] public override string Id { get; set; } = default!;
[Indexed]
[RedisIdField]
public override string Id { get; set; } = default!;

[Indexed] public string Name { get; set; } = default!;
[Indexed]
public string Name { get; set; } = default!;

[Indexed] public string Site { get; init; } = default!;
[Indexed]
public string Site { get; init; } = default!;

[Indexed] public string SliceType { get; init; } = default!;
[Indexed]
public string SliceType { get; init; } = default!;

[Indexed] public int ExpDataRateUl { get; init; }
[Indexed]
public int ExpDataRateUl { get; init; }

[Indexed] public int ExpDataRateDl { get; init; }
[Indexed]
public int ExpDataRateDl { get; init; }

[Indexed] public int? Latency { get; init; }
[Indexed]
public int? Latency { get; init; }

[Indexed] public int? Jitter { get; init; }
[Indexed]
public int? Jitter { get; init; }

[Indexed] public int? UserDensity { get; init; }
[Indexed]
public int? UserDensity { get; init; }

[Indexed] public int? UserSpeed { get; init; }
[Indexed]
public int? UserSpeed { get; init; }

[Indexed] public string TrafficType { get; init; } = default!;
[Indexed]
public string TrafficType { get; init; } = default!;

[Indexed] public List<string> Imsi { get; init; } = new();
[Indexed]
public List<string> Imsi { get; init; } = new();

public override BaseModel ToModel()
{
Expand Down
14 changes: 13 additions & 1 deletion src/OcelotGateway/ocelot.Development.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@
},
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "PATCH", "DELETE" ]
},
{
"DownstreamPathTemplate": "/api/v1/slice/{all}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "redisinterface.api",
"Port": "80"
}
],
"UpstreamPathTemplate": "/api/v1/sliceInventory/SB/reportSliceParameters/{all}",
"UpstreamHttpMethod": [ "POST", "PUT", "DELETE" ]
},
//TaskPlanner API
{
"DownstreamPathTemplate": "/api/v1/{all}",
Expand Down Expand Up @@ -112,7 +124,7 @@
}
],
"UpstreamPathTemplate": "/status/{all}",
"UpstreamHttpMethod": [ "GET", "POST"]
"UpstreamHttpMethod": [ "GET", "POST" ]
}
],
"GlobalConfiguration": {
Expand Down
12 changes: 12 additions & 0 deletions src/OcelotGateway/ocelot.Production.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@
},
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "PATCH", "DELETE" ]
},
{
"DownstreamPathTemplate": "/api/v1/slice/{all}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "redisinterface.api",
"Port": "80"
}
],
"UpstreamPathTemplate": "/api/v1/sliceInventory/SB/reportSliceParameters/{all}",
"UpstreamHttpMethod": [ "POST", "PUT", "DELETE" ]
},
//TaskPlanner API
{
"DownstreamPathTemplate": "/api/v1/{all}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ public async Task Consume(ConsumeContext<ConnectRobotToSliceMessage> context)

var slice = _sliceManagerClientFactory.CreateSliceManagerClient();
//TODO: select correct values for up link and down link
await slice.AttachImsiToSlice(message.Imsi, message.Slice, 100, 100);
await slice.AttachImsiToSlice(message.RobotId, message.Imsi, message.Slice, 100, 100);
}
}
2 changes: 1 addition & 1 deletion src/Orchestrator/SliceManager/ISliceManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ internal interface ISliceManager
/// <param name="dataRateUpLink"></param>
/// <param name="dataRateDownLink"></param>
/// <returns></returns>
Task AttachImsiToSlice(string imsi, string sliceId, int dataRateUpLink, int dataRateDownLink);
Task AttachImsiToSlice(Guid robotId, string imsi, string sliceId, int dataRateUpLink, int dataRateDownLink);
}
89 changes: 86 additions & 3 deletions src/Orchestrator/SliceManager/SliceManager.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
using Middleware.Orchestrator.SliceManager.Contracts;
using Middleware.Models.Domain;
using Middleware.Models.Domain.Slice;
using Middleware.Orchestrator.SliceManager.Contracts;
using Middleware.RedisInterface.Contracts.Mappings;
using Middleware.RedisInterface.Sdk;

namespace Middleware.Orchestrator.SliceManager;

internal class SliceManager : ISliceManager
{
private readonly bool _isSliceManagerAvailable;
private readonly IRedisInterfaceClient _redisInterfaceClient;
private readonly ISliceManagerApi _sliceManagerApi;

public SliceManager(ISliceManagerApi sliceManagerApi, bool isSliceManagerAvailable)
public SliceManager(ISliceManagerApi sliceManagerApi, bool isSliceManagerAvailable,
IRedisInterfaceClient redisInterfaceClient)
{
_sliceManagerApi = sliceManagerApi;
_isSliceManagerAvailable = isSliceManagerAvailable;
_redisInterfaceClient = redisInterfaceClient;
}

public async Task AttachImsiToSlice(string imsi, string sliceId, int dataRateUpLink, int dataRateDownLink)
public async Task AttachImsiToSlice(Guid robotId, string imsi, string sliceId, int dataRateUpLink,
int dataRateDownLink)
{
if (!_isSliceManagerAvailable)
return;

var request = new AttachImsiToSliceRequest
{
Imsi = imsi,
Expand All @@ -24,5 +35,77 @@ public async Task AttachImsiToSlice(string imsi, string sliceId, int dataRateUpL
};

await _sliceManagerApi.AttachImsiToSlice(request);

//get the slice by the id
var slice = await GetSlice(sliceId);
var robot = await GetRobot(robotId);

if (slice is null || robot is null) return;

// check robot is connected to slice
var connectedSlices =
await _redisInterfaceClient.GetRelationAsync(robot, "CONNECTED_TO");


if (connectedSlices is null || connectedSlices.Count == 0)
{
//attach the new imsi to the specific slice
await ConnectRobotToSlice(robot, slice, imsi);
return;
}

// when it is connected to the correct slice already
if (connectedSlices.Count == 1 && connectedSlices.First().PointsTo.Name == sliceId)
return;

// when it is connected to a different slice[s]
// delete connection from the previous slice[s] (should always be connected to a single slice)
foreach (var relation in connectedSlices)
{
await DeleteRobotConnectionToSlice(robot, imsi, relation.PointsTo.Name);
}

// add connection to a new slice
await ConnectRobotToSlice(robot, slice, imsi);
}

private async Task DeleteRobotConnectionToSlice(RobotModel robot, string imsi, string sliceName)
{
var sliceResp = await _redisInterfaceClient.GetBySliceIdAsync(sliceName);
if (sliceResp is null) return;
var slice = sliceResp.ToSlice();

slice.Imsi.Remove(imsi);
await UpdateSlice(slice);

await _redisInterfaceClient.DeleteRelationAsync(robot, slice, "CONNECTED_TO");
}

private async Task ConnectRobotToSlice(RobotModel robot, SliceModel slice, string imsi)
{
slice.Imsi.Add(imsi);
//store this slice in redis
await UpdateSlice(slice);
await _redisInterfaceClient.AddRelationAsync(robot, slice, "CONNECTED_TO");
}

private async Task UpdateSlice(SliceModel slice)
{
var sliceRequest = slice.ToSliceRequest();
await _redisInterfaceClient.SliceAddAsync(sliceRequest);
}

private async Task<RobotModel> GetRobot(Guid robotId)
{
var robotResp = await _redisInterfaceClient.RobotGetByIdAsync(robotId);
var robot = robotResp?.ToRobot();
return robot;
}

private async Task<SliceModel> GetSlice(string sliceId)
{
var sliceResponse = await _redisInterfaceClient.GetBySliceIdAsync(sliceId);
var slice = sliceResponse?.ToSlice();
return slice;
}
}
7 changes: 5 additions & 2 deletions src/Orchestrator/SliceManager/SliceManagerClientFactory.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
using Microsoft.Extensions.Options;
using Middleware.Common.Config;
using Middleware.Orchestrator.SliceManager.Contracts;
using Middleware.RedisInterface.Sdk;
using Refit;

namespace Middleware.Orchestrator.SliceManager;

internal class SliceManagerClientFactory : ISliceManagerClientFactory
{
private readonly IRedisInterfaceClient _redisInterfaceClient;
private readonly IOptions<SliceConfig> _sliceConfig;

public SliceManagerClientFactory(IOptions<SliceConfig> sliceConfig)
public SliceManagerClientFactory(IOptions<SliceConfig> sliceConfig, IRedisInterfaceClient redisInterfaceClient)
{
_sliceConfig = sliceConfig;
_redisInterfaceClient = redisInterfaceClient;
}

public bool IsSlicingAvailable()
Expand All @@ -27,6 +30,6 @@ public ISliceManager CreateSliceManagerClient()

var client = RestService.For<ISliceManagerApi>(_sliceConfig.Value.Hostname);

return new SliceManager(client, IsSlicingAvailable());
return new SliceManager(client, IsSlicingAvailable(), _redisInterfaceClient);
}
}
Loading

0 comments on commit 720f92e

Please sign in to comment.