@@ -22,57 +22,137 @@ class SpectrumClientParameterError(SpectrumClientException):
22
22
23
23
24
24
class Spectrum (object ):
25
-
26
- _namespace = {'ca' : 'http://www.ca.com/spectrum/restful/schema/response' }
25
+ xml_namespace = {'ca' : 'http://www.ca.com/spectrum/restful/schema/response' }
26
+ default_attributes = '''
27
+ <rs:requested-attribute id="0x1006e"/> <!-- Model Name -->
28
+ <rs:requested-attribute id="0x1000a"/> <!-- Condition -->
29
+ <rs:requested-attribute id="0x11ee8"/> <!-- Model Class -->
30
+ <rs:requested-attribute id="0x129e7"/> <!-- Site ID -->
31
+ <rs:requested-attribute id="0x12d7f"/> <!-- IP Address -->
32
+ <rs:requested-attribute id="0x1290c"/> <!-- Criticality -->
33
+ <rs:requested-attribute id="0x10000"/> <!-- Model Type Name -->
34
+ <rs:requested-attribute id="0x23000e"/> <!-- Device Type -->
35
+ <rs:requested-attribute id="0x11d42"/> <!-- Landscape Name-->
36
+ '''
37
+ models_search_template = '''<?xml version="1.0" encoding="UTF-8"?>
38
+ <rs:model-request throttlesize="9999"
39
+ xmlns:rs="http://www.ca.com/spectrum/restful/schema/request"
40
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
41
+ xsi:schemaLocation="http://www.ca.com/spectrum/restful/schema/request ../../../xsd/Request.xsd ">
42
+ <rs:target-models>
43
+ <rs:models-search>
44
+ <rs:search-criteria xmlns="http://www.ca.com/spectrum/restful/schema/filter">
45
+ <filtered-models>
46
+ {models_filter}
47
+ </filtered-models>
48
+ </rs:search-criteria>
49
+ </rs:models-search>
50
+ </rs:target-models>
51
+ ''' + default_attributes + '</rs:model-request>'
27
52
28
53
def __init__ (self , url = SPECTRUM_URL , username = SPECTRUM_USERNAME , password = SPECTRUM_PASSWORD ):
29
54
if url is None :
30
55
raise ValueError ('Spectrum (OneClick) url must be provided either in the constructor or as an environment variable' )
31
56
self .url = url if not url .endswith ('/' ) else url [:- 1 ]
32
57
self .auth = HTTPBasicAuth (username , password )
33
58
34
- def _check_http (self , res ):
35
- if res .status_code == 401 :
36
- raise SpectrumClientAuthException ('Authorization Failure. Invalid user name or password.' )
37
- res .raise_for_status ()
38
-
39
59
def _parse_get (self , res ):
40
- self ._check_http (res )
60
+ self .check_http_response (res )
41
61
42
62
root = ET .fromstring (res .text )
43
- model_error = root .find ('.//ca:model' , self ._namespace ).get ('error' )
63
+ model_error = root .find ('.//ca:model' , self .xml_namespace ).get ('error' )
44
64
if model_error :
45
65
raise SpectrumClientParameterError ('Model Error: ' + model_error )
46
- attr_error = root .find ('.//ca:attribute' , self ._namespace ).get ('error' )
66
+ attr_error = root .find ('.//ca:attribute' , self .xml_namespace ).get ('error' )
47
67
if attr_error :
48
68
raise SpectrumClientParameterError (attr_error )
49
69
50
70
def _parse_update (self , res ):
51
- self ._check_http (res )
71
+ self .check_http_response (res )
52
72
53
73
root = ET .fromstring (res .text )
54
- if root .find ('.//ca:model' , self ._namespace ).get ('error' ) == 'Success' :
74
+ if root .find ('.//ca:model' , self .xml_namespace ).get ('error' ) == 'Success' :
55
75
return
56
76
57
- if root .find ('.//ca:model' , self ._namespace ).get ('error' ) == 'PartialFailure' :
58
- msg = root .find ('.//ca:attribute' , self ._namespace ).get ('error-message' )
77
+ if root .find ('.//ca:model' , self .xml_namespace ).get ('error' ) == 'PartialFailure' :
78
+ msg = root .find ('.//ca:attribute' , self .xml_namespace ).get ('error-message' )
59
79
else :
60
- msg = root .find ('.//ca:model' , self ._namespace ).get ('error-message' )
80
+ msg = root .find ('.//ca:model' , self .xml_namespace ).get ('error-message' )
61
81
raise SpectrumClientParameterError (msg )
62
82
83
+ @staticmethod
84
+ def check_http_response (res ):
85
+ if res .status_code == 401 :
86
+ raise SpectrumClientAuthException ('Authorization Failure. Invalid user name or password.' )
87
+ res .raise_for_status ()
88
+
89
+ @staticmethod
90
+ def xml_landscape_filter (landscape ):
91
+ xml = '''
92
+ <greater-than>
93
+ <attribute id="0x129fa">
94
+ <value>{}</value>
95
+ </attribute>
96
+ </greater-than>
97
+ <less-than>
98
+ <attribute id="0x129fa">
99
+ <value>{}</value>
100
+ </attribute>
101
+ </less-than>'''
102
+ landscape_start = hex (landscape )
103
+ landscape_end = hex (landscape + 0xfffff )
104
+ return xml .format (landscape_start , landscape_end ).strip ()
105
+
63
106
def get_attribute (self , model_handle , attr_id ):
64
107
"""Get an attribute of a Spectrum model.
65
108
66
109
Arguments:
67
110
model_handle {int} -- Model Handle of the model being queried.
68
111
attr_id {int} -- Attribute ID of the attribute being queried.
69
112
"""
70
- url = f' { self . url } /spectrum/restful/model/{ hex (model_handle )} '
113
+ url = '{ }/spectrum/restful/model/{}' . format ( self . url , hex (model_handle ))
71
114
params = {'attr' : hex (attr_id )}
72
115
res = requests .get (url , params = params , auth = self .auth )
73
116
self ._parse_get (res )
74
117
root = ET .fromstring (res .text )
75
- return root .find ('.//ca:attribute' , self ._namespace ).text
118
+ return root .find ('.//ca:attribute' , self .xml_namespace ).text
119
+
120
+ def devices_by_name (self , regex , landscape = None ):
121
+ if landscape :
122
+ landscape_filter = self .xml_landscape_filter (landscape )
123
+ else :
124
+ landscape_filter = ''
125
+
126
+ models_filter = '''
127
+ <and>
128
+ <is-derived-from>
129
+ <model-type>0x1004b</model-type> <!-- Device -->
130
+ </is-derived-from>
131
+ {landscape_filter}
132
+ <has-pcre>
133
+ <attribute id="0x1006e">
134
+ <value>{regex}</value>
135
+ </attribute>
136
+ </has-pcre>
137
+ </and>''' .format (regex = regex , landscape_filter = landscape_filter )
138
+ xml = self .models_search_template .format (models_filter = models_filter )
139
+ root = ET .fromstring (self .search_models (xml ))
140
+ models = root .findall ('.//ca:model' , self .xml_namespace )
141
+ devices = {
142
+ model .get ('mh' ): {
143
+ attr .get ('id' ): attr .text for attr in model .getchildren ()
144
+ } for model in models
145
+ }
146
+ return devices
147
+
148
+ def search_models (self , xml ):
149
+ url = '{}/spectrum/restful/models' .format (self .url )
150
+ res = requests .post (url , xml , auth = self .auth )
151
+ self .check_http_response (res )
152
+ return res .text
153
+
154
+ def set_maintenance (self , model_handle , on = True ):
155
+ return self .update_attribute (model_handle , 0x1295d , str (not on ))
76
156
77
157
def update_attribute (self , model_handle , attr_id , value ):
78
158
"""Update an attribute of a Spectrum model.
@@ -82,11 +162,7 @@ def update_attribute(self, model_handle, attr_id, value):
82
162
attr_id {int} -- Attribute ID of the attribute being updated.
83
163
value {int or str} -- Value to set the attribute to.
84
164
"""
85
-
86
- url = f'{ self .url } /spectrum/restful/model/{ hex (model_handle )} '
165
+ url = '{}/spectrum/restful/model/{}' .format (self .url , hex (model_handle ))
87
166
params = {'attr' : hex (attr_id ), 'val' : value }
88
167
res = requests .put (url , params = params , auth = self .auth )
89
168
self ._parse_update (res )
90
-
91
- def set_maintenance (self , model_handle , on = True ):
92
- return self .update_attribute (model_handle , 0x1295d , str (not on ))
0 commit comments