fixed-vagrant 0.7.4.dev
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.
- data/.gitignore +15 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +272 -0
- data/Gemfile +21 -0
- data/LICENSE +21 -0
- data/README.md +75 -0
- data/Rakefile +22 -0
- data/bin/vagrant +22 -0
- data/config/default.rb +39 -0
- data/contrib/README.md +12 -0
- data/contrib/emacs/vagrant.el +8 -0
- data/contrib/vim/vagrantfile.vim +9 -0
- data/keys/README.md +17 -0
- data/keys/vagrant +27 -0
- data/keys/vagrant.ppk +26 -0
- data/keys/vagrant.pub +1 -0
- data/lib/vagrant.rb +42 -0
- data/lib/vagrant/action.rb +134 -0
- data/lib/vagrant/action/box.rb +11 -0
- data/lib/vagrant/action/box/destroy.rb +21 -0
- data/lib/vagrant/action/box/download.rb +72 -0
- data/lib/vagrant/action/box/package.rb +19 -0
- data/lib/vagrant/action/box/unpackage.rb +55 -0
- data/lib/vagrant/action/box/verify.rb +23 -0
- data/lib/vagrant/action/builder.rb +124 -0
- data/lib/vagrant/action/builtin.rb +104 -0
- data/lib/vagrant/action/env.rb +7 -0
- data/lib/vagrant/action/env/set.rb +18 -0
- data/lib/vagrant/action/environment.rb +50 -0
- data/lib/vagrant/action/general.rb +8 -0
- data/lib/vagrant/action/general/package.rb +109 -0
- data/lib/vagrant/action/general/validate.rb +19 -0
- data/lib/vagrant/action/vm.rb +31 -0
- data/lib/vagrant/action/vm/boot.rb +48 -0
- data/lib/vagrant/action/vm/check_box.rb +28 -0
- data/lib/vagrant/action/vm/check_guest_additions.rb +30 -0
- data/lib/vagrant/action/vm/clean_machine_folder.rb +43 -0
- data/lib/vagrant/action/vm/clear_forwarded_ports.rb +39 -0
- data/lib/vagrant/action/vm/clear_nfs_exports.rb +20 -0
- data/lib/vagrant/action/vm/clear_shared_folders.rb +32 -0
- data/lib/vagrant/action/vm/customize.rb +21 -0
- data/lib/vagrant/action/vm/destroy.rb +19 -0
- data/lib/vagrant/action/vm/destroy_unused_network_interfaces.rb +30 -0
- data/lib/vagrant/action/vm/discard_state.rb +22 -0
- data/lib/vagrant/action/vm/export.rb +52 -0
- data/lib/vagrant/action/vm/forward_ports.rb +134 -0
- data/lib/vagrant/action/vm/forward_ports_helpers.rb +28 -0
- data/lib/vagrant/action/vm/halt.rb +29 -0
- data/lib/vagrant/action/vm/host_name.rb +21 -0
- data/lib/vagrant/action/vm/import.rb +35 -0
- data/lib/vagrant/action/vm/match_mac_address.rb +21 -0
- data/lib/vagrant/action/vm/network.rb +139 -0
- data/lib/vagrant/action/vm/nfs.rb +159 -0
- data/lib/vagrant/action/vm/nfs_helpers.rb +11 -0
- data/lib/vagrant/action/vm/package.rb +23 -0
- data/lib/vagrant/action/vm/package_vagrantfile.rb +33 -0
- data/lib/vagrant/action/vm/provision.rb +41 -0
- data/lib/vagrant/action/vm/resume.rb +20 -0
- data/lib/vagrant/action/vm/share_folders.rb +70 -0
- data/lib/vagrant/action/vm/suspend.rb +20 -0
- data/lib/vagrant/action/warden.rb +79 -0
- data/lib/vagrant/box.rb +90 -0
- data/lib/vagrant/box_collection.rb +53 -0
- data/lib/vagrant/cli.rb +55 -0
- data/lib/vagrant/command.rb +25 -0
- data/lib/vagrant/command/base.rb +106 -0
- data/lib/vagrant/command/box.rb +33 -0
- data/lib/vagrant/command/destroy.rb +17 -0
- data/lib/vagrant/command/group_base.rb +107 -0
- data/lib/vagrant/command/halt.rb +18 -0
- data/lib/vagrant/command/helpers.rb +33 -0
- data/lib/vagrant/command/init.rb +14 -0
- data/lib/vagrant/command/named_base.rb +14 -0
- data/lib/vagrant/command/package.rb +41 -0
- data/lib/vagrant/command/provision.rb +17 -0
- data/lib/vagrant/command/reload.rb +17 -0
- data/lib/vagrant/command/resume.rb +17 -0
- data/lib/vagrant/command/ssh.rb +42 -0
- data/lib/vagrant/command/ssh_config.rb +26 -0
- data/lib/vagrant/command/status.rb +22 -0
- data/lib/vagrant/command/suspend.rb +17 -0
- data/lib/vagrant/command/up.rb +19 -0
- data/lib/vagrant/command/upgrade_to_060.rb +45 -0
- data/lib/vagrant/command/version.rb +13 -0
- data/lib/vagrant/config.rb +123 -0
- data/lib/vagrant/config/base.rb +85 -0
- data/lib/vagrant/config/error_recorder.rb +19 -0
- data/lib/vagrant/config/nfs.rb +10 -0
- data/lib/vagrant/config/package.rb +9 -0
- data/lib/vagrant/config/ssh.rb +33 -0
- data/lib/vagrant/config/top.rb +61 -0
- data/lib/vagrant/config/vagrant.rb +16 -0
- data/lib/vagrant/config/vm.rb +137 -0
- data/lib/vagrant/config/vm/provisioner.rb +56 -0
- data/lib/vagrant/config/vm/sub_vm.rb +17 -0
- data/lib/vagrant/data_store.rb +70 -0
- data/lib/vagrant/downloaders.rb +7 -0
- data/lib/vagrant/downloaders/base.rb +23 -0
- data/lib/vagrant/downloaders/file.rb +22 -0
- data/lib/vagrant/downloaders/http.rb +64 -0
- data/lib/vagrant/environment.rb +392 -0
- data/lib/vagrant/errors.rb +332 -0
- data/lib/vagrant/hosts.rb +8 -0
- data/lib/vagrant/hosts/arch.rb +27 -0
- data/lib/vagrant/hosts/base.rb +78 -0
- data/lib/vagrant/hosts/bsd.rb +52 -0
- data/lib/vagrant/hosts/linux.rb +47 -0
- data/lib/vagrant/plugin.rb +57 -0
- data/lib/vagrant/provisioners.rb +9 -0
- data/lib/vagrant/provisioners/base.rb +63 -0
- data/lib/vagrant/provisioners/chef.rb +130 -0
- data/lib/vagrant/provisioners/chef_server.rb +103 -0
- data/lib/vagrant/provisioners/chef_solo.rb +142 -0
- data/lib/vagrant/provisioners/puppet.rb +137 -0
- data/lib/vagrant/provisioners/puppet_server.rb +55 -0
- data/lib/vagrant/provisioners/shell.rb +52 -0
- data/lib/vagrant/ssh.rb +173 -0
- data/lib/vagrant/ssh/session.rb +125 -0
- data/lib/vagrant/systems.rb +11 -0
- data/lib/vagrant/systems/base.rb +87 -0
- data/lib/vagrant/systems/debian.rb +36 -0
- data/lib/vagrant/systems/freebsd.rb +84 -0
- data/lib/vagrant/systems/gentoo.rb +27 -0
- data/lib/vagrant/systems/linux.rb +83 -0
- data/lib/vagrant/systems/linux/config.rb +21 -0
- data/lib/vagrant/systems/linux/error.rb +9 -0
- data/lib/vagrant/systems/redhat.rb +39 -0
- data/lib/vagrant/systems/solaris.rb +62 -0
- data/lib/vagrant/systems/ubuntu.rb +17 -0
- data/lib/vagrant/test_helpers.rb +128 -0
- data/lib/vagrant/ui.rb +69 -0
- data/lib/vagrant/util.rb +13 -0
- data/lib/vagrant/util/busy.rb +59 -0
- data/lib/vagrant/util/hash_with_indifferent_access.rb +63 -0
- data/lib/vagrant/util/plain_logger.rb +25 -0
- data/lib/vagrant/util/platform.rb +65 -0
- data/lib/vagrant/util/resource_logger.rb +63 -0
- data/lib/vagrant/util/retryable.rb +25 -0
- data/lib/vagrant/util/stacked_proc_runner.rb +35 -0
- data/lib/vagrant/util/template_renderer.rb +83 -0
- data/lib/vagrant/version.rb +6 -0
- data/lib/vagrant/vm.rb +177 -0
- data/templates/chef_server_client.erb +18 -0
- data/templates/chef_solo_solo.erb +19 -0
- data/templates/commands/init/Vagrantfile.erb +82 -0
- data/templates/config/validation_failed.erb +7 -0
- data/templates/locales/en.yml +535 -0
- data/templates/network_entry_debian.erb +8 -0
- data/templates/network_entry_gentoo.erb +5 -0
- data/templates/network_entry_redhat.erb +8 -0
- data/templates/nfs/exports.erb +5 -0
- data/templates/nfs/exports_linux.erb +5 -0
- data/templates/package_Vagrantfile.erb +11 -0
- data/templates/ssh_config.erb +9 -0
- data/test/locales/en.yml +8 -0
- data/test/test_helper.rb +26 -0
- data/test/vagrant/action/box/destroy_test.rb +18 -0
- data/test/vagrant/action/box/download_test.rb +125 -0
- data/test/vagrant/action/box/package_test.rb +25 -0
- data/test/vagrant/action/box/unpackage_test.rb +84 -0
- data/test/vagrant/action/box/verify_test.rb +30 -0
- data/test/vagrant/action/builder_test.rb +203 -0
- data/test/vagrant/action/env/set_test.rb +24 -0
- data/test/vagrant/action/environment_test.rb +27 -0
- data/test/vagrant/action/general/package_test.rb +268 -0
- data/test/vagrant/action/general/validate_test.rb +31 -0
- data/test/vagrant/action/vm/boot_test.rb +66 -0
- data/test/vagrant/action/vm/check_box_test.rb +56 -0
- data/test/vagrant/action/vm/check_guest_additions_test.rb +9 -0
- data/test/vagrant/action/vm/clean_machine_folder_test.rb +84 -0
- data/test/vagrant/action/vm/clear_forwarded_ports_test.rb +72 -0
- data/test/vagrant/action/vm/clear_nfs_exports_test.rb +22 -0
- data/test/vagrant/action/vm/clear_shared_folders_test.rb +49 -0
- data/test/vagrant/action/vm/customize_test.rb +30 -0
- data/test/vagrant/action/vm/destroy_test.rb +25 -0
- data/test/vagrant/action/vm/destroy_unused_network_interfaces_test.rb +49 -0
- data/test/vagrant/action/vm/discard_state_test.rb +45 -0
- data/test/vagrant/action/vm/export_test.rb +107 -0
- data/test/vagrant/action/vm/forward_ports_helpers_test.rb +70 -0
- data/test/vagrant/action/vm/forward_ports_test.rb +194 -0
- data/test/vagrant/action/vm/halt_test.rb +79 -0
- data/test/vagrant/action/vm/host_name_test.rb +36 -0
- data/test/vagrant/action/vm/import_test.rb +66 -0
- data/test/vagrant/action/vm/match_mac_address_test.rb +36 -0
- data/test/vagrant/action/vm/network_test.rb +286 -0
- data/test/vagrant/action/vm/nfs_helpers_test.rb +26 -0
- data/test/vagrant/action/vm/nfs_test.rb +260 -0
- data/test/vagrant/action/vm/package_test.rb +25 -0
- data/test/vagrant/action/vm/package_vagrantfile_test.rb +46 -0
- data/test/vagrant/action/vm/provision_test.rb +90 -0
- data/test/vagrant/action/vm/resume_test.rb +35 -0
- data/test/vagrant/action/vm/share_folders_test.rb +139 -0
- data/test/vagrant/action/vm/suspend_test.rb +35 -0
- data/test/vagrant/action/warden_test.rb +119 -0
- data/test/vagrant/action_test.rb +89 -0
- data/test/vagrant/box_collection_test.rb +45 -0
- data/test/vagrant/box_test.rb +74 -0
- data/test/vagrant/cli_test.rb +35 -0
- data/test/vagrant/command/base_test.rb +23 -0
- data/test/vagrant/command/group_base_test.rb +15 -0
- data/test/vagrant/command/helpers_test.rb +88 -0
- data/test/vagrant/command/package_test.rb +27 -0
- data/test/vagrant/config/base_test.rb +52 -0
- data/test/vagrant/config/error_recorder_test.rb +18 -0
- data/test/vagrant/config/ssh_test.rb +12 -0
- data/test/vagrant/config/vagrant_test.rb +35 -0
- data/test/vagrant/config/vm/provisioner_test.rb +92 -0
- data/test/vagrant/config/vm_test.rb +86 -0
- data/test/vagrant/config_test.rb +162 -0
- data/test/vagrant/data_store_test.rb +77 -0
- data/test/vagrant/downloaders/base_test.rb +28 -0
- data/test/vagrant/downloaders/file_test.rb +48 -0
- data/test/vagrant/downloaders/http_test.rb +80 -0
- data/test/vagrant/environment_test.rb +508 -0
- data/test/vagrant/errors_test.rb +42 -0
- data/test/vagrant/hosts/base_test.rb +46 -0
- data/test/vagrant/hosts/bsd_test.rb +53 -0
- data/test/vagrant/hosts/linux_test.rb +54 -0
- data/test/vagrant/plugin_test.rb +9 -0
- data/test/vagrant/provisioners/base_test.rb +63 -0
- data/test/vagrant/provisioners/chef_server_test.rb +188 -0
- data/test/vagrant/provisioners/chef_solo_test.rb +219 -0
- data/test/vagrant/provisioners/chef_test.rb +179 -0
- data/test/vagrant/provisioners/puppet_server_test.rb +68 -0
- data/test/vagrant/provisioners/puppet_test.rb +182 -0
- data/test/vagrant/provisioners/shell_test.rb +68 -0
- data/test/vagrant/ssh/session_test.rb +40 -0
- data/test/vagrant/ssh_test.rb +342 -0
- data/test/vagrant/systems/base_test.rb +18 -0
- data/test/vagrant/systems/linux_test.rb +114 -0
- data/test/vagrant/ui_test.rb +29 -0
- data/test/vagrant/util/busy_test.rb +106 -0
- data/test/vagrant/util/hash_with_indifferent_access_test.rb +39 -0
- data/test/vagrant/util/plain_logger_test.rb +17 -0
- data/test/vagrant/util/platform_test.rb +18 -0
- data/test/vagrant/util/resource_logger_test.rb +78 -0
- data/test/vagrant/util/retryable_test.rb +50 -0
- data/test/vagrant/util/stacked_proc_runner_test.rb +43 -0
- data/test/vagrant/util/template_renderer_test.rb +145 -0
- data/test/vagrant/vm_test.rb +291 -0
- data/vagrant.gemspec +36 -0
- metadata +514 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
module Vagrant
|
|
2
|
+
module Provisioners
|
|
3
|
+
class PuppetError < Vagrant::Errors::VagrantError
|
|
4
|
+
error_namespace("vagrant.provisioners.puppet")
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
class Puppet < Base
|
|
8
|
+
register :puppet
|
|
9
|
+
|
|
10
|
+
class Config < Vagrant::Config::Base
|
|
11
|
+
attr_accessor :manifest_file
|
|
12
|
+
attr_accessor :manifests_path
|
|
13
|
+
attr_accessor :module_path
|
|
14
|
+
attr_accessor :pp_path
|
|
15
|
+
attr_accessor :options
|
|
16
|
+
|
|
17
|
+
def initialize
|
|
18
|
+
@manifest_file = nil
|
|
19
|
+
@manifests_path = "manifests"
|
|
20
|
+
@module_path = nil
|
|
21
|
+
@pp_path = "/tmp/vagrant-puppet"
|
|
22
|
+
@options = []
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Returns the manifests path expanded relative to the root path of the
|
|
26
|
+
# environment.
|
|
27
|
+
def expanded_manifests_path
|
|
28
|
+
Pathname.new(manifests_path).expand_path(env.root_path)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Returns the manifest file if set otherwise returns the box name pp file
|
|
32
|
+
# which may or may not exist.
|
|
33
|
+
def computed_manifest_file
|
|
34
|
+
manifest_file || "#{top.vm.box}.pp"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Returns the module paths as an array of paths expanded relative to the
|
|
38
|
+
# root path.
|
|
39
|
+
def expanded_module_paths
|
|
40
|
+
return [] if !module_path
|
|
41
|
+
|
|
42
|
+
# Get all the paths and expand them relative to the root path, returning
|
|
43
|
+
# the array of expanded paths
|
|
44
|
+
paths = module_path
|
|
45
|
+
paths = [paths] if !paths.is_a?(Array)
|
|
46
|
+
paths.map do |path|
|
|
47
|
+
Pathname.new(path).expand_path(env.root_path)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def validate(errors)
|
|
52
|
+
super
|
|
53
|
+
|
|
54
|
+
# Manifests path/file validation
|
|
55
|
+
if !expanded_manifests_path.directory?
|
|
56
|
+
errors.add(I18n.t("vagrant.provisioners.puppet.manifests_path_missing", :path => expanded_manifests_path))
|
|
57
|
+
else
|
|
58
|
+
if !expanded_manifests_path.join(computed_manifest_file).file?
|
|
59
|
+
errors.add(I18n.t("vagrant.provisioners.puppet.manifest_missing", :manifest => computed_manifest_file))
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Module paths validation
|
|
64
|
+
expanded_module_paths.each do |path|
|
|
65
|
+
if !path.directory?
|
|
66
|
+
errors.add(I18n.t("vagrant.provisioners.puppet.module_path_missing", :path => path))
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def prepare
|
|
73
|
+
set_module_paths
|
|
74
|
+
share_manifests
|
|
75
|
+
share_module_paths
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def provision!
|
|
79
|
+
verify_binary("puppet")
|
|
80
|
+
run_puppet_client
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def share_manifests
|
|
84
|
+
env.config.vm.share_folder("manifests", manifests_guest_path, config.expanded_manifests_path)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def share_module_paths
|
|
88
|
+
count = 0
|
|
89
|
+
@module_paths.each do |from, to|
|
|
90
|
+
# Sorry for the cryptic key here, but VirtualBox has a strange limit on
|
|
91
|
+
# maximum size for it and its something small (around 10)
|
|
92
|
+
env.config.vm.share_folder("v-pp-m#{count}", to, from)
|
|
93
|
+
count += 1
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def set_module_paths
|
|
98
|
+
@module_paths = {}
|
|
99
|
+
config.expanded_module_paths.each_with_index do |path, i|
|
|
100
|
+
@module_paths[path] = File.join(config.pp_path, "modules-#{i}")
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def manifests_guest_path
|
|
105
|
+
File.join(config.pp_path, "manifests")
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def verify_binary(binary)
|
|
109
|
+
vm.ssh.execute do |ssh|
|
|
110
|
+
ssh.sudo!("which #{binary}", :error_class => PuppetError, :_key => :puppet_not_detected, :binary => binary)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def run_puppet_client
|
|
115
|
+
options = [config.options].flatten
|
|
116
|
+
options << "--modulepath '#{@module_paths.values.join(':')}'" if !@module_paths.empty?
|
|
117
|
+
options << config.computed_manifest_file
|
|
118
|
+
options = options.join(" ")
|
|
119
|
+
|
|
120
|
+
commands = ["cd #{manifests_guest_path}",
|
|
121
|
+
"puppet #{options}"]
|
|
122
|
+
|
|
123
|
+
env.ui.info I18n.t("vagrant.provisioners.puppet.running_puppet", :manifest => config.computed_manifest_file)
|
|
124
|
+
|
|
125
|
+
vm.ssh.execute do |ssh|
|
|
126
|
+
ssh.sudo! commands do |ch, type, data|
|
|
127
|
+
if type == :exit_status
|
|
128
|
+
ssh.check_exit_status(data, commands)
|
|
129
|
+
else
|
|
130
|
+
env.ui.info(data)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module Vagrant
|
|
2
|
+
module Provisioners
|
|
3
|
+
class PuppetServerError < Vagrant::Errors::VagrantError
|
|
4
|
+
error_namespace("vagrant.provisioners.puppet_server")
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
class PuppetServer < Base
|
|
8
|
+
register :puppet_server
|
|
9
|
+
|
|
10
|
+
class Config < Vagrant::Config::Base
|
|
11
|
+
attr_accessor :puppet_server
|
|
12
|
+
attr_accessor :puppet_node
|
|
13
|
+
attr_accessor :options
|
|
14
|
+
|
|
15
|
+
def initialize
|
|
16
|
+
@puppet_server = "puppet"
|
|
17
|
+
@puppet_node = "puppet_node"
|
|
18
|
+
@options = []
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def provision!
|
|
23
|
+
verify_binary("puppetd")
|
|
24
|
+
run_puppetd_client
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def verify_binary(binary)
|
|
28
|
+
vm.ssh.execute do |ssh|
|
|
29
|
+
ssh.sudo!("which #{binary}", :error_class => PuppetServerError, :_key => :puppetd_not_detected, :binary => binary)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def run_puppetd_client
|
|
34
|
+
options = config.options
|
|
35
|
+
options = options.join(" ") if options.is_a?(Array)
|
|
36
|
+
if config.puppet_node
|
|
37
|
+
cn = config.puppet_node
|
|
38
|
+
else
|
|
39
|
+
cn = env.config.vm.box
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
commands = "puppetd #{options} --server #{config.puppet_server} --certname #{cn}"
|
|
43
|
+
|
|
44
|
+
env.ui.info I18n.t("vagrant.provisioners.puppet_server.running_puppetd")
|
|
45
|
+
|
|
46
|
+
vm.ssh.execute do |ssh|
|
|
47
|
+
ssh.sudo!(commands) do |channel, type, data|
|
|
48
|
+
ssh.check_exit_status(data, commands) if type == :exit_status
|
|
49
|
+
env.ui.info(data) if type != :exit_status
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module Vagrant
|
|
2
|
+
module Provisioners
|
|
3
|
+
class Shell < Base
|
|
4
|
+
register :shell
|
|
5
|
+
|
|
6
|
+
class Config < Vagrant::Config::Base
|
|
7
|
+
attr_accessor :path
|
|
8
|
+
attr_accessor :upload_path
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
@upload_path = "/tmp/vagrant-shell"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def expanded_path
|
|
15
|
+
Pathname.new(path).expand_path(env.root_path) if path
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def validate(errors)
|
|
19
|
+
super
|
|
20
|
+
|
|
21
|
+
if !path
|
|
22
|
+
errors.add(I18n.t("vagrant.provisioners.shell.path_not_set"))
|
|
23
|
+
elsif !expanded_path.file?
|
|
24
|
+
errors.add(I18n.t("vagrant.provisioners.shell.path_invalid", :path => expanded_path))
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
if !upload_path
|
|
28
|
+
errors.add(I18n.t("vagrant.provisioners.shell.upload_path_not_set"))
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def provision!
|
|
34
|
+
commands = ["chmod +x #{config.upload_path}", config.upload_path]
|
|
35
|
+
|
|
36
|
+
# Upload the script to the VM
|
|
37
|
+
vm.ssh.upload!(config.expanded_path.to_s, config.upload_path)
|
|
38
|
+
|
|
39
|
+
# Execute it with sudo
|
|
40
|
+
vm.ssh.execute do |ssh|
|
|
41
|
+
ssh.sudo!(commands) do |ch, type, data|
|
|
42
|
+
if type == :exit_status
|
|
43
|
+
ssh.check_exit_status(data, commands)
|
|
44
|
+
else
|
|
45
|
+
env.ui.info(data)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
data/lib/vagrant/ssh.rb
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
require 'timeout'
|
|
2
|
+
require 'net/ssh'
|
|
3
|
+
require 'net/scp'
|
|
4
|
+
require 'mario'
|
|
5
|
+
|
|
6
|
+
require 'vagrant/ssh/session'
|
|
7
|
+
|
|
8
|
+
module Vagrant
|
|
9
|
+
# Manages SSH access to a specific environment. Allows an environment to
|
|
10
|
+
# replace the process with SSH itself, run a specific set of commands,
|
|
11
|
+
# upload files, or even check if a host is up.
|
|
12
|
+
class SSH
|
|
13
|
+
include Util::Retryable
|
|
14
|
+
|
|
15
|
+
# Reference back up to the environment which this SSH object belongs
|
|
16
|
+
# to
|
|
17
|
+
attr_accessor :env
|
|
18
|
+
|
|
19
|
+
def initialize(environment)
|
|
20
|
+
@env = environment
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Connects to the environment's virtual machine, replacing the ruby
|
|
24
|
+
# process with an SSH process. This method optionally takes a hash
|
|
25
|
+
# of options which override the configuration values.
|
|
26
|
+
def connect(opts={})
|
|
27
|
+
if Mario::Platform.windows?
|
|
28
|
+
raise Errors::SSHUnavailableWindows, :key_path => env.config.ssh.private_key_path,
|
|
29
|
+
:ssh_port => port(opts)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
raise Errors::SSHUnavailable if !Kernel.system("which ssh > /dev/null 2>&1")
|
|
33
|
+
|
|
34
|
+
options = {}
|
|
35
|
+
options[:port] = port(opts)
|
|
36
|
+
[:host, :username, :private_key_path].each do |param|
|
|
37
|
+
options[param] = opts[param] || env.config.ssh.send(param)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
check_key_permissions(options[:private_key_path])
|
|
41
|
+
|
|
42
|
+
# Command line options
|
|
43
|
+
command_options = ["-p #{options[:port]}", "-o UserKnownHostsFile=/dev/null",
|
|
44
|
+
"-o StrictHostKeyChecking=no", "-o IdentitiesOnly=yes",
|
|
45
|
+
"-i #{options[:private_key_path]}"]
|
|
46
|
+
command_options << "-o ForwardAgent=yes" if env.config.ssh.forward_agent
|
|
47
|
+
|
|
48
|
+
if env.config.ssh.forward_x11
|
|
49
|
+
# Both are required so that no warnings are shown regarding X11
|
|
50
|
+
command_options << "-o ForwardX11=yes"
|
|
51
|
+
command_options << "-o ForwardX11Trusted=yes"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Some hackery going on here. On Mac OS X Leopard (10.5), exec fails
|
|
55
|
+
# (GH-51). As a workaround, we fork and wait. On all other platforms,
|
|
56
|
+
# we simply exec.
|
|
57
|
+
pid = nil
|
|
58
|
+
pid = fork if Util::Platform.leopard? || Util::Platform.tiger?
|
|
59
|
+
Kernel.exec "ssh #{command_options.join(" ")} #{options[:username]}@#{options[:host]}".strip if pid.nil?
|
|
60
|
+
Process.wait(pid) if pid
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Opens an SSH connection to this environment's virtual machine and yields
|
|
64
|
+
# a Net::SSH object which can be used to execute remote commands.
|
|
65
|
+
def execute(opts={})
|
|
66
|
+
# Check the key permissions to avoid SSH hangs
|
|
67
|
+
check_key_permissions(env.config.ssh.private_key_path)
|
|
68
|
+
|
|
69
|
+
# Merge in any additional options
|
|
70
|
+
opts = opts.dup
|
|
71
|
+
opts[:forward_agent] = true if env.config.ssh.forward_agent
|
|
72
|
+
opts[:port] ||= port
|
|
73
|
+
|
|
74
|
+
retryable(:tries => 5, :on => Errno::ECONNREFUSED) do
|
|
75
|
+
Net::SSH.start(env.config.ssh.host,
|
|
76
|
+
env.config.ssh.username,
|
|
77
|
+
opts.merge( :keys => [env.config.ssh.private_key_path],
|
|
78
|
+
:keys_only => true,
|
|
79
|
+
:user_known_hosts_file => [],
|
|
80
|
+
:paranoid => false,
|
|
81
|
+
:config => false)) do |ssh|
|
|
82
|
+
yield SSH::Session.new(ssh, env)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
rescue Errno::ECONNREFUSED
|
|
86
|
+
raise Errors::SSHConnectionRefused
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Uploads a file from `from` to `to`. `from` is expected to be a filename
|
|
90
|
+
# or StringIO, and `to` is expected to be a path. This method simply forwards
|
|
91
|
+
# the arguments to `Net::SCP#upload!` so view that for more information.
|
|
92
|
+
def upload!(from, to)
|
|
93
|
+
retryable(:tries => 5, :on => IOError) do
|
|
94
|
+
execute do |ssh|
|
|
95
|
+
scp = Net::SCP.new(ssh.session)
|
|
96
|
+
scp.upload!(from, to)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Checks if this environment's machine is up (i.e. responding to SSH).
|
|
102
|
+
#
|
|
103
|
+
# @return [Boolean]
|
|
104
|
+
def up?
|
|
105
|
+
# We have to determine the port outside of the block since it uses
|
|
106
|
+
# API calls which can only be used from the main thread in JRuby on
|
|
107
|
+
# Windows
|
|
108
|
+
ssh_port = port
|
|
109
|
+
|
|
110
|
+
Timeout.timeout(env.config.ssh.timeout) do
|
|
111
|
+
execute(:timeout => env.config.ssh.timeout,
|
|
112
|
+
:port => ssh_port) { |ssh| }
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
true
|
|
116
|
+
rescue Net::SSH::AuthenticationFailed
|
|
117
|
+
raise Errors::SSHAuthenticationFailed
|
|
118
|
+
rescue Timeout::Error, Errno::ECONNREFUSED, Net::SSH::Disconnect,
|
|
119
|
+
Errors::SSHConnectionRefused, Net::SSH::AuthenticationFailed
|
|
120
|
+
return false
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Checks the file permissions for the private key, resetting them
|
|
124
|
+
# if needed, or on failure erroring.
|
|
125
|
+
def check_key_permissions(key_path)
|
|
126
|
+
# Windows systems don't have this issue
|
|
127
|
+
return if Mario::Platform.windows?
|
|
128
|
+
|
|
129
|
+
stat = File.stat(key_path)
|
|
130
|
+
|
|
131
|
+
if stat.owned? && file_perms(key_path) != "600"
|
|
132
|
+
File.chmod(0600, key_path)
|
|
133
|
+
|
|
134
|
+
raise Errors::SSHKeyBadPermissions, :key_path => key_path if file_perms(key_path) != "600"
|
|
135
|
+
end
|
|
136
|
+
rescue Errno::EPERM
|
|
137
|
+
# This shouldn't happen since we verify we own the file, but just
|
|
138
|
+
# in case.
|
|
139
|
+
raise Errors::SSHKeyBadPermissions, :key_path => key_path
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Returns the file permissions of a given file. This is fairly unix specific
|
|
143
|
+
# and probably doesn't belong in this class. Will be refactored out later.
|
|
144
|
+
def file_perms(path)
|
|
145
|
+
perms = sprintf("%o", File.stat(path).mode)
|
|
146
|
+
perms.reverse[0..2].reverse
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Returns the port which is either given in the options hash or taken from
|
|
150
|
+
# the config by finding it in the forwarded ports hash based on the
|
|
151
|
+
# `config.ssh.forwarded_port_key`.
|
|
152
|
+
def port(opts={})
|
|
153
|
+
# Check if port was specified in options hash
|
|
154
|
+
pnum = opts[:port]
|
|
155
|
+
return pnum if pnum
|
|
156
|
+
|
|
157
|
+
# Check if we have an SSH forwarded port
|
|
158
|
+
pnum = nil
|
|
159
|
+
env.vm.vm.network_adapters.each do |na|
|
|
160
|
+
pnum = na.nat_driver.forwarded_ports.detect do |fp|
|
|
161
|
+
fp.name == env.config.ssh.forwarded_port_key
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
break if pnum
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
return pnum.hostport if pnum
|
|
168
|
+
|
|
169
|
+
# This should NEVER happen.
|
|
170
|
+
raise Errors::SSHPortNotDetected
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
module Vagrant
|
|
2
|
+
class SSH
|
|
3
|
+
# A helper class which wraps around `Net::SSH::Connection::Session`
|
|
4
|
+
# in order to provide basic command error checking while still
|
|
5
|
+
# providing access to the actual session object.
|
|
6
|
+
class Session
|
|
7
|
+
include Util::Retryable
|
|
8
|
+
|
|
9
|
+
attr_reader :session
|
|
10
|
+
attr_reader :env
|
|
11
|
+
|
|
12
|
+
def initialize(session, env)
|
|
13
|
+
@session = session
|
|
14
|
+
@env = env
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Executes a given command and simply returns true/false if the
|
|
18
|
+
# command succeeded or not.
|
|
19
|
+
def test?(command)
|
|
20
|
+
exec!(command) do |ch, type, data|
|
|
21
|
+
return true if type == :exit_status && data == 0
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
false
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Executes a given command on the SSH session using `sudo` and
|
|
28
|
+
# blocks until the command completes. This takes the same parameters
|
|
29
|
+
# as {#exec!}. The only difference is that the command can be an
|
|
30
|
+
# array of commands, which will be placed into the same script.
|
|
31
|
+
#
|
|
32
|
+
# This is different than just calling {#exec!} with `sudo`, since
|
|
33
|
+
# this command is tailor-made to be compliant with older versions
|
|
34
|
+
# of `sudo`.
|
|
35
|
+
def sudo!(commands, options=nil, &block)
|
|
36
|
+
channel = session.open_channel do |ch|
|
|
37
|
+
ch.exec("sudo #{env.config.ssh.sudo_shell} -l") do |ch2, success|
|
|
38
|
+
# Set the terminal
|
|
39
|
+
ch2.send_data "export TERM=vt100\n"
|
|
40
|
+
|
|
41
|
+
# Output each command as if they were entered on the command line
|
|
42
|
+
[commands].flatten.each do |command|
|
|
43
|
+
ch2.send_data "#{command}\n"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Remember to exit or we'll hang!
|
|
47
|
+
ch2.send_data "exit\n"
|
|
48
|
+
|
|
49
|
+
# Setup the callbacks with our options so we get all the
|
|
50
|
+
# stdout/stderr and error checking goodies
|
|
51
|
+
setup_channel_callbacks(ch2, commands, options, block)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
channel.wait
|
|
56
|
+
channel[:result]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Executes a given command on the SSH session and blocks until
|
|
60
|
+
# the command completes. This is an almost line for line copy of
|
|
61
|
+
# the actual `exec!` implementation, except that this
|
|
62
|
+
# implementation also reports `:exit_status` to the block if given.
|
|
63
|
+
def exec!(command, options=nil, &block)
|
|
64
|
+
retryable(:tries => 5, :on => [IOError, Net::SSH::Disconnect], :sleep => 1.0) do
|
|
65
|
+
metach = session.open_channel do |channel|
|
|
66
|
+
channel.exec(command) do |ch, success|
|
|
67
|
+
raise "could not execute command: #{command.inspect}" unless success
|
|
68
|
+
setup_channel_callbacks(ch, command, options, block)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
metach.wait
|
|
73
|
+
metach[:result]
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Sets up the channel callbacks to properly check exit statuses and
|
|
78
|
+
# callback on stdout/stderr.
|
|
79
|
+
def setup_channel_callbacks(channel, command, options, block)
|
|
80
|
+
options = { :error_check => true }.merge(options || {})
|
|
81
|
+
|
|
82
|
+
block ||= Proc.new do |ch, type, data|
|
|
83
|
+
check_exit_status(data, command, options, ch[:result]) if type == :exit_status && options[:error_check]
|
|
84
|
+
|
|
85
|
+
ch[:result] ||= ""
|
|
86
|
+
ch[:result] << data if [:stdout, :stderr].include?(type)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Output stdout data to the block
|
|
90
|
+
channel.on_data do |ch2, data|
|
|
91
|
+
# This clears the screen, we want to filter it out.
|
|
92
|
+
data.gsub!("\e[H", "")
|
|
93
|
+
|
|
94
|
+
block.call(ch2, :stdout, data)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Output stderr data to the block
|
|
98
|
+
channel.on_extended_data do |ch2, type, data|
|
|
99
|
+
block.call(ch2, :stderr, data)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Output exit status information to the block
|
|
103
|
+
channel.on_request("exit-status") do |ch2, data|
|
|
104
|
+
block.call(ch2, :exit_status, data.read_long)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Checks for an erroroneous exit status and raises an exception
|
|
109
|
+
# if so.
|
|
110
|
+
def check_exit_status(exit_status, commands, options=nil, output=nil)
|
|
111
|
+
if exit_status != 0
|
|
112
|
+
output ||= '[no output]'
|
|
113
|
+
options = {
|
|
114
|
+
:_error_class => Errors::VagrantError,
|
|
115
|
+
:_key => :ssh_bad_exit_status,
|
|
116
|
+
:command => [commands].flatten.join("\n"),
|
|
117
|
+
:output => output
|
|
118
|
+
}.merge(options || {})
|
|
119
|
+
|
|
120
|
+
raise options[:_error_class], options
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|