leap_cli 1.6.2 → 1.7.3
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 +7 -0
- data/bin/leap +20 -6
- data/lib/leap/platform.rb +10 -12
- data/lib/leap_cli.rb +5 -3
- data/lib/leap_cli/commands/ca.rb +46 -35
- data/lib/leap_cli/commands/compile.rb +6 -2
- data/lib/leap_cli/commands/db.rb +42 -6
- data/lib/leap_cli/commands/deploy.rb +117 -35
- data/lib/leap_cli/commands/pre.rb +49 -34
- data/lib/leap_cli/commands/ssh.rb +84 -16
- data/lib/leap_cli/commands/user.rb +1 -1
- data/lib/leap_cli/commands/vagrant.rb +38 -51
- data/lib/leap_cli/config/manager.rb +6 -3
- data/lib/leap_cli/config/object.rb +41 -2
- data/lib/leap_cli/config/object_list.rb +1 -1
- data/lib/leap_cli/config/secrets.rb +18 -7
- data/lib/leap_cli/config/sources.rb +11 -0
- data/lib/leap_cli/core_ext/deep_dup.rb +53 -0
- data/lib/leap_cli/core_ext/time.rb +86 -0
- data/lib/leap_cli/leapfile.rb +21 -10
- data/lib/leap_cli/logger.rb +5 -5
- data/lib/leap_cli/remote/leap_plugin.rb +11 -0
- data/lib/leap_cli/remote/puppet_plugin.rb +1 -1
- data/lib/leap_cli/remote/tasks.rb +3 -2
- data/lib/leap_cli/util.rb +31 -23
- data/lib/leap_cli/util/secret.rb +1 -1
- data/lib/leap_cli/version.rb +2 -2
- data/vendor/certificate_authority/lib/certificate_authority/certificate.rb +2 -2
- data/vendor/certificate_authority/lib/certificate_authority/certificate_revocation_list.rb +2 -2
- data/vendor/certificate_authority/lib/certificate_authority/signing_request.rb +1 -1
- metadata +105 -168
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 36be7f0c765dbd1c64ca36079780ad6f44797fe0
|
4
|
+
data.tar.gz: 379a244c172b9a07d0f9b1a1635d47aa16bd68bc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 079ed74cf97faa015438ecf0dbc4ac2e4bc50a0360e48b602597ef9e8a7e7959943872a498554ef38d455ba461ff65e481d444c25bd55d14e92b6f7abd842fed
|
7
|
+
data.tar.gz: 1ec35e8f043b0b0b4516a6fa447420f0d1eb0e42c062b40afb9aae9ab939c0ce50b97dcf5989a5aac7fd70d26aa88333a8e77c655dfa76d97d7573a616f77f20
|
data/bin/leap
CHANGED
@@ -3,13 +3,20 @@
|
|
3
3
|
if ARGV.include?('--debug') || ARGV.include?('-d')
|
4
4
|
DEBUG=true
|
5
5
|
begin
|
6
|
-
|
6
|
+
if RUBY_VERSION =~ /^2/
|
7
|
+
require 'byebug'
|
8
|
+
else
|
9
|
+
require 'debugger'
|
10
|
+
end
|
7
11
|
rescue LoadError
|
8
12
|
end
|
9
13
|
else
|
10
14
|
DEBUG=false
|
11
15
|
end
|
12
16
|
|
17
|
+
LEAP_CLI_BASE_DIR = File.expand_path('..', File.dirname(File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__))
|
18
|
+
ORIGINAL_ARGV = ARGV.dup
|
19
|
+
|
13
20
|
begin
|
14
21
|
require 'leap_cli'
|
15
22
|
rescue LoadError
|
@@ -24,8 +31,7 @@ rescue LoadError
|
|
24
31
|
# This allows you to run the command directly while developing the gem, and also lets you
|
25
32
|
# run from anywhere (I like to link 'bin/leap' to /usr/local/bin/leap).
|
26
33
|
#
|
27
|
-
|
28
|
-
require File.join(base_dir, 'lib','leap_cli','load_paths')
|
34
|
+
require File.join(LEAP_CLI_BASE_DIR, 'lib','leap_cli','load_paths')
|
29
35
|
require 'leap_cli'
|
30
36
|
end
|
31
37
|
|
@@ -77,9 +83,16 @@ module LeapCli::Commands
|
|
77
83
|
program_desc LeapCli::SUMMARY
|
78
84
|
program_long_desc LeapCli::DESCRIPTION
|
79
85
|
|
80
|
-
# handle --version ourselves
|
86
|
+
# handle --version ourselves (and not GLI)
|
81
87
|
if ARGV.grep(/--version/).any?
|
82
88
|
puts "leap #{LeapCli::VERSION}, ruby #{RUBY_VERSION}"
|
89
|
+
begin
|
90
|
+
commands_from('leap_cli/commands')
|
91
|
+
initialize_leap_cli(false, {:verbose => 2})
|
92
|
+
rescue StandardError => exc
|
93
|
+
puts exc.to_s
|
94
|
+
raise exc if DEBUG
|
95
|
+
end
|
83
96
|
exit(0)
|
84
97
|
end
|
85
98
|
|
@@ -88,9 +101,10 @@ module LeapCli::Commands
|
|
88
101
|
def error_message(msg)
|
89
102
|
end
|
90
103
|
|
91
|
-
# load commands
|
104
|
+
# load commands
|
92
105
|
commands_from('leap_cli/commands')
|
93
|
-
|
106
|
+
|
107
|
+
# run command
|
94
108
|
begin
|
95
109
|
exit_status = run(ARGV)
|
96
110
|
exit(LeapCli::Util.exit_status || exit_status)
|
data/lib/leap/platform.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'versionomy'
|
2
|
-
|
3
1
|
module Leap
|
4
2
|
|
5
3
|
class Platform
|
@@ -34,24 +32,24 @@ module Leap
|
|
34
32
|
|
35
33
|
self.instance_eval(&block)
|
36
34
|
|
37
|
-
@version ||=
|
35
|
+
@version ||= Gem::Version.new("0.0")
|
38
36
|
end
|
39
37
|
|
40
38
|
def version=(version)
|
41
|
-
@version =
|
39
|
+
@version = Gem::Version.new(version)
|
42
40
|
end
|
43
41
|
|
44
42
|
def compatible_cli=(range)
|
45
43
|
@compatible_cli = range
|
46
|
-
@minimum_cli_version =
|
47
|
-
@maximum_cli_version =
|
44
|
+
@minimum_cli_version = Gem::Version.new(range.first)
|
45
|
+
@maximum_cli_version = Gem::Version.new(range.last)
|
48
46
|
end
|
49
47
|
|
50
48
|
#
|
51
49
|
# return true if the cli_version is compatible with this platform.
|
52
50
|
#
|
53
51
|
def compatible_with_cli?(cli_version)
|
54
|
-
cli_version =
|
52
|
+
cli_version = Gem::Version.new(cli_version)
|
55
53
|
cli_version >= @minimum_cli_version && cli_version <= @maximum_cli_version
|
56
54
|
end
|
57
55
|
|
@@ -62,16 +60,16 @@ module Leap
|
|
62
60
|
if range.is_a? String
|
63
61
|
range = range.split('..')
|
64
62
|
end
|
65
|
-
minimum_platform_version =
|
66
|
-
maximum_platform_version =
|
63
|
+
minimum_platform_version = Gem::Version.new(range.first)
|
64
|
+
maximum_platform_version = Gem::Version.new(range.last)
|
67
65
|
@version >= minimum_platform_version && @version <= maximum_platform_version
|
68
66
|
end
|
69
67
|
|
70
68
|
def major_version
|
71
|
-
if @version.
|
72
|
-
|
69
|
+
if @version.segments.first == 0
|
70
|
+
@version.segments[0..1].join('.')
|
73
71
|
else
|
74
|
-
@version.
|
72
|
+
@version.segments.first
|
75
73
|
end
|
76
74
|
end
|
77
75
|
|
data/lib/leap_cli.rb
CHANGED
@@ -12,7 +12,7 @@ $:.unshift(File.expand_path('../leap_cli/override',__FILE__))
|
|
12
12
|
# enforce the compatible versions here:
|
13
13
|
require 'rubygems'
|
14
14
|
gem 'net-ssh', '~> 2.7.0'
|
15
|
-
gem 'gli', '~> 2.12.0'
|
15
|
+
gem 'gli', '~> 2.12', '>= 2.12.0'
|
16
16
|
|
17
17
|
require 'leap/platform'
|
18
18
|
|
@@ -20,11 +20,13 @@ require 'leap_cli/version'
|
|
20
20
|
require 'leap_cli/exceptions'
|
21
21
|
|
22
22
|
require 'leap_cli/leapfile'
|
23
|
-
require 'leap_cli/core_ext/hash'
|
24
23
|
require 'leap_cli/core_ext/boolean'
|
24
|
+
require 'leap_cli/core_ext/deep_dup'
|
25
|
+
require 'leap_cli/core_ext/hash'
|
26
|
+
require 'leap_cli/core_ext/json'
|
25
27
|
require 'leap_cli/core_ext/nil'
|
26
28
|
require 'leap_cli/core_ext/string'
|
27
|
-
require 'leap_cli/core_ext/
|
29
|
+
require 'leap_cli/core_ext/time'
|
28
30
|
require 'leap_cli/core_ext/yaml'
|
29
31
|
|
30
32
|
require 'leap_cli/log'
|
data/lib/leap_cli/commands/ca.rb
CHANGED
@@ -28,26 +28,11 @@ module LeapCli; module Commands
|
|
28
28
|
cert.command :update do |update|
|
29
29
|
update.switch 'force', :desc => 'Always generate new certificates', :negatable => false
|
30
30
|
update.action do |global_options,options,args|
|
31
|
-
|
32
|
-
assert_config! 'provider.ca.server_certificates.bit_size'
|
33
|
-
assert_config! 'provider.ca.server_certificates.digest'
|
34
|
-
assert_config! 'provider.ca.server_certificates.life_span'
|
35
|
-
assert_config! 'common.x509.use'
|
36
|
-
|
37
|
-
nodes = manager.filter!(args)
|
38
|
-
nodes.each_node do |node|
|
39
|
-
warn_if_commercial_cert_will_soon_expire(node)
|
40
|
-
if !node.x509.use
|
41
|
-
remove_file!([:node_x509_key, node.name])
|
42
|
-
remove_file!([:node_x509_cert, node.name])
|
43
|
-
elsif options[:force] || cert_needs_updating?(node)
|
44
|
-
generate_cert_for_node(node)
|
45
|
-
end
|
46
|
-
end
|
31
|
+
update_certificates(manager.filter!(args), options)
|
47
32
|
end
|
48
33
|
end
|
49
34
|
|
50
|
-
cert.desc 'Creates a Diffie-Hellman parameter file.' # (needed for server-side of some TLS connections)
|
35
|
+
cert.desc 'Creates a Diffie-Hellman parameter file, needed for forward secret OpenVPN ciphers.' # (needed for server-side of some TLS connections)
|
51
36
|
cert.command :dh do |dh|
|
52
37
|
dh.action do |global_options,options,args|
|
53
38
|
long_running do
|
@@ -102,7 +87,11 @@ module LeapCli; module Commands
|
|
102
87
|
assert_config! 'provider.ca.server_certificates.bit_size'
|
103
88
|
assert_config! 'provider.ca.server_certificates.digest'
|
104
89
|
domain = options[:domain] || provider.domain
|
105
|
-
|
90
|
+
|
91
|
+
unless global_options[:force]
|
92
|
+
assert_files_missing! [:commercial_key, domain], [:commercial_csr, domain],
|
93
|
+
:msg => 'If you really want to create a new key and CSR, remove these files first or run with --force.'
|
94
|
+
end
|
106
95
|
|
107
96
|
server_certificates = provider.ca.server_certificates
|
108
97
|
|
@@ -139,7 +128,7 @@ module LeapCli; module Commands
|
|
139
128
|
cert = csr.to_cert
|
140
129
|
cert.serial_number.number = cert_serial_number(domain)
|
141
130
|
cert.not_before = yesterday
|
142
|
-
cert.not_after =
|
131
|
+
cert.not_after = yesterday.advance(:years => 1)
|
143
132
|
cert.parent = ca_root
|
144
133
|
cert.sign! domain_test_signing_profile
|
145
134
|
write_file! [:commercial_cert, domain], cert.to_pem
|
@@ -158,6 +147,29 @@ module LeapCli; module Commands
|
|
158
147
|
end
|
159
148
|
end
|
160
149
|
|
150
|
+
protected
|
151
|
+
|
152
|
+
#
|
153
|
+
# will generate new certificates for the specified nodes, if needed.
|
154
|
+
#
|
155
|
+
def update_certificates(nodes, options={})
|
156
|
+
assert_files_exist! :ca_cert, :ca_key, :msg => 'Run `leap cert ca` to create them'
|
157
|
+
assert_config! 'provider.ca.server_certificates.bit_size'
|
158
|
+
assert_config! 'provider.ca.server_certificates.digest'
|
159
|
+
assert_config! 'provider.ca.server_certificates.life_span'
|
160
|
+
assert_config! 'common.x509.use'
|
161
|
+
|
162
|
+
nodes.each_node do |node|
|
163
|
+
warn_if_commercial_cert_will_soon_expire(node)
|
164
|
+
if !node.x509.use
|
165
|
+
remove_file!([:node_x509_key, node.name])
|
166
|
+
remove_file!([:node_x509_cert, node.name])
|
167
|
+
elsif options[:force] || cert_needs_updating?(node)
|
168
|
+
generate_cert_for_node(node)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
161
173
|
private
|
162
174
|
|
163
175
|
def generate_new_certificate_authority(key_file, cert_file, common_name)
|
@@ -179,7 +191,7 @@ module LeapCli; module Commands
|
|
179
191
|
|
180
192
|
# set expiration
|
181
193
|
root.not_before = yesterday
|
182
|
-
root.not_after =
|
194
|
+
root.not_after = yesterday_advance(provider.ca.life_span)
|
183
195
|
|
184
196
|
# generate private key
|
185
197
|
root.serial_number.number = 1
|
@@ -203,12 +215,12 @@ module LeapCli; module Commands
|
|
203
215
|
return true
|
204
216
|
else
|
205
217
|
cert = load_certificate_file([:node_x509_cert, node.name])
|
206
|
-
if cert.not_after <
|
218
|
+
if cert.not_after < Time.now.advance(:months => 2)
|
207
219
|
log :updating, "cert for node '#{node.name}' because it will expire soon"
|
208
220
|
return true
|
209
221
|
end
|
210
222
|
if cert.subject.common_name != node.domain.full
|
211
|
-
log :updating, "cert for node '#{node.name}' because domain.full has changed"
|
223
|
+
log :updating, "cert for node '#{node.name}' because domain.full has changed (was #{cert.subject.common_name}, now #{node.domain.full})"
|
212
224
|
return true
|
213
225
|
end
|
214
226
|
cert.openssl_body.extensions.each do |ext|
|
@@ -242,7 +254,7 @@ module LeapCli; module Commands
|
|
242
254
|
if cert.not_after < Time.now.utc
|
243
255
|
log :error, "the commercial certificate '#{path}' has EXPIRED! " +
|
244
256
|
"You should renew it with `leap cert csr --domain #{domain}`."
|
245
|
-
elsif cert.not_after <
|
257
|
+
elsif cert.not_after < Time.now.advance(:months => 2)
|
246
258
|
log :warning, "the commercial certificate '#{path}' will expire soon. "+
|
247
259
|
"You should renew it with `leap cert csr --domain #{domain}`."
|
248
260
|
end
|
@@ -261,7 +273,7 @@ module LeapCli; module Commands
|
|
261
273
|
|
262
274
|
# set expiration
|
263
275
|
cert.not_before = yesterday
|
264
|
-
cert.not_after =
|
276
|
+
cert.not_after = yesterday_advance(provider.ca.server_certificates.life_span)
|
265
277
|
|
266
278
|
# generate key
|
267
279
|
cert.key_material.generate_key(provider.ca.server_certificates.bit_size)
|
@@ -283,7 +295,7 @@ module LeapCli; module Commands
|
|
283
295
|
cert.serial_number.number = cert_serial_number(provider.domain)
|
284
296
|
cert.subject.common_name = [prefix, random_common_name(provider.domain)].join
|
285
297
|
cert.not_before = yesterday
|
286
|
-
cert.not_after =
|
298
|
+
cert.not_after = yesterday.advance(:years => 1)
|
287
299
|
cert.key_material.generate_key(1024) # just for testing, remember!
|
288
300
|
cert.parent = client_ca_root
|
289
301
|
cert.sign! client_test_signing_profile
|
@@ -492,16 +504,15 @@ module LeapCli; module Commands
|
|
492
504
|
Time.utc t.year, t.month, t.day
|
493
505
|
end
|
494
506
|
|
495
|
-
def
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
Time.utc date.year, date.month, date.day
|
507
|
+
def yesterday_advance(string)
|
508
|
+
number, unit = string.split(' ')
|
509
|
+
unless ['years', 'months', 'days', 'hours', 'minutes'].include? unit
|
510
|
+
bail!("The time property '#{string}' is missing a unit (one of: years, months, days, hours, minutes).")
|
511
|
+
end
|
512
|
+
unless number.to_i.to_s == number
|
513
|
+
bail!("The time property '#{string}' is missing a number.")
|
514
|
+
end
|
515
|
+
yesterday.advance(unit.to_sym => number.to_i)
|
505
516
|
end
|
506
517
|
|
507
518
|
end; end
|
@@ -12,8 +12,12 @@ module LeapCli
|
|
12
12
|
if !LeapCli.leapfile.environment.nil? && !environment.nil? && environment != LeapCli.leapfile.environment
|
13
13
|
bail! "You cannot specify an ENVIRONMENT argument while the environment is pinned."
|
14
14
|
end
|
15
|
-
if environment
|
16
|
-
|
15
|
+
if environment
|
16
|
+
if manager.environment_names.include?(environment)
|
17
|
+
compile_hiera_files(manager.filter([environment]))
|
18
|
+
else
|
19
|
+
bail! "There is no environment named `#{environment}`."
|
20
|
+
end
|
17
21
|
else
|
18
22
|
compile_hiera_files(manager.filter)
|
19
23
|
end
|
data/lib/leap_cli/commands/db.rb
CHANGED
@@ -2,21 +2,32 @@ module LeapCli; module Commands
|
|
2
2
|
|
3
3
|
desc 'Database commands.'
|
4
4
|
command :db do |db|
|
5
|
-
db.desc 'Destroy
|
5
|
+
db.desc 'Destroy one or more databases. If present, limit to FILTER nodes. For example `leap db destroy --db sessions,tokens testing`.'
|
6
6
|
db.arg_name 'FILTER', :optional => true
|
7
7
|
db.command :destroy do |destroy|
|
8
|
+
destroy.flag :db, :arg_name => "DATABASES", :desc => 'Comma separated list of databases to destroy (no space). Use "--db all" to destroy all databases.', :optional => false
|
8
9
|
destroy.action do |global_options,options,args|
|
9
|
-
|
10
|
-
|
10
|
+
dbs = (options[:db]||"").split(',')
|
11
|
+
bail!('No databases specified') if dbs.empty?
|
11
12
|
nodes = manager.filter(args)
|
12
13
|
if nodes.any?
|
13
14
|
nodes = nodes[:services => 'couchdb']
|
14
15
|
end
|
15
16
|
if nodes.any?
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
unless global_options[:yes]
|
18
|
+
if dbs.include?('all')
|
19
|
+
say 'You are about to permanently destroy all database data for nodes [%s].' % nodes.keys.join(', ')
|
20
|
+
else
|
21
|
+
say 'You are about to permanently destroy databases [%s] for nodes [%s].' % [dbs.join(', '), nodes.keys.join(', ')]
|
22
|
+
end
|
23
|
+
bail! unless agree("Continue? ")
|
19
24
|
end
|
25
|
+
if dbs.include?('all')
|
26
|
+
destroy_all_dbs(nodes)
|
27
|
+
else
|
28
|
+
destroy_dbs(nodes, dbs)
|
29
|
+
end
|
30
|
+
say 'You must run `leap deploy` in order to create the databases again.'
|
20
31
|
else
|
21
32
|
say 'No nodes'
|
22
33
|
end
|
@@ -26,4 +37,29 @@ module LeapCli; module Commands
|
|
26
37
|
|
27
38
|
private
|
28
39
|
|
40
|
+
def destroy_all_dbs(nodes)
|
41
|
+
ssh_connect(nodes) do |ssh|
|
42
|
+
ssh.run('/etc/init.d/bigcouch stop && test ! -z "$(ls /opt/bigcouch/var/lib/ 2> /dev/null)" && rm -r /opt/bigcouch/var/lib/* && echo "db destroyed" || echo "db already destroyed"')
|
43
|
+
ssh.run('grep ^seq_dir /etc/leap/tapicero.yaml | cut -f2 -d\" | xargs rm -rv')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def destroy_dbs(nodes, dbs)
|
48
|
+
nodes.each_node do |node|
|
49
|
+
ssh_connect(node) do |ssh|
|
50
|
+
dbs.each do |db|
|
51
|
+
ssh.run(DESTROY_DB_COMMAND % {:db => db})
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
DESTROY_DB_COMMAND = %{
|
58
|
+
if [ 200 = `curl -ns -w "%%{http_code}" -X GET "127.0.0.1:5984/%{db}" -o /dev/null` ]; then
|
59
|
+
echo "Result from DELETE /%{db}:" `curl -ns -X DELETE "127.0.0.1:5984/%{db}"`;
|
60
|
+
else
|
61
|
+
echo "Skipping db '%{db}': it does not exist or has already been deleted.";
|
62
|
+
fi
|
63
|
+
}
|
64
|
+
|
29
65
|
end; end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'etc'
|
1
2
|
|
2
3
|
module LeapCli
|
3
4
|
module Commands
|
@@ -7,20 +8,17 @@ module LeapCli
|
|
7
8
|
arg_name 'FILTER'
|
8
9
|
command [:deploy, :d] do |c|
|
9
10
|
|
10
|
-
# --fast
|
11
11
|
c.switch :fast, :desc => 'Makes the deploy command faster by skipping some slow steps. A "fast" deploy can be used safely if you recently completed a normal deploy.',
|
12
12
|
:negatable => false
|
13
13
|
|
14
|
-
|
15
|
-
c.switch :sync, :desc => "Sync files, but don't actually apply recipes."
|
14
|
+
c.switch :sync, :desc => "Sync files, but don't actually apply recipes.", :negatable => false
|
16
15
|
|
17
|
-
# --force
|
18
16
|
c.switch :force, :desc => 'Deploy even if there is a lockfile.', :negatable => false
|
19
17
|
|
20
|
-
|
18
|
+
c.switch :downgrade, :desc => 'Allows deploy to run with an older platform version.', :negatable => false
|
19
|
+
|
21
20
|
c.switch :dev, :desc => "Development mode: don't run 'git submodule update' before deploy.", :negatable => false
|
22
21
|
|
23
|
-
# --tags
|
24
22
|
c.flag :tags, :desc => 'Specify tags to pass through to puppet (overriding the default).',
|
25
23
|
:arg_name => 'TAG[,TAG]'
|
26
24
|
|
@@ -49,11 +47,13 @@ module LeapCli
|
|
49
47
|
environments = [nil]
|
50
48
|
end
|
51
49
|
environments.each do |env|
|
52
|
-
check_platform_pinning(env)
|
50
|
+
check_platform_pinning(env, global)
|
53
51
|
end
|
54
52
|
# compile hiera files for all the nodes in every environment that is
|
55
53
|
# being deployed and only those environments.
|
56
54
|
compile_hiera_files(manager.filter(environments))
|
55
|
+
# update server certificates if needed
|
56
|
+
update_certificates(nodes)
|
57
57
|
|
58
58
|
ssh_connect(nodes, connect_options(options)) do |ssh|
|
59
59
|
ssh.leap.log :checking, 'node' do
|
@@ -69,7 +69,12 @@ module LeapCli
|
|
69
69
|
end
|
70
70
|
unless options[:sync]
|
71
71
|
ssh.leap.log :applying, "puppet" do
|
72
|
-
ssh.puppet.apply(:verbosity => [LeapCli.log_level,5].min,
|
72
|
+
ssh.puppet.apply(:verbosity => [LeapCli.log_level,5].min,
|
73
|
+
:tags => tags(options),
|
74
|
+
:force => options[:force],
|
75
|
+
:info => deploy_info,
|
76
|
+
:downgrade => options[:downgrade]
|
77
|
+
)
|
73
78
|
end
|
74
79
|
end
|
75
80
|
end
|
@@ -79,8 +84,34 @@ module LeapCli
|
|
79
84
|
end
|
80
85
|
end
|
81
86
|
|
87
|
+
desc 'Display recent deployment history for a set of nodes.'
|
88
|
+
long_desc 'The FILTER can be the name of a node, service, or tag.'
|
89
|
+
arg_name 'FILTER'
|
90
|
+
command [:history, :h] do |c|
|
91
|
+
c.flag :port, :desc => 'Override the default SSH port.',
|
92
|
+
:arg_name => 'PORT'
|
93
|
+
c.flag :ip, :desc => 'Override the default SSH IP address.',
|
94
|
+
:arg_name => 'IPADDRESS'
|
95
|
+
c.action do |global,options,args|
|
96
|
+
nodes = manager.filter!(args)
|
97
|
+
ssh_connect(nodes, connect_options(options)) do |ssh|
|
98
|
+
ssh.leap.history
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
82
103
|
private
|
83
104
|
|
105
|
+
def forcible_prompt(forced, msg, prompt)
|
106
|
+
say(msg)
|
107
|
+
if forced
|
108
|
+
log :warning, "continuing anyway because of --force"
|
109
|
+
else
|
110
|
+
say "hint: use --force to skip this prompt."
|
111
|
+
quit!("OK. Bye.") unless agree(prompt)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
84
115
|
#
|
85
116
|
# The currently activated provider.json could have loaded some pinning
|
86
117
|
# information for the platform. If this is the case, refuse to deploy
|
@@ -94,7 +125,7 @@ module LeapCli
|
|
94
125
|
# "commit": "e1d6280e0a8c565b7fb1a4ed3969ea6fea31a5e2..HEAD"
|
95
126
|
# }
|
96
127
|
#
|
97
|
-
def check_platform_pinning(environment)
|
128
|
+
def check_platform_pinning(environment, global_options)
|
98
129
|
provider = manager.env(environment).provider
|
99
130
|
return unless provider['platform']
|
100
131
|
|
@@ -112,34 +143,46 @@ module LeapCli
|
|
112
143
|
# check version
|
113
144
|
if provider.platform['version']
|
114
145
|
if !Leap::Platform.version_in_range?(provider.platform.version)
|
115
|
-
|
116
|
-
|
117
|
-
"
|
118
|
-
|
146
|
+
forcible_prompt(
|
147
|
+
global_options[:force],
|
148
|
+
"The platform is pinned to a version range of '#{provider.platform.version}' "+
|
149
|
+
"by the `platform.version` property in #{provider_json}, but the platform "+
|
150
|
+
"(#{Path.platform}) has version #{Leap::Platform.version}.",
|
151
|
+
"Do you really want to deploy from the wrong version? "
|
152
|
+
)
|
119
153
|
end
|
120
154
|
end
|
121
155
|
|
122
156
|
# check branch
|
123
157
|
if provider.platform['branch']
|
124
158
|
if !is_git_directory?(Path.platform)
|
125
|
-
|
126
|
-
|
127
|
-
|
159
|
+
forcible_prompt(
|
160
|
+
global_options[:force],
|
161
|
+
"The platform is pinned to a particular branch by the `platform.branch` property "+
|
162
|
+
"in #{provider_json}, but the platform directory (#{Path.platform}) is not a git repository.",
|
163
|
+
"Do you really want to deploy anyway? "
|
164
|
+
)
|
128
165
|
end
|
129
166
|
unless provider.platform.branch == current_git_branch(Path.platform)
|
130
|
-
|
131
|
-
|
132
|
-
"
|
133
|
-
|
167
|
+
forcible_prompt(
|
168
|
+
global_options[:force],
|
169
|
+
"The platform is pinned to branch '#{provider.platform.branch}' by the `platform.branch` property "+
|
170
|
+
"in #{provider_json}, but the current branch is '#{current_git_branch(Path.platform)}' " +
|
171
|
+
"(for directory '#{Path.platform}')",
|
172
|
+
"Do you really want to deploy from the wrong branch? "
|
173
|
+
)
|
134
174
|
end
|
135
175
|
end
|
136
176
|
|
137
177
|
# check commit
|
138
178
|
if provider.platform['commit']
|
139
179
|
if !is_git_directory?(Path.platform)
|
140
|
-
|
141
|
-
|
142
|
-
|
180
|
+
forcible_prompt(
|
181
|
+
global_options[:force],
|
182
|
+
"The platform is pinned to a particular commit range by the `platform.commit` property "+
|
183
|
+
"in #{provider_json}, but the platform directory (#{Path.platform}) is not a git repository.",
|
184
|
+
"Do you really want to deploy anyway? "
|
185
|
+
)
|
143
186
|
end
|
144
187
|
current_commit = current_git_commit(Path.platform)
|
145
188
|
Dir.chdir(Path.platform) do
|
@@ -150,10 +193,13 @@ module LeapCli
|
|
150
193
|
commit_range = commit_range.split("\n")
|
151
194
|
if !commit_range.include?(current_commit) &&
|
152
195
|
provider.platform.commit.split('..').first != current_commit
|
153
|
-
|
154
|
-
|
155
|
-
"
|
156
|
-
|
196
|
+
forcible_prompt(
|
197
|
+
global_options[:force],
|
198
|
+
"The platform is pinned via the `platform.commit` property in #{provider_json} " +
|
199
|
+
"to a commit in the range #{provider.platform.commit}, but the current HEAD " +
|
200
|
+
"(#{current_commit}) is not in that range.",
|
201
|
+
"Do you really want to deploy from the wrong commit? "
|
202
|
+
)
|
157
203
|
end
|
158
204
|
end
|
159
205
|
end
|
@@ -177,17 +223,11 @@ module LeapCli
|
|
177
223
|
#
|
178
224
|
def sync_support_files(ssh)
|
179
225
|
dest_dir = Leap::Platform.files_dir
|
180
|
-
|
181
|
-
if Path.defined?(:custom_puppet_dir) && file_exists?(:custom_puppet_dir)
|
182
|
-
source_files += [:custom_puppet_dir, :custom_puppet_modules_dir, :custom_puppet_manifests_dir].collect{|path|
|
183
|
-
Path.relative_path(path, Path.provider) + '/' # rsync needs trailing slash
|
184
|
-
}
|
185
|
-
ensure_dir :custom_puppet_modules_dir
|
186
|
-
end
|
226
|
+
custom_files = build_custom_file_list
|
187
227
|
ssh.rsync.update do |server|
|
188
228
|
node = manager.node(server.host)
|
189
229
|
files_to_sync = node.file_paths.collect {|path| Path.relative_path(path, Path.provider) }
|
190
|
-
files_to_sync +=
|
230
|
+
files_to_sync += custom_files
|
191
231
|
if files_to_sync.any?
|
192
232
|
ssh.leap.log(files_to_sync.join(', ') + ' -> ' + node.name + ':' + dest_dir)
|
193
233
|
{
|
@@ -282,5 +322,47 @@ module LeapCli
|
|
282
322
|
tags.join(',')
|
283
323
|
end
|
284
324
|
|
325
|
+
#
|
326
|
+
# a provider might have various customization files that should be sync'ed to the server.
|
327
|
+
# this method builds that list of files to sync.
|
328
|
+
#
|
329
|
+
def build_custom_file_list
|
330
|
+
custom_files = []
|
331
|
+
Leap::Platform.paths.keys.grep(/^custom_/).each do |path|
|
332
|
+
if file_exists?(path)
|
333
|
+
relative_path = Path.relative_path(path, Path.provider)
|
334
|
+
if dir_exists?(path)
|
335
|
+
custom_files << relative_path + '/' # rsync needs trailing slash
|
336
|
+
else
|
337
|
+
custom_files << relative_path
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
return custom_files
|
342
|
+
end
|
343
|
+
|
344
|
+
def deploy_info
|
345
|
+
info = []
|
346
|
+
info << "user: %s" % Etc.getpwuid(Process.euid).name
|
347
|
+
if is_git_directory?(Path.platform) && current_git_branch(Path.platform) != 'master'
|
348
|
+
info << "platform: %s (%s %s)" % [
|
349
|
+
Leap::Platform.version,
|
350
|
+
current_git_branch(Path.platform),
|
351
|
+
current_git_commit(Path.platform)[0..4]
|
352
|
+
]
|
353
|
+
else
|
354
|
+
info << "platform: %s" % Leap::Platform.version
|
355
|
+
end
|
356
|
+
if is_git_directory?(LEAP_CLI_BASE_DIR)
|
357
|
+
info << "leap_cli: %s (%s %s)" % [
|
358
|
+
LeapCli::VERSION,
|
359
|
+
current_git_branch(LEAP_CLI_BASE_DIR),
|
360
|
+
current_git_commit(LEAP_CLI_BASE_DIR)[0..4]
|
361
|
+
]
|
362
|
+
else
|
363
|
+
info << "leap_cli: %s" % LeapCli::VERSION
|
364
|
+
end
|
365
|
+
info.join(', ')
|
366
|
+
end
|
285
367
|
end
|
286
368
|
end
|