def action(name, opts=nil)
      @triggers.fire_triggers(name, :before, @name.to_s, :action)

      @logger.info("Calling action: #{name} on provider #{@provider}")

      opts ||= {}

      # Determine whether we lock or not
      lock = true
      lock = opts.delete(:lock) if opts.key?(:lock)

      # Extra env keys are the remaining opts
      extra_env = opts.dup
      # An environment is required for triggers to function properly. This is
      # passed in specifically for the `#Action::Warden` class triggers. We call it
      # `:trigger_env` instead of `env` in case it collides with an existing environment
      extra_env[:trigger_env] = @env

      check_cwd # Warns the UI if the machine was last used on a different dir

      # Create a deterministic ID for this machine
      vf = nil
      vf = @env.vagrantfile_name[0] if @env.vagrantfile_name
      id = Digest::MD5.hexdigest(
        "#{@env.root_path}#{vf}#{@env.local_data_path}#{@name}")

      # We only lock if we're not executing an SSH action. In the future
      # we will want to do more fine-grained unlocking in actions themselves
      # but for a 1.6.2 release this will work.
      locker = Proc.new { |*args, &block| block.call }
      locker = @env.method(:lock) if lock && !name.to_s.start_with?("ssh")

      # Lock this machine for the duration of this action
      return_env = locker.call("machine-action-#{id}") do
        # Get the callable from the provider.
        callable = @provider.action(name)

        # If this action doesn't exist on the provider, then an exception
        # must be raised.
        if callable.nil?
          raise Errors::UnimplementedProviderAction,
            action: name,
            provider: @provider.to_s
        end

        # Call the action
        ui.machine("action", name.to_s, "start")
        action_result = action_raw(name, callable, extra_env)
        ui.machine("action", name.to_s, "end")
        action_result
      end

      @triggers.fire_triggers(name, :after, @name.to_s, :action)
      # preserve returning environment after machine action runs
      return return_env
    rescue Errors::EnvironmentLockedError
      raise Errors::MachineActionLockedError,
        action: name,
        name: @name
    end
def action(name, opts=nil)
      @triggers.fire_triggers(name, :before, @name.to_s, :action)

      @logger.info("Calling action: #{name} on provider #{@provider}")

      opts ||= {}

      # Determine whether we lock or not
      lock = true
      lock = opts.delete(:lock) if opts.key?(:lock)

      # Extra env keys are the remaining opts
      extra_env = opts.dup
      # An environment is required for triggers to function properly. This is
      # passed in specifically for the `#Action::Warden` class triggers. We call it
      # `:trigger_env` instead of `env` in case it collides with an existing environment
      extra_env[:trigger_env] = @env

      check_cwd # Warns the UI if the machine was last used on a different dir

      # Create a deterministic ID for this machine
      vf = nil
      vf = @env.vagrantfile_name[0] if @env.vagrantfile_name
      id = Digest::MD5.hexdigest(
        "#{@env.root_path}#{vf}#{@env.local_data_path}#{@name}")

      # We only lock if we're not executing an SSH action. In the future
      # we will want to do more fine-grained unlocking in actions themselves
      # but for a 1.6.2 release this will work.
      locker = Proc.new { |*args, &block| block.call }
      locker = @env.method(:lock) if lock && !name.to_s.start_with?("ssh")

      # Lock this machine for the duration of this action
      return_env = locker.call("machine-action-#{id}") do
        # Get the callable from the provider.
        callable = @provider.action(name)

        # If this action doesn't exist on the provider, then an exception
        # must be raised.
        if callable.nil?
          raise Errors::UnimplementedProviderAction,
            action: name,
            provider: @provider.to_s
        end

        # Call the action
        ui.machine("action", name.to_s, "start")
        action_result = action_raw(name, callable, extra_env)
        ui.machine("action", name.to_s, "end")
        action_result
      end

      @triggers.fire_triggers(name, :after, @name.to_s, :action)
      # preserve returning environment after machine action runs
      return return_env
    rescue Errors::EnvironmentLockedError
      raise Errors::MachineActionLockedError,
        action: name,
        name: @name
    end
Initialize a new machine.

 @param [String] name Name of the virtual machine.
 @param [Class] provider The provider backing this machine. This is
   currently expected to be a V1 `provider` plugin.
 @param [Object] provider_config The provider-specific configuration for
   this machine.
 @param [Hash] provider_options The provider-specific options from the
   plugin definition.
 @param [Object] config The configuration for this machine.
 @param [Pathname] data_dir The directory where machine-specific data
   can be stored. This directory is ensured to exist.
 @param [Box] box The box that is backing this virtual machine.
 @param [Environment] env The environment that this machine is a
   part of.
 This calls an action on the provider. The provider may or may not
 actually implement the action.

 @param [Symbol] name Name of the action to run.
 @param [Hash] extra_env This data will be passed into the action runner
   as extra data set on the environment hash for the middleware
   runner.