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.
- checksums.yaml +7 -0
- data/.yardopts +7 -0
- data/CHANGES.md +112 -0
- data/LICENSE.txt +174 -0
- data/README.md +426 -0
- data/THANKS.md +6 -0
- data/bin/cgrouper +485 -0
- data/bin/subnet-update +400 -0
- data/lib/jss-api.rb +2 -0
- data/lib/jss.rb +190 -0
- data/lib/jss/api_connection.rb +410 -0
- data/lib/jss/api_object.rb +616 -0
- data/lib/jss/api_object/advanced_search.rb +389 -0
- data/lib/jss/api_object/advanced_search/advanced_computer_search.rb +95 -0
- data/lib/jss/api_object/advanced_search/advanced_mobile_device_search.rb +96 -0
- data/lib/jss/api_object/advanced_search/advanced_user_search.rb +95 -0
- data/lib/jss/api_object/building.rb +92 -0
- data/lib/jss/api_object/category.rb +147 -0
- data/lib/jss/api_object/computer.rb +852 -0
- data/lib/jss/api_object/creatable.rb +98 -0
- data/lib/jss/api_object/criteriable.rb +189 -0
- data/lib/jss/api_object/criteriable/criteria.rb +231 -0
- data/lib/jss/api_object/criteriable/criterion.rb +228 -0
- data/lib/jss/api_object/department.rb +93 -0
- data/lib/jss/api_object/distribution_point.rb +560 -0
- data/lib/jss/api_object/extendable.rb +221 -0
- data/lib/jss/api_object/extension_attribute.rb +466 -0
- data/lib/jss/api_object/extension_attribute/computer_extension_attribute.rb +362 -0
- data/lib/jss/api_object/extension_attribute/mobile_device_extension_attribute.rb +189 -0
- data/lib/jss/api_object/extension_attribute/user_extension_attribute.rb +117 -0
- data/lib/jss/api_object/group.rb +380 -0
- data/lib/jss/api_object/group/computer_group.rb +124 -0
- data/lib/jss/api_object/group/mobile_device_group.rb +139 -0
- data/lib/jss/api_object/group/user_group.rb +139 -0
- data/lib/jss/api_object/ldap_server.rb +535 -0
- data/lib/jss/api_object/locatable.rb +286 -0
- data/lib/jss/api_object/matchable.rb +97 -0
- data/lib/jss/api_object/mobile_device.rb +556 -0
- data/lib/jss/api_object/netboot_server.rb +148 -0
- data/lib/jss/api_object/network_segment.rb +414 -0
- data/lib/jss/api_object/osx_configuration_profile.rb +262 -0
- data/lib/jss/api_object/package.rb +839 -0
- data/lib/jss/api_object/peripheral.rb +335 -0
- data/lib/jss/api_object/peripheral_type.rb +295 -0
- data/lib/jss/api_object/policy.rb +898 -0
- data/lib/jss/api_object/purchasable.rb +316 -0
- data/lib/jss/api_object/removable_macaddr.rb +98 -0
- data/lib/jss/api_object/scopable.rb +136 -0
- data/lib/jss/api_object/scopable/scope.rb +621 -0
- data/lib/jss/api_object/script.rb +631 -0
- data/lib/jss/api_object/self_servable.rb +356 -0
- data/lib/jss/api_object/site.rb +93 -0
- data/lib/jss/api_object/software_update_server.rb +109 -0
- data/lib/jss/api_object/updatable.rb +117 -0
- data/lib/jss/api_object/uploadable.rb +138 -0
- data/lib/jss/api_object/user.rb +272 -0
- data/lib/jss/client.rb +504 -0
- data/lib/jss/compatibility.rb +66 -0
- data/lib/jss/composer.rb +185 -0
- data/lib/jss/configuration.rb +306 -0
- data/lib/jss/db_connection.rb +298 -0
- data/lib/jss/exceptions.rb +95 -0
- data/lib/jss/ruby_extensions.rb +35 -0
- data/lib/jss/ruby_extensions/filetest.rb +43 -0
- data/lib/jss/ruby_extensions/hash.rb +79 -0
- data/lib/jss/ruby_extensions/ipaddr.rb +91 -0
- data/lib/jss/ruby_extensions/pathname.rb +77 -0
- data/lib/jss/ruby_extensions/string.rb +59 -0
- data/lib/jss/ruby_extensions/time.rb +63 -0
- data/lib/jss/server.rb +108 -0
- data/lib/jss/utility.rb +478 -0
- data/lib/jss/version.rb +31 -0
- 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"
|