Class: Chef::Knife::Winrm

Inherits:
Chef::Knife show all
Includes:
WinrmBase
Defined in:
lib/chef/knife/winrm.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from WinrmBase

included

Instance Attribute Details

#password=(value) ⇒ Object (writeonly)

Sets the attribute password

Parameters:

  • value

    the value to set the attribute password to.



34
35
36
# File 'lib/chef/knife/winrm.rb', line 34

def password=(value)
  @password = value
end

Instance Method Details

#check_for_errors!(exit_codes) ⇒ Object



222
223
224
225
226
227
228
229
230
231
# File 'lib/chef/knife/winrm.rb', line 222

def check_for_errors!(exit_codes)

  exit_codes.each do |host, value|
    unless Chef::Config[:knife][:returns].include? value.to_i
      @exit_code = 1
      ui.error "Failed to execute command on #{host} return code #{value}"
    end
  end

end

#configure_sessionObject



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
# File 'lib/chef/knife/winrm.rb', line 78

def configure_session
  list = case config[:manual]
         when true
           @name_args[0].split(" ")
         when false
           r = Array.new
           q = Chef::Search::Query.new
           @action_nodes = q.search(:node, @name_args[0])[0]
           @action_nodes.each do |item|
             i = format_for_display(item)[config[:address_attribute]]
             r.push(i) unless i.nil?
           end
           r
         end
  if list.length == 0
    if @action_nodes.length == 0
      ui.fatal("No nodes returned from search!")
    else
      p format_for_display(@action_nodes[0])#['fqdn']
      p @action_nodes[0]
      ui.fatal("#{@action_nodes.length} #{@action_nodes.length > 1 ? "nodes":"node"} found, " +
               "but does not have the required attribute (#{config[:address_attribute]}) to establish the connection. " +
               "Try setting another attribute to open the connection using --address_attribute.")
    end
    exit 10
  end
  session_from_list(list)
end

#get_passwordObject



163
164
165
# File 'lib/chef/knife/winrm.rb', line 163

def get_password
  @password ||= ui.ask("Enter your password: ") { |q| q.echo = false }
end

#interactiveObject



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/chef/knife/winrm.rb', line 192

def interactive
  puts "Connected to #{ui.list(session.servers.collect { |s| ui.color(s.host, :cyan) }, :inline, " and ")}"
  puts
  puts "To run a command on a list of servers, do:"
  puts "  on SERVER1 SERVER2 SERVER3; COMMAND"
  puts "  Example: on latte foamy; echo foobar"
  puts
  puts "To exit interactive mode, use 'quit!'"
  puts
  while 1
    command = read_line
    case command
    when 'quit!'
      puts 'Bye!'
      session.close
      break
    when /^on (.+?); (.+)$/
      raw_list = $1.split(" ")
      server_list = Array.new
      session.servers.each do |session_server|
        server_list << session_server if raw_list.include?(session_server.host)
      end
      command = $2
      winrm_command(command, session.on(*server_list))
    else
      winrm_command(command)
    end
  end
end


147
148
149
150
151
152
153
154
155
156
# File 'lib/chef/knife/winrm.rb', line 147

def print_data(host, data, color = :cyan)
  if data =~ /\n/
    data.split(/\n/).each { |d| print_data(host, d, color) }
  else
    padding = @longest - host.length
    print ui.color(host, color)
    padding.downto(0) { print " " }
    puts data.chomp
  end
end

#read_lineObject

Present the prompt and read a single line from the console. It also detects ^D and returns “exit” in that case. Adds the input to the history, unless the input is empty. Loops repeatedly until a non-empty line is input.



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/chef/knife/winrm.rb', line 171

def read_line
  loop do
    command = reader.readline("#{ui.color('knife-winrm>', :bold)} ", true)

    if command.nil?
      command = "exit"
      puts(command)
    else
      command.strip!
    end

    unless command.empty?
      return command
    end
  end
end

#readerObject



188
189
190
# File 'lib/chef/knife/winrm.rb', line 188

def reader
  Readline
end

#runObject



233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/chef/knife/winrm.rb', line 233

def run
  STDOUT.sync = STDERR.sync = true

  begin
    @longest = 0

    configure_session

    case @name_args[1]
    when "interactive"
      interactive
    else
      winrm_command(@name_args[1..-1].join(" "))

      if config[:returns]
        check_for_errors! session.exit_codes
      end

      session.close
      @exit_code || 0
    end
  rescue WinRM::WinRMHTTPTransportError => e
    case e.message
    when /401/
      ui.error "Failed to authenticate to #{@name_args[0].split(" ")} as #{config[:winrm_user]}"
      ui.info "Response: #{e.message}"
    else
      raise e
    end
  end
end

#sessionObject



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/chef/knife/winrm.rb', line 58

def session
  session_opts = {}
  session_opts[:logger] = Chef::Log.logger if Chef::Log.level == :debug
  @session ||= begin
    s = EventMachine::WinRM::Session.new(session_opts)
    s.on_output do |host, data|
      print_data(host, data)
    end
    s.on_error do |host, err|
      print_data(host, err, :red)
    end
    s.on_command_complete do |host|
      host = host == :all ? 'All Servers' : host
      Chef::Log.debug("command complete on #{host}")
    end
    s
  end

end

#session_from_list(list) ⇒ Object



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/chef/knife/winrm.rb', line 107

def session_from_list(list)
  list.each do |item|
    Chef::Log.debug("Adding #{item}")
    session_opts = {}
    session_opts[:user] = config[:winrm_user] = Chef::Config[:knife][:winrm_user] || config[:winrm_user]
    session_opts[:password] = config[:winrm_password] = Chef::Config[:knife][:winrm_password] || config[:winrm_password]
    session_opts[:port] = Chef::Config[:knife][:winrm_port] || config[:winrm_port]
    session_opts[:keytab] = Chef::Config[:knife][:kerberos_keytab_file] if Chef::Config[:knife][:kerberos_keytab_file]
    session_opts[:realm] = Chef::Config[:knife][:kerberos_realm] if Chef::Config[:knife][:kerberos_realm]
    session_opts[:service] = Chef::Config[:knife][:kerberos_service] if Chef::Config[:knife][:kerberos_service]
    session_opts[:ca_trust_path] = Chef::Config[:knife][:ca_trust_file] if Chef::Config[:knife][:ca_trust_file]
    session_opts[:operation_timeout] = 1800 # 30 min OperationTimeout for long bootstraps fix for KNIFE_WINDOWS-8

    ## If you have a \\ in your name you need to use NTLM domain authentication
    if session_opts[:user].split("\\").length.eql?(2)
      session_opts[:basic_auth_only] = false
    else
      session_opts[:basic_auth_only] = true
    end

    if config.keys.any? {|k| k.to_s =~ /kerberos/ }
      session_opts[:transport] = :kerberos
      session_opts[:basic_auth_only] = false
    else
      session_opts[:transport] = (Chef::Config[:knife][:winrm_transport] || config[:winrm_transport]).to_sym
      session_opts[:disable_sspi] = true
      if session_opts[:user] and
          (not session_opts[:password])
        session_opts[:password] = Chef::Config[:knife][:winrm_password] = config[:winrm_password] = get_password

      end
    end

    session.use(item, session_opts)

    @longest = item.length if item.length > @longest
  end
  session
end

#winrm_command(command, subsession = nil) ⇒ Object



158
159
160
161
# File 'lib/chef/knife/winrm.rb', line 158

def winrm_command(command, subsession=nil)
  subsession ||= session
  subsession.relay_command(command)
end