cdk-dms-replication 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,213 @@
1
+ #!/usr/bin/env node
2
+ // Queries the DMS API for orderable replication instance classes and
3
+ // regenerates the ReplicationInstanceClass enum in src/enums.ts.
4
+ //
5
+ // Usage:
6
+ // node scripts/sync-instance-classes.js
7
+ // AWS_REGION=eu-west-1 node scripts/sync-instance-classes.js
8
+ //
9
+ // Requires: AWS CLI configured with dms:DescribeOrderableReplicationInstances
10
+ 'use strict';
11
+
12
+ const { execSync } = require('child_process');
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+
16
+ const REGION = process.env.AWS_REGION ?? 'us-east-1';
17
+ const ENUMS_FILE = path.resolve(__dirname, '..', 'src', 'enums.ts');
18
+
19
+ // Known family descriptions and preferred display order.
20
+ // Unknown families (if AWS adds a new one) appear at the end, alphabetically.
21
+ const FAMILY_META = {
22
+ 't3': 'T3 — burstable general purpose',
23
+ 'c5': 'C5 — compute optimized (previous generation)',
24
+ 'c6i': 'C6i — compute optimized (current generation)',
25
+ 'c7i': 'C7i — compute optimized (latest generation)',
26
+ 'x7i': 'X7i — compute optimized (latest generation, larger sizes)',
27
+ 'r5': 'R5 — memory optimized (previous generation)',
28
+ 'r6i': 'R6i — memory optimized (current generation)',
29
+ 'r7i': 'R7i — memory optimized (latest generation)',
30
+ };
31
+
32
+ const SIZE_ORDER = [
33
+ 'micro', 'small', 'medium', 'large',
34
+ 'xlarge', '2xlarge', '4xlarge', '8xlarge', '9xlarge',
35
+ '12xlarge', '16xlarge', '18xlarge', '24xlarge', '32xlarge', '48xlarge',
36
+ ];
37
+
38
+ // ---------------------------------------------------------------------------
39
+ // AWS API
40
+ // ---------------------------------------------------------------------------
41
+
42
+ function fetchInstanceClasses() {
43
+ const all = new Set();
44
+ let marker;
45
+
46
+ do {
47
+ const markerArg = marker ? `--marker "${marker}"` : '';
48
+ const raw = execSync(
49
+ `aws dms describe-orderable-replication-instances --region ${REGION} ${markerArg} --output json`,
50
+ { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] },
51
+ );
52
+ const page = JSON.parse(raw);
53
+ for (const inst of page.OrderableReplicationInstances ?? []) {
54
+ all.add(inst.ReplicationInstanceClass);
55
+ }
56
+ marker = page.Marker || undefined;
57
+ } while (marker);
58
+
59
+ return [...all];
60
+ }
61
+
62
+ // ---------------------------------------------------------------------------
63
+ // Enum generation
64
+ // ---------------------------------------------------------------------------
65
+
66
+ function getFamily(cls) {
67
+ return cls.replace('dms.', '').split('.')[0];
68
+ }
69
+
70
+ function sizeRank(cls) {
71
+ const size = cls.split('.').pop();
72
+ const idx = SIZE_ORDER.indexOf(size);
73
+ return idx === -1 ? 999 : idx;
74
+ }
75
+
76
+ function toEnumKey(cls) {
77
+ return cls.replace('dms.', '').replace(/\./g, '_').toUpperCase();
78
+ }
79
+
80
+ function buildEnumBody(classes) {
81
+ // Group by family
82
+ const grouped = {};
83
+ for (const cls of classes) {
84
+ const f = getFamily(cls);
85
+ (grouped[f] = grouped[f] ?? []).push(cls);
86
+ }
87
+
88
+ // Sort within each family by size
89
+ for (const f of Object.keys(grouped)) {
90
+ grouped[f].sort((a, b) => sizeRank(a) - sizeRank(b));
91
+ }
92
+
93
+ // Sort families: known order first, then unknowns alphabetically
94
+ const knownOrder = Object.keys(FAMILY_META);
95
+ const families = Object.keys(grouped).sort((a, b) => {
96
+ const ai = knownOrder.indexOf(a);
97
+ const bi = knownOrder.indexOf(b);
98
+ if (ai !== -1 && bi !== -1) return ai - bi;
99
+ if (ai !== -1) return -1;
100
+ if (bi !== -1) return 1;
101
+ return a.localeCompare(b);
102
+ });
103
+
104
+ const lines = [];
105
+ for (let i = 0; i < families.length; i++) {
106
+ const f = families[i];
107
+ const comment = FAMILY_META[f] ?? `${f.toUpperCase()} instances`;
108
+ lines.push(` // ${comment}`);
109
+ for (const cls of grouped[f]) {
110
+ lines.push(` ${toEnumKey(cls)} = '${cls}',`);
111
+ }
112
+ if (i < families.length - 1) lines.push('');
113
+ }
114
+
115
+ return lines.join('\n');
116
+ }
117
+
118
+ // ---------------------------------------------------------------------------
119
+ // File update
120
+ // ---------------------------------------------------------------------------
121
+
122
+ function replaceEnum(filePath, enumBody) {
123
+ const content = fs.readFileSync(filePath, 'utf-8');
124
+ const lines = content.split('\n');
125
+
126
+ // Find the line with 'export enum ReplicationInstanceClass {'
127
+ let enumLineIdx = -1;
128
+ for (let i = 0; i < lines.length; i++) {
129
+ if (/^export enum ReplicationInstanceClass\s*\{/.test(lines[i])) {
130
+ enumLineIdx = i;
131
+ break;
132
+ }
133
+ }
134
+ if (enumLineIdx === -1) throw new Error('Cannot find ReplicationInstanceClass enum');
135
+
136
+ // Walk back to include the preceding JSDoc comment block
137
+ let blockStart = enumLineIdx;
138
+ for (let i = enumLineIdx - 1; i >= 0; i--) {
139
+ const t = lines[i].trim();
140
+ if (t.startsWith('/**') || t.startsWith('*') || t === '*/') {
141
+ blockStart = i;
142
+ } else {
143
+ break;
144
+ }
145
+ }
146
+
147
+ // Walk forward, counting braces, to find the closing '}'
148
+ let depth = 0;
149
+ let blockEnd = -1;
150
+ for (let i = enumLineIdx; i < lines.length; i++) {
151
+ for (const ch of lines[i]) {
152
+ if (ch === '{') depth++;
153
+ if (ch === '}') depth--;
154
+ }
155
+ if (depth === 0) { blockEnd = i; break; }
156
+ }
157
+ if (blockEnd === -1) throw new Error('Cannot find closing brace of ReplicationInstanceClass enum');
158
+
159
+ const newBlock = [
160
+ '/**',
161
+ ' * DMS replication instance class.',
162
+ ' *',
163
+ ' * @see https://docs.aws.amazon.com/dms/latest/userguide/CHAP_ReplicationInstance.Types.html',
164
+ ' */',
165
+ 'export enum ReplicationInstanceClass {',
166
+ enumBody,
167
+ '}',
168
+ ].join('\n');
169
+
170
+ const before = lines.slice(0, blockStart).join('\n');
171
+ const after = lines.slice(blockEnd + 1).join('\n');
172
+ return (before ? before + '\n' : '') + newBlock + (after ? '\n' + after : '');
173
+ }
174
+
175
+ // ---------------------------------------------------------------------------
176
+ // Main
177
+ // ---------------------------------------------------------------------------
178
+
179
+ function main() {
180
+ process.stdout.write(`Querying DMS orderable instances in ${REGION}... `);
181
+
182
+ let classes;
183
+ try {
184
+ classes = fetchInstanceClasses();
185
+ } catch (err) {
186
+ console.error('\nFailed to call DMS API:', err.message);
187
+ console.error('Ensure AWS credentials are configured with dms:DescribeOrderableReplicationInstances.');
188
+ process.exit(1);
189
+ }
190
+ console.log(`${classes.length} classes found.`);
191
+
192
+ const enumBody = buildEnumBody(classes);
193
+ const newContent = replaceEnum(ENUMS_FILE, enumBody);
194
+ const oldContent = fs.readFileSync(ENUMS_FILE, 'utf-8');
195
+
196
+ if (newContent === oldContent) {
197
+ console.log('✓ ReplicationInstanceClass is already up to date.');
198
+ return;
199
+ }
200
+
201
+ // Report the diff before writing
202
+ const oldClasses = new Set([...oldContent.matchAll(/'(dms\.[^']+)'/g)].map(m => m[1]));
203
+ const newClasses = new Set(classes);
204
+ const added = classes.filter(c => !oldClasses.has(c));
205
+ const removed = [...oldClasses].filter(c => !newClasses.has(c));
206
+ if (added.length) console.log(' + Added: ', added.join(', '));
207
+ if (removed.length) console.log(' - Removed:', removed.join(', '));
208
+
209
+ fs.writeFileSync(ENUMS_FILE, newContent);
210
+ console.log('✓ Updated src/enums.ts');
211
+ }
212
+
213
+ main();