This repository has been archived by the owner on Mar 24, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathsetup_environment.rb
executable file
·284 lines (235 loc) · 9.18 KB
/
setup_environment.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
#! /usr/bin/env ruby
require "net/http"
require "uri"
require 'optparse'
require 'json'
require 'pp'
require 'open3'
require 'pty'
require 'fileutils'
require 'yaml'
options = {}
opt_parser = OptionParser.new do |opt|
opt.banner = "Usage: setup_environment.rb [OPTIONS]"
opt.on("-u", "--username USERNAME", String, "Lastpass username containing a shared telemetry folder") do |username|
options[:username] = username
end
opt.on("-e", "--environment environment", String, "The environment you want to setup") do |environment|
options[:environment] = environment
end
opt.on("-i", "--url local-file-url", "the url of the environment lock file") do |url|
options[:url] = url
end
opt.on("-h","--help","help") do
puts opt_parser
exit
end
end
opt_parser.parse(ARGV)
if !options[:environment] && !options[:url]
puts "error: Must supply either the environment or the url to the lock file"
puts opt_parser
exit 1
end
if !options[:username]
puts "error: Must supply the lastpass username"
puts opt_parser
exit 1
end
lastpass_username = options[:username]
unless logged_into_lastpass?
puts "Logging into lastpass"
lastpass_login(username: lastpass_username)
end
if options[:environment]
puts "Getting lock file from Last Pass"
env_lock = load_lock_file_from_lastpass(name: options[:environment])
else
puts "Loading lock file from url"
env_lock = load_lock_file_from_url(url: options[:url])
end
env_dir = "#{Dir.home}/workspace/#{env_lock[:name]}"
FileUtils.mkdir_p(env_dir)
puts "Writing SSH key: #{env_dir}/ssh-key"
File.write("#{env_dir}/ssh-key", env_lock[:ops_manager_private_key])
File.chmod(0600, "#{env_dir}/ssh-key")
puts "Fetching root ca cert from ops manager: #{env_lock[:ops_manager][:url]}"
ca_cert_json, _, _ = run_command(cmd: "#{om} -k curl --path /api/v0/security/root_ca_certificate",
env: om_opts(env_lock: env_lock))
ca_cert = JSON.parse(ca_cert_json, symbolize_names: true)
puts "Writing CA cert: #{env_dir}/root_ca_certificate"
File.write("#{env_dir}/root_ca_certificate", ca_cert[:root_ca_certificate_pem])
puts "Fetching BOSH credentials from ops manager"
bosh_creds_json, _, _ = run_command(cmd: "#{om} -k curl --path /api/v0/deployed/director/credentials/bosh_commandline_credentials",
env: om_opts(env_lock: env_lock))
bosh_creds = parse_bosh_creds(bosh_json: bosh_creds_json)
puts "Writing .envrc"
File.write("#{env_dir}/.envrc", envrc(client: bosh_creds[:BOSH_CLIENT],
client_secret: bosh_creds[:BOSH_CLIENT_SECRET],
director_ip: bosh_creds[:BOSH_ENVIRONMENT],
ca_cert_path: "#{env_dir}/root_ca_certificate",
ssh_key_path: "#{env_dir}/ssh-key",
env_lock: env_lock))
iaas_type = env_lock[:iaas_type]
if iaas_type == "vsphere"
target_network_name = "default"
elsif iaas_type == "gcp"
target_network_name = "#{env_lock[:name]}-services-subnet"
end
pipeline_vars = {
'director_name' => env_lock[:name],
'network_name' => target_network_name,
'jumpbox_url' => "#{env_lock[:ops_manager_dns]}:22",
# hardcoded password is OK. Only used in test environments.
'mysql_pks_billing_db_password' => 'Zns0tZ3vRHhJYdO8ANZSIJEfchjsAU',
'bosh_client' => bosh_creds[:BOSH_CLIENT],
'bosh_client_secret' => bosh_creds[:BOSH_CLIENT_SECRET],
'credhub_secret' => bosh_creds[:BOSH_CLIENT_SECRET],
'bosh_ca_cert' => ca_cert[:root_ca_certificate_pem],
'opsmgr_private_key' => env_lock[:ops_manager_private_key]
}
puts 'Fetching networks from Ops Manager'
networks_list_json, _, _ = run_command(cmd: "#{om} -k curl --path /api/v0/staged/director/networks",
env: om_opts(env_lock: env_lock))
networks_list = JSON.parse(networks_list_json, symbolize_names: true)[:networks]
services_subnet = networks_list.find { |n| n[:name] == target_network_name }
pipeline_vars['azs'] = services_subnet[:subnets].first[:availability_zone_names]
telemetry_test_certs = YAML.load_file(File.join(__dir__, 'telemetry-test-certs-new.yml'))
pipeline_vars['telemetry_tls'] = telemetry_test_certs
puts 'Writing pipeline-vars.yml'
File.write("#{env_dir}/pipeline-vars.yml", YAML.dump(pipeline_vars))
lpass_creds_entry = "Shared-PKS Telemetry/[#{env_lock[:name]}] OpsMgr Creds"
puts "Creating lpass username/password entry: #{lpass_creds_entry}"
if already_in_lpass?(entry: lpass_creds_entry)
puts "#{lpass_creds_entry} already exists. Skipping..."
else
run_command(cmd: lastpass_creds_entry_cmd(env_lock: env_lock, entry: lpass_creds_entry))
end
lpass_lock_file_entry = "Shared-PKS Telemetry/[#{env_lock[:name]}] opsmgr-lock-file.json"
puts "Creating lpass lock file entry: #{lpass_lock_file_entry}"
if already_in_lpass?(entry: lpass_lock_file_entry)
puts "#{lpass_lock_file_entry} already exists. Skipping..."
else
run_command(cmd: lastpass_lock_file_entry_cmd(env_lock: env_lock, entry: lpass_lock_file_entry))
end
ssh_config_path = "#{Dir.home}/.ssh/config.d/#{env_lock[:name]}"
puts "Writing ssh config at: #{ssh_config_path}"
FileUtils.mkdir_p("#{Dir.home}/.ssh/config.d/")
File.write(ssh_config_path, ssh_config_directive(env_name: env_lock[:name],
opsmanager_dns: env_lock[:ops_manager_dns],
ssh_key_path: "#{env_dir}/ssh-key"))
run_command(cmd: 'lpass sync now')
BEGIN {
def already_in_lpass?(entry:)
stdout, _, _ = run_command(cmd: "#{lpass} ls '#{entry}'")
!stdout.empty?
end
def load_lock_file_from_url(url:)
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.open_timeout = http.read_timeout = 5
http.use_ssl = true
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
unless response.kind_of?(Net::HTTPSuccess)
fail " got error from #{url}. response code: #{response.code}. response: #{response.body}"
end
JSON.parse(response.body, symbolize_names: true)
end
def load_lock_file_from_lastpass(name:)
cmd_string = "lpass show \"Shared-PKS Telemetry/[#{name}] opsmgr-lock-file.json\" --notes"
lock_file_json, _, _ = run_command(cmd: cmd_string)
JSON.parse(lock_file_json, symbolize_names: true)
end
def run_command(cmd:, env: {})
puts "$ #{cmd}"
stdout, stderr, status = Open3.capture3(env.merge(ENV), cmd)
unless status.success?
fail "command failed. stderr: #{stderr}. stdout: #{stdout}"
end
[stdout, stderr, status]
end
def om
@om ||= `which om`.chomp
if @om.empty?
fail 'cannot find om on path'
end
@om
end
def lpass
@lpass ||= `which lpass`.chomp
if @lpass.empty?
fail "cannot find lpass on path"
end
@lpass
end
def envrc(client:, client_secret:, director_ip:, ca_cert_path:, ssh_key_path:, env_lock:)
ops_manager_hostname = env_lock[:ops_manager_dns]
bosh_vars = <<~ENVRC
export BOSH_CLIENT=#{client}
export BOSH_CLIENT_SECRET=#{client_secret}
export BOSH_CA_CERT=#{ca_cert_path}
export BOSH_ENVIRONMENT=#{director_ip}
export BOSH_ALL_PROXY=ssh+socks5://ubuntu@#{ops_manager_hostname}:22?private-key=#{ssh_key_path}
export CREDHUB_PROXY=ssh+socks5://ubuntu@#{ops_manager_hostname}:22?private-key=#{ssh_key_path}
ENVRC
om_vars = om_opts(env_lock: env_lock).map { |k, v| "export #{k}=#{v}" }.join("\n")
[bosh_vars, om_vars].join("\n")
end
def parse_bosh_creds(bosh_json:)
s = JSON.parse(bosh_json, symbolize_names: true)[:credential]
s.split.map { |i| i.split('=') }.inject({}) { |memo, cred| memo[cred.first.to_sym] = cred.last; memo }
end
def om_opts(env_lock:)
{
"OM_USERNAME" => env_lock[:ops_manager][:username],
"OM_PASSWORD" => env_lock[:ops_manager][:password],
"OM_TARGET" => env_lock[:ops_manager][:url],
}
end
def lastpass_creds_entry_cmd(env_lock:, entry:)
<<~LPASS
printf "Username: #{env_lock[:ops_manager][:username]}\nPassword: #{env_lock[:ops_manager][:password]}\nURL: #{env_lock[:ops_manager][:url]}" |
#{lpass} add --non-interactive "#{entry}"
LPASS
end
def lastpass_lock_file_entry_cmd(env_lock:, entry:)
<<~LPASS
gecho -E '#{env_lock.to_json}' |
#{lpass} add --non-interactive --notes "#{entry}"
LPASS
end
def squish(str)
str.gsub(/\A[[:space:]]+/, '').gsub(/[[:space:]]+\z/, '').gsub(/[[:space:]]+/, ' ')
end
def logged_into_lastpass?
_, _, status = Open3.capture3("#{lpass} sync")
status.success?
end
def lastpass_login(username:, trust: false)
PTY.open
puts "Logging into LastPass"
pid = fork do
if trust
exec("#{lpass} login --trust #{username}")
else
exec("#{lpass} login #{username}")
end
end
Signal.trap(:INT) {}
_, status = Process.waitpid2(pid)
unless status.success?
fail 'error logging into lastpass'
end
ensure
Signal.trap(:INT, nil)
end
def ssh_config_directive(env_name:, opsmanager_dns:, ssh_key_path:)
<<~SSH
Host #{env_name} #{opsmanager_dns}
HostName #{opsmanager_dns}
User ubuntu
IdentityFile #{ssh_key_path}
SSH
end
}