leap_cli 1.2.5

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