From 3ca029a9b9f98897fdf3cba564c3683e99a47f77 Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Wed, 25 Feb 2026 06:59:12 -0800 Subject: [PATCH 1/5] WIP: Add support for app autoscaling --- MountAws/MountAws.csproj | 1 + .../Services/Autoscaling/ApiExtensions.cs | 22 +++++++++++ .../Autoscaling/KnownAutoscalingService.cs | 19 ++++++++++ MountAws/Services/Autoscaling/RootHandler.cs | 27 ++++++++++++++ .../Autoscaling/ScalableTargetItem.cs | 11 ++++++ .../Autoscaling/ScalableTargetsHandler.cs | 26 +++++++++++++ .../Services/Autoscaling/ServiceHandler.cs | 23 ++++++++++++ MountAws/Services/Autoscaling/ServiceItem.cs | 16 ++++++++ .../Services/Autoscaling/ServicesHandler.cs | 23 ++++++++++++ .../DynamoDb/TableAutoscalingHandler.cs | 23 ++++++++++++ MountAws/Services/DynamoDb/TableHandler.cs | 18 ++------- .../Services/DynamoDb/TableItemsHandler.cs | 37 +++++++++++++++++++ 12 files changed, 231 insertions(+), 15 deletions(-) create mode 100644 MountAws/Services/Autoscaling/ApiExtensions.cs create mode 100644 MountAws/Services/Autoscaling/KnownAutoscalingService.cs create mode 100644 MountAws/Services/Autoscaling/RootHandler.cs create mode 100644 MountAws/Services/Autoscaling/ScalableTargetItem.cs create mode 100644 MountAws/Services/Autoscaling/ScalableTargetsHandler.cs create mode 100644 MountAws/Services/Autoscaling/ServiceHandler.cs create mode 100644 MountAws/Services/Autoscaling/ServiceItem.cs create mode 100644 MountAws/Services/Autoscaling/ServicesHandler.cs create mode 100644 MountAws/Services/DynamoDb/TableAutoscalingHandler.cs create mode 100644 MountAws/Services/DynamoDb/TableItemsHandler.cs diff --git a/MountAws/MountAws.csproj b/MountAws/MountAws.csproj index 9680e2b..95a6d1b 100644 --- a/MountAws/MountAws.csproj +++ b/MountAws/MountAws.csproj @@ -26,6 +26,7 @@ + diff --git a/MountAws/Services/Autoscaling/ApiExtensions.cs b/MountAws/Services/Autoscaling/ApiExtensions.cs new file mode 100644 index 0000000..8b42ba6 --- /dev/null +++ b/MountAws/Services/Autoscaling/ApiExtensions.cs @@ -0,0 +1,22 @@ +using Amazon.ApplicationAutoScaling; +using Amazon.ApplicationAutoScaling.Model; +using static MountAws.PagingHelper; + +namespace MountAws.Services.Autoscaling; + +public static class ApiExtensions +{ + public static IEnumerable DescribeScalableTargets(this IAmazonApplicationAutoScaling autoScaling, ServiceNamespace serviceNamespace) + { + return Paginate(nextToken => + { + var response = autoScaling.DescribeScalableTargetsAsync(new DescribeScalableTargetsRequest + { + ServiceNamespace = serviceNamespace, + NextToken = nextToken + }).GetAwaiter().GetResult(); + + return (response.ScalableTargets, response.NextToken); + }); + } +} \ No newline at end of file diff --git a/MountAws/Services/Autoscaling/KnownAutoscalingService.cs b/MountAws/Services/Autoscaling/KnownAutoscalingService.cs new file mode 100644 index 0000000..00d3875 --- /dev/null +++ b/MountAws/Services/Autoscaling/KnownAutoscalingService.cs @@ -0,0 +1,19 @@ +using Amazon.ApplicationAutoScaling; + +namespace MountAws.Services.Autoscaling; + +public class KnownAutoscalingService(string serviceNamespace, string[] supportedDimensions) +{ + public static KnownAutoscalingService[] All { get; } = + [ + DynamoDB + ]; + + public static KnownAutoscalingService DynamoDB { get; } = new("dynamodb", [ + "dynamodb:table:ReadCapacityUnits", + "dynamodb:table:WriteCapacityUnits" + ]); + + public ServiceNamespace ServiceNamespace => serviceNamespace; + public string[] SupportedDimensions => supportedDimensions; +} \ No newline at end of file diff --git a/MountAws/Services/Autoscaling/RootHandler.cs b/MountAws/Services/Autoscaling/RootHandler.cs new file mode 100644 index 0000000..631d9fe --- /dev/null +++ b/MountAws/Services/Autoscaling/RootHandler.cs @@ -0,0 +1,27 @@ +using MountAnything; +using MountAws.Services.Core; + +namespace MountAws.Services.Autoscaling; + +public class RootHandler : PathHandler +{ + public static Item CreateItem(ItemPath parentPath) + { + return new GenericContainerItem(parentPath, "autoscaling", + "Navigate application autoscaling dimensions"); + } + + public RootHandler(ItemPath path, IPathHandlerContext context) : base(path, context) + { + } + + protected override IItem? GetItemImpl() + { + return CreateItem(ParentPath); + } + + protected override IEnumerable GetChildItemsImpl() + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/MountAws/Services/Autoscaling/ScalableTargetItem.cs b/MountAws/Services/Autoscaling/ScalableTargetItem.cs new file mode 100644 index 0000000..b919aae --- /dev/null +++ b/MountAws/Services/Autoscaling/ScalableTargetItem.cs @@ -0,0 +1,11 @@ +using Amazon.ApplicationAutoScaling.Model; +using MountAnything; + +namespace MountAws.Services.Autoscaling; + +public class ScalableTargetItem(ItemPath parentPath, ScalableTarget underlyingObject) + : AwsItem(parentPath, underlyingObject) +{ + public override string ItemName => UnderlyingObject. + public override bool IsContainer { get; } +} \ No newline at end of file diff --git a/MountAws/Services/Autoscaling/ScalableTargetsHandler.cs b/MountAws/Services/Autoscaling/ScalableTargetsHandler.cs new file mode 100644 index 0000000..8a0a4ac --- /dev/null +++ b/MountAws/Services/Autoscaling/ScalableTargetsHandler.cs @@ -0,0 +1,26 @@ +using Amazon.ApplicationAutoScaling; +using Amazon.ApplicationAutoScaling.Model; +using MountAnything; +using MountAws.Services.Core; + +namespace MountAws.Services.Autoscaling; + +public class ScalableTargetsHandler(ItemPath path, IPathHandlerContext context, ServiceNamespace serviceNamespace, IAmazonApplicationAutoScaling autoScaling) + : PathHandler(path, context) +{ + public static Item CreateItem(ItemPath parentPath) + { + return new GenericContainerItem(parentPath, "scalable-targets", + "Navigate the scalable targets of the current service namespace."); + } + + protected override IItem? GetItemImpl() + { + return CreateItem(ParentPath); + } + + protected override IEnumerable GetChildItemsImpl() + { + autoScaling.DescribeScalableTargets(serviceNamespace).Select(target => new ScalableTargetItem) + } +} \ No newline at end of file diff --git a/MountAws/Services/Autoscaling/ServiceHandler.cs b/MountAws/Services/Autoscaling/ServiceHandler.cs new file mode 100644 index 0000000..7d89a4a --- /dev/null +++ b/MountAws/Services/Autoscaling/ServiceHandler.cs @@ -0,0 +1,23 @@ +using Amazon.ApplicationAutoScaling; +using MountAnything; + +namespace MountAws.Services.Autoscaling; + +public class ServiceHandler : PathHandler +{ + public ServiceHandler(ItemPath path, IPathHandlerContext context) : base(path, context) + { + } + + protected override IItem? GetItemImpl() + { + var serviceNamespace = new ServiceNamespace(Path.Name); + + return new ServiceItem(ParentPath, serviceNamespace); + } + + protected override IEnumerable GetChildItemsImpl() + { + yield return ScalableTargetsHandler.CreateItem(Path); + } +} \ No newline at end of file diff --git a/MountAws/Services/Autoscaling/ServiceItem.cs b/MountAws/Services/Autoscaling/ServiceItem.cs new file mode 100644 index 0000000..a0387a4 --- /dev/null +++ b/MountAws/Services/Autoscaling/ServiceItem.cs @@ -0,0 +1,16 @@ +using System.Management.Automation; +using Amazon.ApplicationAutoScaling; +using MountAnything; + +namespace MountAws.Services.Autoscaling; + +public class ServiceItem : AwsItem +{ + public ServiceItem(ItemPath parentPath, ServiceNamespace underlyingObject) : base(parentPath, underlyingObject) + { + + } + + public override string ItemName => UnderlyingObject.Value; + public override bool IsContainer => true; +} \ No newline at end of file diff --git a/MountAws/Services/Autoscaling/ServicesHandler.cs b/MountAws/Services/Autoscaling/ServicesHandler.cs new file mode 100644 index 0000000..0f99f6c --- /dev/null +++ b/MountAws/Services/Autoscaling/ServicesHandler.cs @@ -0,0 +1,23 @@ +using MountAnything; +using MountAws.Services.Core; + +namespace MountAws.Services.Autoscaling; + +public class ServicesHandler : PathHandler +{ + + + public ServicesHandler(ItemPath path, IPathHandlerContext context) : base(path, context) + { + } + + protected override IItem? GetItemImpl() + { + throw new NotImplementedException(); + } + + protected override IEnumerable GetChildItemsImpl() + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/MountAws/Services/DynamoDb/TableAutoscalingHandler.cs b/MountAws/Services/DynamoDb/TableAutoscalingHandler.cs new file mode 100644 index 0000000..e1327b5 --- /dev/null +++ b/MountAws/Services/DynamoDb/TableAutoscalingHandler.cs @@ -0,0 +1,23 @@ +using MountAnything; +using MountAws.Services.Core; + +namespace MountAws.Services.DynamoDb; + +public class TableAutoscalingHandler(ItemPath path, IPathHandlerContext context) : PathHandler(path, context) +{ + public static IItem CreateItem(ItemPath parentPath) + { + return new GenericContainerItem(parentPath, "autoscaling", + "Navigate DynamoDB autoscaling dimensions, policies and activities for this table"); + } + + protected override IItem? GetItemImpl() + { + return CreateItem(ParentPath); + } + + protected override IEnumerable GetChildItemsImpl() + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/MountAws/Services/DynamoDb/TableHandler.cs b/MountAws/Services/DynamoDb/TableHandler.cs index 21d4b55..2e7230c 100644 --- a/MountAws/Services/DynamoDb/TableHandler.cs +++ b/MountAws/Services/DynamoDb/TableHandler.cs @@ -5,7 +5,7 @@ namespace MountAws.Services.DynamoDb; -public class TableHandler : PathHandler, IGetChildItemParameters +public class TableHandler : PathHandler { private readonly IAmazonDynamoDB _dynamo; @@ -29,19 +29,7 @@ public TableHandler(ItemPath path, IPathHandlerContext context, IAmazonDynamoDB protected override IEnumerable GetChildItemsImpl() { - var table = _dynamo.DescribeTable(ItemName); - - return _dynamo.Scan(ItemName, GetChildItemParameters.Limit).Select(v => new DynamoItem(Path, table.KeySchema, v)); + yield return TableAutoscalingHandler.CreateItem(Path); + yield return TableItemsHandler.CreateItem(Path); } - - // since we don't return the full child item set, we don't want the list of children cached - protected override bool CacheChildren => false; - - public TableChildItemParameters GetChildItemParameters { get; set; } = null!; -} - -public class TableChildItemParameters -{ - [Parameter()] - public int? Limit { get; set; } } \ No newline at end of file diff --git a/MountAws/Services/DynamoDb/TableItemsHandler.cs b/MountAws/Services/DynamoDb/TableItemsHandler.cs new file mode 100644 index 0000000..9af735a --- /dev/null +++ b/MountAws/Services/DynamoDb/TableItemsHandler.cs @@ -0,0 +1,37 @@ +using System.Management.Automation; +using Amazon.DynamoDBv2; +using MountAnything; +using MountAws.Services.Core; + +namespace MountAws.Services.DynamoDb; + +public class TableItemsHandler(ItemPath path, IPathHandlerContext context, IAmazonDynamoDB dynamo) : PathHandler(path, context), IGetChildItemParameters +{ + public static IItem CreateItem(ItemPath parentPath) + { + return new GenericContainerItem(parentPath, "items", "Navigate the items in this table"); + } + + protected override IItem? GetItemImpl() + { + return CreateItem(ParentPath); + } + + protected override IEnumerable GetChildItemsImpl() + { + var table = dynamo.DescribeTable(ItemName); + + return dynamo.Scan(ItemName, GetChildItemParameters.Limit).Select(v => new DynamoItem(Path, table.KeySchema, v)); + } + + // since we don't return the full child item set, we don't want the list of children cached + protected override bool CacheChildren => false; + + public TableItemsChildItemParameters GetChildItemParameters { get; set; } = null!; +} + +public class TableItemsChildItemParameters +{ + [Parameter] + public int? Limit { get; set; } +} \ No newline at end of file From 8f3e51f2b2a4dda8ba8c9e224301b2c06a51daa1 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 1 Mar 2026 19:50:32 +0000 Subject: [PATCH 2/5] Add Application Auto Scaling service with full API coverage Complete the WIP app-autoscaling implementation by: - Adding missing Routes.cs and Registrar.cs for service auto-discovery - Fixing syntax errors in ScalableTargetItem and ScalableTargetsHandler - Implementing all stub handlers (RootHandler, ServicesHandler, TableAutoscalingHandler) - Adding full API coverage: scalable targets, scaling policies, scaling activities, and scheduled actions - Restructuring DynamoDB tables to expose autoscaling and items as children - Adding the autoscaling service to the region-level directory listing - Adding PowerShell formatting (Formats.ps1xml) for all item types - Adding routing tests for both the autoscaling service and DynamoDB changes The filesystem hierarchy is: autoscaling/services/{namespace}/scalable-targets/{resource}/ scaling-policies/, scaling-activities/, scheduled-actions/ DynamoDB tables now show autoscaling/ and items/ as children, with table-specific scalable targets visible under the autoscaling path. https://claude.ai/code/session_01N4ZYL8QWZVtwXKJK88kpsS --- MountAws.UnitTests/AutoscalingTests.cs | 37 +++++ MountAws.UnitTests/DynamoDbRoutingTests.cs | 31 ++++ .../Services/Autoscaling/ApiExtensions.cs | 47 ++++++- .../Services/Autoscaling/CurrentResourceId.cs | 8 ++ .../Autoscaling/CurrentServiceNamespace.cs | 8 ++ MountAws/Services/Autoscaling/Formats.ps1xml | 132 ++++++++++++++++++ .../Autoscaling/KnownAutoscalingService.cs | 19 --- MountAws/Services/Autoscaling/Registrar.cs | 16 +++ MountAws/Services/Autoscaling/RootHandler.cs | 6 +- MountAws/Services/Autoscaling/Routes.cs | 34 +++++ .../Autoscaling/ScalableTargetHandler.cs | 27 ++++ .../Autoscaling/ScalableTargetItem.cs | 18 ++- .../Autoscaling/ScalableTargetsHandler.cs | 7 +- .../Autoscaling/ScalingActivitiesHandler.cs | 28 ++++ .../Autoscaling/ScalingActivityItem.cs | 32 +++++ .../Autoscaling/ScalingPoliciesHandler.cs | 28 ++++ .../Autoscaling/ScalingPolicyHandler.cs | 23 +++ .../Services/Autoscaling/ScalingPolicyItem.cs | 23 +++ .../Autoscaling/ScheduledActionHandler.cs | 23 +++ .../Autoscaling/ScheduledActionItem.cs | 29 ++++ .../Autoscaling/ScheduledActionsHandler.cs | 28 ++++ MountAws/Services/Autoscaling/ServiceItem.cs | 1 - .../Services/Autoscaling/ServicesHandler.cs | 34 ++++- MountAws/Services/Core/RegionHandler.cs | 1 + MountAws/Services/DynamoDb/Routes.cs | 6 +- .../DynamoDb/TableAutoscalingHandler.cs | 15 +- 26 files changed, 621 insertions(+), 40 deletions(-) create mode 100644 MountAws.UnitTests/AutoscalingTests.cs create mode 100644 MountAws.UnitTests/DynamoDbRoutingTests.cs create mode 100644 MountAws/Services/Autoscaling/CurrentResourceId.cs create mode 100644 MountAws/Services/Autoscaling/CurrentServiceNamespace.cs create mode 100644 MountAws/Services/Autoscaling/Formats.ps1xml delete mode 100644 MountAws/Services/Autoscaling/KnownAutoscalingService.cs create mode 100644 MountAws/Services/Autoscaling/Registrar.cs create mode 100644 MountAws/Services/Autoscaling/Routes.cs create mode 100644 MountAws/Services/Autoscaling/ScalableTargetHandler.cs create mode 100644 MountAws/Services/Autoscaling/ScalingActivitiesHandler.cs create mode 100644 MountAws/Services/Autoscaling/ScalingActivityItem.cs create mode 100644 MountAws/Services/Autoscaling/ScalingPoliciesHandler.cs create mode 100644 MountAws/Services/Autoscaling/ScalingPolicyHandler.cs create mode 100644 MountAws/Services/Autoscaling/ScalingPolicyItem.cs create mode 100644 MountAws/Services/Autoscaling/ScheduledActionHandler.cs create mode 100644 MountAws/Services/Autoscaling/ScheduledActionItem.cs create mode 100644 MountAws/Services/Autoscaling/ScheduledActionsHandler.cs diff --git a/MountAws.UnitTests/AutoscalingTests.cs b/MountAws.UnitTests/AutoscalingTests.cs new file mode 100644 index 0000000..721700b --- /dev/null +++ b/MountAws.UnitTests/AutoscalingTests.cs @@ -0,0 +1,37 @@ +using System; +using AwesomeAssertions; +using MountAnything; +using MountAnything.Routing; +using MountAws.Services.Autoscaling; +using Xunit; + +namespace MountAws.UnitTests; + +public class AutoscalingTests +{ + private readonly Router _router; + + public AutoscalingTests() + { + var provider = new MountAwsProvider(); + _router = provider.CreateRouter(); + } + + [Theory] + [InlineData("myprofile/us-east-1/autoscaling", typeof(RootHandler))] + [InlineData("myprofile/us-east-1/autoscaling/services", typeof(ServicesHandler))] + [InlineData("myprofile/us-east-1/autoscaling/services/dynamodb", typeof(ServiceHandler))] + [InlineData("myprofile/us-east-1/autoscaling/services/ecs", typeof(ServiceHandler))] + [InlineData("myprofile/us-east-1/autoscaling/services/dynamodb/scalable-targets", typeof(ScalableTargetsHandler))] + [InlineData("myprofile/us-east-1/autoscaling/services/dynamodb/scalable-targets/table:my-table", typeof(ScalableTargetHandler))] + [InlineData("myprofile/us-east-1/autoscaling/services/dynamodb/scalable-targets/table:my-table/scaling-policies", typeof(ScalingPoliciesHandler))] + [InlineData("myprofile/us-east-1/autoscaling/services/dynamodb/scalable-targets/table:my-table/scaling-policies/my-policy", typeof(ScalingPolicyHandler))] + [InlineData("myprofile/us-east-1/autoscaling/services/dynamodb/scalable-targets/table:my-table/scaling-activities", typeof(ScalingActivitiesHandler))] + [InlineData("myprofile/us-east-1/autoscaling/services/dynamodb/scalable-targets/table:my-table/scheduled-actions", typeof(ScheduledActionsHandler))] + [InlineData("myprofile/us-east-1/autoscaling/services/dynamodb/scalable-targets/table:my-table/scheduled-actions/my-action", typeof(ScheduledActionHandler))] + public void AutoscalingRoutesResolveToCorrectHandlers(string path, Type expectedHandlerType) + { + var resolver = _router.GetResolver(new ItemPath(path)); + resolver.HandlerType.Should().Be(expectedHandlerType); + } +} diff --git a/MountAws.UnitTests/DynamoDbRoutingTests.cs b/MountAws.UnitTests/DynamoDbRoutingTests.cs new file mode 100644 index 0000000..6183815 --- /dev/null +++ b/MountAws.UnitTests/DynamoDbRoutingTests.cs @@ -0,0 +1,31 @@ +using System; +using AwesomeAssertions; +using MountAnything; +using MountAnything.Routing; +using MountAws.Services.DynamoDb; +using Xunit; + +namespace MountAws.UnitTests; + +public class DynamoDbRoutingTests +{ + private readonly Router _router; + + public DynamoDbRoutingTests() + { + var provider = new MountAwsProvider(); + _router = provider.CreateRouter(); + } + + [Theory] + [InlineData("myprofile/us-east-1/dynamodb", typeof(DynamoDbRootHandler))] + [InlineData("myprofile/us-east-1/dynamodb/tables", typeof(TablesHandler))] + [InlineData("myprofile/us-east-1/dynamodb/tables/my-table", typeof(TableHandler))] + [InlineData("myprofile/us-east-1/dynamodb/tables/my-table/autoscaling", typeof(TableAutoscalingHandler))] + [InlineData("myprofile/us-east-1/dynamodb/tables/my-table/items", typeof(TableItemsHandler))] + public void DynamoDbRoutesResolveToCorrectHandlers(string path, Type expectedHandlerType) + { + var resolver = _router.GetResolver(new ItemPath(path)); + resolver.HandlerType.Should().Be(expectedHandlerType); + } +} diff --git a/MountAws/Services/Autoscaling/ApiExtensions.cs b/MountAws/Services/Autoscaling/ApiExtensions.cs index 8b42ba6..e2af953 100644 --- a/MountAws/Services/Autoscaling/ApiExtensions.cs +++ b/MountAws/Services/Autoscaling/ApiExtensions.cs @@ -19,4 +19,49 @@ public static IEnumerable DescribeScalableTargets(this IAmazonAp return (response.ScalableTargets, response.NextToken); }); } -} \ No newline at end of file + + public static IEnumerable DescribeScalingPolicies(this IAmazonApplicationAutoScaling autoScaling, ServiceNamespace serviceNamespace, string resourceId) + { + return Paginate(nextToken => + { + var response = autoScaling.DescribeScalingPoliciesAsync(new DescribeScalingPoliciesRequest + { + ServiceNamespace = serviceNamespace, + ResourceId = resourceId, + NextToken = nextToken + }).GetAwaiter().GetResult(); + + return (response.ScalingPolicies, response.NextToken); + }); + } + + public static IEnumerable DescribeScalingActivities(this IAmazonApplicationAutoScaling autoScaling, ServiceNamespace serviceNamespace, string resourceId) + { + return Paginate(nextToken => + { + var response = autoScaling.DescribeScalingActivitiesAsync(new DescribeScalingActivitiesRequest + { + ServiceNamespace = serviceNamespace, + ResourceId = resourceId, + NextToken = nextToken + }).GetAwaiter().GetResult(); + + return (response.ScalingActivities, response.NextToken); + }); + } + + public static IEnumerable DescribeScheduledActions(this IAmazonApplicationAutoScaling autoScaling, ServiceNamespace serviceNamespace, string resourceId) + { + return Paginate(nextToken => + { + var response = autoScaling.DescribeScheduledActionsAsync(new DescribeScheduledActionsRequest + { + ServiceNamespace = serviceNamespace, + ResourceId = resourceId, + NextToken = nextToken + }).GetAwaiter().GetResult(); + + return (response.ScheduledActions, response.NextToken); + }); + } +} diff --git a/MountAws/Services/Autoscaling/CurrentResourceId.cs b/MountAws/Services/Autoscaling/CurrentResourceId.cs new file mode 100644 index 0000000..84cc2b9 --- /dev/null +++ b/MountAws/Services/Autoscaling/CurrentResourceId.cs @@ -0,0 +1,8 @@ +using MountAnything; + +namespace MountAws.Services.Autoscaling; + +public class CurrentResourceId : TypedString +{ + public CurrentResourceId(string value) : base(value) { } +} diff --git a/MountAws/Services/Autoscaling/CurrentServiceNamespace.cs b/MountAws/Services/Autoscaling/CurrentServiceNamespace.cs new file mode 100644 index 0000000..aa1e684 --- /dev/null +++ b/MountAws/Services/Autoscaling/CurrentServiceNamespace.cs @@ -0,0 +1,8 @@ +using MountAnything; + +namespace MountAws.Services.Autoscaling; + +public class CurrentServiceNamespace : TypedString +{ + public CurrentServiceNamespace(string value) : base(value) { } +} diff --git a/MountAws/Services/Autoscaling/Formats.ps1xml b/MountAws/Services/Autoscaling/Formats.ps1xml new file mode 100644 index 0000000..13a2f50 --- /dev/null +++ b/MountAws/Services/Autoscaling/Formats.ps1xml @@ -0,0 +1,132 @@ + + + + ScalableTarget + + MountAws.Services.Autoscaling.ScalableTargetItem + + + + + + + + + + + + + ItemName + + + ScalableDimension + + + MinCapacity + + + MaxCapacity + + + + + + + + ScalingPolicy + + MountAws.Services.Autoscaling.ScalingPolicyItem + + + + + + + + + + + + + ItemName + + + PolicyType + + + ScalableDimension + + + CreationTime + + + + + + + + ScalingActivity + + MountAws.Services.Autoscaling.ScalingActivityItem + + + + + + + + + + + + + ItemName + + + StatusCode + + + Description + + + StartTime + + + + + + + + ScheduledAction + + MountAws.Services.Autoscaling.ScheduledActionItem + + + + + + + + + + + + + ItemName + + + Schedule + + + ScalableDimension + + + CreationTime + + + + + + + + diff --git a/MountAws/Services/Autoscaling/KnownAutoscalingService.cs b/MountAws/Services/Autoscaling/KnownAutoscalingService.cs deleted file mode 100644 index 00d3875..0000000 --- a/MountAws/Services/Autoscaling/KnownAutoscalingService.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Amazon.ApplicationAutoScaling; - -namespace MountAws.Services.Autoscaling; - -public class KnownAutoscalingService(string serviceNamespace, string[] supportedDimensions) -{ - public static KnownAutoscalingService[] All { get; } = - [ - DynamoDB - ]; - - public static KnownAutoscalingService DynamoDB { get; } = new("dynamodb", [ - "dynamodb:table:ReadCapacityUnits", - "dynamodb:table:WriteCapacityUnits" - ]); - - public ServiceNamespace ServiceNamespace => serviceNamespace; - public string[] SupportedDimensions => supportedDimensions; -} \ No newline at end of file diff --git a/MountAws/Services/Autoscaling/Registrar.cs b/MountAws/Services/Autoscaling/Registrar.cs new file mode 100644 index 0000000..5e291f8 --- /dev/null +++ b/MountAws/Services/Autoscaling/Registrar.cs @@ -0,0 +1,16 @@ +using Amazon; +using Amazon.ApplicationAutoScaling; +using Amazon.Runtime; +using Autofac; + +namespace MountAws.Services.Autoscaling; + +public class Registrar : IServiceRegistrar +{ + public void Register(ContainerBuilder builder) + { + builder.RegisterType() + .As() + .UsingConstructor(typeof(AWSCredentials), typeof(RegionEndpoint)); + } +} diff --git a/MountAws/Services/Autoscaling/RootHandler.cs b/MountAws/Services/Autoscaling/RootHandler.cs index 631d9fe..c0394a6 100644 --- a/MountAws/Services/Autoscaling/RootHandler.cs +++ b/MountAws/Services/Autoscaling/RootHandler.cs @@ -10,7 +10,7 @@ public static Item CreateItem(ItemPath parentPath) return new GenericContainerItem(parentPath, "autoscaling", "Navigate application autoscaling dimensions"); } - + public RootHandler(ItemPath path, IPathHandlerContext context) : base(path, context) { } @@ -22,6 +22,6 @@ public RootHandler(ItemPath path, IPathHandlerContext context) : base(path, cont protected override IEnumerable GetChildItemsImpl() { - throw new NotImplementedException(); + yield return ServicesHandler.CreateItem(Path); } -} \ No newline at end of file +} diff --git a/MountAws/Services/Autoscaling/Routes.cs b/MountAws/Services/Autoscaling/Routes.cs new file mode 100644 index 0000000..3290efd --- /dev/null +++ b/MountAws/Services/Autoscaling/Routes.cs @@ -0,0 +1,34 @@ +using MountAnything.Routing; + +namespace MountAws.Services.Autoscaling; + +public class Routes : IServiceRoutes +{ + public void AddServiceRoutes(Route regionRoute) + { + regionRoute.MapLiteral("autoscaling", autoscaling => + { + autoscaling.MapLiteral("services", services => + { + services.Map(service => + { + service.MapLiteral("scalable-targets", scalableTargets => + { + scalableTargets.Map(scalableTarget => + { + scalableTarget.MapLiteral("scaling-policies", scalingPolicies => + { + scalingPolicies.Map(); + }); + scalableTarget.MapLiteral("scaling-activities"); + scalableTarget.MapLiteral("scheduled-actions", scheduledActions => + { + scheduledActions.Map(); + }); + }); + }); + }); + }); + }); + } +} diff --git a/MountAws/Services/Autoscaling/ScalableTargetHandler.cs b/MountAws/Services/Autoscaling/ScalableTargetHandler.cs new file mode 100644 index 0000000..1acaccb --- /dev/null +++ b/MountAws/Services/Autoscaling/ScalableTargetHandler.cs @@ -0,0 +1,27 @@ +using Amazon.ApplicationAutoScaling; +using Amazon.ApplicationAutoScaling.Model; +using MountAnything; + +namespace MountAws.Services.Autoscaling; + +public class ScalableTargetHandler(ItemPath path, IPathHandlerContext context, CurrentServiceNamespace currentServiceNamespace, CurrentResourceId currentResourceId, IAmazonApplicationAutoScaling autoScaling) + : PathHandler(path, context) +{ + protected override IItem? GetItemImpl() + { + var serviceNamespace = new ServiceNamespace(currentServiceNamespace.Value); + var resourceId = currentResourceId.Value.Replace(":", "/"); + + var target = autoScaling.DescribeScalableTargets(serviceNamespace) + .FirstOrDefault(t => t.ResourceId == resourceId); + + return target != null ? new ScalableTargetItem(ParentPath, target) : null; + } + + protected override IEnumerable GetChildItemsImpl() + { + yield return ScalingPoliciesHandler.CreateItem(Path); + yield return ScalingActivitiesHandler.CreateItem(Path); + yield return ScheduledActionsHandler.CreateItem(Path); + } +} diff --git a/MountAws/Services/Autoscaling/ScalableTargetItem.cs b/MountAws/Services/Autoscaling/ScalableTargetItem.cs index b919aae..1f93c1c 100644 --- a/MountAws/Services/Autoscaling/ScalableTargetItem.cs +++ b/MountAws/Services/Autoscaling/ScalableTargetItem.cs @@ -6,6 +6,18 @@ namespace MountAws.Services.Autoscaling; public class ScalableTargetItem(ItemPath parentPath, ScalableTarget underlyingObject) : AwsItem(parentPath, underlyingObject) { - public override string ItemName => UnderlyingObject. - public override bool IsContainer { get; } -} \ No newline at end of file + public override string ItemName => UnderlyingObject.ResourceId.Replace("/", ":"); + public override bool IsContainer => true; + + [ItemProperty] + public string ScalableDimension => UnderlyingObject.ScalableDimension.Value; + + [ItemProperty] + public int MinCapacity => UnderlyingObject.MinCapacity; + + [ItemProperty] + public int MaxCapacity => UnderlyingObject.MaxCapacity; + + [ItemProperty] + public string ServiceNamespace => UnderlyingObject.ServiceNamespace.Value; +} diff --git a/MountAws/Services/Autoscaling/ScalableTargetsHandler.cs b/MountAws/Services/Autoscaling/ScalableTargetsHandler.cs index 8a0a4ac..3558cf5 100644 --- a/MountAws/Services/Autoscaling/ScalableTargetsHandler.cs +++ b/MountAws/Services/Autoscaling/ScalableTargetsHandler.cs @@ -5,7 +5,7 @@ namespace MountAws.Services.Autoscaling; -public class ScalableTargetsHandler(ItemPath path, IPathHandlerContext context, ServiceNamespace serviceNamespace, IAmazonApplicationAutoScaling autoScaling) +public class ScalableTargetsHandler(ItemPath path, IPathHandlerContext context, CurrentServiceNamespace currentServiceNamespace, IAmazonApplicationAutoScaling autoScaling) : PathHandler(path, context) { public static Item CreateItem(ItemPath parentPath) @@ -21,6 +21,7 @@ public static Item CreateItem(ItemPath parentPath) protected override IEnumerable GetChildItemsImpl() { - autoScaling.DescribeScalableTargets(serviceNamespace).Select(target => new ScalableTargetItem) + return autoScaling.DescribeScalableTargets(currentServiceNamespace.Value) + .Select(target => new ScalableTargetItem(Path, target)); } -} \ No newline at end of file +} diff --git a/MountAws/Services/Autoscaling/ScalingActivitiesHandler.cs b/MountAws/Services/Autoscaling/ScalingActivitiesHandler.cs new file mode 100644 index 0000000..3102705 --- /dev/null +++ b/MountAws/Services/Autoscaling/ScalingActivitiesHandler.cs @@ -0,0 +1,28 @@ +using Amazon.ApplicationAutoScaling; +using MountAnything; +using MountAws.Services.Core; + +namespace MountAws.Services.Autoscaling; + +public class ScalingActivitiesHandler(ItemPath path, IPathHandlerContext context, CurrentServiceNamespace currentServiceNamespace, CurrentResourceId currentResourceId, IAmazonApplicationAutoScaling autoScaling) + : PathHandler(path, context) +{ + public static Item CreateItem(ItemPath parentPath) + { + return new GenericContainerItem(parentPath, "scaling-activities", + "Navigate the scaling activities for this scalable target"); + } + + protected override IItem? GetItemImpl() + { + return CreateItem(ParentPath); + } + + protected override IEnumerable GetChildItemsImpl() + { + var serviceNamespace = new ServiceNamespace(currentServiceNamespace.Value); + var resourceId = currentResourceId.Value.Replace(":", "/"); + return autoScaling.DescribeScalingActivities(serviceNamespace, resourceId) + .Select(a => new ScalingActivityItem(Path, a)); + } +} diff --git a/MountAws/Services/Autoscaling/ScalingActivityItem.cs b/MountAws/Services/Autoscaling/ScalingActivityItem.cs new file mode 100644 index 0000000..6c9a33c --- /dev/null +++ b/MountAws/Services/Autoscaling/ScalingActivityItem.cs @@ -0,0 +1,32 @@ +using Amazon.ApplicationAutoScaling.Model; +using MountAnything; + +namespace MountAws.Services.Autoscaling; + +public class ScalingActivityItem(ItemPath parentPath, ScalingActivity underlyingObject) + : AwsItem(parentPath, underlyingObject) +{ + public override string ItemName => UnderlyingObject.ActivityId; + public override bool IsContainer => false; + + [ItemProperty] + public string StatusCode => UnderlyingObject.StatusCode.Value; + + [ItemProperty] + public string Description => UnderlyingObject.Description; + + [ItemProperty] + public string Cause => UnderlyingObject.Cause; + + [ItemProperty] + public DateTime StartTime => UnderlyingObject.StartTime; + + [ItemProperty] + public DateTime? EndTime => UnderlyingObject.EndTime; + + [ItemProperty] + public string ResourceId => UnderlyingObject.ResourceId; + + [ItemProperty] + public string ScalableDimension => UnderlyingObject.ScalableDimension.Value; +} diff --git a/MountAws/Services/Autoscaling/ScalingPoliciesHandler.cs b/MountAws/Services/Autoscaling/ScalingPoliciesHandler.cs new file mode 100644 index 0000000..e0c6115 --- /dev/null +++ b/MountAws/Services/Autoscaling/ScalingPoliciesHandler.cs @@ -0,0 +1,28 @@ +using Amazon.ApplicationAutoScaling; +using MountAnything; +using MountAws.Services.Core; + +namespace MountAws.Services.Autoscaling; + +public class ScalingPoliciesHandler(ItemPath path, IPathHandlerContext context, CurrentServiceNamespace currentServiceNamespace, CurrentResourceId currentResourceId, IAmazonApplicationAutoScaling autoScaling) + : PathHandler(path, context) +{ + public static Item CreateItem(ItemPath parentPath) + { + return new GenericContainerItem(parentPath, "scaling-policies", + "Navigate the scaling policies for this scalable target"); + } + + protected override IItem? GetItemImpl() + { + return CreateItem(ParentPath); + } + + protected override IEnumerable GetChildItemsImpl() + { + var serviceNamespace = new ServiceNamespace(currentServiceNamespace.Value); + var resourceId = currentResourceId.Value.Replace(":", "/"); + return autoScaling.DescribeScalingPolicies(serviceNamespace, resourceId) + .Select(p => new ScalingPolicyItem(Path, p)); + } +} diff --git a/MountAws/Services/Autoscaling/ScalingPolicyHandler.cs b/MountAws/Services/Autoscaling/ScalingPolicyHandler.cs new file mode 100644 index 0000000..08109a7 --- /dev/null +++ b/MountAws/Services/Autoscaling/ScalingPolicyHandler.cs @@ -0,0 +1,23 @@ +using Amazon.ApplicationAutoScaling; +using MountAnything; + +namespace MountAws.Services.Autoscaling; + +public class ScalingPolicyHandler(ItemPath path, IPathHandlerContext context, CurrentServiceNamespace currentServiceNamespace, CurrentResourceId currentResourceId, IAmazonApplicationAutoScaling autoScaling) + : PathHandler(path, context) +{ + protected override IItem? GetItemImpl() + { + var serviceNamespace = new ServiceNamespace(currentServiceNamespace.Value); + var resourceId = currentResourceId.Value.Replace(":", "/"); + var policy = autoScaling.DescribeScalingPolicies(serviceNamespace, resourceId) + .FirstOrDefault(p => p.PolicyName == ItemName); + + return policy != null ? new ScalingPolicyItem(ParentPath, policy) : null; + } + + protected override IEnumerable GetChildItemsImpl() + { + return Enumerable.Empty(); + } +} diff --git a/MountAws/Services/Autoscaling/ScalingPolicyItem.cs b/MountAws/Services/Autoscaling/ScalingPolicyItem.cs new file mode 100644 index 0000000..421d8ab --- /dev/null +++ b/MountAws/Services/Autoscaling/ScalingPolicyItem.cs @@ -0,0 +1,23 @@ +using Amazon.ApplicationAutoScaling.Model; +using MountAnything; + +namespace MountAws.Services.Autoscaling; + +public class ScalingPolicyItem(ItemPath parentPath, ScalingPolicy underlyingObject) + : AwsItem(parentPath, underlyingObject) +{ + public override string ItemName => UnderlyingObject.PolicyName; + public override bool IsContainer => false; + + [ItemProperty] + public string PolicyType => UnderlyingObject.PolicyType; + + [ItemProperty] + public string ScalableDimension => UnderlyingObject.ScalableDimension.Value; + + [ItemProperty] + public string ResourceId => UnderlyingObject.ResourceId; + + [ItemProperty] + public DateTime CreationTime => UnderlyingObject.CreationTime; +} diff --git a/MountAws/Services/Autoscaling/ScheduledActionHandler.cs b/MountAws/Services/Autoscaling/ScheduledActionHandler.cs new file mode 100644 index 0000000..c109317 --- /dev/null +++ b/MountAws/Services/Autoscaling/ScheduledActionHandler.cs @@ -0,0 +1,23 @@ +using Amazon.ApplicationAutoScaling; +using MountAnything; + +namespace MountAws.Services.Autoscaling; + +public class ScheduledActionHandler(ItemPath path, IPathHandlerContext context, CurrentServiceNamespace currentServiceNamespace, CurrentResourceId currentResourceId, IAmazonApplicationAutoScaling autoScaling) + : PathHandler(path, context) +{ + protected override IItem? GetItemImpl() + { + var serviceNamespace = new ServiceNamespace(currentServiceNamespace.Value); + var resourceId = currentResourceId.Value.Replace(":", "/"); + var action = autoScaling.DescribeScheduledActions(serviceNamespace, resourceId) + .FirstOrDefault(a => a.ScheduledActionName == ItemName); + + return action != null ? new ScheduledActionItem(ParentPath, action) : null; + } + + protected override IEnumerable GetChildItemsImpl() + { + return Enumerable.Empty(); + } +} diff --git a/MountAws/Services/Autoscaling/ScheduledActionItem.cs b/MountAws/Services/Autoscaling/ScheduledActionItem.cs new file mode 100644 index 0000000..eca313d --- /dev/null +++ b/MountAws/Services/Autoscaling/ScheduledActionItem.cs @@ -0,0 +1,29 @@ +using Amazon.ApplicationAutoScaling.Model; +using MountAnything; + +namespace MountAws.Services.Autoscaling; + +public class ScheduledActionItem(ItemPath parentPath, ScheduledAction underlyingObject) + : AwsItem(parentPath, underlyingObject) +{ + public override string ItemName => UnderlyingObject.ScheduledActionName; + public override bool IsContainer => false; + + [ItemProperty] + public string Schedule => UnderlyingObject.Schedule; + + [ItemProperty] + public string ResourceId => UnderlyingObject.ResourceId; + + [ItemProperty] + public string ScalableDimension => UnderlyingObject.ScalableDimension.Value; + + [ItemProperty] + public DateTime? StartTime => UnderlyingObject.StartTime; + + [ItemProperty] + public DateTime? EndTime => UnderlyingObject.EndTime; + + [ItemProperty] + public DateTime CreationTime => UnderlyingObject.CreationTime; +} diff --git a/MountAws/Services/Autoscaling/ScheduledActionsHandler.cs b/MountAws/Services/Autoscaling/ScheduledActionsHandler.cs new file mode 100644 index 0000000..dcc141d --- /dev/null +++ b/MountAws/Services/Autoscaling/ScheduledActionsHandler.cs @@ -0,0 +1,28 @@ +using Amazon.ApplicationAutoScaling; +using MountAnything; +using MountAws.Services.Core; + +namespace MountAws.Services.Autoscaling; + +public class ScheduledActionsHandler(ItemPath path, IPathHandlerContext context, CurrentServiceNamespace currentServiceNamespace, CurrentResourceId currentResourceId, IAmazonApplicationAutoScaling autoScaling) + : PathHandler(path, context) +{ + public static Item CreateItem(ItemPath parentPath) + { + return new GenericContainerItem(parentPath, "scheduled-actions", + "Navigate the scheduled actions for this scalable target"); + } + + protected override IItem? GetItemImpl() + { + return CreateItem(ParentPath); + } + + protected override IEnumerable GetChildItemsImpl() + { + var serviceNamespace = new ServiceNamespace(currentServiceNamespace.Value); + var resourceId = currentResourceId.Value.Replace(":", "/"); + return autoScaling.DescribeScheduledActions(serviceNamespace, resourceId) + .Select(a => new ScheduledActionItem(Path, a)); + } +} diff --git a/MountAws/Services/Autoscaling/ServiceItem.cs b/MountAws/Services/Autoscaling/ServiceItem.cs index a0387a4..358baf5 100644 --- a/MountAws/Services/Autoscaling/ServiceItem.cs +++ b/MountAws/Services/Autoscaling/ServiceItem.cs @@ -1,4 +1,3 @@ -using System.Management.Automation; using Amazon.ApplicationAutoScaling; using MountAnything; diff --git a/MountAws/Services/Autoscaling/ServicesHandler.cs b/MountAws/Services/Autoscaling/ServicesHandler.cs index 0f99f6c..90e1b09 100644 --- a/MountAws/Services/Autoscaling/ServicesHandler.cs +++ b/MountAws/Services/Autoscaling/ServicesHandler.cs @@ -1,3 +1,4 @@ +using Amazon.ApplicationAutoScaling; using MountAnything; using MountAws.Services.Core; @@ -5,19 +6,42 @@ namespace MountAws.Services.Autoscaling; public class ServicesHandler : PathHandler { - - + internal static readonly ServiceNamespace[] KnownServiceNamespaces = + [ + ServiceNamespace.Appstream, + ServiceNamespace.Cassandra, + ServiceNamespace.Comprehend, + ServiceNamespace.CustomResource, + ServiceNamespace.Dynamodb, + ServiceNamespace.Ec2, + ServiceNamespace.Ecs, + ServiceNamespace.Elasticache, + ServiceNamespace.Elasticmapreduce, + ServiceNamespace.Kafka, + ServiceNamespace.Lambda, + ServiceNamespace.Neptune, + ServiceNamespace.Rds, + ServiceNamespace.Sagemaker, + ServiceNamespace.Workspaces + ]; + + public static Item CreateItem(ItemPath parentPath) + { + return new GenericContainerItem(parentPath, "services", + "Navigate application autoscaling service namespaces"); + } + public ServicesHandler(ItemPath path, IPathHandlerContext context) : base(path, context) { } protected override IItem? GetItemImpl() { - throw new NotImplementedException(); + return CreateItem(ParentPath); } protected override IEnumerable GetChildItemsImpl() { - throw new NotImplementedException(); + return KnownServiceNamespaces.Select(ns => new ServiceItem(Path, ns)); } -} \ No newline at end of file +} diff --git a/MountAws/Services/Core/RegionHandler.cs b/MountAws/Services/Core/RegionHandler.cs index d3d2aa8..8781ca4 100644 --- a/MountAws/Services/Core/RegionHandler.cs +++ b/MountAws/Services/Core/RegionHandler.cs @@ -37,6 +37,7 @@ public RegionHandler(ItemPath path, IPathHandlerContext context) : base(path, co protected override IEnumerable GetChildItemsImpl() { + yield return Services.Autoscaling.RootHandler.CreateItem(Path); yield return CloudfrontRootHandler.CreateItem(Path); yield return Services.Cloudwatch.RootHandler.CreateItem(Path); yield return DynamoDbRootHandler.CreateItem(Path); diff --git a/MountAws/Services/DynamoDb/Routes.cs b/MountAws/Services/DynamoDb/Routes.cs index 20f959d..c4bca04 100644 --- a/MountAws/Services/DynamoDb/Routes.cs +++ b/MountAws/Services/DynamoDb/Routes.cs @@ -12,7 +12,11 @@ public void AddServiceRoutes(Route regionRoute) { tables.Map(table => { - table.MapRegex(@"[a-z0-9-_\.\,]+"); + table.MapLiteral("autoscaling"); + table.MapLiteral("items", items => + { + items.MapRegex(@"[a-z0-9-_\.\,]+"); + }); }); }); }); diff --git a/MountAws/Services/DynamoDb/TableAutoscalingHandler.cs b/MountAws/Services/DynamoDb/TableAutoscalingHandler.cs index e1327b5..17d43a7 100644 --- a/MountAws/Services/DynamoDb/TableAutoscalingHandler.cs +++ b/MountAws/Services/DynamoDb/TableAutoscalingHandler.cs @@ -1,16 +1,19 @@ +using Amazon.ApplicationAutoScaling; +using Amazon.ApplicationAutoScaling.Model; using MountAnything; +using MountAws.Services.Autoscaling; using MountAws.Services.Core; namespace MountAws.Services.DynamoDb; -public class TableAutoscalingHandler(ItemPath path, IPathHandlerContext context) : PathHandler(path, context) +public class TableAutoscalingHandler(ItemPath path, IPathHandlerContext context, IAmazonApplicationAutoScaling autoScaling) : PathHandler(path, context) { public static IItem CreateItem(ItemPath parentPath) { return new GenericContainerItem(parentPath, "autoscaling", "Navigate DynamoDB autoscaling dimensions, policies and activities for this table"); } - + protected override IItem? GetItemImpl() { return CreateItem(ParentPath); @@ -18,6 +21,10 @@ public static IItem CreateItem(ItemPath parentPath) protected override IEnumerable GetChildItemsImpl() { - throw new NotImplementedException(); + var tableName = ParentPath.Name; + return autoScaling.DescribeScalableTargets(ServiceNamespace.Dynamodb) + .Where(t => t.ResourceId == $"table/{tableName}") + .Select(t => new ScalableTargetItem(Path, t)) + .ToList(); } -} \ No newline at end of file +} From 8d834c2e4b65f470d8ff37e42c803897e5b44abd Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Sun, 1 Mar 2026 18:32:05 -0800 Subject: [PATCH 3/5] Removed separate app autoscaling service section in favor of embedding autoscaling elements into individual services. --- MountAws.UnitTests/AutoscalingTests.cs | 37 ----------- .../ApiExtensions.cs | 2 +- .../AppAutoscaling/AutoscalingHandler.cs | 25 ++++++++ .../CurrentServiceNamespace.cs | 2 +- .../Formats.ps1xml | 10 +-- .../AppAutoscaling/IResourceIdResolver.cs | 6 ++ .../AppAutoscaling/ItemResourceIdResolver.cs | 9 +++ .../Registrar.cs | 2 +- .../RootHandler.cs | 2 +- .../AppAutoscaling/RouteExtensions.cs | 37 +++++++++++ .../ScalableTargetItem.cs | 2 +- .../ScalableTargetsHandler.cs | 3 +- .../ScalingActivitiesHandler.cs | 12 ++-- .../AppAutoscaling/ScalingActivityHandler.cs | 25 ++++++++ .../ScalingActivityItem.cs | 2 +- .../ScalingPoliciesHandler.cs | 12 ++-- .../ScalingPolicyHandler.cs | 12 ++-- .../AppAutoscaling/ScalingPolicyItem.cs | 49 ++++++++++++++ .../ScheduledActionHandler.cs | 12 ++-- .../ScheduledActionItem.cs | 2 +- .../ScheduledActionsHandler.cs | 12 ++-- .../ServiceHandler.cs | 2 +- .../ServiceItem.cs | 2 +- .../ServicesHandler.cs | 2 +- .../Services/Autoscaling/CurrentResourceId.cs | 8 --- MountAws/Services/Autoscaling/Routes.cs | 34 ---------- .../Autoscaling/ScalableTargetHandler.cs | 27 -------- .../Services/Autoscaling/ScalingPolicyItem.cs | 23 ------- MountAws/Services/Core/RegionHandler.cs | 3 +- MountAws/Services/DynamoDb/Routes.cs | 3 +- .../DynamoDb/TableAutoscalingHandler.cs | 2 +- MountAws/Services/Ecs/ClustersHandler.cs | 13 +--- MountAws/Services/Ecs/CurrentService.cs | 8 +++ MountAws/Services/Ecs/EcsApiExtensions.cs | 6 +- MountAws/Services/Ecs/EcsRoutes.cs | 9 ++- MountAws/Services/Ecs/ServiceHandler.cs | 34 +--------- MountAws/Services/Ecs/TasksHandler.cs | 64 +++++++++++++++++++ 37 files changed, 300 insertions(+), 215 deletions(-) delete mode 100644 MountAws.UnitTests/AutoscalingTests.cs rename MountAws/Services/{Autoscaling => AppAutoscaling}/ApiExtensions.cs (98%) create mode 100644 MountAws/Services/AppAutoscaling/AutoscalingHandler.cs rename MountAws/Services/{Autoscaling => AppAutoscaling}/CurrentServiceNamespace.cs (76%) rename MountAws/Services/{Autoscaling => AppAutoscaling}/Formats.ps1xml (91%) create mode 100644 MountAws/Services/AppAutoscaling/IResourceIdResolver.cs create mode 100644 MountAws/Services/AppAutoscaling/ItemResourceIdResolver.cs rename MountAws/Services/{Autoscaling => AppAutoscaling}/Registrar.cs (89%) rename MountAws/Services/{Autoscaling => AppAutoscaling}/RootHandler.cs (93%) create mode 100644 MountAws/Services/AppAutoscaling/RouteExtensions.cs rename MountAws/Services/{Autoscaling => AppAutoscaling}/ScalableTargetItem.cs (94%) rename MountAws/Services/{Autoscaling => AppAutoscaling}/ScalableTargetsHandler.cs (90%) rename MountAws/Services/{Autoscaling => AppAutoscaling}/ScalingActivitiesHandler.cs (67%) create mode 100644 MountAws/Services/AppAutoscaling/ScalingActivityHandler.cs rename MountAws/Services/{Autoscaling => AppAutoscaling}/ScalingActivityItem.cs (95%) rename MountAws/Services/{Autoscaling => AppAutoscaling}/ScalingPoliciesHandler.cs (68%) rename MountAws/Services/{Autoscaling => AppAutoscaling}/ScalingPolicyHandler.cs (62%) create mode 100644 MountAws/Services/AppAutoscaling/ScalingPolicyItem.cs rename MountAws/Services/{Autoscaling => AppAutoscaling}/ScheduledActionHandler.cs (62%) rename MountAws/Services/{Autoscaling => AppAutoscaling}/ScheduledActionItem.cs (95%) rename MountAws/Services/{Autoscaling => AppAutoscaling}/ScheduledActionsHandler.cs (68%) rename MountAws/Services/{Autoscaling => AppAutoscaling}/ServiceHandler.cs (92%) rename MountAws/Services/{Autoscaling => AppAutoscaling}/ServiceItem.cs (89%) rename MountAws/Services/{Autoscaling => AppAutoscaling}/ServicesHandler.cs (96%) delete mode 100644 MountAws/Services/Autoscaling/CurrentResourceId.cs delete mode 100644 MountAws/Services/Autoscaling/Routes.cs delete mode 100644 MountAws/Services/Autoscaling/ScalableTargetHandler.cs delete mode 100644 MountAws/Services/Autoscaling/ScalingPolicyItem.cs create mode 100644 MountAws/Services/Ecs/CurrentService.cs create mode 100644 MountAws/Services/Ecs/TasksHandler.cs diff --git a/MountAws.UnitTests/AutoscalingTests.cs b/MountAws.UnitTests/AutoscalingTests.cs deleted file mode 100644 index 721700b..0000000 --- a/MountAws.UnitTests/AutoscalingTests.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using AwesomeAssertions; -using MountAnything; -using MountAnything.Routing; -using MountAws.Services.Autoscaling; -using Xunit; - -namespace MountAws.UnitTests; - -public class AutoscalingTests -{ - private readonly Router _router; - - public AutoscalingTests() - { - var provider = new MountAwsProvider(); - _router = provider.CreateRouter(); - } - - [Theory] - [InlineData("myprofile/us-east-1/autoscaling", typeof(RootHandler))] - [InlineData("myprofile/us-east-1/autoscaling/services", typeof(ServicesHandler))] - [InlineData("myprofile/us-east-1/autoscaling/services/dynamodb", typeof(ServiceHandler))] - [InlineData("myprofile/us-east-1/autoscaling/services/ecs", typeof(ServiceHandler))] - [InlineData("myprofile/us-east-1/autoscaling/services/dynamodb/scalable-targets", typeof(ScalableTargetsHandler))] - [InlineData("myprofile/us-east-1/autoscaling/services/dynamodb/scalable-targets/table:my-table", typeof(ScalableTargetHandler))] - [InlineData("myprofile/us-east-1/autoscaling/services/dynamodb/scalable-targets/table:my-table/scaling-policies", typeof(ScalingPoliciesHandler))] - [InlineData("myprofile/us-east-1/autoscaling/services/dynamodb/scalable-targets/table:my-table/scaling-policies/my-policy", typeof(ScalingPolicyHandler))] - [InlineData("myprofile/us-east-1/autoscaling/services/dynamodb/scalable-targets/table:my-table/scaling-activities", typeof(ScalingActivitiesHandler))] - [InlineData("myprofile/us-east-1/autoscaling/services/dynamodb/scalable-targets/table:my-table/scheduled-actions", typeof(ScheduledActionsHandler))] - [InlineData("myprofile/us-east-1/autoscaling/services/dynamodb/scalable-targets/table:my-table/scheduled-actions/my-action", typeof(ScheduledActionHandler))] - public void AutoscalingRoutesResolveToCorrectHandlers(string path, Type expectedHandlerType) - { - var resolver = _router.GetResolver(new ItemPath(path)); - resolver.HandlerType.Should().Be(expectedHandlerType); - } -} diff --git a/MountAws/Services/Autoscaling/ApiExtensions.cs b/MountAws/Services/AppAutoscaling/ApiExtensions.cs similarity index 98% rename from MountAws/Services/Autoscaling/ApiExtensions.cs rename to MountAws/Services/AppAutoscaling/ApiExtensions.cs index e2af953..fa922cd 100644 --- a/MountAws/Services/Autoscaling/ApiExtensions.cs +++ b/MountAws/Services/AppAutoscaling/ApiExtensions.cs @@ -2,7 +2,7 @@ using Amazon.ApplicationAutoScaling.Model; using static MountAws.PagingHelper; -namespace MountAws.Services.Autoscaling; +namespace MountAws.Services.AppAutoscaling; public static class ApiExtensions { diff --git a/MountAws/Services/AppAutoscaling/AutoscalingHandler.cs b/MountAws/Services/AppAutoscaling/AutoscalingHandler.cs new file mode 100644 index 0000000..a078bc9 --- /dev/null +++ b/MountAws/Services/AppAutoscaling/AutoscalingHandler.cs @@ -0,0 +1,25 @@ +using MountAnything; +using MountAws.Services.Core; + +namespace MountAws.Services.AppAutoscaling; + +public class AutoscalingHandler(ItemPath path, IPathHandlerContext context) : PathHandler(path, context) +{ + public static Item CreateItem(ItemPath parentPath) + { + return new GenericContainerItem(parentPath, "autoscaling", + "Navigate application autoscaling dimensions"); + } + + protected override IItem? GetItemImpl() + { + return CreateItem(ParentPath); + } + + protected override IEnumerable GetChildItemsImpl() + { + yield return ScalingPoliciesHandler.CreateItem(Path); + yield return ScalingActivitiesHandler.CreateItem(Path); + yield return ScheduledActionsHandler.CreateItem(Path); + } +} \ No newline at end of file diff --git a/MountAws/Services/Autoscaling/CurrentServiceNamespace.cs b/MountAws/Services/AppAutoscaling/CurrentServiceNamespace.cs similarity index 76% rename from MountAws/Services/Autoscaling/CurrentServiceNamespace.cs rename to MountAws/Services/AppAutoscaling/CurrentServiceNamespace.cs index aa1e684..fc13aec 100644 --- a/MountAws/Services/Autoscaling/CurrentServiceNamespace.cs +++ b/MountAws/Services/AppAutoscaling/CurrentServiceNamespace.cs @@ -1,6 +1,6 @@ using MountAnything; -namespace MountAws.Services.Autoscaling; +namespace MountAws.Services.AppAutoscaling; public class CurrentServiceNamespace : TypedString { diff --git a/MountAws/Services/Autoscaling/Formats.ps1xml b/MountAws/Services/AppAutoscaling/Formats.ps1xml similarity index 91% rename from MountAws/Services/Autoscaling/Formats.ps1xml rename to MountAws/Services/AppAutoscaling/Formats.ps1xml index 13a2f50..80633e1 100644 --- a/MountAws/Services/Autoscaling/Formats.ps1xml +++ b/MountAws/Services/AppAutoscaling/Formats.ps1xml @@ -3,7 +3,7 @@ ScalableTarget - MountAws.Services.Autoscaling.ScalableTargetItem + MountAws.Services.AppAutoscaling.ScalableTargetItem @@ -35,7 +35,7 @@ ScalingPolicy - MountAws.Services.Autoscaling.ScalingPolicyItem + MountAws.Services.AppAutoscaling.ScalingPolicyItem @@ -57,7 +57,7 @@ ScalableDimension - CreationTime + Summary @@ -67,7 +67,7 @@ ScalingActivity - MountAws.Services.Autoscaling.ScalingActivityItem + MountAws.Services.AppAutoscaling.ScalingActivityItem @@ -99,7 +99,7 @@ ScheduledAction - MountAws.Services.Autoscaling.ScheduledActionItem + MountAws.Services.AppAutoscaling.ScheduledActionItem diff --git a/MountAws/Services/AppAutoscaling/IResourceIdResolver.cs b/MountAws/Services/AppAutoscaling/IResourceIdResolver.cs new file mode 100644 index 0000000..8bbde56 --- /dev/null +++ b/MountAws/Services/AppAutoscaling/IResourceIdResolver.cs @@ -0,0 +1,6 @@ +namespace MountAws.Services.AppAutoscaling; + +public interface IResourceIdResolver +{ + string ResourceId { get; } +} \ No newline at end of file diff --git a/MountAws/Services/AppAutoscaling/ItemResourceIdResolver.cs b/MountAws/Services/AppAutoscaling/ItemResourceIdResolver.cs new file mode 100644 index 0000000..c3de7af --- /dev/null +++ b/MountAws/Services/AppAutoscaling/ItemResourceIdResolver.cs @@ -0,0 +1,9 @@ +using MountAnything; + +namespace MountAws.Services.AppAutoscaling; + +public class ItemResourceIdResolver(IItemAncestor itemAncestor, Func resourceIdAccessor) + : IResourceIdResolver where TItem : IItem +{ + public string ResourceId => resourceIdAccessor(itemAncestor.Item); +} \ No newline at end of file diff --git a/MountAws/Services/Autoscaling/Registrar.cs b/MountAws/Services/AppAutoscaling/Registrar.cs similarity index 89% rename from MountAws/Services/Autoscaling/Registrar.cs rename to MountAws/Services/AppAutoscaling/Registrar.cs index 5e291f8..31492f5 100644 --- a/MountAws/Services/Autoscaling/Registrar.cs +++ b/MountAws/Services/AppAutoscaling/Registrar.cs @@ -3,7 +3,7 @@ using Amazon.Runtime; using Autofac; -namespace MountAws.Services.Autoscaling; +namespace MountAws.Services.AppAutoscaling; public class Registrar : IServiceRegistrar { diff --git a/MountAws/Services/Autoscaling/RootHandler.cs b/MountAws/Services/AppAutoscaling/RootHandler.cs similarity index 93% rename from MountAws/Services/Autoscaling/RootHandler.cs rename to MountAws/Services/AppAutoscaling/RootHandler.cs index c0394a6..c5be943 100644 --- a/MountAws/Services/Autoscaling/RootHandler.cs +++ b/MountAws/Services/AppAutoscaling/RootHandler.cs @@ -1,7 +1,7 @@ using MountAnything; using MountAws.Services.Core; -namespace MountAws.Services.Autoscaling; +namespace MountAws.Services.AppAutoscaling; public class RootHandler : PathHandler { diff --git a/MountAws/Services/AppAutoscaling/RouteExtensions.cs b/MountAws/Services/AppAutoscaling/RouteExtensions.cs new file mode 100644 index 0000000..e2e7eb2 --- /dev/null +++ b/MountAws/Services/AppAutoscaling/RouteExtensions.cs @@ -0,0 +1,37 @@ +using Autofac; +using MountAnything; +using MountAnything.Routing; + +namespace MountAws.Services.AppAutoscaling; + +public static class RouteExtensions +{ + public static void MapAppAutoscaling(this Route route, string serviceNamespace, Func resourceIdSelector) where TItem : IItem + { + route.ConfigureContainer(c => + { + c.RegisterInstance(new CurrentServiceNamespace(serviceNamespace)); + c.Register(s => + { + var item = s.Resolve>(); + + return new ItemResourceIdResolver(item, resourceIdSelector); + }).As(); + }); + route.MapLiteral("autoscaling", autoscaling => + { + autoscaling.MapLiteral("scaling-policies", scalablePolicies => + { + scalablePolicies.Map(); + }); + autoscaling.MapLiteral("scaling-activities", scalingActivities => + { + scalingActivities.Map(); + }); + autoscaling.MapLiteral("scheduled-actions", scheduledActions => + { + scheduledActions.Map(); + }); + }); + } +} \ No newline at end of file diff --git a/MountAws/Services/Autoscaling/ScalableTargetItem.cs b/MountAws/Services/AppAutoscaling/ScalableTargetItem.cs similarity index 94% rename from MountAws/Services/Autoscaling/ScalableTargetItem.cs rename to MountAws/Services/AppAutoscaling/ScalableTargetItem.cs index 1f93c1c..1af99bf 100644 --- a/MountAws/Services/Autoscaling/ScalableTargetItem.cs +++ b/MountAws/Services/AppAutoscaling/ScalableTargetItem.cs @@ -1,7 +1,7 @@ using Amazon.ApplicationAutoScaling.Model; using MountAnything; -namespace MountAws.Services.Autoscaling; +namespace MountAws.Services.AppAutoscaling; public class ScalableTargetItem(ItemPath parentPath, ScalableTarget underlyingObject) : AwsItem(parentPath, underlyingObject) diff --git a/MountAws/Services/Autoscaling/ScalableTargetsHandler.cs b/MountAws/Services/AppAutoscaling/ScalableTargetsHandler.cs similarity index 90% rename from MountAws/Services/Autoscaling/ScalableTargetsHandler.cs rename to MountAws/Services/AppAutoscaling/ScalableTargetsHandler.cs index 3558cf5..d0cfddf 100644 --- a/MountAws/Services/Autoscaling/ScalableTargetsHandler.cs +++ b/MountAws/Services/AppAutoscaling/ScalableTargetsHandler.cs @@ -1,9 +1,8 @@ using Amazon.ApplicationAutoScaling; -using Amazon.ApplicationAutoScaling.Model; using MountAnything; using MountAws.Services.Core; -namespace MountAws.Services.Autoscaling; +namespace MountAws.Services.AppAutoscaling; public class ScalableTargetsHandler(ItemPath path, IPathHandlerContext context, CurrentServiceNamespace currentServiceNamespace, IAmazonApplicationAutoScaling autoScaling) : PathHandler(path, context) diff --git a/MountAws/Services/Autoscaling/ScalingActivitiesHandler.cs b/MountAws/Services/AppAutoscaling/ScalingActivitiesHandler.cs similarity index 67% rename from MountAws/Services/Autoscaling/ScalingActivitiesHandler.cs rename to MountAws/Services/AppAutoscaling/ScalingActivitiesHandler.cs index 3102705..6bf9391 100644 --- a/MountAws/Services/Autoscaling/ScalingActivitiesHandler.cs +++ b/MountAws/Services/AppAutoscaling/ScalingActivitiesHandler.cs @@ -2,9 +2,14 @@ using MountAnything; using MountAws.Services.Core; -namespace MountAws.Services.Autoscaling; +namespace MountAws.Services.AppAutoscaling; -public class ScalingActivitiesHandler(ItemPath path, IPathHandlerContext context, CurrentServiceNamespace currentServiceNamespace, CurrentResourceId currentResourceId, IAmazonApplicationAutoScaling autoScaling) +public class ScalingActivitiesHandler( + ItemPath path, + IPathHandlerContext context, + CurrentServiceNamespace currentServiceNamespace, + IResourceIdResolver resourceIdResolver, + IAmazonApplicationAutoScaling autoScaling) : PathHandler(path, context) { public static Item CreateItem(ItemPath parentPath) @@ -21,8 +26,7 @@ public static Item CreateItem(ItemPath parentPath) protected override IEnumerable GetChildItemsImpl() { var serviceNamespace = new ServiceNamespace(currentServiceNamespace.Value); - var resourceId = currentResourceId.Value.Replace(":", "/"); - return autoScaling.DescribeScalingActivities(serviceNamespace, resourceId) + return autoScaling.DescribeScalingActivities(serviceNamespace, resourceIdResolver.ResourceId) .Select(a => new ScalingActivityItem(Path, a)); } } diff --git a/MountAws/Services/AppAutoscaling/ScalingActivityHandler.cs b/MountAws/Services/AppAutoscaling/ScalingActivityHandler.cs new file mode 100644 index 0000000..bd1e9c5 --- /dev/null +++ b/MountAws/Services/AppAutoscaling/ScalingActivityHandler.cs @@ -0,0 +1,25 @@ +using Amazon.ApplicationAutoScaling; +using MountAnything; + +namespace MountAws.Services.AppAutoscaling; + +public class ScalingActivityHandler( + ItemPath path, + IPathHandlerContext context, + CurrentServiceNamespace currentServiceNamespace, + IResourceIdResolver resourceIdResolver, + IAmazonApplicationAutoScaling autoScaling) : PathHandler(path, context) +{ + protected override IItem? GetItemImpl() + { + var scalingActivity = autoScaling.DescribeScalingActivities(currentServiceNamespace.Value, resourceIdResolver.ResourceId) + .FirstOrDefault(a => a.ActivityId == ItemName); + + return scalingActivity == null ? null : new ScalingActivityItem(ParentPath, scalingActivity); + } + + protected override IEnumerable GetChildItemsImpl() + { + yield break; + } +} \ No newline at end of file diff --git a/MountAws/Services/Autoscaling/ScalingActivityItem.cs b/MountAws/Services/AppAutoscaling/ScalingActivityItem.cs similarity index 95% rename from MountAws/Services/Autoscaling/ScalingActivityItem.cs rename to MountAws/Services/AppAutoscaling/ScalingActivityItem.cs index 6c9a33c..fea538a 100644 --- a/MountAws/Services/Autoscaling/ScalingActivityItem.cs +++ b/MountAws/Services/AppAutoscaling/ScalingActivityItem.cs @@ -1,7 +1,7 @@ using Amazon.ApplicationAutoScaling.Model; using MountAnything; -namespace MountAws.Services.Autoscaling; +namespace MountAws.Services.AppAutoscaling; public class ScalingActivityItem(ItemPath parentPath, ScalingActivity underlyingObject) : AwsItem(parentPath, underlyingObject) diff --git a/MountAws/Services/Autoscaling/ScalingPoliciesHandler.cs b/MountAws/Services/AppAutoscaling/ScalingPoliciesHandler.cs similarity index 68% rename from MountAws/Services/Autoscaling/ScalingPoliciesHandler.cs rename to MountAws/Services/AppAutoscaling/ScalingPoliciesHandler.cs index e0c6115..a85a876 100644 --- a/MountAws/Services/Autoscaling/ScalingPoliciesHandler.cs +++ b/MountAws/Services/AppAutoscaling/ScalingPoliciesHandler.cs @@ -2,9 +2,14 @@ using MountAnything; using MountAws.Services.Core; -namespace MountAws.Services.Autoscaling; +namespace MountAws.Services.AppAutoscaling; -public class ScalingPoliciesHandler(ItemPath path, IPathHandlerContext context, CurrentServiceNamespace currentServiceNamespace, CurrentResourceId currentResourceId, IAmazonApplicationAutoScaling autoScaling) +public class ScalingPoliciesHandler( + ItemPath path, + IPathHandlerContext context, + CurrentServiceNamespace currentServiceNamespace, + IResourceIdResolver resourceIdResolver, + IAmazonApplicationAutoScaling autoScaling) : PathHandler(path, context) { public static Item CreateItem(ItemPath parentPath) @@ -21,8 +26,7 @@ public static Item CreateItem(ItemPath parentPath) protected override IEnumerable GetChildItemsImpl() { var serviceNamespace = new ServiceNamespace(currentServiceNamespace.Value); - var resourceId = currentResourceId.Value.Replace(":", "/"); - return autoScaling.DescribeScalingPolicies(serviceNamespace, resourceId) + return autoScaling.DescribeScalingPolicies(serviceNamespace, resourceIdResolver.ResourceId) .Select(p => new ScalingPolicyItem(Path, p)); } } diff --git a/MountAws/Services/Autoscaling/ScalingPolicyHandler.cs b/MountAws/Services/AppAutoscaling/ScalingPolicyHandler.cs similarity index 62% rename from MountAws/Services/Autoscaling/ScalingPolicyHandler.cs rename to MountAws/Services/AppAutoscaling/ScalingPolicyHandler.cs index 08109a7..19ac20d 100644 --- a/MountAws/Services/Autoscaling/ScalingPolicyHandler.cs +++ b/MountAws/Services/AppAutoscaling/ScalingPolicyHandler.cs @@ -1,16 +1,20 @@ using Amazon.ApplicationAutoScaling; using MountAnything; -namespace MountAws.Services.Autoscaling; +namespace MountAws.Services.AppAutoscaling; -public class ScalingPolicyHandler(ItemPath path, IPathHandlerContext context, CurrentServiceNamespace currentServiceNamespace, CurrentResourceId currentResourceId, IAmazonApplicationAutoScaling autoScaling) +public class ScalingPolicyHandler( + ItemPath path, + IPathHandlerContext context, + CurrentServiceNamespace currentServiceNamespace, + IResourceIdResolver resourceIdResolver, + IAmazonApplicationAutoScaling autoScaling) : PathHandler(path, context) { protected override IItem? GetItemImpl() { var serviceNamespace = new ServiceNamespace(currentServiceNamespace.Value); - var resourceId = currentResourceId.Value.Replace(":", "/"); - var policy = autoScaling.DescribeScalingPolicies(serviceNamespace, resourceId) + var policy = autoScaling.DescribeScalingPolicies(serviceNamespace, resourceIdResolver.ResourceId) .FirstOrDefault(p => p.PolicyName == ItemName); return policy != null ? new ScalingPolicyItem(ParentPath, policy) : null; diff --git a/MountAws/Services/AppAutoscaling/ScalingPolicyItem.cs b/MountAws/Services/AppAutoscaling/ScalingPolicyItem.cs new file mode 100644 index 0000000..599d704 --- /dev/null +++ b/MountAws/Services/AppAutoscaling/ScalingPolicyItem.cs @@ -0,0 +1,49 @@ +using System.Globalization; +using Amazon.ApplicationAutoScaling.Model; +using MountAnything; + +namespace MountAws.Services.AppAutoscaling; + +public class ScalingPolicyItem(ItemPath parentPath, ScalingPolicy underlyingObject) + : AwsItem(parentPath, underlyingObject) +{ + public override string ItemName => UnderlyingObject.PolicyName; + public override bool IsContainer => false; + + [ItemProperty] + public string ScalableDimension => UnderlyingObject.ScalableDimension.Value; + + [ItemProperty] + public string Summary => UnderlyingObject switch + { + { TargetTrackingScalingPolicyConfiguration: not null } => GetTargetTrackingSummary(UnderlyingObject + .TargetTrackingScalingPolicyConfiguration), + { PredictiveScalingPolicyConfiguration: not null } => GetPredictiveScalingSummary(UnderlyingObject + .PredictiveScalingPolicyConfiguration), + { StepScalingPolicyConfiguration: not null } => GetStepScalingSummary(UnderlyingObject + .StepScalingPolicyConfiguration), + _ => UnderlyingObject.PolicyType.Value + }; + + private string GetTargetTrackingSummary(TargetTrackingScalingPolicyConfiguration targetTracking) + { + return targetTracking switch + { + { PredefinedMetricSpecification: not null } => + $"{targetTracking.PredefinedMetricSpecification.PredefinedMetricType} {targetTracking.TargetValue}", + { CustomizedMetricSpecification: not null } => + $"{targetTracking.CustomizedMetricSpecification.MetricName} {targetTracking.TargetValue}", + _ => targetTracking.TargetValue.ToString(CultureInfo.CurrentCulture) + }; + } + + private string GetPredictiveScalingSummary(PredictiveScalingPolicyConfiguration predectiveScaling) + { + return predectiveScaling.Mode.Value; + } + + private string GetStepScalingSummary(StepScalingPolicyConfiguration stepScaling) + { + return $"{stepScaling.MetricAggregationType} {stepScaling.AdjustmentType}"; + } +} diff --git a/MountAws/Services/Autoscaling/ScheduledActionHandler.cs b/MountAws/Services/AppAutoscaling/ScheduledActionHandler.cs similarity index 62% rename from MountAws/Services/Autoscaling/ScheduledActionHandler.cs rename to MountAws/Services/AppAutoscaling/ScheduledActionHandler.cs index c109317..b4ab3cd 100644 --- a/MountAws/Services/Autoscaling/ScheduledActionHandler.cs +++ b/MountAws/Services/AppAutoscaling/ScheduledActionHandler.cs @@ -1,16 +1,20 @@ using Amazon.ApplicationAutoScaling; using MountAnything; -namespace MountAws.Services.Autoscaling; +namespace MountAws.Services.AppAutoscaling; -public class ScheduledActionHandler(ItemPath path, IPathHandlerContext context, CurrentServiceNamespace currentServiceNamespace, CurrentResourceId currentResourceId, IAmazonApplicationAutoScaling autoScaling) +public class ScheduledActionHandler( + ItemPath path, + IPathHandlerContext context, + CurrentServiceNamespace currentServiceNamespace, + IResourceIdResolver resourceIdResolver, + IAmazonApplicationAutoScaling autoScaling) : PathHandler(path, context) { protected override IItem? GetItemImpl() { var serviceNamespace = new ServiceNamespace(currentServiceNamespace.Value); - var resourceId = currentResourceId.Value.Replace(":", "/"); - var action = autoScaling.DescribeScheduledActions(serviceNamespace, resourceId) + var action = autoScaling.DescribeScheduledActions(serviceNamespace, resourceIdResolver.ResourceId) .FirstOrDefault(a => a.ScheduledActionName == ItemName); return action != null ? new ScheduledActionItem(ParentPath, action) : null; diff --git a/MountAws/Services/Autoscaling/ScheduledActionItem.cs b/MountAws/Services/AppAutoscaling/ScheduledActionItem.cs similarity index 95% rename from MountAws/Services/Autoscaling/ScheduledActionItem.cs rename to MountAws/Services/AppAutoscaling/ScheduledActionItem.cs index eca313d..5780300 100644 --- a/MountAws/Services/Autoscaling/ScheduledActionItem.cs +++ b/MountAws/Services/AppAutoscaling/ScheduledActionItem.cs @@ -1,7 +1,7 @@ using Amazon.ApplicationAutoScaling.Model; using MountAnything; -namespace MountAws.Services.Autoscaling; +namespace MountAws.Services.AppAutoscaling; public class ScheduledActionItem(ItemPath parentPath, ScheduledAction underlyingObject) : AwsItem(parentPath, underlyingObject) diff --git a/MountAws/Services/Autoscaling/ScheduledActionsHandler.cs b/MountAws/Services/AppAutoscaling/ScheduledActionsHandler.cs similarity index 68% rename from MountAws/Services/Autoscaling/ScheduledActionsHandler.cs rename to MountAws/Services/AppAutoscaling/ScheduledActionsHandler.cs index dcc141d..203e568 100644 --- a/MountAws/Services/Autoscaling/ScheduledActionsHandler.cs +++ b/MountAws/Services/AppAutoscaling/ScheduledActionsHandler.cs @@ -2,9 +2,14 @@ using MountAnything; using MountAws.Services.Core; -namespace MountAws.Services.Autoscaling; +namespace MountAws.Services.AppAutoscaling; -public class ScheduledActionsHandler(ItemPath path, IPathHandlerContext context, CurrentServiceNamespace currentServiceNamespace, CurrentResourceId currentResourceId, IAmazonApplicationAutoScaling autoScaling) +public class ScheduledActionsHandler( + ItemPath path, + IPathHandlerContext context, + CurrentServiceNamespace currentServiceNamespace, + IResourceIdResolver resourceIdResolver, + IAmazonApplicationAutoScaling autoScaling) : PathHandler(path, context) { public static Item CreateItem(ItemPath parentPath) @@ -21,8 +26,7 @@ public static Item CreateItem(ItemPath parentPath) protected override IEnumerable GetChildItemsImpl() { var serviceNamespace = new ServiceNamespace(currentServiceNamespace.Value); - var resourceId = currentResourceId.Value.Replace(":", "/"); - return autoScaling.DescribeScheduledActions(serviceNamespace, resourceId) + return autoScaling.DescribeScheduledActions(serviceNamespace, resourceIdResolver.ResourceId) .Select(a => new ScheduledActionItem(Path, a)); } } diff --git a/MountAws/Services/Autoscaling/ServiceHandler.cs b/MountAws/Services/AppAutoscaling/ServiceHandler.cs similarity index 92% rename from MountAws/Services/Autoscaling/ServiceHandler.cs rename to MountAws/Services/AppAutoscaling/ServiceHandler.cs index 7d89a4a..904a4af 100644 --- a/MountAws/Services/Autoscaling/ServiceHandler.cs +++ b/MountAws/Services/AppAutoscaling/ServiceHandler.cs @@ -1,7 +1,7 @@ using Amazon.ApplicationAutoScaling; using MountAnything; -namespace MountAws.Services.Autoscaling; +namespace MountAws.Services.AppAutoscaling; public class ServiceHandler : PathHandler { diff --git a/MountAws/Services/Autoscaling/ServiceItem.cs b/MountAws/Services/AppAutoscaling/ServiceItem.cs similarity index 89% rename from MountAws/Services/Autoscaling/ServiceItem.cs rename to MountAws/Services/AppAutoscaling/ServiceItem.cs index 358baf5..2c23e6f 100644 --- a/MountAws/Services/Autoscaling/ServiceItem.cs +++ b/MountAws/Services/AppAutoscaling/ServiceItem.cs @@ -1,7 +1,7 @@ using Amazon.ApplicationAutoScaling; using MountAnything; -namespace MountAws.Services.Autoscaling; +namespace MountAws.Services.AppAutoscaling; public class ServiceItem : AwsItem { diff --git a/MountAws/Services/Autoscaling/ServicesHandler.cs b/MountAws/Services/AppAutoscaling/ServicesHandler.cs similarity index 96% rename from MountAws/Services/Autoscaling/ServicesHandler.cs rename to MountAws/Services/AppAutoscaling/ServicesHandler.cs index 90e1b09..c37c085 100644 --- a/MountAws/Services/Autoscaling/ServicesHandler.cs +++ b/MountAws/Services/AppAutoscaling/ServicesHandler.cs @@ -2,7 +2,7 @@ using MountAnything; using MountAws.Services.Core; -namespace MountAws.Services.Autoscaling; +namespace MountAws.Services.AppAutoscaling; public class ServicesHandler : PathHandler { diff --git a/MountAws/Services/Autoscaling/CurrentResourceId.cs b/MountAws/Services/Autoscaling/CurrentResourceId.cs deleted file mode 100644 index 84cc2b9..0000000 --- a/MountAws/Services/Autoscaling/CurrentResourceId.cs +++ /dev/null @@ -1,8 +0,0 @@ -using MountAnything; - -namespace MountAws.Services.Autoscaling; - -public class CurrentResourceId : TypedString -{ - public CurrentResourceId(string value) : base(value) { } -} diff --git a/MountAws/Services/Autoscaling/Routes.cs b/MountAws/Services/Autoscaling/Routes.cs deleted file mode 100644 index 3290efd..0000000 --- a/MountAws/Services/Autoscaling/Routes.cs +++ /dev/null @@ -1,34 +0,0 @@ -using MountAnything.Routing; - -namespace MountAws.Services.Autoscaling; - -public class Routes : IServiceRoutes -{ - public void AddServiceRoutes(Route regionRoute) - { - regionRoute.MapLiteral("autoscaling", autoscaling => - { - autoscaling.MapLiteral("services", services => - { - services.Map(service => - { - service.MapLiteral("scalable-targets", scalableTargets => - { - scalableTargets.Map(scalableTarget => - { - scalableTarget.MapLiteral("scaling-policies", scalingPolicies => - { - scalingPolicies.Map(); - }); - scalableTarget.MapLiteral("scaling-activities"); - scalableTarget.MapLiteral("scheduled-actions", scheduledActions => - { - scheduledActions.Map(); - }); - }); - }); - }); - }); - }); - } -} diff --git a/MountAws/Services/Autoscaling/ScalableTargetHandler.cs b/MountAws/Services/Autoscaling/ScalableTargetHandler.cs deleted file mode 100644 index 1acaccb..0000000 --- a/MountAws/Services/Autoscaling/ScalableTargetHandler.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Amazon.ApplicationAutoScaling; -using Amazon.ApplicationAutoScaling.Model; -using MountAnything; - -namespace MountAws.Services.Autoscaling; - -public class ScalableTargetHandler(ItemPath path, IPathHandlerContext context, CurrentServiceNamespace currentServiceNamespace, CurrentResourceId currentResourceId, IAmazonApplicationAutoScaling autoScaling) - : PathHandler(path, context) -{ - protected override IItem? GetItemImpl() - { - var serviceNamespace = new ServiceNamespace(currentServiceNamespace.Value); - var resourceId = currentResourceId.Value.Replace(":", "/"); - - var target = autoScaling.DescribeScalableTargets(serviceNamespace) - .FirstOrDefault(t => t.ResourceId == resourceId); - - return target != null ? new ScalableTargetItem(ParentPath, target) : null; - } - - protected override IEnumerable GetChildItemsImpl() - { - yield return ScalingPoliciesHandler.CreateItem(Path); - yield return ScalingActivitiesHandler.CreateItem(Path); - yield return ScheduledActionsHandler.CreateItem(Path); - } -} diff --git a/MountAws/Services/Autoscaling/ScalingPolicyItem.cs b/MountAws/Services/Autoscaling/ScalingPolicyItem.cs deleted file mode 100644 index 421d8ab..0000000 --- a/MountAws/Services/Autoscaling/ScalingPolicyItem.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Amazon.ApplicationAutoScaling.Model; -using MountAnything; - -namespace MountAws.Services.Autoscaling; - -public class ScalingPolicyItem(ItemPath parentPath, ScalingPolicy underlyingObject) - : AwsItem(parentPath, underlyingObject) -{ - public override string ItemName => UnderlyingObject.PolicyName; - public override bool IsContainer => false; - - [ItemProperty] - public string PolicyType => UnderlyingObject.PolicyType; - - [ItemProperty] - public string ScalableDimension => UnderlyingObject.ScalableDimension.Value; - - [ItemProperty] - public string ResourceId => UnderlyingObject.ResourceId; - - [ItemProperty] - public DateTime CreationTime => UnderlyingObject.CreationTime; -} diff --git a/MountAws/Services/Core/RegionHandler.cs b/MountAws/Services/Core/RegionHandler.cs index 8781ca4..b2a16c9 100644 --- a/MountAws/Services/Core/RegionHandler.cs +++ b/MountAws/Services/Core/RegionHandler.cs @@ -1,5 +1,6 @@ using Amazon; using MountAnything; +using MountAws.Services.AppAutoscaling; using MountAws.Services.Cloudfront; using MountAws.Services.Core; using MountAws.Services.DynamoDb; @@ -37,7 +38,7 @@ public RegionHandler(ItemPath path, IPathHandlerContext context) : base(path, co protected override IEnumerable GetChildItemsImpl() { - yield return Services.Autoscaling.RootHandler.CreateItem(Path); + yield return RootHandler.CreateItem(Path); yield return CloudfrontRootHandler.CreateItem(Path); yield return Services.Cloudwatch.RootHandler.CreateItem(Path); yield return DynamoDbRootHandler.CreateItem(Path); diff --git a/MountAws/Services/DynamoDb/Routes.cs b/MountAws/Services/DynamoDb/Routes.cs index c4bca04..6b164bc 100644 --- a/MountAws/Services/DynamoDb/Routes.cs +++ b/MountAws/Services/DynamoDb/Routes.cs @@ -1,4 +1,5 @@ using MountAnything.Routing; +using MountAws.Services.AppAutoscaling; namespace MountAws.Services.DynamoDb; @@ -12,7 +13,7 @@ public void AddServiceRoutes(Route regionRoute) { tables.Map(table => { - table.MapLiteral("autoscaling"); + table.MapAppAutoscaling("dynamodb", item => $"table/{item.ItemName}"); table.MapLiteral("items", items => { items.MapRegex(@"[a-z0-9-_\.\,]+"); diff --git a/MountAws/Services/DynamoDb/TableAutoscalingHandler.cs b/MountAws/Services/DynamoDb/TableAutoscalingHandler.cs index 17d43a7..4a16abf 100644 --- a/MountAws/Services/DynamoDb/TableAutoscalingHandler.cs +++ b/MountAws/Services/DynamoDb/TableAutoscalingHandler.cs @@ -1,7 +1,7 @@ using Amazon.ApplicationAutoScaling; using Amazon.ApplicationAutoScaling.Model; using MountAnything; -using MountAws.Services.Autoscaling; +using MountAws.Services.AppAutoscaling; using MountAws.Services.Core; namespace MountAws.Services.DynamoDb; diff --git a/MountAws/Services/Ecs/ClustersHandler.cs b/MountAws/Services/Ecs/ClustersHandler.cs index 664aeba..1dfaa67 100644 --- a/MountAws/Services/Ecs/ClustersHandler.cs +++ b/MountAws/Services/Ecs/ClustersHandler.cs @@ -7,20 +7,13 @@ namespace MountAws.Services.Ecs; -public class ClustersHandler : PathHandler +public class ClustersHandler(ItemPath path, IPathHandlerContext context, IAmazonECS ecs) : PathHandler(path, context) { - private readonly IAmazonECS _ecs; - public static Item CreateItem(ItemPath parentPath) { return new GenericContainerItem(parentPath, "clusters", "Navigate the ECS clusters in this account and region"); } - - public ClustersHandler(ItemPath path, IPathHandlerContext context, IAmazonECS ecs) : base(path, context) - { - _ecs = ecs; - } protected override IItem? GetItemImpl() { @@ -29,8 +22,8 @@ public ClustersHandler(ItemPath path, IPathHandlerContext context, IAmazonECS ec protected override IEnumerable GetChildItemsImpl() { - var clusterArns = _ecs.ListClusters(); - var clusters = _ecs.DescribeClusters(clusterArns, new []{"TAGS"}); + var clusterArns = ecs.ListClusters(); + var clusters = ecs.DescribeClusters(clusterArns, new []{"TAGS"}); return clusters.Select(c => new ClusterItem(Path, c)).OrderBy(c => c.ItemName); } diff --git a/MountAws/Services/Ecs/CurrentService.cs b/MountAws/Services/Ecs/CurrentService.cs new file mode 100644 index 0000000..e74604e --- /dev/null +++ b/MountAws/Services/Ecs/CurrentService.cs @@ -0,0 +1,8 @@ +using MountAnything; + +namespace MountAws.Services.Ecs; + +public class CurrentService(string serviceName) : TypedString(serviceName) +{ + public string Name => Value; +} \ No newline at end of file diff --git a/MountAws/Services/Ecs/EcsApiExtensions.cs b/MountAws/Services/Ecs/EcsApiExtensions.cs index ccbe6a7..30ed70a 100644 --- a/MountAws/Services/Ecs/EcsApiExtensions.cs +++ b/MountAws/Services/Ecs/EcsApiExtensions.cs @@ -35,11 +35,11 @@ public static IEnumerable ListClusters(this IAmazonECS ecs) public static IEnumerable DescribeClusters(this IAmazonECS ecs, IEnumerable clusters, IEnumerable? include = null) { - return ecs.DescribeClustersAsync(new DescribeClustersRequest + return clusters.Chunk(100).SelectMany(clustersPage => ecs.DescribeClustersAsync(new DescribeClustersRequest { - Clusters = clusters.ToList(), + Clusters = clustersPage.ToList(), Include = include?.ToList() - }).GetAwaiter().GetResult().Clusters; + }).GetAwaiter().GetResult().Clusters); } public static Cluster DescribeCluster(this IAmazonECS ecs, string cluster, IEnumerable? include = null) diff --git a/MountAws/Services/Ecs/EcsRoutes.cs b/MountAws/Services/Ecs/EcsRoutes.cs index b35881e..f180951 100644 --- a/MountAws/Services/Ecs/EcsRoutes.cs +++ b/MountAws/Services/Ecs/EcsRoutes.cs @@ -1,4 +1,5 @@ using MountAnything.Routing; +using MountAws.Services.AppAutoscaling; namespace MountAws.Services.Ecs; @@ -21,9 +22,13 @@ public void AddServiceRoutes(Route route) }); cluster.MapLiteral("services", services => { - services.Map(service => + services.Map(service => { - service.Map(); + service.MapAppAutoscaling("ecs", item => $"service/{item.UnderlyingObject.ClusterName()}/{item.ItemName}"); + service.MapLiteral("tasks", tasks => + { + tasks.Map(); + }); }); }); }); diff --git a/MountAws/Services/Ecs/ServiceHandler.cs b/MountAws/Services/Ecs/ServiceHandler.cs index b05717d..a049359 100644 --- a/MountAws/Services/Ecs/ServiceHandler.cs +++ b/MountAws/Services/Ecs/ServiceHandler.cs @@ -3,6 +3,7 @@ using Amazon.ECS; using MountAnything; using MountAws.Api.AwsSdk.Ecs; +using MountAws.Services.AppAutoscaling; using MountAws.Services.Ec2; namespace MountAws.Services.Ecs; @@ -36,37 +37,8 @@ public ServiceHandler(ItemPath path, IPathHandlerContext context, IAmazonECS ecs protected override IEnumerable GetChildItemsImpl() { - var taskArns = _ecs.ListTasksByService(_currentCluster.Name, ItemName); - - var tasks = taskArns.Chunk(10).SelectMany(taskArnChunk => - { - return _ecs.DescribeTasks(_currentCluster.Name, - taskArnChunk, - new[] { "TAGS" }); - }); - - var containerInstanceArns = tasks - .Where(t => !string.IsNullOrEmpty(t.ContainerInstanceArn)) - .Select(t => t.ContainerInstanceArn) - .Distinct() - .ToArray(); - Dictionary ec2InstancesByContainerInstanceArn = new Dictionary(); - if (containerInstanceArns.Any()) - { - var containerInstances = _ecs.DescribeContainerInstances(_currentCluster.Name, containerInstanceArns) - .Where(c => !string.IsNullOrEmpty(c.Ec2InstanceId)) - .ToDictionary(i => i.Ec2InstanceId); - - var ec2InstanceIds = containerInstances.Values.Select(c => c.Ec2InstanceId); - ec2InstancesByContainerInstanceArn = _ec2.GetInstancesByIds(ec2InstanceIds) - .Where(instance => containerInstances.ContainsKey(instance.InstanceId)) - .ToDictionary(i => containerInstances[i.InstanceId].ContainerInstanceArn); - } - - return tasks.Select(t => new TaskItem(Path, t, - t.ContainerInstanceArn != null - ? ec2InstancesByContainerInstanceArn.GetValueOrDefault(t.ContainerInstanceArn) - : null, LinkGenerator, useServiceView:true)); + yield return TasksHandler.CreateItem(Path); + yield return AutoscalingHandler.CreateItem(Path); } public void RemoveItem() diff --git a/MountAws/Services/Ecs/TasksHandler.cs b/MountAws/Services/Ecs/TasksHandler.cs new file mode 100644 index 0000000..6e19dc7 --- /dev/null +++ b/MountAws/Services/Ecs/TasksHandler.cs @@ -0,0 +1,64 @@ +using Amazon.EC2; +using Amazon.EC2.Model; +using Amazon.ECS; +using MountAnything; +using MountAws.Api.AwsSdk.Ecs; +using MountAws.Services.Core; +using MountAws.Services.Ec2; + +namespace MountAws.Services.Ecs; + +public class TasksHandler( + ItemPath path, + IPathHandlerContext context, + CurrentCluster currentCluster, + CurrentService currentService, + IAmazonECS ecs, + IAmazonEC2 ec2) : PathHandler(path, context) +{ + public static Item CreateItem(ItemPath parentPath) + { + return new GenericContainerItem(parentPath, "tasks", + "Navigate the ECS tasks in this service"); + } + + protected override IItem? GetItemImpl() + { + return CreateItem(ParentPath); + } + + protected override IEnumerable GetChildItemsImpl() + { + var taskArns = ecs.ListTasksByService(currentCluster.Name, currentService.Name); + + var tasks = taskArns.Chunk(10).SelectMany(taskArnChunk => + { + return ecs.DescribeTasks(currentCluster.Name, + taskArnChunk, + new[] { "TAGS" }); + }); + + var containerInstanceArns = tasks + .Where(t => !string.IsNullOrEmpty(t.ContainerInstanceArn)) + .Select(t => t.ContainerInstanceArn) + .Distinct() + .ToArray(); + Dictionary ec2InstancesByContainerInstanceArn = new Dictionary(); + if (containerInstanceArns.Any()) + { + var containerInstances = ecs.DescribeContainerInstances(currentCluster.Name, containerInstanceArns) + .Where(c => !string.IsNullOrEmpty(c.Ec2InstanceId)) + .ToDictionary(i => i.Ec2InstanceId); + + var ec2InstanceIds = containerInstances.Values.Select(c => c.Ec2InstanceId); + ec2InstancesByContainerInstanceArn = ec2.GetInstancesByIds(ec2InstanceIds) + .Where(instance => containerInstances.ContainsKey(instance.InstanceId)) + .ToDictionary(i => containerInstances[i.InstanceId].ContainerInstanceArn); + } + + return tasks.Select(t => new TaskItem(Path, t, + t.ContainerInstanceArn != null + ? ec2InstancesByContainerInstanceArn.GetValueOrDefault(t.ContainerInstanceArn) + : null, LinkGenerator, useServiceView:true)); + } +} \ No newline at end of file From 0416114b98565b5914672e186d0cf163b782064b Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Sun, 1 Mar 2026 19:51:00 -0800 Subject: [PATCH 4/5] Fixed some issues with browsing dynamodb tables after shuffling the hierarchy. --- MountAws/Services/DynamoDb/CurrentTable.cs | 8 ++++++++ MountAws/Services/DynamoDb/Routes.cs | 4 ++-- .../{ItemHandler.cs => TableItemHandler.cs} | 18 ++++++++---------- .../Services/DynamoDb/TableItemsHandler.cs | 10 +++++++--- 4 files changed, 25 insertions(+), 15 deletions(-) create mode 100644 MountAws/Services/DynamoDb/CurrentTable.cs rename MountAws/Services/DynamoDb/{ItemHandler.cs => TableItemHandler.cs} (50%) diff --git a/MountAws/Services/DynamoDb/CurrentTable.cs b/MountAws/Services/DynamoDb/CurrentTable.cs new file mode 100644 index 0000000..0dd4926 --- /dev/null +++ b/MountAws/Services/DynamoDb/CurrentTable.cs @@ -0,0 +1,8 @@ +using MountAnything; + +namespace MountAws.Services.DynamoDb; + +public class CurrentTable(string tableName) : TypedString(tableName) +{ + public string Name => Value; +} \ No newline at end of file diff --git a/MountAws/Services/DynamoDb/Routes.cs b/MountAws/Services/DynamoDb/Routes.cs index 6b164bc..be396c0 100644 --- a/MountAws/Services/DynamoDb/Routes.cs +++ b/MountAws/Services/DynamoDb/Routes.cs @@ -11,12 +11,12 @@ public void AddServiceRoutes(Route regionRoute) { dynamodb.MapLiteral("tables", tables => { - tables.Map(table => + tables.Map(table => { table.MapAppAutoscaling("dynamodb", item => $"table/{item.ItemName}"); table.MapLiteral("items", items => { - items.MapRegex(@"[a-z0-9-_\.\,]+"); + items.MapRegex(@"[a-z0-9-_\.\,]+"); }); }); }); diff --git a/MountAws/Services/DynamoDb/ItemHandler.cs b/MountAws/Services/DynamoDb/TableItemHandler.cs similarity index 50% rename from MountAws/Services/DynamoDb/ItemHandler.cs rename to MountAws/Services/DynamoDb/TableItemHandler.cs index ccd4c4e..c747da8 100644 --- a/MountAws/Services/DynamoDb/ItemHandler.cs +++ b/MountAws/Services/DynamoDb/TableItemHandler.cs @@ -3,20 +3,18 @@ namespace MountAws.Services.DynamoDb; -public class ItemHandler : PathHandler +public class TableItemHandler( + ItemPath path, + IPathHandlerContext context, + CurrentTable currentTable, + IAmazonDynamoDB dynamo) + : PathHandler(path, context) { - private readonly IAmazonDynamoDB _dynamo; - - public ItemHandler(ItemPath path, IPathHandlerContext context, IAmazonDynamoDB dynamo) : base(path, context) - { - _dynamo = dynamo; - } - protected override IItem? GetItemImpl() { - var table = _dynamo.DescribeTable(ParentPath.Name); + var table = dynamo.DescribeTable(currentTable.Name); var keys = ItemName.Split(","); - var item = _dynamo.GetItem(table, keys); + var item = dynamo.GetItem(table, keys); return new DynamoItem(ParentPath, table.KeySchema, item); } diff --git a/MountAws/Services/DynamoDb/TableItemsHandler.cs b/MountAws/Services/DynamoDb/TableItemsHandler.cs index 9af735a..2e068b5 100644 --- a/MountAws/Services/DynamoDb/TableItemsHandler.cs +++ b/MountAws/Services/DynamoDb/TableItemsHandler.cs @@ -5,7 +5,11 @@ namespace MountAws.Services.DynamoDb; -public class TableItemsHandler(ItemPath path, IPathHandlerContext context, IAmazonDynamoDB dynamo) : PathHandler(path, context), IGetChildItemParameters +public class TableItemsHandler( + ItemPath path, + IPathHandlerContext context, + CurrentTable currentTable, + IAmazonDynamoDB dynamo) : PathHandler(path, context), IGetChildItemParameters { public static IItem CreateItem(ItemPath parentPath) { @@ -19,9 +23,9 @@ public static IItem CreateItem(ItemPath parentPath) protected override IEnumerable GetChildItemsImpl() { - var table = dynamo.DescribeTable(ItemName); + var table = dynamo.DescribeTable(currentTable.Name); - return dynamo.Scan(ItemName, GetChildItemParameters.Limit).Select(v => new DynamoItem(Path, table.KeySchema, v)); + return dynamo.Scan(currentTable.Name, GetChildItemParameters.Limit).Select(v => new DynamoItem(Path, table.KeySchema, v)); } // since we don't return the full child item set, we don't want the list of children cached From 2e167ad2e8f3807b03a25ed21912d6dcaa5e65c5 Mon Sep 17 00:00:00 2001 From: Andy Alm Date: Sun, 1 Mar 2026 20:02:32 -0800 Subject: [PATCH 5/5] Removed autoscaling service from child items of the region --- .../Services/AppAutoscaling/RootHandler.cs | 27 ------------------- MountAws/Services/Core/RegionHandler.cs | 2 -- 2 files changed, 29 deletions(-) delete mode 100644 MountAws/Services/AppAutoscaling/RootHandler.cs diff --git a/MountAws/Services/AppAutoscaling/RootHandler.cs b/MountAws/Services/AppAutoscaling/RootHandler.cs deleted file mode 100644 index c5be943..0000000 --- a/MountAws/Services/AppAutoscaling/RootHandler.cs +++ /dev/null @@ -1,27 +0,0 @@ -using MountAnything; -using MountAws.Services.Core; - -namespace MountAws.Services.AppAutoscaling; - -public class RootHandler : PathHandler -{ - public static Item CreateItem(ItemPath parentPath) - { - return new GenericContainerItem(parentPath, "autoscaling", - "Navigate application autoscaling dimensions"); - } - - public RootHandler(ItemPath path, IPathHandlerContext context) : base(path, context) - { - } - - protected override IItem? GetItemImpl() - { - return CreateItem(ParentPath); - } - - protected override IEnumerable GetChildItemsImpl() - { - yield return ServicesHandler.CreateItem(Path); - } -} diff --git a/MountAws/Services/Core/RegionHandler.cs b/MountAws/Services/Core/RegionHandler.cs index b2a16c9..d3d2aa8 100644 --- a/MountAws/Services/Core/RegionHandler.cs +++ b/MountAws/Services/Core/RegionHandler.cs @@ -1,6 +1,5 @@ using Amazon; using MountAnything; -using MountAws.Services.AppAutoscaling; using MountAws.Services.Cloudfront; using MountAws.Services.Core; using MountAws.Services.DynamoDb; @@ -38,7 +37,6 @@ public RegionHandler(ItemPath path, IPathHandlerContext context) : base(path, co protected override IEnumerable GetChildItemsImpl() { - yield return RootHandler.CreateItem(Path); yield return CloudfrontRootHandler.CreateItem(Path); yield return Services.Cloudwatch.RootHandler.CreateItem(Path); yield return DynamoDbRootHandler.CreateItem(Path);