Skip to content

Commit

Permalink
fix: middleware removing netapps in use (#232)
Browse files Browse the repository at this point in the history
* fix: middleware removing netapps in use

* chore: release 0.7.2

Release-As: 0.7.2

* chore: release 0.7.2

Release-As: 0.7.2

* fix: test compilation

* test: skip unused test
  • Loading branch information
Artonus authored Nov 27, 2023
1 parent 42c4266 commit 3b34d14
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 23 deletions.
44 changes: 27 additions & 17 deletions src/CentralApi/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -1,33 +1,24 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:16069",
"sslPort": 44312
}
},
{
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5267",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:5267"
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7134;http://localhost:5267",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"dotnetRunMessages": true,
"applicationUrl": "https://localhost:7134;http://localhost:5267"
},
"IIS Express": {
"commandName": "IISExpress",
Expand All @@ -36,6 +27,25 @@
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Docker": {
"commandName": "Docker",
"launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
"environmentVariables": {
"ASPNETCORE_URLS": "https://+:443;http://+:80"
},
"publishAllPorts": true,
"useSSL": true
}
},
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:16069",
"sslPort": 44312
}
}
}
}
20 changes: 20 additions & 0 deletions src/Orchestrator/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// In SDK-style projects such as this one, several assembly attributes that were historically
// defined in this file are now automatically added during build and populated with
// values defined in project properties. For details of which attributes are included
// and how to customise this process see: https://aka.ms/assembly-info-properties


// Setting ComVisible to false makes the types in this assembly not visible to COM
// components. If you need to access a type in this assembly from COM, set the ComVisible
// attribute to true on that type.

[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM.

[assembly: Guid("64ae49d8-8cba-42ed-8c3a-289c67918464")]

[assembly: InternalsVisibleTo("Orchestrator.Tests.Unit")]
3 changes: 2 additions & 1 deletion src/Orchestrator/Controllers/OrchestrateController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ public async Task<ActionResult> DeletePlanById(Guid id)
var isSuccess = await _deploymentService.DeletePlanAsync(actionPlan);

//Delete the LOCATED_AT relationships between instance and edge/cloud.
// TODO: refactor so RedisInterfaceClient can take ILocation as parameter to adding the relation
var actionTempList = actionPlan.ActionSequence;
foreach (var action in actionTempList!)
{
Expand Down Expand Up @@ -185,7 +186,7 @@ public async Task<ActionResult> DeletePlanById(Guid id)

if (isSuccess == false)
{
var statusCode = (int)HttpStatusCode.InternalServerError;
var statusCode = (int)HttpStatusCode.BadRequest;
return StatusCode(statusCode,
new ApiResponse(statusCode, $"Unable to delete the services for the action plan with id {id}"));
}
Expand Down
2 changes: 1 addition & 1 deletion src/Orchestrator/Deployment/Abstract/IDeploymentService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public interface IDeploymentService
V1Service CreateStartupService(string serviceImageName, K8SServiceKind kind, V1ObjectMeta meta);

/// <summary>
/// Deletes the resources instantiated by the specified Action Plan
/// Deletes the ActionPlan and resources instantiated by the specified ActionPlan if not used by other ActionPlans
/// </summary>
/// <param name="actionPlan">Action Plan to be deleted</param>
/// <returns>Has the operation succeeded</returns>
Expand Down
41 changes: 37 additions & 4 deletions src/Orchestrator/Deployment/DeploymentService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,26 +82,36 @@ public V1Service CreateStartupService(string serviceImageName, K8SServiceKind ki
public async Task<bool> DeletePlanAsync(ActionPlanModel actionPlan)
{
var retVal = true;
var location = await GetCurrentLocationAsync();
try
{
foreach (var action in actionPlan.ActionSequence!)
{
var relayShouldBeDeleted = true;
var actionLoc =
await GetLocationAsync(Enum.Parse<LocationType>(action.PlacementType!), action.Placement);

foreach (var srv in action.Services)
{
if (srv.IsReusable is not null && srv.IsReusable!.Value &&
await IsServiceUsedInOtherActionPlans(actionPlan.Id, srv.ServiceInstanceId))
{
relayShouldBeDeleted = false;
continue;
}

retVal &= await TerminateNetAppByIdAsync(srv.ServiceInstanceId);

if (ShouldDeployInterRelay(srv, action) == false)
{
await _publisher.PublishGatewayDeleteNetAppEntryAsync(location, srv.Name, actionPlan.Id,
await _publisher.PublishGatewayDeleteNetAppEntryAsync(actionLoc, srv.Name, actionPlan.Id,
srv.ServiceInstanceId);
}
}

if (action.ShouldUseInterRelayForRosNetApps())
if (relayShouldBeDeleted && action.ShouldUseInterRelayForRosNetApps())
{
var deletedRelayName = await TerminateInterRelayNetApp(actionPlan.Id, action.Id);
await _publisher.PublishGatewayDeleteNetAppEntryAsync(location, deletedRelayName, actionPlan.Id,
await _publisher.PublishGatewayDeleteNetAppEntryAsync(actionLoc, deletedRelayName, actionPlan.Id,
action.Id);
}
}
Expand Down Expand Up @@ -340,6 +350,20 @@ await _publisher.PublishGatewayAddNetAppEntryAsync(location, kvp.Value.Name, tas
return isSuccess;
}

private async Task<bool> IsServiceUsedInOtherActionPlans(Guid actionPlanId, Guid serviceInstanceId)
{
var actionPlans = await _redisInterfaceClient.ActionPlanGetAllAsync();

if (actionPlans is null) return true;

// select all instances from all action plans except of current one
var filtered = actionPlans.Where(a => a.Id != actionPlanId)
.SelectMany(a => a.ActionSequence!.SelectMany(x => x.Services))
.Where(i => i.ServiceInstanceId == serviceInstanceId).ToList();

return filtered.Count > 0;
}

private static bool ShouldDeployInterRelay(InstanceModel instance, ActionModel action)
{
return string.IsNullOrWhiteSpace(instance.RosDistro) == false && action.SingleNetAppEntryPoint;
Expand Down Expand Up @@ -431,6 +455,15 @@ private async Task<ILocation> GetCurrentLocationAsync()
: (await _redisInterfaceClient.GetEdgeByNameAsync(_mwConfig.Value.InstanceName)).ToEdge();
}

private async Task<ILocation> GetLocationAsync(LocationType type, string name)
{
_logger.LogDebug("Retrieving location details (cloud or edge) for type {type}, name: {name}", type.ToString(),
name);
return type == LocationType.Cloud
? (await _redisInterfaceClient.GetCloudByNameAsync(name)).ToCloud()
: (await _redisInterfaceClient.GetEdgeByNameAsync(name)).ToEdge();
}

/// <summary>
/// Saves the specified task to the redis as an action plan
/// </summary>
Expand Down
93 changes: 93 additions & 0 deletions test/Orchestrator.Tests.Unit/Deployment/DeploymentServiceTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using k8s;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Middleware.Common.Config;
using Middleware.Models.Domain;
using Middleware.Orchestrator.Deployment;
using Middleware.Orchestrator.Publishers;
using Middleware.RedisInterface.Sdk;
using NSubstitute;
using Xunit;

namespace Orchestrator.Tests.Unit.Deployment;

public class DeploymentServiceTests
{
private readonly IKubernetes _kube = Substitute.For<IKubernetes>();
private readonly IKubernetesBuilder _kubeBuilder = Substitute.For<IKubernetesBuilder>();
private readonly IKubernetesObjectBuilder _kubernetesObjectBuilder = Substitute.For<IKubernetesObjectBuilder>();
private readonly ILogger<DeploymentService> _logger = Substitute.For<ILogger<DeploymentService>>();

private readonly IOptions<MiddlewareConfig> _mwConfig = Options.Create(new MiddlewareConfig
{
InstanceName = "test-MW",
InstanceType = "Edge",
Organization = "5G-ERA-TST"
});

private readonly IPublishingService _publishingService = Substitute.For<IPublishingService>();
private readonly IRedisInterfaceClient _redisInterface = Substitute.For<IRedisInterfaceClient>();
private readonly IRosConnectionBuilderFactory _rosConnection = Substitute.For<IRosConnectionBuilderFactory>();

private readonly DeploymentService _sut;

public DeploymentServiceTests()
{
_kubeBuilder.CreateKubernetesClient().Returns(_kube);
_sut = new(_kubeBuilder, _logger, _redisInterface, _mwConfig, _kubernetesObjectBuilder,
_rosConnection, _publishingService);
}

[Fact(Skip = "Test not ready due to the complexity of the used functionalities")]
public async Task DeletePlanAsync_ShouldAlwaysDeleteActionPlan_WhenCalled()
{
//arrange
var actionPlan = CreateActionPlan();
var instanceId = actionPlan.ActionSequence!.First().Services.First().ServiceInstanceId;
//_kube.AppsV1
// .ListNamespacedDeploymentAsync("middleware",
// labelSelector: KubernetesObjectExtensions.GetNetAppLabelSelector(instanceId))
// .Returns(new V1DeploymentList());
//act

//assert
await _redisInterface.Received(1).ActionPlanDeleteAsync(actionPlan.Id);
}

private ActionPlanModel CreateActionPlan()
{
return new()
{
Id = Guid.NewGuid(),
Name = "TST",
RobotId = Guid.NewGuid(),
TaskId = Guid.NewGuid(),
TaskStartedAt = DateTime.Now,
ActionSequence = new()
{
new()
{
Name = "Action1",
Id = Guid.NewGuid(),
Placement = "test-MW",
PlacementType = "Edge",
SingleNetAppEntryPoint = true,
Services = new()
{
new()
{
Id = Guid.NewGuid(),
Name = "Instance1",
RosDistro = RosDistro.Foxy.ToString(),
IsReusable = true,
ServiceInstanceId = Guid.NewGuid()
}
}
}
}
};
}
}

0 comments on commit 3b34d14

Please sign in to comment.