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.



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

def initialize opts
  @ns = opts[:ns] or fail "no namespace specified"
  @rev = opts[:rev] or fail "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.



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

def deserializer
  @deserializer
end

#profileObject (readonly)

Returns the value of attribute profile.



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

def profile
  @profile
end

#profile_summaryObject (readonly)

Returns the value of attribute profile_summary.



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

def profile_summary
  @profile_summary
end

#profilingObject

Returns the value of attribute profiling.



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

def profiling
  @profiling
end

#revObject

Returns the value of attribute rev.



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

def rev
  @rev
end

Class Method Details

.add_extension_dir(dir) ⇒ Object



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

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

.extension_dirsObject



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

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

.loaderObject



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

def self.loader; @loader; end

.reload_extensionsObject



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

def self.reload_extensions
  @loader.reload_extensions
end

.type(name) ⇒ Object



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/rbvmomi/connection.rb', line 197

def self.type name
  fail 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
    if first_char.downcase == first_char
      name = "%s%s" % [first_char.upcase, name[1..-1]]
    end

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

Instance Method Details

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



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

def call method, desc, this, params
  fail "this is not a managed object" unless this.is_a? BasicTypes::ManagedObject
  fail "parameters must be passed as a hash" unless params.is_a? Hash
  fail 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



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

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
        fail "missing required parameter #{d['name']}" unless d['is-optional']
      end
    end
  end
end

#instanceUuidObject



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

def instanceUuid
  nil
end

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

hic sunt dracones



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

def obj2xml xml, name, type, is_array, o, attrs={}
  expected = type(type)
  fail "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
      fail "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
      fail "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
    fail "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
    if expected and not expected >= o.class and not expected == BasicTypes::AnyType
      fail "expected #{expected.wsdl_name} for '#{name}', got #{o.class.wsdl_name} for field #{name.inspect}"
    end
    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
      fail "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
    fail "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 fail "unexpected object class #{o.class} for '#{name}'"
  end
  xml
rescue
  $stderr.puts "#{$!.class} while serializing #{name} (#{type}):"
  PP.pp o, $stderr
  raise
end

#parse_response(resp, desc) ⇒ Object



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

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
      fail "#{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



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

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

#type(name) ⇒ Object



223
224
225
# File 'lib/rbvmomi/connection.rb', line 223

def type name
  self.class.type name
end