pvcglue 0.1.39 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/README.md +12 -3
- data/bin/pvc +4 -2
- data/lib/pvcglue.rb +106 -21
- data/lib/pvcglue/bootstrap.rb +1 -1
- data/lib/pvcglue/cli.rb +28 -17
- data/lib/pvcglue/cloud.rb +243 -56
- data/lib/pvcglue/configuration.rb +43 -5
- data/lib/pvcglue/connection.rb +236 -0
- data/lib/pvcglue/custom_hashie.rb +3 -0
- data/lib/pvcglue/db.rb +19 -13
- data/lib/pvcglue/digital_ocean.rb +21 -0
- data/lib/pvcglue/env.rb +52 -28
- data/lib/pvcglue/manager.rb +38 -25
- data/lib/pvcglue/minion.rb +182 -0
- data/lib/pvcglue/nodes.rb +1 -1
- data/lib/pvcglue/{packages → old_packages}/bootstrap.rb +15 -15
- data/lib/pvcglue/{packages → old_packages}/env.rb +8 -8
- data/lib/pvcglue/old_packages/firewall.rb +48 -0
- data/lib/pvcglue/old_packages/manager.rb +116 -0
- data/lib/pvcglue/{packages → old_packages}/monit-bootstrap.rb +0 -0
- data/lib/pvcglue/{packages → old_packages}/monit-web.rb +0 -0
- data/lib/pvcglue/{packages → old_packages}/nginx.rb +0 -0
- data/lib/pvcglue/{packages → old_packages}/nodejs.rb +0 -0
- data/lib/pvcglue/{packages → old_packages}/passenger.rb +0 -0
- data/lib/pvcglue/old_packages/postgresql.rb +10 -0
- data/lib/pvcglue/{packages → old_packages}/role_db.rb +9 -9
- data/lib/pvcglue/{packages → old_packages}/role_lb.rb +6 -6
- data/lib/pvcglue/{packages → old_packages}/role_memcached.rb +0 -0
- data/lib/pvcglue/{packages → old_packages}/role_redis.rb +0 -0
- data/lib/pvcglue/{packages → old_packages}/role_web.rb +9 -9
- data/lib/pvcglue/old_packages/rvm.rb +78 -0
- data/lib/pvcglue/{packages → old_packages}/timezone.rb +0 -0
- data/lib/pvcglue/{packages → old_packages}/ubuntu.rb +0 -0
- data/lib/pvcglue/packages.rb +192 -71
- data/lib/pvcglue/packages/apt.rb +74 -0
- data/lib/pvcglue/packages/apt_repos.rb +48 -0
- data/lib/pvcglue/packages/apt_update.rb +18 -0
- data/lib/pvcglue/packages/apt_upgrade.rb +20 -0
- data/lib/pvcglue/packages/authorized_keys.rb +33 -0
- data/lib/pvcglue/packages/bundler.rb +14 -0
- data/lib/pvcglue/packages/dir_base.rb +16 -0
- data/lib/pvcglue/packages/dir_shared.rb +16 -0
- data/lib/pvcglue/packages/firewall.rb +30 -46
- data/lib/pvcglue/packages/load_balancer.rb +71 -0
- data/lib/pvcglue/packages/maintenance_mode.rb +28 -0
- data/lib/pvcglue/packages/manager.rb +101 -99
- data/lib/pvcglue/packages/postgresql.rb +36 -8
- data/lib/pvcglue/packages/roles.rb +23 -0
- data/lib/pvcglue/packages/ruby.rb +13 -0
- data/lib/pvcglue/packages/rvm.rb +18 -71
- data/lib/pvcglue/packages/secrets.rb +36 -0
- data/lib/pvcglue/packages/ssh_key_check.rb +11 -0
- data/lib/pvcglue/packages/ssl.rb +45 -0
- data/lib/pvcglue/packages/ssl_acme.rb +29 -0
- data/lib/pvcglue/packages/swap.rb +14 -0
- data/lib/pvcglue/packages/unattended_upgrades.rb +20 -0
- data/lib/pvcglue/packages/users.rb +20 -0
- data/lib/pvcglue/packages/web.rb +50 -0
- data/lib/pvcglue/stack.rb +166 -0
- data/lib/pvcglue/templates/50unattended-upgrades.erb +63 -0
- data/lib/pvcglue/templates/capfile.erb +4 -1
- data/lib/pvcglue/templates/deploy.rb.erb +3 -2
- data/lib/pvcglue/templates/lb.sites-enabled.erb +15 -9
- data/lib/pvcglue/templates/letsencrypt-webroot.erb +3 -0
- data/lib/pvcglue/templates/pg_hba.conf.erb +1 -2
- data/lib/pvcglue/templates/postgresql.conf.erb +376 -291
- data/lib/pvcglue/templates/stage-deploy.rb.erb +2 -2
- data/lib/pvcglue/templates/web.bashrc.erb +16 -5
- data/lib/pvcglue/templates/web.nginx.conf.erb +1 -1
- data/lib/pvcglue/templates/web.sites-enabled.erb +1 -1
- data/lib/pvcglue/version.rb +1 -1
- data/pvcglue.gemspec +17 -12
- metadata +125 -22
@@ -38,7 +38,10 @@ module Pvcglue
|
|
38
38
|
init(:local_cloud_manager)
|
39
39
|
@cloud_manager = @local_cloud_manager
|
40
40
|
else
|
41
|
-
init(:cloud_manager)
|
41
|
+
unless init(:cloud_manager)
|
42
|
+
say('The manager has not been configured.')
|
43
|
+
configure_manager
|
44
|
+
end
|
42
45
|
end
|
43
46
|
|
44
47
|
# raise(Thor::Error, "The manager has not been configured. :(") if cloud_manager.nil?
|
@@ -57,7 +60,6 @@ module Pvcglue
|
|
57
60
|
end
|
58
61
|
|
59
62
|
def configure_manager
|
60
|
-
say('The manager has not been configured.')
|
61
63
|
manager = ask('What is the IP address or host name of the manager?')
|
62
64
|
default = !no?('Will this be the default manager? (Y/n)')
|
63
65
|
file_name = default ? user_file_name : project_file_name
|
@@ -188,14 +190,50 @@ module Pvcglue
|
|
188
190
|
end
|
189
191
|
end
|
190
192
|
|
191
|
-
def web_app_base_dir
|
192
|
-
|
193
|
+
# def web_app_base_dir
|
194
|
+
# # '/sites'
|
195
|
+
# '~/www'
|
196
|
+
# # "/home/#{user_name}/.ssh"
|
197
|
+
# end
|
198
|
+
|
199
|
+
def build_log_extra_dir
|
200
|
+
@build_log_extra_dir ||= begin
|
201
|
+
option = Pvcglue.command_line_options[:save_before_upload]
|
202
|
+
if option != 'save_before_upload'
|
203
|
+
dir_name = option
|
204
|
+
else
|
205
|
+
dir_name = Time.now.strftime('%Y-%m-%d-%H%M%S')
|
206
|
+
end
|
207
|
+
result = File.join(pvcglue_tmp_dir, dir_name)
|
208
|
+
`mkdir -p '#{result}'`
|
209
|
+
raise $?.inspect unless $?.exitstatus == 0
|
210
|
+
result
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def build_log_extra_filename(minion, user, remote_filename)
|
215
|
+
# local_filename = File.basename(remote_filename)
|
216
|
+
relative = remote_filename.sub(Pvcglue.cloud.web_app_base_dir, '/project')
|
217
|
+
local_filename = relative.sub(/\A\//, '').gsub(/\//, '__')
|
218
|
+
# local_filename = File.basename(remote_filename)
|
219
|
+
versioned_filename(File.join(build_log_extra_dir, "#{minion.machine_name}--#{user}--#{local_filename}"))
|
220
|
+
end
|
221
|
+
|
222
|
+
# TODO: Refactor to a utilities module or something
|
223
|
+
def versioned_filename(base, first_suffix='.00')
|
224
|
+
suffix = nil
|
225
|
+
filename = base
|
226
|
+
while File.exists?(filename)
|
227
|
+
suffix = (suffix ? suffix.succ : first_suffix)
|
228
|
+
filename = base + suffix
|
229
|
+
end
|
230
|
+
return filename
|
193
231
|
end
|
194
232
|
end
|
195
233
|
|
196
234
|
end
|
197
235
|
|
198
|
-
|
236
|
+
# --------------------------------------------------------------------------------------------------------------------
|
199
237
|
|
200
238
|
def self.configuration
|
201
239
|
@configuration ||= Configuration.new
|
@@ -0,0 +1,236 @@
|
|
1
|
+
module Pvcglue
|
2
|
+
# TODO: Check ssh config
|
3
|
+
## https://puppet.com/blog/speed-up-ssh-by-reusing-connections
|
4
|
+
# ~/.ssh/config
|
5
|
+
#Host *
|
6
|
+
#ControlMaster auto
|
7
|
+
##ControlPath ~/.ssh/sockets/%r@%h-%p
|
8
|
+
#ControlPath ~/.ssh/%r@%h-%p
|
9
|
+
#ControlPersist 600
|
10
|
+
#
|
11
|
+
# Way Faster!!!
|
12
|
+
#
|
13
|
+
|
14
|
+
class Connection
|
15
|
+
def initialize(minion)
|
16
|
+
@minion = minion
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_accessor :minion
|
20
|
+
attr_accessor :minion_state_data
|
21
|
+
|
22
|
+
def file_exists?(user, file)
|
23
|
+
result = ssh?(user, '', "test -e #{file}")
|
24
|
+
result.exitstatus == 0
|
25
|
+
end
|
26
|
+
|
27
|
+
def mkdir_p(user, remote_dir, owner = nil, group = nil, permissions = nil)
|
28
|
+
ssh!(user, '', "mkdir -p #{remote_dir}")
|
29
|
+
chown_chmod(user, remote_dir, owner, group, permissions)
|
30
|
+
end
|
31
|
+
|
32
|
+
def ssh_retry_wait(user, options, cmd, times, wait)
|
33
|
+
tries = 0
|
34
|
+
begin
|
35
|
+
result = ssh?(user, options, cmd)
|
36
|
+
unless result.exitstatus == 0
|
37
|
+
Pvcglue.logger.info("Command `#{cmd}` failed, retrying...")
|
38
|
+
sleep(wait)
|
39
|
+
end
|
40
|
+
tries += 1
|
41
|
+
raise "Exceeded #{times} retries: #{result.inspect}" if tries >= times
|
42
|
+
end until result.exitstatus == 0
|
43
|
+
end
|
44
|
+
|
45
|
+
def escape_ssh_command(cmd)
|
46
|
+
# cmd.gsub(/'/, "\\'")
|
47
|
+
# cmd.gsub(/'/) { |match| "\\#{match}" }
|
48
|
+
# cmd.gsub(/'/) { |match| '\\' + match } # "CREATEDB PASSWORD 'monkey'" #=> "CREATEDB PASSWORD \'monkey\'"
|
49
|
+
# if cmd.include?("'") || cmd.include?('"')
|
50
|
+
# # if cmd.include?('"')
|
51
|
+
# # "<<'EOF'\n#{cmd}\nEOF"
|
52
|
+
# # cmd.gsub(/'/) { |match| %Q('"'"') }
|
53
|
+
# # "$'" + cmd.gsub(/'/) { |match| '\\' + match } + "'"
|
54
|
+
# '"' + cmd.gsub(/"/) { |match| '\\' + match } + '"'
|
55
|
+
# else
|
56
|
+
# "'#{cmd}'"
|
57
|
+
# end
|
58
|
+
# Another possible solution: http://stackoverflow.com/a/21761956/444774
|
59
|
+
'"' + cmd.gsub(/"/) { |match| '\\' + match } + '"'
|
60
|
+
end
|
61
|
+
|
62
|
+
def ssh?(user, options, cmd)
|
63
|
+
# if cmd.include?("'") # DONE: Quick fix, should be refactored to do proper escaping
|
64
|
+
# system_command?(%Q(ssh #{user}@#{minion.public_ip} #{options} "#{cmd}"))
|
65
|
+
# else
|
66
|
+
# system_command?(%Q(ssh #{user}@#{minion.public_ip} #{options} '#{cmd}'))
|
67
|
+
# end
|
68
|
+
system_command?(%Q(ssh #{user}@#{minion.public_ip} #{options} #{escape_ssh_command(cmd)}))
|
69
|
+
end
|
70
|
+
|
71
|
+
def ssh!(user, options, cmd)
|
72
|
+
result = ssh?(user, options, cmd)
|
73
|
+
raise result.inspect unless result.exitstatus == 0
|
74
|
+
end
|
75
|
+
|
76
|
+
def system_command?(cmd)
|
77
|
+
Pvcglue.logger.debug { cmd }
|
78
|
+
system(cmd)
|
79
|
+
Pvcglue.logger.debug { "exit_code=#{$?.exitstatus}" }
|
80
|
+
$?
|
81
|
+
end
|
82
|
+
|
83
|
+
def system_command!(cmd)
|
84
|
+
result = system_command?(cmd)
|
85
|
+
raise result.inspect unless result.exitstatus == 0
|
86
|
+
end
|
87
|
+
|
88
|
+
def run_get_stdout(user, options, cmd)
|
89
|
+
full_cmd = "ssh #{user}@#{minion.public_ip} #{options} #{escape_ssh_command(cmd)}"
|
90
|
+
Pvcglue.logger.debug { full_cmd }
|
91
|
+
result = `#{full_cmd}`
|
92
|
+
Pvcglue.verbose? { result }
|
93
|
+
Pvcglue.logger.debug { "exit_code=#{$?.to_i}" }
|
94
|
+
result
|
95
|
+
end
|
96
|
+
|
97
|
+
def run_get_stdout!(user, options, cmd)
|
98
|
+
result = run_get_stdout(user, options, cmd)
|
99
|
+
raise $?.inspect unless $?.exitstatus == 0
|
100
|
+
result
|
101
|
+
end
|
102
|
+
|
103
|
+
def run!(user, options, cmd)
|
104
|
+
ssh!(user, options, cmd)
|
105
|
+
end
|
106
|
+
|
107
|
+
def run?(user, options, cmd)
|
108
|
+
ssh?(user, options, cmd)
|
109
|
+
# puts user.inspect
|
110
|
+
# cmd = 'pwd'
|
111
|
+
# full_command = "ssh root@#{minion.public_ip} '#{cmd}'"
|
112
|
+
# full_command = "ssh root@#{minion.public_ip} 'ls -ahl'"
|
113
|
+
# puts "running: #{full_command}"
|
114
|
+
# puts `#{full_command}`
|
115
|
+
# 1.times do
|
116
|
+
# 100.times do
|
117
|
+
# puts "running: #{full_command}"
|
118
|
+
# puts `#{full_command}`
|
119
|
+
# puts `ls -ahl ~/.ssh/config`
|
120
|
+
# system %Q(ssh root@#{minion.public_ip} -o strictHostKeyChecking=no -t 'pwd')
|
121
|
+
# ap system %Q(ssh root@#{minion.public_ip} 'test -e test')
|
122
|
+
# ap system %Q(ssh root@#{minion.public_ip} -t 'test -e test')
|
123
|
+
# ap $?
|
124
|
+
# ap system %Q(ssh root@#{minion.public_ip} 'test -e .bashrc')
|
125
|
+
# ap $?
|
126
|
+
# ap file_exists?(:root, 'test')
|
127
|
+
# ap file_exists?(:root, '.bashrc')
|
128
|
+
# end
|
129
|
+
end
|
130
|
+
|
131
|
+
def read_from_file(user, file)
|
132
|
+
tmp_file = Tempfile.new('pvc')
|
133
|
+
begin
|
134
|
+
download_file(user, file, tmp_file.path)
|
135
|
+
data = tmp_file.read
|
136
|
+
Pvcglue.verbose? { data }
|
137
|
+
ensure
|
138
|
+
tmp_file.close
|
139
|
+
tmp_file.unlink # deletes the temp file
|
140
|
+
end
|
141
|
+
data
|
142
|
+
end
|
143
|
+
|
144
|
+
def read_from_file_if_exists?(user, file)
|
145
|
+
tmp_file = Tempfile.new('pvc')
|
146
|
+
begin
|
147
|
+
result = download_file(user, file, tmp_file.path, false)
|
148
|
+
if result.exitstatus == 0
|
149
|
+
data = tmp_file.read
|
150
|
+
elsif result.exitstatus == 1
|
151
|
+
data = nil
|
152
|
+
else
|
153
|
+
raise $?.inspect
|
154
|
+
end
|
155
|
+
Pvcglue.verbose? { data }
|
156
|
+
ensure
|
157
|
+
tmp_file.close
|
158
|
+
tmp_file.unlink # deletes the temp file
|
159
|
+
end
|
160
|
+
data
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
def write_to_file_from_template(user, template_file_name, file, owner = nil, group = nil, permissions = nil)
|
165
|
+
Pvcglue.logger.debug { "Writing to #{file} from template '#{template_file_name}'" }
|
166
|
+
template = Tilt.new(Pvcglue.template_file_name(template_file_name))
|
167
|
+
data = template.render(self, minion: minion)
|
168
|
+
|
169
|
+
write_to_file(user, data, file, owner, group, permissions)
|
170
|
+
end
|
171
|
+
|
172
|
+
def write_to_file(user, data, file, owner = nil, group = nil, permissions = nil)
|
173
|
+
tmp_file = Tempfile.new('pvc')
|
174
|
+
begin
|
175
|
+
tmp_file.write(data)
|
176
|
+
tmp_file.flush
|
177
|
+
upload_file(user, tmp_file.path, file, owner, group, permissions)
|
178
|
+
Pvcglue.verbose? { data }
|
179
|
+
ensure
|
180
|
+
tmp_file.close
|
181
|
+
tmp_file.unlink # deletes the temp file
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def download_file(user, remote_file, local_file, raise_error = true)
|
186
|
+
cmd = %{scp #{user}@#{minion.public_ip}:#{remote_file} #{local_file}}
|
187
|
+
if raise_error
|
188
|
+
system_command!(cmd)
|
189
|
+
else
|
190
|
+
system_command?(cmd)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def upload_file(user, local_file, remote_file, owner = nil, group = nil, permissions = nil)
|
195
|
+
if Pvcglue.command_line_options[:save_before_upload] && file_exists?(user, remote_file)
|
196
|
+
download_file(user, remote_file, Pvcglue.configuration.build_log_extra_filename(minion, user, remote_file))
|
197
|
+
end
|
198
|
+
system_command!(%{scp #{local_file} #{user}@#{minion.public_ip}:#{remote_file}})
|
199
|
+
chown_chmod(user, remote_file, owner, group, permissions)
|
200
|
+
end
|
201
|
+
|
202
|
+
def chown_chmod(user, remote, owner, group, permissions = nil)
|
203
|
+
unless owner.nil? && group.nil?
|
204
|
+
raise('Invalid owner or group for chown') if owner.nil? || group.nil?
|
205
|
+
chown(user, remote, owner, group)
|
206
|
+
end
|
207
|
+
unless permissions.nil?
|
208
|
+
chmod(user, remote, permissions)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def chown(user, remote, owner, group, options = nil)
|
213
|
+
ssh!(user, '', "chown #{options} #{owner}:#{group} #{remote}")
|
214
|
+
end
|
215
|
+
|
216
|
+
def chmod(user, remote, permissions, options = nil)
|
217
|
+
ssh!(user, '', "chmod #{options} #{permissions} #{remote}")
|
218
|
+
end
|
219
|
+
|
220
|
+
def file_matches?(user, data, remote_file)
|
221
|
+
# NOTE: This could be optimized
|
222
|
+
return false unless file_exists?(user, remote_file)
|
223
|
+
read_from_file(user, remote_file) == data
|
224
|
+
end
|
225
|
+
|
226
|
+
def rsync_up (user, options, local_source_dir, remote_destination_dir, mkdir = true)
|
227
|
+
mkdir_p(user, remote_destination_dir) if mkdir
|
228
|
+
cmd = ''
|
229
|
+
# cmd += "mkdir -p #{remote_destination_dir} && "
|
230
|
+
cmd += %(rsync #{options} #{local_source_dir}/ #{user}@#{minion.public_ip}:#{remote_destination_dir}/)
|
231
|
+
# cmd = (%(rsync -rzv --exclude=maintenance.on --delete -e 'ssh -p #{Pvcglue.cloud.port_in_node_context}' #{source_dir}/ #{node.get(:user)}@#{node.host}:#{dest_dir}/))
|
232
|
+
system_command!(cmd)
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
236
|
+
end
|
data/lib/pvcglue/db.rb
CHANGED
@@ -96,8 +96,8 @@ module Pvcglue
|
|
96
96
|
end
|
97
97
|
|
98
98
|
def self.db_host_public
|
99
|
-
|
100
|
-
|
99
|
+
# Assume 1 pg server
|
100
|
+
Pvcglue.cloud.minions_filtered('pg').values.first.public_ip
|
101
101
|
end
|
102
102
|
|
103
103
|
|
@@ -128,12 +128,15 @@ module Pvcglue
|
|
128
128
|
|
129
129
|
|
130
130
|
def pg_dump(db, file_name, fast)
|
131
|
+
# TODO: Refactor into the db package
|
131
132
|
file_name = self.class.file_helper(file_name)
|
132
133
|
|
133
134
|
if db.kind == :remote
|
134
|
-
|
135
|
+
minion = Pvcglue.cloud.minions_filtered('pg').values.first
|
136
|
+
# Assume 1 pg server
|
137
|
+
host = minion.public_ip
|
135
138
|
port = Pvcglue.cloud.port_in_context(:shell)
|
136
|
-
user =
|
139
|
+
user = minion.remote_user_name
|
137
140
|
end
|
138
141
|
|
139
142
|
cmd = "pg_dump -Fc --no-acl --no-owner -h #{db.host} -p #{db.port}"
|
@@ -153,43 +156,46 @@ module Pvcglue
|
|
153
156
|
unless Pvcglue.run_remote(host, port, user, cmd)
|
154
157
|
puts "ERROR:"
|
155
158
|
puts $?.inspect
|
156
|
-
raise(
|
159
|
+
raise("Error: #{$?}")
|
157
160
|
end
|
158
161
|
|
159
162
|
cmd = %{scp -P #{port} #{user}@#{host}:#{file_name} #{file_name}}
|
160
163
|
puts "Running `#{cmd}`"
|
161
164
|
|
162
165
|
unless system cmd
|
163
|
-
raise(
|
166
|
+
raise("Error: #{$?}")
|
164
167
|
end
|
165
168
|
else
|
166
169
|
unless system(cmd)
|
167
170
|
puts "ERROR:"
|
168
171
|
puts $?.inspect
|
169
|
-
raise(
|
172
|
+
raise("Error: #{$?}")
|
170
173
|
end
|
171
174
|
end
|
172
175
|
end
|
173
176
|
|
174
177
|
def pg_restore(db, file_name, fast = false)
|
178
|
+
# TODO: Refactor into the db package
|
175
179
|
Pvcglue.cloud.stage_name == 'production' && destroy_prod?(db)
|
176
180
|
file_name = self.class.file_helper(file_name)
|
177
181
|
|
182
|
+
|
178
183
|
if db.kind == :remote
|
179
|
-
|
184
|
+
minion = Pvcglue.cloud.minions_filtered('pg').values.first
|
185
|
+
host = minion.public_ip
|
180
186
|
port = Pvcglue.cloud.port_in_context(:shell)
|
181
|
-
user =
|
187
|
+
user = minion.remote_user_name
|
182
188
|
|
183
189
|
# cmd = %{scp -P #{port} #{file_name} #{user}@#{host}:#{file_name}}
|
184
190
|
cmd = %{rsync -avhPe "ssh -p #{port}" --progress #{file_name} #{user}@#{host}:#{file_name}}
|
185
191
|
unless system cmd
|
186
|
-
raise(
|
192
|
+
raise("Error: #{$?}")
|
187
193
|
end
|
188
194
|
|
189
195
|
unless fast
|
190
196
|
# Drop and recreate DB
|
191
|
-
Pvcglue::Packages.apply('postgresql-app-stage-db-drop'.to_sym, :build, Pvcglue.cloud.
|
192
|
-
Pvcglue::Packages.apply('postgresql-app-stage-conf'.to_sym, :build, Pvcglue.cloud.
|
197
|
+
Pvcglue::Packages.apply('postgresql-app-stage-db-drop'.to_sym, :build, Pvcglue.cloud.minions_filtered('db'))
|
198
|
+
Pvcglue::Packages.apply('postgresql-app-stage-conf'.to_sym, :build, Pvcglue.cloud.minions_filtered('db'))
|
193
199
|
end
|
194
200
|
end
|
195
201
|
|
@@ -205,7 +211,7 @@ module Pvcglue
|
|
205
211
|
end
|
206
212
|
else
|
207
213
|
unless system(" PGPASSWORD=#{db.password} #{cmd}")
|
208
|
-
raise(
|
214
|
+
raise("Error: #{$?}")
|
209
215
|
end
|
210
216
|
end
|
211
217
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Pvcglue
|
2
|
+
class DigitalOcean
|
3
|
+
|
4
|
+
def self.client
|
5
|
+
@@client ||= get_client
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.get_client
|
9
|
+
access_token = YAML::load(File.open(File.join(ENV['HOME'], '.config/doctl/config.yaml')))['access-token']
|
10
|
+
::DropletKit::Client.new(access_token: access_token)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.get_ip_addresses(droplet)
|
14
|
+
ips = ::SafeMash.new
|
15
|
+
droplet.networks.v4.each do |network|
|
16
|
+
ips[network.type] = network.ip_address
|
17
|
+
end
|
18
|
+
ips
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/pvcglue/env.rb
CHANGED
@@ -6,16 +6,18 @@ module Pvcglue
|
|
6
6
|
desc "push", "push"
|
7
7
|
|
8
8
|
def push
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
raise('Not implemented')
|
10
|
+
# Pvcglue::Packages.apply('env-push'.to_sym, :manager, Pvcglue::Manager.manager_node, 'pvcglue')
|
11
|
+
# self.class.clear_stage_env_cache
|
12
|
+
# Pvcglue::Packages.apply('app-env-file'.to_sym, :env, Pvcglue.cloud.nodes_in_stage('web'))
|
12
13
|
end
|
13
14
|
|
14
15
|
desc "pull", "pull"
|
15
16
|
|
16
17
|
def pull
|
17
|
-
|
18
|
-
|
18
|
+
raise('Not implemented')
|
19
|
+
# Pvcglue::Packages.apply('env-pull'.to_sym, :manager, Pvcglue::Manager.manager_node, 'pvcglue')
|
20
|
+
# self.class.clear_stage_env_cache
|
19
21
|
end
|
20
22
|
|
21
23
|
desc "list", "list"
|
@@ -38,10 +40,12 @@ module Pvcglue
|
|
38
40
|
|
39
41
|
def set(*args)
|
40
42
|
self.class.initialize_stage_env
|
43
|
+
Pvcglue.logger.debug { args.each { |arg| arg.inspect } }
|
41
44
|
options = Hash[args.each.map { |l| l.chomp.split('=') }]
|
45
|
+
Pvcglue.logger.debug { options.inspect }
|
42
46
|
Pvcglue.cloud.stage_env.merge!(options)
|
43
47
|
self.class.save_stage_env
|
44
|
-
|
48
|
+
self.class.apply_changes
|
45
49
|
end
|
46
50
|
|
47
51
|
desc "unset", "remove environment variable(s) for the stage XYZ [ZZZ]"
|
@@ -50,7 +54,7 @@ module Pvcglue
|
|
50
54
|
self.class.initialize_stage_env
|
51
55
|
args.each { |arg| puts "WARNING: Key '#{arg}' not found." unless Pvcglue.cloud.stage_env.delete(arg) }
|
52
56
|
self.class.save_stage_env
|
53
|
-
|
57
|
+
self.class.apply_changes
|
54
58
|
end
|
55
59
|
|
56
60
|
desc "rm", "alternative to unset"
|
@@ -63,10 +67,11 @@ module Pvcglue
|
|
63
67
|
# ------------------------------------------------------------------------------------------------------------------
|
64
68
|
|
65
69
|
def self.initialize_stage_env
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
+
Pvcglue::Packages::Secrets.load_for_stage
|
71
|
+
# unless read_cached_stage_env
|
72
|
+
# Pvcglue::Packages.apply('env-get-stage'.to_sym, :manager, Pvcglue::Manager.manager_node, 'pvcglue')
|
73
|
+
# write_stage_env_cache
|
74
|
+
# end
|
70
75
|
merged = stage_env_defaults.merge(Pvcglue.cloud.stage_env)
|
71
76
|
if merged != Pvcglue.cloud.stage_env
|
72
77
|
Pvcglue.cloud.stage_env = merged
|
@@ -75,35 +80,48 @@ module Pvcglue
|
|
75
80
|
end
|
76
81
|
|
77
82
|
def self.save_stage_env
|
78
|
-
Pvcglue::Packages
|
79
|
-
|
83
|
+
Pvcglue::Packages::Secrets.save_for_stage
|
84
|
+
# Pvcglue::Packages.apply('env-set-stage'.to_sym, :manager, Pvcglue::Manager.manager_node, 'pvcglue')
|
85
|
+
# write_stage_env_cache
|
80
86
|
end
|
81
87
|
|
82
88
|
def self.stage_env_defaults
|
83
|
-
{
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
89
|
+
defaults = {}
|
90
|
+
|
91
|
+
defaults['RAILS_SECRET_TOKEN'] = SecureRandom.hex(64) # From rails/railties/lib/rails/tasks/misc.rake
|
92
|
+
defaults['SECRET_KEY_BASE'] = SecureRandom.hex(64) # From rails/railties/lib/rails/tasks/misc.rake
|
93
|
+
|
94
|
+
if Pvcglue.cloud.minions_filtered('pg').any?
|
95
|
+
defaults['DB_USER_POSTGRES_HOST'] = db_host
|
96
|
+
defaults['DB_USER_POSTGRES_PORT'] = "5432"
|
97
|
+
defaults['DB_USER_POSTGRES_USERNAME'] = "#{Pvcglue.cloud.app_name}_#{Pvcglue.cloud.stage_name_validated}"
|
98
|
+
defaults['DB_USER_POSTGRES_DATABASE'] = "#{Pvcglue.cloud.app_name}_#{Pvcglue.cloud.stage_name_validated}"
|
99
|
+
defaults['DB_USER_POSTGRES_PASSWORD'] = new_password
|
100
|
+
end
|
101
|
+
|
102
|
+
if Pvcglue.cloud.minions_filtered('memcached').any?
|
103
|
+
defaults['MEMCACHE_SERVERS'] = memcached_host
|
104
|
+
end
|
105
|
+
|
106
|
+
if Pvcglue.cloud.minions_filtered('redis').any?
|
107
|
+
defaults['REDIS_SERVER'] = redis_host
|
108
|
+
end
|
109
|
+
|
110
|
+
defaults
|
93
111
|
end
|
94
112
|
|
95
113
|
def self.db_host
|
96
|
-
|
97
|
-
|
114
|
+
# Assume 1 pg server
|
115
|
+
Pvcglue.cloud.minions_filtered('pg').values.first.private_ip
|
98
116
|
end
|
99
117
|
|
100
118
|
def self.memcached_host
|
101
|
-
node = Pvcglue.cloud.
|
119
|
+
node = Pvcglue.cloud.find_minion_by_name('memcached', false)
|
102
120
|
node ? "#{node['memcached']['private_ip']}:11211" : ""
|
103
121
|
end
|
104
122
|
|
105
123
|
def self.redis_host
|
106
|
-
node = Pvcglue.cloud.
|
124
|
+
node = Pvcglue.cloud.find_minion_by_name('redis', false)
|
107
125
|
node ? "#{node['redis']['private_ip']}:6379" : ""
|
108
126
|
end
|
109
127
|
|
@@ -143,7 +161,13 @@ module Pvcglue
|
|
143
161
|
File.delete(stage_env_cache_file_name) if File.exists?(stage_env_cache_file_name)
|
144
162
|
end
|
145
163
|
|
146
|
-
|
164
|
+
def self.apply_changes
|
165
|
+
Pvcglue.cloud.minions.each do |minion_name, minion|
|
166
|
+
if minion.has_roles? %w(web worker)
|
167
|
+
Pvcglue::Packages::Secrets.apply(minion)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
147
171
|
end
|
148
172
|
|
149
173
|
end
|