leap_cli 1.7.4 → 1.8
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 +4 -4
- data/bin/leap +6 -13
- data/lib/leap/platform.rb +2 -0
- data/lib/leap_cli.rb +2 -1
- data/lib/leap_cli/bootstrap.rb +197 -0
- data/lib/leap_cli/commands/common.rb +61 -0
- data/lib/leap_cli/commands/new.rb +5 -1
- data/lib/leap_cli/commands/pre.rb +1 -66
- data/lib/leap_cli/config/environment.rb +180 -0
- data/lib/leap_cli/config/manager.rb +100 -197
- data/lib/leap_cli/config/node.rb +2 -2
- data/lib/leap_cli/config/object.rb +56 -43
- data/lib/leap_cli/config/object_list.rb +6 -3
- data/lib/leap_cli/config/provider.rb +11 -0
- data/lib/leap_cli/config/secrets.rb +14 -1
- data/lib/leap_cli/config/tag.rb +2 -2
- data/lib/leap_cli/leapfile.rb +1 -0
- data/lib/leap_cli/log.rb +1 -0
- data/lib/leap_cli/logger.rb +16 -12
- data/lib/leap_cli/markdown_document_listener.rb +3 -1
- data/lib/leap_cli/path.rb +12 -0
- data/lib/leap_cli/remote/leap_plugin.rb +9 -34
- data/lib/leap_cli/remote/puppet_plugin.rb +0 -40
- data/lib/leap_cli/remote/tasks.rb +9 -34
- data/lib/leap_cli/ssh_key.rb +5 -2
- data/lib/leap_cli/version.rb +2 -2
- metadata +5 -18
- data/lib/leap_cli/commands/ca.rb +0 -518
- data/lib/leap_cli/commands/clean.rb +0 -16
- data/lib/leap_cli/commands/compile.rb +0 -340
- data/lib/leap_cli/commands/db.rb +0 -65
- data/lib/leap_cli/commands/deploy.rb +0 -368
- data/lib/leap_cli/commands/env.rb +0 -76
- data/lib/leap_cli/commands/facts.rb +0 -100
- data/lib/leap_cli/commands/inspect.rb +0 -144
- data/lib/leap_cli/commands/list.rb +0 -132
- data/lib/leap_cli/commands/node.rb +0 -165
- data/lib/leap_cli/commands/node_init.rb +0 -169
- data/lib/leap_cli/commands/ssh.rb +0 -220
- data/lib/leap_cli/commands/test.rb +0 -74
- data/lib/leap_cli/commands/user.rb +0 -136
- data/lib/leap_cli/commands/util.rb +0 -50
- data/lib/leap_cli/commands/vagrant.rb +0 -197
@@ -1,76 +0,0 @@
|
|
1
|
-
module LeapCli
|
2
|
-
module Commands
|
3
|
-
|
4
|
-
desc "Manipulate and query environment information."
|
5
|
-
long_desc "The 'environment' node property can be used to isolate sets of nodes into entirely separate environments. "+
|
6
|
-
"A node in one environment will never interact with a node from another environment. "+
|
7
|
-
"Environment pinning works by modifying your ~/.leaprc file and is dependent on the "+
|
8
|
-
"absolute file path of your provider directory (pins don't apply if you move the directory)"
|
9
|
-
command [:env, :e] do |c|
|
10
|
-
c.desc "List the available environments. The pinned environment, if any, will be marked with '*'. Will also set the pin if run with an environment argument."
|
11
|
-
c.arg_name 'ENVIRONMENT', :optional => true
|
12
|
-
c.command :ls do |ls|
|
13
|
-
ls.action do |global_options, options, args|
|
14
|
-
environment = get_env_from_args(args)
|
15
|
-
if environment
|
16
|
-
pin(environment)
|
17
|
-
LeapCli.leapfile.load
|
18
|
-
end
|
19
|
-
print_envs
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
c.desc 'Pin the environment to ENVIRONMENT. All subsequent commands will only apply to nodes in this environment.'
|
24
|
-
c.arg_name 'ENVIRONMENT'
|
25
|
-
c.command :pin do |pin|
|
26
|
-
pin.action do |global_options,options,args|
|
27
|
-
environment = get_env_from_args(args)
|
28
|
-
if environment
|
29
|
-
pin(environment)
|
30
|
-
else
|
31
|
-
bail! "There is no environment `#{environment}`"
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
c.desc "Unpin the environment. All subsequent commands will apply to all nodes."
|
37
|
-
c.command :unpin do |unpin|
|
38
|
-
unpin.action do |global_options, options, args|
|
39
|
-
LeapCli.leapfile.unset('environment')
|
40
|
-
log 0, :saved, "~/.leaprc, removing environment property."
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
c.default_command :ls
|
45
|
-
end
|
46
|
-
|
47
|
-
protected
|
48
|
-
|
49
|
-
def get_env_from_args(args)
|
50
|
-
environment = args.first
|
51
|
-
if environment == 'default' || (environment && manager.environment_names.include?(environment))
|
52
|
-
return environment
|
53
|
-
else
|
54
|
-
return nil
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def pin(environment)
|
59
|
-
LeapCli.leapfile.set('environment', environment)
|
60
|
-
log 0, :saved, "~/.leaprc with environment set to #{environment}."
|
61
|
-
end
|
62
|
-
|
63
|
-
def print_envs
|
64
|
-
envs = ["default"] + manager.environment_names.compact.sort
|
65
|
-
envs.each do |env|
|
66
|
-
if env
|
67
|
-
if LeapCli.leapfile.environment == env
|
68
|
-
puts "* #{env}"
|
69
|
-
else
|
70
|
-
puts " #{env}"
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
@@ -1,100 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Gather facter facts
|
3
|
-
#
|
4
|
-
|
5
|
-
module LeapCli; module Commands
|
6
|
-
|
7
|
-
desc 'Gather information on nodes.'
|
8
|
-
command :facts do |facts|
|
9
|
-
facts.desc 'Query servers to update facts.json.'
|
10
|
-
facts.long_desc "Queries every node included in FILTER and saves the important information to facts.json"
|
11
|
-
facts.arg_name 'FILTER'
|
12
|
-
facts.command :update do |update|
|
13
|
-
update.action do |global_options,options,args|
|
14
|
-
update_facts(global_options, options, args)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
protected
|
20
|
-
|
21
|
-
def facter_cmd
|
22
|
-
'facter --json ' + Leap::Platform.facts.join(' ')
|
23
|
-
end
|
24
|
-
|
25
|
-
def remove_node_facts(name)
|
26
|
-
if file_exists?(:facts)
|
27
|
-
update_facts_file({name => nil})
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def update_node_facts(name, facts)
|
32
|
-
update_facts_file({name => facts})
|
33
|
-
end
|
34
|
-
|
35
|
-
def rename_node_facts(old_name, new_name)
|
36
|
-
if file_exists?(:facts)
|
37
|
-
facts = JSON.parse(read_file(:facts) || {})
|
38
|
-
facts[new_name] = facts[old_name]
|
39
|
-
facts[old_name] = nil
|
40
|
-
update_facts_file(facts, true)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
#
|
45
|
-
# if overwrite = true, then ignore existing facts.json.
|
46
|
-
#
|
47
|
-
def update_facts_file(new_facts, overwrite=false)
|
48
|
-
replace_file!(:facts) do |content|
|
49
|
-
if overwrite || content.nil? || content.empty?
|
50
|
-
old_facts = {}
|
51
|
-
else
|
52
|
-
old_facts = manager.facts
|
53
|
-
end
|
54
|
-
facts = old_facts.merge(new_facts)
|
55
|
-
facts.each do |name, value|
|
56
|
-
if value.is_a? String
|
57
|
-
if value == ""
|
58
|
-
value = nil
|
59
|
-
else
|
60
|
-
value = JSON.parse(value) rescue JSON::ParserError
|
61
|
-
end
|
62
|
-
end
|
63
|
-
if value.is_a? Hash
|
64
|
-
value.delete_if {|key,v| v.nil?}
|
65
|
-
end
|
66
|
-
facts[name] = value
|
67
|
-
end
|
68
|
-
facts.delete_if do |name, value|
|
69
|
-
value.nil? || value.empty?
|
70
|
-
end
|
71
|
-
if facts.empty?
|
72
|
-
"{}\n"
|
73
|
-
else
|
74
|
-
JSON.sorted_generate(facts) + "\n"
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
private
|
80
|
-
|
81
|
-
def update_facts(global_options, options, args)
|
82
|
-
nodes = manager.filter(args, :local => false, :disabled => false)
|
83
|
-
new_facts = {}
|
84
|
-
ssh_connect(nodes) do |ssh|
|
85
|
-
ssh.leap.run_with_progress(facter_cmd) do |response|
|
86
|
-
node = manager.node(response[:host])
|
87
|
-
if node
|
88
|
-
new_facts[node.name] = response[:data].strip
|
89
|
-
else
|
90
|
-
log :warning, 'Could not find node for hostname %s' % response[:host]
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
# only overwrite the entire facts file if and only if we are gathering facts
|
95
|
-
# for all nodes in all environments.
|
96
|
-
overwrite_existing = args.empty? && LeapCli.leapfile.environment.nil?
|
97
|
-
update_facts_file(new_facts, overwrite_existing)
|
98
|
-
end
|
99
|
-
|
100
|
-
end; end
|
@@ -1,144 +0,0 @@
|
|
1
|
-
module LeapCli; module Commands
|
2
|
-
|
3
|
-
desc 'Prints details about a file. Alternately, the argument FILE can be the name of a node, service or tag.'
|
4
|
-
arg_name 'FILE'
|
5
|
-
command [:inspect, :i] do |c|
|
6
|
-
c.switch 'base', :desc => 'Inspect the FILE from the provider_base (i.e. without local inheritance).', :negatable => false
|
7
|
-
c.action do |global_options,options,args|
|
8
|
-
object = args.first
|
9
|
-
assert! object, 'A file path or node/service/tag name is required'
|
10
|
-
method = inspection_method(object)
|
11
|
-
if method && defined?(method)
|
12
|
-
self.send(method, object, options)
|
13
|
-
else
|
14
|
-
log "Sorry, I don't know how to inspect that."
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
FTYPE_MAP = {
|
22
|
-
"PEM certificate" => :inspect_x509_cert,
|
23
|
-
"PEM RSA private key" => :inspect_x509_key,
|
24
|
-
"OpenSSH RSA public key" => :inspect_ssh_pub_key,
|
25
|
-
"PEM certificate request" => :inspect_x509_csr
|
26
|
-
}
|
27
|
-
|
28
|
-
def inspection_method(object)
|
29
|
-
if File.exists?(object)
|
30
|
-
ftype = `file #{object}`.split(':').last.strip
|
31
|
-
log 2, "file is of type '#{ftype}'"
|
32
|
-
if FTYPE_MAP[ftype]
|
33
|
-
FTYPE_MAP[ftype]
|
34
|
-
elsif File.extname(object) == ".json"
|
35
|
-
full_path = File.expand_path(object, Dir.pwd)
|
36
|
-
if path_match?(:node_config, full_path)
|
37
|
-
:inspect_node
|
38
|
-
elsif path_match?(:service_config, full_path)
|
39
|
-
:inspect_service
|
40
|
-
elsif path_match?(:tag_config, full_path)
|
41
|
-
:inspect_tag
|
42
|
-
elsif path_match?(:provider_config, full_path) || path_match?(:provider_env_config, full_path)
|
43
|
-
:inspect_provider
|
44
|
-
elsif path_match?(:common_config, full_path)
|
45
|
-
:inspect_common
|
46
|
-
else
|
47
|
-
nil
|
48
|
-
end
|
49
|
-
end
|
50
|
-
elsif manager.nodes[object]
|
51
|
-
:inspect_node
|
52
|
-
elsif manager.services[object]
|
53
|
-
:inspect_service
|
54
|
-
elsif manager.tags[object]
|
55
|
-
:inspect_tag
|
56
|
-
elsif object == "common"
|
57
|
-
:inspect_common
|
58
|
-
elsif object == "provider"
|
59
|
-
:inspect_provider
|
60
|
-
else
|
61
|
-
nil
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
#
|
66
|
-
# inspectors
|
67
|
-
#
|
68
|
-
|
69
|
-
def inspect_x509_key(file_path, options)
|
70
|
-
assert_bin! 'openssl'
|
71
|
-
puts assert_run! 'openssl rsa -in %s -text -check' % file_path
|
72
|
-
end
|
73
|
-
|
74
|
-
def inspect_x509_cert(file_path, options)
|
75
|
-
assert_bin! 'openssl'
|
76
|
-
puts assert_run! 'openssl x509 -in %s -text -noout' % file_path
|
77
|
-
log 0, :"SHA256 fingerprint", X509.fingerprint("SHA256", file_path)
|
78
|
-
end
|
79
|
-
|
80
|
-
def inspect_x509_csr(file_path, options)
|
81
|
-
assert_bin! 'openssl'
|
82
|
-
puts assert_run! 'openssl req -text -noout -verify -in %s' % file_path
|
83
|
-
end
|
84
|
-
|
85
|
-
#def inspect_ssh_pub_key(file_path)
|
86
|
-
#end
|
87
|
-
|
88
|
-
def inspect_node(arg, options)
|
89
|
-
inspect_json manager.nodes[name(arg)]
|
90
|
-
end
|
91
|
-
|
92
|
-
def inspect_service(arg, options)
|
93
|
-
if options[:base]
|
94
|
-
inspect_json manager.base_services[name(arg)]
|
95
|
-
else
|
96
|
-
inspect_json manager.services[name(arg)]
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def inspect_tag(arg, options)
|
101
|
-
if options[:base]
|
102
|
-
inspect_json manager.base_tags[name(arg)]
|
103
|
-
else
|
104
|
-
inspect_json manager.tags[name(arg)]
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def inspect_provider(arg, options)
|
109
|
-
if options[:base]
|
110
|
-
inspect_json manager.base_provider
|
111
|
-
elsif arg =~ /provider\.(.*)\.json/
|
112
|
-
inspect_json manager.env($1).provider
|
113
|
-
else
|
114
|
-
inspect_json manager.provider
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def inspect_common(arg, options)
|
119
|
-
if options[:base]
|
120
|
-
inspect_json manager.base_common
|
121
|
-
else
|
122
|
-
inspect_json manager.common
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
#
|
127
|
-
# helpers
|
128
|
-
#
|
129
|
-
|
130
|
-
def name(arg)
|
131
|
-
File.basename(arg).sub(/\.json$/, '')
|
132
|
-
end
|
133
|
-
|
134
|
-
def inspect_json(config)
|
135
|
-
if config
|
136
|
-
puts JSON.sorted_generate(config)
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
def path_match?(path_symbol, path)
|
141
|
-
Dir.glob(Path.named_path([path_symbol, '*'])).include?(path)
|
142
|
-
end
|
143
|
-
|
144
|
-
end; end
|
@@ -1,132 +0,0 @@
|
|
1
|
-
require 'command_line_reporter'
|
2
|
-
|
3
|
-
module LeapCli; module Commands
|
4
|
-
|
5
|
-
desc 'List nodes and their classifications'
|
6
|
-
long_desc 'Prints out a listing of nodes, services, or tags. ' +
|
7
|
-
'If present, the FILTER can be a list of names of nodes, services, or tags. ' +
|
8
|
-
'If the name is prefixed with +, this acts like an AND condition. ' +
|
9
|
-
"For example:\n\n" +
|
10
|
-
"`leap list node1 node2` matches all nodes named \"node1\" OR \"node2\"\n\n" +
|
11
|
-
"`leap list openvpn +local` matches all nodes with service \"openvpn\" AND tag \"local\""
|
12
|
-
|
13
|
-
arg_name 'FILTER', :optional => true
|
14
|
-
command [:list,:ls] do |c|
|
15
|
-
c.flag 'print', :desc => 'What attributes to print (optional)'
|
16
|
-
c.switch 'disabled', :desc => 'Include disabled nodes in the list.', :negatable => false
|
17
|
-
c.action do |global_options,options,args|
|
18
|
-
# don't rely on default manager(), because we want to pass custom options to load()
|
19
|
-
manager = LeapCli::Config::Manager.new
|
20
|
-
if global_options[:color]
|
21
|
-
colors = ['cyan', 'white']
|
22
|
-
else
|
23
|
-
colors = [nil, nil]
|
24
|
-
end
|
25
|
-
puts
|
26
|
-
manager.load(:include_disabled => options['disabled'], :continue_on_error => true)
|
27
|
-
if options['print']
|
28
|
-
print_node_properties(manager.filter(args), options['print'])
|
29
|
-
else
|
30
|
-
if args.any?
|
31
|
-
NodeTable.new(manager.filter(args), colors).run
|
32
|
-
else
|
33
|
-
environment = LeapCli.leapfile.environment || '_all_'
|
34
|
-
TagTable.new('SERVICES', manager.env(environment).services, colors).run
|
35
|
-
TagTable.new('TAGS', manager.env(environment).tags, colors).run
|
36
|
-
NodeTable.new(manager.filter(), colors).run
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def self.print_node_properties(nodes, properties)
|
45
|
-
properties = properties.split(',')
|
46
|
-
max_width = nodes.keys.inject(0) {|max,i| [i.size,max].max}
|
47
|
-
nodes.each_node do |node|
|
48
|
-
value = properties.collect{|prop|
|
49
|
-
prop_value = node[prop]
|
50
|
-
if prop_value.nil?
|
51
|
-
"null"
|
52
|
-
elsif prop_value == ""
|
53
|
-
"empty"
|
54
|
-
elsif prop_value.is_a? LeapCli::Config::Object
|
55
|
-
node[prop].dump_json(:compact) # TODO: add option of getting pre-evaluation values.
|
56
|
-
else
|
57
|
-
prop_value.to_s
|
58
|
-
end
|
59
|
-
}.join(', ')
|
60
|
-
printf("%#{max_width}s %s\n", node.name, value)
|
61
|
-
end
|
62
|
-
puts
|
63
|
-
end
|
64
|
-
|
65
|
-
class TagTable
|
66
|
-
include CommandLineReporter
|
67
|
-
def initialize(heading, tag_list, colors)
|
68
|
-
@heading = heading
|
69
|
-
@tag_list = tag_list
|
70
|
-
@colors = colors
|
71
|
-
end
|
72
|
-
def run
|
73
|
-
tags = @tag_list.keys.select{|tag| tag !~ /^_/}.sort # sorted list of tags, excluding _partials
|
74
|
-
max_width = [20, (tags+[@heading]).inject(0) {|max,i| [i.size,max].max}].max
|
75
|
-
table :border => false do
|
76
|
-
row :color => @colors[0] do
|
77
|
-
column @heading, :align => 'right', :width => max_width
|
78
|
-
column "NODES", :width => HighLine::SystemExtensions.terminal_size.first - max_width - 2, :padding => 2
|
79
|
-
end
|
80
|
-
tags.each do |tag|
|
81
|
-
next if @tag_list[tag].node_list.empty?
|
82
|
-
row :color => @colors[1] do
|
83
|
-
column tag
|
84
|
-
column @tag_list[tag].node_list.keys.sort.join(', ')
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
vertical_spacing
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
#
|
93
|
-
# might be handy: HighLine::SystemExtensions.terminal_size.first
|
94
|
-
#
|
95
|
-
class NodeTable
|
96
|
-
include CommandLineReporter
|
97
|
-
def initialize(node_list, colors)
|
98
|
-
@node_list = node_list
|
99
|
-
@colors = colors
|
100
|
-
end
|
101
|
-
def run
|
102
|
-
rows = @node_list.keys.sort.collect do |node_name|
|
103
|
-
[node_name, @node_list[node_name].services.sort.join(', '), @node_list[node_name].tags.sort.join(', ')]
|
104
|
-
end
|
105
|
-
unless rows.any?
|
106
|
-
puts Paint["no results", :red]
|
107
|
-
puts
|
108
|
-
return
|
109
|
-
end
|
110
|
-
padding = 2
|
111
|
-
max_node_width = [20, (rows.map{|i|i[0]} + ["NODES"] ).inject(0) {|max,i| [i.size,max].max}].max
|
112
|
-
max_service_width = (rows.map{|i|i[1]} + ["SERVICES"]).inject(0) {|max,i| [i.size+padding+padding,max].max}
|
113
|
-
max_tag_width = (rows.map{|i|i[2]} + ["TAGS"] ).inject(0) {|max,i| [i.size,max].max}
|
114
|
-
table :border => false do
|
115
|
-
row :color => @colors[0] do
|
116
|
-
column "NODES", :align => 'right', :width => max_node_width
|
117
|
-
column "SERVICES", :width => max_service_width, :padding => 2
|
118
|
-
column "TAGS", :width => max_tag_width
|
119
|
-
end
|
120
|
-
rows.each do |r|
|
121
|
-
row :color => @colors[1] do
|
122
|
-
column r[0]
|
123
|
-
column r[1]
|
124
|
-
column r[2]
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
vertical_spacing
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
end; end
|