rubywbem 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/AUTHORS +1 -0
- data/CHANGELOG +3 -0
- data/LICENSE +339 -0
- data/README +28 -0
- data/Rakefile +146 -0
- data/lib/wbem.rb +23 -0
- data/lib/wbem/cim_constants.rb +50 -0
- data/lib/wbem/cim_http.rb +137 -0
- data/lib/wbem/cim_obj.rb +1148 -0
- data/lib/wbem/cim_operations.rb +571 -0
- data/lib/wbem/cim_types.rb +195 -0
- data/lib/wbem/cim_xml.rb +1428 -0
- data/lib/wbem/tupleparse.rb +1181 -0
- data/lib/wbem/tupletree.rb +138 -0
- data/ruby-wbem.spec +54 -0
- data/testsuite/CIM_DTD_V22.dtd +324 -0
- data/testsuite/comfychair.rb +442 -0
- data/testsuite/runtests.sh +56 -0
- data/testsuite/test_cim_obj.rb +1610 -0
- data/testsuite/test_cim_operations.rb +702 -0
- data/testsuite/test_cim_xml.rb +1495 -0
- data/testsuite/test_nocasehash.rb +248 -0
- data/testsuite/test_tupleparse.rb +208 -0
- data/testsuite/validate.rb +93 -0
- metadata +68 -0
data/lib/wbem.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2006, Red Hat, Inc
|
3
|
+
# Scott Seago <sseago@redhat.com>
|
4
|
+
#
|
5
|
+
# derived from pywbem, written by Tim Potter <tpot@hp.com>, Martin Pool <mbp@hp.com>
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation; either version 2 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# You should have received a copy of the GNU General Public License
|
13
|
+
# along with this program; if not, write to the Free Software
|
14
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
15
|
+
#
|
16
|
+
require "wbem/cim_constants"
|
17
|
+
require "wbem/cim_http"
|
18
|
+
require "wbem/cim_obj"
|
19
|
+
require "wbem/cim_types"
|
20
|
+
require "wbem/cim_operations"
|
21
|
+
require "wbem/cim_xml"
|
22
|
+
require "wbem/tupleparse"
|
23
|
+
require "wbem/tupletree"
|
@@ -0,0 +1,50 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2006, Red Hat, Inc
|
3
|
+
# Scott Seago <sseago@redhat.com>
|
4
|
+
#
|
5
|
+
# derived from pywbem, written by Tim Potter <tpot@hp.com>
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation; either version 2 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# You should have received a copy of the GNU General Public License
|
13
|
+
# along with this program; if not, write to the Free Software
|
14
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
15
|
+
#
|
16
|
+
#"""Useful CIM constants."""
|
17
|
+
|
18
|
+
module WBEM
|
19
|
+
|
20
|
+
# CIMError error code constants
|
21
|
+
|
22
|
+
CIM_ERR_FAILED = 1 # A general error occurred
|
23
|
+
CIM_ERR_ACCESS_DENIED = 2 # Resource not available
|
24
|
+
CIM_ERR_INVALID_NAMESPACE = 3 # The target namespace does not exist
|
25
|
+
CIM_ERR_INVALID_PARAMETER = 4 # Parameter value(s) invalid
|
26
|
+
CIM_ERR_INVALID_CLASS = 5 # The specified Class does not exist
|
27
|
+
CIM_ERR_NOT_FOUND = 6 # Requested object could not be found
|
28
|
+
CIM_ERR_NOT_SUPPORTED = 7 # Operation not supported
|
29
|
+
CIM_ERR_CLASS_HAS_CHILDREN = 8 # Class has subclasses
|
30
|
+
CIM_ERR_CLASS_HAS_INSTANCES = 9 # Class has instances
|
31
|
+
CIM_ERR_INVALID_SUPERCLASS = 10 # Superclass does not exist
|
32
|
+
CIM_ERR_ALREADY_EXISTS = 11 # Object already exists
|
33
|
+
CIM_ERR_NO_SUCH_PROPERTY = 12 # Property does not exist
|
34
|
+
CIM_ERR_TYPE_MISMATCH = 13 # Value incompatible with type
|
35
|
+
CIM_ERR_QUERY_LANGUAGE_NOT_SUPPORTED = 14 # Query language not supported
|
36
|
+
CIM_ERR_INVALID_QUERY = 15 # Query not valid
|
37
|
+
CIM_ERR_METHOD_NOT_AVAILABLE = 16 # Extrinsic method not executed
|
38
|
+
CIM_ERR_METHOD_NOT_FOUND = 17 # Extrinsic method does not exist
|
39
|
+
|
40
|
+
# Provider types
|
41
|
+
|
42
|
+
PROVIDERTYPE_CLASS = 1
|
43
|
+
PROVIDERTYPE_INSTANCE = 2
|
44
|
+
PROVIDERTYPE_ASSOCIATION = 3
|
45
|
+
PROVIDERTYPE_INDICATION = 4
|
46
|
+
PROVIDERTYPE_METHOD = 5
|
47
|
+
PROVIDERTYPE_CONSUMER = 6 # Indication consumer
|
48
|
+
PROVIDERTYPE_QUERY = 7
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2006, Red Hat, Inc
|
3
|
+
# Scott Seago <sseago@redhat.com>
|
4
|
+
#
|
5
|
+
# derived from pywbem, written by Tim Potter <tpot@hp.com>, Martin Pool <mbp@hp.com>
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation; either version 2 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# You should have received a copy of the GNU General Public License
|
13
|
+
# along with this program; if not, write to the Free Software
|
14
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
15
|
+
#
|
16
|
+
|
17
|
+
#'''
|
18
|
+
#This module implements CIM operations over HTTP.
|
19
|
+
#
|
20
|
+
#This module should not know anything about the fact that the data
|
21
|
+
#being transferred is XML. It is up to the caller to format the input
|
22
|
+
#data and interpret the result.
|
23
|
+
#'''
|
24
|
+
|
25
|
+
require "wbem/cim_obj"
|
26
|
+
require "net/https"
|
27
|
+
|
28
|
+
module WBEM
|
29
|
+
class CIMHttpError < Exception
|
30
|
+
# """This exception is raised when a transport error occurs."""
|
31
|
+
end
|
32
|
+
class AuthError < StandardError
|
33
|
+
#"""This exception is raised when an authentication error (401) occurs."""
|
34
|
+
end
|
35
|
+
|
36
|
+
def WBEM.parse_url(url)
|
37
|
+
#"""Return an array of (host, port, ssl, credentials) from the URL parameter.
|
38
|
+
#The returned port defaults to 5988 if not specified. SSL supports
|
39
|
+
#defaults to False if not specified. Credentials are optional
|
40
|
+
#as they may be specified as a separate parameter to
|
41
|
+
#wbem_request. """
|
42
|
+
|
43
|
+
host = url.sub(%r{^https?://}, "") # Eat protocol name
|
44
|
+
port = 5988
|
45
|
+
ssl = false
|
46
|
+
|
47
|
+
if /^https/.match(url) # Set SSL if specified
|
48
|
+
ssl = true
|
49
|
+
port = 5989
|
50
|
+
end
|
51
|
+
|
52
|
+
s = host.split("@") # parse creds if specified
|
53
|
+
if (s.length > 1 )
|
54
|
+
creds = s[0].split(":")
|
55
|
+
host = s[1]
|
56
|
+
end
|
57
|
+
s = host.split(":") # Set port number
|
58
|
+
if (s.length > 1 )
|
59
|
+
host = s[0]
|
60
|
+
port = s[1].to_i
|
61
|
+
end
|
62
|
+
# STDOUT << "host: #{host}, port: #{port}, ssl: #{ssl}, creds: #{creds}\n"
|
63
|
+
return host, port, ssl, creds
|
64
|
+
end
|
65
|
+
|
66
|
+
def WBEM.wbem_request(url, data, creds, headers = [], debug = 0, x509 = nil)
|
67
|
+
#"""Send XML data over HTTP to the specified url. Return the
|
68
|
+
#response in XML. Uses Python's build-in httplib. x509 may be a
|
69
|
+
#dictionary containing the location of the SSL certificate and key
|
70
|
+
#files."""
|
71
|
+
|
72
|
+
host, port, ssl, urlcreds = WBEM.parse_url(url)
|
73
|
+
creds = urlcreds unless creds
|
74
|
+
h = Net::HTTP.new(host, port)
|
75
|
+
if (ssl)
|
76
|
+
if x509
|
77
|
+
cert_file = x509.get("cert_file")
|
78
|
+
key_file = x509.get("key_file", cert_file)
|
79
|
+
else
|
80
|
+
cert_file = nil
|
81
|
+
key_file = nil
|
82
|
+
end
|
83
|
+
h.use_ssl = true
|
84
|
+
# key_file, cert_file ???
|
85
|
+
end
|
86
|
+
data = "<?xml version='1.0' encoding='utf-8' ?>\n" + data
|
87
|
+
response = nil
|
88
|
+
h.start do |http|
|
89
|
+
request = Net::HTTP::Post.new("/cimom")
|
90
|
+
request.basic_auth creds[0], creds[1]
|
91
|
+
request.content_type = "application/xml"
|
92
|
+
request.content_length = data.length
|
93
|
+
headers.each do |header|
|
94
|
+
s = header.split(":", 2).collect { |x| x.strip }
|
95
|
+
request.add_field(URI.escape(s[0]), URI.escape(s[1]))
|
96
|
+
end
|
97
|
+
# STDOUT << "request: #{data}\n"
|
98
|
+
response = http.request(request, data)
|
99
|
+
# STDOUT << "response: #{response.body}\n"
|
100
|
+
end
|
101
|
+
unless response.kind_of?(Net::HTTPSuccess)
|
102
|
+
if (response.kind_of?(NET::HTTPUnauthorized))
|
103
|
+
raise AuthError, response.reason
|
104
|
+
elsif (response.fetch("CIMError", []) or response.fetch("PGErrorDetail", []))
|
105
|
+
raise CIMHttpError, "CIMError: #{response.fetch('CIMError',[])}: #{response.fetch('PGErrorDetail',[])}"
|
106
|
+
end
|
107
|
+
raise CIMHttpError, "HTTP error: #{response.reason}"
|
108
|
+
end
|
109
|
+
# TODO: do we need more error checking here?
|
110
|
+
|
111
|
+
response.body
|
112
|
+
end
|
113
|
+
|
114
|
+
def WBEM.get_object_header(obj)
|
115
|
+
#"""Return the HTTP header required to make a CIM operation request
|
116
|
+
#using the given object. Return None if the object does not need
|
117
|
+
#to have a header."""
|
118
|
+
|
119
|
+
# Local namespacepath
|
120
|
+
|
121
|
+
if obj.kind_of?(String)
|
122
|
+
return "CIMObject: #{obj}"
|
123
|
+
end
|
124
|
+
|
125
|
+
# CIMLocalClassPath
|
126
|
+
|
127
|
+
if obj.kind_of?(CIMLocalClassPath)
|
128
|
+
return "CIMObject: #{obj.localnamespacepath}:#{obj.classname}"
|
129
|
+
end
|
130
|
+
# CIMInstanceName with namespace
|
131
|
+
|
132
|
+
if obj.kind_of?(CIMInstanceName) && !obj.namespace.nil?
|
133
|
+
return 'CIMObject: %s' % obj
|
134
|
+
end
|
135
|
+
raise CIMHttpError, "Don\'t know how to generate HTTP headers for #{obj}"
|
136
|
+
end
|
137
|
+
end
|
data/lib/wbem/cim_obj.rb
ADDED
@@ -0,0 +1,1148 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2006, Red Hat, Inc
|
3
|
+
# Scott Seago <sseago@redhat.com>
|
4
|
+
#
|
5
|
+
# derived from pywbem, written by Tim Potter <tpot@hp.com>, Martin Pool <mbp@hp.com>
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation; either version 2 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# You should have received a copy of the GNU General Public License
|
13
|
+
# along with this program; if not, write to the Free Software
|
14
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
15
|
+
#
|
16
|
+
|
17
|
+
require "wbem/cim_types"
|
18
|
+
require "wbem/cim_xml"
|
19
|
+
require "date"
|
20
|
+
|
21
|
+
#"""
|
22
|
+
#Representations of CIM Objects.
|
23
|
+
#
|
24
|
+
#In general we try to map CIM objects directly into standard Ruby types,
|
25
|
+
#except when that is not possible or would be ambiguous. For example,
|
26
|
+
#CIM Class names are simply strings, but a ClassPath is
|
27
|
+
#represented as a special object.
|
28
|
+
#
|
29
|
+
#These objects can also be mapped back into XML, by the toxml() method
|
30
|
+
#which returns a string.
|
31
|
+
#"""
|
32
|
+
|
33
|
+
#
|
34
|
+
# Base objects
|
35
|
+
#
|
36
|
+
|
37
|
+
module WBEM
|
38
|
+
|
39
|
+
class NocaseHash < Hash
|
40
|
+
|
41
|
+
def initialize(initial_values = {})
|
42
|
+
super()
|
43
|
+
initial_values = initial_values.to_a if initial_values.is_a?(Hash)
|
44
|
+
if initial_values.is_a?(Array)
|
45
|
+
initial_values.each do |item|
|
46
|
+
self[item[0]] = item[1] if item.is_a?(Array)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_key(key)
|
52
|
+
key.is_a?(String) ? key.downcase : key
|
53
|
+
end
|
54
|
+
def [](key)
|
55
|
+
v = super(get_key(key))
|
56
|
+
v[1] unless v.nil?
|
57
|
+
end
|
58
|
+
def []=(key, value)
|
59
|
+
unless key.is_a?(String)
|
60
|
+
raise IndexError, "Key must be a String"
|
61
|
+
end
|
62
|
+
super(get_key(key),[key, value])
|
63
|
+
end
|
64
|
+
alias rawkeys keys
|
65
|
+
alias rawvalues values
|
66
|
+
alias rawarray to_a
|
67
|
+
def keys
|
68
|
+
rawvalues.collect { |v| v[0] }
|
69
|
+
end
|
70
|
+
def values
|
71
|
+
super.collect { |v| v[1] }
|
72
|
+
end
|
73
|
+
def to_a
|
74
|
+
super.collect { |k,v| [v[0], v[1]] }
|
75
|
+
end
|
76
|
+
def each(&block)
|
77
|
+
to_a.each(&block)
|
78
|
+
end
|
79
|
+
def sort
|
80
|
+
rawarray.sort.collect { |k,v| [v[0], v[1]] }
|
81
|
+
end
|
82
|
+
def ==(other)
|
83
|
+
self.each do |key, value|
|
84
|
+
return false unless (other.include?(key) and other[key] == value)
|
85
|
+
end
|
86
|
+
return self.length == other.length
|
87
|
+
end
|
88
|
+
|
89
|
+
def delete(key)
|
90
|
+
super(get_key(key))
|
91
|
+
end
|
92
|
+
def fetch(key)
|
93
|
+
super(get_key(key))[1]
|
94
|
+
end
|
95
|
+
def has_key?(key)
|
96
|
+
super(get_key(key))
|
97
|
+
end
|
98
|
+
def include?(key)
|
99
|
+
super(get_key(key))
|
100
|
+
end
|
101
|
+
def update(otherHash)
|
102
|
+
otherHash.to_a.each { |key, value| self[key] = value }
|
103
|
+
end
|
104
|
+
def clone
|
105
|
+
return NocaseHash.new(self)
|
106
|
+
end
|
107
|
+
alias copy clone
|
108
|
+
end
|
109
|
+
|
110
|
+
class XMLObject
|
111
|
+
#"""Base class for objects that produce cim_xml document fragments."""
|
112
|
+
|
113
|
+
def toxml
|
114
|
+
#"""Return the XML string representation of ourselves."""
|
115
|
+
ret = ""
|
116
|
+
self.tocimxml().write(ret)
|
117
|
+
return ret
|
118
|
+
end
|
119
|
+
def hash
|
120
|
+
self.toxml().hash
|
121
|
+
end
|
122
|
+
# probably not the best equality method, as trivial
|
123
|
+
# differences such as attribute order will affect the results,
|
124
|
+
# but better than the default eql? method defined in object --
|
125
|
+
# subclasses can define this in a better way
|
126
|
+
def eql?(other)
|
127
|
+
(self.toxml == other.toxml)
|
128
|
+
end
|
129
|
+
|
130
|
+
def nilcmp(obj1, obj2)
|
131
|
+
cmpname(obj1, obj2, false)
|
132
|
+
end
|
133
|
+
|
134
|
+
def cmpname(name1, name2, downcase_strings = true)
|
135
|
+
#"""Compare to CIM names. The comparison is done
|
136
|
+
#case-insensitvely, and one or both of the names may be None."""
|
137
|
+
|
138
|
+
if name1.nil? and name2.nil?
|
139
|
+
return 0
|
140
|
+
end
|
141
|
+
unless (name1 || name2)
|
142
|
+
return 0
|
143
|
+
end
|
144
|
+
|
145
|
+
if name1.nil?
|
146
|
+
return -1
|
147
|
+
end
|
148
|
+
|
149
|
+
if name2.nil?
|
150
|
+
return 1
|
151
|
+
end
|
152
|
+
if (downcase_strings)
|
153
|
+
name1.downcase <=> name2.downcase
|
154
|
+
elsif (name2.is_a?(Boolean))
|
155
|
+
(name2 <=> name1)*-1
|
156
|
+
elsif (!name1.methods.include?("<=>"))
|
157
|
+
(name1 == name2) ? 0 : 1
|
158
|
+
elsif ((name1.nil? || name1 == false) &&
|
159
|
+
(name2.nil? || name2 == false))
|
160
|
+
return 0
|
161
|
+
else
|
162
|
+
name1 <=> name2
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
#
|
168
|
+
# Object location classes
|
169
|
+
#
|
170
|
+
|
171
|
+
#
|
172
|
+
# It turns out that most of the object location elements can be
|
173
|
+
# represented easily using one base class which roughly corresponds to
|
174
|
+
# the OBJECTPATH element.
|
175
|
+
#
|
176
|
+
# Element Name (host, namespace, classname, instancename)
|
177
|
+
# ---------------------------------------------------------------------------
|
178
|
+
# CLASSNAME (None, None, 'CIM_Foo', None)
|
179
|
+
# LOCALNAMESPACEPATH (None, 'root/cimv2', None, None)
|
180
|
+
# NAMESPACEPATH ('leonardo', 'root/cimv2', None, None)
|
181
|
+
# LOCALCLASSPATH (None, 'root/cimv2', 'CIM_Foo', None)
|
182
|
+
# CLASSPATH ('leonardo', 'root/cimv2', 'CIM_Foo', None)
|
183
|
+
# LOCALINSTANCEPATH (None, 'root/cimv2', None, InstanceName)
|
184
|
+
# INSTANCEPATH ('leonardo', 'root/cimv2', None, InstanceName)
|
185
|
+
#
|
186
|
+
# These guys also have string representations similar to the output
|
187
|
+
# produced by the Pegasus::CIMObjectPath.toString() method:
|
188
|
+
#
|
189
|
+
# Element Name Python Class String representation
|
190
|
+
# ---------------------------------------------------------------------------
|
191
|
+
# CLASSNAME CIMClassName CIM_Foo
|
192
|
+
# LOCALNAMESPACEPATH String root/cimv2:
|
193
|
+
# NAMESPACEPATH CIMNamespacePath //leo/root/cimv2:
|
194
|
+
# LOCALCLASSPATH CIMLocalClassPath root/cimv2:CIM_Foo
|
195
|
+
# CLASSPATH CIMClassPath //leo/root/cimv2:CIM_Foo
|
196
|
+
# INSTANCENAME CIMInstanceName CIM_Foo.Foo="Bar"
|
197
|
+
# LOCALINSTANCEPATH CIMLocalInstancePath root/cimv2:CIM_Foo.Foo="Bar"
|
198
|
+
# INSTANCEPATH CIMInstancePath //leo/root/cimv2:CIM_Foo.Foo="Bar"
|
199
|
+
#
|
200
|
+
|
201
|
+
class CIMObjectLocation < XMLObject
|
202
|
+
include Comparable
|
203
|
+
#"""A base class that can name any CIM object."""
|
204
|
+
|
205
|
+
attr_writer :host, :localnamespacepath, :classname, :instancename
|
206
|
+
attr_reader :host, :localnamespacepath, :classname, :instancename
|
207
|
+
|
208
|
+
def initialize(host = nil, localnamespacepath = nil,
|
209
|
+
classname = nil, instancename = nil)
|
210
|
+
@host = host
|
211
|
+
@localnamespacepath = localnamespacepath
|
212
|
+
@classname = classname
|
213
|
+
@instancename = instancename
|
214
|
+
end
|
215
|
+
|
216
|
+
def HOST
|
217
|
+
HOST.new(@host)
|
218
|
+
end
|
219
|
+
|
220
|
+
def CLASSNAME
|
221
|
+
CLASSNAME.new(@classname)
|
222
|
+
end
|
223
|
+
|
224
|
+
def LOCALNAMESPACEPATH
|
225
|
+
nsArray = @localnamespacepath.split("/").collect { |name| NAMESPACE.new(name) }
|
226
|
+
LOCALNAMESPACEPATH.new(nsArray)
|
227
|
+
end
|
228
|
+
|
229
|
+
def NAMESPACEPATH
|
230
|
+
NAMESPACEPATH.new(self.HOST, self.LOCALNAMESPACEPATH)
|
231
|
+
end
|
232
|
+
|
233
|
+
def eql?(other)
|
234
|
+
(self <=> other) == 0
|
235
|
+
end
|
236
|
+
def hash
|
237
|
+
self.host.hash + self.localnamespacepath.hash + self.classname.hash + self.instancename.hash
|
238
|
+
end
|
239
|
+
def <=>(other)
|
240
|
+
if equal?(other)
|
241
|
+
return 0
|
242
|
+
elsif (!other.kind_of?(CIMObjectLocation))
|
243
|
+
return 1
|
244
|
+
end
|
245
|
+
ret_val = cmpname(self.host, other.host)
|
246
|
+
ret_val = nilcmp(self.localnamespacepath, other.localnamespacepath) if (ret_val == 0)
|
247
|
+
ret_val = cmpname(lclassname, lOclassname) if (ret_val == 0)
|
248
|
+
ret_val = nilcmp(self.instancename, other.instancename) if (ret_val == 0)
|
249
|
+
ret_val
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
class CIMClassName < CIMObjectLocation
|
254
|
+
def initialize(classname)
|
255
|
+
unless classname.kind_of?(String)
|
256
|
+
raise TypeError, "classname argument must be a string"
|
257
|
+
end
|
258
|
+
|
259
|
+
# TODO: There are some odd restrictions on what a CIM
|
260
|
+
# classname can look like (i.e must start with a
|
261
|
+
# non-underscore and only one underscore per classname).
|
262
|
+
super()
|
263
|
+
self.classname=classname
|
264
|
+
end
|
265
|
+
|
266
|
+
def tocimxml
|
267
|
+
self.CLASSNAME
|
268
|
+
end
|
269
|
+
|
270
|
+
def to_s
|
271
|
+
self.classname
|
272
|
+
end
|
273
|
+
|
274
|
+
end
|
275
|
+
|
276
|
+
class CIMNamespacePath < CIMObjectLocation
|
277
|
+
def initialize(host, localnamespacepath)
|
278
|
+
unless host.kind_of?(String)
|
279
|
+
raise TypeError, "host argument must be a string"
|
280
|
+
end
|
281
|
+
unless localnamespacepath.kind_of?(String)
|
282
|
+
raise TypeError, "localnamespacepath argument must be a string"
|
283
|
+
end
|
284
|
+
|
285
|
+
super()
|
286
|
+
self.host=host
|
287
|
+
self.localnamespacepath=localnamespacepath
|
288
|
+
end
|
289
|
+
|
290
|
+
def tocimxml
|
291
|
+
self.NAMESPACEPATH
|
292
|
+
end
|
293
|
+
|
294
|
+
def to_s
|
295
|
+
"//#{self.host}/#{self.localnamespacepath}"
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
class CIMLocalClassPath < CIMObjectLocation
|
300
|
+
def initialize(localnamespacepath, classname)
|
301
|
+
unless localnamespacepath.kind_of?(String)
|
302
|
+
raise TypeError, "localnamespacepath argument must be a string"
|
303
|
+
end
|
304
|
+
unless classname.kind_of?(String)
|
305
|
+
raise TypeError, "classname argument must be a string"
|
306
|
+
end
|
307
|
+
|
308
|
+
super()
|
309
|
+
self.classname=classname
|
310
|
+
self.localnamespacepath=localnamespacepath
|
311
|
+
end
|
312
|
+
|
313
|
+
def tocimxml
|
314
|
+
LOCALCLASSPATH.new(self.LOCALNAMESPACEPATH, self.CLASSNAME)
|
315
|
+
end
|
316
|
+
|
317
|
+
def to_s
|
318
|
+
"#{self.localnamespacepath}:#{self.classname}"
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
class CIMClassPath < CIMObjectLocation
|
323
|
+
def initialize(localnamespacepath, classname)
|
324
|
+
unless host.kind_of?(String)
|
325
|
+
raise TypeError, "host argument must be a string"
|
326
|
+
end
|
327
|
+
unless localnamespacepath.kind_of?(String)
|
328
|
+
raise TypeError, "localnamespacepath argument must be a string"
|
329
|
+
end
|
330
|
+
unless classname.kind_of?(String)
|
331
|
+
raise TypeError, "classname argument must be a string"
|
332
|
+
end
|
333
|
+
|
334
|
+
super()
|
335
|
+
self.host=host
|
336
|
+
self.classname=classname
|
337
|
+
self.localnamespacepath=localnamespacepath
|
338
|
+
end
|
339
|
+
|
340
|
+
def tocimxml
|
341
|
+
CLASSPATH.new(self.NAMESPACEPATH, self.CLASSNAME)
|
342
|
+
end
|
343
|
+
|
344
|
+
def to_s
|
345
|
+
"//#{self.host}/#{self.localnamespacepath}:#{self.classname}"
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
# Object value elements
|
350
|
+
|
351
|
+
class CIMProperty < XMLObject
|
352
|
+
include Comparable
|
353
|
+
#"""A property of a CIMInstance.
|
354
|
+
|
355
|
+
#Property objects represent both properties on particular instances,
|
356
|
+
#and the property defined in a class. In the first case, the property
|
357
|
+
#will have a Value and in the second it will not.
|
358
|
+
|
359
|
+
#The property may hold an array value, in which case it is encoded
|
360
|
+
#in XML to PROPERTY.ARRAY containing VALUE.ARRAY.
|
361
|
+
|
362
|
+
#Properties holding references are handled specially as
|
363
|
+
#CIMPropertyReference."""
|
364
|
+
|
365
|
+
attr_writer :name, :prop_type, :class_origin, :propagated, :value, :is_array, :reference_class, :array_size
|
366
|
+
attr_reader :name, :prop_type, :class_origin, :propagated, :value, :is_array, :qualifiers, :reference_class, :array_size
|
367
|
+
|
368
|
+
def initialize(name, value, type=nil, class_origin=nil, propagated=nil,
|
369
|
+
is_array = false, qualifiers = {},
|
370
|
+
reference_class = nil, array_size = nil)
|
371
|
+
#"""Construct a new CIMProperty
|
372
|
+
#Either the type or the value must be given. If the value is not
|
373
|
+
#given, it is left as nil. If the type is not given, it is implied
|
374
|
+
#from the value."""
|
375
|
+
unless name.kind_of?(String)
|
376
|
+
raise TypeError, "name argument must be a string"
|
377
|
+
end
|
378
|
+
unless (class_origin.nil? or class_origin.kind_of?(String))
|
379
|
+
raise TypeError, "class_origin argument must be a string"
|
380
|
+
end
|
381
|
+
|
382
|
+
@name = name
|
383
|
+
@value = value
|
384
|
+
@prop_type = type
|
385
|
+
@class_origin = class_origin
|
386
|
+
@propagated = propagated
|
387
|
+
@qualifiers = NocaseHash.new(qualifiers)
|
388
|
+
@is_array = is_array
|
389
|
+
@array_size = array_size
|
390
|
+
@reference_class = reference_class
|
391
|
+
|
392
|
+
if type.nil?
|
393
|
+
if (value.nil?)
|
394
|
+
raise TypeError, "value argument must not be nil if type is missing"
|
395
|
+
end
|
396
|
+
if (value.is_a?(Array))
|
397
|
+
if (value.empty?)
|
398
|
+
raise TypeError, "Empty property array #{name} must have a type"
|
399
|
+
end
|
400
|
+
@is_array = true
|
401
|
+
@prop_type = WBEM.cimtype(value[0])
|
402
|
+
else
|
403
|
+
@prop_type = WBEM.cimtype(value)
|
404
|
+
end
|
405
|
+
else
|
406
|
+
@is_array = true if (value.is_a?(Array))
|
407
|
+
@prop_type = type
|
408
|
+
end
|
409
|
+
@value = value
|
410
|
+
end
|
411
|
+
|
412
|
+
def qualifiers=(qualifiers)
|
413
|
+
@qualifiers = NocaseHash.new(qualifiers)
|
414
|
+
end
|
415
|
+
|
416
|
+
def clone
|
417
|
+
return CIMProperty.new(self.name,
|
418
|
+
self.value,
|
419
|
+
self.prop_type,
|
420
|
+
self.class_origin,
|
421
|
+
self.propagated,
|
422
|
+
self.is_array,
|
423
|
+
self.qualifiers,
|
424
|
+
self.reference_class,
|
425
|
+
self.array_size)
|
426
|
+
end
|
427
|
+
|
428
|
+
def to_s
|
429
|
+
r = "#{self.class}(name=#{self.name}, type=#{self.prop_type}"
|
430
|
+
r += ", class_origin=#{self.class_origin}" if self.class_origin
|
431
|
+
r += ", propagated=#{self.propagated}" if self.propagated
|
432
|
+
r += ", value=#{self.value}" if self.value
|
433
|
+
r += ", qualifiers=#{self.qualifiers}" if self.qualifiers
|
434
|
+
r += ", is_array=#{self.is_array}"
|
435
|
+
r += ")"
|
436
|
+
end
|
437
|
+
|
438
|
+
def <=>(other)
|
439
|
+
if equal?(other)
|
440
|
+
ret_val = 0
|
441
|
+
elsif (!other.kind_of?(CIMProperty ))
|
442
|
+
ret_val = 1
|
443
|
+
else
|
444
|
+
ret_val = cmpname(self.name, other.name)
|
445
|
+
ret_val = nilcmp(self.value, other.value) if (ret_val == 0)
|
446
|
+
ret_val = nilcmp(self.prop_type, other.prop_type) if (ret_val == 0)
|
447
|
+
ret_val = nilcmp(self.class_origin, other.class_origin) if (ret_val == 0)
|
448
|
+
ret_val = nilcmp(self.propagated, other.propagated) if (ret_val == 0)
|
449
|
+
ret_val = nilcmp(self.qualifiers, other.qualifiers) if (ret_val == 0)
|
450
|
+
ret_val = nilcmp(self.is_array, other.is_array) if (ret_val == 0)
|
451
|
+
ret_val = cmpname(self.reference_class, other.reference_class) if (ret_val == 0)
|
452
|
+
end
|
453
|
+
ret_val
|
454
|
+
end
|
455
|
+
|
456
|
+
def tocimxml
|
457
|
+
if self.is_array
|
458
|
+
return PROPERTY_ARRAY.new(self.name,
|
459
|
+
self.prop_type,
|
460
|
+
WBEM.tocimxml(self.value),
|
461
|
+
self.array_size,
|
462
|
+
self.class_origin,
|
463
|
+
self.propagated,
|
464
|
+
self.qualifiers.values.collect { |q| q.tocimxml})
|
465
|
+
elsif self.prop_type == 'reference'
|
466
|
+
return PROPERTY_REFERENCE.new(self.name,
|
467
|
+
WBEM.tocimxml(self.value, true),
|
468
|
+
self.reference_class,
|
469
|
+
self.class_origin,
|
470
|
+
self.propagated,
|
471
|
+
self.qualifiers.values.collect { |q| q.tocimxml})
|
472
|
+
else
|
473
|
+
return PROPERTY.new(self.name,
|
474
|
+
self.prop_type,
|
475
|
+
WBEM.tocimxml(self.value),
|
476
|
+
self.class_origin,
|
477
|
+
self.propagated,
|
478
|
+
self.qualifiers.values.collect { |q| q.tocimxml})
|
479
|
+
end
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
class CIMInstanceName < XMLObject
|
484
|
+
include Comparable
|
485
|
+
#"""Name (keys) identifying an instance.
|
486
|
+
|
487
|
+
#This may be treated as a hash to retrieve the keys."""
|
488
|
+
# qualifiers removed?
|
489
|
+
attr_reader :classname, :keybindings, :host, :namespace
|
490
|
+
attr_writer :classname, :keybindings, :host, :namespace
|
491
|
+
def initialize(classname, keybindings = {}, host = nil, namespace = nil)
|
492
|
+
@classname = classname
|
493
|
+
@keybindings = NocaseHash.new(keybindings)
|
494
|
+
@host = host
|
495
|
+
@namespace = namespace
|
496
|
+
end
|
497
|
+
|
498
|
+
def clone
|
499
|
+
CIMInstanceName.new(@classname, @keybindings, @host, @namespace)
|
500
|
+
end
|
501
|
+
|
502
|
+
def <=>(other)
|
503
|
+
if equal?(other)
|
504
|
+
ret_val = 0
|
505
|
+
elsif (!other.kind_of?(CIMInstanceName ))
|
506
|
+
ret_val = 1
|
507
|
+
else
|
508
|
+
## TODO: Allow for the type to be null as long as the values
|
509
|
+
## are the same and non-null?
|
510
|
+
ret_val = cmpname(self.classname, other.classname)
|
511
|
+
ret_val = nilcmp(self.keybindings, other.keybindings) if (ret_val == 0)
|
512
|
+
ret_val = cmpname(self.host, other.host) if (ret_val == 0)
|
513
|
+
ret_val = cmpname(self.namespace, other.namespace) if (ret_val == 0)
|
514
|
+
end
|
515
|
+
ret_val
|
516
|
+
end
|
517
|
+
|
518
|
+
def keybindings=(keybindings)
|
519
|
+
@keybindings = NocaseHash.new(keybindings)
|
520
|
+
end
|
521
|
+
|
522
|
+
def to_s
|
523
|
+
s = ''
|
524
|
+
|
525
|
+
unless self.host.nil?
|
526
|
+
s += '//%s/' % self.host
|
527
|
+
end
|
528
|
+
unless self.namespace.nil?
|
529
|
+
s += '%s:' % self.namespace
|
530
|
+
end
|
531
|
+
s += '%s.' % self.classname
|
532
|
+
|
533
|
+
self.keybindings.to_a.each do |key, value|
|
534
|
+
|
535
|
+
s += "#{key}="
|
536
|
+
|
537
|
+
if value.kind_of?(Integer)
|
538
|
+
s += value.to_s
|
539
|
+
else
|
540
|
+
s += '"%s"' % value
|
541
|
+
end
|
542
|
+
s += ","
|
543
|
+
end
|
544
|
+
return s[0..-2]
|
545
|
+
end
|
546
|
+
# A whole bunch of dictionary methods that map to the equivalent
|
547
|
+
# operation on self.keybindings.
|
548
|
+
|
549
|
+
def fetch(key)
|
550
|
+
return self.keybindings.fetch(key)
|
551
|
+
end
|
552
|
+
def [](key)
|
553
|
+
return self.keybindings[key]
|
554
|
+
end
|
555
|
+
def []=(key, value)
|
556
|
+
return self.keybindings[key] = value
|
557
|
+
end
|
558
|
+
def delete(key)
|
559
|
+
self.keybindings.delete(key)
|
560
|
+
end
|
561
|
+
def length
|
562
|
+
return self.keybindings.length
|
563
|
+
end
|
564
|
+
def has_key?(key)
|
565
|
+
return self.keybindings.has_key?(key)
|
566
|
+
end
|
567
|
+
def keys
|
568
|
+
return self.keybindings.keys()
|
569
|
+
end
|
570
|
+
def values
|
571
|
+
return self.keybindings.values()
|
572
|
+
end
|
573
|
+
def to_a
|
574
|
+
return self.keybindings.to_a()
|
575
|
+
end
|
576
|
+
|
577
|
+
def tocimxml
|
578
|
+
# Generate an XML representation of the instance classname and
|
579
|
+
# keybindings.
|
580
|
+
|
581
|
+
if (self.keybindings.kind_of?(String))
|
582
|
+
# Class with single key string property
|
583
|
+
instancename_xml = INSTANCENAME.new(self.classname,
|
584
|
+
KEYVALUE.new(self.keybindings, "string"))
|
585
|
+
|
586
|
+
elsif (self.keybindings.kind_of?(Integer))
|
587
|
+
# Class with single key numeric property
|
588
|
+
instancename_xml = INSTANCENAME.new(self.classname,
|
589
|
+
KEYVALUE.new(self.keybindings.to_s, "numeric"))
|
590
|
+
|
591
|
+
elsif (self.keybindings.kind_of?(NocaseHash))
|
592
|
+
# Dictionary of keybindings
|
593
|
+
kbs = []
|
594
|
+
self.keybindings.to_a.each do |kb|
|
595
|
+
# Keybindings can be integers, booleans, strings or
|
596
|
+
# value references.
|
597
|
+
if (kb[1].methods.include?("tocimxml"))
|
598
|
+
kbs << KEYBINDING.new(kb[0], VALUE_REFERENCE.new(kb[1].tocimxml()))
|
599
|
+
next
|
600
|
+
end
|
601
|
+
|
602
|
+
if (kb[1].kind_of?(Integer) or kb[1].kind_of?(CIMInt))
|
603
|
+
_type = "numeric"
|
604
|
+
value = kb[1].to_s
|
605
|
+
elsif (kb[1] == true or kb[1] == false)
|
606
|
+
_type = "boolean"
|
607
|
+
if kb[1]
|
608
|
+
value = "TRUE"
|
609
|
+
else
|
610
|
+
value = "FALSE"
|
611
|
+
end
|
612
|
+
elsif (kb[1].kind_of?(String )) # unicode?
|
613
|
+
_type = "string"
|
614
|
+
value = kb[1]
|
615
|
+
else
|
616
|
+
raise TypeError, "Invalid keybinding type #{kb[1]}(#{kb[1].class}) for keybinding #{kb[0]}"
|
617
|
+
end
|
618
|
+
|
619
|
+
kbs << KEYBINDING.new(kb[0], KEYVALUE.new(value, _type))
|
620
|
+
|
621
|
+
end
|
622
|
+
instancename_xml = INSTANCENAME.new(self.classname, kbs)
|
623
|
+
|
624
|
+
else
|
625
|
+
# Value reference
|
626
|
+
|
627
|
+
return instancename_xml = INSTANCENAME.new(self.classname, self.keybindings.nil? ? nil : VALUE_REFERENCE.new(self.keybindings.tocimxml()))
|
628
|
+
end
|
629
|
+
# Instance name plus namespace = LOCALINSTANCEPATH
|
630
|
+
|
631
|
+
if (self.host.nil? && !self.namespace.nil?)
|
632
|
+
return LOCALINSTANCEPATH.new(
|
633
|
+
LOCALNAMESPACEPATH.new(
|
634
|
+
self.namespace.split('/').collect { |ns| NAMESPACE.new(ns)}),
|
635
|
+
instancename_xml)
|
636
|
+
end
|
637
|
+
|
638
|
+
# Instance name plus host and namespace = INSTANCEPATH
|
639
|
+
if (!self.host.nil? && !self.namespace.nil?)
|
640
|
+
return INSTANCEPATH.new(
|
641
|
+
NAMESPACEPATH.new(
|
642
|
+
HOST.new(self.host),
|
643
|
+
LOCALNAMESPACEPATH.new(
|
644
|
+
self.namespace.split('/').collect { |ns| NAMESPACE.new(ns)})),
|
645
|
+
instancename_xml)
|
646
|
+
end
|
647
|
+
|
648
|
+
# Just a regular INSTANCENAME
|
649
|
+
return instancename_xml
|
650
|
+
end
|
651
|
+
end
|
652
|
+
|
653
|
+
class CIMInstance < XMLObject
|
654
|
+
include Comparable
|
655
|
+
#"""Instance of a CIM Object.
|
656
|
+
|
657
|
+
#Has a classname (string), and named arrays of properties and qualifiers.
|
658
|
+
|
659
|
+
#The properties is indexed by name and points to CIMProperty
|
660
|
+
#instances."""
|
661
|
+
|
662
|
+
attr_reader :classname, :properties, :qualifiers, :path
|
663
|
+
attr_writer :classname, :path
|
664
|
+
def initialize(classname, properties = {}, qualifiers = {},
|
665
|
+
path = nil)
|
666
|
+
#"""Create CIMInstance.
|
667
|
+
|
668
|
+
@classname = classname
|
669
|
+
@qualifiers = NocaseHash.new(qualifiers)
|
670
|
+
@path = path
|
671
|
+
@properties = NocaseHash.new
|
672
|
+
properties.each do |k, v|
|
673
|
+
self[k]=v
|
674
|
+
end
|
675
|
+
end
|
676
|
+
|
677
|
+
def clone
|
678
|
+
CIMInstance.new(@classname, @properties, @qualifiers, @path)
|
679
|
+
end
|
680
|
+
|
681
|
+
def properties=(properties)
|
682
|
+
@properties = NocaseHash.new
|
683
|
+
properties.each do |k, v|
|
684
|
+
self[k]=v
|
685
|
+
end
|
686
|
+
end
|
687
|
+
|
688
|
+
def qualifiers=(qualifiers)
|
689
|
+
@qualifiers = NocaseHash.new(qualifiers)
|
690
|
+
end
|
691
|
+
|
692
|
+
def <=>(other)
|
693
|
+
if equal?(other)
|
694
|
+
return 0
|
695
|
+
elsif (!other.kind_of?(CIMInstance))
|
696
|
+
return 1
|
697
|
+
end
|
698
|
+
## TODO: Allow for the type to be null as long as the values
|
699
|
+
## are the same and non-null?
|
700
|
+
ret_val = cmpname(self.classname, other.classname)
|
701
|
+
ret_val = nilcmp(self.path, other.path) if (ret_val == 0)
|
702
|
+
ret_val = nilcmp(self.properties, other.properties) if (ret_val == 0)
|
703
|
+
ret_val = nilcmp(self.qualifiers, other.qualifiers) if (ret_val == 0)
|
704
|
+
ret_val
|
705
|
+
end
|
706
|
+
|
707
|
+
def to_s
|
708
|
+
# Don't show all the properties and qualifiers because they're
|
709
|
+
# just too big
|
710
|
+
"#{self.class}(classname=#{self.classname} ...)"
|
711
|
+
end
|
712
|
+
|
713
|
+
# A whole bunch of dictionary methods that map to the equivalent
|
714
|
+
# operation on self.properties.
|
715
|
+
|
716
|
+
def fetch(key)
|
717
|
+
return self.properties.fetch(key)
|
718
|
+
end
|
719
|
+
def [](key)
|
720
|
+
ret = self.properties[key]
|
721
|
+
ret = ret.value unless ret.nil?
|
722
|
+
end
|
723
|
+
def delete(key)
|
724
|
+
self.properties.delete(key)
|
725
|
+
end
|
726
|
+
def length
|
727
|
+
self.properties.length
|
728
|
+
end
|
729
|
+
def has_key?(key)
|
730
|
+
self.properties.has_key?(key)
|
731
|
+
end
|
732
|
+
def keys
|
733
|
+
self.properties.keys()
|
734
|
+
end
|
735
|
+
def values
|
736
|
+
self.properties.values.collect { |v| v.value }
|
737
|
+
end
|
738
|
+
def to_a
|
739
|
+
self.properties.to_a.collect { |k, v| [k, v.value] }
|
740
|
+
end
|
741
|
+
#def iterkeys(self): return self.properties.iterkeys()
|
742
|
+
#def itervalues(self): return self.properties.itervalues()
|
743
|
+
#def iteritems(self): return self.properties.iteritems()
|
744
|
+
|
745
|
+
def []=(key, value)
|
746
|
+
|
747
|
+
# Don't let anyone set integer or float values. You must use
|
748
|
+
# a subclass from the cim_type module.
|
749
|
+
|
750
|
+
unless (value.is_a?(CIMProperty))
|
751
|
+
unless WBEM.valid_cimtype?(value)
|
752
|
+
raise TypeError, "Must use a CIM type assigning numeric values."
|
753
|
+
end
|
754
|
+
value = CIMProperty.new(key, value)
|
755
|
+
end
|
756
|
+
self.properties[key] = value
|
757
|
+
end
|
758
|
+
|
759
|
+
def tocimxml
|
760
|
+
props = []
|
761
|
+
self.properties.each do |key, prop|
|
762
|
+
if (prop.is_a?(CIMProperty))
|
763
|
+
props << prop
|
764
|
+
else
|
765
|
+
props << CIMProperty.new(key, prop)
|
766
|
+
end
|
767
|
+
end
|
768
|
+
instance_xml = INSTANCE.new(self.classname,
|
769
|
+
props.collect { |p| p.tocimxml},
|
770
|
+
self.qualifiers.values.collect { |q| q.tocimxml})
|
771
|
+
if self.path.nil?
|
772
|
+
return instance_xml
|
773
|
+
end
|
774
|
+
return VALUE_NAMEDINSTANCE.new(self.path.tocimxml,
|
775
|
+
instance_xml)
|
776
|
+
end
|
777
|
+
end
|
778
|
+
|
779
|
+
class CIMClass < XMLObject
|
780
|
+
#"""Class, including a description of properties, methods and qualifiers.
|
781
|
+
#superclass may be None."""
|
782
|
+
include Comparable
|
783
|
+
attr_reader :classname, :properties, :qualifiers, :cim_methods, :superclass
|
784
|
+
attr_writer :classname, :superclass
|
785
|
+
def initialize(classname, properties = {}, qualifiers = {},
|
786
|
+
methods = {}, superclass = nil)
|
787
|
+
unless (classname.kind_of?(String))
|
788
|
+
raise TypeError, "classname must be a String"
|
789
|
+
end
|
790
|
+
@classname = classname
|
791
|
+
@properties = NocaseHash.new
|
792
|
+
unless properties.nil?
|
793
|
+
properties.each do |k, v|
|
794
|
+
@properties[k]=v
|
795
|
+
end
|
796
|
+
end
|
797
|
+
@qualifiers = NocaseHash.new(qualifiers)
|
798
|
+
@cim_methods = NocaseHash.new(methods)
|
799
|
+
@superclass = superclass
|
800
|
+
end
|
801
|
+
|
802
|
+
def clone
|
803
|
+
return CIMClass.new(@classname, @properties, @qualifiers,
|
804
|
+
@cim_methods, @superclass)
|
805
|
+
end
|
806
|
+
|
807
|
+
def properties=(properties)
|
808
|
+
@properties = NocaseHash.new
|
809
|
+
unless properties.nil?
|
810
|
+
properties.each do |k, v|
|
811
|
+
@properties[k]=v
|
812
|
+
end
|
813
|
+
end
|
814
|
+
end
|
815
|
+
|
816
|
+
def qualifiers=(qualifiers)
|
817
|
+
@qualifiers = NocaseHash.new(qualifiers)
|
818
|
+
end
|
819
|
+
|
820
|
+
def cim_methods=(cim_methods)
|
821
|
+
@cim_methods = NocaseHash.new(cim_methods)
|
822
|
+
end
|
823
|
+
|
824
|
+
def to_s
|
825
|
+
"#{self.class}(#{self.classname}, ...)"
|
826
|
+
end
|
827
|
+
|
828
|
+
def <=>(other)
|
829
|
+
if equal?(other)
|
830
|
+
return 0
|
831
|
+
elsif (!other.kind_of?(CIMClass))
|
832
|
+
return 1
|
833
|
+
end
|
834
|
+
ret_val = cmpname(self.classname, other.classname)
|
835
|
+
ret_val = cmpname(self.superclass, other.superclass) if (ret_val == 0)
|
836
|
+
ret_val = nilcmp(self.properties, other.properties) if (ret_val == 0)
|
837
|
+
ret_val = nilcmp(self.qualifiers, other.qualifiers) if (ret_val == 0)
|
838
|
+
ret_val = nilcmp(self.cim_methods, other.cim_methods) if (ret_val == 0)
|
839
|
+
ret_val
|
840
|
+
end
|
841
|
+
|
842
|
+
def tocimxml
|
843
|
+
return CLASS.new(self.classname,
|
844
|
+
self.properties.values.collect {|p| p.tocimxml()},
|
845
|
+
self.cim_methods.values.collect {|m| m.tocimxml()},
|
846
|
+
self.qualifiers.values.collect {|q| q.tocimxml()},
|
847
|
+
self.superclass)
|
848
|
+
end
|
849
|
+
end
|
850
|
+
|
851
|
+
class CIMMethod < XMLObject
|
852
|
+
include Comparable
|
853
|
+
|
854
|
+
attr_reader :name, :parameters, :qualifiers, :class_origin, :return_type, :propagated
|
855
|
+
attr_writer :name, :class_origin, :return_type, :propagated
|
856
|
+
def initialize(methodname, return_type = nil, parameters = {}, class_origin = nil, propagated = false, qualifiers = {} )
|
857
|
+
@name = methodname
|
858
|
+
@return_type = return_type
|
859
|
+
@parameters = NocaseHash.new(parameters)
|
860
|
+
@class_origin = class_origin
|
861
|
+
@propagated = propagated
|
862
|
+
@qualifiers = NocaseHash.new(qualifiers)
|
863
|
+
end
|
864
|
+
|
865
|
+
def clone
|
866
|
+
return CIMMethod.new(@name, @return_type, @parameters,
|
867
|
+
@class_origin, @propagated, @qualifiers)
|
868
|
+
end
|
869
|
+
|
870
|
+
def parameters=(parameters)
|
871
|
+
@parameters = NocaseHash.new(parameters)
|
872
|
+
end
|
873
|
+
|
874
|
+
def qualifiers=(qualifiers)
|
875
|
+
@qualifiers = NocaseHash.new(qualifiers)
|
876
|
+
end
|
877
|
+
|
878
|
+
def tocimxml
|
879
|
+
METHOD.new(self.name,
|
880
|
+
self.parameters.values.collect {|p| p.tocimxml()},
|
881
|
+
self.return_type,
|
882
|
+
self.class_origin,
|
883
|
+
self.propagated,
|
884
|
+
self.qualifiers.values.collect {|q| q.tocimxml()})
|
885
|
+
end
|
886
|
+
|
887
|
+
def <=>(other)
|
888
|
+
ret_val = 0
|
889
|
+
if equal?(other)
|
890
|
+
return 0
|
891
|
+
elsif (!other.kind_of?(CIMMethod))
|
892
|
+
return 1
|
893
|
+
end
|
894
|
+
ret_val = cmpname(self.name, other.name)
|
895
|
+
ret_val = nilcmp(self.parameters, other.parameters) if (ret_val == 0)
|
896
|
+
ret_val = nilcmp(self.qualifiers, other.qualifiers) if (ret_val == 0)
|
897
|
+
ret_val = nilcmp(self.class_origin, other.class_origin) if (ret_val == 0)
|
898
|
+
ret_val = nilcmp(self.propagated, other.propagated) if (ret_val == 0)
|
899
|
+
ret_val = nilcmp(self.return_type, other.return_type) if (ret_val == 0)
|
900
|
+
ret_val
|
901
|
+
end
|
902
|
+
|
903
|
+
def to_s
|
904
|
+
"#{self.class}(name=#{self.name}, return_type=#{self.return_type}...)"
|
905
|
+
end
|
906
|
+
end
|
907
|
+
|
908
|
+
class CIMParameter < XMLObject
|
909
|
+
include Comparable
|
910
|
+
|
911
|
+
attr_writer :name, :param_type, :is_array, :reference_class, :array_size
|
912
|
+
attr_reader :name, :param_type, :is_array, :qualifiers, :reference_class, :array_size
|
913
|
+
|
914
|
+
def initialize(name, type, reference_class=nil, is_array = nil,
|
915
|
+
array_size = nil, qualifiers = {})
|
916
|
+
@name = name
|
917
|
+
@param_type = type
|
918
|
+
@reference_class = reference_class
|
919
|
+
@is_array = is_array
|
920
|
+
@array_size = array_size
|
921
|
+
@qualifiers = NocaseHash.new(qualifiers)
|
922
|
+
end
|
923
|
+
|
924
|
+
def clone
|
925
|
+
return CIMParameter.new(@name, @param_type, @reference_class,
|
926
|
+
@is_array, @array_size, @qualifiers)
|
927
|
+
end
|
928
|
+
|
929
|
+
def qualifiers=(qualifiers)
|
930
|
+
@qualifiers = NocaseHash.new(qualifiers)
|
931
|
+
end
|
932
|
+
|
933
|
+
def to_s
|
934
|
+
"#{self.class}(name=#{self.name}, type=#{self.param_type}, is_array=#{self.is_array})"
|
935
|
+
end
|
936
|
+
|
937
|
+
def <=>(other)
|
938
|
+
if equal?(other)
|
939
|
+
return 0
|
940
|
+
elsif (!other.kind_of?(CIMParameter ))
|
941
|
+
return 1
|
942
|
+
end
|
943
|
+
ret_val = cmpname(self.name, other.name)
|
944
|
+
ret_val = nilcmp(self.param_type, other.param_type) if (ret_val == 0)
|
945
|
+
ret_val = cmpname(self.reference_class, other.reference_class) if (ret_val == 0)
|
946
|
+
ret_val = nilcmp(self.is_array, other.is_array) if (ret_val == 0)
|
947
|
+
ret_val = nilcmp(self.array_size, other.array_size) if (ret_val == 0)
|
948
|
+
ret_val = nilcmp(self.qualifiers, other.qualifiers) if (ret_val == 0)
|
949
|
+
ret_val
|
950
|
+
end
|
951
|
+
|
952
|
+
def tocimxml
|
953
|
+
if self.param_type == 'reference'
|
954
|
+
if self.is_array
|
955
|
+
return PARAMETER_REFARRAY.new(self.name,
|
956
|
+
self.reference_class,
|
957
|
+
array_size.nil? ? nil : self.array_size.to_s,
|
958
|
+
self.qualifiers.values.collect {|q| q.tocimxml()})
|
959
|
+
else
|
960
|
+
return PARAMETER_REFERENCE.new(self.name,
|
961
|
+
self.reference_class,
|
962
|
+
self.qualifiers.values.collect {|q| q.tocimxml()})
|
963
|
+
end
|
964
|
+
elsif self.is_array
|
965
|
+
return PARAMETER_ARRAY.new(self.name,
|
966
|
+
self.param_type,
|
967
|
+
array_size.nil? ? nil : self.array_size.to_s,
|
968
|
+
self.qualifiers.values.collect { |q| q.tocimxml})
|
969
|
+
else
|
970
|
+
return PARAMETER.new(self.name,
|
971
|
+
self.param_type,
|
972
|
+
self.qualifiers.values.collect { |q| q.tocimxml})
|
973
|
+
end
|
974
|
+
end
|
975
|
+
end
|
976
|
+
|
977
|
+
class CIMQualifier < XMLObject
|
978
|
+
include Comparable
|
979
|
+
#"""Represents static annotations of a class, method, property, etc.
|
980
|
+
|
981
|
+
#Includes information such as a documentation string and whether a property
|
982
|
+
#is a key."""
|
983
|
+
|
984
|
+
attr_reader :name, :qual_type, :value, :overridable, :propagated, :toinstance, :tosubclass, :translatable
|
985
|
+
attr_writer :name, :qual_type, :value, :overridable, :propagated, :toinstance, :tosubclass, :translatable
|
986
|
+
def initialize(name, value, propagated=nil, overridable=nil,
|
987
|
+
tosubclass=nil, toinstance=nil, translatable=nil)
|
988
|
+
@name = name
|
989
|
+
@value = value
|
990
|
+
@overridable = overridable
|
991
|
+
@propagated = propagated
|
992
|
+
@toinstance = toinstance
|
993
|
+
@tosubclass = tosubclass
|
994
|
+
@translatable = translatable
|
995
|
+
@qual_type = WBEM.cimtype(value)
|
996
|
+
end
|
997
|
+
|
998
|
+
def clone
|
999
|
+
CIMQualifier.new(@name, @value, @propagated, @overridable,
|
1000
|
+
@tosubclass, @toinstance, @translatable)
|
1001
|
+
end
|
1002
|
+
|
1003
|
+
def to_s
|
1004
|
+
"#{self.class}(#{self.name}, #{self.value}, ...)"
|
1005
|
+
end
|
1006
|
+
|
1007
|
+
def <=>(other)
|
1008
|
+
ret_val = 0
|
1009
|
+
if equal?(other)
|
1010
|
+
return 0
|
1011
|
+
elsif (!other.kind_of?(CIMQualifier))
|
1012
|
+
return 1
|
1013
|
+
end
|
1014
|
+
ret_val = cmpname(self.name, other.name)
|
1015
|
+
ret_val = nilcmp(self.value, other.value) if (ret_val == 0)
|
1016
|
+
ret_val = nilcmp(self.propagated, other.propagated) if (ret_val == 0)
|
1017
|
+
ret_val = nilcmp(self.overridable, other.overridable) if (ret_val == 0)
|
1018
|
+
ret_val = nilcmp(self.tosubclass, other.tosubclass) if (ret_val == 0)
|
1019
|
+
ret_val = nilcmp(self.toinstance, other.toinstance) if (ret_val == 0)
|
1020
|
+
ret_val = nilcmp(self.translatable, other.translatable) if (ret_val == 0)
|
1021
|
+
ret_val
|
1022
|
+
end
|
1023
|
+
def tocimxml
|
1024
|
+
QUALIFIER.new(self.name,
|
1025
|
+
self.qual_type,
|
1026
|
+
WBEM.tocimxml(self.value),
|
1027
|
+
self.propagated,
|
1028
|
+
self.overridable,
|
1029
|
+
self.tosubclass,
|
1030
|
+
self.toinstance,
|
1031
|
+
self.translatable)
|
1032
|
+
end
|
1033
|
+
end
|
1034
|
+
|
1035
|
+
def WBEM.tocimxml(value, wrap_references = false)
|
1036
|
+
#"""Convert an arbitrary object to CIM xml. Works with cim_obj
|
1037
|
+
#objects and builtin types."""
|
1038
|
+
|
1039
|
+
|
1040
|
+
# CIMType or builtin type
|
1041
|
+
|
1042
|
+
if ([CIMType, String, Integer, DateTime, TimeDelta, TrueClass, FalseClass].any? do |item|
|
1043
|
+
value.is_a?(item)
|
1044
|
+
end)
|
1045
|
+
return VALUE.new(WBEM.atomic_to_cim_xml(value))
|
1046
|
+
elsif (wrap_references and (value.is_a?(CIMInstanceName) or
|
1047
|
+
value.is_a?(CIMClassName) or
|
1048
|
+
value.is_a?(CIMLocalClassPath)))
|
1049
|
+
return VALUE_REFERENCE.new(WBEM.atomic_to_cim_xml(value))
|
1050
|
+
elsif (value.methods.include?("tocimxml"))
|
1051
|
+
return value.tocimxml()
|
1052
|
+
elsif (value.is_a?(Array))
|
1053
|
+
if (wrap_references and (value[0].is_a?(CIMInstanceName) or
|
1054
|
+
value[0].is_a?(CIMClassName) or
|
1055
|
+
value.is_a?(CIMLocalClassPath)))
|
1056
|
+
return VALUE_REFARRAY.new(value.collect {|val| WBEM.tocimxml(val, wrap_references)})
|
1057
|
+
else
|
1058
|
+
return VALUE_ARRAY.new(value.collect {|val| WBEM.tocimxml(val, wrap_references)})
|
1059
|
+
end
|
1060
|
+
elsif (value.nil?)
|
1061
|
+
return value
|
1062
|
+
end
|
1063
|
+
raise TypeError, "Can't convert #{value} (#{value.class}) to CIM XML"
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
def WBEM.tocimobj(_type, value)
|
1067
|
+
#"""Convert a CIM type and a string value into an appropriate
|
1068
|
+
#builtin type."""
|
1069
|
+
|
1070
|
+
# Lists of values
|
1071
|
+
|
1072
|
+
if value.is_a?(Array)
|
1073
|
+
return value.collect { |val| WBEM.tocimobj(_type, val) }
|
1074
|
+
end
|
1075
|
+
|
1076
|
+
case _type
|
1077
|
+
# Boolean type
|
1078
|
+
when "boolean"
|
1079
|
+
return Boolean.new(value)
|
1080
|
+
# String type
|
1081
|
+
when "string"
|
1082
|
+
return value
|
1083
|
+
# Integer types
|
1084
|
+
when "uint8"
|
1085
|
+
return Uint8.new(value)
|
1086
|
+
when "sint8"
|
1087
|
+
return Sint8.new(value)
|
1088
|
+
when "uint16"
|
1089
|
+
return Uint16.new(value)
|
1090
|
+
when "sint16"
|
1091
|
+
return Sint16.new(value)
|
1092
|
+
when "uint32"
|
1093
|
+
return Uint32.new(value)
|
1094
|
+
when "sint32"
|
1095
|
+
return Sint32.new(value)
|
1096
|
+
when "uint64"
|
1097
|
+
return Uint64.new(value)
|
1098
|
+
when "sint64"
|
1099
|
+
return Sint64.new(value)
|
1100
|
+
# Real types
|
1101
|
+
when "real32"
|
1102
|
+
return Real32.new(value)
|
1103
|
+
when "real64"
|
1104
|
+
return Real64.new(value)
|
1105
|
+
# Char16
|
1106
|
+
when "char16"
|
1107
|
+
raise TypeError, "CIMType char16 not handled"
|
1108
|
+
# Datetime
|
1109
|
+
when "datetime"
|
1110
|
+
if (value.nil?)
|
1111
|
+
return nil
|
1112
|
+
end
|
1113
|
+
tv_pattern = /^(\d{8})(\d{2})(\d{2})(\d{2})\.(\d{6})(:)(\d{3})/
|
1114
|
+
date_pattern = /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})\.(\d{6})([+|-])(\d{3})/
|
1115
|
+
s = tv_pattern.match(value)
|
1116
|
+
if (s.nil?)
|
1117
|
+
if ((s = date_pattern.match(value)).nil?)
|
1118
|
+
raise TypeError, "Invalid Datetime format #{value}"
|
1119
|
+
end
|
1120
|
+
return DateTime.new(s[1].to_i,s[2].to_i,s[3].to_i,s[4].to_i,s[5].to_i,s[6].to_i+Rational(s[7].to_i,1000000))
|
1121
|
+
else
|
1122
|
+
# returning a rational num for the #days rather than a python timedelta
|
1123
|
+
return TimeDelta.new(s[1].to_i, s[2].to_i, s[3].to_i, s[4].to_i, s[5].to_i)
|
1124
|
+
end
|
1125
|
+
return value
|
1126
|
+
else
|
1127
|
+
return nil if _type.nil?
|
1128
|
+
raise TypeError, "Invalid CIM type #{_type}"
|
1129
|
+
end
|
1130
|
+
end
|
1131
|
+
def WBEM.byname(nlist)
|
1132
|
+
#"""Convert a list of named objects into a map indexed by name"""
|
1133
|
+
hash = Hash.new
|
1134
|
+
nlist.each { |x| hash[x.name] = x }
|
1135
|
+
return hash
|
1136
|
+
end
|
1137
|
+
class TimeDelta
|
1138
|
+
attr_reader :days, :hours, :minutes, :seconds, :microseconds
|
1139
|
+
attr_writer :days, :hours, :minutes, :seconds, :microseconds
|
1140
|
+
def initialize(days=0, hours=0, minutes=0, seconds=0, microseconds=0)
|
1141
|
+
@days = days
|
1142
|
+
@hours = hours
|
1143
|
+
@minutes = minutes
|
1144
|
+
@seconds = seconds
|
1145
|
+
@microseconds = microseconds
|
1146
|
+
end
|
1147
|
+
end
|
1148
|
+
end
|