ufo 6.2.0 → 6.2.1

Sign up to get free protection for your applications and to get access to all the features.
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