Class: RbVmomi::Connection

Inherits:
TrivialSoap show all
Defined in:
lib/rbvmomi/connection.rb

Direct Known Subclasses

PBM, SMS, VIM

Constant Summary collapse

NS_XSI =
'http://www.w3.org/2001/XMLSchema-instance'

Instance Attribute Summary collapse

Attributes inherited from TrivialSoap

#cookie, #debug, #http, #operation_id

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from TrivialSoap

#close, #host, on_connect, #request, #restart_http, #soap_envelope

Constructor Details

#initialize(opts) ⇒ Connection

Returns a new instance of Connection.



28
29
30
31
32
33
34
35
# File 'lib/rbvmomi/connection.rb', line 28

def initialize opts
  @ns = opts[:ns] or raise 'no namespace specified'
  @rev = opts[:rev] or raise 'no revision specified'
  @deserializer = Deserializer.new self
  reset_profiling
  @profiling = false
  super opts
end

Instance Attribute Details

#deserializerObject (readonly)

Returns the value of attribute deserializer.



26
27
28
# File 'lib/rbvmomi/connection.rb', line 26

def deserializer
  @deserializer
end

#profileObject (readonly)

Returns the value of attribute profile.



23
24
25
# File 'lib/rbvmomi/connection.rb', line 23

def profile
  @profile
end

#profile_summaryObject (readonly)

Returns the value of attribute profile_summary.



24
25
26
# File 'lib/rbvmomi/connection.rb', line 24

def profile_summary
  @profile_summary
end

#profilingObject

Returns the value of attribute profiling.



25
26
27
# File 'lib/rbvmomi/connection.rb', line 25

def profiling
  @profiling
end

#revObject

Returns the value of attribute rev.



22
23
24
# File 'lib/rbvmomi/connection.rb', line 22

def rev
  @rev
end

Class Method Details

.add_extension_dir(dir) ⇒ Object



239
240
241
242
# File 'lib/rbvmomi/connection.rb', line 239

def self.add_extension_dir dir
  extension_dirs << dir
  @loader.reload_extensions_dir dir if @loader
end

.extension_dirsObject



235
236
237
# File 'lib/rbvmomi/connection.rb', line 235

def self.extension_dirs
  @extension_dirs ||= []
end

.loaderObject



248
# File 'lib/rbvmomi/connection.rb', line 248

def self.loader; @loader; end

.reload_extensionsObject



244
245
246
# File 'lib/rbvmomi/connection.rb', line 244

def self.reload_extensions
  @loader.reload_extensions
end

.type(name) ⇒ Object



202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/rbvmomi/connection.rb', line 202

def self.type name
  raise unless name and (name.is_a? String or name.is_a? Symbol)

  name = $' if name.to_s =~ /^xsd:/
  case name.to_sym
  when :anyType then BasicTypes::AnyType
  when :boolean then BasicTypes::Boolean
  when :string then String
  when :int, :long, :short, :byte then Integer
  when :float, :double then Float
  when :dateTime then Time
  when :base64Binary then BasicTypes::Binary
  when :KeyValue then BasicTypes::KeyValue
  else
    first_char = name[0].chr
    name = '%s%s' % [first_char.upcase, name[1..-1]] if first_char.downcase == first_char

    if @loader.has? name
      const_get(name)
    else
      raise "no such type #{name.inspect}"
    end
  end
end

Instance Method Details

#call(method, desc, this, params) ⇒ Object



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
# File 'lib/rbvmomi/connection.rb', line 79

def call method, desc, this, params
  raise 'this is not a managed object' unless this.is_a? BasicTypes::ManagedObject
  raise 'parameters must be passed as a hash' unless params.is_a? Hash
  raise unless desc.is_a? Hash

  t1 = Time.now
  body = soap_envelope do |xml|
    emit_request xml, method, desc['params'], this, params
  end.target!

  t2 = Time.now
  resp, resp_size = request "#{@ns}/#{@rev}", body

  t3 = Time.now
  out = parse_response resp, desc['result']

  if @profiling
    t4 = Time.now
    @profile[method] ||= []
    profile_info = {
      network_latency: (t3 - t2),
      request_emit: t2 - t1,
      response_parse: t4 - t3,
      params: params,
      obj: this,
      backtrace: caller,
      request_size: body.length,
      response_size: resp_size,
    }
    @profile[method] << profile_info
    @profile_summary[:network_latency] += profile_info[:network_latency]
    @profile_summary[:response_parse] += profile_info[:response_parse]
    @profile_summary[:request_emit] += profile_info[:request_emit]
    @profile_summary[:num_calls] += 1
  end

  out
end

#emit_request(xml, method, descs, this, params) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/rbvmomi/connection.rb', line 42

def emit_request xml, method, descs, this, params
  xml.tag! method, xmlns: @ns do
    obj2xml xml, '_this', 'ManagedObject', false, this
    descs.each do |d|
      k = d['name']
      k = k.to_sym if !params.member?(k) && params.member?(k.to_sym)
      v = params[k]
      if not v == nil
        obj2xml xml, d['name'], d['wsdl_type'], d['is-array'], v
      else
        raise "missing required parameter #{d['name']}" unless d['is-optional']
      end
    end
  end
end

#instanceUuidObject



231
232
233
# File 'lib/rbvmomi/connection.rb', line 231

def instanceUuid
  nil
end

#obj2xml(xml, name, type, is_array, o, attrs = {}) ⇒ Object

hic sunt dracones



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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/rbvmomi/connection.rb', line 119

def obj2xml xml, name, type, is_array, o, attrs={}
  expected = type(type)
  raise "expected array for '#{name}', got #{o.class.wsdl_name}" if is_array and not (o.is_a? Array or (o.is_a? Hash and expected == BasicTypes::KeyValue))

  case o
  when Array, BasicTypes::KeyValue
    if o.is_a? BasicTypes::KeyValue and expected != BasicTypes::KeyValue
      raise "expected #{expected.wsdl_name} for '#{name}', got KeyValue"
    elsif expected == BasicTypes::KeyValue and not is_array
      xml.tag! name, attrs do
        xml.tag! 'key', o[0].to_s
        xml.tag! 'value', o[1].to_s
      end
    else
      raise "expected #{expected.wsdl_name} for '#{name}', got array" unless is_array

      o.each do |e|
        obj2xml xml, name, expected.wsdl_name, false, e, attrs
      end
    end
  when BasicTypes::ManagedObject, BasicTypes::OpaqueObject
    raise "expected #{expected.wsdl_name} for '#{name}', got #{o.class.wsdl_name} for field #{name.inspect}" if expected and not expected >= o.class and not expected == BasicTypes::AnyType

    xml.tag! name, o._ref, type: o.class.wsdl_name
  when BasicTypes::DataObject
    raise "expected #{expected.wsdl_name} for '#{name}', got #{o.class.wsdl_name} for field #{name.inspect}" if expected and not expected >= o.class and not expected == BasicTypes::AnyType

    xml.tag! name, attrs.merge('xsi:type' => o.class.wsdl_name) do
      o.class.full_props_desc.each do |desc|
        if o.props.member? desc['name'].to_sym
          v = o.props[desc['name'].to_sym]
          next if v.nil?

          obj2xml xml, desc['name'], desc['wsdl_type'], desc['is-array'], v
        end
      end
    end
  when BasicTypes::Enum
    xml.tag! name, o.value.to_s, attrs
  when Hash
    if expected == BasicTypes::KeyValue and is_array
      obj2xml xml, name, type, is_array, o.to_a, attrs
    else
      raise "expected #{expected.wsdl_name} for '#{name}', got a hash" unless expected <= BasicTypes::DataObject

      obj2xml xml, name, type, false, expected.new(o), attrs
    end
  when true, false
    raise "expected #{expected.wsdl_name} for '#{name}', got a boolean" unless [BasicTypes::Boolean, BasicTypes::AnyType].member? expected

    attrs['xsi:type'] = 'xsd:boolean' if expected == BasicTypes::AnyType
    xml.tag! name, (o ? '1' : '0'), attrs
  when Symbol, String
    if expected == BasicTypes::Binary
      attrs['xsi:type'] = 'xsd:base64Binary' if expected == BasicTypes::AnyType
      xml.tag! name, [o].pack('m').chomp.gsub("\n", ''), attrs
    else
      attrs['xsi:type'] = 'xsd:string' if expected == BasicTypes::AnyType
      xml.tag! name, o.to_s, attrs
    end
  when Integer
    attrs['xsi:type'] = 'xsd:long' if expected == BasicTypes::AnyType
    xml.tag! name, o.to_s, attrs
  when Float
    attrs['xsi:type'] = 'xsd:double' if expected == BasicTypes::AnyType
    xml.tag! name, o.to_s, attrs
  when DateTime
    attrs['xsi:type'] = 'xsd:dateTime' if expected == BasicTypes::AnyType
    xml.tag! name, o.strftime('%FT%T%:z'), attrs
  when Time
    attrs['xsi:type'] = 'xsd:dateTime' if expected == BasicTypes::AnyType
    xml.tag! name, o.iso8601, attrs
  when BasicTypes::Int
    attrs['xsi:type'] = 'xsd:int'
    xml.tag! name, o.to_s, attrs
  else raise "unexpected object class #{o.class} for '#{name}'"
  end
  xml
rescue
  RbVmomi.logger.error("#{$!.class} while serializing #{name} (#{type})\n#{o.pretty_inspect}")
  raise
end

#parse_response(resp, desc) ⇒ Object



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

def parse_response resp, desc
  if resp.at('faultcode')
    detail = resp.at('detail')
    fault = detail && @deserializer.deserialize(detail.children.first, 'MethodFault')
    msg = resp.at('faultstring').text
    if fault
      raise RbVmomi::Fault.new(msg, fault)
    else
      raise "#{resp.at('faultcode').text}: #{msg}"
    end
  else
    if desc
      type = desc['is-task'] ? 'Task' : desc['wsdl_type']
      returnvals = resp.children.select(&:element?).map { |c| @deserializer.deserialize c, type }
      (desc['is-array'] && !desc['is-task']) ? returnvals : returnvals.first
    else
      nil
    end
  end
end

#reset_profilingObject



37
38
39
40
# File 'lib/rbvmomi/connection.rb', line 37

def reset_profiling
  @profile = {}
  @profile_summary = {network_latency: 0, request_emit: 0, response_parse: 0, num_calls: 0}
end

#type(name) ⇒ Object



227
228
229
# File 'lib/rbvmomi/connection.rb', line 227

def type name
  self.class.type name
end