belt 0.3.27 → 0.3.29
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.
- checksums.yaml +4 -4
- data/lib/belt/cli/destroy_command.rb +21 -0
- data/lib/belt/cli/dns_command.rb +96 -8
- data/lib/belt/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 84353c2ac395a3d2855e5df323c6d90305eda791b58906c41c89571e842325bb
|
|
4
|
+
data.tar.gz: d1364d5d4a87087431b67782f2919ffcc2ab37779d30ff779c2a7c9a8ced58ce
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bcea273ea44bfd7410ad5bc249fd21206ee050bf78a7e31ad841e51196a3930e7646e5dd237fb80ecd49253b8fdd9a1982cc5972e46cee43ddfbef4441a8baaa
|
|
7
|
+
data.tar.gz: 7cf36fd36c683e8ca9694f27943401a909793a8f64757f03bb44a7f985bd6229670a9876446d4f8ba9b60ee021e700fa2e70d08f120ae72bcec4f4bd2bc512db
|
|
@@ -236,6 +236,9 @@ module Belt
|
|
|
236
236
|
@removed << dir
|
|
237
237
|
puts " remove #{dir}/"
|
|
238
238
|
puts "\n✓ Environment '#{@name}' destroyed!"
|
|
239
|
+
|
|
240
|
+
# Check if DNS delegation exists and warn about cleanup
|
|
241
|
+
warn_about_dns_delegation(@name)
|
|
239
242
|
end
|
|
240
243
|
|
|
241
244
|
def terraform_state_exists?(dir)
|
|
@@ -258,6 +261,24 @@ module Belt
|
|
|
258
261
|
true
|
|
259
262
|
end
|
|
260
263
|
|
|
264
|
+
def warn_about_dns_delegation(env_name)
|
|
265
|
+
dns_tfvars = 'infrastructure/dns/terraform.tfvars'
|
|
266
|
+
return unless File.exist?(dns_tfvars)
|
|
267
|
+
|
|
268
|
+
content = File.read(dns_tfvars)
|
|
269
|
+
# Only match a real HCL entry (e.g. " dev = [") at the start of a line,
|
|
270
|
+
# not the commented-out examples in the tfvars template (e.g. "# dev = [").
|
|
271
|
+
# This mirrors the anchored patterns DNSCommand uses when writing entries.
|
|
272
|
+
return unless content =~ /^\s*#{Regexp.escape(env_name)}\s*=/
|
|
273
|
+
|
|
274
|
+
puts ''
|
|
275
|
+
puts '⚠ DNS delegation still exists for this environment.'
|
|
276
|
+
puts ' To clean up the root zone delegation:'
|
|
277
|
+
puts ''
|
|
278
|
+
puts " belt dns remove #{env_name}"
|
|
279
|
+
puts ' belt dns deploy'
|
|
280
|
+
end
|
|
281
|
+
|
|
261
282
|
def run_terraform_destroy(dir)
|
|
262
283
|
puts "\n━━━ terraform destroy (#{@name}) ━━━"
|
|
263
284
|
|
data/lib/belt/cli/dns_command.rb
CHANGED
|
@@ -25,6 +25,8 @@ module Belt
|
|
|
25
25
|
new.generate(args)
|
|
26
26
|
when 'add'
|
|
27
27
|
new.add_environment(args)
|
|
28
|
+
when 'remove', 'rm'
|
|
29
|
+
new.remove_environment(args)
|
|
28
30
|
when 'show', 'list'
|
|
29
31
|
new.show(args)
|
|
30
32
|
when '--help', '-h', 'help'
|
|
@@ -43,6 +45,7 @@ module Belt
|
|
|
43
45
|
deploy Deploy the dns infrastructure (init → plan → apply)
|
|
44
46
|
generate Create the infrastructure/dns directory (same as belt generate dns)
|
|
45
47
|
add <env> Add an environment's NS records to dns/terraform.tfvars
|
|
48
|
+
remove <env> Remove an environment's NS records from dns/terraform.tfvars
|
|
46
49
|
show Show root zone name servers (for registrar configuration)
|
|
47
50
|
help Show this help
|
|
48
51
|
|
|
@@ -55,6 +58,7 @@ module Belt
|
|
|
55
58
|
belt dns generate # Scaffold infrastructure/dns (prompts for profile)
|
|
56
59
|
belt dns generate --aws-profile fpshared # Non-interactive with profile
|
|
57
60
|
belt dns add staging # Add staging's NS records to tfvars
|
|
61
|
+
belt dns remove staging # Remove staging's NS delegation
|
|
58
62
|
belt dns show # Show root name servers to configure at registrar
|
|
59
63
|
|
|
60
64
|
The dns directory manages your root domain and delegates subdomains to
|
|
@@ -67,6 +71,11 @@ module Belt
|
|
|
67
71
|
3. belt dns add dev # Add dev's NS records
|
|
68
72
|
4. belt dns deploy # Deploy root zone
|
|
69
73
|
5. Update registrar NS records to output values
|
|
74
|
+
|
|
75
|
+
When destroying an environment:
|
|
76
|
+
1. belt destroy environment dev # Destroy the environment
|
|
77
|
+
2. belt dns remove dev # Remove DNS delegation
|
|
78
|
+
3. belt dns deploy # Apply the change
|
|
70
79
|
HELP
|
|
71
80
|
end
|
|
72
81
|
|
|
@@ -208,6 +217,37 @@ module Belt
|
|
|
208
217
|
puts "\nRun 'belt dns deploy' to apply the changes."
|
|
209
218
|
end
|
|
210
219
|
|
|
220
|
+
# --- Remove Environment ---
|
|
221
|
+
def remove_environment(args)
|
|
222
|
+
env_name = args.shift
|
|
223
|
+
|
|
224
|
+
if env_name.nil? || env_name.start_with?('-')
|
|
225
|
+
puts 'Usage: belt dns remove <env>'
|
|
226
|
+
puts "\nExample: belt dns remove staging"
|
|
227
|
+
exit 1
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
tfvars_path = "#{DNS_DIR}/terraform.tfvars"
|
|
231
|
+
unless File.exist?(tfvars_path)
|
|
232
|
+
puts "#{tfvars_path} not found."
|
|
233
|
+
puts "\nNo DNS infrastructure to modify."
|
|
234
|
+
exit 1
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
content = File.read(tfvars_path)
|
|
238
|
+
|
|
239
|
+
# Check if the environment exists in the tfvars
|
|
240
|
+
unless content.include?("#{env_name} =")
|
|
241
|
+
puts "Environment '#{env_name}' not found in #{tfvars_path}."
|
|
242
|
+
puts "\nNothing to remove."
|
|
243
|
+
exit 0
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
remove_env_from_tfvars(tfvars_path, env_name)
|
|
247
|
+
puts "✓ Removed #{env_name} NS records from #{tfvars_path}"
|
|
248
|
+
puts "\nRun 'belt dns deploy' to apply the changes."
|
|
249
|
+
end
|
|
250
|
+
|
|
211
251
|
# --- Show ---
|
|
212
252
|
def show(_args)
|
|
213
253
|
require 'open3'
|
|
@@ -241,18 +281,11 @@ module Belt
|
|
|
241
281
|
end
|
|
242
282
|
end
|
|
243
283
|
|
|
244
|
-
# Extract values
|
|
284
|
+
# Extract values from terraform state
|
|
245
285
|
name_servers = outputs.dig('root_name_servers', 'value') || []
|
|
246
286
|
zone_id = outputs.dig('root_zone_id', 'value')
|
|
247
287
|
environments = outputs.dig('delegated_environments', 'value') || []
|
|
248
288
|
|
|
249
|
-
if name_servers.empty?
|
|
250
|
-
puts 'No name servers found. Is the DNS zone deployed?'
|
|
251
|
-
puts "\nRun:"
|
|
252
|
-
puts ' belt dns deploy'
|
|
253
|
-
exit 1
|
|
254
|
-
end
|
|
255
|
-
|
|
256
289
|
# Read domain from tfvars
|
|
257
290
|
tfvars_path = "#{DNS_DIR}/terraform.tfvars"
|
|
258
291
|
domain = nil
|
|
@@ -262,6 +295,26 @@ module Belt
|
|
|
262
295
|
domain = match[1] if match
|
|
263
296
|
end
|
|
264
297
|
|
|
298
|
+
# Verify the zone actually exists in AWS (terraform state can be stale)
|
|
299
|
+
if zone_id && !zone_exists_in_aws?(zone_id, env)
|
|
300
|
+
puts 'Root Zone Not Found'
|
|
301
|
+
puts '==================='
|
|
302
|
+
puts ''
|
|
303
|
+
puts "Terraform state references zone #{zone_id}, but it doesn't exist in AWS."
|
|
304
|
+
puts 'The zone may have been deleted or the state is stale.'
|
|
305
|
+
puts ''
|
|
306
|
+
puts 'To create the root zone:'
|
|
307
|
+
puts ' belt dns deploy'
|
|
308
|
+
exit 1
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
if name_servers.empty?
|
|
312
|
+
puts 'No name servers found. Is the DNS zone deployed?'
|
|
313
|
+
puts "\nRun:"
|
|
314
|
+
puts ' belt dns deploy'
|
|
315
|
+
exit 1
|
|
316
|
+
end
|
|
317
|
+
|
|
265
318
|
# Display
|
|
266
319
|
puts 'Root Zone Name Servers'
|
|
267
320
|
puts '======================'
|
|
@@ -386,6 +439,31 @@ module Belt
|
|
|
386
439
|
File.write(path, content)
|
|
387
440
|
end
|
|
388
441
|
|
|
442
|
+
def remove_env_from_tfvars(path, env_name)
|
|
443
|
+
content = File.read(path)
|
|
444
|
+
|
|
445
|
+
# Match the environment entry: " env_name = [\n ...\n ]" with optional trailing comma
|
|
446
|
+
# The entry can be followed by another entry, a closing brace, or whitespace
|
|
447
|
+
#
|
|
448
|
+
# Pattern breakdown:
|
|
449
|
+
# - ^(\s*)#{env_name}\s*= matches " env_name =" at start of line
|
|
450
|
+
# - \s*\[\s* matches " [" with optional whitespace
|
|
451
|
+
# - [^\]]* matches everything inside brackets (the NS records)
|
|
452
|
+
# - \]\s*,?\s* matches "]" with optional trailing comma and whitespace
|
|
453
|
+
# - (?=\n|\s*[}\w]) lookahead for newline or closing brace/next entry
|
|
454
|
+
entry_pattern = /^\s*#{Regexp.escape(env_name)}\s*=\s*\[[^\]]*\]\s*,?\s*\n?/m
|
|
455
|
+
|
|
456
|
+
content.gsub!(entry_pattern, '')
|
|
457
|
+
|
|
458
|
+
# Clean up any double newlines that may have been created
|
|
459
|
+
content.gsub!(/\n{3,}/, "\n\n")
|
|
460
|
+
|
|
461
|
+
# If the environment_zones block is now empty (just whitespace), clean it up
|
|
462
|
+
content.gsub!(/^environment_zones\s*=\s*\{\s*\n\s*\}/, 'environment_zones = {}')
|
|
463
|
+
|
|
464
|
+
File.write(path, content)
|
|
465
|
+
end
|
|
466
|
+
|
|
389
467
|
# Resolve the state bucket name to use in backend.tf.
|
|
390
468
|
# Priority: existing sibling backend.tf → AWS account ID → bare placeholder.
|
|
391
469
|
def resolve_state_bucket
|
|
@@ -456,6 +534,16 @@ module Belt
|
|
|
456
534
|
_, status = Open3.capture2e(*cmd)
|
|
457
535
|
status.success?
|
|
458
536
|
end
|
|
537
|
+
|
|
538
|
+
# Verify a Route 53 hosted zone exists in AWS.
|
|
539
|
+
# env is a hash with optional AWS_PROFILE for the aws CLI.
|
|
540
|
+
def zone_exists_in_aws?(zone_id, env = {})
|
|
541
|
+
require 'open3'
|
|
542
|
+
cmd = ['aws', 'route53', 'get-hosted-zone', '--id', zone_id]
|
|
543
|
+
cmd += ['--profile', env['AWS_PROFILE']] if env['AWS_PROFILE']
|
|
544
|
+
_, status = Open3.capture2e(*cmd)
|
|
545
|
+
status.success?
|
|
546
|
+
end
|
|
459
547
|
end
|
|
460
548
|
end
|
|
461
549
|
end
|
data/lib/belt/version.rb
CHANGED