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