convox_installer 1.0.8 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,48 +1,54 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "highline"
4
- require "fileutils"
5
- require "json"
6
- require "securerandom"
3
+ require 'highline'
4
+ require 'fileutils'
5
+ require 'json'
6
+ require 'securerandom'
7
7
 
8
8
  module ConvoxInstaller
9
9
  class Config
10
- CONFIG_FILE = File.expand_path("./.installer_config.json").freeze
10
+ CONFIG_FILE = File.expand_path('./.installer_config.json').freeze
11
11
 
12
12
  attr_accessor :logger, :config, :prompts, :highline
13
13
 
14
14
  DEFAULT_PROMPTS = [
15
15
  {
16
16
  key: :stack_name,
17
- title: "Convox Stack Name",
18
- prompt: "Please enter a name for your Convox installation",
19
- default: "convox",
17
+ title: 'Convox Stack Name',
18
+ prompt: 'Please enter a name for your Convox installation',
19
+ default: 'convox'
20
20
  },
21
21
  {
22
22
  key: :aws_region,
23
- title: "AWS Region",
24
- default: "us-east-1",
23
+ title: 'AWS Region',
24
+ default: 'us-east-1'
25
25
  },
26
26
  {
27
27
  key: :instance_type,
28
- title: "EC2 Instance Type",
29
- default: "t3.medium",
28
+ title: 'EC2 Instance Type',
29
+ default: 't3.medium'
30
30
  },
31
31
  {
32
- section: "Admin AWS Credentials",
32
+ section: 'Admin AWS Credentials'
33
33
  },
34
34
  {
35
35
  key: :aws_access_key_id,
36
- title: "AWS Access Key ID",
36
+ title: 'AWS Access Key ID'
37
37
  },
38
38
  {
39
39
  key: :aws_secret_access_key,
40
- title: "AWS Secret Access Key",
40
+ title: 'AWS Secret Access Key'
41
41
  },
42
+ # Short random ID used to ensure that resources are always unique
43
+ {
44
+ key: :random_id,
45
+ value: -> { SecureRandom.hex(4) },
46
+ hidden: true
47
+ }
42
48
  ].freeze
43
49
 
44
50
  def initialize(options = {})
45
- @logger = Logger.new(STDOUT)
51
+ @logger = Logger.new($stdout)
46
52
  logger.level = options[:log_level] || Logger::INFO
47
53
 
48
54
  self.prompts = options[:prompts] || DEFAULT_PROMPTS
@@ -74,13 +80,16 @@ module ConvoxInstaller
74
80
 
75
81
  @completed_prompt = true
76
82
 
77
- highline.say "Please double check all of these configuration details."
83
+ highline.say 'Please double check all of these configuration details.'
84
+
85
+ break if ENV['AUTOSTART_CONVOX_INSTALLATION']
78
86
 
79
87
  agree = highline.agree(
80
- "Would you like to start the Convox installation?" \
88
+ 'Would you like to start the Convox installation?' \
81
89
  " (press 'n' to correct any settings)"
82
90
  )
83
91
  break if agree
92
+
84
93
  highline.say "\n"
85
94
  end
86
95
 
@@ -89,7 +98,7 @@ module ConvoxInstaller
89
98
 
90
99
  def show_config_summary
91
100
  highline.say "\n============================================"
92
- highline.say " SUMMARY"
101
+ highline.say ' SUMMARY'
93
102
  highline.say "============================================\n\n"
94
103
 
95
104
  config_titles = prompts.map do |prompt|
@@ -106,10 +115,18 @@ module ConvoxInstaller
106
115
  highline.say " #{padded_key} #{value}"
107
116
  end
108
117
  highline.say "\nWe've saved your configuration to: #{CONFIG_FILE}"
109
- highline.say "If anything goes wrong during the installation, " \
118
+ highline.say 'If anything goes wrong during the installation, ' \
110
119
  "you can restart the script to reload the config and continue.\n\n"
111
120
  end
112
121
 
122
+ def self.config_file_exists?
123
+ File.exist?(CONFIG_FILE)
124
+ end
125
+
126
+ def self.read_config_file
127
+ File.read(CONFIG_FILE)
128
+ end
129
+
113
130
  private
114
131
 
115
132
  def ask_prompt(prompt)
@@ -129,7 +146,11 @@ module ConvoxInstaller
129
146
  return if config[key]
130
147
 
131
148
  default = prompt[:value]
132
- config[key] = default.is_a?(Proc) ? default.call(config) : default
149
+ config[key] = if default.is_a?(Proc)
150
+ default.arity.zero? ? default.call : default.call(config)
151
+ else
152
+ default
153
+ end
133
154
  save_config_to_file
134
155
  return
135
156
  end
@@ -153,7 +174,7 @@ module ConvoxInstaller
153
174
 
154
175
  logger.debug "Loading saved config from #{CONFIG_FILE}..."
155
176
 
156
- loaded_config = JSON.parse(Config.read_config_file)["config"].symbolize_keys
177
+ loaded_config = JSON.parse(Config.read_config_file)['config'].symbolize_keys
157
178
  self.config = config.merge(loaded_config)
158
179
  end
159
180
 
@@ -174,13 +195,5 @@ module ConvoxInstaller
174
195
  f.puts(JSON.pretty_generate(config: config))
175
196
  end
176
197
  end
177
-
178
- def self.config_file_exists?
179
- File.exist?(CONFIG_FILE)
180
- end
181
-
182
- def self.read_config_file
183
- File.read(CONFIG_FILE)
184
- end
185
198
  end
186
199
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "highline"
4
- require "os"
5
- require "logger"
3
+ require 'highline'
4
+ require 'os'
5
+ require 'logger'
6
6
 
7
7
  module ConvoxInstaller
8
8
  class Requirements
@@ -10,46 +10,66 @@ module ConvoxInstaller
10
10
 
11
11
  def initialize(options = {})
12
12
  @ecr_label = options[:ecr_label]
13
- @logger = Logger.new(STDOUT)
13
+ @logger = Logger.new($stdout)
14
14
  logger.level = options[:log_level] || Logger::INFO
15
15
  end
16
16
 
17
17
  def ensure_requirements!
18
- logger.debug "Checking for required commands..."
18
+ logger.debug 'Checking for required commands...'
19
19
 
20
20
  @missing_packages = []
21
- unless has_command? "convox"
21
+ unless command_present? 'convox'
22
22
  @missing_packages << {
23
- name: "convox",
24
- brew: "convox",
25
- docs: "https://docs.convox.com/introduction/installation",
23
+ name: 'convox',
24
+ brew: 'convox',
25
+ docs: 'https://docs.convox.com/introduction/installation'
26
26
  }
27
27
  end
28
28
 
29
- unless has_command? "aws"
29
+ unless command_present? 'aws'
30
30
  @missing_packages << {
31
- name: "aws",
32
- brew: "awscli",
33
- docs: "https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html",
31
+ name: 'aws',
32
+ brew: 'awscli',
33
+ docs: 'https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html'
34
+ }
35
+ end
36
+
37
+ unless command_present? 'terraform'
38
+ @missing_packages << {
39
+ name: 'terraform',
40
+ brew: 'terraform',
41
+ docs: 'https://learn.hashicorp.com/tutorials/terraform/install-cli'
34
42
  }
35
43
  end
36
44
 
37
45
  if @missing_packages.any?
38
- logger.error "This script requires the convox and AWS CLI tools."
46
+ logger.error 'This script requires the convox and AWS CLI tools.'
39
47
  if OS.mac?
40
- logger.error "Please run: brew install " \
41
- "#{@missing_packages.map { |p| p[:brew] }.join(" ")}"
48
+ logger.error 'Please run: brew install ' \
49
+ "#{@missing_packages.map { |p| p[:brew] }.join(' ')}"
42
50
  else
43
- logger.error "Installation Instructions:"
51
+ logger.error 'Installation Instructions:'
44
52
  @missing_packages.each do |package|
45
53
  logger.error "* #{package[:name]}: #{package[:docs]}"
46
54
  end
47
55
  end
48
56
  quit!
49
57
  end
58
+
59
+ client = Convox::Client.new
60
+ if client.convox_3_cli?
61
+ logger.debug "=> Convox CLI is version 3.x.x (#{client.cli_version_string})"
62
+ return
63
+ end
64
+
65
+ logger.error 'This script requires Convox CLI version 3.x.x. ' \
66
+ "Your Convox CLI version is: #{client.cli_version_string}"
67
+ logger.error "Please run 'brew update convox' or follow the instructions " \
68
+ 'at https://docs.convox.com/getting-started/introduction'
69
+ quit!
50
70
  end
51
71
 
52
- def has_command?(command)
72
+ def command_present?(command)
53
73
  path = find_command command
54
74
  if path.present?
55
75
  logger.debug "=> Found #{command}: #{path}"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ConvoxInstaller
4
- VERSION = "1.0.8"
4
+ VERSION = '3.0.0'
5
5
  end
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support"
4
- require "active_support/core_ext"
5
- require "convox_installer/config"
6
- require "convox_installer/requirements"
7
- require "convox"
3
+ require 'active_support'
4
+ require 'active_support/core_ext'
5
+ require 'convox_installer/config'
6
+ require 'convox_installer/requirements'
7
+ require 'convox'
8
8
 
9
9
  module ConvoxInstaller
10
10
  def client
@@ -12,7 +12,7 @@ module ConvoxInstaller
12
12
  end
13
13
 
14
14
  def config
15
- options = {log_level: @log_level}
15
+ options = { log_level: @log_level }
16
16
  options[:prompts] = @prompts if @prompts
17
17
  @config ||= Config.new(options)
18
18
  end
@@ -32,18 +32,24 @@ module ConvoxInstaller
32
32
  %w[
33
33
  backup_convox_host_and_rack
34
34
  install_convox
35
- validate_convox_auth_and_set_host!
36
- validate_convox_rack!
35
+ validate_convox_rack_and_write_current!
36
+ validate_convox_rack_api!
37
37
  convox_rack_data
38
38
  create_convox_app!
39
39
  set_default_app_for_directory!
40
- create_s3_bucket!
41
- set_s3_bucket_cors_policy
40
+ add_s3_bucket
41
+ add_rds_database
42
+ add_elasticache_cluster
43
+ apply_terraform_update!
44
+ terraform_state
42
45
  s3_bucket_details
46
+ elasticache_details
47
+ rds_details
43
48
  add_docker_registry!
44
49
  default_service_domain_name
45
50
  run_convox_command!
46
51
  logger
52
+ rack_already_installed?
47
53
  ].each do |method|
48
54
  define_method(method) do |*args|
49
55
  client.send(method, *args)
@@ -1,20 +1,54 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "convox/client"
3
+ require 'convox/client'
4
4
 
5
5
  RSpec.describe Convox::Client do
6
- let(:home_dir) { File.expand_path("~") }
6
+ let(:home_dir) { File.expand_path('~') }
7
7
 
8
- it "finds the authentication details in ~/.convox/auth" do
8
+ it 'finds the authentication details in ~/.convox/auth' do
9
9
  expect(File).to receive(:exist?).with("#{home_dir}/.convox/auth").and_return(true)
10
10
  expect(File).to receive(:read).with("#{home_dir}/.convox/auth").and_return(
11
11
  '{ "test.example.com": "1234567890" }'
12
12
  )
13
13
  client = described_class.new
14
- expect(client.auth).to eq("test.example.com" => "1234567890")
14
+ expect(client.auth).to eq('test.example.com' => '1234567890')
15
15
  end
16
16
 
17
- it "should backup existing Convox host and rack files" do
17
+ describe 'Convox CLI version' do
18
+ let(:client) { described_class.new }
19
+
20
+ it 'returns the convox CLI version output for 20210208170413' do
21
+ expect(client).to receive(:cli_version_string).at_least(:once).and_return('20210208170413')
22
+ expect(client.convox_2_cli?).to be true
23
+ expect(client.convox_3_cli?).to be false
24
+ end
25
+
26
+ it 'returns the convox CLI version output for 20200101130413' do
27
+ expect(client).to receive(:cli_version_string).at_least(:once).and_return('20200101130413')
28
+ expect(client.convox_2_cli?).to be true
29
+ expect(client.convox_3_cli?).to be false
30
+ end
31
+
32
+ it 'returns the convox CLI version output for 3.0.0' do
33
+ expect(client).to receive(:cli_version_string).at_least(:once).and_return('3.0.0')
34
+ expect(client.convox_2_cli?).to be false
35
+ expect(client.convox_3_cli?).to be true
36
+ end
37
+
38
+ it 'returns the convox CLI version output for 3.1.3' do
39
+ expect(client).to receive(:cli_version_string).at_least(:once).and_return('3.1.3')
40
+ expect(client.convox_2_cli?).to be false
41
+ expect(client.convox_3_cli?).to be true
42
+ end
43
+
44
+ it 'returns the convox CLI version output for 4.0.0' do
45
+ expect(client).to receive(:cli_version_string).at_least(:once).and_return('4.0.0')
46
+ expect(client.convox_2_cli?).to be false
47
+ expect(client.convox_3_cli?).to be false
48
+ end
49
+ end
50
+
51
+ it 'backups existing Convox host and rack files' do
18
52
  expect(File).to receive(:exist?).with(
19
53
  "#{home_dir}/.convox/host"
20
54
  ).and_return(true)
@@ -34,61 +68,63 @@ RSpec.describe Convox::Client do
34
68
  client.backup_convox_host_and_rack
35
69
  end
36
70
 
37
- describe "#install" do
38
- it "should require the correct config vars" do
71
+ describe '#install' do
72
+ it 'requires the correct config vars' do
39
73
  client = described_class.new
40
- expect { client.install_convox }.to raise_error("aws_region is missing from the config!")
74
+ expect { client.install_convox }.to raise_error('aws_region is missing from the config!')
41
75
 
42
- client = described_class.new(config: {aws_region: "us-east-1"})
43
- expect { client.install_convox }.to raise_error("stack_name is missing from the config!")
76
+ client = described_class.new(config: { aws_region: 'us-east-1' })
77
+ expect { client.install_convox }.to raise_error('stack_name is missing from the config!')
44
78
  end
45
79
 
46
- it "should run the correct convox CLI command" do
80
+ it 'runs the correct convox CLI command' do
47
81
  client = described_class.new(
48
82
  config: {
49
- aws_region: "us-east-1",
50
- aws_access_key_id: "asdf",
51
- aws_secret_access_key: "1234",
52
- stack_name: "asdf",
53
- instance_type: "t3.medium",
54
- },
83
+ aws_region: 'us-east-1',
84
+ aws_access_key_id: 'asdf',
85
+ aws_secret_access_key: '1234',
86
+ stack_name: 'asdf',
87
+ instance_type: 't3.medium'
88
+ }
55
89
  )
56
90
 
57
91
  expect(client.logger).to receive(:info)
58
92
  expect(client).to receive(:run_convox_command!).with(
59
- "rack install aws --name \"asdf\" \"InstanceType=t3.medium\" " \
60
- "\"BuildInstance=\"",
61
- "AWS_ACCESS_KEY_ID" => "asdf",
62
- "AWS_REGION" => "us-east-1",
63
- "AWS_SECRET_ACCESS_KEY" => "1234",
93
+ 'rack install aws --name "asdf" "InstanceType=t3.medium" ' \
94
+ '"BuildInstance="',
95
+ 'AWS_ACCESS_KEY_ID' => 'asdf',
96
+ 'AWS_REGION' => 'us-east-1',
97
+ 'AWS_SECRET_ACCESS_KEY' => '1234'
64
98
  )
65
99
  client.install_convox
66
100
  end
67
101
  end
68
102
 
69
- describe "#validate_convox_auth_and_set_host!" do
70
- it "should require the correct config vars" do
103
+ describe '#validate_convox_auth_and_write_host!' do
104
+ it 'requires the correct config vars' do
71
105
  client = described_class.new
72
- expect { client.validate_convox_auth_and_set_host! }.to raise_error("aws_region is missing from the config!")
106
+ expect do
107
+ client.validate_convox_auth_and_write_host!
108
+ end.to raise_error('aws_region is missing from the config!')
73
109
  end
74
110
 
75
- it "should raise an error if auth file is missing" do
111
+ it 'raises an error if auth file is missing' do
76
112
  client = described_class.new(
77
113
  config: {
78
- aws_region: "us-east-1",
79
- stack_name: "asdf",
80
- },
114
+ aws_region: 'us-east-1',
115
+ stack_name: 'asdf'
116
+ }
81
117
  )
82
118
  expect(File).to receive(:exist?).with(
83
119
  "#{home_dir}/.convox/auth"
84
120
  ).and_return(false)
85
121
 
86
- expect {
87
- client.validate_convox_auth_and_set_host!
88
- }.to raise_error(/Could not find auth file at /)
122
+ expect do
123
+ client.validate_convox_auth_and_write_host!
124
+ end.to raise_error(/Could not find auth file at /)
89
125
  end
90
126
 
91
- it "should set ~/.convox/host if a matching host is found in the auth file" do
127
+ it 'sets ~/.convox/host if a matching host is found in the auth file' do
92
128
  expect(File).to receive(:exist?).with(
93
129
  "#{home_dir}/.convox/auth"
94
130
  ).twice.and_return(true)
@@ -98,19 +134,19 @@ RSpec.describe Convox::Client do
98
134
  )
99
135
  client = described_class.new(
100
136
  config: {
101
- aws_region: "us-west-2",
102
- stack_name: "convox-test",
103
- },
137
+ aws_region: 'us-west-2',
138
+ stack_name: 'convox-test'
139
+ }
104
140
  )
105
- expect(client).to receive(:set_host).with(
106
- "convox-test-697645520.us-west-2.elb.amazonaws.com"
141
+ expect(client).to receive(:write_current).with(
142
+ 'convox-test-697645520.us-west-2.elb.amazonaws.com'
107
143
  )
108
- expect(client.validate_convox_auth_and_set_host!).to(
109
- eq("convox-test-697645520.us-west-2.elb.amazonaws.com")
144
+ expect(client.validate_convox_auth_and_write_host!).to(
145
+ eq('convox-test-697645520.us-west-2.elb.amazonaws.com')
110
146
  )
111
147
  end
112
148
 
113
- it "should raise an error if no matching host is found" do
149
+ it 'raises an error if no matching host is found' do
114
150
  expect(File).to receive(:exist?).with(
115
151
  "#{home_dir}/.convox/auth"
116
152
  ).twice.and_return(true)
@@ -120,17 +156,17 @@ RSpec.describe Convox::Client do
120
156
  )
121
157
  client = described_class.new(
122
158
  config: {
123
- aws_region: "us-east-1",
124
- stack_name: "convox-test",
125
- },
159
+ aws_region: 'us-east-1',
160
+ stack_name: 'convox-test'
161
+ }
126
162
  )
127
- expect {
128
- client.validate_convox_auth_and_set_host!
129
- }.to raise_error("Could not find matching authentication for " \
130
- "region: us-east-1, stack: convox-test")
163
+ expect do
164
+ client.validate_convox_auth_and_write_host!
165
+ end.to raise_error('Could not find matching authentication for ' \
166
+ 'region: us-east-1, stack: convox-test')
131
167
  end
132
168
 
133
- it "should raise an error if it finds multiple matching hosts" do
169
+ it 'raises an error if it finds multiple matching hosts' do
134
170
  expect(File).to receive(:exist?).with(
135
171
  "#{home_dir}/.convox/auth"
136
172
  ).twice.and_return(true)
@@ -141,14 +177,14 @@ RSpec.describe Convox::Client do
141
177
  )
142
178
  client = described_class.new(
143
179
  config: {
144
- aws_region: "us-west-2",
145
- stack_name: "convox-test",
146
- },
180
+ aws_region: 'us-west-2',
181
+ stack_name: 'convox-test'
182
+ }
147
183
  )
148
- expect {
149
- client.validate_convox_auth_and_set_host!
150
- }.to raise_error("Found multiple matching hosts for " \
151
- "region: us-west-2, stack: convox-test")
184
+ expect do
185
+ client.validate_convox_auth_and_write_host!
186
+ end.to raise_error('Found multiple matching hosts for ' \
187
+ 'region: us-west-2, stack: convox-test')
152
188
  end
153
189
  end
154
190
  end