Module: Mixlib::ShellOut::Windows

Includes:
Windows::Handle, Windows::Process, Windows::Synchronize
Included in:
Mixlib::ShellOut
Defined in:
lib/mixlib/shellout/windows.rb

Defined Under Namespace

Modules: Utils Classes: ThingThatLooksSortOfLikeAProcessStatus

Constant Summary collapse

TIME_SLICE =
0.05

Instance Method Summary collapse

Instance Method Details

#run_commandObject

– Missing lots of features from the UNIX version, such as uid, etc.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/mixlib/shellout/windows.rb', line 50

def run_command

  #
  # Create pipes to capture stdout and stderr,
  #
  stdout_read, stdout_write = IO.pipe
  stderr_read, stderr_write = IO.pipe
  stdin_read, stdin_write = IO.pipe
  open_streams = [ stdout_read, stderr_read ]

  begin

    #
    # Set cwd, environment, appname, etc.
    #
    app_name, command_line = command_to_run(self.command)
    create_process_args = {
      :app_name => app_name,
      :command_line => command_line,
      :startup_info => {
        :stdout => stdout_write,
        :stderr => stderr_write,
        :stdin => stdin_read
      },
      :environment => inherit_environment.map { |k,v| "#{k}=#{v}" },
      :close_handles => false
    }
    create_process_args[:cwd] = cwd if cwd
    # default to local account database if domain is not specified
    create_process_args[:domain] = domain.nil? ? "." : domain
    create_process_args[:with_logon] = with_logon if with_logon
    create_process_args[:password] = password if password

    #
    # Start the process
    #
    process = Process.create(create_process_args)
    begin
      # Start pushing data into input
      stdin_write << input if input

      # Close pipe to kick things off
      stdin_write.close

      #
      # Wait for the process to finish, consuming output as we go
      #
      start_wait = Time.now
      while true
        wait_status = WaitForSingleObject(process.process_handle, 0)
        case wait_status
        when WAIT_OBJECT_0
          # Get process exit code
          exit_code = [0].pack('l')
          unless GetExitCodeProcess(process.process_handle, exit_code)
            raise get_last_error
          end
          @status = ThingThatLooksSortOfLikeAProcessStatus.new
          @status.exitstatus = exit_code.unpack('l').first

          return self
        when WAIT_TIMEOUT
          # Kill the process
          if (Time.now - start_wait) > timeout
            begin
              Process.kill(:KILL, process.process_id)
            rescue Errno::EIO
              logger.warn("Failed to kill timed out process #{process.process_id}") if logger
            end

            raise Mixlib::ShellOut::CommandTimeout, "command timed out:\n#{format_for_exception}"
          end

          consume_output(open_streams, stdout_read, stderr_read)
        else
          raise "Unknown response from WaitForSingleObject(#{process.process_handle}, #{timeout*1000}): #{wait_status}"
        end

      end

    ensure
      CloseHandle(process.thread_handle) if process.thread_handle
      CloseHandle(process.process_handle) if process.process_handle
    end

  ensure
    #
    # Consume all remaining data from the pipes until they are closed
    #
    stdout_write.close
    stderr_write.close

    while consume_output(open_streams, stdout_read, stderr_read)
    end
  end
end

#validate_options(opts) ⇒ Object

Option validation that is windows specific



39
40
41
42
43
44
45
# File 'lib/mixlib/shellout/windows.rb', line 39

def validate_options(opts)
  if opts[:user]
    unless opts[:password]
      raise InvalidCommandOption, "You must supply both a username and password when supplying a user in windows"
    end
  end
end