aws-rails-provisioner 0.0.0.rc1
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 +7 -0
- data/bin/aws-rails-provisioner +132 -0
- data/lib/aws-rails-provisioner.rb +42 -0
- data/lib/aws-rails-provisioner/build.rb +43 -0
- data/lib/aws-rails-provisioner/cdk_builder.rb +68 -0
- data/lib/aws-rails-provisioner/cdk_code_builder.rb +140 -0
- data/lib/aws-rails-provisioner/cdk_deployer.rb +62 -0
- data/lib/aws-rails-provisioner/code_build.rb +28 -0
- data/lib/aws-rails-provisioner/db_cluster.rb +299 -0
- data/lib/aws-rails-provisioner/errors.rb +24 -0
- data/lib/aws-rails-provisioner/fargate.rb +93 -0
- data/lib/aws-rails-provisioner/migration.rb +45 -0
- data/lib/aws-rails-provisioner/parser.rb +22 -0
- data/lib/aws-rails-provisioner/scaling.rb +448 -0
- data/lib/aws-rails-provisioner/service.rb +90 -0
- data/lib/aws-rails-provisioner/services.rb +44 -0
- data/lib/aws-rails-provisioner/subnet_selection.rb +20 -0
- data/lib/aws-rails-provisioner/utils.rb +89 -0
- data/lib/aws-rails-provisioner/version.rb +5 -0
- data/lib/aws-rails-provisioner/view.rb +29 -0
- data/lib/aws-rails-provisioner/views/fargate_stack.rb +100 -0
- data/lib/aws-rails-provisioner/views/init_stack.rb +35 -0
- data/lib/aws-rails-provisioner/views/pipeline_stack.rb +107 -0
- data/lib/aws-rails-provisioner/views/project.rb +33 -0
- data/lib/aws-rails-provisioner/vpc.rb +111 -0
- data/templates/fargate_stack.mustache +316 -0
- data/templates/init_stack.mustache +50 -0
- data/templates/pipeline_stack.mustache +156 -0
- data/templates/project.mustache +33 -0
- metadata +115 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Aws::RailsProvisioner
|
4
|
+
# @api private
|
5
|
+
class Service
|
6
|
+
|
7
|
+
def initialize(name, options = {})
|
8
|
+
@name = name.to_s
|
9
|
+
@file_path = options[:file_path] || 'aws-rails-provisioner.yml'
|
10
|
+
@stack_prefix = _camel_case(@name)
|
11
|
+
@path_prefix = _path_prefix(@name)
|
12
|
+
@const_prefix = _const_prefix(@stack_prefix)
|
13
|
+
@enable_cicd = !!options[:enable_cicd]
|
14
|
+
@profile = options[:profile]
|
15
|
+
@packages = Set.new
|
16
|
+
|
17
|
+
# fargate stack
|
18
|
+
@source_path = options.fetch(:source_path)
|
19
|
+
@fargate = options[:fargate] || {}
|
20
|
+
|
21
|
+
@db_cluster = options[:db_cluster]
|
22
|
+
@scaling = options[:scaling]
|
23
|
+
|
24
|
+
# pipeline stack
|
25
|
+
@cicd = options[:cicd] || {}
|
26
|
+
end
|
27
|
+
|
28
|
+
# @return [String]
|
29
|
+
attr_reader :name
|
30
|
+
|
31
|
+
# @return [String]
|
32
|
+
attr_reader :stack_prefix
|
33
|
+
|
34
|
+
# @return [String]
|
35
|
+
attr_reader :path_prefix
|
36
|
+
|
37
|
+
# @return [String]
|
38
|
+
attr_reader :const_prefix
|
39
|
+
|
40
|
+
# @return [Boolean]
|
41
|
+
attr_reader :enable_cicd
|
42
|
+
|
43
|
+
# @return [Set]
|
44
|
+
attr_reader :packages
|
45
|
+
|
46
|
+
def fargate_stack
|
47
|
+
stack = Aws::RailsProvisioner::Views::FargateStack.new(
|
48
|
+
file_path: @file_path,
|
49
|
+
service_name: @name,
|
50
|
+
path_prefix: @path_prefix,
|
51
|
+
stack_prefix: @stack_prefix,
|
52
|
+
profile: @profile,
|
53
|
+
source_path: @source_path,
|
54
|
+
db_cluster: @db_cluster,
|
55
|
+
fargate: @fargate,
|
56
|
+
scaling: @scaling,
|
57
|
+
)
|
58
|
+
@packages.merge(stack.packages)
|
59
|
+
stack.render
|
60
|
+
end
|
61
|
+
|
62
|
+
def pipeline_stack
|
63
|
+
if @db_cluster.nil? || @db_cluster.empty?
|
64
|
+
@cicd[:skip_migration] = true
|
65
|
+
end
|
66
|
+
@cicd[:source_path] = @source_path
|
67
|
+
@cicd[:stack_prefix] = @stack_prefix
|
68
|
+
stack = Aws::RailsProvisioner::Views::PipelineStack.new(@cicd)
|
69
|
+
@packages.merge(stack.packages)
|
70
|
+
stack.render
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def _camel_case(str)
|
76
|
+
str.split('_').collect(&:capitalize).join
|
77
|
+
end
|
78
|
+
|
79
|
+
def _path_prefix(str)
|
80
|
+
str.downcase.gsub('_', '-')
|
81
|
+
end
|
82
|
+
|
83
|
+
def _const_prefix(str)
|
84
|
+
dup = str.dup
|
85
|
+
dup[0] = dup[0].downcase
|
86
|
+
dup
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Aws::RailsProvisioner
|
2
|
+
# @api private
|
3
|
+
class ServiceEnumerator
|
4
|
+
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
@configs = options || {}
|
9
|
+
end
|
10
|
+
|
11
|
+
# @param [String] name
|
12
|
+
def [](name)
|
13
|
+
if services.key?(name)
|
14
|
+
services[name]
|
15
|
+
else
|
16
|
+
msg = "unknown service #{identifier.inspect} under :services"
|
17
|
+
raise Aws::RailsProvisioner::ValidationError, msg
|
18
|
+
end
|
19
|
+
end
|
20
|
+
alias service []
|
21
|
+
|
22
|
+
def each(&block)
|
23
|
+
services.values.each(&block)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def services
|
29
|
+
@service ||= begin
|
30
|
+
@configs.inject({}) do |hash, (name, config)|
|
31
|
+
hash[name] = build_service(name, config)
|
32
|
+
hash
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def build_service(name, config)
|
38
|
+
Aws::RailsProvisioner::Service.new(name, config)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
Services = ServiceEnumerator.new
|
44
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Aws::RailsProvisioner
|
2
|
+
class SubnetSelection
|
3
|
+
|
4
|
+
def initialize(options = {})
|
5
|
+
@name = options[:name]
|
6
|
+
@type = Aws::RailsProvisioner::Util.subnet_type(options[:type]) if options[:type]
|
7
|
+
if @name && @type
|
8
|
+
msg = "At most one of :type and :name can be supplied."
|
9
|
+
raise Aws::RailsProvisioner::Errors::ValidationError, msg
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [String]
|
14
|
+
attr_reader :name
|
15
|
+
|
16
|
+
# @return [String]
|
17
|
+
attr_reader :type
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Aws::RailsProvisioner
|
4
|
+
# @api private
|
5
|
+
module Utils
|
6
|
+
|
7
|
+
def self.ip_address_type(str)
|
8
|
+
types = %w(ipv4, dualstack)
|
9
|
+
if types.include?(str.downcase)
|
10
|
+
str.upcase
|
11
|
+
else
|
12
|
+
msg = "Unsupported ip address type, please choose from #{types}"
|
13
|
+
raise Aws::RailsProvisioner::Errors::ValidationError, msg
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.subnet_type(str)
|
18
|
+
types = %w(isolated private public)
|
19
|
+
if types.include?(str.downcase)
|
20
|
+
str.upcase
|
21
|
+
else
|
22
|
+
msg = "Unsupported subnet type, please choose from #{types}"
|
23
|
+
raise Aws::RailsProvisioner::Errors::ValidationError, msg
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.removal_policy(str)
|
28
|
+
types = %w(retain destroy)
|
29
|
+
if types.include?(str.downcase)
|
30
|
+
str.upcase
|
31
|
+
else
|
32
|
+
msg = "Unsupported removal policy, please choose from #{types}"
|
33
|
+
raise Aws::RailsProvisioner::Errors::ValidationError, msg
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.protocol(str)
|
38
|
+
types = %w(https http tcp tls)
|
39
|
+
if types.include?(str.downcase)
|
40
|
+
str.upcase
|
41
|
+
else
|
42
|
+
msg = "Unsupported protocol type, please choose from #{types}"
|
43
|
+
raise Aws::RailsProvisioner::Errors::ValidationError, msg
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.adjustment_type(str)
|
48
|
+
types = %w(change_in_capacity percent_change_in_capacity exact_capacity)
|
49
|
+
if types.include?(str.downcase)
|
50
|
+
str.upcase
|
51
|
+
else
|
52
|
+
msg = "Unsupported adjustment type, please choose from #{types}"
|
53
|
+
raise Aws::RailsProvisioner::Errors::ValidationError, msg
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.parse(file_path)
|
58
|
+
config = YAML.load(File.read(file_path))
|
59
|
+
symbolize_keys(config)
|
60
|
+
rescue
|
61
|
+
raise Aws::RailsProvisioner::Errors::InvalidYAMLFile.new
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.to_pairs(hash)
|
65
|
+
hash.inject([]) do |arr, (key, value)|
|
66
|
+
arr << "'#{key}': '#{value}',"
|
67
|
+
arr
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.to_pkgs(services)
|
72
|
+
services.inject([]) do |pkgs, svc|
|
73
|
+
pkgs << "@aws-cdk/aws-#{svc}"
|
74
|
+
pkgs
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def self.symbolize_keys(hash)
|
81
|
+
hash.inject({}) do |h, (k,v)|
|
82
|
+
v = symbolize_keys(v) if v.respond_to?(:keys)
|
83
|
+
h[k.to_sym] = v
|
84
|
+
h
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'mustache'
|
2
|
+
|
3
|
+
module Aws::RailsProvisioner
|
4
|
+
# @api private
|
5
|
+
class View < Mustache
|
6
|
+
|
7
|
+
TEMPLATE_DIR = File.expand_path('../../../templates', __FILE__)
|
8
|
+
|
9
|
+
def self.inherited(subclass)
|
10
|
+
parts = subclass.name.split('::')
|
11
|
+
parts.shift #=> remove AWS
|
12
|
+
parts.shift #=> remove RailsProvisioner
|
13
|
+
parts.shift #=> remove Views
|
14
|
+
path = parts.map { |part| underscore(part) }.join('/')
|
15
|
+
subclass.template_path = TEMPLATE_DIR
|
16
|
+
subclass.template_file = "#{TEMPLATE_DIR}/#{path}.mustache"
|
17
|
+
subclass.raise_on_context_miss = true
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def underscore(str)
|
23
|
+
string = str.dup
|
24
|
+
string.scan(/[a-z0-9]+|\d+|[A-Z0-9]+[a-z]*/).join('_'.freeze)
|
25
|
+
string.downcase!
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Aws::RailsProvisioner
|
2
|
+
module Views
|
3
|
+
|
4
|
+
class FargateStack < View
|
5
|
+
|
6
|
+
# Fargate Stack Generation
|
7
|
+
#
|
8
|
+
# @param [Hash] options
|
9
|
+
#
|
10
|
+
# @option options [String] :source_path relative path from `aws-rails-provisioner.yml`
|
11
|
+
# to the directory containing Rails Application source
|
12
|
+
#
|
13
|
+
# @option options [Hash] :db_cluster
|
14
|
+
# @see {Aws::RailsProvisioner::DBCluster}
|
15
|
+
#
|
16
|
+
# @option options [Hash] :fargate configurations for
|
17
|
+
# fargate service.
|
18
|
+
# @see {Aws::RailsProvisioner::Fargate}
|
19
|
+
#
|
20
|
+
# @option options [Hash] :scaling configurations for
|
21
|
+
# scaling setting for Fargate service
|
22
|
+
# @see {Aws::RailsProvisioner::Scaling}
|
23
|
+
#
|
24
|
+
def initialize(options = {})
|
25
|
+
# code gen only
|
26
|
+
@service_name = options[:service_name]
|
27
|
+
@path_prefix = options[:path_prefix]
|
28
|
+
@stack_prefix = options[:stack_prefix]
|
29
|
+
@profile = options[:profile]
|
30
|
+
|
31
|
+
dir = File.dirname(File.expand_path(options[:file_path]))
|
32
|
+
@source_path = File.join(dir, options[:source_path])
|
33
|
+
@rds_config = options[:db_cluster] || {}
|
34
|
+
@fargate_config = options[:fargate] || {}
|
35
|
+
@scaling_config = options[:scaling] || {}
|
36
|
+
end
|
37
|
+
|
38
|
+
# @return [String]
|
39
|
+
attr_reader :stack_prefix
|
40
|
+
|
41
|
+
# @return [String]
|
42
|
+
attr_reader :source_path
|
43
|
+
|
44
|
+
def services
|
45
|
+
base = [
|
46
|
+
{ abbr: 'ec2', value: 'ec2' },
|
47
|
+
{ abbr: 'ecs', value: 'ecs' },
|
48
|
+
{ abbr: 'ecr', value: 'ecr' },
|
49
|
+
{ abbr: 'ecs_patterns', value: 'ecs-patterns' },
|
50
|
+
{ abbr: 'ecr_assets', value: 'ecr-assets' },
|
51
|
+
{ abbr: 'rds', value: 'rds' }
|
52
|
+
]
|
53
|
+
if @fargate_config && @fargate_config[:certificate]
|
54
|
+
base << { abbr: 'certificatemanager', value: 'certificatemanager' }
|
55
|
+
end
|
56
|
+
if @scaling_config &&
|
57
|
+
(@scaling_config[:on_metric] || @scaling_config[:on_custom_metric])
|
58
|
+
base << { abbr: 'cloudwatch', value: 'cloudwatch' }
|
59
|
+
end
|
60
|
+
if @rds_config && !@rds_config.empty?
|
61
|
+
base << { abbr: 'secretsmanager', value: 'secretsmanager' }
|
62
|
+
if @rds_config[:kms_key_arn]
|
63
|
+
base << { abbr: 'kms', value: 'kms'}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
base
|
67
|
+
end
|
68
|
+
|
69
|
+
def packages
|
70
|
+
keys = services.map {|svc| svc[:value] }
|
71
|
+
Aws::RailsProvisioner::Utils.to_pkgs(keys)
|
72
|
+
end
|
73
|
+
|
74
|
+
def db_cluster
|
75
|
+
if @rds_config && !@rds_config.empty?
|
76
|
+
unless @rds_config[:username]
|
77
|
+
@rds_config[:username] = "#{stack_prefix}DBAdminUser"
|
78
|
+
end
|
79
|
+
@rds_config[:profile] = @profile if @profile
|
80
|
+
Aws::RailsProvisioner::DBCluster.new(@rds_config)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def fargate
|
85
|
+
if @rds_config && !@rds_config.empty?
|
86
|
+
@fargate_config[:has_db] = true
|
87
|
+
end
|
88
|
+
@fargate_config[:service_name] = @stack_prefix
|
89
|
+
Aws::RailsProvisioner::Fargate.new(@fargate_config)
|
90
|
+
end
|
91
|
+
|
92
|
+
def scaling
|
93
|
+
if @scaling_config && !@scaling_config.empty?
|
94
|
+
Aws::RailsProvisioner::Scaling.new(@scaling_config)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Aws::RailsProvisioner
|
2
|
+
module Views
|
3
|
+
class InitStack < View
|
4
|
+
|
5
|
+
# For InitStack Generation
|
6
|
+
#
|
7
|
+
# @param [Hash] options
|
8
|
+
#
|
9
|
+
# @option options [Hash] :vpc
|
10
|
+
# @see {Aws::RailsProvisioner::Vpc}
|
11
|
+
#
|
12
|
+
def initialize(options = {})
|
13
|
+
@vpc_config = options[:vpc]
|
14
|
+
@stack_prefix = options[:stack_prefix]
|
15
|
+
end
|
16
|
+
|
17
|
+
# @api private
|
18
|
+
# @return [String]
|
19
|
+
attr_reader :stack_prefix
|
20
|
+
|
21
|
+
def services
|
22
|
+
['ec2', 'ecs']
|
23
|
+
end
|
24
|
+
|
25
|
+
def packages
|
26
|
+
Aws::RailsProvisioner::Utils.to_pkgs(services)
|
27
|
+
end
|
28
|
+
|
29
|
+
def vpc
|
30
|
+
Aws::RailsProvisioner::Vpc.new(@vpc_config)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module Aws::RailsProvisioner
|
2
|
+
module Views
|
3
|
+
class PipelineStack < View
|
4
|
+
|
5
|
+
# Pipeline (CICD) Generation under :cicd
|
6
|
+
#
|
7
|
+
# @param [Hash] options
|
8
|
+
#
|
9
|
+
# @option options [String] :pipeline_name Name for the
|
10
|
+
# AWS CodePipeline generated
|
11
|
+
#
|
12
|
+
# @option options [String] :source_repo CodeCommit Repo
|
13
|
+
# name for holding your rails app source, default to
|
14
|
+
# folder name where your rails app lives
|
15
|
+
#
|
16
|
+
# @option options [String] :source_description Description for
|
17
|
+
# the CodeCommit Repo, default to 'created by aws-rails-provisioner'
|
18
|
+
#
|
19
|
+
# @option options [Hash] :build configurations for codebuild project
|
20
|
+
# for building images
|
21
|
+
# @see {Aws::RailsProvisioner::Build}
|
22
|
+
#
|
23
|
+
# @option options [Hash] :migration configuration for db migration
|
24
|
+
# codebuild, available if :db_cluster is configured
|
25
|
+
# @see {Aws::RailsProvisioner::Migration}
|
26
|
+
#
|
27
|
+
def initialize(options = {})
|
28
|
+
@stack_prefix = options[:stack_prefix]
|
29
|
+
|
30
|
+
@pipeline_name = options[:pipeline_name] || "#{@stack_prefix}Pipeline"
|
31
|
+
@source_repo = options[:source_repo] || _extract_repo_name(options[:source_path])
|
32
|
+
@source_description = options[:source_description] || "created by aws-rails-provisioner with AWS CDK for #{@stack_prefix}"
|
33
|
+
|
34
|
+
@build_config = options[:build] || {}
|
35
|
+
unless @build_config[:project_name]
|
36
|
+
@build_config[:project_name] = "#{@stack_prefix}ImageBuild"
|
37
|
+
end
|
38
|
+
|
39
|
+
@skip_migration = options[:skip_migration] || false
|
40
|
+
unless @skip_migration
|
41
|
+
@migration_config = options[:migration] || {}
|
42
|
+
unless @migration_config[:project_name]
|
43
|
+
@migration_config[:project_name] = "#{@stack_prefix}DBMigration"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def services
|
49
|
+
[
|
50
|
+
{ abbr: 'iam', value: 'iam'},
|
51
|
+
{ abbr: 'ec2', value: 'ec2'},
|
52
|
+
{ abbr: 'ecr', value: 'ecr' },
|
53
|
+
{ abbr: 'ecs', value: 'ecs' },
|
54
|
+
{ abbr: 'rds', value: 'rds' },
|
55
|
+
{ abbr: 'codebuild', value: 'codebuild'},
|
56
|
+
{ abbr: 'codecommit', value: 'codecommit'},
|
57
|
+
{ abbr: 'codepipeline', value: 'codepipeline' },
|
58
|
+
{ abbr: 'pipelineactions', value: 'codepipeline-actions'}
|
59
|
+
]
|
60
|
+
end
|
61
|
+
|
62
|
+
def packages
|
63
|
+
keys = services.map {|svc| svc[:value] }
|
64
|
+
Aws::RailsProvisioner::Utils.to_pkgs(keys)
|
65
|
+
end
|
66
|
+
|
67
|
+
# @return [String]
|
68
|
+
attr_reader :stack_prefix
|
69
|
+
|
70
|
+
# @return [String]
|
71
|
+
attr_reader :pipeline_name
|
72
|
+
|
73
|
+
# @return [String]
|
74
|
+
attr_reader :source_repo
|
75
|
+
|
76
|
+
# @return [String]
|
77
|
+
attr_reader :source_description
|
78
|
+
|
79
|
+
# @return [Aws::RailsProvisioner::Build]
|
80
|
+
attr_reader :build
|
81
|
+
|
82
|
+
# @return [Aws::RailsProvisioner::Migration]
|
83
|
+
attr_reader :migration
|
84
|
+
|
85
|
+
# @return [Boolean]
|
86
|
+
attr_reader :skip_migration
|
87
|
+
|
88
|
+
def build
|
89
|
+
Aws::RailsProvisioner::Build.new(@build_config)
|
90
|
+
end
|
91
|
+
|
92
|
+
def migration
|
93
|
+
if @migration_config
|
94
|
+
Aws::RailsProvisioner::Migration.new(@migration_config)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def _extract_repo_name(path)
|
101
|
+
path.split('/')[-1] || 'AwsRailsProvisionerRailsAppSource'
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|