* Implemented usage of workflow definitions as activities * Updated designer * Removed activity definitions module * Allow user to mark workflow to be used as activity * Refactor * Refactor * Cleanup csproj * Cleanup WorkflowDefinitionActivity * Pascalize typename * Fix JS intellisense initial load issue * Add XML comments * Add Jobs dependency * Hide Composite root port from designer * Move finding workflow activities logic to lower level * Generate unique identities across hierarchy * Refactor * Revert "Generate unique identities across hierarchy" This reverts commit 74f5e7830309ee76af6ab3a000a5e1ec41f1e90c. * Implement unique node IDs * Introduce new VersionOptions option * Remove unused namespaces --------- Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
118 lines
5.1 KiB
C#
118 lines
5.1 KiB
C#
using Azure;
|
|
using Azure.ResourceManager;
|
|
using Azure.ResourceManager.AppContainers;
|
|
using Azure.ResourceManager.Resources;
|
|
using Azure.ResourceManager.Resources.Models;
|
|
using Microsoft.Extensions.Logging;
|
|
using Proto;
|
|
using Proto.Cluster;
|
|
|
|
namespace Elsa.ProtoActor.Cluster.AzureContainerApps;
|
|
|
|
public static class ArmClientUtils
|
|
{
|
|
private static readonly ILogger Logger = Log.CreateLogger(nameof(ArmClientUtils));
|
|
|
|
public static async Task<Member[]> GetClusterMembers(this ArmClient client, string resourceGroupName, string containerAppName)
|
|
{
|
|
var members = new List<Member>();
|
|
|
|
var containerApp = await (await client.GetResourceGroupByName(resourceGroupName)).Value.GetContainerAppAsync(containerAppName);
|
|
|
|
if (containerApp is null || !containerApp.HasValue)
|
|
{
|
|
Logger.LogError("Container App: {ContainerApp} in resource group: {ResourceGroup} is not found", containerApp, resourceGroupName);
|
|
return members.ToArray();
|
|
}
|
|
|
|
var containerAppRevisions = GetActiveRevisionsWithTraffic(containerApp).ToList();
|
|
if (!containerAppRevisions.Any())
|
|
{
|
|
Logger.LogError("Container App: {ContainerApp} in resource group: {ResourceGroup} does not contain any active revisions with traffic", containerAppName, resourceGroupName);
|
|
return members.ToArray();
|
|
}
|
|
|
|
var replicasWithTraffic = containerAppRevisions.SelectMany(r => r.GetContainerAppReplicas());
|
|
|
|
var allTags = (await containerApp.Value.GetTagResource().GetAsync()).Value.Data.TagValues;
|
|
|
|
foreach (var replica in replicasWithTraffic)
|
|
{
|
|
var replicaNameTag = allTags.FirstOrDefault(kvp => kvp.Value == replica.Data.Name);
|
|
if (replicaNameTag.Key == null)
|
|
{
|
|
Logger.LogWarning("Skipping Replica with name: {Name}, no Proto Tags found", replica.Data.Name);
|
|
continue;
|
|
}
|
|
|
|
var replicaNameTagPrefix = replicaNameTag.Key.Replace(ResourceTagLabels.LabelReplicaNameWithoutPrefix, string.Empty);
|
|
var currentReplicaTags = allTags.Where(kvp => kvp.Key.StartsWith(replicaNameTagPrefix)).ToDictionary(x => x.Key, x => x.Value);
|
|
|
|
var memberId = currentReplicaTags.FirstOrDefault(kvp => kvp.Key.ToString().Contains(ResourceTagLabels.LabelMemberIdWithoutPrefix)).Value;
|
|
|
|
var kinds = currentReplicaTags
|
|
.Where(kvp => kvp.Key.StartsWith(ResourceTagLabels.LabelKind(memberId)))
|
|
.Select(kvp => kvp.Key[(ResourceTagLabels.LabelKind(memberId).Length + 1)..])
|
|
.ToArray();
|
|
|
|
var member = new Member
|
|
{
|
|
Id = currentReplicaTags[ResourceTagLabels.LabelMemberId(memberId)],
|
|
Port = int.Parse(currentReplicaTags[ResourceTagLabels.LabelPort(memberId)]),
|
|
Host = currentReplicaTags[ResourceTagLabels.LabelHost(memberId)],
|
|
Kinds = { kinds }
|
|
};
|
|
|
|
members.Add(member);
|
|
}
|
|
|
|
return members.ToArray();
|
|
}
|
|
|
|
public static async Task AddMemberTags(this ArmClient client, string resourceGroupName, string containerAppName, Dictionary<string, string> newTags)
|
|
{
|
|
var resourceTag = new Tag();
|
|
foreach (var tag in newTags)
|
|
{
|
|
resourceTag.TagValues.Add(tag);
|
|
}
|
|
|
|
var resourceGroup = await client.GetResourceGroupByName(resourceGroupName);
|
|
var containerApp = await resourceGroup.Value.GetContainerAppAsync(containerAppName);
|
|
var tagResource = containerApp.Value.GetTagResource();
|
|
|
|
var existingTags = (await tagResource.GetAsync()).Value.Data.TagValues;
|
|
foreach (var tag in existingTags)
|
|
{
|
|
resourceTag.TagValues.Add(tag);
|
|
}
|
|
|
|
await tagResource.CreateOrUpdateAsync(WaitUntil.Completed, new TagResourceData(resourceTag));
|
|
}
|
|
|
|
public static async Task ClearMemberTags(this ArmClient client, string resourceGroupName, string containerAppName, string memberId)
|
|
{
|
|
var resourceGroup = await client.GetResourceGroupByName(resourceGroupName);
|
|
var containerApp = await resourceGroup.Value.GetContainerAppAsync(containerAppName);
|
|
var tagResource = containerApp.Value.GetTagResource();
|
|
|
|
var resourceTag = new Tag();
|
|
var existingTags = (await tagResource.GetAsync()).Value.Data.TagValues;
|
|
|
|
foreach (var tag in existingTags)
|
|
{
|
|
if (!tag.Key.StartsWith(ResourceTagLabels.LabelPrefix(memberId)))
|
|
{
|
|
resourceTag.TagValues.Add(tag);
|
|
}
|
|
}
|
|
|
|
await tagResource.CreateOrUpdateAsync(WaitUntil.Completed, new TagResourceData(resourceTag));
|
|
}
|
|
|
|
public static async Task<Response<ResourceGroupResource>> GetResourceGroupByName(this ArmClient client, string resourceGroupName) =>
|
|
await (await client.GetDefaultSubscriptionAsync()).GetResourceGroups().GetAsync(resourceGroupName);
|
|
|
|
private static IEnumerable<ContainerAppRevisionResource> GetActiveRevisionsWithTraffic(ContainerAppResource containerApp) =>
|
|
containerApp.GetContainerAppRevisions().Where(r => r.HasData && (r.Data.IsActive ?? false) && r.Data.TrafficWeight > 0);
|
|
} |