vagrant-lxc 0.8.0 → 1.0.0.alpha.1

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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -2
  3. data/BOXES.md +13 -21
  4. data/CHANGELOG.md +49 -0
  5. data/CONTRIBUTING.md +5 -2
  6. data/Gemfile +12 -13
  7. data/Gemfile.lock +66 -51
  8. data/README.md +39 -25
  9. data/development/Vagrantfile +0 -2
  10. data/lib/vagrant-backports/README.md +12 -0
  11. data/lib/vagrant-backports/action/handle_box.rb +1 -0
  12. data/lib/vagrant-backports/action/is_state.rb +34 -0
  13. data/lib/vagrant-backports/action/message.rb +20 -0
  14. data/lib/{vagrant-lxc → vagrant-backports}/action/wait_for_communicator.rb +6 -5
  15. data/lib/vagrant-backports/ui.rb +12 -0
  16. data/lib/vagrant-backports/utils.rb +27 -0
  17. data/lib/vagrant-lxc.rb +8 -0
  18. data/lib/vagrant-lxc/action.rb +81 -48
  19. data/lib/vagrant-lxc/action/boot.rb +2 -1
  20. data/lib/vagrant-lxc/action/fetch_ip_from_dnsmasq_leases.rb +1 -0
  21. data/lib/vagrant-lxc/action/handle_box_metadata.rb +36 -14
  22. data/lib/vagrant-lxc/action/message.rb +0 -23
  23. data/lib/vagrant-lxc/action/prepare_nfs_settings.rb +64 -0
  24. data/lib/vagrant-lxc/action/prepare_nfs_valid_ids.rb +19 -0
  25. data/lib/vagrant-lxc/action/setup_package_files.rb +6 -2
  26. data/lib/vagrant-lxc/{action → backports/action}/share_folders.rb +0 -0
  27. data/lib/vagrant-lxc/command/root.rb +58 -0
  28. data/lib/vagrant-lxc/command/sudoers.rb +87 -0
  29. data/lib/vagrant-lxc/driver.rb +21 -11
  30. data/lib/vagrant-lxc/plugin.rb +23 -5
  31. data/lib/vagrant-lxc/provider/cap/public_address.rb +17 -0
  32. data/lib/vagrant-lxc/synced_folder.rb +42 -0
  33. data/lib/vagrant-lxc/version.rb +1 -1
  34. data/locales/en.yml +6 -5
  35. data/scripts/lxc-template +165 -0
  36. data/spec/spec_helper.rb +9 -13
  37. data/spec/unit/action/clear_forwarded_ports_spec.rb +3 -3
  38. data/spec/unit/action/compress_rootfs_spec.rb +7 -5
  39. data/spec/unit/action/forward_ports_spec.rb +8 -8
  40. data/spec/unit/action/handle_box_metadata_spec.rb +71 -15
  41. data/spec/unit/action/setup_package_files_spec.rb +32 -8
  42. data/spec/unit/driver/cli_spec.rb +31 -30
  43. data/spec/unit/driver_spec.rb +35 -27
  44. data/spec/unit/support/unit_example_group.rb +6 -6
  45. data/spec/unit_helper.rb +4 -2
  46. data/tasks/spec.rake +18 -11
  47. data/vagrant-lxc.gemspec +7 -0
  48. data/vagrant-spec.config.rb +24 -0
  49. metadata +24 -36
  50. data/boxes/build-all.sh +0 -22
  51. data/boxes/build-debian-box.sh +0 -167
  52. data/boxes/build-openmandriva-box.sh +0 -159
  53. data/boxes/build-ubuntu-box.sh +0 -151
  54. data/boxes/common/cleanup +0 -7
  55. data/boxes/common/install-babushka +0 -16
  56. data/boxes/common/install-chef +0 -15
  57. data/boxes/common/install-puppet +0 -13
  58. data/boxes/common/install-salt +0 -12
  59. data/boxes/common/install-salt-debian +0 -28
  60. data/boxes/common/lxc-template +0 -226
  61. data/boxes/common/lxc-template-openmandriva +0 -225
  62. data/boxes/common/lxc.conf +0 -49
  63. data/boxes/common/metadata.json +0 -5
  64. data/lib/vagrant-lxc/action/check_created.rb +0 -21
  65. data/lib/vagrant-lxc/action/check_running.rb +0 -21
  66. data/lib/vagrant-lxc/action/created.rb +0 -20
  67. data/lib/vagrant-lxc/action/disconnect.rb +0 -18
  68. data/lib/vagrant-lxc/action/is_running.rb +0 -19
  69. data/spec/acceptance/sanity_check_spec.rb +0 -111
  70. data/spec/acceptance/support/acceptance_example_group.rb +0 -76
  71. data/spec/acceptance/support/machine_ext.rb +0 -12
  72. data/spec/acceptance/support/test_ui.rb +0 -22
  73. data/spec/acceptance_helper.rb +0 -21
@@ -1,23 +0,0 @@
1
- module Vagrant
2
- module LXC
3
- module Action
4
- # XXX: Is this really needed? Should we contribute this back to Vagrant's core?
5
- class Message
6
- def initialize(app, env, msg_key, type = :info)
7
- @app = app
8
- @msg_key = msg_key
9
- @type = type
10
- end
11
-
12
- def call(env)
13
- machine = env[:machine]
14
- message = I18n.t("vagrant_lxc.messages.#{@msg_key}", name: machine.name)
15
-
16
- env[:ui].send @type, message
17
-
18
- @app.call env
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -0,0 +1,64 @@
1
+ module Vagrant
2
+ module LXC
3
+ module Action
4
+ class PrepareNFSSettings
5
+ include Vagrant::Util::Retryable
6
+
7
+ def initialize(app, env)
8
+ @app = app
9
+ @logger = Log4r::Logger.new("vagrant::action::vm::nfs")
10
+ end
11
+
12
+ def call(env)
13
+ @machine = env[:machine]
14
+
15
+ @app.call(env)
16
+
17
+ # if using_nfs? # TODO: && !privileged_container?
18
+ # raise Errors::NfsWithoutPrivilegedError
19
+ # end
20
+
21
+ if using_nfs?
22
+ @logger.info("Using NFS, preparing NFS settings by reading host IP and machine IP")
23
+ add_ips_to_env!(env)
24
+ end
25
+ end
26
+
27
+ # We're using NFS if we have any synced folder with NFS configured. If
28
+ # we are not using NFS we don't need to do the extra work to
29
+ # populate these fields in the environment.
30
+ def using_nfs?
31
+ @machine.config.vm.synced_folders.any? { |_, opts| opts[:type] == :nfs }
32
+ end
33
+
34
+ # TODO:
35
+ # def privileged_container?
36
+ # @machine.provider.driver.privileged?(@machine.id)
37
+ # end
38
+
39
+ # Extracts the proper host and guest IPs for NFS mounts and stores them
40
+ # in the environment for the SyncedFolder action to use them in
41
+ # mounting.
42
+ #
43
+ # The ! indicates that this method modifies its argument.
44
+ def add_ips_to_env!(env)
45
+ provider = @machine.provider
46
+
47
+ host_ip = read_host_ip
48
+ machine_ip = provider.ssh_info[:host]
49
+
50
+ raise Vagrant::Errors::NFSNoHostonlyNetwork if !host_ip || !machine_ip
51
+
52
+ env[:nfs_host_ip] = host_ip
53
+ env[:nfs_machine_ip] = machine_ip
54
+ end
55
+
56
+ def read_host_ip
57
+ @machine.communicate.execute 'echo $SSH_CLIENT' do |buffer, output|
58
+ return output.chomp.split(' ')[0] if buffer == :stdout
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,19 @@
1
+ module Vagrant
2
+ module LXC
3
+ module Action
4
+ class PrepareNFSValidIds
5
+ def initialize(app, env)
6
+ @app = app
7
+ @logger = Log4r::Logger.new("vagrant::action::vm::nfs")
8
+ end
9
+
10
+ def call(env)
11
+ machine = env[:machine]
12
+ env[:nfs_valid_ids] = machine.provider.driver.all_containers
13
+
14
+ @app.call(env)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -43,12 +43,16 @@ module Vagrant
43
43
 
44
44
  def copy_box_files_to_pkg_dir
45
45
  box_dir = @env[:machine].box.directory
46
- FileUtils.cp box_dir.join('lxc-template').to_s, @env['package.directory'].to_s
47
46
  FileUtils.cp box_dir.join('metadata.json').to_s, @env['package.directory'].to_s
48
- # TODO: Update built-on metadata.json
47
+ if (template = box_dir.join('lxc-template')).exist?
48
+ FileUtils.cp template.to_s, @env['package.directory'].to_s
49
+ end
49
50
  if (conf = box_dir.join('lxc.conf')).exist?
50
51
  FileUtils.cp conf.to_s, @env['package.directory'].to_s
51
52
  end
53
+ if (conf = box_dir.join('lxc-config')).exist?
54
+ FileUtils.cp conf.to_s, @env['package.directory'].to_s
55
+ end
52
56
  end
53
57
  end
54
58
  end
@@ -0,0 +1,58 @@
1
+ module Vagrant
2
+ module LXC
3
+ module Command
4
+ class Root < Vagrant.plugin("2", :command)
5
+ def self.synopsis
6
+ 'vagrant-lxc specific commands'
7
+ end
8
+
9
+ def initialize(argv, env)
10
+ @args, @sub_command, @sub_args = split_main_and_subcommand(argv)
11
+ @subcommands = Vagrant::Registry.new.tap do |registry|
12
+ registry.register(:sudoers) do
13
+ require_relative 'sudoers'
14
+ Sudoers
15
+ end
16
+ end
17
+ super(argv, env)
18
+ end
19
+
20
+ def execute
21
+ # Print the help
22
+ return help if @args.include?("-h") || @args.include?("--help")
23
+
24
+ klazz = @subcommands.get(@sub_command.to_sym) if @sub_command
25
+ return help unless klazz
26
+
27
+ @logger.debug("Executing command: #{klazz} #{@sub_args.inspect}")
28
+
29
+ # Initialize and execute the command class
30
+ klazz.new(@sub_args, @env).execute
31
+ end
32
+
33
+ def help
34
+ opts = OptionParser.new do |opts|
35
+ opts.banner = "Usage: vagrant lxc <subcommand> [<args>]"
36
+ opts.separator ""
37
+ opts.separator "Available subcommands:"
38
+
39
+ # REFACTOR Use @subcommands.keys.sort
40
+ # https://github.com/mitchellh/vagrant/commit/4194da19c60956f6e59239c0145f772be257e79d
41
+ keys = []
42
+ @subcommands.each { |key, value| keys << key }
43
+
44
+ keys.sort.each do |key|
45
+ opts.separator " #{key}"
46
+ end
47
+
48
+ opts.separator ""
49
+ opts.separator "For help on any individual subcommand run `vagrant lxc <subcommand> -h`"
50
+ end
51
+
52
+ @env.ui.info(opts.help, :prefix => false)
53
+ end
54
+
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,87 @@
1
+ require 'tempfile'
2
+
3
+ module Vagrant
4
+ module LXC
5
+ module Command
6
+ class Sudoers < Vagrant.plugin("2", :command)
7
+ def execute
8
+ options = { user: ENV['USER'] }
9
+
10
+ opts = OptionParser.new do |opts|
11
+ opts.banner = "Usage: vagrant lxc sudoers"
12
+ opts.separator ""
13
+ opts.on('-u', '--user', "The user for which to create the policy (defaults to '#{options[:user]}')") do |u|
14
+ options[:user] = u
15
+ end
16
+ end
17
+
18
+ argv = parse_options(opts)
19
+ return unless argv
20
+
21
+ filename = "vagrant-lxc-#{options[:user]}"
22
+ to_sudoers!(create_tempfile!(options[:user], filename), filename)
23
+ end
24
+
25
+ private
26
+
27
+ # REFACTOR: Make use ERB rendering after https://github.com/mitchellh/vagrant/issues/3231
28
+ # lands into core
29
+ def create_tempfile!(user, filename)
30
+ sudoers = Tempfile.new(filename).tap do |file|
31
+ file.write "# Automatically created by vagrant-lxc\n"
32
+ commands.each do |command|
33
+ file.write sudoers_policy(user, command[:cmd], command[:args])
34
+ end
35
+ end
36
+ sudoers.close
37
+ File.chmod(0644, sudoers.path)
38
+ sudoers.path
39
+ end
40
+
41
+ def to_sudoers!(source, destination)
42
+ destination = "/etc/sudoers.d/#{destination}"
43
+ commands = [
44
+ "rm -f #{destination}",
45
+ "cp #{source} #{destination}",
46
+ "chmod 440 #{destination}"
47
+ ]
48
+ `echo "#{commands.join('; ')}" | sudo sh`
49
+ end
50
+
51
+ def sudoers_policy(user, command, args)
52
+ vagrant_home = "#{`echo ~#{user}`.chomp}/.vagrant.d"
53
+ args = args.gsub /%\{VAGRANT_D\}/, vagrant_home
54
+ args = args.gsub /%\{BOXES\}/, "#{vagrant_home}/boxes"
55
+ "#{user} ALL=(root) NOPASSWD: #{command} #{args}\n"
56
+ end
57
+
58
+ def commands
59
+ [
60
+ { cmd: '/usr/bin/lxc-ls', args: '' },
61
+ { cmd: '/usr/bin/lxc-info', args: '' },
62
+ { cmd: '/usr/bin/lxc-attach', args: '' },
63
+ { cmd: '/usr/bin/which', args: 'lxc-*' },
64
+ { cmd: '/bin/cat', args: '/var/lib/lxc/*' },
65
+ { cmd: '/bin/mkdir', args: '-p /var/lib/lxc/*' },
66
+ { cmd: '/bin/su', args: "root -c sed -e '*' -ibak /var/lib/lxc/*" },
67
+ { cmd: '/bin/su', args: "root -c echo '*' >> /var/lib/lxc/*" },
68
+ { cmd: '/usr/bin/lxc-start', args: '-d --name *' },
69
+ { cmd: '/bin/cp', args: '%{BOXES}/*/lxc/lxc-template /usr/lib/lxc/templates/*' },
70
+ { cmd: '/bin/cp', args: '%{VAGRANT_D}/gems/gems/vagrant-lxc-*/scripts/lxc-template /usr/lib/lxc/templates/*' },
71
+ { cmd: '/bin/cp', args: '%{BOXES}/*/lxc/lxc-template /usr/share/lxc/templates/*' },
72
+ { cmd: '/bin/cp', args: '%{VAGRANT_D}/gems/gems/vagrant-lxc-*/scripts/lxc-template /usr/share/lxc/templates/*' },
73
+ { cmd: '/bin/rm', args: '/usr/lib/lxc/templates/*' },
74
+ { cmd: '/bin/rm', args: '/usr/share/lxc/templates/*' },
75
+ { cmd: '/bin/chmod', args: '+x /usr/lib/lxc/*' },
76
+ { cmd: '/bin/chmod', args: '+x /usr/share/lxc/*' },
77
+ { cmd: '/usr/bin/lxc-create', args: '--template * --name * -- --tarball %{BOXES}/*' },
78
+ { cmd: '/bin/rm', args: '-rf /var/lib/lxc/*/rootfs/tmp/*' },
79
+ { cmd: '/usr/bin/lxc-shutdown', args: '--name *' },
80
+ { cmd: '/usr/bin/lxc-stop', args: '--name *' },
81
+ { cmd: '/usr/bin/lxc-destroy', args: '--name *' }
82
+ ]
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -31,6 +31,10 @@ module Vagrant
31
31
  raise ContainerNotFound if @container_name && ! @cli.list.include?(@container_name)
32
32
  end
33
33
 
34
+ def all_containers
35
+ @cli.list
36
+ end
37
+
34
38
  def base_path
35
39
  Pathname.new("#{CONTAINERS_PATH}/#{@container_name}")
36
40
  end
@@ -57,19 +61,24 @@ module Vagrant
57
61
  end
58
62
 
59
63
  def share_folders(folders)
60
- folders.each do |folder|
61
- guestpath = rootfs_path.join(folder[:guestpath].gsub(/^\//, ''))
62
- unless guestpath.directory?
63
- begin
64
- @logger.debug("Guest path doesn't exist, creating: #{guestpath}")
65
- @sudo_wrapper.run('mkdir', '-p', guestpath.to_s)
66
- rescue Errno::EACCES
67
- raise Vagrant::Errors::SharedFolderCreateFailed, :path => guestpath.to_s
68
- end
69
- end
64
+ folders.each do |f|
65
+ share_folder(f[:hostpath], f[:guestpath], f.fetch(:mount_options, 'bind'))
66
+ end
67
+ end
70
68
 
71
- @customizations << ['mount.entry', "#{folder[:hostpath]} #{guestpath} none bind 0 0"]
69
+ def share_folder(host_path, guest_path, mount_options = nil)
70
+ guest_path = rootfs_path.join(guest_path.gsub(/^\//, ''))
71
+ unless guest_path.directory?
72
+ begin
73
+ @logger.debug("Guest path doesn't exist, creating: #{guest_path}")
74
+ @sudo_wrapper.run('mkdir', '-p', guest_path.to_s)
75
+ rescue Errno::EACCES
76
+ raise Vagrant::Errors::SharedFolderCreateFailed, :path => guest_path.to_s
77
+ end
72
78
  end
79
+
80
+ mount_options = Array(mount_options || ['bind'])
81
+ @customizations << ['mount.entry', "#{host_path} #{guest_path} none #{mount_options.join(',')} 0 0"]
73
82
  end
74
83
 
75
84
  def start(customizations)
@@ -87,6 +96,7 @@ module Vagrant
87
96
 
88
97
  def forced_halt
89
98
  @logger.info('Shutting down container...')
99
+ # TODO: Remove `lxc-shutdown` usage, graceful halt is enough
90
100
  @cli.transition_to(:stopped) { |c| c.shutdown }
91
101
  # REFACTOR: Do not use exception to control the flow
92
102
  rescue CLI::TargetStateNotReached, CLI::ShutdownNotSupported
@@ -1,4 +1,5 @@
1
- require "vagrant"
1
+ require 'vagrant'
2
+ require 'vagrant-backports/utils'
2
3
 
3
4
  module Vagrant
4
5
  module LXC
@@ -9,7 +10,9 @@ module Vagrant
9
10
  LXC-based virtual machines.
10
11
  EOF
11
12
 
12
- provider(:lxc, parallel: true) do
13
+ extra = []
14
+ extra << {parallel: true} if Vagrant::Backports.vagrant_1_2_or_later?
15
+ provider(:lxc, *extra) do
13
16
  require File.expand_path("../provider", __FILE__)
14
17
 
15
18
  I18n.load_path << File.expand_path(File.dirname(__FILE__) + '/../../locales/en.yml')
@@ -18,14 +21,29 @@ module Vagrant
18
21
  Provider
19
22
  end
20
23
 
24
+ command "lxc" do
25
+ require_relative 'command/root'
26
+ Command::Root
27
+ end
28
+
21
29
  config(:lxc, :provider) do
22
30
  require File.expand_path("../config", __FILE__)
23
31
  Config
24
32
  end
25
- end
26
33
 
27
- def self.vagrant_1_3_or_later
28
- Gem::Version.new(Vagrant::VERSION) >= Gem::Version.new('1.3.0')
34
+ if Vagrant::Backports.vagrant_1_4_or_later?
35
+ synced_folder(:lxc) do
36
+ require File.expand_path("../synced_folder", __FILE__)
37
+ SyncedFolder
38
+ end
39
+ end
40
+
41
+ if Vagrant::Backports.vagrant_1_5_or_later?
42
+ provider_capability("lxc", "public_address") do
43
+ require_relative "provider/cap/public_address"
44
+ Provider::Cap::PublicAddress
45
+ end
46
+ end
29
47
  end
30
48
  end
31
49
  end
@@ -0,0 +1,17 @@
1
+ module Vagrant
2
+ module LXC
3
+ class Provider
4
+ module Cap
5
+ module PublicAddress
6
+ def self.public_address(machine)
7
+ return nil if machine.state.id != :running
8
+
9
+ ssh_info = machine.ssh_info
10
+ return nil if !ssh_info
11
+ ssh_info[:host]
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,42 @@
1
+ module Vagrant
2
+ module LXC
3
+ class SyncedFolder < Vagrant.plugin("2", :synced_folder)
4
+ def usable?(machine)
5
+ # These synced folders only work if the provider is LXC
6
+ machine.provider_name == :lxc
7
+ end
8
+
9
+ def prepare(machine, folders, _opts)
10
+ machine.ui.output(I18n.t("vagrant.actions.lxc.share_folders.preparing"))
11
+
12
+ folders.each do |id, data|
13
+ host_path = Pathname.new(File.expand_path(data[:hostpath], machine.env.root_path))
14
+ guest_path = data[:guestpath]
15
+
16
+ machine.env.ui.warn(I18n.t("vagrant_lxc.messages.warn_owner")) if data[:owner]
17
+ machine.env.ui.warn(I18n.t("vagrant_lxc.messages.warn_group")) if data[:group]
18
+
19
+ if !host_path.directory? && data[:create]
20
+ # Host path doesn't exist, so let's create it.
21
+ @logger.info("Host path doesn't exist, creating: #{host_path}")
22
+
23
+ begin
24
+ host_path.mkpath
25
+ rescue Errno::EACCES
26
+ raise Vagrant::Errors::SharedFolderCreateFailed,
27
+ :path => hostpath.to_s
28
+ end
29
+ end
30
+
31
+ mount_opts = data[:mount_options]
32
+ machine.provider.driver.share_folder(host_path, guest_path, mount_opts)
33
+ # Guest path specified, so mount the folder to specified point
34
+ machine.ui.detail(I18n.t("vagrant.actions.vm.share_folders.mounting_entry",
35
+ guestpath: data[:guestpath],
36
+ hostpath: data[:hostpath],
37
+ guest_path: data[:guestpath]))
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end