ruby-jss 1.2.3 → 1.2.4a1

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.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/lib/jamf.rb +169 -0
  3. data/lib/jamf/api/abstract_classes/collection_resource.rb +422 -0
  4. data/lib/jamf/api/abstract_classes/generic_reference.rb +145 -0
  5. data/lib/jamf/api/abstract_classes/json_object.rb +1074 -0
  6. data/lib/jamf/api/abstract_classes/prestage.rb +219 -0
  7. data/lib/jamf/api/abstract_classes/prestage_skip_setup_items.rb +126 -0
  8. data/lib/jamf/api/abstract_classes/resource.rb +250 -0
  9. data/lib/jamf/api/abstract_classes/singleton_resource.rb +87 -0
  10. data/lib/jamf/api/attribute_classes/ip_address.rb +66 -0
  11. data/lib/jamf/api/attribute_classes/timestamp.rb +144 -0
  12. data/lib/jamf/api/connection.rb +734 -0
  13. data/lib/jamf/api/connection/api_error.rb +111 -0
  14. data/lib/jamf/api/connection/api_error_styleguide.rb +96 -0
  15. data/lib/jamf/api/connection/token.rb +220 -0
  16. data/lib/jamf/api/json_objects/account_prefs.rb +79 -0
  17. data/lib/jamf/api/json_objects/android_details.rb +139 -0
  18. data/lib/jamf/api/json_objects/appletv_details.rb +110 -0
  19. data/lib/jamf/api/json_objects/attachment.rb +68 -0
  20. data/lib/jamf/api/json_objects/cellular_network.rb +151 -0
  21. data/lib/jamf/api/json_objects/change_log_entry.rb +77 -0
  22. data/lib/jamf/api/json_objects/computer_prestage_skip_setup_items.rb +67 -0
  23. data/lib/jamf/api/json_objects/country.rb +51 -0
  24. data/lib/jamf/api/json_objects/extension_attribute_value.rb +128 -0
  25. data/lib/jamf/api/json_objects/installed_application.rb +59 -0
  26. data/lib/jamf/api/json_objects/installed_certificate.rb +53 -0
  27. data/lib/jamf/api/json_objects/installed_configuration_profile.rb +67 -0
  28. data/lib/jamf/api/json_objects/installed_ebook.rb +58 -0
  29. data/lib/jamf/api/json_objects/installed_provisioning_profile.rb +59 -0
  30. data/lib/jamf/api/json_objects/inventory_preload_extension_attribute.rb +52 -0
  31. data/lib/jamf/api/json_objects/ios_details.rb +244 -0
  32. data/lib/jamf/api/json_objects/location.rb +95 -0
  33. data/lib/jamf/api/json_objects/md_prestage_name.rb +57 -0
  34. data/lib/jamf/api/json_objects/md_prestage_names.rb +82 -0
  35. data/lib/jamf/api/json_objects/md_prestage_skip_setup_items.rb +165 -0
  36. data/lib/jamf/api/json_objects/mobile_device_details.rb +219 -0
  37. data/lib/jamf/api/json_objects/mobile_device_security.rb +101 -0
  38. data/lib/jamf/api/json_objects/prestage_assignment.rb +61 -0
  39. data/lib/jamf/api/json_objects/prestage_location.rb +104 -0
  40. data/lib/jamf/api/json_objects/prestage_purchasing_data.rb +132 -0
  41. data/lib/jamf/api/json_objects/prestage_scope.rb +54 -0
  42. data/lib/jamf/api/json_objects/prestage_sync_status.rb +63 -0
  43. data/lib/jamf/api/json_objects/purchasing_data.rb +125 -0
  44. data/lib/jamf/api/mixins/abstract.rb +58 -0
  45. data/lib/jamf/api/mixins/bulk_deletable.rb +39 -0
  46. data/lib/jamf/api/mixins/change_log.rb +136 -0
  47. data/lib/jamf/api/mixins/extendable.rb +75 -0
  48. data/lib/jamf/api/mixins/immutable.rb +39 -0
  49. data/lib/jamf/api/mixins/locatable.rb +124 -0
  50. data/lib/jamf/api/mixins/lockable.rb +48 -0
  51. data/lib/jamf/api/mixins/referable.rb +92 -0
  52. data/lib/jamf/api/mixins/searchable.rb +202 -0
  53. data/lib/jamf/api/mixins/uncreatable.rb +40 -0
  54. data/lib/jamf/api/mixins/undeletable.rb +40 -0
  55. data/lib/jamf/api/resources/collection_resources/account.rb +163 -0
  56. data/lib/jamf/api/resources/collection_resources/building.rb +114 -0
  57. data/lib/jamf/api/resources/collection_resources/category.rb +82 -0
  58. data/lib/jamf/api/resources/collection_resources/computer.rb +49 -0
  59. data/lib/jamf/api/resources/collection_resources/computer_prestage.rb +80 -0
  60. data/lib/jamf/api/resources/collection_resources/department.rb +79 -0
  61. data/lib/jamf/api/resources/collection_resources/extension_attribute.rb +45 -0
  62. data/lib/jamf/api/resources/collection_resources/inventory_preload_record.rb +274 -0
  63. data/lib/jamf/api/resources/collection_resources/md_prestage.rb +139 -0
  64. data/lib/jamf/api/resources/collection_resources/mobile_device.rb +315 -0
  65. data/lib/jamf/api/resources/collection_resources/script.rb +190 -0
  66. data/lib/jamf/api/resources/collection_resources/site.rb +77 -0
  67. data/lib/jamf/api/resources/singleton_resources/app_store_country_codes.rb +131 -0
  68. data/lib/jamf/api/resources/singleton_resources/authorization.rb +88 -0
  69. data/lib/jamf/api/resources/singleton_resources/client_checkin_settings.rb +139 -0
  70. data/lib/jamf/api/resources/singleton_resources/reenrollment_settings.rb +95 -0
  71. data/lib/jamf/client.rb +301 -0
  72. data/lib/jamf/client/jamf_binary.rb +132 -0
  73. data/lib/jamf/client/jamf_helper.rb +298 -0
  74. data/lib/jamf/client/management_action.rb +114 -0
  75. data/lib/jamf/compatibility.rb +88 -0
  76. data/lib/jamf/composer.rb +190 -0
  77. data/lib/jamf/configuration.rb +281 -0
  78. data/lib/jamf/exceptions.rb +107 -0
  79. data/lib/jamf/ruby_extensions.rb +36 -0
  80. data/lib/jamf/ruby_extensions/array.rb +35 -0
  81. data/lib/jamf/ruby_extensions/array/predicates.rb +46 -0
  82. data/lib/jamf/ruby_extensions/array/utils.rb +47 -0
  83. data/lib/jamf/ruby_extensions/filetest.rb +32 -0
  84. data/lib/jamf/ruby_extensions/filetest/predicates.rb +46 -0
  85. data/lib/jamf/ruby_extensions/hash.rb +33 -0
  86. data/lib/jamf/ruby_extensions/hash/backports.rb +92 -0
  87. data/lib/jamf/ruby_extensions/ipaddr.rb +37 -0
  88. data/lib/jamf/ruby_extensions/ipaddr/utils.rb +95 -0
  89. data/lib/jamf/ruby_extensions/object.rb +30 -0
  90. data/lib/jamf/ruby_extensions/object/predicates.rb +51 -0
  91. data/lib/jamf/ruby_extensions/pathname.rb +39 -0
  92. data/lib/jamf/ruby_extensions/pathname/predicates.rb +50 -0
  93. data/lib/jamf/ruby_extensions/pathname/utils.rb +75 -0
  94. data/lib/jamf/ruby_extensions/string.rb +35 -0
  95. data/lib/jamf/ruby_extensions/string/backports.rb +66 -0
  96. data/lib/jamf/ruby_extensions/string/conversions.rb +65 -0
  97. data/lib/jamf/ruby_extensions/string/predicates.rb +47 -0
  98. data/lib/jamf/utility.rb +423 -0
  99. data/lib/jamf/validate.rb +224 -0
  100. data/lib/jamf/version.rb +32 -0
  101. data/lib/jpapi.rb +26 -0
  102. data/lib/jss/version.rb +1 -1
  103. metadata +104 -4
@@ -0,0 +1,65 @@
1
+ # Copyright 2019 Pixar
2
+
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "Apache License")
5
+ # with the following modification; you may not use this file except in
6
+ # compliance with the Apache License and the following modification to it:
7
+ # Section 6. Trademarks. is deleted and replaced with:
8
+ #
9
+ # 6. Trademarks. This License does not grant permission to use the trade
10
+ # names, trademarks, service marks, or product names of the Licensor
11
+ # and its affiliates, except as required to comply with Section 4(c) of
12
+ # the License and to reproduce the content of the NOTICE file.
13
+ #
14
+ # You may obtain a copy of the Apache License at
15
+ #
16
+ # http://www.apache.org/licenses/LICENSE-2.0
17
+ #
18
+ # Unless required by applicable law or agreed to in writing, software
19
+ # distributed under the Apache License with the above modification is
20
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21
+ # KIND, either express or implied. See the Apache License for the specific
22
+ # language governing permissions and limitations under the Apache License.
23
+
24
+ module JamfRubyExtensions
25
+
26
+ module String
27
+
28
+ module Conversions
29
+
30
+ # Convert the strings "true" and "false"
31
+ # (after stripping whitespace and downcasing)
32
+ # to TrueClass and FalseClass respectively
33
+ #
34
+ # Return nil if any other string.
35
+ #
36
+ # @return [Boolean,nil] the boolean value
37
+ #
38
+ def j_to_bool
39
+ case strip.downcase
40
+ when 'true' then true
41
+ when 'false' then false
42
+ end # case
43
+ end # to bool
44
+
45
+ # Convert a string to a Jamf::Timestamp object
46
+ #
47
+ # @return [Time] the time represented by the string.
48
+ #
49
+ def j_to_timestamp
50
+ Jamf::Timestamp.new self
51
+ end
52
+
53
+ # Convert a String to a Pathname object
54
+ #
55
+ # @return [Pathname]
56
+ #
57
+ def j_to_pathname
58
+ Pathname.new self
59
+ end
60
+
61
+ end # module
62
+
63
+ end # module
64
+
65
+ end # module
@@ -0,0 +1,47 @@
1
+ # Copyright 2019 Pixar
2
+
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "Apache License")
5
+ # with the following modification; you may not use this file except in
6
+ # compliance with the Apache License and the following modification to it:
7
+ # Section 6. Trademarks. is deleted and replaced with:
8
+ #
9
+ # 6. Trademarks. This License does not grant permission to use the trade
10
+ # names, trademarks, service marks, or product names of the Licensor
11
+ # and its affiliates, except as required to comply with Section 4(c) of
12
+ # the License and to reproduce the content of the NOTICE file.
13
+ #
14
+ # You may obtain a copy of the Apache License at
15
+ #
16
+ # http://www.apache.org/licenses/LICENSE-2.0
17
+ #
18
+ # Unless required by applicable law or agreed to in writing, software
19
+ # distributed under the Apache License with the above modification is
20
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21
+ # KIND, either express or implied. See the Apache License for the specific
22
+ # language governing permissions and limitations under the Apache License.
23
+ #
24
+ #
25
+
26
+ module JamfRubyExtensions
27
+
28
+ module String
29
+
30
+ module Predicates
31
+
32
+ INTEGER_RE = /\A[0-9]+\Z/.freeze
33
+
34
+ # Is this string also a positive integer?
35
+ # (i.e. it consists only of numberic digits)
36
+ #
37
+ # @return [Boolean]
38
+ #
39
+ def j_integer?
40
+ self =~ INTEGER_RE ? true : false
41
+ end
42
+
43
+ end # module
44
+
45
+ end # module
46
+
47
+ end # module
@@ -0,0 +1,423 @@
1
+ # Copyright 2019 Pixar
2
+
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "Apache License")
5
+ # with the following modification; you may not use this file except in
6
+ # compliance with the Apache License and the following modification to it:
7
+ # Section 6. Trademarks. is deleted and replaced with:
8
+ #
9
+ # 6. Trademarks. This License does not grant permission to use the trade
10
+ # names, trademarks, service marks, or product names of the Licensor
11
+ # and its affiliates, except as required to comply with Section 4(c) of
12
+ # the License and to reproduce the content of the NOTICE file.
13
+ #
14
+ # You may obtain a copy of the Apache License at
15
+ #
16
+ # http://www.apache.org/licenses/LICENSE-2.0
17
+ #
18
+ # Unless required by applicable law or agreed to in writing, software
19
+ # distributed under the Apache License with the above modification is
20
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21
+ # KIND, either express or implied. See the Apache License for the specific
22
+ # language governing permissions and limitations under the Apache License.
23
+ #
24
+ #
25
+
26
+ # The Module
27
+ module Jamf
28
+
29
+ # Constants
30
+ ###################################
31
+
32
+ # These Utility constants are useful all over the place.
33
+ # Many of them are commonly used Strings.
34
+
35
+ BLANK = ''.freeze
36
+
37
+ UNDERSCORE = '_'.freeze
38
+
39
+ # A collection of useful utility methods. Mostly for
40
+ # converting values between formats, parsing data, and
41
+ # user interaction.
42
+
43
+ # TODO: confirm need for each method in Jamf Pro API.
44
+
45
+ # Converts an OS Version into an Array of higher OS versions.
46
+ #
47
+ # It's unlikely that this library will still be in use as-is by the release of OS X 10.30.20.
48
+ # Hopefully well before then JAMF will implement a "minimum OS" in the JSS itself.
49
+ #
50
+ # @param min_os [String] the mimimum OS version to expand, e.g. ">=10.6.7" or "10.6.7"
51
+ #
52
+ # @return [Array] Nearly all potential OS versions from the minimum to 10.19.x.
53
+ #
54
+ # @example
55
+ # JSS.expand_min_os ">=10.6.7" # => returns this array
56
+ # # ["10.6.7",
57
+ # # "10.6.8",
58
+ # # "10.6.9",
59
+ # # ...
60
+ # # "10.6.20",
61
+ # # "10.7.x",
62
+ # # "10.8.x",
63
+ # # ...
64
+ # # "10.30.x"]
65
+ #
66
+ #
67
+ def self.expand_min_os(min_os)
68
+ min_os = min_os.delete '>='
69
+
70
+ # split the version into major, minor and maintenance release numbers
71
+ (maj, min, maint) = min_os.split('.')
72
+ maint = 'x' if maint.nil? || maint == '0'
73
+
74
+ # if the maint release number is an "x" just start the list of OK OS's with it
75
+ if maint == 'x'
76
+ ok_oses = [maj + '.' + min.to_s + '.x']
77
+
78
+ # otherwise, start with it and explicitly add all maint releases up to 20
79
+ # (and hope apple doesn't do more than 20 maint releases for an OS)
80
+ else
81
+ ok_oses = []
82
+ (maint.to_i..20).each do |m|
83
+ ok_oses << maj + '.' + min + '.' + m.to_s
84
+ end # each m
85
+ end
86
+
87
+ # now account for all OS X versions starting with 10.
88
+ # up to at least 10.30.x
89
+ ((min.to_i + 1)..30).each do |v|
90
+ ok_oses << maj + '.' + v.to_s + '.x'
91
+ end # each v
92
+ ok_oses
93
+ end
94
+
95
+ # Scripts and packages can have processor limitations.
96
+ # This method tests a given processor, against a requirement
97
+ # to see if the requirement is met.
98
+ #
99
+ # @param requirement[String] The processor requirement.
100
+ # either 'ppc', 'x86', or some variation on "none", nil, or empty
101
+ #
102
+ # @param processor[String] the processor to check, defaults to
103
+ # the processor of the current machine. Any flavor of intel
104
+ ## is (i486, i386, x86-64, etc) is treated as "x86"
105
+ #
106
+ # @return [Boolean] can this pkg be installed with the processor
107
+ # given?
108
+ #
109
+ def self.processor_ok?(requirement, processor = nil)
110
+ return true if requirement.to_s.empty? || requirement =~ /none/i
111
+ processor ||= `/usr/bin/uname -p`
112
+ requirement == (processor.to_s.include?('86') ? 'x86' : 'ppc')
113
+ end
114
+
115
+ # Scripts and packages can have OS limitations.
116
+ # This method tests a given OS, against a requirement list
117
+ # to see if the requirement is met.
118
+ #
119
+ # @param requirement[String,Array] The os requirement list, a comma-seprated string
120
+ # or array of strings of allows OSes. e.g. 10.7, 10.8.5 or 10.9.x
121
+ #
122
+ # @param processor[String] the os to check, defaults to
123
+ # the os of the current machine.
124
+ #
125
+ # @return [Boolean] can this pkg be installed with the processor
126
+ # given?
127
+ #
128
+ def self.os_ok?(requirement, os_to_check = nil)
129
+ return true if requirement.to_s =~ /none/i
130
+ return true if requirement.to_s == 'n'
131
+ requirement = JSS.to_s_and_a(requirement)[:arrayform]
132
+ return true if requirement.empty?
133
+
134
+ os_to_check ||= `/usr/bin/sw_vers -productVersion`.chomp
135
+
136
+ # convert the requirement array into an array of regexps.
137
+ # examples:
138
+ # "10.8.5" becomes /^10\.8\.5$/
139
+ # "10.8" becomes /^10.8(.0)?$/
140
+ # "10.8.x" /^10\.8\.?\d*$/
141
+ req_regexps = requirement.map do |r|
142
+ if r.end_with?('.x')
143
+ /^#{r.chomp('.x').gsub('.', '\.')}\.?\d*$/
144
+
145
+ elsif r =~ /^\d+\.\d+$/
146
+ /^#{r.gsub('.', '\.')}(.0)?$/
147
+
148
+ else
149
+ /^#{r.gsub('.', '\.')}$/
150
+ end
151
+ end
152
+
153
+ req_regexps.each { |re| return true if os_to_check =~ re }
154
+ false
155
+ end
156
+
157
+ # Given a list of data as a comma-separated string, or an Array of strings,
158
+ # return a Hash with both versions.
159
+ #
160
+ # Some parts of the JSS require lists as comma-separated strings, while
161
+ # often those data are easier work with as arrays. This method is a handy way
162
+ # to get either form when given either form.
163
+ #
164
+ # @param somedata [String, Array] the data to parse, of either class,
165
+ #
166
+ # @return [Hash{:stringform => String, :arrayform => Array}] the data as both comma-separated String and Array
167
+ #
168
+ # @example
169
+ # JSS.to_s_and_a "foo, bar, baz" # Hash => {:stringform => "foo, bar, baz", :arrayform => ["foo", "bar", "baz"]}
170
+ #
171
+ # JSS.to_s_and_a ["foo", "bar", "baz"] # Hash => {:stringform => "foo, bar, baz", :arrayform => ["foo", "bar", "baz"]}
172
+ #
173
+ def self.to_s_and_a(somedata)
174
+ case somedata
175
+ when nil
176
+ valstr = ''
177
+ valarr = []
178
+ when String
179
+ valstr = somedata
180
+ valarr = somedata.split(/,\s*/)
181
+ when Array
182
+ valstr = somedata.join ', '
183
+ valarr = somedata
184
+ else
185
+ raise Jamf::InvalidDataError, 'Input must be a comma-separated String or an Array of Strings'
186
+ end # case
187
+ { stringform: valstr, arrayform: valarr }
188
+ end # to_s_and_a
189
+
190
+ # Parse a plist into a Ruby data structure.
191
+ # This enhances Plist::parse_xml taking file paths, as well as XML Strings
192
+ # and reading the files regardless of binary/XML format.
193
+ #
194
+ # @param plist[Pathname, String] the plist XML, or the path to a plist file
195
+ #
196
+ # @return [Object] the parsed plist as a ruby hash,array, etc.
197
+ #
198
+ def self.parse_plist(plist)
199
+ # did we get a string of xml, or a string pathname?
200
+ case plist
201
+ when String
202
+ return Plist.parse_xml plist if plist.include? '</plist>'
203
+ plist = Pathname.new plist
204
+ when Pathname
205
+ true
206
+ else
207
+ raise ArgumentError, 'Argument must be a path (as a Pathname or String) or a String of XML'
208
+ end # case plist
209
+
210
+ # if we're here, its a Pathname
211
+ raise Jamf::MissingDataError, "No such file: #{plist}" unless plist.file?
212
+
213
+ Plist.parse_xml `/usr/libexec/PlistBuddy -x -c print #{Shellwords.escape(plist.to_s)}`.force_encoding('UTF-8')
214
+ end # parse_plist
215
+
216
+ # TODO: Sill needed in Jamf API?
217
+ #
218
+ # Converts anything that responds to #to_s to a Time, or nil
219
+ #
220
+ # Return nil if the item is nil, 0 or an empty String.
221
+ #
222
+ # Otherwise the item converted to a string, and parsed with DateTime.parse.
223
+ # It is then examined to see if it has a UTC offset. If not, the local offset
224
+ # is applied, then the DateTime is converted to a Time.
225
+ #
226
+ # @param a_datetime [#to_s] The thing to convert to a time.
227
+ #
228
+ # @return [Time, nil] nil is returned if a_datetime is nil, 0 or an empty String.
229
+ #
230
+ def self.parse_time(a_datetime)
231
+ return nil if NIL_DATES.include? a_datetime
232
+
233
+ the_dt = DateTime.parse(a_datetime.to_s)
234
+
235
+ # The microseconds in DateTimes are stored as a fraction of a day.
236
+ # Convert them to an integer of microseconds
237
+ usec = (the_dt.sec_fraction * 60 * 60 * 24 * (10**6)).to_i
238
+
239
+ # if the UTC offset of the datetime is zero, make a new one with the correct local offset
240
+ # (which might also be zero if we happen to be in GMT)
241
+ the_dt = DateTime.new(the_dt.year, the_dt.month, the_dt.day, the_dt.hour, the_dt.min, the_dt.sec, Jamf::TIME_ZONE_OFFSET) if the_dt.offset.zero?
242
+ # now convert it to a Time and return it
243
+ Time.at the_dt.strftime('%s').to_i, usec
244
+ end # parse_time
245
+
246
+ # TODO: Sill needed in Jamf API?
247
+ #
248
+ # Converts JSS epoch (unix epoch + milliseconds) to a Ruby Time object
249
+ #
250
+ # @param epoch[String, Integer, nil]
251
+ #
252
+ # @return [Time, nil] nil is returned if epoch is nil, 0 or an empty String.
253
+ #
254
+ def self.epoch_to_time(epoch)
255
+ return nil if NIL_DATES.include? epoch
256
+ Time.at(epoch.to_i / 1000.0)
257
+ end # parse_date
258
+
259
+ # TODO: Move to APIObject
260
+ #
261
+ # Given a name, singular or plural, of a Jamf::APIObject subclass as a String
262
+ # or Symbol (e.g. :computer/'computers'), return the class itself
263
+ # (e.g. Jamf::Computer)
264
+ # The available names are the RSRC_LIST_KEY
265
+ # and RSRC_OBJECT_KEY values for each APIObject subclass.
266
+ #
267
+ # @seealso JSS.api_object_names
268
+ #
269
+ # @param name[String,Symbol] The name of a Jamf::APIObject subclass, singluar
270
+ # or plural
271
+ #
272
+ # @return [Class] The class
273
+ #
274
+ def self.api_object_class(name)
275
+ klass = api_object_names[name.downcase.to_sym]
276
+ raise Jamf::InvalidDataError, "Unknown API Object Class: #{name}" unless klass
277
+ klass
278
+ end
279
+
280
+ # TODO: Move to APIObject
281
+ #
282
+ # APIObject subclasses have singular names, and are, of course
283
+ # capitalized, e.g. 'Computer'
284
+ # But we often want to refer to them in the plural, or lowercase,
285
+ # e.g. 'computers'
286
+ # This method returns a Hash of the RSRC_LIST_KEY (a plural symbol)
287
+ # and the RSRC_OBJECT_KEY (a singular symbol) of each APIObject
288
+ # subclass, keyed to the class itself, such that both :computer
289
+ # and :computers are keys for Jamf::Computer and both :policy and
290
+ # :policies are keys for Jamf::Policy, and so on.
291
+ #
292
+ # @return [Hash] APIObject subclass names to Classes
293
+ #
294
+ def self.api_object_names
295
+ return @api_object_names if @api_object_names
296
+ @api_object_names ||= {}
297
+ JSS.constants.each do |const|
298
+ klass = JSS.const_get const
299
+ next unless klass.is_a? Class
300
+ next unless klass.ancestors.include? Jamf::APIObject
301
+ @api_object_names[klass.const_get(:RSRC_LIST_KEY).to_sym] = klass if klass.constants.include? :RSRC_LIST_KEY
302
+ @api_object_names[klass.const_get(:RSRC_OBJECT_KEY).to_sym] = klass if klass.constants.include? :RSRC_OBJECT_KEY
303
+ end
304
+ @api_object_names
305
+ end
306
+
307
+ # TODO: Update or remove for Jamf API
308
+ # Parse a JSS Version number into something comparable.
309
+ #
310
+ # This method returns a Hash with these keys:
311
+ # * :major => the major version, Integer
312
+ # * :minor => the minor version, Integor
313
+ # * :maint => the revision, Integer (also available as :patch and :revision)
314
+ # * :build => the revision, String
315
+ # * :version => a Gem::Version object built from :major, :minor, :revision
316
+ # which can be easily compared with other Gem::Version objects.
317
+ #
318
+ # NOTE: the :version value ignores build numbers, so comparisons
319
+ # only compare major.minor.maint
320
+ #
321
+ # @param version[String] a JSS version number from the API
322
+ #
323
+ # @return [Hash{Symbol => String, Gem::Version}] the parsed version data.
324
+ #
325
+ def self.parse_jss_version(version)
326
+ major, second_part, *_rest = version.split('.')
327
+ raise Jamf::InvalidDataError, 'JSS Versions must start with "x.x" where x is one or more digits' unless major =~ /\d$/ && second_part =~ /^\d/
328
+
329
+ release, build = version.split(/-/)
330
+
331
+ major, minor, revision = release.split '.'
332
+ minor ||= 0
333
+ revision ||= 0
334
+
335
+ {
336
+ major: major.to_i,
337
+ minor: minor.to_i,
338
+ revision: revision.to_i,
339
+ maint: revision.to_i,
340
+ patch: revision.to_i,
341
+ build: build,
342
+ version: Gem::Version.new("#{major}.#{minor}.#{revision}")
343
+ }
344
+ end
345
+
346
+ # @return [Boolean] is this code running as root?
347
+ #
348
+ def self.superuser?
349
+ Process.euid.zero?
350
+ end
351
+
352
+ # Retrive one or all lines from whatever was piped to standard input.
353
+ #
354
+ # Standard input is read completely the first time this method is called
355
+ # and the lines are stored as an Array in the module var @stdin_lines
356
+ #
357
+ # @param line[Integer] which line of stdin is being retrieved.
358
+ # The default is zero (0) which returns all of stdin as a single string.
359
+ #
360
+ # @return [String, nil] the requested ling of stdin, or nil if it doesn't exist.
361
+ #
362
+ def self.stdin(line = 0)
363
+ @stdin_lines ||= ($stdin.tty? ? [] : $stdin.read.lines.map { |l| l.chomp("\n") })
364
+
365
+ return @stdin_lines.join("\n") if line <= 0
366
+ idx = line - 1
367
+ @stdin_lines[idx]
368
+ end
369
+
370
+ # Prompt for a password in a terminal.
371
+ #
372
+ # @param message [String] the prompt message to display
373
+ #
374
+ # @return [String] the text typed by the user
375
+ #
376
+ def self.prompt_for_password(message)
377
+ begin
378
+ $stdin.reopen '/dev/tty' unless $stdin.tty?
379
+ $stderr.print "#{message} "
380
+ system '/bin/stty -echo'
381
+ pw = $stdin.gets.chomp("\n")
382
+ puts
383
+ ensure
384
+ system '/bin/stty echo'
385
+ end # begin
386
+ pw
387
+ end
388
+
389
+ # Very handy!
390
+ # lifted from
391
+ # http://stackoverflow.com/questions/4136248/how-to-generate-a-human-readable-time-range-using-ruby-on-rails
392
+ #
393
+ def self.humanize_secs(secs)
394
+ [[60, :second], [60, :minute], [24, :hour], [7, :day], [52.179, :week], [1_000_000, :year]].map do |count, name|
395
+ next unless secs > 0
396
+
397
+ secs, n = secs.divmod(count)
398
+ n = n.to_i
399
+ "#{n} #{n == 1 ? name : (name.to_s + 's')}"
400
+ end.compact.reverse.join(' ')
401
+ end
402
+
403
+ # un/set devmode mode.
404
+ # Useful when coding - methods can call JSS.devmode? and then
405
+ # e.g. spit out something instead of performing some action.
406
+ #
407
+ # @param [Symbol] Set devmode :on or :off
408
+ #
409
+ # @return [Boolean] The new state of devmode
410
+ #
411
+ def self.devmode(setting)
412
+ @devmode = setting == :on
413
+ end
414
+
415
+ # is devmode currently on?
416
+ #
417
+ # @return [Boolean]
418
+ #
419
+ def self.devmode?
420
+ @devmode
421
+ end
422
+
423
+ end # module