belt 0.3.23 → 0.3.24
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/dns_command.rb +24 -0
- data/lib/belt/cli/setup_command.rb +67 -16
- 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: 9e5f26e4b71c7d784ea8e6a2596952a21d9357f65a9284b9358c5c79a34e50a8
|
|
4
|
+
data.tar.gz: f98d7e78c1620e38700eb53151cbf21daaace261f0b2802dc36633665bc50d1d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d6d165f29d693cbc4cd19b693a74867ad578c70bcc255ffc25672ae616694a7604870e090800df16a73d6534e772d95fd417bdad888c07674f15998f838cdaa7
|
|
7
|
+
data.tar.gz: 835dfd43f148de3966d7cba26784922b2c6f952ab24d1c9fb61abf4f51f596d29107526c91a6cdba5be191f061f91acd6504298bd6067ccc756ac7b556b09a88
|
data/lib/belt/cli/dns_command.rb
CHANGED
|
@@ -5,6 +5,7 @@ require 'erb'
|
|
|
5
5
|
require 'json'
|
|
6
6
|
require_relative 'app_detection'
|
|
7
7
|
require_relative 'environment_config'
|
|
8
|
+
require_relative 'setup_command'
|
|
8
9
|
|
|
9
10
|
module Belt
|
|
10
11
|
module CLI
|
|
@@ -100,6 +101,9 @@ module Belt
|
|
|
100
101
|
# Resolve state bucket using the specified profile (or current credentials)
|
|
101
102
|
@state_bucket = resolve_state_bucket_for_profile(@aws_profile)
|
|
102
103
|
|
|
104
|
+
# Ensure the state bucket exists (convention over configuration)
|
|
105
|
+
ensure_state_bucket_exists(@state_bucket)
|
|
106
|
+
|
|
103
107
|
puts 'Creating dns infrastructure...' unless @quiet
|
|
104
108
|
if @aws_profile && !@quiet
|
|
105
109
|
puts " Using AWS profile: #{@aws_profile}"
|
|
@@ -346,6 +350,26 @@ module Belt
|
|
|
346
350
|
|
|
347
351
|
"belt-terraform-state-#{data['Account']}"
|
|
348
352
|
end
|
|
353
|
+
|
|
354
|
+
# Ensure the state bucket exists, creating it if necessary.
|
|
355
|
+
# Uses belt setup state --aws-profile for convention over configuration.
|
|
356
|
+
def ensure_state_bucket_exists(bucket)
|
|
357
|
+
return if bucket == 'belt-terraform-state' # Placeholder means no credentials
|
|
358
|
+
return if bucket_exists?(bucket)
|
|
359
|
+
|
|
360
|
+
puts "State bucket #{bucket} not found. Creating it..." unless @quiet
|
|
361
|
+
args = []
|
|
362
|
+
args += ['--aws-profile', @aws_profile] if @aws_profile
|
|
363
|
+
SetupCommand.new(args, quiet: @quiet, aws_profile: @aws_profile).run_state_setup
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def bucket_exists?(bucket)
|
|
367
|
+
require 'open3'
|
|
368
|
+
cmd = ['aws', 's3api', 'head-bucket', '--bucket', bucket]
|
|
369
|
+
cmd += ['--profile', @aws_profile] if @aws_profile
|
|
370
|
+
_, status = Open3.capture2e(*cmd)
|
|
371
|
+
status.success?
|
|
372
|
+
end
|
|
349
373
|
end
|
|
350
374
|
end
|
|
351
375
|
end
|
|
@@ -29,26 +29,48 @@ module Belt
|
|
|
29
29
|
when 'frontend'
|
|
30
30
|
Belt::CLI::FrontendSetupCommand.run(args)
|
|
31
31
|
else
|
|
32
|
-
|
|
33
|
-
puts "\nSubcommands:"
|
|
34
|
-
puts ' state Set up S3 bucket for Terraform state'
|
|
35
|
-
puts ' tables Generate DynamoDB table definitions from contracts.rb'
|
|
36
|
-
puts ' frontend Generate S3 + CloudFront infrastructure for frontend hosting'
|
|
32
|
+
print_usage
|
|
37
33
|
exit 1
|
|
38
34
|
end
|
|
39
35
|
end
|
|
40
36
|
|
|
41
|
-
def
|
|
37
|
+
def self.print_usage
|
|
38
|
+
puts <<~USAGE
|
|
39
|
+
Usage: belt setup <state|tables|frontend> [options]
|
|
40
|
+
|
|
41
|
+
Subcommands:
|
|
42
|
+
state Set up S3 bucket for Terraform state
|
|
43
|
+
tables Generate DynamoDB table definitions from contracts.rb
|
|
44
|
+
frontend Generate S3 + CloudFront infrastructure for frontend hosting
|
|
45
|
+
|
|
46
|
+
Options for state:
|
|
47
|
+
--aws-profile NAME Use a specific AWS profile (for multi-account setups)
|
|
48
|
+
--bucket NAME Use a custom bucket name instead of belt-terraform-state-<account>
|
|
49
|
+
--select Interactively select from existing buckets
|
|
50
|
+
|
|
51
|
+
Examples:
|
|
52
|
+
belt setup state # Create/verify bucket using current credentials
|
|
53
|
+
belt setup state --aws-profile fpshared # Create bucket in a specific AWS account
|
|
54
|
+
belt setup state --select # Choose from existing buckets
|
|
55
|
+
belt setup state --bucket my-bucket # Use a custom bucket name
|
|
56
|
+
|
|
57
|
+
The state bucket stores Terraform state for all Belt applications in an AWS account.
|
|
58
|
+
By default, Belt uses `belt-terraform-state-<account_id>` as the bucket name.
|
|
59
|
+
USAGE
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def initialize(args = [], quiet: false, aws_profile: nil)
|
|
42
63
|
@app_name = detect_app_name
|
|
43
64
|
@env_name = nil
|
|
44
65
|
@custom_bucket = nil
|
|
45
66
|
@select_mode = false
|
|
46
67
|
@quiet = quiet
|
|
68
|
+
@aws_profile = aws_profile
|
|
47
69
|
|
|
48
70
|
parse_args(args)
|
|
49
71
|
|
|
50
72
|
@region = detect_region
|
|
51
|
-
@bucket_name =
|
|
73
|
+
@bucket_name = nil # Resolved after credentials check
|
|
52
74
|
end
|
|
53
75
|
|
|
54
76
|
def run_state_setup
|
|
@@ -62,8 +84,11 @@ module Belt
|
|
|
62
84
|
exit 1
|
|
63
85
|
end
|
|
64
86
|
|
|
87
|
+
# Show which profile we're using
|
|
88
|
+
puts "Using AWS profile: #{@aws_profile}" if @aws_profile && !@quiet
|
|
89
|
+
|
|
65
90
|
# Resolve final bucket name now that we have credentials
|
|
66
|
-
@bucket_name =
|
|
91
|
+
@bucket_name = @custom_bucket || resolve_bucket_name
|
|
67
92
|
|
|
68
93
|
@bucket_name = interactive_bucket_selection if @select_mode
|
|
69
94
|
setup_or_verify_bucket
|
|
@@ -140,10 +165,14 @@ module Belt
|
|
|
140
165
|
when '--bucket'
|
|
141
166
|
@custom_bucket = args.shift
|
|
142
167
|
abort '✗ --bucket requires a value' unless @custom_bucket
|
|
168
|
+
when '--aws-profile'
|
|
169
|
+
@aws_profile = args.shift
|
|
170
|
+
abort '✗ --aws-profile requires a value' unless @aws_profile
|
|
143
171
|
when '--select'
|
|
144
172
|
@select_mode = true
|
|
145
173
|
when '--help', '-h'
|
|
146
|
-
self.class.
|
|
174
|
+
self.class.print_usage
|
|
175
|
+
exit 0
|
|
147
176
|
else
|
|
148
177
|
@env_name = arg unless arg.start_with?('-')
|
|
149
178
|
end
|
|
@@ -194,7 +223,9 @@ module Belt
|
|
|
194
223
|
end
|
|
195
224
|
|
|
196
225
|
def list_buckets
|
|
197
|
-
|
|
226
|
+
cmd = ['aws', 's3api', 'list-buckets', '--query', 'Buckets[].Name', '--output', 'json']
|
|
227
|
+
cmd += ['--profile', @aws_profile] if @aws_profile
|
|
228
|
+
output = safe_capture(*cmd)
|
|
198
229
|
return [] unless output
|
|
199
230
|
|
|
200
231
|
JSON.parse(output)
|
|
@@ -205,7 +236,9 @@ module Belt
|
|
|
205
236
|
# --- AWS operations ---
|
|
206
237
|
|
|
207
238
|
def aws_configured?
|
|
208
|
-
|
|
239
|
+
cmd = %w[aws sts get-caller-identity]
|
|
240
|
+
cmd += ['--profile', @aws_profile] if @aws_profile
|
|
241
|
+
output, status = Open3.capture2e(*cmd)
|
|
209
242
|
if status.success?
|
|
210
243
|
data = begin
|
|
211
244
|
JSON.parse(output)
|
|
@@ -223,7 +256,9 @@ module Belt
|
|
|
223
256
|
attr_reader :aws_account_id
|
|
224
257
|
|
|
225
258
|
def bucket_exists?(bucket)
|
|
226
|
-
|
|
259
|
+
cmd = ['aws', 's3api', 'head-bucket', '--bucket', bucket]
|
|
260
|
+
cmd += ['--profile', @aws_profile] if @aws_profile
|
|
261
|
+
output, status = Open3.capture2e(*cmd)
|
|
227
262
|
return true if status.success?
|
|
228
263
|
|
|
229
264
|
# 403 = bucket exists but owned by someone else; 404 = doesn't exist
|
|
@@ -239,6 +274,7 @@ module Belt
|
|
|
239
274
|
def create_bucket(bucket)
|
|
240
275
|
args = ['aws', 's3api', 'create-bucket', '--bucket', bucket, '--region', @region]
|
|
241
276
|
args.push('--create-bucket-configuration', "LocationConstraint=#{@region}") unless @region == 'us-east-1'
|
|
277
|
+
args += ['--profile', @aws_profile] if @aws_profile
|
|
242
278
|
run!(*args)
|
|
243
279
|
end
|
|
244
280
|
|
|
@@ -252,11 +288,14 @@ module Belt
|
|
|
252
288
|
AbortIncompleteMultipartUpload: { DaysAfterInitiation: 7 }
|
|
253
289
|
}]
|
|
254
290
|
}
|
|
255
|
-
|
|
256
|
-
|
|
291
|
+
cmd = ['aws', 's3api', 'put-bucket-lifecycle-configuration', '--bucket', bucket,
|
|
292
|
+
'--lifecycle-configuration', JSON.generate(lifecycle)]
|
|
293
|
+
cmd += ['--profile', @aws_profile] if @aws_profile
|
|
294
|
+
run!(*cmd)
|
|
257
295
|
end
|
|
258
296
|
|
|
259
297
|
def run!(*args)
|
|
298
|
+
args = inject_profile(args)
|
|
260
299
|
output, status = Open3.capture2e(*args)
|
|
261
300
|
return if status.success?
|
|
262
301
|
|
|
@@ -265,11 +304,23 @@ module Belt
|
|
|
265
304
|
exit 1
|
|
266
305
|
end
|
|
267
306
|
|
|
268
|
-
def safe_capture(*)
|
|
269
|
-
|
|
307
|
+
def safe_capture(*args)
|
|
308
|
+
args = inject_profile(args)
|
|
309
|
+
output, status = Open3.capture2(*args, err: File::NULL)
|
|
270
310
|
status.success? ? output : nil
|
|
271
311
|
end
|
|
272
312
|
|
|
313
|
+
# Inject --profile flag for AWS CLI commands if @aws_profile is set
|
|
314
|
+
def inject_profile(args)
|
|
315
|
+
return args unless @aws_profile
|
|
316
|
+
return args unless args.first == 'aws'
|
|
317
|
+
|
|
318
|
+
# Already has a profile flag
|
|
319
|
+
return args if args.include?('--profile')
|
|
320
|
+
|
|
321
|
+
args + ['--profile', @aws_profile]
|
|
322
|
+
end
|
|
323
|
+
|
|
273
324
|
def say(message)
|
|
274
325
|
puts message unless @quiet
|
|
275
326
|
end
|
data/lib/belt/version.rb
CHANGED