fgrehm/vagrant-lxc

View on GitHub
lib/vagrant-lxc/command/sudoers.rb

Summary

Maintainability
A
0 mins
Test Coverage
require 'tempfile'

require "vagrant-lxc/driver"
require "vagrant-lxc/sudo_wrapper"

module Vagrant
  module LXC
    module Command
      class Sudoers < Vagrant.plugin("2", :command)

        def initialize(argv, env)
          super
          @argv
          @env = env
        end

        def execute
          options = { user: ENV['USER'] }

          opts = OptionParser.new do |opts|
            opts.banner = "Usage: vagrant lxc sudoers"
            opts.separator ""
            opts.on('-u user', '--user user', String, "The user for which to create the policy (defaults to '#{options[:user]}')") do |u|
              options[:user] = u
            end
          end

          argv = parse_options(opts)
          return unless argv

          wrapper_path = SudoWrapper.dest_path
          wrapper = create_wrapper!
          sudoers = create_sudoers!(options[:user], wrapper_path)

          su_copy([
            {source: wrapper, target: wrapper_path, mode: "0555"},
            {source: sudoers, target: sudoers_path, mode: "0440"}
          ])
        end

        def sudoers_path
          "/etc/sudoers.d/vagrant-lxc"
        end

        private

        # This requires vagrant 1.5.2+ https://github.com/mitchellh/vagrant/commit/3371c3716278071680af9b526ba19235c79c64cb
        def create_wrapper!
          lxc_base_path = Driver.new("").containers_path
          wrapper = Tempfile.new('lxc-wrapper').tap do |file|
            template = Vagrant::Util::TemplateRenderer.new(
              'sudoers.rb',
              :template_root  => Vagrant::LXC.source_root.join('templates').to_s,
              :cmd_paths      => build_cmd_paths_hash,
              :lxc_base_path  => lxc_base_path,
              :pipework_regex => "#{ENV['HOME']}/\.vagrant\.d/gems/(?:\\d+?\\.\\d+?\\.\\d+?/)?gems/vagrant-lxc.+/scripts/pipework"
            )
            file.puts template.render
          end
          wrapper.close
          wrapper.path
        end

        def create_sudoers!(user, command)
          sudoers = Tempfile.new('vagrant-lxc-sudoers').tap do |file|
            file.puts "# Automatically created by vagrant-lxc"
            file.puts "#{user} ALL=(root) NOPASSWD: #{command}"
          end
          sudoers.close
          sudoers.path
        end

        def su_copy(files)
          commands = files.map { |file|
            [
              "rm -f #{file[:target]}",
              "cp #{file[:source]} #{file[:target]}",
              "chown root:root #{file[:target]}",
              "chmod #{file[:mode]} #{file[:target]}"
            ]
          }.flatten
          system "echo \"#{commands.join("; ")}\" | sudo sh"
        end

        def build_cmd_paths_hash
          {}.tap do |hash|
            %w( which cat mkdir cp chown chmod rm tar chown ip ifconfig brctl ).each do |cmd|
              hash[cmd] = `sudo which #{cmd}`.strip
            end
            hash['lxc_bin'] = Pathname(`sudo which lxc-create`.strip).parent.to_s
            hash['ruby'] = Gem.ruby
          end
        end
      end
    end
  end
end