leap_cli 1.2.5

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.
Files changed (72) hide show
  1. data/bin/leap +81 -0
  2. data/lib/core_ext/boolean.rb +14 -0
  3. data/lib/core_ext/hash.rb +35 -0
  4. data/lib/core_ext/json.rb +42 -0
  5. data/lib/core_ext/nil.rb +5 -0
  6. data/lib/core_ext/string.rb +14 -0
  7. data/lib/leap/platform.rb +52 -0
  8. data/lib/leap_cli/commands/ca.rb +430 -0
  9. data/lib/leap_cli/commands/clean.rb +16 -0
  10. data/lib/leap_cli/commands/compile.rb +134 -0
  11. data/lib/leap_cli/commands/deploy.rb +172 -0
  12. data/lib/leap_cli/commands/facts.rb +93 -0
  13. data/lib/leap_cli/commands/inspect.rb +140 -0
  14. data/lib/leap_cli/commands/list.rb +122 -0
  15. data/lib/leap_cli/commands/new.rb +126 -0
  16. data/lib/leap_cli/commands/node.rb +272 -0
  17. data/lib/leap_cli/commands/pre.rb +99 -0
  18. data/lib/leap_cli/commands/shell.rb +67 -0
  19. data/lib/leap_cli/commands/test.rb +55 -0
  20. data/lib/leap_cli/commands/user.rb +140 -0
  21. data/lib/leap_cli/commands/util.rb +50 -0
  22. data/lib/leap_cli/commands/vagrant.rb +201 -0
  23. data/lib/leap_cli/config/macros.rb +369 -0
  24. data/lib/leap_cli/config/manager.rb +369 -0
  25. data/lib/leap_cli/config/node.rb +37 -0
  26. data/lib/leap_cli/config/object.rb +336 -0
  27. data/lib/leap_cli/config/object_list.rb +174 -0
  28. data/lib/leap_cli/config/secrets.rb +43 -0
  29. data/lib/leap_cli/config/tag.rb +18 -0
  30. data/lib/leap_cli/constants.rb +7 -0
  31. data/lib/leap_cli/leapfile.rb +97 -0
  32. data/lib/leap_cli/load_paths.rb +15 -0
  33. data/lib/leap_cli/log.rb +166 -0
  34. data/lib/leap_cli/logger.rb +216 -0
  35. data/lib/leap_cli/markdown_document_listener.rb +134 -0
  36. data/lib/leap_cli/path.rb +84 -0
  37. data/lib/leap_cli/remote/leap_plugin.rb +204 -0
  38. data/lib/leap_cli/remote/puppet_plugin.rb +66 -0
  39. data/lib/leap_cli/remote/rsync_plugin.rb +35 -0
  40. data/lib/leap_cli/remote/tasks.rb +36 -0
  41. data/lib/leap_cli/requirements.rb +19 -0
  42. data/lib/leap_cli/ssh_key.rb +130 -0
  43. data/lib/leap_cli/util/remote_command.rb +110 -0
  44. data/lib/leap_cli/util/secret.rb +54 -0
  45. data/lib/leap_cli/util/x509.rb +32 -0
  46. data/lib/leap_cli/util.rb +431 -0
  47. data/lib/leap_cli/version.rb +9 -0
  48. data/lib/leap_cli.rb +46 -0
  49. data/lib/lib_ext/capistrano_connections.rb +16 -0
  50. data/lib/lib_ext/gli.rb +52 -0
  51. data/lib/lib_ext/markdown_document_listener.rb +122 -0
  52. data/vendor/certificate_authority/lib/certificate_authority/certificate.rb +200 -0
  53. data/vendor/certificate_authority/lib/certificate_authority/certificate_revocation_list.rb +77 -0
  54. data/vendor/certificate_authority/lib/certificate_authority/distinguished_name.rb +97 -0
  55. data/vendor/certificate_authority/lib/certificate_authority/extensions.rb +266 -0
  56. data/vendor/certificate_authority/lib/certificate_authority/key_material.rb +148 -0
  57. data/vendor/certificate_authority/lib/certificate_authority/ocsp_handler.rb +144 -0
  58. data/vendor/certificate_authority/lib/certificate_authority/pkcs11_key_material.rb +65 -0
  59. data/vendor/certificate_authority/lib/certificate_authority/revocable.rb +14 -0
  60. data/vendor/certificate_authority/lib/certificate_authority/serial_number.rb +10 -0
  61. data/vendor/certificate_authority/lib/certificate_authority/signing_entity.rb +16 -0
  62. data/vendor/certificate_authority/lib/certificate_authority/signing_request.rb +56 -0
  63. data/vendor/certificate_authority/lib/certificate_authority.rb +21 -0
  64. data/vendor/rsync_command/lib/rsync_command/ssh_options.rb +159 -0
  65. data/vendor/rsync_command/lib/rsync_command/thread_pool.rb +36 -0
  66. data/vendor/rsync_command/lib/rsync_command/version.rb +3 -0
  67. data/vendor/rsync_command/lib/rsync_command.rb +96 -0
  68. data/vendor/rsync_command/test/rsync_test.rb +74 -0
  69. data/vendor/rsync_command/test/ssh_options_test.rb +61 -0
  70. data/vendor/vagrant_ssh_keys/vagrant.key +27 -0
  71. data/vendor/vagrant_ssh_keys/vagrant.pub +1 -0
  72. metadata +345 -0
@@ -0,0 +1,140 @@
1
+ require 'gpgme'
2
+
3
+ #
4
+ # perhaps we want to verify that the key files are actually the key files we expect.
5
+ # we could use 'file' for this:
6
+ #
7
+ # > file ~/.gnupg/00440025.asc
8
+ # ~/.gnupg/00440025.asc: PGP public key block
9
+ #
10
+ # > file ~/.ssh/id_rsa.pub
11
+ # ~/.ssh/id_rsa.pub: OpenSSH RSA public key
12
+ #
13
+
14
+ module LeapCli
15
+ module Commands
16
+
17
+ desc 'Adds a new trusted sysadmin by adding public keys to the "users" directory.'
18
+ arg_name 'USERNAME' #, :optional => false, :multiple => false
19
+ command :'add-user' do |c|
20
+
21
+ c.switch 'self', :desc => 'Add yourself as a trusted sysadin by choosing among the public keys available for the current user.', :negatable => false
22
+ c.flag 'ssh-pub-key', :desc => 'SSH public key file for this new user'
23
+ c.flag 'pgp-pub-key', :desc => 'OpenPGP public key file for this new user'
24
+
25
+ c.action do |global_options,options,args|
26
+ username = args.first
27
+ if !username.any? && !options[:self]
28
+ help! "Either 'username' or --self is required."
29
+ end
30
+
31
+ ssh_pub_key = nil
32
+ pgp_pub_key = nil
33
+
34
+ if options['ssh-pub-key']
35
+ ssh_pub_key = read_file!(options['ssh-pub-key'])
36
+ end
37
+ if options['pgp-pub-key']
38
+ pgp_pub_key = read_file!(options['pgp-pub-key'])
39
+ end
40
+
41
+ if options[:self]
42
+ username ||= `whoami`.strip
43
+ ssh_pub_key ||= pick_ssh_key.to_s
44
+ pgp_pub_key ||= pick_pgp_key
45
+ end
46
+
47
+ assert!(ssh_pub_key, 'Sorry, could not find SSH public key.')
48
+
49
+ if ssh_pub_key
50
+ write_file!([:user_ssh, username], ssh_pub_key)
51
+ end
52
+ if pgp_pub_key
53
+ write_file!([:user_pgp, username], pgp_pub_key)
54
+ end
55
+
56
+ update_authorized_keys
57
+ end
58
+ end
59
+
60
+ #
61
+ # let the the user choose among the ssh public keys that we encounter, or just pick the key if there is only one.
62
+ #
63
+ def pick_ssh_key
64
+ ssh_keys = []
65
+ Dir.glob("#{ENV['HOME']}/.ssh/*.pub").each do |keyfile|
66
+ ssh_keys << SshKey.load(keyfile)
67
+ end
68
+
69
+ if `which ssh-add`.strip.any?
70
+ `ssh-add -L 2> /dev/null`.split("\n").compact.each do |line|
71
+ key = SshKey.load(line)
72
+ key.comment = 'ssh-agent'
73
+ ssh_keys << key unless ssh_keys.include?(key)
74
+ end
75
+ end
76
+ ssh_keys.compact!
77
+
78
+ assert! ssh_keys.any?, 'Sorry, could not find any SSH public key for you. Have you run ssh-keygen?'
79
+
80
+ if ssh_keys.length > 1
81
+ key_index = numbered_choice_menu('Choose your SSH public key', ssh_keys.collect(&:summary)) do |line, i|
82
+ say("#{i+1}. #{line}")
83
+ end
84
+ else
85
+ key_index = 0
86
+ end
87
+
88
+ return ssh_keys[key_index]
89
+ end
90
+
91
+ #
92
+ # let the the user choose among the gpg public keys that we encounter, or just pick the key if there is only one.
93
+ #
94
+ def pick_pgp_key
95
+ secret_keys = GPGME::Key.find(:secret)
96
+ if secret_keys.empty?
97
+ log "Skipping OpenPGP setup because I could not find any OpenPGP keys for you"
98
+ return nil
99
+ end
100
+
101
+ assert_bin! 'gpg'
102
+
103
+ if secret_keys.length > 1
104
+ key_index = numbered_choice_menu('Choose your OpenPGP public key', secret_keys) do |key, i|
105
+ key_info = key.to_s.split("\n")[0..1].map{|line| line.sub(/^\s*(sec|uid)\s*/,'')}.join(' -- ')
106
+ say("#{i+1}. #{key_info}")
107
+ end
108
+ else
109
+ key_index = 0
110
+ end
111
+
112
+ key_id = secret_keys[key_index].sha
113
+
114
+ # can't use this, it includes signatures:
115
+ #puts GPGME::Key.export(key_id, :armor => true, :export_options => :export_minimal)
116
+
117
+ # export with signatures removed:
118
+ return `gpg --armor --export-options export-minimal --export #{key_id}`.strip
119
+ end
120
+
121
+ def update_authorized_keys
122
+ buffer = StringIO.new
123
+ keys = Dir.glob(path([:user_ssh, '*']))
124
+ if keys.empty?
125
+ bail! "You must have at least one public SSH user key configured in order to proceed. See `leap help add-user`."
126
+ end
127
+ keys.sort.each do |keyfile|
128
+ ssh_type, ssh_key = File.read(keyfile).strip.split(" ")
129
+ buffer << ssh_type
130
+ buffer << " "
131
+ buffer << ssh_key
132
+ buffer << " "
133
+ buffer << Path.relative_path(keyfile)
134
+ buffer << "\n"
135
+ end
136
+ write_file!(:authorized_keys, buffer.string)
137
+ end
138
+
139
+ end
140
+ end
@@ -0,0 +1,50 @@
1
+ module LeapCli; module Commands
2
+
3
+ extend self
4
+ extend LeapCli::Util
5
+ extend LeapCli::Util::RemoteCommand
6
+
7
+ def path(name)
8
+ Path.named_path(name)
9
+ end
10
+
11
+ #
12
+ # keeps prompting the user for a numbered choice, until they pick a good one or bail out.
13
+ #
14
+ # block is yielded and is responsible for rendering the choices.
15
+ #
16
+ def numbered_choice_menu(msg, items, &block)
17
+ while true
18
+ say("\n" + msg + ':')
19
+ items.each_with_index &block
20
+ say("q. quit")
21
+ index = ask("number 1-#{items.length}> ")
22
+ if index.empty?
23
+ next
24
+ elsif index =~ /q/
25
+ bail!
26
+ else
27
+ i = index.to_i - 1
28
+ if i < 0 || i >= items.length
29
+ bail!
30
+ else
31
+ return i
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+
38
+ def parse_node_list(nodes)
39
+ if nodes.is_a? Config::Object
40
+ Config::ObjectList.new(nodes)
41
+ elsif nodes.is_a? Config::ObjectList
42
+ nodes
43
+ elsif nodes.is_a? String
44
+ manager.filter!(nodes)
45
+ else
46
+ bail! "argument error"
47
+ end
48
+ end
49
+
50
+ end; end
@@ -0,0 +1,201 @@
1
+ require 'ipaddr'
2
+ require 'fileutils'
3
+
4
+ module LeapCli; module Commands
5
+
6
+ desc "Manage local virtual machines."
7
+ long_desc "This command provides a convient way to manage Vagrant-based virtual machines. If FILTER argument is missing, the command runs on all local virtual machines. The Vagrantfile is automatically generated in 'test/Vagrantfile'. If you want to run vagrant commands manually, cd to 'test'."
8
+ command :local do |local|
9
+ local.desc 'Starts up the virtual machine(s)'
10
+ local.arg_name 'FILTER', :optional => true #, :multiple => false
11
+ local.command :start do |start|
12
+ start.action do |global_options,options,args|
13
+ vagrant_command(["up", "sandbox on"], args)
14
+ end
15
+ end
16
+
17
+ local.desc 'Shuts down the virtual machine(s)'
18
+ local.arg_name 'FILTER', :optional => true #, :multiple => false
19
+ local.command :stop do |stop|
20
+ stop.action do |global_options,options,args|
21
+ if global_options[:yes]
22
+ vagrant_command("halt --force", args)
23
+ else
24
+ vagrant_command("halt", args)
25
+ end
26
+ end
27
+ end
28
+
29
+ local.desc 'Destroys the virtual machine(s), reclaiming the disk space'
30
+ local.arg_name 'FILTER', :optional => true #, :multiple => false
31
+ local.command :destroy do |destroy|
32
+ destroy.action do |global_options,options,args|
33
+ if global_options[:yes]
34
+ vagrant_command("destroy --force", args)
35
+ else
36
+ vagrant_command("destroy", args)
37
+ end
38
+ end
39
+ end
40
+
41
+ local.desc 'Print the status of local virtual machine(s)'
42
+ local.arg_name 'FILTER', :optional => true #, :multiple => false
43
+ local.command :status do |status|
44
+ status.action do |global_options,options,args|
45
+ vagrant_command("status", args)
46
+ end
47
+ end
48
+
49
+ local.desc 'Saves the current state of the virtual machine as a new snapshot'
50
+ local.arg_name 'FILTER', :optional => true #, :multiple => false
51
+ local.command :save do |status|
52
+ status.action do |global_options,options,args|
53
+ vagrant_command("sandbox commit", args)
54
+ end
55
+ end
56
+
57
+ local.desc 'Resets virtual machine(s) to the last saved snapshot'
58
+ local.arg_name 'FILTER', :optional => true #, :multiple => false
59
+ local.command :reset do |reset|
60
+ reset.action do |global_options,options,args|
61
+ vagrant_command("sandbox rollback", args)
62
+ end
63
+ end
64
+ end
65
+
66
+ public
67
+
68
+ #
69
+ # returns the path to a vagrant ssh key file.
70
+ #
71
+ # if the vagrant.key file is owned by root or ourselves, then
72
+ # we need to make sure that it owned by us and not world readable.
73
+ #
74
+ def vagrant_ssh_key_file
75
+ file_path = File.expand_path('../../../vendor/vagrant_ssh_keys/vagrant.key', File.dirname(__FILE__))
76
+ Util.assert_files_exist! file_path
77
+ uid = File.new(file_path).stat.uid
78
+ if uid == 0 || uid == Process.euid
79
+ FileUtils.install file_path, '/tmp/vagrant.key', :mode => 0600
80
+ file_path = '/tmp/vagrant.key'
81
+ end
82
+ return file_path
83
+ end
84
+
85
+ protected
86
+
87
+ def vagrant_command(cmds, args)
88
+ vagrant_setup
89
+ cmds = cmds.to_a
90
+ if args.empty?
91
+ nodes = [""]
92
+ else
93
+ nodes = manager.filter(args)[:environment => "local"].field(:name)
94
+ end
95
+ if nodes.any?
96
+ vagrant_dir = File.dirname(Path.named_path(:vagrantfile))
97
+ exec = ["cd #{vagrant_dir}"]
98
+ cmds.each do |cmd|
99
+ nodes.each do |node|
100
+ exec << "vagrant #{cmd} #{node}"
101
+ end
102
+ end
103
+ execute exec.join('; ')
104
+ else
105
+ bail! "No nodes found. This command only works on nodes with ip_address in the network #{LeapCli.leapfile.vagrant_network}"
106
+ end
107
+ end
108
+
109
+ private
110
+
111
+ def vagrant_setup
112
+ assert_bin! 'vagrant', 'Vagrant is required for running local virtual machines. Run "sudo apt-get install vagrant".'
113
+
114
+ version = vagrant_version
115
+ case version
116
+ when 0..1
117
+ gem_path = assert_run!('vagrant gem which sahara')
118
+ if gem_path.nil? || gem_path.empty? || gem_path =~ /^ERROR/
119
+ log :installing, "vagrant plugin 'sahara'"
120
+ assert_run! 'vagrant gem install sahara -v 0.0.13'
121
+ # (sahara versions above 0.0.13 require vagrant > 1.0)
122
+ end
123
+ when 2
124
+ unless assert_run!('vagrant plugin list | grep sahara | cat').chars.any?
125
+ log :installing, "vagrant plugin 'sahara'"
126
+ assert_run! 'vagrant plugin install sahara'
127
+ end
128
+ end
129
+ create_vagrant_file
130
+ end
131
+
132
+ def vagrant_version
133
+ minor_version = `vagrant --version | rev | cut -d'.' -f 2`.to_i
134
+ version = case minor_version
135
+ when 1..9 then 2
136
+ when 0 then 1
137
+ else 0
138
+ end
139
+ return version
140
+ end
141
+
142
+ def execute(cmd)
143
+ log 2, :run, cmd
144
+ exec cmd
145
+ end
146
+
147
+ def create_vagrant_file
148
+ lines = []
149
+ netmask = IPAddr.new('255.255.255.255').mask(LeapCli.leapfile.vagrant_network.split('/').last).to_s
150
+
151
+ version = vagrant_version
152
+ case version
153
+ when 0..1
154
+ lines << %[Vagrant::Config.run do |config|]
155
+ manager.each_node do |node|
156
+ if node.vagrant?
157
+ lines << %[ config.vm.define :#{node.name} do |config|]
158
+ lines << %[ config.vm.box = "leap-wheezy"]
159
+ lines << %[ config.vm.box_url = "http://download.leap.se/leap-debian.box"]
160
+ lines << %[ config.vm.network :hostonly, "#{node.ip_address}", :netmask => "#{netmask}"]
161
+ lines << %[ config.vm.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]]
162
+ lines << %[ config.vm.customize ["modifyvm", :id, "--name", "#{node.name}"]]
163
+ lines << %[ #{leapfile.custom_vagrant_vm_line}] if leapfile.custom_vagrant_vm_line
164
+ lines << %[ end]
165
+ end
166
+ end
167
+ when 2
168
+ lines << %[Vagrant.configure("2") do |config|]
169
+ manager.each_node do |node|
170
+ if node.vagrant?
171
+ lines << %[ config.vm.define :#{node.name} do |config|]
172
+ lines << %[ config.vm.box = "leap-wheezy"]
173
+ lines << %[ config.vm.box_url = "http://download.leap.se/leap-debian.box"]
174
+ lines << %[ config.vm.network :private_network, ip: "#{node.ip_address}"]
175
+ lines << %[ config.vm.provider "virtualbox" do |v|]
176
+ lines << %[ v.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]]
177
+ lines << %[ v.name = "#{node.name}"]
178
+ lines << %[ end]
179
+ lines << %[ #{leapfile.custom_vagrant_vm_line}] if leapfile.custom_vagrant_vm_line
180
+ lines << %[ end]
181
+ end
182
+ end
183
+ end
184
+
185
+ lines << %[end]
186
+ lines << ""
187
+ write_file! :vagrantfile, lines.join("\n")
188
+ end
189
+
190
+ def pick_next_vagrant_ip_address
191
+ taken_ips = manager.nodes[:environment => "local"].field(:ip_address)
192
+ if taken_ips.any?
193
+ highest_ip = taken_ips.map{|ip| IPAddr.new(ip)}.max
194
+ new_ip = highest_ip.succ
195
+ else
196
+ new_ip = IPAddr.new(LeapCli.leapfile.vagrant_network).succ.succ
197
+ end
198
+ return new_ip.to_s
199
+ end
200
+
201
+ end; end