Skip to content

Commit

Permalink
Added initial support for Elasticache
Browse files Browse the repository at this point in the history
  • Loading branch information
andyalm committed May 9, 2022
1 parent 1de8674 commit 38c362b
Show file tree
Hide file tree
Showing 17 changed files with 492 additions and 0 deletions.
1 change: 1 addition & 0 deletions MountAws/MountAws.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
<PackageReference Include="AWSSDK.Cloudfront" Version="3.7.*" />
<PackageReference Include="AWSSDK.IdentityManagement" Version="3.7.*" />
<PackageReference Include="AWSSDK.DynamoDBv2" Version="3.7.*" />
<PackageReference Include="AWSSDK.ElastiCache" Version="3.7.*" />
</ItemGroup>

<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions MountAws/Services/Core/RegionHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ protected override IEnumerable<IItem> GetChildItemsImpl()
yield return Ec2RootHandler.CreateItem(Path);
yield return EcrRootHandler.CreateItem(Path);
yield return ECSRootHandler.CreateItem(Path);
yield return Services.Elasticache.RootHandler.CreateItem(Path);
yield return Elbv2RootHandler.CreateItem(Path);
yield return IamRootHandler.CreateItem(Path);
yield return Route53RootHandler.CreateItem(Path);
Expand Down
53 changes: 53 additions & 0 deletions MountAws/Services/Elasticache/ApiExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using Amazon.ElastiCache;
using Amazon.ElastiCache.Model;

using static MountAws.PagingHelper;

namespace MountAws.Services.Elasticache;

public static class ApiExtensions
{
public static IEnumerable<CacheCluster> DescribeCacheClusters(this IAmazonElastiCache elastiCache, bool replicationGroups)
{
return Paginate(nextToken =>
{
var response = elastiCache.DescribeCacheClustersAsync(new DescribeCacheClustersRequest
{
Marker = nextToken,
ShowCacheClustersNotInReplicationGroups = !replicationGroups
}).GetAwaiter().GetResult();

return (response.CacheClusters, response.Marker);
});
}

public static CacheCluster DescribeCacheCluster(this IAmazonElastiCache elastiCache, string id, bool includeNodeInfo = false)
{
return elastiCache.DescribeCacheClustersAsync(new DescribeCacheClustersRequest
{
CacheClusterId = id,
ShowCacheNodeInfo = includeNodeInfo
}).GetAwaiter().GetResult().CacheClusters.Single();
}

public static IEnumerable<ReplicationGroup> DescribeReplicationGroups(this IAmazonElastiCache elastiCache)
{
return Paginate(nextToken =>
{
var response = elastiCache.DescribeReplicationGroupsAsync(new DescribeReplicationGroupsRequest
{
Marker = nextToken
}).GetAwaiter().GetResult();

return (response.ReplicationGroups, response.Marker);
});
}

public static ReplicationGroup DescribeReplicationGroup(this IAmazonElastiCache elastiCache, string id)
{
return elastiCache.DescribeReplicationGroupsAsync(new DescribeReplicationGroupsRequest
{
ReplicationGroupId = id
}).GetAwaiter().GetResult().ReplicationGroups.Single();
}
}
25 changes: 25 additions & 0 deletions MountAws/Services/Elasticache/CacheNodeHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Amazon.ElastiCache;
using MountAnything;

namespace MountAws.Services.Elasticache;

public class CacheNodeHandler : PathHandler
{
private readonly ClusterHandler _parentHandler;

public CacheNodeHandler(ItemPath path, IPathHandlerContext context, IAmazonElastiCache elastiCache) : base(path, context)
{
_parentHandler = new ClusterHandler(path.Parent, context, elastiCache);
}

protected override IItem? GetItemImpl()
{
return _parentHandler.GetChildItems()
.SingleOrDefault(i => i.ItemName.Equals(ItemName, StringComparison.OrdinalIgnoreCase));
}

protected override IEnumerable<IItem> GetChildItemsImpl()
{
yield break;
}
}
23 changes: 23 additions & 0 deletions MountAws/Services/Elasticache/CacheNodeItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Amazon.ElastiCache.Model;
using MountAnything;

namespace MountAws.Services.Elasticache;

public class CacheNodeItem : AwsItem<CacheNode>
{
public CacheNodeItem(ItemPath parentPath, CacheNode cacheNode) : base(parentPath, cacheNode)
{
ItemName = cacheNode.CacheNodeId;
if (cacheNode.Endpoint != null)
{
EndpointAddress = $"{cacheNode.Endpoint.Address}:{cacheNode.Endpoint.Port}";
}
}

public override string ItemName { get; }

[ItemProperty]
public string? EndpointAddress { get; }

public override bool IsContainer => false;
}
43 changes: 43 additions & 0 deletions MountAws/Services/Elasticache/ClusterHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Amazon.ElastiCache;
using Amazon.ElastiCache.Model;
using MountAnything;

namespace MountAws.Services.Elasticache;

public class ClusterHandler : PathHandler
{
private readonly IAmazonElastiCache _elastiCache;

public ClusterHandler(ItemPath path, IPathHandlerContext context, IAmazonElastiCache elastiCache) : base(path, context)
{
_elastiCache = elastiCache;
}

protected override IItem? GetItemImpl()
{
try
{
var cacheCluster = _elastiCache.DescribeCacheCluster(ItemName);

return new ClusterItem(ParentPath, cacheCluster);
}
catch (CacheClusterNotFoundException)
{
return null;
}
}

protected override IEnumerable<IItem> GetChildItemsImpl()
{
try
{
var cacheCluster = _elastiCache.DescribeCacheCluster(ItemName, includeNodeInfo:true);

return cacheCluster.CacheNodes.Select(cacheNode => new CacheNodeItem(Path, cacheNode));
}
catch (CacheClusterNotFoundException)
{
return Enumerable.Empty<IItem>();
}
}
}
16 changes: 16 additions & 0 deletions MountAws/Services/Elasticache/ClusterItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Amazon.ElastiCache.Model;
using MountAnything;

namespace MountAws.Services.Elasticache;

public class ClusterItem : AwsItem<CacheCluster>
{
public ClusterItem(ItemPath parentPath, CacheCluster cacheCluster) : base(parentPath, cacheCluster)
{
ItemName = cacheCluster.CacheClusterId;
}

public override string ItemName { get; }

public override bool IsContainer => true;
}
31 changes: 31 additions & 0 deletions MountAws/Services/Elasticache/ClustersHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Amazon.ElastiCache;
using MountAnything;
using MountAws.Services.Core;

namespace MountAws.Services.Elasticache;

public class ClustersHandler : PathHandler
{
public static IItem CreateItem(ItemPath parentPath)
{
return new GenericContainerItem(parentPath, "clusters",
"Navigate elasticache memcached and single-node redis clusters");
}

private readonly IAmazonElastiCache _elastiCache;

public ClustersHandler(ItemPath path, IPathHandlerContext context, IAmazonElastiCache elastiCache) : base(path, context)
{
_elastiCache = elastiCache;
}

protected override IItem? GetItemImpl()
{
return CreateItem(ParentPath);
}

protected override IEnumerable<IItem> GetChildItemsImpl()
{
return _elastiCache.DescribeCacheClusters(replicationGroups:false).Select(cacheCluster => new ClusterItem(Path, cacheCluster));
}
}
117 changes: 117 additions & 0 deletions MountAws/Services/Elasticache/Formats.ps1xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<Configuration>
<ViewDefinitions>
<View>
<Name>ElasticacheReplicationGroupItem</Name>
<ViewSelectedBy>
<TypeName>MountAws.Services.Elasticache.ReplicationGroupItem</TypeName>
</ViewSelectedBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
</TableColumnHeader>
<TableColumnHeader>
</TableColumnHeader>
<TableColumnHeader>
</TableColumnHeader>
<TableColumnHeader>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>Name</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>CacheNodeType</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>MemberCount</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Description</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
<View>
<Name>ElasticacheCacheClusterItem</Name>
<ViewSelectedBy>
<TypeName>MountAws.Services.Elasticache.ClusterItem</TypeName>
</ViewSelectedBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
</TableColumnHeader>
<TableColumnHeader>
</TableColumnHeader>
<TableColumnHeader>
</TableColumnHeader>
<TableColumnHeader>
</TableColumnHeader>
<TableColumnHeader>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>CacheClusterId</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Engine</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>EngineVersion</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>CacheNodeType</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>NumCacheNodes</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
<View>
<Name>ElasticacheCacheCacheNodeItem</Name>
<ViewSelectedBy>
<TypeName>MountAws.Services.Elasticache.CacheNodeItem</TypeName>
</ViewSelectedBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
</TableColumnHeader>
<TableColumnHeader>
</TableColumnHeader>
<TableColumnHeader>
</TableColumnHeader>
<TableColumnHeader>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>CacheNodeId</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>CustomerAvailabilityZone</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>EndpointAddress</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>CacheNodeStatus</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
</ViewDefinitions>
</Configuration>
15 changes: 15 additions & 0 deletions MountAws/Services/Elasticache/Registrar.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Amazon;
using Amazon.ElastiCache;
using Amazon.Runtime;
using Autofac;

namespace MountAws.Services.Elasticache;

public class Registrar : IServiceRegistrar
{
public void Register(ContainerBuilder builder)
{
builder.RegisterType<AmazonElastiCacheClient>().As<IAmazonElastiCache>()
.UsingConstructor(typeof(AWSCredentials), typeof(RegionEndpoint));
}
}
37 changes: 37 additions & 0 deletions MountAws/Services/Elasticache/ReplicationGroupHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Amazon.ElastiCache;
using Amazon.ElastiCache.Model;
using MountAnything;

namespace MountAws.Services.Elasticache;

public class ReplicationGroupHandler : PathHandler
{
private readonly IAmazonElastiCache _elastiCache;

public ReplicationGroupHandler(ItemPath path, IPathHandlerContext context, IAmazonElastiCache elastiCache) : base(path, context)
{
_elastiCache = elastiCache;
}

protected override IItem? GetItemImpl()
{
try
{
var replicationGroup = _elastiCache.DescribeReplicationGroup(ItemName);

return new ReplicationGroupItem(ParentPath, replicationGroup);
}
catch (ReplicationGroupNotFoundException)
{
return null;
}
}

protected override IEnumerable<IItem> GetChildItemsImpl()
{
return _elastiCache.DescribeCacheClusters(replicationGroups: true)
.Where(c => c.ReplicationGroupId?.Equals(ItemName,
StringComparison.OrdinalIgnoreCase) == true)
.Select(c => new ClusterItem(Path, c));
}
}
Loading

0 comments on commit 38c362b

Please sign in to comment.