lib/wbem/wsman.rb in wbem-0.2.6 vs lib/wbem/wsman.rb in wbem-0.2.8
- old
+ new
@@ -18,47 +18,189 @@
def Transport.auth_request_callback( client, auth_type )
STDERR.puts "\t *** Transport.auth_request_callback"
return nil
end
end
+ #
+ # Capture Fault as Exception
+ #
+ class Exception < ::RuntimeError
+ def initialize fault
+ unless fault.is_a? Openwsman::Fault
+ raise "#{fault} is not a fault" unless fault.fault?
+ fault = Openwsman::Fault.new fault
+ end
+ @fault = fault
+ end
+ def to_s
+ "Fault code #{@fault.code}, subcode #{@fault.subcode}" +
+ "\n\treason #{@fault.reason}" +
+ "\n\tdetail #{@fault.detail}"
+ end
+ end
+ #
+ # Capture namespace, classname, and properties as ObjectPath
+ #
class ObjectPath
- attr_reader :namespace, :classname
- def initialize namespace, classname = nil
+ attr_reader :namespace, :classname, :properties
+ def initialize namespace, classname = nil, properties = {}
@namespace = namespace
@classname = classname
+ @properties = properties
end
end
- # Provide Cim::ObjectPath like accessors
+ #
+ # Provide Cim::ObjectPath like accessors for EndPointReference
+ #
class EndPointReference
- alias keys selector_names
- alias key_count selector_count
- alias add_key add_selector
+ alias :keys :selector_names
+ alias :key_count :selector_count
+ alias :add_key :add_selector
def each_key
keys.each { |key| yield key }
end
end
+ #
+ # Capture XmlDoc + WsmanClient as Instance
+ #
+ class Instance
+ def initialize node, client, epr_or_uri
+ @node = (node.is_a? Openwsman::XmlDoc) ? node.body : node
+ @epr = (epr_or_uri.is_a? Openwsman::EndPointReference) ? epr_or_uri : Openwsman::EndPointReference.new(epr_or_uri)
+ @client = client
+ end
+ #
+ #
+ #
+ def to_s
+ "Instance #{@client}\n\t#{@epr}\n\t#{@node.to_xml}"
+ end
+ #
+ # Instance#<property>
+ # Instance#<method>(<args>)
+ #
+ def method_missing name, *args
+ if args.empty?
+ # try property first
+ res = @node.send name
+ return res.text if res
+ end
+ # try as method invocation
+ options = Openwsman::ClientOptions.new
+ options.set_dump_request
+ selectors = {}
+ @epr.each do |k,v|
+ selectors[k] = v
+ end
+ options.selectors = selectors # instance key properties
+ uri = @epr.resource_uri
+
+ #
+ # get method input parameter information
+ #
+ classname = @epr.classname
+ s = "mof/#{classname}"
+ begin
+ require s
+ rescue LoadError
+ raise RuntimeError.new "Cannot load #{s} for type information"
+ end
+ methods = MOF.class_eval "#{classname}::METHODS"
+ method = methods[name.to_s]
+ raise RuntimeError.new("Unknown method #{name} for #{classname}") unless method
+ result_type = method[:type]
+ parameters = method[:parameters] || {}
+ input = parameters[:in]
+ output = parameters[:out]
+ argsin = {}
+ i = 0
+ if input
+ while i < input.size
+ value = args.shift
+ raise "Argument for #{input[i]} is nil, not allowed !" unless value
+ argsin[input[i]] = value
+ # FIXME more typecheck of args ?
+ i += 2
+ end
+ end
+ STDERR.puts "\n\tproperties #{argsin.inspect}\n"
+ options.properties = argsin
+ #
+ # output parameters ?
+ #
+ argsout = nil
+ if output
+ if args.empty?
+ raise "Function #{name} has output arguments, please add an empty hash to the call"
+ end
+ argsout = args.shift
+ unless argsout.kind_of? Hash
+ raise "Function #{name} has output arguments, last argument must be a Hash"
+ end
+ unless args.empty?
+ raise "Function call to #{name} has excess arguments"
+ end
+ end
+ STDERR.puts "\n\targsout #{argsout.inspect}\n"
+Openwsman.debug = -1
+ STDERR.puts "\n\tinvoke #{uri}.#{name}\n"
+ res = @client.client.invoke(options, uri, name.to_s)
+ raise Openwsman::Exception.new(res) if res.fault?
+ STDERR.puts "\n\tresult #{res.to_xml}\n"
+ result = res.find(uri, "#{name}_OUTPUT").find(uri, "ReturnValue").text
+ case result_type
+ when :boolean
+ result == "true" ? true : false
+ when :uint8, :uint16, :uint32, :uint64
+ result.to_i
+ when :string
+ result
+ when :float
+ result.to_f
+ when :datetime
+ else
+ raise "Unsupported result_type #{result_type.inspect}"
+ end
+ end
+ end
end
+
module Wbem
class WsmanClient < WbemClient
private
#
+ # create end point reference URI
+ #
+ def epr_uri_for(namespace,classname)
+ case @product
+ when :winrm
+ # winrm embeds namespace in resource URI
+ Openwsman::epr_uri_for(namespace,classname) rescue "http://schema.suse.com/wbem/wscim/1/cim-schema/2/#{namespace}/#{classname}"
+ else
+ (Openwsman::epr_prefix_for(classname)+"/#{classname}") rescue "http://schema.suse.com/wbem/wscim/1/cim-schema/2/#{classname}"
+ end
+ end
+
+ #
# Handle client connection or protocol fault
#
# @return: true if fault
#
def _handle_fault client, result
if result.nil?
- STDERR.puts "Client connection failed:\n\tResult code #{@client.response_code}, Fault: #{@client.fault_string}"
+ STDERR.puts "Client connection failed:\n\tResult code #{client.response_code}, Fault: #{client.fault_string}" if Wbem.debug
return true
end
if result.fault?
fault = Openwsman::Fault.new result
- STDERR.puts "Client protocol failed for (#{uri})"
- STDERR.puts "\tFault code #{fault.code}, subcode #{fault.subcode}"
- STDERR.puts "\t\treason #{fault.reason}"
- STDERR.puts "\t\tdetail #{fault.detail}"
+ if Wbem.debug
+ STDERR.puts "Client protocol failed for (#{client})"
+ STDERR.puts "\tFault code #{fault.code}, subcode #{fault.subcode}"
+ STDERR.puts "\t\treason #{fault.reason}"
+ STDERR.puts "\t\tdetail #{fault.detail}"
+ end
return true
end
false
end
#
@@ -71,17 +213,18 @@
unless doc
raise RuntimeError.new "Identify failed: HTTP #{@client.response_code}, Err #{@client.last_error}:#{@client.fault_string}"
end
if doc.fault?
fault = doc.fault
- STDERR.puts "Fault: #{fault.to_xml}"
- raise fault.to_s
+ STDERR.puts "Fault: #{fault.to_xml}" if Wbem.debug
+ raise Openwsman::Exception.new fault
end
# STDERR.puts "Return #{doc.to_xml}"
doc
end
public
+ attr_reader :client
def initialize uri, auth_scheme = nil
super uri, auth_scheme
@url.path = "/wsman" if @url.path.nil? || @url.path.empty?
# Openwsman::debug = -1
@@ -90,11 +233,11 @@
@client = Openwsman::Client.new @url.to_s
raise "Cannot create Openwsman client" unless @client
@client.transport.timeout = 5
@client.transport.verify_peer = 0
@client.transport.verify_host = 0
- case @auth_scheme
+ case @auth_scheme.to_s
when nil, ""
@client.transport.auth_method = nil # negotiate
when /none/i
@client.transport.auth_method = Openwsman::NO_AUTH_STR
when /basic/i
@@ -170,54 +313,84 @@
end
STDERR.puts "Connected to vendor '#{@product_vendor}', Version #{@product_version}" if Wbem.debug
end
- def objectpath classname, namespace
- Openwsman::ObjectPath.new classname, namespace
+public
+ #
+ # return list of namespaces
+ #
+ def namespaces ns = "root", cn = "__Namespace"
+ result = []
+ each_instance( ns, cn ) do |inst|
+ name = "#{ns}/#{inst.Name}"
+ result << name
+ result.concat namespaces name, cn
+ end
+ result.uniq
end
- def each_instance( ns, cn )
+ #
+ # Create ObjectPath from namespace, classname, and properties
+ #
+ def objectpath namespace, classname = nil, properties = {}
+ Openwsman::ObjectPath.new namespace, classname, properties
+ end
+
+ #
+ # Enumerate instances
+ #
+ def each_instance( namespace_or_objectpath, classname = nil )
+ op = if namespace_or_objectpath.is_a? Openwsman::ObjectPath
+ namespace_or_objectpath
+ else
+ objectpath namespace_or_objectpath, classname
+ end
@options.flags = Openwsman::FLAG_ENUMERATION_OPTIMIZATION
@options.max_elements = 999
- resource = "#{@prefix}#{ns}/#{cn}"
- result = @client.enumerate( @options, nil, resource )
+ uri = epr_uri_for op.namespace, op.classname
+ result = @client.enumerate( @options, nil, uri )
loop do
if _handle_fault @client, result
break
end
items = result.Items rescue nil
if items
items.each do |inst|
- yield inst
+ yield Openwsman::Instance.new(inst, self, uri)
end
end
context = result.context
break unless context
- result = @client.pull( @options, nil, resource, context )
+ result = @client.pull( @options, nil, uri, context )
end
end
- def class_names namespace, deep_inheritance = false
+ #
+ # Enumerate class names
+ #
+ def class_names op, deep_inheritance = false
@options.flags = Openwsman::FLAG_ENUMERATION_OPTIMIZATION
@options.max_elements = 999
- @options.cim_namespace = namespace if @product == :openwsman
+ namespace = (op.is_a? Sfcc::ObjectPath) ? op.namespace : op
+ classname = (op.is_a? Sfcc::ObjectPath) ? op.classname : nil
case @product
when :openwsman
- unless @product_version >= "2.2"
+ if @product_version < "2.2"
STDERR.puts "ENUMERATE_CLASS_NAMES unsupported for #{@product_vendor} #{@product_version}, please upgrade"
return []
end
method = Openwsman::CIM_ACTION_ENUMERATE_CLASS_NAMES
uri = Openwsman::XML_NS_CIM_INTRINSIC
+ @options.cim_namespace = namespace
@options.add_selector("DeepInheritance", "True") if deep_inheritance
result = @client.invoke( @options, uri, method )
when :winrm
# see https://github.com/kkaempf/openwsman/blob/master/bindings/ruby/tests/winenum.rb
filter = Openwsman::Filter.new
query = "select * from meta_class"
- query << " where __SuperClass is null" unless deep_inheritance
+ query << " where __SuperClass is #{classname?classname:'null'}" unless deep_inheritance
filter.wql query
uri = "#{@prefix}#{namespace}/*"
result = @client.enumerate( @options, filter, uri )
else
raise "Unsupported for WSMAN product #{@product}"
@@ -245,23 +418,47 @@
end if output
context = result.context
break unless context
# get the next chunk
result = @client.pull( @options, nil, uri, context)
- break if _handle_fault
+ break if _handle_fault @client, result
end
end
return classes
end
- def instance_names namespace, classname
+ #
+ # Return list of Wbem::EndpointReference (object pathes) for instances
+ # of namespace, classname
+ # @param namespace : String or Sfcc::Cim::ObjectPath
+ # @param classname : String (optional)
+ # @param properties : Hash (optional)
+ #
+ def instance_names namespace, classname=nil, properties = {}
+ case namespace
+ when Openwsman::ObjectPath
+ classname = namespace.classname
+ properties = namespace.properties
+ namespace = namespace.namespace
+ uri = epr_uri_for(namespace,classname)
+ when Openwsman::EndPointReference
+ namespace.each do |k,v|
+ properties[k] = v
+ end
+ classname = namespace.classname
+ uri = namespace.resource_uri
+ namespace = namespace.namespace
+ else
+ uri = epr_uri_for(namespace, classname)
+ end
@options.flags = Openwsman::FLAG_ENUMERATION_ENUM_EPR # get EPRs
@options.flags = Openwsman::FLAG_ENUMERATION_OPTIMIZATION
@options.max_elements = 999
@options.cim_namespace = namespace if @product == :openwsman
@options.set_dump_request
- uri = Openwsman::epr_prefix_for(classname, namespace) + "/#{classname}"
+ @options.selectors = properties unless properties.empty?
+ start = Time.now
STDERR.puts "instance_names enumerate (#{uri})"
result = @client.enumerate( @options, nil, uri )
names = []
loop do
if _handle_fault @client, result
@@ -276,10 +473,44 @@
end
context = result.context
break unless context
result = @client.pull( @options, nil, uri, context )
end
+ STDERR.puts "Enumerated #{names.size} items in #{Time.now-start} seconds"
return names
end
-
+
+ #
+ # Return matching Wbem::Instance for first instance
+ # matching namespace, classname, properties
+ # @param namespace : String or Sfcc::Cim::ObjectPath
+ # @param classname : String (optional)
+ # @param properties : Hash (optional)
+ #
+ def get_instance namespace, classname=nil, properties={}
+ case namespace
+ when Openwsman::ObjectPath
+ classname = namespace.classname
+ properties = namespace.properties
+ namespace = namespace.namespace
+ uri = epr_uri_for(namespace, classname)
+ when Openwsman::EndPointReference
+ namespace.each do |k,v|
+ properties[k] = v
+ end
+ classname = namespace.classname
+ uri = namespace.resource_uri
+ namespace = namespace.namespace
+ else
+ uri = epr_uri_for(namespace, classname)
+ end
+ @options.set_dump_request
+ @options.cim_namespace = namespace if @product == :openwsman
+ @options.selectors = properties unless properties.empty?
+ STDERR.puts "@client.get(namepace '#{@options.cim_namespace}', props #{properties.inspect}, uri #{uri}"
+ res = @client.get(@options, uri)
+ raise Openwsman::Exception.new res if res.fault?
+ Openwsman::Instance.new res, self, Openwsman::EndPointReference.new(uri, "", properties)
+ end
+
end
-end # module
\ No newline at end of file
+end # module