putpaws 0.0.9 → 0.1.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.
- checksums.yaml +4 -4
- data/README.md +165 -2
- data/lib/Putpawsfile +4 -0
- data/lib/putpaws/ai/ai_task.rb +1 -0
- data/lib/putpaws/ai/guide.rb +119 -0
- data/lib/putpaws/ai/tasks/ai_task.rake +14 -0
- data/lib/putpaws/application_config.rb +15 -2
- data/lib/putpaws/ecs/run_command.rb +121 -0
- data/lib/putpaws/ecs/task_command.rb +63 -9
- data/lib/putpaws/ecs/tasks/ecs_task.rake +117 -6
- data/lib/putpaws/iam/grant_command.rb +205 -0
- data/lib/putpaws/iam/iam_task.rb +1 -0
- data/lib/putpaws/iam/operator_config.rb +46 -0
- data/lib/putpaws/iam/tasks/iam_task.rake +65 -0
- data/lib/putpaws/info.rb +1 -0
- data/lib/putpaws/provision/all.rb +29 -0
- data/lib/putpaws/provision/aws_clients.rb +59 -0
- data/lib/putpaws/provision/config_writer.rb +88 -0
- data/lib/putpaws/provision/policy_generator.rb +221 -0
- data/lib/putpaws/provision/preset.rb +91 -0
- data/lib/putpaws/provision/presets/rails-nginx/preset.json +36 -0
- data/lib/putpaws/provision/presets/rails-nginx/templates/taskdef-app.json.erb +33 -0
- data/lib/putpaws/provision/presets/rails-nginx/templates/taskdef-web.json.erb +52 -0
- data/lib/putpaws/provision/provision_config.rb +170 -0
- data/lib/putpaws/provision/provision_task.rb +1 -0
- data/lib/putpaws/provision/resources/base.rb +49 -0
- data/lib/putpaws/provision/resources/cluster.rb +30 -0
- data/lib/putpaws/provision/resources/codebuild_project.rb +107 -0
- data/lib/putpaws/provision/resources/iam_role.rb +89 -0
- data/lib/putpaws/provision/resources/log_group.rb +50 -0
- data/lib/putpaws/provision/resources/security_group.rb +72 -0
- data/lib/putpaws/provision/resources/service.rb +74 -0
- data/lib/putpaws/provision/resources/task_definition.rb +121 -0
- data/lib/putpaws/provision/runner.rb +218 -0
- data/lib/putpaws/provision/state.rb +45 -0
- data/lib/putpaws/provision/tasks/provision.rake +129 -0
- data/lib/putpaws/provision/util.rb +50 -0
- data/lib/putpaws/tasks/info.rake +35 -0
- data/lib/putpaws/version.rb +1 -1
- metadata +63 -6
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
require 'putpaws/provision/util'
|
|
4
|
+
require 'putpaws/provision/state'
|
|
5
|
+
require 'putpaws/provision/aws_clients'
|
|
6
|
+
require 'putpaws/provision/policy_generator'
|
|
7
|
+
require 'putpaws/provision/config_writer'
|
|
8
|
+
require 'putpaws/provision/resources/base'
|
|
9
|
+
require 'putpaws/provision/resources/iam_role'
|
|
10
|
+
require 'putpaws/provision/resources/security_group'
|
|
11
|
+
require 'putpaws/provision/resources/cluster'
|
|
12
|
+
require 'putpaws/provision/resources/log_group'
|
|
13
|
+
require 'putpaws/provision/resources/task_definition'
|
|
14
|
+
require 'putpaws/provision/resources/service'
|
|
15
|
+
require 'putpaws/provision/resources/codebuild_project'
|
|
16
|
+
|
|
17
|
+
module Putpaws
|
|
18
|
+
module Provision
|
|
19
|
+
# Orchestrates the provisioning commands:
|
|
20
|
+
# ready (provision:init) ... interview + drafts
|
|
21
|
+
# steady (provision:roles) ... create IAM roles from the reviewed drafts
|
|
22
|
+
# ahead (provision:plan) ... dry-run
|
|
23
|
+
# up (provision:up) ... build the rest, idempotent
|
|
24
|
+
#
|
|
25
|
+
# Running `steady` IS the user's explicit confirmation of the drafts:
|
|
26
|
+
# `up` never touches IAM and stops until the role ARNs are filled.
|
|
27
|
+
class Runner
|
|
28
|
+
ROLE_KEYS = [:task_execution_role_arn, :task_role_arn, :codebuild_role_arn, :scheduler_role_arn]
|
|
29
|
+
ROLE_DRAFTS = {
|
|
30
|
+
task_execution_role_arn: 'role-task-execution.json',
|
|
31
|
+
task_role_arn: 'role-task.json',
|
|
32
|
+
codebuild_role_arn: 'role-codebuild.json',
|
|
33
|
+
scheduler_role_arn: 'role-scheduler.json',
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
attr_reader :config, :state, :clients, :prompt, :io
|
|
37
|
+
def initialize(config:, state: nil, clients: nil, prompt: nil, io: $stdout)
|
|
38
|
+
@config = config
|
|
39
|
+
@state = state || State.load(config)
|
|
40
|
+
@clients = clients || AwsClients.new(region: config.region)
|
|
41
|
+
@prompt = prompt
|
|
42
|
+
@io = io
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def blank_role_keys
|
|
46
|
+
ROLE_KEYS.select{|k| Util.blank?(config.roles[k])}
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# A role is managed by `steady` when its ARN is blank (to be created) or
|
|
50
|
+
# when the filled ARN points at the draft's own role name (created by a
|
|
51
|
+
# previous `steady`; kept updatable). An ARN with a different role name
|
|
52
|
+
# is treated as external (org-managed) and never touched.
|
|
53
|
+
def steady_role_entries
|
|
54
|
+
args = {config: config, state: state, clients: clients}
|
|
55
|
+
ROLE_KEYS.map do |key|
|
|
56
|
+
resource = Resources::IamRole.new(roles_key: key, draft_file: ROLE_DRAFTS[key], **args)
|
|
57
|
+
arn = config.roles[key]
|
|
58
|
+
external = !Util.blank?(arn) && arn.split('/').last != resource.name
|
|
59
|
+
{key: key, resource: resource, external: external}
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def service_resources
|
|
64
|
+
args = {config: config, state: state, clients: clients}
|
|
65
|
+
[
|
|
66
|
+
Resources::SecurityGroup.new(**args),
|
|
67
|
+
Resources::LogGroup.new(log_group_name: config.log_group, output_key: :log_group, **args),
|
|
68
|
+
Resources::Cluster.new(**args),
|
|
69
|
+
*config.preset.task_definitions.map{|entry| Resources::TaskDefinition.new(entry: entry, **args)},
|
|
70
|
+
Resources::Service.new(**args),
|
|
71
|
+
]
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def devops_resources
|
|
75
|
+
args = {config: config, state: state, clients: clients}
|
|
76
|
+
[
|
|
77
|
+
Resources::LogGroup.new(log_group_name: config.build_log_group, output_key: :build_log_group, **args),
|
|
78
|
+
Resources::CodebuildProject.new(**args),
|
|
79
|
+
]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def missing_devops_requirements
|
|
83
|
+
missing = []
|
|
84
|
+
missing << 'devops.source_repository (provision.json)' if Util.blank?(config.devops_settings[:source_repository])
|
|
85
|
+
missing
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# `putpaws steady`: show each draft inline, confirm one by one, then
|
|
89
|
+
# apply it as-is and fill the ARN into provision.json.
|
|
90
|
+
# Idempotent: re-run after editing drafts to update.
|
|
91
|
+
def steady!
|
|
92
|
+
io.puts "Applying IAM roles from drafts in #{config.policies_dir}/"
|
|
93
|
+
filled = {}
|
|
94
|
+
steady_role_entries.each do |entry|
|
|
95
|
+
if entry[:external]
|
|
96
|
+
print_action('SKIP', 'IamRole', "#{config.roles[entry[:key]]} (external)")
|
|
97
|
+
next
|
|
98
|
+
end
|
|
99
|
+
resource = entry[:resource]
|
|
100
|
+
action = resource.plan[:action]
|
|
101
|
+
|
|
102
|
+
if action == :skip
|
|
103
|
+
print_action('SKIP', 'IamRole', resource.name)
|
|
104
|
+
else
|
|
105
|
+
io.puts ""
|
|
106
|
+
io.puts "=== #{resource.draft_file} -> #{action.to_s.upcase} role: #{resource.name} ==="
|
|
107
|
+
io.puts JSON.pretty_generate(resource.draft)
|
|
108
|
+
unless prompt.yes?("Apply this content as role #{resource.name}?")
|
|
109
|
+
io.puts "Skipped #{resource.name}"
|
|
110
|
+
next
|
|
111
|
+
end
|
|
112
|
+
print_action(action.to_s.upcase, 'IamRole', resource.name)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
outputs = resource.ensure!
|
|
116
|
+
state.merge_resources!(outputs)
|
|
117
|
+
filled[entry[:key]] = outputs[entry[:key]]
|
|
118
|
+
end
|
|
119
|
+
write_roles_to_provision_json!(filled)
|
|
120
|
+
io.puts "Next: check with `putpaws ahead`, then build with `putpaws up`."
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def plan
|
|
124
|
+
io.puts "Service: #{config.service_name} (region: #{config.region}, account: #{config.account_id})"
|
|
125
|
+
io.puts ""
|
|
126
|
+
resources = steady_role_entries.reject{|e| e[:external]}.map{|e| e[:resource]}
|
|
127
|
+
resources += service_resources
|
|
128
|
+
resources += devops_resources if missing_devops_requirements.empty?
|
|
129
|
+
resources.each do |r|
|
|
130
|
+
p = r.plan
|
|
131
|
+
print_action(p[:action].to_s.upcase, p[:kind], p[:name])
|
|
132
|
+
end
|
|
133
|
+
if blank_role_keys.any?
|
|
134
|
+
io.puts "[stop point] IAM roles are not created yet. Review the drafts, then run `putpaws steady`."
|
|
135
|
+
end
|
|
136
|
+
if missing_devops_requirements.any?
|
|
137
|
+
io.puts "[stop point] Devops step is blocked. Fill in: #{missing_devops_requirements.join(', ')}"
|
|
138
|
+
end
|
|
139
|
+
check_ssm_parameters
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def up!
|
|
143
|
+
if blank_role_keys.any?
|
|
144
|
+
io.puts "[stop point] IAM roles are not ready: #{blank_role_keys.join(', ')}"
|
|
145
|
+
io.puts "1. Review and edit the drafts in #{config.policies_dir}/"
|
|
146
|
+
io.puts "2. Run `putpaws steady` to create the roles and fill their ARNs."
|
|
147
|
+
io.puts " (or fill in existing role ARNs in provision.json yourself)"
|
|
148
|
+
return
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
io.puts "Applying service step for #{config.service_name} (account: #{config.account_id}, region: #{config.region})"
|
|
152
|
+
apply_resources(service_resources)
|
|
153
|
+
state.mark_step!(:service, 'done')
|
|
154
|
+
|
|
155
|
+
ConfigWriter.new(config: config, state: state, prompt: prompt, io: io).apply!
|
|
156
|
+
|
|
157
|
+
if missing_devops_requirements.any?
|
|
158
|
+
io.puts "[stop point] Devops step is not ready. Fill in: #{missing_devops_requirements.join(', ')}"
|
|
159
|
+
io.puts "Then run `putpaws up` again."
|
|
160
|
+
return
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
io.puts "Applying devops step"
|
|
164
|
+
apply_resources(devops_resources)
|
|
165
|
+
state.mark_step!(:devops, 'done')
|
|
166
|
+
ConfigWriter.new(config: config, state: state, prompt: prompt, io: io).apply!
|
|
167
|
+
|
|
168
|
+
io.puts "All steps completed."
|
|
169
|
+
io.puts "Verify with: bundle exec putpaws #{config.service_name} ecs:run cmd='echo ok' wait=true"
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
private
|
|
173
|
+
|
|
174
|
+
def print_action(action, kind, name)
|
|
175
|
+
io.puts format("%-8s %-18s %s", action, kind, name)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def write_roles_to_provision_json!(filled)
|
|
179
|
+
return if filled.empty?
|
|
180
|
+
path = config.dir.join('provision.json')
|
|
181
|
+
data = JSON.parse(File.read(path), symbolize_names: true)
|
|
182
|
+
data[:roles] ||= {}
|
|
183
|
+
changed = filled.reject{|k, arn| data[:roles][k] == arn}
|
|
184
|
+
return if changed.empty?
|
|
185
|
+
FileUtils.cp(path, "#{path}.bak")
|
|
186
|
+
changed.each{|k, arn| data[:roles][k] = arn}
|
|
187
|
+
Util.write_json(path, data)
|
|
188
|
+
config.data[:roles] = data[:roles]
|
|
189
|
+
io.puts "Filled role ARNs into #{path}:"
|
|
190
|
+
changed.each{|k, arn| io.puts " #{k}: #{arn}"}
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def apply_resources(resources)
|
|
194
|
+
resources.each do |r|
|
|
195
|
+
print_action(r.plan[:action].to_s.upcase, r.kind, r.name)
|
|
196
|
+
outputs = r.ensure!
|
|
197
|
+
state.merge_resources!(outputs)
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def check_ssm_parameters
|
|
202
|
+
paths = config.resolved_secrets.values
|
|
203
|
+
return if paths.empty?
|
|
204
|
+
res = clients.ssm.describe_parameters(
|
|
205
|
+
parameter_filters: [{key: 'Name', option: 'Equals', values: paths}]
|
|
206
|
+
)
|
|
207
|
+
existing = res.parameters.map(&:name)
|
|
208
|
+
missing = paths - existing
|
|
209
|
+
if missing.any?
|
|
210
|
+
io.puts "[warning] Missing SSM parameters (register them yourself, putpaws never touches values):"
|
|
211
|
+
missing.each{|p| io.puts " aws ssm put-parameter --type SecureString --name #{p} --value '...'"}
|
|
212
|
+
end
|
|
213
|
+
rescue StandardError => e
|
|
214
|
+
io.puts "(ssm parameter check skipped: #{e.class})"
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'putpaws/provision/util'
|
|
3
|
+
|
|
4
|
+
module Putpaws
|
|
5
|
+
module Provision
|
|
6
|
+
class State
|
|
7
|
+
def self.load(config)
|
|
8
|
+
path = config.dir.join('state.json')
|
|
9
|
+
data = path.exist? ? JSON.parse(File.read(path), symbolize_names: true) : {}
|
|
10
|
+
new(path: path.to_s, data: data)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
attr_reader :path, :data
|
|
14
|
+
def initialize(path:, data:)
|
|
15
|
+
@path = path
|
|
16
|
+
@data = data
|
|
17
|
+
@data[:resources] ||= {}
|
|
18
|
+
@data[:steps] ||= {}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def resources
|
|
22
|
+
data[:resources]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def steps
|
|
26
|
+
data[:steps]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def merge_resources!(outputs)
|
|
30
|
+
resources.merge!(outputs.map{|k, v| [k.to_sym, v]}.to_h)
|
|
31
|
+
save!
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def mark_step!(name, status)
|
|
35
|
+
steps[name.to_sym] = status
|
|
36
|
+
save!
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def save!
|
|
40
|
+
data[:updated_at] = Time.now.to_s
|
|
41
|
+
Util.write_json(path, data)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
require "fileutils"
|
|
2
|
+
require "putpaws/prompt"
|
|
3
|
+
require "putpaws/provision/all"
|
|
4
|
+
|
|
5
|
+
namespace :provision do
|
|
6
|
+
desc "Interview basic infra inputs and generate provision.json + IAM policy drafts. (alias: ready)"
|
|
7
|
+
task :init do
|
|
8
|
+
prompt = Putpaws::Prompt.safe
|
|
9
|
+
util = Putpaws::Provision::Util
|
|
10
|
+
|
|
11
|
+
service_name = ENV['service'] || prompt.ask("Application name (Ex: awesome-api-staging):") do |q|
|
|
12
|
+
q.required(true)
|
|
13
|
+
q.validate(/\A[a-z0-9][a-z0-9\-]*\z/, "lowercase letters, numbers and hyphens only")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
dir = Putpaws::Provision::ProvisionConfig.dir_for(service_name)
|
|
17
|
+
if dir.join('provision.json').exist?
|
|
18
|
+
unless prompt.yes?("#{dir}/provision.json already exists. Overwrite?", default: false)
|
|
19
|
+
puts "Aborted."
|
|
20
|
+
next
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
region = prompt.ask("Region:", default: 'ap-northeast-1')
|
|
25
|
+
preset_choices = Putpaws::Provision::Preset.catalog.map{|e| ["#{e[:name]} (#{e[:source]})", e[:name]]}.to_h
|
|
26
|
+
preset_name = prompt.select("Preset:", preset_choices)
|
|
27
|
+
|
|
28
|
+
puts "--- Basic infra (existing resources; used to generate IAM policies) ---"
|
|
29
|
+
vpc_id = prompt.ask("VPC ID:"){|q| q.required(true)}
|
|
30
|
+
subnets = prompt.ask("Subnet IDs (comma separated):"){|q| q.required(true)}.split(',').map(&:strip)
|
|
31
|
+
sg_ids = prompt.ask("Security group IDs (existing, comma separated, empty to create a new one):")
|
|
32
|
+
.to_s.split(',').map(&:strip).reject(&:empty?)
|
|
33
|
+
ecr_arn = prompt.ask("ECR repository ARN:"){|q| q.required(true)}
|
|
34
|
+
ses_arn = prompt.ask("SES identity ARN (empty to skip):")
|
|
35
|
+
s3_arn = prompt.ask("S3 bucket ARN (empty to skip):")
|
|
36
|
+
ssm_prefix = prompt.ask("SSM parameter path prefix (existing; putpaws never writes values):", default: "/#{service_name}")
|
|
37
|
+
repo = prompt.ask("CodeBuild source repository URL (GitHub, empty to fill later):")
|
|
38
|
+
|
|
39
|
+
data = {
|
|
40
|
+
service_name: service_name,
|
|
41
|
+
region: region,
|
|
42
|
+
preset: preset_name,
|
|
43
|
+
base: {
|
|
44
|
+
vpc_id: vpc_id,
|
|
45
|
+
subnets: subnets,
|
|
46
|
+
security_group_ids: sg_ids,
|
|
47
|
+
ecr_repository_arn: ecr_arn,
|
|
48
|
+
ses_identity_arn: util.blank?(ses_arn) ? nil : ses_arn,
|
|
49
|
+
s3_bucket_arn: util.blank?(s3_arn) ? nil : s3_arn,
|
|
50
|
+
ssm_parameter_prefix: ssm_prefix,
|
|
51
|
+
},
|
|
52
|
+
roles: {
|
|
53
|
+
task_execution_role_arn: nil,
|
|
54
|
+
task_role_arn: nil,
|
|
55
|
+
codebuild_role_arn: nil,
|
|
56
|
+
scheduler_role_arn: nil,
|
|
57
|
+
},
|
|
58
|
+
overrides: {
|
|
59
|
+
cluster_name: nil,
|
|
60
|
+
cpu: nil,
|
|
61
|
+
memory: nil,
|
|
62
|
+
desired_count: nil,
|
|
63
|
+
env: {},
|
|
64
|
+
secrets: {},
|
|
65
|
+
},
|
|
66
|
+
devops: {
|
|
67
|
+
source_repository: util.blank?(repo) ? nil : repo,
|
|
68
|
+
buildspec: "buildspec.yml",
|
|
69
|
+
},
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
Putpaws::Provision::Preset.install(preset_name)
|
|
73
|
+
FileUtils.mkdir_p(dir)
|
|
74
|
+
util.write_json(dir.join('provision.json'), data)
|
|
75
|
+
|
|
76
|
+
config = Putpaws::Provision::ProvisionConfig.new(data)
|
|
77
|
+
files = Putpaws::Provision::PolicyGenerator.new(config).write_step1_drafts!
|
|
78
|
+
|
|
79
|
+
puts ""
|
|
80
|
+
puts "Generated:"
|
|
81
|
+
puts " #{dir}/provision.json"
|
|
82
|
+
files.each{|f| puts " #{f}"}
|
|
83
|
+
puts ""
|
|
84
|
+
puts "Next steps:"
|
|
85
|
+
puts " 1. Review and edit the role drafts in policies/."
|
|
86
|
+
puts " When confirmed, run `putpaws steady` to create the IAM roles from the drafts as-is."
|
|
87
|
+
puts " (or fill in existing role ARNs in provision.json instead)"
|
|
88
|
+
puts " 2. Register SSM parameters (Ex: #{ssm_prefix}/RAILS_MASTER_KEY) yourself."
|
|
89
|
+
puts " 3. Check with `putpaws ahead`, then build with `putpaws up`."
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
desc "Create IAM roles from the reviewed drafts and fill their ARNs into provision.json. Each role is shown and confirmed one by one. Idempotent. (alias: steady)"
|
|
93
|
+
task :roles do
|
|
94
|
+
config = Putpaws::Provision.resolve_config
|
|
95
|
+
prompt = Putpaws::Prompt.safe
|
|
96
|
+
puts "Service: #{config.service_name} / Account: #{config.account_id} / Region: #{config.region}"
|
|
97
|
+
Putpaws::Provision::Runner.new(config: config, prompt: prompt).steady!
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
desc "Show what `putpaws up` would do (dry-run). (alias: ahead)"
|
|
101
|
+
task :plan do
|
|
102
|
+
config = Putpaws::Provision.resolve_config
|
|
103
|
+
Putpaws::Provision::Runner.new(config: config, prompt: Putpaws::Prompt.safe).plan
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
desc "Build infra as far as possible, stopping where manual steps are required. Re-runnable. (alias: up)"
|
|
107
|
+
task :up do
|
|
108
|
+
config = Putpaws::Provision.resolve_config
|
|
109
|
+
prompt = Putpaws::Prompt.safe
|
|
110
|
+
puts "Service: #{config.service_name} / Account: #{config.account_id} / Region: #{config.region}"
|
|
111
|
+
unless prompt.yes?("Proceed?")
|
|
112
|
+
puts "Aborted."
|
|
113
|
+
next
|
|
114
|
+
end
|
|
115
|
+
Putpaws::Provision::Runner.new(config: config, prompt: prompt).up!
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
desc "Alias of provision:init"
|
|
120
|
+
task ready: 'provision:init'
|
|
121
|
+
|
|
122
|
+
desc "Alias of provision:roles"
|
|
123
|
+
task steady: 'provision:roles'
|
|
124
|
+
|
|
125
|
+
desc "Alias of provision:up"
|
|
126
|
+
task up: 'provision:up'
|
|
127
|
+
|
|
128
|
+
desc "Alias of provision:plan"
|
|
129
|
+
task ahead: 'provision:plan'
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
module Putpaws
|
|
4
|
+
module Provision
|
|
5
|
+
module Util
|
|
6
|
+
module_function
|
|
7
|
+
|
|
8
|
+
def underscore(str)
|
|
9
|
+
str.to_s.gsub(/([a-z0-9])([A-Z])/, '\1_\2').downcase
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Task definition JSON is written in camelCase convention.
|
|
13
|
+
# Convert it into snake_case symbol keys for aws-sdk params.
|
|
14
|
+
def deep_underscore_keys(obj)
|
|
15
|
+
case obj
|
|
16
|
+
when Hash
|
|
17
|
+
obj.map{|k, v| [underscore(k).to_sym, deep_underscore_keys(v)]}.to_h
|
|
18
|
+
when Array
|
|
19
|
+
obj.map{|x| deep_underscore_keys(x)}
|
|
20
|
+
else
|
|
21
|
+
obj
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def arn_account_id(arn)
|
|
26
|
+
arn.to_s.split(':')[4]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def arn_region(arn)
|
|
30
|
+
arn.to_s.split(':')[3]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def ecr_repository_name(arn)
|
|
34
|
+
arn.to_s.split(':', 6).last.to_s.sub(/\Arepository\//, '')
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def ecr_repository_uri(arn)
|
|
38
|
+
"#{arn_account_id(arn)}.dkr.ecr.#{arn_region(arn)}.amazonaws.com/#{ecr_repository_name(arn)}"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def blank?(value)
|
|
42
|
+
value.nil? || value.to_s.strip.empty?
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def write_json(path, data)
|
|
46
|
+
File.write(path, JSON.pretty_generate(data) + "\n")
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
desc "Show resolved settings for the service. No AWS access."
|
|
2
|
+
task :info do
|
|
3
|
+
app = fetch(:app)
|
|
4
|
+
row = ->(key, value){ puts format("%-26s %s", "#{key}:", value) unless value.nil? }
|
|
5
|
+
|
|
6
|
+
row.call('name', app.name)
|
|
7
|
+
row.call('region', app.region)
|
|
8
|
+
row.call('cluster', app.cluster)
|
|
9
|
+
row.call('service', app.service)
|
|
10
|
+
row.call('task_name_prefix', app.task_name_prefix)
|
|
11
|
+
row.call('ecs_region', app.ecs_region)
|
|
12
|
+
row.call('log_group_prefix', app.log_group_prefix)
|
|
13
|
+
row.call('log_region', app.log_region)
|
|
14
|
+
row.call('build_project_name_prefix', app.build_project_name_prefix)
|
|
15
|
+
row.call('build_log_group_prefix', app.build_log_group_prefix)
|
|
16
|
+
row.call('build_region', app.build_region)
|
|
17
|
+
|
|
18
|
+
if (network = app.network)
|
|
19
|
+
row.call('network', network.name)
|
|
20
|
+
row.call(' subnets', network.subnets && network.subnets.join(', '))
|
|
21
|
+
row.call(' security_groups', network.security_groups && network.security_groups.join(', '))
|
|
22
|
+
row.call(' assign_public_ip', network.assign_public_ip)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
if (target = app.target)
|
|
26
|
+
row.call('target', target.name)
|
|
27
|
+
row.call(' cluster', target.cluster)
|
|
28
|
+
row.call(' task_definition', target.task_definition)
|
|
29
|
+
row.call(' container_name', target.container_name)
|
|
30
|
+
row.call(' scheduler_role', target.scheduler_role)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
schedules = app.schedules
|
|
34
|
+
row.call('schedules', schedules.map(&:name).join(', ')) unless schedules.empty?
|
|
35
|
+
end
|
data/lib/putpaws/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: putpaws
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.1.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- metheglin
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: rake
|
|
@@ -66,6 +65,34 @@ dependencies:
|
|
|
66
65
|
- - ">="
|
|
67
66
|
- !ruby/object:Gem::Version
|
|
68
67
|
version: '0'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: aws-sdk-ec2
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0'
|
|
75
|
+
type: :runtime
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0'
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: aws-sdk-iam
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '0'
|
|
89
|
+
type: :runtime
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - ">="
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '0'
|
|
69
96
|
- !ruby/object:Gem::Dependency
|
|
70
97
|
name: aws-sdk-cloudwatchlogs
|
|
71
98
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -119,6 +146,9 @@ files:
|
|
|
119
146
|
- bin/putpaws
|
|
120
147
|
- lib/Putpawsfile
|
|
121
148
|
- lib/putpaws.rb
|
|
149
|
+
- lib/putpaws/ai/ai_task.rb
|
|
150
|
+
- lib/putpaws/ai/guide.rb
|
|
151
|
+
- lib/putpaws/ai/tasks/ai_task.rake
|
|
122
152
|
- lib/putpaws/all.rb
|
|
123
153
|
- lib/putpaws/application.rb
|
|
124
154
|
- lib/putpaws/application_config.rb
|
|
@@ -131,25 +161,53 @@ files:
|
|
|
131
161
|
- lib/putpaws/code_build/tasks/build_task.rake
|
|
132
162
|
- lib/putpaws/dsl.rb
|
|
133
163
|
- lib/putpaws/ecs/ecs_task.rb
|
|
164
|
+
- lib/putpaws/ecs/run_command.rb
|
|
134
165
|
- lib/putpaws/ecs/task_command.rb
|
|
135
166
|
- lib/putpaws/ecs/tasks/ecs_task.rake
|
|
136
167
|
- lib/putpaws/env.rb
|
|
137
168
|
- lib/putpaws/hello.rb
|
|
169
|
+
- lib/putpaws/iam/grant_command.rb
|
|
170
|
+
- lib/putpaws/iam/iam_task.rb
|
|
171
|
+
- lib/putpaws/iam/operator_config.rb
|
|
172
|
+
- lib/putpaws/iam/tasks/iam_task.rake
|
|
173
|
+
- lib/putpaws/info.rb
|
|
138
174
|
- lib/putpaws/infra_network_config.rb
|
|
139
175
|
- lib/putpaws/infra_target_config.rb
|
|
140
176
|
- lib/putpaws/prompt.rb
|
|
177
|
+
- lib/putpaws/provision/all.rb
|
|
178
|
+
- lib/putpaws/provision/aws_clients.rb
|
|
179
|
+
- lib/putpaws/provision/config_writer.rb
|
|
180
|
+
- lib/putpaws/provision/policy_generator.rb
|
|
181
|
+
- lib/putpaws/provision/preset.rb
|
|
182
|
+
- lib/putpaws/provision/presets/rails-nginx/preset.json
|
|
183
|
+
- lib/putpaws/provision/presets/rails-nginx/templates/taskdef-app.json.erb
|
|
184
|
+
- lib/putpaws/provision/presets/rails-nginx/templates/taskdef-web.json.erb
|
|
185
|
+
- lib/putpaws/provision/provision_config.rb
|
|
186
|
+
- lib/putpaws/provision/provision_task.rb
|
|
187
|
+
- lib/putpaws/provision/resources/base.rb
|
|
188
|
+
- lib/putpaws/provision/resources/cluster.rb
|
|
189
|
+
- lib/putpaws/provision/resources/codebuild_project.rb
|
|
190
|
+
- lib/putpaws/provision/resources/iam_role.rb
|
|
191
|
+
- lib/putpaws/provision/resources/log_group.rb
|
|
192
|
+
- lib/putpaws/provision/resources/security_group.rb
|
|
193
|
+
- lib/putpaws/provision/resources/service.rb
|
|
194
|
+
- lib/putpaws/provision/resources/task_definition.rb
|
|
195
|
+
- lib/putpaws/provision/runner.rb
|
|
196
|
+
- lib/putpaws/provision/state.rb
|
|
197
|
+
- lib/putpaws/provision/tasks/provision.rake
|
|
198
|
+
- lib/putpaws/provision/util.rb
|
|
141
199
|
- lib/putpaws/schedule_config.rb
|
|
142
200
|
- lib/putpaws/scheduler/schedule_command.rb
|
|
143
201
|
- lib/putpaws/scheduler/scheduler_task.rb
|
|
144
202
|
- lib/putpaws/scheduler/tasks/scheduler_task.rake
|
|
145
203
|
- lib/putpaws/setup.rb
|
|
146
204
|
- lib/putpaws/tasks/hello.rake
|
|
205
|
+
- lib/putpaws/tasks/info.rake
|
|
147
206
|
- lib/putpaws/version.rb
|
|
148
207
|
homepage: https://rubygems.org/gems/putpaws
|
|
149
208
|
licenses:
|
|
150
209
|
- MIT
|
|
151
210
|
metadata: {}
|
|
152
|
-
post_install_message:
|
|
153
211
|
rdoc_options: []
|
|
154
212
|
require_paths:
|
|
155
213
|
- lib
|
|
@@ -164,8 +222,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
164
222
|
- !ruby/object:Gem::Version
|
|
165
223
|
version: '0'
|
|
166
224
|
requirements: []
|
|
167
|
-
rubygems_version:
|
|
168
|
-
signing_key:
|
|
225
|
+
rubygems_version: 4.0.16
|
|
169
226
|
specification_version: 4
|
|
170
227
|
summary: Put your paws up!!
|
|
171
228
|
test_files: []
|