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