vagrant-lxc-2.1-patch 1.4.0

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 (64) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +31 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +10 -0
  5. data/.vimrc +1 -0
  6. data/BOXES.md +47 -0
  7. data/CHANGELOG.md +510 -0
  8. data/CONTRIBUTING.md +24 -0
  9. data/Gemfile +24 -0
  10. data/Guardfile +7 -0
  11. data/LICENSE.txt +22 -0
  12. data/README.md +187 -0
  13. data/Rakefile +3 -0
  14. data/lib/vagrant-lxc.rb +10 -0
  15. data/lib/vagrant-lxc/action.rb +234 -0
  16. data/lib/vagrant-lxc/action/boot.rb +42 -0
  17. data/lib/vagrant-lxc/action/clear_forwarded_ports.rb +56 -0
  18. data/lib/vagrant-lxc/action/compress_rootfs.rb +30 -0
  19. data/lib/vagrant-lxc/action/create.rb +57 -0
  20. data/lib/vagrant-lxc/action/destroy.rb +18 -0
  21. data/lib/vagrant-lxc/action/destroy_confirm.rb +17 -0
  22. data/lib/vagrant-lxc/action/fetch_ip_with_lxc_info.rb +43 -0
  23. data/lib/vagrant-lxc/action/forced_halt.rb +20 -0
  24. data/lib/vagrant-lxc/action/forward_ports.rb +121 -0
  25. data/lib/vagrant-lxc/action/gc_private_network_bridges.rb +47 -0
  26. data/lib/vagrant-lxc/action/handle_box_metadata.rb +94 -0
  27. data/lib/vagrant-lxc/action/prepare_nfs_settings.rb +64 -0
  28. data/lib/vagrant-lxc/action/prepare_nfs_valid_ids.rb +19 -0
  29. data/lib/vagrant-lxc/action/private_networks.rb +46 -0
  30. data/lib/vagrant-lxc/action/setup_package_files.rb +60 -0
  31. data/lib/vagrant-lxc/action/warn_networks.rb +25 -0
  32. data/lib/vagrant-lxc/command/root.rb +58 -0
  33. data/lib/vagrant-lxc/command/sudoers.rb +97 -0
  34. data/lib/vagrant-lxc/config.rb +73 -0
  35. data/lib/vagrant-lxc/driver.rb +288 -0
  36. data/lib/vagrant-lxc/driver/cli.rb +166 -0
  37. data/lib/vagrant-lxc/errors.rb +62 -0
  38. data/lib/vagrant-lxc/plugin.rb +51 -0
  39. data/lib/vagrant-lxc/provider.rb +101 -0
  40. data/lib/vagrant-lxc/provider/cap/public_address.rb +17 -0
  41. data/lib/vagrant-lxc/sudo_wrapper.rb +104 -0
  42. data/lib/vagrant-lxc/synced_folder.rb +72 -0
  43. data/lib/vagrant-lxc/version.rb +5 -0
  44. data/locales/en.yml +82 -0
  45. data/scripts/lxc-template +171 -0
  46. data/scripts/pipework +422 -0
  47. data/spec/Vagrantfile +26 -0
  48. data/spec/fixtures/sample-ip-addr-output +2 -0
  49. data/spec/spec_helper.rb +35 -0
  50. data/spec/support/.gitkeep +0 -0
  51. data/spec/unit/action/clear_forwarded_ports_spec.rb +43 -0
  52. data/spec/unit/action/compress_rootfs_spec.rb +29 -0
  53. data/spec/unit/action/forward_ports_spec.rb +117 -0
  54. data/spec/unit/action/handle_box_metadata_spec.rb +126 -0
  55. data/spec/unit/action/setup_package_files_spec.rb +83 -0
  56. data/spec/unit/driver/cli_spec.rb +263 -0
  57. data/spec/unit/driver_spec.rb +268 -0
  58. data/spec/unit/support/unit_example_group.rb +38 -0
  59. data/spec/unit_helper.rb +17 -0
  60. data/tasks/spec.rake +40 -0
  61. data/templates/sudoers.rb.erb +129 -0
  62. data/vagrant-lxc.gemspec +20 -0
  63. data/vagrant-spec.config.rb +24 -0
  64. metadata +119 -0
@@ -0,0 +1,94 @@
1
+ module Vagrant
2
+ module LXC
3
+ module Action
4
+ # Prepare arguments to be used for lxc-create
5
+ class HandleBoxMetadata
6
+ SUPPORTED_VERSIONS = ['1.0.0', '2', '3']
7
+
8
+ def initialize(app, env)
9
+ @app = app
10
+ @logger = Log4r::Logger.new("vagrant::lxc::action::handle_box_metadata")
11
+ end
12
+
13
+ def call(env)
14
+ @env = env
15
+ @box = @env[:machine].box
16
+
17
+ @env[:ui].info I18n.t("vagrant.actions.vm.import.importing",
18
+ :name => @env[:machine].box.name)
19
+
20
+ @logger.info 'Validating box contents'
21
+ validate_box
22
+
23
+ @logger.info 'Setting box options on environment'
24
+ @env[:lxc_template_src] = template_src
25
+ @env[:lxc_template_opts] = template_opts
26
+
27
+ # FIXME: Remove support for pre 1.0.0 boxes
28
+ if box_version != '1.0.0'
29
+ @env[:ui].warn "WARNING: You are using a base box that has a format that has been deprecated, please upgrade to a new one."
30
+ @env[:lxc_template_opts].merge!(
31
+ '--auth-key' => Vagrant.source_root.join('keys', 'vagrant.pub').expand_path.to_s
32
+ )
33
+ end
34
+
35
+ if template_config_file.exist?
36
+ @env[:lxc_template_opts].merge!('--config' => template_config_file.to_s)
37
+ elsif old_template_config_file.exist?
38
+ @env[:lxc_template_config] = old_template_config_file.to_s
39
+ end
40
+
41
+ @app.call env
42
+ end
43
+
44
+ def template_src
45
+ @template_src ||=
46
+ if (box_template = @box.directory.join('lxc-template')).exist?
47
+ box_template.to_s
48
+ else
49
+ Vagrant::LXC.source_root.join('scripts/lxc-template').to_s
50
+ end
51
+ end
52
+
53
+ def template_config_file
54
+ @template_config_file ||= @box.directory.join('lxc-config')
55
+ end
56
+
57
+ # TODO: Remove this once we remove compatibility for < 1.0.0 boxes
58
+ def old_template_config_file
59
+ @old_template_config_file ||= @box.directory.join('lxc.conf')
60
+ end
61
+
62
+ def template_opts
63
+ @template_opts ||= @box.metadata.fetch('template-opts', {}).dup.merge!(
64
+ '--tarball' => rootfs_tarball
65
+ )
66
+ end
67
+
68
+ def rootfs_tarball
69
+ @rootfs_tarball ||= @box.directory.join('rootfs.tar.gz').to_s
70
+ end
71
+
72
+ def validate_box
73
+ unless SUPPORTED_VERSIONS.include? box_version
74
+ raise Errors::IncompatibleBox.new name: @box.name,
75
+ found: box_version,
76
+ supported: SUPPORTED_VERSIONS.join(', ')
77
+ end
78
+
79
+ unless File.exists?(template_src)
80
+ raise Errors::TemplateFileMissing.new name: @box.name
81
+ end
82
+
83
+ unless File.exists?(rootfs_tarball)
84
+ raise Errors::RootFSTarballMissing.new name: @box.name
85
+ end
86
+ end
87
+
88
+ def box_version
89
+ @box.metadata.fetch('version')
90
+ end
91
+ end
92
+ end
93
+ end
94
+ 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
@@ -0,0 +1,46 @@
1
+ module Vagrant
2
+ module LXC
3
+ module Action
4
+ class PrivateNetworks
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ @app.call(env)
11
+
12
+ if private_network_configured?(env[:machine].config)
13
+ env[:ui].output(I18n.t("vagrant_lxc.messages.setup_private_network"))
14
+ configure_private_networks(env)
15
+ end
16
+ end
17
+
18
+ def private_network_configured?(config)
19
+ config.vm.networks.find do |type, _|
20
+ type.to_sym == :private_network
21
+ end
22
+ end
23
+
24
+ def configure_private_networks(env)
25
+ env[:machine].config.vm.networks.find do |type, config|
26
+ next if type.to_sym != :private_network
27
+
28
+ container_name = env[:machine].provider.driver.container_name
29
+ address_type = config[:type]
30
+ ip = config[:ip]
31
+ bridge_ip = config.fetch(:lxc__bridge_ip) { build_bridge_ip(ip) }
32
+ bridge = config.fetch(:lxc__bridge_name)
33
+
34
+ env[:machine].provider.driver.configure_private_network(bridge, bridge_ip, container_name, address_type, ip)
35
+ end
36
+ end
37
+
38
+ def build_bridge_ip(ip)
39
+ if ip
40
+ ip.sub(/^(\d+\.\d+\.\d+)\.\d+/, '\1.254')
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,60 @@
1
+ require 'fileutils'
2
+
3
+ module Vagrant
4
+ module LXC
5
+ module Action
6
+ class SetupPackageFiles
7
+ def initialize(app, env)
8
+ @app = app
9
+
10
+ env["package.include"] ||= []
11
+ env["package.vagrantfile"] ||= nil
12
+ end
13
+
14
+ def call(env)
15
+ @env = env
16
+
17
+ create_package_temp_dir
18
+ move_rootfs_to_pkg_dir
19
+ copy_box_files_to_pkg_dir
20
+
21
+ @app.call env
22
+
23
+ recover # called to cleanup temp directory
24
+ end
25
+
26
+ def recover(*)
27
+ if @temp_dir && File.exist?(@temp_dir)
28
+ FileUtils.rm_rf(@temp_dir)
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def create_package_temp_dir
35
+ @env[:ui].info I18n.t("vagrant.actions.vm.export.create_dir")
36
+ @temp_dir = @env["package.directory"] = @env[:tmp_path].join("container-export-#{Time.now.to_i.to_s}")
37
+ FileUtils.mkpath(@temp_dir)
38
+ end
39
+
40
+ def move_rootfs_to_pkg_dir
41
+ FileUtils.mv @env['package.rootfs'].to_s, @env['package.directory'].to_s
42
+ end
43
+
44
+ def copy_box_files_to_pkg_dir
45
+ box_dir = @env[:machine].box.directory
46
+ FileUtils.cp box_dir.join('metadata.json').to_s, @env['package.directory'].to_s
47
+ if (template = box_dir.join('lxc-template')).exist?
48
+ FileUtils.cp template.to_s, @env['package.directory'].to_s
49
+ end
50
+ if (conf = box_dir.join('lxc.conf')).exist?
51
+ FileUtils.cp conf.to_s, @env['package.directory'].to_s
52
+ end
53
+ if (conf = box_dir.join('lxc-config')).exist?
54
+ FileUtils.cp conf.to_s, @env['package.directory'].to_s
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,25 @@
1
+ module Vagrant
2
+ module LXC
3
+ module Action
4
+ class WarnNetworks
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ if public_network_configured?(env[:machine].config)
11
+ env[:ui].warn(I18n.t("vagrant_lxc.messages.warn_networks"))
12
+ end
13
+
14
+ @app.call(env)
15
+ end
16
+
17
+ def public_network_configured?(config)
18
+ config.vm.networks.find do |type, _|
19
+ type.to_sym == :public_network
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ 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,97 @@
1
+ require 'tempfile'
2
+
3
+ require "vagrant-lxc/driver"
4
+ require "vagrant-lxc/sudo_wrapper"
5
+
6
+ module Vagrant
7
+ module LXC
8
+ module Command
9
+ class Sudoers < Vagrant.plugin("2", :command)
10
+
11
+ def initialize(argv, env)
12
+ super
13
+ @argv
14
+ @env = env
15
+ end
16
+
17
+ def execute
18
+ options = { user: ENV['USER'] }
19
+
20
+ opts = OptionParser.new do |opts|
21
+ opts.banner = "Usage: vagrant lxc sudoers"
22
+ opts.separator ""
23
+ opts.on('-u user', '--user user', String, "The user for which to create the policy (defaults to '#{options[:user]}')") do |u|
24
+ options[:user] = u
25
+ end
26
+ end
27
+
28
+ argv = parse_options(opts)
29
+ return unless argv
30
+
31
+ wrapper_path = SudoWrapper.dest_path
32
+ wrapper = create_wrapper!
33
+ sudoers = create_sudoers!(options[:user], wrapper_path)
34
+
35
+ su_copy([
36
+ {source: wrapper, target: wrapper_path, mode: "0555"},
37
+ {source: sudoers, target: sudoers_path, mode: "0440"}
38
+ ])
39
+ end
40
+
41
+ def sudoers_path
42
+ "/etc/sudoers.d/vagrant-lxc"
43
+ end
44
+
45
+ private
46
+
47
+ # This requires vagrant 1.5.2+ https://github.com/mitchellh/vagrant/commit/3371c3716278071680af9b526ba19235c79c64cb
48
+ def create_wrapper!
49
+ lxc_base_path = Driver.new("").containers_path
50
+ wrapper = Tempfile.new('lxc-wrapper').tap do |file|
51
+ template = Vagrant::Util::TemplateRenderer.new(
52
+ 'sudoers.rb',
53
+ :template_root => Vagrant::LXC.source_root.join('templates').to_s,
54
+ :cmd_paths => build_cmd_paths_hash,
55
+ :lxc_base_path => lxc_base_path,
56
+ :pipework_regex => "#{ENV['HOME']}/\.vagrant\.d/gems/(?:\\d+?\\.\\d+?\\.\\d+?/)?gems/vagrant-lxc.+/scripts/pipework"
57
+ )
58
+ file.puts template.render
59
+ end
60
+ wrapper.close
61
+ wrapper.path
62
+ end
63
+
64
+ def create_sudoers!(user, command)
65
+ sudoers = Tempfile.new('vagrant-lxc-sudoers').tap do |file|
66
+ file.puts "# Automatically created by vagrant-lxc"
67
+ file.puts "#{user} ALL=(root) NOPASSWD: #{command}"
68
+ end
69
+ sudoers.close
70
+ sudoers.path
71
+ end
72
+
73
+ def su_copy(files)
74
+ commands = files.map { |file|
75
+ [
76
+ "rm -f #{file[:target]}",
77
+ "cp #{file[:source]} #{file[:target]}",
78
+ "chown root:root #{file[:target]}",
79
+ "chmod #{file[:mode]} #{file[:target]}"
80
+ ]
81
+ }.flatten
82
+ system "echo \"#{commands.join("; ")}\" | sudo sh"
83
+ end
84
+
85
+ def build_cmd_paths_hash
86
+ {}.tap do |hash|
87
+ %w( which cat mkdir cp chown chmod rm tar chown ip ifconfig brctl ).each do |cmd|
88
+ hash[cmd] = `sudo which #{cmd}`.strip
89
+ end
90
+ hash['lxc_bin'] = Pathname(`sudo which lxc-create`.strip).parent.to_s
91
+ hash['ruby'] = Gem.ruby
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end