Files
bpsets/src/bpsets/elasticache/ElastiCacheRedisClusterAutomaticBackupCheck.ts
Minhyeok Park 2b0b862345
All checks were successful
/ deploy_site (push) Successful in 2m24s
feat: move external metadata to embeded
2025-01-02 20:11:14 +09:00

118 lines
3.7 KiB
TypeScript

import {
ElastiCacheClient,
DescribeReplicationGroupsCommand,
ModifyReplicationGroupCommand,
} from '@aws-sdk/client-elasticache';
import { BPSet, BPSetStats, BPSetFixFn } from '../../types';
import { Memorizer } from '../../Memorizer';
export class ElastiCacheRedisClusterAutomaticBackupCheck implements BPSet {
private readonly client = new ElastiCacheClient({});
private readonly memoClient = Memorizer.memo(this.client);
private readonly getReplicationGroups = async () => {
const response = await this.memoClient.send(new DescribeReplicationGroupsCommand({}));
return response.ReplicationGroups || [];
};
public readonly getMetadata = () => ({
name: 'ElastiCacheRedisClusterAutomaticBackupCheck',
description: 'Ensures that Redis clusters in ElastiCache have automatic backups enabled.',
priority: 2,
priorityReason: 'Automatic backups are crucial for disaster recovery and data safety.',
awsService: 'ElastiCache',
awsServiceCategory: 'Cache Service',
bestPracticeCategory: 'Reliability',
requiredParametersForFix: [
{
name: 'snapshot-retention-period',
description: 'Number of days to retain automatic snapshots.',
default: '7',
example: '7',
},
],
isFixFunctionUsesDestructiveCommand: false,
commandUsedInCheckFunction: [
{
name: 'DescribeReplicationGroupsCommand',
reason: 'Fetches details of replication groups to verify backup settings.',
},
],
commandUsedInFixFunction: [
{
name: 'ModifyReplicationGroupCommand',
reason: 'Enables automatic snapshots and sets the retention period for Redis clusters.',
},
],
adviseBeforeFixFunction: 'Ensure that enabling snapshots does not conflict with operational or compliance requirements.',
});
private readonly stats: BPSetStats = {
compliantResources: [],
nonCompliantResources: [],
status: 'LOADED',
errorMessage: [],
};
public readonly getStats = () => this.stats;
public readonly clearStats = () => {
this.stats.compliantResources = [];
this.stats.nonCompliantResources = [];
this.stats.status = 'LOADED';
this.stats.errorMessage = [];
};
public readonly check = async () => {
this.stats.status = 'CHECKING';
await this.checkImpl().then(
() => (this.stats.status = 'FINISHED'),
(err) => {
this.stats.status = 'ERROR';
this.stats.errorMessage.push({
date: new Date(),
message: err.message,
});
}
);
};
private readonly checkImpl = async () => {
const compliantResources: string[] = [];
const nonCompliantResources: string[] = [];
const replicationGroups = await this.getReplicationGroups();
for (const group of replicationGroups) {
if (group.SnapshottingClusterId) {
compliantResources.push(group.ARN!);
} else {
nonCompliantResources.push(group.ARN!);
}
}
this.stats.compliantResources = compliantResources;
this.stats.nonCompliantResources = nonCompliantResources;
};
public readonly fix: BPSetFixFn = async (nonCompliantResources, requiredParametersForFix) => {
const retentionPeriod = requiredParametersForFix.find(
(param) => param.name === 'snapshot-retention-period'
)?.value;
if (!retentionPeriod) {
throw new Error("Required parameter 'snapshot-retention-period' is missing.");
}
for (const arn of nonCompliantResources) {
const groupId = arn.split(':replication-group:')[1];
await this.client.send(
new ModifyReplicationGroupCommand({
ReplicationGroupId: groupId,
SnapshotRetentionLimit: parseInt(retentionPeriod, 10),
})
);
}
};
}