ruby-jss 1.2.3 → 1.2.4a1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

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