ufo 6.2.0 → 6.2.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5b86133b126853170107907bce7c02f4620387d8b11c4a5e6e0f03176fda1349
4
- data.tar.gz: 3c543c7b436ec7214043d5f5cf45a798af2ce054aed970fa5de991848f6a4664
3
+ metadata.gz: 19359c25a4a47a3a997d9a2ad481b2dcb7a1b134474cb8c1acb83b8b2a370815
4
+ data.tar.gz: e6f4b287dfa7c1a46a9aaac910718ea39e5d4b6170d937a513ecc967ef21bffd
5
5
  SHA512:
6
- metadata.gz: f4658807edc6f36b07cf8048f9f7f9c75ed90f3a03cd481ea1b763d4332bdf887a17d9199988021fa3866d73e7d0b0f43b1d03ef031915fdf5e0d3ad00a5904c
7
- data.tar.gz: d52d10df7faf76256f336abfc89a9ccd1afb999973d52e7cbf660481c17eb54ae8333c09e600de12455020c707fd1821a32beee0a893c72750337c1aecbcfaaa
6
+ metadata.gz: c718937b596ec38c56d997d6e03e6320ca2b556c595fdb0a430b883ad36c0ae96d3f9c6226d912c957b0168d8d820ea753e9ce0ee0f80e702bad3dea106ea893
7
+ data.tar.gz: f22ffd461ba1992baf9d6f07c9315ff4ed231386663a3fdee77a876effc36ae37120ebc4a9651cf467df104a23409bb86994c947f73c55687a55a39254208808
data/CHANGELOG.md CHANGED
@@ -3,6 +3,10 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  This project *tries* to adhere to [Semantic Versioning](http://semver.org/), even before v1.0.
5
5
 
6
+ ## [6.2.1] - 2022-03-16
7
+ - [#153](https://github.com/tongueroo/ufo/pull/153) dockerfile_port also consider Dockerfile.base
8
+ - [#154](https://github.com/tongueroo/ufo/pull/154) report wrong vpc config errors to user
9
+
6
10
  ## [6.2.0] - 2022-03-16
7
11
  - [#152](https://github.com/tongueroo/ufo/pull/152) ufo docker base: s3 storage support
8
12
 
@@ -15,6 +15,7 @@ class Ufo::CLI::Ps
15
15
  scale
16
16
  target_group
17
17
  deployment_configuration
18
+ wrong_vpc
18
19
  catchall
19
20
  end
20
21
 
@@ -86,6 +87,45 @@ class Ufo::CLI::Ps
86
87
  EOL
87
88
  end
88
89
 
90
+ # To reproduce #1
91
+ #
92
+ # 1. Deploy to with settings where ECS cluster is in custom VPC successfully
93
+ # 2. Deploy again. Accidentally with default VPC settings <= Reproduction
94
+ #
95
+ # This will produce a CloudFormation stack failure
96
+ #
97
+ # > All subnets must belong to the same VPC: 'vpc-11111111' (Service: AmazonElasticLoadBalancing; Status Code: 400; Error Code: InvalidConfigurationRequest; Request ID: b8c683ca-4c6d-4bf9-bf9b-3eb468fa9ea9; Proxy: null)
98
+ #
99
+ # So it's not actually an ECS failure and is caught early on. Notiing it for posterity.
100
+ #
101
+ # To reproduce #2
102
+ #
103
+ # Deploy to default VPC. Even though ECS cluster is running on a custom VPC <= Reproduction
104
+ #
105
+ # This reproduces:
106
+ #
107
+ # > ERROR: (service demo-web-dev-EcsService-RkMBAhHBfx9A) failed to register targets in (target-group arn:aws:elasticloadbalancing:us-west-2:111111111111:targetgroup/demo-Targe-1HEN2QPS5LO9B/0c69c3eb5aa23bc9) with (error The following targets are not in the target group VPC 'vpc-11111111': 'i-11111111111111111')
108
+ #
109
+ # The first deploy suceeeds because CloudFormation doesn't check on the ECS service as much here.
110
+ # ECS does report the error though.
111
+ #
112
+ def wrong_vpc
113
+ error_event = recent_events.find do |e|
114
+ e.message =~ /targets are not in the target group VPC/ ||
115
+ e.message =~ /All subnets must belong to the same VPC/
116
+ end
117
+ return unless error_event
118
+
119
+ logger.info "ERROR: VPC Configuration error".color(:red)
120
+ logger.info error_event.message.color(:red)
121
+ logger.info <<~EOL
122
+ It seems like the ECS Service was deployed to an ECS Cluster running on
123
+ a different VPC than what's the ECS Service is configured with.
124
+
125
+ See: https://ufoships.com/docs/debug/vpc-subnets/
126
+ EOL
127
+ end
128
+
89
129
  # Example:
90
130
  # (service app1-web-dev-EcsService-8FMliG8m6M2p) was unable to stop or start tasks during a deployment because of the service deployment configuration. Update the minimumHealthyPercent or maximumPercent value and try again.
91
131
  def catchall
@@ -4,13 +4,16 @@
4
4
  # * dockerfile_port - Exposed port in the Dockerfile. Only supports one exposed port, the first one that is encountered.
5
5
  #
6
6
  module Ufo::TaskDefinition::Helpers
7
- module Core
8
- extend Memoist
9
-
7
+ module Docker
10
8
  def dockerfile_port
11
- dockerfile_path = "#{Ufo.root}/Dockerfile"
12
- if File.exist?(dockerfile_path)
13
- parse_for_dockerfile_port(dockerfile_path)
9
+ if File.exist?("Dockerfile")
10
+ port = parse_for_dockerfile_port("Dockerfile")
11
+ return port if port
12
+ end
13
+
14
+ # Also consider EXPOSE in Dockerfile.base
15
+ if File.exist?("Dockerfile.base")
16
+ parse_for_dockerfile_port("Dockerfile.base")
14
17
  end
15
18
  end
16
19
 
@@ -19,24 +22,6 @@ module Ufo::TaskDefinition::Helpers
19
22
  Ufo::Docker::Builder.new({}).docker_image
20
23
  end
21
24
 
22
- def env(text)
23
- Vars.new(text: text).env
24
- end
25
- alias_method :env_vars, :env
26
- alias_method :environment, :env
27
-
28
- def env_file(path)
29
- Vars.new(file: path).env
30
- end
31
-
32
- def secrets(text)
33
- Vars.new(text: text).secrets
34
- end
35
-
36
- def secrets_file(path)
37
- Vars.new(file: path).secrets
38
- end
39
-
40
25
  def parse_for_dockerfile_port(dockerfile_path)
41
26
  lines = IO.read(dockerfile_path).split("\n")
42
27
  expose_line = lines.find { |l| l =~ /^EXPOSE / }
@@ -1,4 +1,5 @@
1
- module Ufo::TaskDefinition::Helpers
1
+ module Ufo::TaskDefinition::Helpers::Vars
2
+ # Named AwsHelper to avoid possible conflict with Aws elsewhere
2
3
  module AwsHelper
3
4
  extend Memoist
4
5
  extend ActiveSupport::Concern
@@ -0,0 +1,124 @@
1
+ require "aws_data"
2
+
3
+ module Ufo::TaskDefinition::Helpers::Vars
4
+ class Builder
5
+ extend Memoist
6
+ include AwsHelper
7
+ include Ufo::Concerns::Names
8
+ include Ufo::Utils::Pretty
9
+ include Ufo::Config::CallableOption::Concern
10
+
11
+ def initialize(options={})
12
+ # use either file or text. text takes higher precedence
13
+ @file = options[:file]
14
+ @text = options[:text]
15
+ end
16
+
17
+ def content
18
+ @text || read(@file)
19
+ end
20
+
21
+ def read(path)
22
+ full_path = "#{Ufo.root}/#{path}"
23
+ unless File.exist?(full_path)
24
+ puts "The #{pretty_path(full_path)} env file could not be found. Are you sure it exists?"
25
+ exit 1
26
+ end
27
+ IO.read(full_path)
28
+ end
29
+
30
+ def env
31
+ lines = filtered_lines(content)
32
+ lines.map do |line|
33
+ key,*value = line.strip.split("=").map do |x|
34
+ remove_surrounding_quotes(x.strip)
35
+ end
36
+ value = value.join('=')
37
+ {
38
+ name: key,
39
+ value: value,
40
+ }
41
+ end
42
+ end
43
+
44
+ def secrets
45
+ secrets = env
46
+ secrets.map do |item|
47
+ value = item.delete(:value)
48
+ arn = normalize_to_arn(item[:name], value)
49
+ value = expansion(arn)
50
+ value = value.sub('parameter//','parameter/') # auto fix accidental leading slash for user
51
+ item[:valueFrom] = value
52
+ end
53
+ secrets
54
+ end
55
+
56
+ def normalize_to_arn(name, value)
57
+ case value
58
+ when /^ssm:/i
59
+ value.sub(/^ssm:/i, "arn:aws:ssm:#{region}:#{account}:parameter/")
60
+ when /^secretsmanager:/i
61
+ value.sub(/^secretsmanager:/i, "arn:aws:secretsmanager:#{region}:#{account}:secret:")
62
+ when '' # blank string will mean use convention
63
+ conventional_pattern(name, value)
64
+ else
65
+ value # assume full arn has been passed
66
+ end
67
+ end
68
+
69
+ # arn:aws:ssm:us-west-2:111111111111:parameter/demo/dev/DB-NAME
70
+ # arn:aws:ssm:us-west-2:111111111111:parameter/demo/dev/DB-NAME
71
+ def expansion(arn)
72
+ # performance improvement only run names.expansion on the name portion
73
+ md = arn.match(/(.*:)(parameter\/|secret:)(.*)/)
74
+ prefix, type, name = md[1], md[2], md[3]
75
+ expanded_name = names.expansion(name, dasherize: false) # dasherize: false. dont turn SECRET_NAME => SECRET-NAME
76
+ "#{prefix}#{type}#{expanded_name}"
77
+ end
78
+
79
+ # Examples with config.secrets.provider = "ssm"
80
+ #
81
+ # .secrets
82
+ #
83
+ # DB_NAME
84
+ #
85
+ # Results
86
+ #
87
+ # DB_NAME=:APP/:ENV/:SECRET_NAME # expansion will use => demo/dev/DB_NAME
88
+ #
89
+ def conventional_pattern(name, value)
90
+ secrets = Ufo.config.secrets
91
+ provider = secrets.provider # ssm or secretsmanager
92
+ namespace = provider == "ssm" ? "parameter/" : "secret:"
93
+
94
+ config_name = "secrets.pattern.#{provider}"
95
+ pattern = callable_option(
96
+ config_name: config_name, # Ufo.config.names.stack => :APP-:ROLE-:ENV => demo-web-dev
97
+ passed_args: [self],
98
+ )
99
+ # replace :SECRET_NAME since names expand doesnt know how to nor do we want to add logic there
100
+ pattern = pattern.sub(':SECRET_NAME', name)
101
+ "arn:aws:#{provider}:#{region}:#{account}:#{namespace}#{pattern}"
102
+ end
103
+
104
+ def remove_surrounding_quotes(s)
105
+ if s =~ /^"/ && s =~ /"$/
106
+ s.sub(/^["]/, '').gsub(/["]$/,'') # remove surrounding double quotes
107
+ elsif s =~ /^'/ && s =~ /'$/
108
+ s.sub(/^[']/, '').gsub(/[']$/,'') # remove surrounding single quotes
109
+ else
110
+ s
111
+ end
112
+ end
113
+
114
+ def filtered_lines(content)
115
+ lines = content.split("\n")
116
+ # remove comment at the end of the line
117
+ lines.map! { |l| l.sub(/\s+#.*/,'').strip }
118
+ # filter out commented lines
119
+ lines = lines.reject { |l| l =~ /(^|\s)#/i }
120
+ # filter out empty lines
121
+ lines = lines.reject { |l| l.strip.empty? }
122
+ end
123
+ end
124
+ end
@@ -1,124 +1,21 @@
1
- require "aws_data"
2
-
3
1
  module Ufo::TaskDefinition::Helpers
4
- class Vars
5
- extend Memoist
6
- include AwsHelper
7
- include Ufo::Concerns::Names
8
- include Ufo::Utils::Pretty
9
- include Ufo::Config::CallableOption::Concern
10
-
11
- def initialize(options={})
12
- # use either file or text. text takes higher precedence
13
- @file = options[:file]
14
- @text = options[:text]
15
- end
16
-
17
- def content
18
- @text || read(@file)
19
- end
20
-
21
- def read(path)
22
- full_path = "#{Ufo.root}/#{path}"
23
- unless File.exist?(full_path)
24
- puts "The #{pretty_path(full_path)} env file could not be found. Are you sure it exists?"
25
- exit 1
26
- end
27
- IO.read(full_path)
28
- end
29
-
30
- def env
31
- lines = filtered_lines(content)
32
- lines.map do |line|
33
- key,*value = line.strip.split("=").map do |x|
34
- remove_surrounding_quotes(x.strip)
35
- end
36
- value = value.join('=')
37
- {
38
- name: key,
39
- value: value,
40
- }
41
- end
2
+ module Vars
3
+ def env(text)
4
+ Builder.new(text: text).env
42
5
  end
6
+ alias_method :env_vars, :env
7
+ alias_method :environment, :env
43
8
 
44
- def secrets
45
- secrets = env
46
- secrets.map do |item|
47
- value = item.delete(:value)
48
- arn = normalize_to_arn(item[:name], value)
49
- value = expansion(arn)
50
- value = value.sub('parameter//','parameter/') # auto fix accidental leading slash for user
51
- item[:valueFrom] = value
52
- end
53
- secrets
54
- end
55
-
56
- def normalize_to_arn(name, value)
57
- case value
58
- when /^ssm:/i
59
- value.sub(/^ssm:/i, "arn:aws:ssm:#{region}:#{account}:parameter/")
60
- when /^secretsmanager:/i
61
- value.sub(/^secretsmanager:/i, "arn:aws:secretsmanager:#{region}:#{account}:secret:")
62
- when '' # blank string will mean use convention
63
- conventional_pattern(name, value)
64
- else
65
- value # assume full arn has been passed
66
- end
67
- end
68
-
69
- # arn:aws:ssm:us-west-2:111111111111:parameter/demo/dev/DB-NAME
70
- # arn:aws:ssm:us-west-2:111111111111:parameter/demo/dev/DB-NAME
71
- def expansion(arn)
72
- # performance improvement only run names.expansion on the name portion
73
- md = arn.match(/(.*:)(parameter\/|secret:)(.*)/)
74
- prefix, type, name = md[1], md[2], md[3]
75
- expanded_name = names.expansion(name, dasherize: false) # dasherize: false. dont turn SECRET_NAME => SECRET-NAME
76
- "#{prefix}#{type}#{expanded_name}"
77
- end
78
-
79
- # Examples with config.secrets.provider = "ssm"
80
- #
81
- # .secrets
82
- #
83
- # DB_NAME
84
- #
85
- # Results
86
- #
87
- # DB_NAME=:APP/:ENV/:SECRET_NAME # expansion will use => demo/dev/DB_NAME
88
- #
89
- def conventional_pattern(name, value)
90
- secrets = Ufo.config.secrets
91
- provider = secrets.provider # ssm or secretsmanager
92
- namespace = provider == "ssm" ? "parameter/" : "secret:"
93
-
94
- config_name = "secrets.pattern.#{provider}"
95
- pattern = callable_option(
96
- config_name: config_name, # Ufo.config.names.stack => :APP-:ROLE-:ENV => demo-web-dev
97
- passed_args: [self],
98
- )
99
- # replace :SECRET_NAME since names expand doesnt know how to nor do we want to add logic there
100
- pattern = pattern.sub(':SECRET_NAME', name)
101
- "arn:aws:#{provider}:#{region}:#{account}:#{namespace}#{pattern}"
9
+ def env_file(path)
10
+ Builder.new(file: path).env
102
11
  end
103
12
 
104
- def remove_surrounding_quotes(s)
105
- if s =~ /^"/ && s =~ /"$/
106
- s.sub(/^["]/, '').gsub(/["]$/,'') # remove surrounding double quotes
107
- elsif s =~ /^'/ && s =~ /'$/
108
- s.sub(/^[']/, '').gsub(/[']$/,'') # remove surrounding single quotes
109
- else
110
- s
111
- end
13
+ def secrets(text)
14
+ Builder.new(text: text).secrets
112
15
  end
113
16
 
114
- def filtered_lines(content)
115
- lines = content.split("\n")
116
- # remove comment at the end of the line
117
- lines.map! { |l| l.sub(/\s+#.*/,'').strip }
118
- # filter out commented lines
119
- lines = lines.reject { |l| l =~ /(^|\s)#/i }
120
- # filter out empty lines
121
- lines = lines.reject { |l| l.strip.empty? }
17
+ def secrets_file(path)
18
+ Builder.new(file: path).secrets
122
19
  end
123
20
  end
124
21
  end
data/lib/ufo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ufo
2
- VERSION = "6.2.0"
2
+ VERSION = "6.2.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ufo
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.2.0
4
+ version: 6.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tung Nguyen
@@ -629,14 +629,15 @@ files:
629
629
  - lib/ufo/task_definition/erb/yaml.rb
630
630
  - lib/ufo/task_definition/helpers.rb
631
631
  - lib/ufo/task_definition/helpers/acm.rb
632
- - lib/ufo/task_definition/helpers/aws_helper.rb
633
- - lib/ufo/task_definition/helpers/core.rb
632
+ - lib/ufo/task_definition/helpers/docker.rb
634
633
  - lib/ufo/task_definition/helpers/ecr.rb
635
634
  - lib/ufo/task_definition/helpers/expansion.rb
636
635
  - lib/ufo/task_definition/helpers/ssm.rb
637
636
  - lib/ufo/task_definition/helpers/ssm/fetcher.rb
638
637
  - lib/ufo/task_definition/helpers/stack_output.rb
639
638
  - lib/ufo/task_definition/helpers/vars.rb
639
+ - lib/ufo/task_definition/helpers/vars/aws_helper.rb
640
+ - lib/ufo/task_definition/helpers/vars/builder.rb
640
641
  - lib/ufo/task_definition/helpers/vpc.rb
641
642
  - lib/ufo/task_definition/helpers/waf.rb
642
643
  - lib/ufo/upgrade/params.yml