import { Composite, mergeDefaults } from "@intentius/chant"; import { DbInstance, RDSDBSubnetGroup, RDSDBParameterGroup, SecurityGroup, SecurityGroup_Ingress, } from "../generated"; // A Map (not a Record) so the per-engine lookup uses `.get()` rather than the // computed `ENGINE_DEFAULTS[engine]` element access the evaluability lint flags (#952). const ENGINE_DEFAULTS = new Map([ ["postgres", { port: 5432, username: "postgres", version: "16.6", logExport: "postgresql" }], ["mysql", { port: 3306, username: "admin", version: "8.0.40", logExport: "general" }], ["mariadb", { port: 3306, username: "admin", version: "11.4.3", logExport: "general" }], ]); export interface RdsInstanceProps { // ── Engine ────────────────────────────────────────────────────── engine?: "postgres" | "mysql" | "mariadb"; // ── Networking (required) ───────────────────────────────────── vpcId: string; subnetIds: string[]; ingressSourceSG?: string; ingressCidr?: string; port?: number; publiclyAccessible?: boolean; // ── Identity & auth (required) ──────────────────────────────── masterUsername?: string; masterPassword: string; // ── Engine version ────────────────────────────────────────────── engineVersion?: string; databaseName?: string; // ── Instance sizing ─────────────────────────────────────────── instanceClass?: string; allocatedStorage?: number; storageType?: string; maxAllocatedStorage?: number; // ── High availability ───────────────────────────────────────── multiAZ?: boolean; // ── Encryption ──────────────────────────────────────────────── storageEncrypted?: boolean; kmsKeyId?: string; // ── Backup ──────────────────────────────────────────────────── backupRetentionPeriod?: number; preferredBackupWindow?: string; copyTagsToSnapshot?: boolean; // ── Maintenance ─────────────────────────────────────────────── preferredMaintenanceWindow?: string; autoMinorVersionUpgrade?: boolean; // ── Monitoring ──────────────────────────────────────────────── enableCloudwatchLogs?: boolean; enablePerformanceInsights?: boolean; performanceInsightsRetentionPeriod?: number; // ── Parameter group ─────────────────────────────────────────── parameterGroupFamily?: string; parameters?: Record; // ── Protection ──────────────────────────────────────────────── deletionProtection?: boolean; defaults?: { subnetGroup?: Partial[0]>; sg?: Partial[0]>; db?: Partial[0]>; parameterGroup?: Partial[0]>; }; } export const RdsInstance = Composite((props: RdsInstanceProps) => { const engine = props.engine ?? "postgres"; const defaults = ENGINE_DEFAULTS.get(engine)!; const port = props.port ?? defaults.port; const masterUsername = props.masterUsername ?? defaults.username; const engineVersion = props.engineVersion ?? defaults.version; const instanceClass = props.instanceClass ?? "db.t4g.micro"; const allocatedStorage = props.allocatedStorage ?? 20; const storageType = props.storageType ?? "gp3"; const multiAZ = props.multiAZ ?? false; const storageEncrypted = props.storageEncrypted ?? true; const backupRetentionPeriod = props.backupRetentionPeriod ?? 7; const copyTagsToSnapshot = props.copyTagsToSnapshot ?? true; const autoMinorVersionUpgrade = props.autoMinorVersionUpgrade ?? true; const publiclyAccessible = props.publiclyAccessible ?? false; const deletionProtection = props.deletionProtection ?? false; const { defaults: defs } = props; // DB Subnet Group const subnetGroup = new RDSDBSubnetGroup(mergeDefaults({ DBSubnetGroupDescription: "Subnet group for RDS instance", SubnetIds: props.subnetIds, }, defs?.subnetGroup)); // Security Group // Ternary (not push-inside-if) keeps the `new`s out of control flow (EVL002). const ingressRules: InstanceType[] = props.ingressSourceSG ? [new SecurityGroup_Ingress({ IpProtocol: "tcp", FromPort: port, ToPort: port, SourceSecurityGroupId: props.ingressSourceSG })] : props.ingressCidr ? [new SecurityGroup_Ingress({ IpProtocol: "tcp", FromPort: port, ToPort: port, CidrIp: props.ingressCidr })] : []; const sg = new SecurityGroup(mergeDefaults({ GroupDescription: "Security group for RDS instance", VpcId: props.vpcId, SecurityGroupIngress: ingressRules.length > 0 ? ingressRules : undefined, }, defs?.sg)); // Optional Parameter Group — ternary keeps the `new` out of the `if` (EVL002). const parameterGroup: InstanceType | undefined = props.parameterGroupFamily ? new RDSDBParameterGroup(mergeDefaults({ Family: props.parameterGroupFamily, Description: "Custom parameter group", Parameters: props.parameters, }, defs?.parameterGroup)) : undefined; // DB Instance const dbProps: Record = { Engine: engine, EngineVersion: engineVersion, DBInstanceClass: instanceClass, MasterUsername: masterUsername, MasterUserPassword: props.masterPassword, AllocatedStorage: String(allocatedStorage), StorageType: storageType, DBSubnetGroupName: subnetGroup.Ref, VPCSecurityGroups: [sg.GroupId], Port: String(port), PubliclyAccessible: publiclyAccessible, MultiAZ: multiAZ, StorageEncrypted: storageEncrypted, BackupRetentionPeriod: backupRetentionPeriod, CopyTagsToSnapshot: copyTagsToSnapshot, AutoMinorVersionUpgrade: autoMinorVersionUpgrade, DeletionProtection: deletionProtection, }; if (props.databaseName) dbProps.DBName = props.databaseName; if (props.kmsKeyId) dbProps.KmsKeyId = props.kmsKeyId; if (props.maxAllocatedStorage) dbProps.MaxAllocatedStorage = props.maxAllocatedStorage; if (props.preferredBackupWindow) dbProps.PreferredBackupWindow = props.preferredBackupWindow; if (props.preferredMaintenanceWindow) dbProps.PreferredMaintenanceWindow = props.preferredMaintenanceWindow; if (props.enableCloudwatchLogs) dbProps.EnableCloudwatchLogsExports = [defaults.logExport]; if (props.enablePerformanceInsights) { dbProps.EnablePerformanceInsights = true; if (props.performanceInsightsRetentionPeriod) { dbProps.PerformanceInsightsRetentionPeriod = props.performanceInsightsRetentionPeriod; } } if (parameterGroup) dbProps.DBParameterGroupName = parameterGroup.Ref; const db = new DbInstance(mergeDefaults(dbProps, defs?.db)); const result: Record = { subnetGroup, sg, db }; if (parameterGroup) result.parameterGroup = parameterGroup; return result; }, "RdsInstance");