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