@fjall/components-infrastructure 0.96.0 → 0.99.3

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.
Files changed (209) hide show
  1. package/dist/lib/app.d.ts +68 -1
  2. package/dist/lib/app.js +113 -4
  3. package/dist/lib/config/aws/__t17fixture.d.ts +1 -0
  4. package/dist/lib/config/aws/__t17fixture.js +3 -0
  5. package/dist/lib/config/aws/__t17fixtureType.d.ts +2 -0
  6. package/dist/lib/config/aws/__t17fixtureType.js +1 -0
  7. package/dist/lib/config/aws/alarmTopic.js +8 -4
  8. package/dist/lib/config/aws/cloudTrail.js +1 -1
  9. package/dist/lib/config/aws/disasterRecovery.js +11 -16
  10. package/dist/lib/config/aws/ecrDefaultImage.d.ts +0 -1
  11. package/dist/lib/config/aws/ecrDefaultImage.js +13 -23
  12. package/dist/lib/config/aws/identityCenter.d.ts +10 -3
  13. package/dist/lib/config/aws/identityCenter.js +101 -37
  14. package/dist/lib/config/aws/identityCenterGroupMembership.js +8 -2
  15. package/dist/lib/config/aws/identityCenterMembership.d.ts +11 -0
  16. package/dist/lib/config/aws/identityCenterMembership.js +61 -0
  17. package/dist/lib/config/aws/index.d.ts +1 -1
  18. package/dist/lib/config/aws/index.js +1 -1
  19. package/dist/lib/config/aws/ipam.js +6 -11
  20. package/dist/lib/config/aws/oidcConnector.js +5 -1
  21. package/dist/lib/config/aws/scpPreset.js +4 -1
  22. package/dist/lib/patterns/aws/_eslint_test_tmp/leak.d.ts +1 -0
  23. package/dist/lib/patterns/aws/_eslint_test_tmp/leak.js +4 -0
  24. package/dist/lib/patterns/aws/account.js +2 -4
  25. package/dist/lib/patterns/aws/apexDomainPattern.js +10 -10
  26. package/dist/lib/patterns/aws/bastionFactory.d.ts +10 -0
  27. package/dist/lib/patterns/aws/bastionFactory.js +29 -0
  28. package/dist/lib/patterns/aws/buildkite.d.ts +2 -2
  29. package/dist/lib/patterns/aws/buildkite.js +51 -97
  30. package/dist/lib/patterns/aws/cdn.js +1 -1
  31. package/dist/lib/patterns/aws/clickhouseDatabase.d.ts +173 -0
  32. package/dist/lib/patterns/aws/clickhouseDatabase.js +601 -0
  33. package/dist/lib/patterns/aws/compute.d.ts +4 -6
  34. package/dist/lib/patterns/aws/compute.js +7 -13
  35. package/dist/lib/patterns/aws/computeEcs.d.ts +93 -5
  36. package/dist/lib/patterns/aws/computeEcs.js +867 -37
  37. package/dist/lib/patterns/aws/computeEcsTypes.d.ts +528 -25
  38. package/dist/lib/patterns/aws/computeEcsTypes.js +10 -0
  39. package/dist/lib/patterns/aws/computeLambda.d.ts +0 -5
  40. package/dist/lib/patterns/aws/computeLambda.js +1 -2
  41. package/dist/lib/patterns/aws/database.d.ts +50 -8
  42. package/dist/lib/patterns/aws/database.js +183 -27
  43. package/dist/lib/patterns/aws/domain.js +6 -4
  44. package/dist/lib/patterns/aws/index.d.ts +1 -0
  45. package/dist/lib/patterns/aws/index.js +1 -0
  46. package/dist/lib/patterns/aws/interfaces/compute.d.ts +7 -1
  47. package/dist/lib/patterns/aws/interfaces/database.d.ts +187 -8
  48. package/dist/lib/patterns/aws/interfaces/database.js +17 -3
  49. package/dist/lib/patterns/aws/interfaces/index.d.ts +2 -1
  50. package/dist/lib/patterns/aws/interfaces/index.js +3 -1
  51. package/dist/lib/patterns/aws/interfaces/messaging.d.ts +7 -0
  52. package/dist/lib/patterns/aws/interfaces/migrationContributor.d.ts +47 -0
  53. package/dist/lib/patterns/aws/interfaces/migrationContributor.js +9 -0
  54. package/dist/lib/patterns/aws/messaging.d.ts +66 -10
  55. package/dist/lib/patterns/aws/messaging.js +115 -20
  56. package/dist/lib/patterns/aws/network.js +16 -7
  57. package/dist/lib/patterns/aws/organisation.d.ts +4 -0
  58. package/dist/lib/patterns/aws/organisation.js +22 -4
  59. package/dist/lib/patterns/aws/storage.d.ts +1 -2
  60. package/dist/lib/patterns/aws/storage.js +3 -2
  61. package/dist/lib/patterns/aws/vpcPeer.js +3 -1
  62. package/dist/lib/resources/aws/analytics/clickhouse.js +18 -9
  63. package/dist/lib/resources/aws/analytics/clickhouseAlarms.d.ts +24 -9
  64. package/dist/lib/resources/aws/analytics/clickhouseAlarms.js +61 -10
  65. package/dist/lib/resources/aws/analytics/clickhouseConstants.d.ts +3 -3
  66. package/dist/lib/resources/aws/analytics/clickhouseConstants.js +3 -3
  67. package/dist/lib/resources/aws/analytics/clickhouseTypes.d.ts +7 -1
  68. package/dist/lib/resources/aws/analytics/clickhouseUserData.d.ts +1 -1
  69. package/dist/lib/resources/aws/analytics/clickhouseUserData.js +53 -3
  70. package/dist/lib/resources/aws/base/awsStack.js +4 -2
  71. package/dist/lib/resources/aws/compute/__tmp__/regression-shape.d.ts +2 -0
  72. package/dist/lib/resources/aws/compute/__tmp__/regression-shape.js +11 -0
  73. package/dist/lib/resources/aws/compute/asgInlineLifecycleHook.d.ts +52 -0
  74. package/dist/lib/resources/aws/compute/asgInlineLifecycleHook.js +60 -0
  75. package/dist/lib/resources/aws/compute/blockDeviceVolume.d.ts +8 -0
  76. package/dist/lib/resources/aws/compute/blockDeviceVolume.js +10 -0
  77. package/dist/lib/resources/aws/compute/ec2.d.ts +132 -12
  78. package/dist/lib/resources/aws/compute/ec2.js +163 -23
  79. package/dist/lib/resources/aws/compute/ec2GracefulTerminationHandler.d.ts +41 -0
  80. package/dist/lib/resources/aws/compute/ec2GracefulTerminationHandler.js +194 -0
  81. package/dist/lib/resources/aws/compute/ec2GracefulTerminationLambda.source.cjs +458 -0
  82. package/dist/lib/resources/aws/compute/ecs.d.ts +27 -1
  83. package/dist/lib/resources/aws/compute/ecs.js +42 -2
  84. package/dist/lib/resources/aws/compute/ecsConstants.d.ts +9 -0
  85. package/dist/lib/resources/aws/compute/ecsConstants.js +16 -0
  86. package/dist/lib/resources/aws/compute/ecsImages.js +32 -20
  87. package/dist/lib/resources/aws/compute/ecsLifecycleHookMigration.d.ts +96 -0
  88. package/dist/lib/resources/aws/compute/ecsLifecycleHookMigration.js +113 -0
  89. package/dist/lib/resources/aws/compute/ecsNetworking.d.ts +2 -1
  90. package/dist/lib/resources/aws/compute/ecsNetworking.js +18 -6
  91. package/dist/lib/resources/aws/compute/ecsServiceFactory.d.ts +13 -4
  92. package/dist/lib/resources/aws/compute/ecsServiceFactory.js +155 -33
  93. package/dist/lib/resources/aws/compute/ecsTaskDefinition.d.ts +31 -1
  94. package/dist/lib/resources/aws/compute/ecsTaskDefinition.js +102 -6
  95. package/dist/lib/resources/aws/compute/ecsTypes.d.ts +173 -13
  96. package/dist/lib/resources/aws/compute/ecsValidation.d.ts +9 -0
  97. package/dist/lib/resources/aws/compute/ecsValidation.js +63 -0
  98. package/dist/lib/resources/aws/compute/index.d.ts +2 -0
  99. package/dist/lib/resources/aws/compute/index.js +2 -0
  100. package/dist/lib/resources/aws/compute/lambda.d.ts +7 -13
  101. package/dist/lib/resources/aws/compute/lambda.js +30 -38
  102. package/dist/lib/resources/aws/compute/lifecycleHookLambda.source.cjs +192 -0
  103. package/dist/lib/resources/aws/compute/persistentDataVolume.d.ts +104 -0
  104. package/dist/lib/resources/aws/compute/persistentDataVolume.js +245 -0
  105. package/dist/lib/resources/aws/compute/persistentDataVolumeLambda.source.cjs +398 -0
  106. package/dist/lib/resources/aws/compute/samApplication.d.ts +15 -0
  107. package/dist/lib/resources/aws/compute/samApplication.js +27 -0
  108. package/dist/lib/resources/aws/database/clickhouseConstants.d.ts +159 -0
  109. package/dist/lib/resources/aws/database/clickhouseConstants.js +181 -0
  110. package/dist/lib/resources/aws/database/clickhouseSchemas.d.ts +71 -0
  111. package/dist/lib/resources/aws/database/clickhouseSchemas.js +160 -0
  112. package/dist/lib/resources/aws/database/clickhouseSecurityGroup.d.ts +14 -0
  113. package/dist/lib/resources/aws/database/clickhouseSecurityGroup.js +23 -0
  114. package/dist/lib/resources/aws/database/clickhouseUserData.d.ts +69 -0
  115. package/dist/lib/resources/aws/database/clickhouseUserData.js +371 -0
  116. package/dist/lib/resources/aws/database/clickhouseXmlRenderer.d.ts +56 -0
  117. package/dist/lib/resources/aws/database/clickhouseXmlRenderer.js +112 -0
  118. package/dist/lib/resources/aws/database/rdsAurora.d.ts +8 -1
  119. package/dist/lib/resources/aws/database/rdsAurora.js +42 -32
  120. package/dist/lib/resources/aws/database/rdsAuroraGlobal.d.ts +15 -2
  121. package/dist/lib/resources/aws/database/rdsAuroraGlobal.js +39 -43
  122. package/dist/lib/resources/aws/database/rdsDefaults.d.ts +6 -0
  123. package/dist/lib/resources/aws/database/rdsDefaults.js +7 -1
  124. package/dist/lib/resources/aws/database/rdsHelpers.d.ts +3 -3
  125. package/dist/lib/resources/aws/database/rdsHelpers.js +1 -0
  126. package/dist/lib/resources/aws/database/rdsInstance.d.ts +8 -1
  127. package/dist/lib/resources/aws/database/rdsInstance.js +51 -34
  128. package/dist/lib/resources/aws/database/rdsProxyOutput.d.ts +1 -1
  129. package/dist/lib/resources/aws/database/rdsProxyOutput.js +1 -1
  130. package/dist/lib/resources/aws/iam/delegationRole.js +1 -1
  131. package/dist/lib/resources/aws/iam/identityCenter/groupMembership.d.ts +9 -0
  132. package/dist/lib/resources/aws/iam/identityCenter/groupMembership.js +12 -0
  133. package/dist/lib/resources/aws/iam/identityCenter/index.d.ts +1 -0
  134. package/dist/lib/resources/aws/iam/identityCenter/index.js +1 -0
  135. package/dist/lib/resources/aws/iam/identityCenter/permissionSet.d.ts +1 -0
  136. package/dist/lib/resources/aws/iam/identityCenter/permissionSet.js +1 -0
  137. package/dist/lib/resources/aws/logging/logGroup.d.ts +0 -8
  138. package/dist/lib/resources/aws/logging/logGroup.js +0 -11
  139. package/dist/lib/resources/aws/messaging/defaultEventBus.d.ts +7 -0
  140. package/dist/lib/resources/aws/messaging/defaultEventBus.js +21 -0
  141. package/dist/lib/resources/aws/messaging/eventBridgeRule.d.ts +96 -0
  142. package/dist/lib/resources/aws/messaging/eventBridgeRule.js +110 -0
  143. package/dist/lib/resources/aws/messaging/eventTargets.d.ts +84 -0
  144. package/dist/lib/resources/aws/messaging/eventTargets.js +152 -0
  145. package/dist/lib/resources/aws/messaging/eventbridge.d.ts +25 -2
  146. package/dist/lib/resources/aws/messaging/eventbridge.js +22 -10
  147. package/dist/lib/resources/aws/messaging/index.d.ts +5 -0
  148. package/dist/lib/resources/aws/messaging/index.js +2 -0
  149. package/dist/lib/resources/aws/messaging/schedule.d.ts +118 -0
  150. package/dist/lib/resources/aws/messaging/schedule.js +64 -0
  151. package/dist/lib/resources/aws/messaging/sns.d.ts +2 -1
  152. package/dist/lib/resources/aws/messaging/sqs.d.ts +2 -1
  153. package/dist/lib/resources/aws/messaging/subscription.d.ts +112 -0
  154. package/dist/lib/resources/aws/messaging/subscription.js +67 -0
  155. package/dist/lib/resources/aws/messaging/utils.d.ts +6 -0
  156. package/dist/lib/resources/aws/messaging/utils.js +10 -0
  157. package/dist/lib/resources/aws/monitoring/clickhouseAlarms.d.ts +60 -0
  158. package/dist/lib/resources/aws/monitoring/clickhouseAlarms.js +139 -0
  159. package/dist/lib/resources/aws/monitoring/index.d.ts +2 -0
  160. package/dist/lib/resources/aws/monitoring/index.js +2 -0
  161. package/dist/lib/resources/aws/monitoring/scheduleAlarms.d.ts +47 -0
  162. package/dist/lib/resources/aws/monitoring/scheduleAlarms.js +106 -0
  163. package/dist/lib/resources/aws/networking/crossAccountDelegationRecord.js +6 -4
  164. package/dist/lib/resources/aws/networking/crossAccountReturnRoutes.js +17 -13
  165. package/dist/lib/resources/aws/networking/dnsRecord/dnsRecordBase.js +7 -5
  166. package/dist/lib/resources/aws/networking/domainCertificate.d.ts +2 -2
  167. package/dist/lib/resources/aws/networking/domainCertificate.js +6 -4
  168. package/dist/lib/resources/aws/networking/hostedZone.js +6 -5
  169. package/dist/lib/resources/aws/networking/serviceDiscovery.d.ts +96 -0
  170. package/dist/lib/resources/aws/networking/serviceDiscovery.js +96 -0
  171. package/dist/lib/resources/aws/networking/vpc.d.ts +4 -1
  172. package/dist/lib/resources/aws/networking/vpc.js +4 -1
  173. package/dist/lib/resources/aws/networking/vpcPeeringConnection.js +21 -3
  174. package/dist/lib/resources/aws/organisation/costAllocationTagActivator.d.ts +16 -5
  175. package/dist/lib/resources/aws/organisation/costAllocationTagActivator.js +17 -3
  176. package/dist/lib/resources/aws/organisation/index.d.ts +1 -1
  177. package/dist/lib/resources/aws/organisation/organisationPolicy.d.ts +2 -0
  178. package/dist/lib/resources/aws/organisation/organisationPolicy.js +3 -2
  179. package/dist/lib/resources/aws/secrets/secret.d.ts +7 -0
  180. package/dist/lib/resources/aws/secrets/secret.js +4 -3
  181. package/dist/lib/resources/aws/storage/bucketDeployment.d.ts +16 -0
  182. package/dist/lib/resources/aws/storage/bucketDeployment.js +17 -0
  183. package/dist/lib/resources/aws/storage/ecr.js +5 -5
  184. package/dist/lib/resources/aws/storage/index.d.ts +1 -0
  185. package/dist/lib/resources/aws/storage/index.js +1 -0
  186. package/dist/lib/resources/aws/storage/s3.js +10 -3
  187. package/dist/lib/resources/aws/utilities/customResource.js +18 -9
  188. package/dist/lib/synth_dump.d.ts +1 -0
  189. package/dist/lib/synth_dump.js +42 -0
  190. package/dist/lib/utils/cdkContext.d.ts +2 -0
  191. package/dist/lib/utils/cdkContext.js +4 -2
  192. package/dist/lib/utils/connections.js +6 -0
  193. package/dist/lib/utils/connector.d.ts +12 -0
  194. package/dist/lib/utils/costAllocationTags.d.ts +9 -0
  195. package/dist/lib/utils/costAllocationTags.js +11 -1
  196. package/dist/lib/utils/databaseTypes.d.ts +14 -0
  197. package/dist/lib/utils/getConfig.d.ts +2 -0
  198. package/dist/lib/utils/getConfig.js +2 -0
  199. package/dist/lib/utils/index.d.ts +1 -0
  200. package/dist/lib/utils/index.js +1 -0
  201. package/dist/lib/utils/manifestWriter.d.ts +6 -89
  202. package/dist/lib/utils/manifestWriter.js +36 -23
  203. package/dist/lib/utils/migrationVersionResolvers.d.ts +2 -0
  204. package/dist/lib/utils/migrationVersionResolvers.js +2 -0
  205. package/dist/lib/utils/orgConfigParser.js +2 -1
  206. package/dist/lib/utils/resolveAlertsTopic.d.ts +14 -0
  207. package/dist/lib/utils/resolveAlertsTopic.js +30 -0
  208. package/dist/lib/utils/validationLogger.js +6 -3
  209. package/package.json +22 -19
@@ -0,0 +1,371 @@
1
+ import { CLICKHOUSE_DATA_MOUNT_PATH, CLICKHOUSE_EBS_DEVICE_NAME, CLICKHOUSE_CONFIG_SUBDIR, CLICKHOUSE_USERS_SUBDIR, CLICKHOUSE_HTTP_PORT, CLICKHOUSE_PROMETHEUS_PORT, clickHousePasswordSha256Snippet } from "./clickhouseConstants.js";
2
+ import { renderUsersXml } from "./clickhouseXmlRenderer.js";
3
+ export function generateServerConfigXml(options) {
4
+ const { backupBucketName, backupBucketRegion, coldTier } = options;
5
+ const storageBlock = coldTier !== undefined
6
+ ? ` <storage_configuration>
7
+ <!-- Same CH 26 rule as the no-cold-tier branch: a <local_ssd> disk
8
+ whose path equals the global <path> trips UNKNOWN_ELEMENT_IN_CONFIG
9
+ at boot. Use the implicit <default> disk for hot tier; only S3
10
+ cold needs an explicit <disks> entry. -->
11
+ <disks>
12
+ <s3_cold>
13
+ <type>s3</type>
14
+ <endpoint>https://${coldTier.bucketName}.s3.${coldTier.region}.amazonaws.com/cold/</endpoint>
15
+ <use_environment_credentials>true</use_environment_credentials>
16
+ <metadata_path>/var/lib/clickhouse/disks/s3_cold/</metadata_path>
17
+ </s3_cold>
18
+ </disks>
19
+ <policies>
20
+ <tiered>
21
+ <volumes>
22
+ <hot>
23
+ <disk>default</disk>
24
+ </hot>
25
+ <cold>
26
+ <disk>s3_cold</disk>
27
+ </cold>
28
+ </volumes>
29
+ <move_factor>0.05</move_factor>
30
+ </tiered>
31
+ <local_only>
32
+ <volumes>
33
+ <default>
34
+ <disk>default</disk>
35
+ </default>
36
+ </volumes>
37
+ </local_only>
38
+ </policies>
39
+ </storage_configuration>`
40
+ : ` <storage_configuration>
41
+ <!-- CH 26.x reserves the implicit <default> disk and rejects any
42
+ explicit <disks><default>...</default></disks> override whose
43
+ resolved path equals the global <path>:
44
+ "Disk path ('/var/lib/clickhouse/') cannot be equal to <path>.
45
+ Use <default> disk instead. (UNKNOWN_ELEMENT_IN_CONFIG)"
46
+ So we drop the <disks> block entirely; policies referencing
47
+ <disk>default</disk> resolve to CH's built-in default. -->
48
+ <policies>
49
+ <!-- Single-volume tiered policy: 11 schema tables hardcode
50
+ storage_policy='tiered'. -->
51
+ <tiered>
52
+ <volumes>
53
+ <hot>
54
+ <disk>default</disk>
55
+ </hot>
56
+ </volumes>
57
+ </tiered>
58
+ <local_only>
59
+ <volumes>
60
+ <default>
61
+ <disk>default</disk>
62
+ </default>
63
+ </volumes>
64
+ </local_only>
65
+ </policies>
66
+ </storage_configuration>`;
67
+ const backupEndpointBlock = ` <s3>
68
+ <backup_endpoint>
69
+ <endpoint>https://${backupBucketName}.s3.${backupBucketRegion}.amazonaws.com/</endpoint>
70
+ <use_environment_credentials>true</use_environment_credentials>
71
+ </backup_endpoint>
72
+ </s3>`;
73
+ return `<clickhouse>
74
+ <logger>
75
+ <level>warning</level>
76
+ <log>/var/log/clickhouse-server/clickhouse-server.log</log>
77
+ <errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
78
+ <size>100M</size>
79
+ <count>3</count>
80
+ <!-- Mirror to stderr so the awslogs driver captures startup +
81
+ crash banners. File-only logs die with the container. -->
82
+ <console>1</console>
83
+ </logger>
84
+ <!-- Bind to all IPv4 addresses. CH 26 defaults its listener set to
85
+ include \`[::1]\` (IPv6 loopback). Under awsvpc that fails because
86
+ the ENI has no IPv6 loopback assigned (errno 99 EADDRNOTAVAIL on
87
+ 8123 / 9000 / 9004 / 9005 / 9009 / 9363); under host mode it would
88
+ work, but explicit beats implicit and keeps the listener identical
89
+ across network modes. -->
90
+ <listen_host>0.0.0.0</listen_host>
91
+ <!-- m7g.medium tuning philosophy: 1 vCPU sustained / 4 GB / 3 GB container.
92
+ Single-thread CPU has no headroom (raising max_threads beyond 1 just
93
+ oversubscribes the kernel scheduler), so we trade RAM for CPU — size
94
+ caches generously so dashboard reads hit cache rather than rescanning,
95
+ and let a single query use most of the budget if needed.
96
+ Re-tune these in lockstep when DEFAULT_CLICKHOUSE_INSTANCE_TYPE moves
97
+ to a larger box. -->
98
+ <!-- 0.75 ratio gives the kernel ~750 MB cushion on the 3 GB cgroup for
99
+ CH's untracked allocations (libc allocator, executable image, malloc
100
+ fragmentation, jemalloc virtual reservations on ARM64). The default
101
+ 0.9 left only ~300 MB and OOM-killed the process at boot when cache
102
+ + thread init pushed the cgroup over the limit (exit 137 in CW).
103
+ Computed at runtime from the cgroup limit so it tracks instance size
104
+ when DEFAULT_CLICKHOUSE_INSTANCE_TYPE moves to a larger box. -->
105
+ <max_server_memory_usage_to_ram_ratio>0.75</max_server_memory_usage_to_ram_ratio>
106
+ <!-- Per-query caps (max_memory_usage, max_bytes_before_external_sort,
107
+ max_bytes_before_external_group_by) live in the profile blocks of
108
+ users.xml — ClickHouse 26.3.10 rejects them at top level with
109
+ UNKNOWN_ELEMENT_IN_CONFIG. The default localhost user inherits
110
+ ClickHouse's built-in defaults; workload users (app_writer,
111
+ audit_writer, backup_reader, schema_admin) carry explicit caps. -->
112
+ <!-- 384 MB mark cache + 128 MB index mark cache. CH counts these against
113
+ max_server_memory_usage, so the read-cache footprint is 512 MB total
114
+ (~17% of the budget). On a single-tenant dashboard workload this
115
+ pays back fast — same queries repeat, mark hits avoid index re-scans. -->
116
+ <mark_cache_size>402653184</mark_cache_size>
117
+ <index_mark_cache_size>134217728</index_mark_cache_size>
118
+ <!-- Filesystem page cache handles uncompressed-block warmth on the
119
+ host side; an in-CH uncompressed cache would just duplicate it. -->
120
+ <uncompressed_cache_size>0</uncompressed_cache_size>
121
+ <!-- Sized for m7g.medium (1 vCPU sustained). 4 concurrent queries is the
122
+ sweet spot: enough headroom for the OPTIMIZE FINAL sidecar + a single
123
+ dashboard read + one async insert + one ad-hoc, but low enough that
124
+ context switching does not dominate at the kernel scheduler level.
125
+ Bump in lockstep with instance size if DEFAULT_CLICKHOUSE_INSTANCE_TYPE
126
+ moves to a >=2 vCPU host. -->
127
+ <max_concurrent_queries>4</max_concurrent_queries>
128
+ <background_pool_size>2</background_pool_size>
129
+ <background_schedule_pool_size>2</background_schedule_pool_size>
130
+ <background_merges_mutations_concurrency_ratio>2</background_merges_mutations_concurrency_ratio>
131
+ <background_move_pool_size>1</background_move_pool_size>
132
+ <background_fetches_pool_size>1</background_fetches_pool_size>
133
+ <background_message_broker_schedule_pool_size>1</background_message_broker_schedule_pool_size>
134
+ <merge_tree>
135
+ <max_suspicious_broken_parts>5</max_suspicious_broken_parts>
136
+ <parts_to_delay_insert>150</parts_to_delay_insert>
137
+ <parts_to_throw_insert>300</parts_to_throw_insert>
138
+ <!-- ClickHouse 26.3.10 sanity-checks the free-pool thresholds against
139
+ background_pool_size * background_merges_mutations_concurrency_ratio
140
+ (= 2 * 2 = 4 here). The defaults (20 / 8 / 25) all exceed 4 and
141
+ trip BAD_ARGUMENTS at startup on a 1 vCPU m7g.medium. Lower each
142
+ to 1 so a mutation/merge/optimise can begin as soon as one pool
143
+ slot is free — appropriate for the small instance footprint. -->
144
+ <number_of_free_entries_in_pool_to_execute_mutation>1</number_of_free_entries_in_pool_to_execute_mutation>
145
+ <number_of_free_entries_in_pool_to_lower_max_size_of_merge>1</number_of_free_entries_in_pool_to_lower_max_size_of_merge>
146
+ <number_of_free_entries_in_pool_to_execute_optimize_entire_partition>1</number_of_free_entries_in_pool_to_execute_optimize_entire_partition>
147
+ </merge_tree>
148
+ <http_port>${CLICKHOUSE_HTTP_PORT}</http_port>
149
+ <custom_settings_prefixes>current_</custom_settings_prefixes>
150
+ <!-- HTTP keep-alive window. Must exceed @clickhouse/client idle_socket_ttl (15 s)
151
+ so the client always closes the socket first. Prevents ECONNRESET on reuse. -->
152
+ <keep_alive_timeout>30</keep_alive_timeout>
153
+ <query_log>
154
+ <database>system</database>
155
+ <table>query_log</table>
156
+ <flush_interval_milliseconds>7500</flush_interval_milliseconds>
157
+ <ttl>event_date + INTERVAL 14 DAY DELETE</ttl>
158
+ </query_log>
159
+ <!-- All system log tables need bounded retention on 80GB EBS (mirror query_log's 14-day policy). -->
160
+ <asynchronous_metric_log>
161
+ <database>system</database>
162
+ <table>asynchronous_metric_log</table>
163
+ <ttl>event_date + INTERVAL 14 DAY DELETE</ttl>
164
+ </asynchronous_metric_log>
165
+ <metric_log>
166
+ <database>system</database>
167
+ <table>metric_log</table>
168
+ <ttl>event_date + INTERVAL 14 DAY DELETE</ttl>
169
+ </metric_log>
170
+ <part_log>
171
+ <database>system</database>
172
+ <table>part_log</table>
173
+ <ttl>event_date + INTERVAL 14 DAY DELETE</ttl>
174
+ </part_log>
175
+ <error_log>
176
+ <database>system</database>
177
+ <table>error_log</table>
178
+ <ttl>event_date + INTERVAL 14 DAY DELETE</ttl>
179
+ </error_log>
180
+ ${storageBlock}
181
+ ${backupEndpointBlock}
182
+ <!-- 256 MB query cache. Single-tenant dashboard pattern means the same
183
+ queries repeat at fixed cadences (5/15min refresh, manual reloads);
184
+ a hit returns in microseconds instead of re-scanning. Sized generously
185
+ relative to other caches because the workload pattern is uniquely
186
+ cache-friendly. -->
187
+ <query_cache>
188
+ <max_size_in_bytes>268435456</max_size_in_bytes>
189
+ <max_entries>1024</max_entries>
190
+ <max_entry_size_in_bytes>1048576</max_entry_size_in_bytes>
191
+ </query_cache>
192
+ <prometheus>
193
+ <endpoint>/metrics</endpoint>
194
+ <port>${CLICKHOUSE_PROMETHEUS_PORT}</port>
195
+ <metrics>true</metrics>
196
+ <events>true</events>
197
+ <asynchronous_metrics>true</asynchronous_metrics>
198
+ </prometheus>
199
+ <query_thread_log remove="1"/>
200
+ <opentelemetry_span_log remove="1"/>
201
+ <processors_profile_log remove="1"/>
202
+ </clickhouse>`;
203
+ }
204
+ /**
205
+ * Construct-side thin wrapper around `renderUsersXml`. Always emits the
206
+ * prod shape: loopback-only `<default>` user, `from_env=` sha256 password
207
+ * directives. The container entrypoint wrapper (see
208
+ * `buildClickHouseEntrypointWrapper`) resolves the `USER_<NAME>_SHA256` env
209
+ * vars at server start from `sha256sum` of each ECS-injected plaintext.
210
+ *
211
+ * TODO secondary CIDRs: props.vpc.vpcCidrBlock returns only the primary CIDR.
212
+ * BYOC consumers with multi-CIDR VPCs need a per-CIDR `<ip>` emitter — see
213
+ * designs/2026-05-12-clickhouse-construct-leak-fixes.md § "Phase 1.5".
214
+ */
215
+ export function generateUsersConfigXml(options) {
216
+ return renderUsersXml({
217
+ schemaAdmin: options.schemaAdmin,
218
+ profiles: options.profiles,
219
+ vpcCidr: options.vpcCidr,
220
+ defaultUserAccess: "loopback-only",
221
+ passwordSource: { mode: "from_env" }
222
+ });
223
+ }
224
+ // EC2 LaunchTemplate UserData is capped at 16,384 bytes; the pretty-printed
225
+ // source overflows once XML/bash comments are included.
226
+ function compactUserDataScript(script) {
227
+ return script
228
+ .replace(/<!--[\s\S]*?-->/g, "")
229
+ .split("\n")
230
+ .map((line) => {
231
+ const trimmed = line.replace(/\s+$/, "").replace(/^\s+/, "");
232
+ if (trimmed.startsWith("#") && !trimmed.startsWith("#!"))
233
+ return "";
234
+ return trimmed;
235
+ })
236
+ .filter((line, index, all) => line !== "" || (index > 0 && all[index - 1] !== ""))
237
+ .join("\n");
238
+ }
239
+ /**
240
+ * Build the EC2 user-data script that bootstraps ClickHouse on the ASG instance.
241
+ *
242
+ * Per design D27 + D12: cold-storage and backups authenticate to S3 via IAM
243
+ * (the EC2 instance role's grants), not via env-var access keys. The rendered
244
+ * output contains zero `R2_*` / `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`
245
+ * references — `<use_environment_credentials>true</use_environment_credentials>`
246
+ * tells ClickHouse to use the IMDS-derived credentials instead.
247
+ */
248
+ export function buildClickHouseUserData(options) {
249
+ const serverConfigXml = generateServerConfigXml(options);
250
+ const script = `#!/bin/bash
251
+ set -euo pipefail
252
+
253
+ DEVICE="${CLICKHOUSE_EBS_DEVICE_NAME}"
254
+ MOUNT_POINT="${CLICKHOUSE_DATA_MOUNT_PATH}"
255
+
256
+ # Host kernel tuning for ClickHouse. Applied before the container starts so
257
+ # the settings are inherited via the docker daemon.
258
+ #
259
+ # 1. Transparent Huge Pages → madvise. ClickHouse explicitly recommends
260
+ # 'madvise' over 'always': 'always' triggers latency spikes from khugepaged
261
+ # rewriting hot pages; 'never' loses the THP win on large allocations
262
+ # (mark/group-by hash tables). 'madvise' is the documented sweet spot.
263
+ # https://clickhouse.com/docs/operations/tips#transparenthugepages
264
+ echo madvise > /sys/kernel/mm/transparent_hugepage/enabled || true
265
+ echo madvise > /sys/kernel/mm/transparent_hugepage/defrag || true
266
+
267
+ # 2. Raise file-descriptor ceiling for the docker daemon (and therefore the
268
+ # CH container). CH's default config requests 500K+ FDs for distributed
269
+ # table caches, S3 backup readers, and per-tenant connection pools; the
270
+ # default 1024 ulimit causes 'too many open files' under load. Set the
271
+ # systemd override before docker starts so the limit is in place when the
272
+ # ECS agent launches the CH task.
273
+ mkdir -p /etc/systemd/system/docker.service.d
274
+ cat > /etc/systemd/system/docker.service.d/override.conf << 'DOCKEROVERRIDE'
275
+ [Service]
276
+ LimitNOFILE=1048576
277
+ LimitNPROC=unlimited
278
+ DOCKEROVERRIDE
279
+ systemctl daemon-reload
280
+ systemctl restart docker || true
281
+
282
+ # Wait for the EBS volume to be attached (up to 60 seconds)
283
+ for i in $(seq 1 60); do
284
+ if [ -b "$DEVICE" ]; then
285
+ break
286
+ fi
287
+ sleep 1
288
+ done
289
+
290
+ if [ ! -b "$DEVICE" ]; then
291
+ echo "ERROR: EBS volume $DEVICE not found after 60 seconds" >&2
292
+ exit 1
293
+ fi
294
+
295
+ # Format only if not already formatted (idempotent)
296
+ if ! blkid "$DEVICE" | grep -q ext4; then
297
+ mkfs.ext4 -m 0 "$DEVICE"
298
+ fi
299
+
300
+ # Mount
301
+ mkdir -p "$MOUNT_POINT"
302
+ mount "$DEVICE" "$MOUNT_POINT"
303
+
304
+ # Persist across reboots
305
+ if ! grep -q "$MOUNT_POINT" /etc/fstab; then
306
+ echo "$DEVICE $MOUNT_POINT ext4 defaults,nofail 0 2" >> /etc/fstab
307
+ fi
308
+
309
+ # Write ClickHouse server config (memory limits, storage policies, Prometheus)
310
+ mkdir -p "$MOUNT_POINT/${CLICKHOUSE_CONFIG_SUBDIR}"
311
+ cat > "$MOUNT_POINT/${CLICKHOUSE_CONFIG_SUBDIR}/fjall.xml" << 'CONFIGEOF'
312
+ ${serverConfigXml}
313
+ CONFIGEOF
314
+
315
+ # Pull ClickHouse users config from S3 (BucketDeployment uploads it to
316
+ # s3://<backup-bucket>/config/users.d.xml at synth time). Retry up to 90×2s
317
+ # to absorb BucketDeployment Lambda cold-start (~60-120s observed).
318
+ mkdir -p "$MOUNT_POINT/${CLICKHOUSE_USERS_SUBDIR}"
319
+ USERS_CONFIG_RETRIEVED=0
320
+ for i in $(seq 1 90); do
321
+ if aws s3 cp "s3://${options.backupBucketName}/config/users.d.xml" \\
322
+ "$MOUNT_POINT/${CLICKHOUSE_USERS_SUBDIR}/fjall.xml.new" 2>/dev/null; then
323
+ mv "$MOUNT_POINT/${CLICKHOUSE_USERS_SUBDIR}/fjall.xml.new" \\
324
+ "$MOUNT_POINT/${CLICKHOUSE_USERS_SUBDIR}/fjall.xml"
325
+ USERS_CONFIG_RETRIEVED=1
326
+ break
327
+ fi
328
+ sleep 2
329
+ done
330
+ if [ "$USERS_CONFIG_RETRIEVED" != "1" ]; then
331
+ echo "ERROR: users.d/fjall.xml not retrieved from s3://${options.backupBucketName}/config/users.d.xml after 180s" >&2
332
+ exit 1
333
+ fi
334
+
335
+ chown -R 101:101 "$MOUNT_POINT"
336
+ `;
337
+ return compactUserDataScript(script);
338
+ }
339
+ /**
340
+ * Build the bash wrapper executed as the CH container's entrypoint.
341
+ *
342
+ * The CH server reads `users.d/fjall.xml`, which carries
343
+ * `<password_sha256_hex from_env="USER_<NAME>_SHA256"/>` directives, and
344
+ * resolves those `from_env=` lookups against the server process's
345
+ * environment at startup. ECS injects the plaintext password for each user
346
+ * as `USER_<NAME>_PASSWORD` via `secretsImport`; this wrapper derives the
347
+ * matching `USER_<NAME>_SHA256` env var (via the same SHA-256 pipeline as
348
+ * the EC2 user-data loop in `buildClickHouseUserData()`) and then `exec`s
349
+ * the stock CH entrypoint so the server inherits the derived vars after
350
+ * the gosu privilege drop.
351
+ *
352
+ * Pure-bash iteration via `${!USER_@}` avoids spawning `env`/`grep` and
353
+ * guarantees only ECS-injected secrets are considered. The `case` filter
354
+ * skips any future `USER_*_HOST`/`USER_*_PORT` envs that don't match the
355
+ * password convention.
356
+ */
357
+ export function buildClickHouseEntrypointWrapper() {
358
+ // `pipefail` so `printf | sha256sum | awk` aborts on mid-pipeline failure
359
+ // instead of exporting an empty hash; parity with the SSM live-reload script.
360
+ return `set -euo pipefail
361
+ for var in "\${!USER_@}"; do
362
+ case "$var" in
363
+ *_PASSWORD)
364
+ base=\${var%_PASSWORD}
365
+ hash=$(${clickHousePasswordSha256Snippet('"${!var}"')})
366
+ export "\${base}_SHA256=$hash"
367
+ ;;
368
+ esac
369
+ done
370
+ exec /entrypoint.sh`;
371
+ }
@@ -0,0 +1,56 @@
1
+ import type { ClickHouseSchemaAdmin, ProfileSpec } from "./clickhouseSchemas.js";
2
+ /**
3
+ * Pure helper for rendering the `users.d/fjall.xml` ClickHouse users config.
4
+ *
5
+ * Two callers, two shapes:
6
+ * - **Prod** (construct): `passwordSource: { mode: "from_env" }`,
7
+ * `defaultUserAccess: "loopback-only"`. The XML emits
8
+ * `<password_sha256_hex from_env="USER_<NAME>_SHA256"/>` directives; the
9
+ * EC2 user-data resolves these from env vars set by computing `sha256sum`
10
+ * of each plaintext fetched from Secrets Manager at boot.
11
+ * - **Dev** (gen-script): `passwordSource: { mode: "literal-hashes", hashes }`,
12
+ * `defaultUserAccess: "permissive"`. The XML embeds the pre-computed
13
+ * sha256 hex literally; the `<default>` user accepts RFC1918 + loopback so
14
+ * docker-compose sidecars on the bridge network can authenticate.
15
+ *
16
+ * Only the schema-admin user is emitted into the XML — managed-password
17
+ * workload users are created at runtime by the migration helper and bind
18
+ * their profiles via customer SQL. The schema admin's profile is bound here,
19
+ * in the XML, because it must be live before any SQL runs.
20
+ */
21
+ export interface RenderUsersXmlOptions {
22
+ schemaAdmin: ClickHouseSchemaAdmin;
23
+ profiles: Record<string, ProfileSpec>;
24
+ /**
25
+ * Primary VPC CIDR block — emitted into the schema admin's `<networks><ip>`.
26
+ * In prod the construct passes `props.vpc.vpcCidrBlock` (a CDK Token that
27
+ * resolves at deploy time); in dev the gen-script passes `"0.0.0.0/0"`
28
+ * because dev access is gated by `defaultUserAccess: "permissive"` on the
29
+ * `<default>` user.
30
+ */
31
+ vpcCidr: string;
32
+ defaultUserAccess: "loopback-only" | "permissive";
33
+ passwordSource: {
34
+ mode: "from_env";
35
+ } | {
36
+ mode: "literal-hashes";
37
+ hashes: Record<string, string>;
38
+ };
39
+ }
40
+ /**
41
+ * Pure renderer. Validates that `schemaAdmin.profile` exists in `profiles`,
42
+ * and (in literal-hashes mode) that the schema admin has a hash entry. No
43
+ * CDK dependency — the construct passes `vpc.vpcCidrBlock` as a string-valued
44
+ * Token that resolves through CFN at deploy time.
45
+ *
46
+ * **Schema-admin-only emission.** Only the schema admin lands in the XML.
47
+ * Managed-password workload users are created at runtime by the migration
48
+ * helper (`@fjall/clickhouse-migrations § provisionUsersFromEnv`) — they
49
+ * authenticate via plaintext from `USER_<NAME>_PASSWORD` env vars at runtime
50
+ * and bind their profiles via customer SQL.
51
+ *
52
+ * Quotas are SQL-managed. No `<quotas>` block is emitted — the schema admin
53
+ * references CH's built-in `default` quota at boot; SQL-defined quotas take
54
+ * over post-migration.
55
+ */
56
+ export declare function renderUsersXml(opts: RenderUsersXmlOptions): string;
@@ -0,0 +1,112 @@
1
+ function camelToSnakeCase(input) {
2
+ return input.replace(/[A-Z]/g, (m) => "_" + m.toLowerCase());
3
+ }
4
+ function renderProfileSpec(spec) {
5
+ const lines = [];
6
+ for (const [key, value] of Object.entries(spec)) {
7
+ if (value === undefined)
8
+ continue;
9
+ const xmlName = camelToSnakeCase(key);
10
+ const xmlValue = typeof value === "boolean" ? (value ? "1" : "0") : String(value);
11
+ lines.push(` <${xmlName}>${xmlValue}</${xmlName}>`);
12
+ }
13
+ return lines.join("\n");
14
+ }
15
+ function renderDefaultUserBlock(access) {
16
+ if (access === "loopback-only") {
17
+ return ` <default>
18
+ <networks>
19
+ <ip>127.0.0.1</ip>
20
+ <ip>::1</ip>
21
+ </networks>
22
+ </default>`;
23
+ }
24
+ return ` <default>
25
+ <password></password>
26
+ <networks>
27
+ <ip>127.0.0.1</ip>
28
+ <ip>::1</ip>
29
+ <ip>172.16.0.0/12</ip>
30
+ <ip>10.0.0.0/8</ip>
31
+ <ip>192.168.0.0/16</ip>
32
+ </networks>
33
+ <access_management>1</access_management>
34
+ </default>`;
35
+ }
36
+ function renderPasswordElement(name, passwordSource) {
37
+ if (passwordSource.mode === "from_env") {
38
+ const envName = `USER_${name.toUpperCase()}_SHA256`;
39
+ return `<password_sha256_hex from_env="${envName}"/>`;
40
+ }
41
+ const hash = passwordSource.hashes[name];
42
+ if (hash === undefined) {
43
+ throw new Error(`renderUsersXml: literal-hashes mode missing hash for user '${name}'`);
44
+ }
45
+ return `<password_sha256_hex>${hash}</password_sha256_hex>`;
46
+ }
47
+ function renderSchemaAdminBlock(schemaAdmin, vpcCidr, passwordSource) {
48
+ const passwordElement = renderPasswordElement(schemaAdmin.name, passwordSource);
49
+ return ` <${schemaAdmin.name}>
50
+ ${passwordElement}
51
+ <networks>
52
+ <ip>${vpcCidr}</ip>
53
+ </networks>
54
+ <profile>${schemaAdmin.profile}</profile>
55
+ <quota>default</quota>
56
+ <access_management>1</access_management>
57
+ <named_collection_control>1</named_collection_control>
58
+ <show_named_collections>1</show_named_collections>
59
+ <show_named_collections_secrets>1</show_named_collections_secrets>
60
+ </${schemaAdmin.name}>`;
61
+ }
62
+ function renderProfileBlock(name, spec) {
63
+ const body = renderProfileSpec(spec);
64
+ return ` <${name}>
65
+ ${body}
66
+ </${name}>`;
67
+ }
68
+ /**
69
+ * Pure renderer. Validates that `schemaAdmin.profile` exists in `profiles`,
70
+ * and (in literal-hashes mode) that the schema admin has a hash entry. No
71
+ * CDK dependency — the construct passes `vpc.vpcCidrBlock` as a string-valued
72
+ * Token that resolves through CFN at deploy time.
73
+ *
74
+ * **Schema-admin-only emission.** Only the schema admin lands in the XML.
75
+ * Managed-password workload users are created at runtime by the migration
76
+ * helper (`@fjall/clickhouse-migrations § provisionUsersFromEnv`) — they
77
+ * authenticate via plaintext from `USER_<NAME>_PASSWORD` env vars at runtime
78
+ * and bind their profiles via customer SQL.
79
+ *
80
+ * Quotas are SQL-managed. No `<quotas>` block is emitted — the schema admin
81
+ * references CH's built-in `default` quota at boot; SQL-defined quotas take
82
+ * over post-migration.
83
+ */
84
+ export function renderUsersXml(opts) {
85
+ if (!(opts.schemaAdmin.profile in opts.profiles)) {
86
+ throw new Error(`renderUsersXml: schemaAdmin '${opts.schemaAdmin.name}' references unknown profile '${opts.schemaAdmin.profile}'. ` +
87
+ `Known profiles: ${Object.keys(opts.profiles).join(", ")}`);
88
+ }
89
+ const defaultBlock = renderDefaultUserBlock(opts.defaultUserAccess);
90
+ const adminBlock = renderSchemaAdminBlock(opts.schemaAdmin, opts.vpcCidr, opts.passwordSource);
91
+ const defaultProfileBlock = ` <default>
92
+ <optimize_move_to_prewhere>1</optimize_move_to_prewhere>
93
+ <!-- ALTER TABLE ... MODIFY TTL on a 30-day-partitioned table would otherwise
94
+ trigger an immediate full-table rewrite (default = 1). On the m7g.medium
95
+ box that's a merge-pool starvation event. Keep TTL changes lazy: parts
96
+ re-evaluate TTL on their next natural merge, no forced rewrite. -->
97
+ <materialize_ttl_after_modify>0</materialize_ttl_after_modify>
98
+ </default>`;
99
+ const profileBlocks = Object.entries(opts.profiles)
100
+ .map(([name, spec]) => renderProfileBlock(name, spec))
101
+ .join("\n");
102
+ return `<clickhouse>
103
+ <users>
104
+ ${defaultBlock}
105
+ ${adminBlock}
106
+ </users>
107
+ <profiles>
108
+ ${defaultProfileBlock}
109
+ ${profileBlocks}
110
+ </profiles>
111
+ </clickhouse>`;
112
+ }
@@ -5,7 +5,7 @@ import { Construct } from "constructs";
5
5
  import { Secret } from "../secrets/index.js";
6
6
  import type { ITopic } from "aws-cdk-lib/aws-sns";
7
7
  import { type RdsAlarmThresholds } from "../monitoring/index.js";
8
- import { type EngineConfig, type ProxyConfig, type CredentialsConfig, type AuroraEncryptionConfig, type AuroraWriterConfig, type AuroraReadersConfig, type DatabaseInsightsConfig } from "../../../utils/databaseTypes.js";
8
+ import { type EngineConfig, type ProxyConfig, type CredentialsConfig, type AuroraEncryptionConfig, type AuroraWriterConfig, type AuroraReadersConfig, type DatabaseInsightsConfig, type SnapshotTarget } from "../../../utils/databaseTypes.js";
9
9
  interface RdsProps {
10
10
  vpc: IVpc;
11
11
  databaseName?: string;
@@ -61,6 +61,7 @@ export declare class RdsAurora extends Construct implements IConnectable {
61
61
  private databaseProxy?;
62
62
  private databaseCredentials;
63
63
  private cfnCluster?;
64
+ private databaseNameValue;
64
65
  constructor(scope: Construct, id: string, props: RdsProps);
65
66
  private buildReaders;
66
67
  private addProxy;
@@ -68,6 +69,12 @@ export declare class RdsAurora extends Construct implements IConnectable {
68
69
  getHostEndpoint(): string;
69
70
  getHostPort(): string;
70
71
  getCredentials(): Secret;
72
+ getClusterIdentifier(): string;
73
+ getSnapshotTarget(): Extract<SnapshotTarget, {
74
+ kind: "cluster";
75
+ }>;
76
+ getDatabaseName(): string;
77
+ getConnectionString(): string;
71
78
  getCfnCluster(): CfnDBCluster | undefined;
72
79
  getDatabaseCluster(): DatabaseCluster;
73
80
  }