ruby-jss 0.6.3

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.

Potentially problematic release.


This version of ruby-jss might be problematic. Click here for more details.

Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +7 -0
  3. data/CHANGES.md +112 -0
  4. data/LICENSE.txt +174 -0
  5. data/README.md +426 -0
  6. data/THANKS.md +6 -0
  7. data/bin/cgrouper +485 -0
  8. data/bin/subnet-update +400 -0
  9. data/lib/jss-api.rb +2 -0
  10. data/lib/jss.rb +190 -0
  11. data/lib/jss/api_connection.rb +410 -0
  12. data/lib/jss/api_object.rb +616 -0
  13. data/lib/jss/api_object/advanced_search.rb +389 -0
  14. data/lib/jss/api_object/advanced_search/advanced_computer_search.rb +95 -0
  15. data/lib/jss/api_object/advanced_search/advanced_mobile_device_search.rb +96 -0
  16. data/lib/jss/api_object/advanced_search/advanced_user_search.rb +95 -0
  17. data/lib/jss/api_object/building.rb +92 -0
  18. data/lib/jss/api_object/category.rb +147 -0
  19. data/lib/jss/api_object/computer.rb +852 -0
  20. data/lib/jss/api_object/creatable.rb +98 -0
  21. data/lib/jss/api_object/criteriable.rb +189 -0
  22. data/lib/jss/api_object/criteriable/criteria.rb +231 -0
  23. data/lib/jss/api_object/criteriable/criterion.rb +228 -0
  24. data/lib/jss/api_object/department.rb +93 -0
  25. data/lib/jss/api_object/distribution_point.rb +560 -0
  26. data/lib/jss/api_object/extendable.rb +221 -0
  27. data/lib/jss/api_object/extension_attribute.rb +466 -0
  28. data/lib/jss/api_object/extension_attribute/computer_extension_attribute.rb +362 -0
  29. data/lib/jss/api_object/extension_attribute/mobile_device_extension_attribute.rb +189 -0
  30. data/lib/jss/api_object/extension_attribute/user_extension_attribute.rb +117 -0
  31. data/lib/jss/api_object/group.rb +380 -0
  32. data/lib/jss/api_object/group/computer_group.rb +124 -0
  33. data/lib/jss/api_object/group/mobile_device_group.rb +139 -0
  34. data/lib/jss/api_object/group/user_group.rb +139 -0
  35. data/lib/jss/api_object/ldap_server.rb +535 -0
  36. data/lib/jss/api_object/locatable.rb +286 -0
  37. data/lib/jss/api_object/matchable.rb +97 -0
  38. data/lib/jss/api_object/mobile_device.rb +556 -0
  39. data/lib/jss/api_object/netboot_server.rb +148 -0
  40. data/lib/jss/api_object/network_segment.rb +414 -0
  41. data/lib/jss/api_object/osx_configuration_profile.rb +262 -0
  42. data/lib/jss/api_object/package.rb +839 -0
  43. data/lib/jss/api_object/peripheral.rb +335 -0
  44. data/lib/jss/api_object/peripheral_type.rb +295 -0
  45. data/lib/jss/api_object/policy.rb +898 -0
  46. data/lib/jss/api_object/purchasable.rb +316 -0
  47. data/lib/jss/api_object/removable_macaddr.rb +98 -0
  48. data/lib/jss/api_object/scopable.rb +136 -0
  49. data/lib/jss/api_object/scopable/scope.rb +621 -0
  50. data/lib/jss/api_object/script.rb +631 -0
  51. data/lib/jss/api_object/self_servable.rb +356 -0
  52. data/lib/jss/api_object/site.rb +93 -0
  53. data/lib/jss/api_object/software_update_server.rb +109 -0
  54. data/lib/jss/api_object/updatable.rb +117 -0
  55. data/lib/jss/api_object/uploadable.rb +138 -0
  56. data/lib/jss/api_object/user.rb +272 -0
  57. data/lib/jss/client.rb +504 -0
  58. data/lib/jss/compatibility.rb +66 -0
  59. data/lib/jss/composer.rb +185 -0
  60. data/lib/jss/configuration.rb +306 -0
  61. data/lib/jss/db_connection.rb +298 -0
  62. data/lib/jss/exceptions.rb +95 -0
  63. data/lib/jss/ruby_extensions.rb +35 -0
  64. data/lib/jss/ruby_extensions/filetest.rb +43 -0
  65. data/lib/jss/ruby_extensions/hash.rb +79 -0
  66. data/lib/jss/ruby_extensions/ipaddr.rb +91 -0
  67. data/lib/jss/ruby_extensions/pathname.rb +77 -0
  68. data/lib/jss/ruby_extensions/string.rb +59 -0
  69. data/lib/jss/ruby_extensions/time.rb +63 -0
  70. data/lib/jss/server.rb +108 -0
  71. data/lib/jss/utility.rb +478 -0
  72. data/lib/jss/version.rb +31 -0
  73. metadata +187 -0
@@ -0,0 +1,221 @@
1
+ ### Copyright 2016 Pixar
2
+ ###
3
+ ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
+ ### with the following modification; you may not use this file except in
5
+ ### compliance with the Apache License and the following modification to it:
6
+ ### Section 6. Trademarks. is deleted and replaced with:
7
+ ###
8
+ ### 6. Trademarks. This License does not grant permission to use the trade
9
+ ### names, trademarks, service marks, or product names of the Licensor
10
+ ### and its affiliates, except as required to comply with Section 4(c) of
11
+ ### the License and to reproduce the content of the NOTICE file.
12
+ ###
13
+ ### You may obtain a copy of the Apache License at
14
+ ###
15
+ ### http://www.apache.org/licenses/LICENSE-2.0
16
+ ###
17
+ ### Unless required by applicable law or agreed to in writing, software
18
+ ### distributed under the Apache License with the above modification is
19
+ ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
+ ### KIND, either express or implied. See the Apache License for the specific
21
+ ### language governing permissions and limitations under the Apache License.
22
+ ###
23
+ ###
24
+
25
+ ###
26
+ module JSS
27
+
28
+ #####################################
29
+ ### Module Variables
30
+ #####################################
31
+
32
+ #####################################
33
+ ### Module Methods
34
+ #####################################
35
+
36
+ #####################################
37
+ ### Sub-Modules
38
+ #####################################
39
+
40
+ ### A mix-in module for handling extension attribute data for objects in the JSS.
41
+ ###
42
+ ### This module provides standardized ways to deal with Extension Attribute data
43
+ ### in objects that gather that data ({JSS::Computer}s, {JSS::MobileDevice}s,
44
+ ### and {JSS::User}s). For working with the Extension Attributes themselves, see
45
+ ### {JSS::ExtensionAttribute} and its subclasses.
46
+ ###
47
+ ### API objects that have Extension Attribute data return it in an Array of Hashes,
48
+ ### one for each defined ExtensionAttribute for the class;
49
+ ### i.e. a {JSS::Computer}'s Array has one Hash for each {JSS::ComputerExtensionAttribute}
50
+ ### defined in the JSS.
51
+ ###
52
+ ### The Hash keys are:
53
+ ### * :id => the ExtAttr id
54
+ ### * :name => the ExtAttr name
55
+ ### * :type => the data type of the ExtAttr value
56
+ ### * :value => the value for the ExtAttr for this object as of the last report.
57
+ ###
58
+ ### Classes including this module must define the constant EXT_ATTRIB_CLASS
59
+ ### specifying which {JSS::ExtensionAttribute} subclass defines the relevant extension attributes.
60
+ ### For Example, {JSS::Computer} sets this:
61
+ ### EXT_ATTRIB_CLASS = JSS::ComputerExtensionAttribute
62
+ ###
63
+ ### During initialization those classes must call {#parse_ext_attrs} to populate the @extension_attributes
64
+ ### attribute from @init_data.
65
+ ###
66
+ ### Parsing also populates @ext_attrs which is a Hash of name => value for each EA.
67
+ ###
68
+ ### When updating or creating, those classes must add the REXML output of {#ext_attr_xml} to their
69
+ ### rest_xml output.
70
+ ###
71
+ module Extendable
72
+
73
+ #####################################
74
+ ### Constants
75
+ #####################################
76
+
77
+ ###
78
+ EXTENDABLE = true
79
+
80
+
81
+ ### ExtensionAttributes refer to the numeric data type as "Integer"
82
+ ### but the ext. attr values that come with extendable objects refer to
83
+ ### that data type as "Number". Here's an array with both, so we can
84
+ ### work with ether more easily.
85
+ NUMERIC_TYPES = ["Number", "Integer"]
86
+
87
+ #####################################
88
+ ### Variables
89
+ #####################################
90
+
91
+ #####################################
92
+ ### Attribtues
93
+ #####################################
94
+
95
+ ### @return [Array<Hash>] The extension attribute values for the object
96
+ attr_reader :extension_attributes
97
+
98
+ ### @return [Hash] A mapping of Ext Attrib names to their values
99
+ attr_reader :ext_attrs
100
+
101
+ #####################################
102
+ ### Mixed-in Instance Methods
103
+ #####################################
104
+
105
+
106
+
107
+ ###
108
+ ### Populate @extension_attributes (the Array of Hashes that comes from the API)
109
+ ### and @ext_attr_names, which is a Hash mapping the EA names to their
110
+ ### index in the @extension_attributes Array.
111
+ ###
112
+ ### Classes including this module should call this in #initialize
113
+ ###
114
+ ### @return [void]
115
+ ###
116
+ def parse_ext_attrs
117
+
118
+ unless @init_data[:extension_attributes]
119
+ @extension_attributes = []
120
+ @ext_attrs = {}
121
+ return
122
+ end
123
+
124
+ @extension_attributes = @init_data[:extension_attributes]
125
+ @ext_attrs = {}
126
+
127
+ @extension_attributes.each do |ea|
128
+ case ea[:type]
129
+
130
+ when "Date"
131
+ begin # if there's random non-date data, the parse will fail
132
+ ea[:value] = JSS.parse_datetime ea[:value]
133
+ rescue
134
+ end
135
+
136
+ when *NUMERIC_TYPES
137
+ ea[:value] = ea[:value].to_i unless ea[:value].to_s.empty?
138
+ end # case
139
+
140
+ @ext_attrs[ea[:name]] = ea[:value]
141
+
142
+ end # each do ea
143
+ end
144
+
145
+ ###
146
+ ### Set the value of an extension attribute
147
+ ###
148
+ ### If the extension attribute is defined as a popup menu, the value must be one of the
149
+ ### defined popup choices.
150
+ ###
151
+ ### If the ext. attrib. is defined with a data type of Integer, the value must be an Integer.
152
+ ###
153
+ ### If the ext. attrib. is defined with a data type of Date, the value will be converted to a Time
154
+ ###
155
+ ### @param name[String] the name of the extension attribute to set
156
+ ###
157
+ ### @param value[String,Time,Time,Integer] the new value for the extension attribute for this user
158
+ ###
159
+ ### @return [void]
160
+ ###
161
+ def set_ext_attr(name, value)
162
+
163
+ # this will raise an exception if the name doesn't exist
164
+ ea_def = self.class::EXT_ATTRIB_CLASS.new :name => name
165
+
166
+ unless JSS::ExtensionAttribute::EDITABLE_INPUT_TYPES.include? ea_def.input_type
167
+ raise JSS::UnsupportedError, "The value for #{name} cannot be modified. It is gathered during inventory updates."
168
+ end
169
+
170
+ if ea_def.input_type == "Pop-up Menu" and (not ea_def.popup_choices.include? value.to_s)
171
+ raise JSS::UnsupportedError, "The value for #{name} must be one of: '#{ea_def.popup_choices.join("' '")}'"
172
+ end
173
+
174
+ case ea_def.data_type
175
+ when "Date"
176
+
177
+ value = JSS.parse_datetime value
178
+
179
+ when *NUMERIC_TYPES
180
+ raise JSS::InvalidDataError, "The value for #{name} must be an integer" unless value.kind_of? Integer
181
+
182
+ end #case
183
+
184
+ @extension_attributes.each do |ea|
185
+ ea[:value] = value if ea[:name] == name
186
+ end
187
+ @ext_attrs[name] = value
188
+
189
+ @need_to_update = true
190
+ end
191
+
192
+ ###
193
+ ### @api private
194
+ ###
195
+ ### @return [REXML::Element] An <extension_attribute> element to be
196
+ ### included in the rest_xml of objects that mix-in this module.
197
+ ###
198
+ def ext_attr_xml
199
+
200
+ eaxml = REXML::Element.new('extension_attributes')
201
+
202
+ @extension_attributes.each do |ea|
203
+ ea_el = eaxml.add_element('extension_attribute')
204
+ ea_el.add_element('name').text = ea[:name]
205
+
206
+ if ea[:type] == "Date"
207
+ begin
208
+ ea_el.add_element('value').text = ea[:value].to_jss_date
209
+ rescue
210
+ ea_el.add_element('value').text = ea[:value].to_s
211
+ end
212
+ else
213
+ ea_el.add_element('value').text = ea[:value]
214
+ end # if
215
+ end # each do ea
216
+
217
+ return eaxml
218
+ end
219
+
220
+ end # module Purchasable
221
+ end # module JSS
@@ -0,0 +1,466 @@
1
+ ### Copyright 2016 Pixar
2
+ ###
3
+ ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
+ ### with the following modification; you may not use this file except in
5
+ ### compliance with the Apache License and the following modification to it:
6
+ ### Section 6. Trademarks. is deleted and replaced with:
7
+ ###
8
+ ### 6. Trademarks. This License does not grant permission to use the trade
9
+ ### names, trademarks, service marks, or product names of the Licensor
10
+ ### and its affiliates, except as required to comply with Section 4(c) of
11
+ ### the License and to reproduce the content of the NOTICE file.
12
+ ###
13
+ ### You may obtain a copy of the Apache License at
14
+ ###
15
+ ### http://www.apache.org/licenses/LICENSE-2.0
16
+ ###
17
+ ### Unless required by applicable law or agreed to in writing, software
18
+ ### distributed under the Apache License with the above modification is
19
+ ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
+ ### KIND, either express or implied. See the Apache License for the specific
21
+ ### language governing permissions and limitations under the Apache License.
22
+ ###
23
+ ###
24
+
25
+ ###
26
+ module JSS
27
+
28
+
29
+
30
+ #####################################
31
+ ### Constants
32
+ #####################################
33
+
34
+ #####################################
35
+ ### Module Variables
36
+ #####################################
37
+
38
+ #####################################
39
+ ### Module Methods
40
+ #####################################
41
+
42
+ ####################################
43
+ ### Classes
44
+ #####################################
45
+
46
+
47
+ ###
48
+ ### The parent class of ExtensionAttribute objects in the JSS.
49
+ ###
50
+ ### The API extension attribute objects work with the definitions of extension
51
+ ### attributes, not the resulting values stored in the JSS with the inventory
52
+ ### reports.
53
+ ###
54
+ ### This superclass, however, uses the {AdvancedSearch} subclasses to provide
55
+ ### access to the reported values in two ways:
56
+ ### * A list of target objects with a certain value for the ExtensionAttribute instance.
57
+ ### See the {#all_with_result} method for details
58
+ ### * A list of the most recent value for this ExtensionAttribute in all targets in the JSS
59
+ ###
60
+ ### The {ComputerExtensionAttribute} subclass offers a {ComputerExtensionAttribute#history}
61
+ ### method providing the history of values for the EA for one computer. This requires
62
+ ### MySQL access to the JSS database since that history isn't available via the API.
63
+ ###
64
+ ### Subclasses of ExtensionAttribute must define these constants:
65
+ ### * TARGET_CLASS - the {APIObject} subclass to which the extention attribute applies.
66
+ ### e.g. {JSS::Computer}
67
+ ###
68
+ ### * ALL_TARGETS_CRITERION - a {JSS::Criteriable::Criterion} instance that will be used in
69
+ ### an {AdvancedSearch} to find all of members of the TARGET_CLASS
70
+ ###
71
+ ### @see JSS::APIObject
72
+ ###
73
+ class ExtensionAttribute < JSS::APIObject
74
+
75
+ #####################################
76
+ ### Mix-Ins
77
+ #####################################
78
+ include JSS::Creatable
79
+ include JSS::Updatable
80
+
81
+ #####################################
82
+ ### Class Methods
83
+ #####################################
84
+
85
+ #####################################
86
+ ### Class Constants
87
+ #####################################
88
+
89
+ ### What kinds of data can be created by EAs?
90
+ ### Note, Dates must be in the format "YYYY-MM-DD hh:mm:ss"
91
+ DATA_TYPES = ["String", "Date", "Integer"]
92
+ DEFAULT_DATA_TYPE = "String"
93
+
94
+ ### Where does the data come from?
95
+ INPUT_TYPES = [ "Text Field", "Pop-up Menu", "script", "LDAP Attribute Mapping"]
96
+ DEFAULT_INPUT_TYPE = "Text Field"
97
+
98
+ ### These input types can be modified, the others cannot.
99
+ EDITABLE_INPUT_TYPES = ["Text Field", "Pop-up Menu"]
100
+
101
+ ### Where can it be displayed in the WebApp?
102
+ ### subclasses can add to this list
103
+ WEB_DISPLAY_CHOICES = [
104
+ "General",
105
+ "Operating System",
106
+ "Hardware",
107
+ "User and Location",
108
+ "Purchasing",
109
+ "Extension Attributes"
110
+ ]
111
+ DEFAULT_WEB_DISPLAY_CHOICE = "Extension Attributes"
112
+
113
+ LAST_RECON_FIELD = 'Last Inventory Update'
114
+ LAST_RECON_FIELD_SYM = LAST_RECON_FIELD.gsub(' ', '_').to_sym
115
+
116
+ USERNAME_FIELD = "Username"
117
+ USERNAME_FIELD_SYM = USERNAME_FIELD.to_sym
118
+
119
+ ######################
120
+ ### Attributes
121
+ ######################
122
+
123
+ ### :id, :name, :in_jss, :need_to_update, and :rest_rsrc come from JSS::APIObject
124
+
125
+ ### @return [String] description of the ext attrib
126
+ attr_reader :description
127
+
128
+ ### @return [String] the type of data created by the EA. Must be one of DATA_TYPES
129
+ attr_reader :data_type
130
+
131
+ ### @return [String] where does this data come from? Must be one of the INPUT_TYPES.
132
+ attr_reader :input_type
133
+
134
+ ### @return [Array<String>] the choices available in the UI when the @input_type is "Pop-up Menu"
135
+ attr_reader :popup_choices
136
+
137
+ ### @return [String] In which part of the web UI does the data appear?
138
+ attr_reader :web_display
139
+
140
+
141
+
142
+ #####################################
143
+ ### Constructor
144
+ #####################################
145
+
146
+ ###
147
+ ### @see JSS::APIObject#initialize
148
+ ###
149
+ def initialize(args = {})
150
+
151
+ super args
152
+
153
+ ### @init_data now has the raw data
154
+ ### so fill in our attributes or set defaults
155
+
156
+ @description = @init_data[:description]
157
+ @data_type = @init_data[:data_type] || DEFAULT_DATA_TYPE
158
+ @web_display = @init_data[:inventory_display] || DEFAULT_WEB_DISPLAY_CHOICE
159
+
160
+
161
+ if @init_data[:input_type]
162
+ @input_type = @init_data[:input_type][:type] || DEFAULT_INPUT_TYPE
163
+ @popup_choices = @init_data[:input_type][:popup_choices]
164
+ else
165
+ @input_type = DEFAULT_INPUT_TYPE
166
+ end
167
+
168
+ ### the name of the EA might have spaces and caps, which the will come to us as symbols with the spaces
169
+ ### as underscores, like this.
170
+ @symbolized_name = @name.gsub(' ','_').to_sym
171
+
172
+ end # init
173
+
174
+ #####################################
175
+ ### Public Instance Methods
176
+ #####################################
177
+
178
+ ###
179
+ ### @see JSS::Creatable#create
180
+ ###
181
+ def create
182
+ if @input_type == "Pop-up Menu"
183
+ raise MissingDataError, "No popup_choices set for Pop-up Menu input_type." unless @popup_choices.kind_of? Array and (not @popup_choices.empty?)
184
+ end
185
+ super
186
+ end
187
+
188
+ ###
189
+ ### @see JSS::Updatable#update
190
+ ###
191
+ def update
192
+ if @input_type == "Pop-up Menu"
193
+ raise MissingDataError, "No popup_choices set for Pop-up Menu input_type." unless @popup_choices.kind_of? Array and (not @popup_choices.empty?)
194
+ end
195
+ super
196
+ end
197
+
198
+
199
+ ###
200
+ ### @see JSS::APIObject#delete
201
+ ###
202
+ def delete
203
+ orig_open_timeout = JSS::API.cnx.options[:open_timeout]
204
+ orig_timeout = JSS::API.cnx.options[:timeout]
205
+ JSS::API.timeout = orig_timeout + 1800
206
+ JSS::API.open_timeout = orig_open_timeout + 1800
207
+ begin
208
+ super
209
+ ensure
210
+ JSS::API.timeout = orig_timeout
211
+ JSS::API.open_timeout = orig_open_timeout
212
+ end
213
+ end
214
+
215
+ ###
216
+ ### Change the description of this EA
217
+ ###
218
+ ### @param new_val[String] the new value
219
+ ###
220
+ ### @return [void]
221
+ ###
222
+ def description= (new_val)
223
+ return nil if @description == new_val
224
+ @description = new_val
225
+ @need_to_update = true
226
+ end # name=(newname)
227
+
228
+ ###
229
+ ### Change the data type of this EA
230
+ ###
231
+ ### @param new_val[String] the new value, which must be a member of DATA_TYPES
232
+ ###
233
+ ### @return [void]
234
+ ###
235
+ def data_type= (new_val)
236
+ return nil if @data_type == new_val
237
+ raise JSS::InvalidDataError, "data_type must be a string, one of: #{DATA_TYPES.join(", ")}" unless DATA_TYPES.include? new_val
238
+ @data_type = new_val
239
+ @need_to_update = true
240
+ end #
241
+
242
+
243
+ ###
244
+ ### Change the inventory_display of this EA
245
+ ###
246
+ ### @param new_val[String] the new value, which must be a member of INVENTORY_DISPLAY_CHOICES
247
+ ###
248
+ ### @return [void]
249
+ ###
250
+ def web_display= (new_val)
251
+ return nil if @web_display == new_val
252
+ raise JSS::InvalidDataError, "inventory_display must be a string, one of: #{INVENTORY_DISPLAY_CHOICES.join(", ")}" unless WEB_DISPLAY_CHOICES.include? new_val
253
+ @web_display = new_val
254
+ @need_to_update = true
255
+ end #
256
+
257
+
258
+ ###
259
+ ### Change the input type of this EA
260
+ ###
261
+ ### @param new_val[String] the new value, which must be a member of INPUT_TYPES
262
+ ###
263
+ ### @return [void]
264
+ ###
265
+ def input_type= (new_val)
266
+ return nil if @input_type == new_val
267
+ raise JSS::InvalidDataError, "input_type must be a string, one of: #{INPUT_TYPES.join(", ")}" unless INPUT_TYPES.include? new_val
268
+ @input_type = new_val
269
+ @popup_choices = nil if @input_type == "Text Field"
270
+ @need_to_update = true
271
+ end #
272
+
273
+ ###
274
+ ### Change the Popup Choices of this EA
275
+ ### New value must be an Array, the items will be converted to Strings.
276
+ ###
277
+ ### This automatically sets input_type to "Pop-up Menu"
278
+ ###
279
+ ### Values are checked to ensure they match the @data_type
280
+ ### Note, Dates must be in the format "YYYY-MM-DD hh:mm:ss"
281
+ ###
282
+ ### @param new_val[Array<#to_s>] the new values
283
+ ###
284
+ ### @return [void]
285
+ ###
286
+ def popup_choices= (new_val)
287
+ return nil if @popup_choices == new_val
288
+ raise JSS::InvalidDataError, "popup_choices must be an Array" unless new_val.kind_of?(Array)
289
+
290
+ ### convert each one to a String,
291
+ ### and check that it matches the @data_type
292
+ new_val.map! do |v|
293
+ v = v.to_s.strip
294
+ case @data_type
295
+ when "Date"
296
+ raise JSS::InvalidDataError, "data_type is Date, but '#{v}' is not formatted 'YYYY-MM-DD hh:mm:ss'" unless v =~ /^\d{4}(-\d\d){2} (\d\d:){2}\d\d$/
297
+ when "Integer"
298
+ raise JSS::InvalidDataError, "data_type is Integer, but '#{v}' is not one" unless v =~ /^\d+$/
299
+ end
300
+ v
301
+ end
302
+ self.input_type = "Pop-up Menu"
303
+ @popup_choices = new_val
304
+ @need_to_update = true
305
+ end #
306
+
307
+
308
+ ###
309
+ ### Get an Array of Hashes for all inventory objects
310
+ ### with a desired result in their latest report for this EA.
311
+ ###
312
+ ### Each Hash is one inventory object (computer, mobile device, user), with these keys:
313
+ ### :id - the computer id
314
+ ### :name - the computer name
315
+ ### :value - the matching ext attr value for the objects latest report.
316
+ ###
317
+ ### This is done by creating a temprary {AdvancedSearch} for objects with matching
318
+ ### values in the EA field, then getting the #search_results hash from it.
319
+ ###
320
+ ### The AdvancedSearch is then deleted.
321
+ ###
322
+ ### @param search_type[String] how are we comparing the stored value with the desired value.
323
+ ### must be a member of JSS::Criterion::SEARCH_TYPES
324
+ ###
325
+ ### @param desired_value[String] the value to compare with the stored value to determine a match.
326
+ ###
327
+ ### @return [Array<Hash{:id=>Integer,:name=>String,:value=>String,Integer,Time}>] the items that match the result.
328
+ ###
329
+ def all_with_result(search_type, desired_value)
330
+ raise JSS::NoSuchItemError, "EA Not In JSS! Use #create to create this #{self.class::RSRC_OBJECT_KEY}." unless @in_jss
331
+ raise JSS::InvalidDataError, "Invalid search_type, see JSS::Criteriable::Criterion::SEARCH_TYPES" unless JSS::Criteriable::Criterion::SEARCH_TYPES.include? search_type.to_s
332
+ begin
333
+
334
+ search_class = self.class::TARGET_CLASS::SEARCH_CLASS
335
+ acs = search_class.new :id => :new, :name => "JSSgem-EA-#{Time.now.to_jss_epoch}-result-search"
336
+ acs.display_fields = [@name]
337
+ crit_list = [JSS::Criteriable::Criterion.new(:and_or => "and", :name => @name, :search_type => search_type.to_s, :value => desired_value)]
338
+ acs.criteria = JSS::Criteriable::Criteria.new crit_list
339
+
340
+ acs.create :get_results
341
+
342
+ results = []
343
+
344
+ acs.search_results.each{ |i|
345
+ value = case @data_type
346
+ when "Date" then JSS.parse_datetime i[@symbolized_name]
347
+ when "Integer" then i[@symbolized_name].to_i
348
+ else i[@symbolized_name]
349
+ end # case
350
+ results << {:id => i[:id], :name => i[:name], :value => value}
351
+ }
352
+
353
+ ensure
354
+ acs.delete
355
+ end
356
+ results
357
+ end
358
+
359
+
360
+
361
+ ### Return an Array of Hashes showing the most recent value
362
+ ### for this EA on all inventory objects in the JSS.
363
+ ###
364
+ ### Each Hash is one inventory object (computer, mobile device, user), with these keys:
365
+ ### :id - the jss id
366
+ ### :name - the object (computer, user, mobiledevice) name
367
+ ### :value - the most recent ext attr value for the object.
368
+ ### :as_of - the timestamp of when the value was collected (nil for User EAs)
369
+ ### :username - the username associated with the object
370
+ ###
371
+ ### This is done by creating a temporary {AdvancedSearch}
372
+ ### for all objects, with the EA as a display field. The #search_result
373
+ ### then contains the desired data.
374
+ ###
375
+ ### The AdvancedSearch is then deleted.
376
+ ###
377
+ ### @return [Array<Hash{:id=>Integer,:name=>String,:value=>String,Integer,Time,:as_of=>Time}>]
378
+ ###
379
+ ### @see JSS::AdvancedSearch
380
+ ###
381
+ ### @see JSS::AdvancedComputerSearch
382
+ ###
383
+ ### @see JSS::AdvancedMobileDeviceSearch
384
+ ###
385
+ ### @see JSS::AdvancedUserSearch
386
+ ###
387
+ def latest_values
388
+ raise JSS::NoSuchItemError, "EA Not In JSS! Use #create to create this #{self.class::RSRC_OBJECT_KEY}." unless @in_jss
389
+ tmp_advsrch = "JSSgem-EA-#{Time.now.to_jss_epoch}-latest-search"
390
+
391
+ begin
392
+ search_class = self.class::TARGET_CLASS::SEARCH_CLASS
393
+ acs = search_class.new :id => :new, :name => tmp_advsrch
394
+ acs.display_fields = self.class::TARGET_CLASS == JSS::User ? [@name, USERNAME_FIELD] : [@name, USERNAME_FIELD, LAST_RECON_FIELD]
395
+
396
+ # search for 'Username like "" ' because all searchable object classes have a "Username" value
397
+ crit = JSS::Criteriable::Criterion.new(:and_or => "and", :name => "Username", :search_type => "like", :value => '')
398
+ # crit = self.class::ALL_TARGETS_CRITERION
399
+ acs.criteria = JSS::Criteriable::Criteria.new [crit]
400
+ acs.create :get_results
401
+
402
+ results = []
403
+
404
+ acs.search_results.each do |i|
405
+ value = case @data_type
406
+ when "Date" then JSS.parse_datetime i[@symbolized_name]
407
+ when "Integer" then i[@symbolized_name].to_i
408
+ else i[@symbolized_name]
409
+ end # case
410
+
411
+ as_of = Time.parse(i[LAST_RECON_FIELD_SYM]) if i[LAST_RECON_FIELD_SYM]
412
+
413
+ results << {:id => i[:id], :name => i[:name], :username => i[USERNAME_FIELD_SYM] , :value => value, :as_of => as_of }
414
+ end #acs.search_results.each
415
+
416
+ ensure
417
+ acs.delete
418
+ self.class::TARGET_CLASS::SEARCH_CLASS.new(:name => tmp_advsrch).delete if self.class::TARGET_CLASS::SEARCH_CLASS.all_names(:refresh).include? tmp_advsrch
419
+ end
420
+
421
+ results
422
+
423
+ end
424
+
425
+
426
+ ### aliases
427
+
428
+ alias desc description
429
+
430
+
431
+
432
+ ######################
433
+ ### Private Instance Methods
434
+ #####################
435
+
436
+ private
437
+
438
+ ###
439
+ ### Return a REXML object for this ext attr, with the current values.
440
+ ### Subclasses should augment this in their rest_xml methods
441
+ ### then return it .to_s, for saving or updating
442
+ ###
443
+ def rest_rexml
444
+ ea = REXML::Element.new self.class::RSRC_OBJECT_KEY.to_s
445
+ ea.add_element('name').text = @name
446
+ ea.add_element('description').text = @description
447
+ ea.add_element('data_type').text = @data_type
448
+ ea.add_element('inventory_display').text = @web_display
449
+
450
+ it = ea.add_element('input_type')
451
+ it.add_element('type').text = @input_type
452
+ if @input_type == "Pop-up Menu"
453
+ pcs = it.add_element('popup_choices')
454
+ @popup_choices.each{|pc| pcs.add_element('choice').text = pc}
455
+ end
456
+ return ea
457
+ end # rest xml
458
+
459
+
460
+ end # class ExtAttrib
461
+
462
+ end # module JSS
463
+
464
+ require "jss/api_object/extension_attribute/computer_extension_attribute"
465
+ require "jss/api_object/extension_attribute/mobile_device_extension_attribute"
466
+ require "jss/api_object/extension_attribute/user_extension_attribute"