ruby-jss 1.4.1 → 1.6.0

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 (107) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +95 -0
  3. data/THANKS.md +3 -2
  4. data/lib/jamf.rb +18 -17
  5. data/lib/jamf/api/base_classes/collection_resource.rb +613 -0
  6. data/lib/jamf/api/{abstract_classes → base_classes}/json_object.rb +109 -101
  7. data/lib/jamf/api/{abstract_classes → base_classes}/prestage.rb +55 -30
  8. data/lib/jamf/api/{abstract_classes → base_classes}/resource.rb +10 -6
  9. data/lib/jamf/api/{abstract_classes → base_classes}/singleton_resource.rb +4 -3
  10. data/lib/jamf/api/connection.rb +13 -9
  11. data/lib/jamf/api/connection/api_error.rb +8 -8
  12. data/lib/jamf/api/connection/token.rb +16 -15
  13. data/lib/jamf/api/json_objects/device_enrollment_device.rb +14 -7
  14. data/lib/jamf/api/json_objects/{location.rb → device_enrollment_device_sync_state.rb} +27 -41
  15. data/lib/jamf/api/json_objects/device_enrollment_sync_status.rb +1 -1
  16. data/lib/jamf/api/json_objects/{attachment.rb → locale.rb} +14 -23
  17. data/lib/jamf/api/json_objects/md_prestage_name.rb +1 -1
  18. data/lib/jamf/api/json_objects/md_prestage_names.rb +2 -2
  19. data/lib/jamf/api/json_objects/md_prestage_skip_setup_items.rb +50 -1
  20. data/lib/jamf/api/json_objects/prestage_assignment.rb +2 -2
  21. data/lib/jamf/api/json_objects/prestage_location.rb +3 -3
  22. data/lib/jamf/api/json_objects/prestage_purchasing_data.rb +7 -7
  23. data/lib/jamf/api/json_objects/prestage_scope.rb +1 -1
  24. data/lib/jamf/api/{resources/collection_resources → json_objects}/time_zone.rb +9 -23
  25. data/lib/jamf/api/mixins/{abstract.rb → base_class.rb} +34 -16
  26. data/lib/jamf/api/mixins/bulk_deletable.rb +27 -6
  27. data/lib/jamf/api/mixins/change_log.rb +201 -51
  28. data/lib/jamf/api/{resources/collection_resources/computer.rb → mixins/filterable.rb} +19 -17
  29. data/lib/jamf/api/mixins/pageable.rb +208 -0
  30. data/lib/jamf/api/{json_objects/installed_application.rb → mixins/sortable.rb} +33 -33
  31. data/lib/jamf/api/resources/collection_resources/building.rb +16 -9
  32. data/lib/jamf/api/resources/collection_resources/category.rb +5 -4
  33. data/lib/jamf/api/resources/collection_resources/computer_prestage.rb +12 -5
  34. data/lib/jamf/api/resources/collection_resources/department.rb +0 -2
  35. data/lib/jamf/api/resources/collection_resources/device_enrollment.rb +10 -10
  36. data/lib/jamf/api/resources/collection_resources/inventory_preload_record.rb +11 -3
  37. data/lib/jamf/api/resources/collection_resources/mobile_device_prestage.rb +25 -23
  38. data/lib/jamf/api/resources/collection_resources/script.rb +61 -25
  39. data/lib/jamf/api/resources/singleton_resources/app_store_country_codes.rb +15 -5
  40. data/lib/jamf/api/resources/singleton_resources/locales.rb +155 -0
  41. data/lib/jamf/api/resources/singleton_resources/time_zones.rb +213 -0
  42. data/lib/jamf/client.rb +3 -3
  43. data/lib/jamf/client/management_action.rb +2 -3
  44. data/lib/jamf/composer.rb +2 -2
  45. data/lib/jamf/utility.rb +35 -7
  46. data/lib/jamf/validate.rb +63 -24
  47. data/lib/jamf/version.rb +1 -1
  48. data/lib/jss.rb +2 -2
  49. data/lib/jss/api_connection.rb +114 -406
  50. data/lib/jss/api_object.rb +3 -19
  51. data/lib/jss/api_object/categorizable.rb +1 -1
  52. data/lib/jss/api_object/computer.rb +13 -0
  53. data/lib/jss/api_object/configuration_profile.rb +61 -5
  54. data/lib/jss/api_object/directory_binding_type.rb +66 -60
  55. data/lib/jss/api_object/directory_binding_type/active_directory.rb +71 -34
  56. data/lib/jss/api_object/directory_binding_type/admitmac.rb +536 -467
  57. data/lib/jss/api_object/directory_binding_type/centrify.rb +21 -7
  58. data/lib/jss/api_object/directory_binding_type/open_directory.rb +4 -4
  59. data/lib/jss/api_object/distribution_point.rb +2 -2
  60. data/lib/jss/api_object/dock_item.rb +102 -96
  61. data/lib/jss/api_object/extendable.rb +1 -1
  62. data/lib/jss/api_object/group.rb +33 -2
  63. data/lib/jss/api_object/network_segment.rb +45 -13
  64. data/lib/jss/api_object/patch_source.rb +10 -9
  65. data/lib/jss/api_object/policy.rb +155 -25
  66. data/lib/jss/api_object/printer.rb +10 -4
  67. data/lib/jss/api_object/scopable.rb +10 -15
  68. data/lib/jss/api_object/scopable/scope.rb +31 -30
  69. data/lib/jss/api_object/script.rb +242 -352
  70. data/lib/jss/api_object/user.rb +1 -1
  71. data/lib/jss/client/management_action.rb +1 -2
  72. data/lib/jss/composer.rb +2 -2
  73. data/lib/jss/exceptions.rb +3 -0
  74. data/lib/jss/server.rb +15 -0
  75. data/lib/jss/utility.rb +213 -45
  76. data/lib/jss/version.rb +1 -1
  77. metadata +46 -64
  78. data/lib/jamf/api/abstract_classes/advanced_search.rb +0 -86
  79. data/lib/jamf/api/abstract_classes/collection_resource.rb +0 -433
  80. data/lib/jamf/api/abstract_classes/generic_reference.rb +0 -145
  81. data/lib/jamf/api/abstract_classes/prestage_skip_setup_items.rb +0 -126
  82. data/lib/jamf/api/json_objects/account_prefs.rb +0 -79
  83. data/lib/jamf/api/json_objects/android_details.rb +0 -139
  84. data/lib/jamf/api/json_objects/appletv_details.rb +0 -110
  85. data/lib/jamf/api/json_objects/cellular_network.rb +0 -151
  86. data/lib/jamf/api/json_objects/computer_prestage_skip_setup_items.rb +0 -67
  87. data/lib/jamf/api/json_objects/criterion.rb +0 -152
  88. data/lib/jamf/api/json_objects/extension_attribute_value.rb +0 -128
  89. data/lib/jamf/api/json_objects/installed_certificate.rb +0 -53
  90. data/lib/jamf/api/json_objects/installed_configuration_profile.rb +0 -67
  91. data/lib/jamf/api/json_objects/installed_ebook.rb +0 -58
  92. data/lib/jamf/api/json_objects/installed_provisioning_profile.rb +0 -59
  93. data/lib/jamf/api/json_objects/ios_details.rb +0 -244
  94. data/lib/jamf/api/json_objects/mobile_device_details.rb +0 -219
  95. data/lib/jamf/api/json_objects/mobile_device_security.rb +0 -101
  96. data/lib/jamf/api/json_objects/purchasing_data.rb +0 -125
  97. data/lib/jamf/api/mixins/locatable.rb +0 -124
  98. data/lib/jamf/api/mixins/referable.rb +0 -92
  99. data/lib/jamf/api/resources/collection_resources/account.rb +0 -163
  100. data/lib/jamf/api/resources/collection_resources/advanced_mobile_device_search.rb +0 -52
  101. data/lib/jamf/api/resources/collection_resources/advanced_user_search.rb +0 -52
  102. data/lib/jamf/api/resources/collection_resources/extension_attribute.rb +0 -45
  103. data/lib/jamf/api/resources/collection_resources/mobile_device.rb +0 -315
  104. data/lib/jamf/api/resources/collection_resources/site.rb +0 -77
  105. data/lib/jamf/api/resources/singleton_resources/authorization.rb +0 -88
  106. data/lib/jamf/api/resources/singleton_resources/client_checkin_settings.rb +0 -139
  107. data/lib/jamf/api/resources/singleton_resources/reenrollment_settings.rb +0 -95
@@ -94,7 +94,7 @@ module JSS
94
94
  #
95
95
  def self.set_mgmt_action_ncprefs_flags(user, flags, hup: true)
96
96
  plist = Pathname.new "/Users/#{user}/Library/Preferences/#{NCPREFS_DOMAIN}.plist"
97
- prefs = JSS.parse_plist plist
97
+ prefs = Jamf.parse_plist plist
98
98
  mgmt_action_setting = prefs['apps'].select { |a| a['bundle-id'] == MGMT_ACTION_BUNDLE_ID }.first
99
99
  if mgmt_action_setting
100
100
  orig_flags = mgmt_action_setting['flags']
@@ -103,8 +103,7 @@ module JSS
103
103
  orig_flags = flags
104
104
  prefs['apps'] << { 'bundle-id' => MGMT_ACTION_BUNDLE_ID, 'flags' => flags }
105
105
  end
106
- # system "/usr/bin/defaults write #{NCPREFS_DOMAIN} '#{prefs.to_plist}'"
107
- plist.open('w') { |f| f.write prefs.to_plist }
106
+ plist.open('w') { |f| f.write Jamf.xml_plist_from(prefs) }
108
107
  system HUP_NOTIF_CTR_CMD if hup
109
108
  orig_flags
110
109
  end
data/lib/jamf/composer.rb CHANGED
@@ -126,7 +126,7 @@ module Jamf
126
126
  ###
127
127
  comp_plist_out = Pathname.new "/tmp/#{PKG_BUNDLE_ID_PFX}-#{pkg_filename}.plist"
128
128
  system "#{PKGBUILD} --analyze --root '#{root}' '#{comp_plist_out}'"
129
- comp_plist = Plist.parse_xml comp_plist_out.read
129
+ comp_plist = Jamf.parse_plist comp_plist_out
130
130
 
131
131
  ### if the plist is empty, there are no bundles in the pkg
132
132
  if comp_plist[0].nil?
@@ -141,7 +141,7 @@ module Jamf
141
141
  bndl['BundleHasStrictIdentifier'] = false
142
142
  end
143
143
  ### write out the edits
144
- comp_plist_out.open('w') { |f| f.write comp_plist.to_plist }
144
+ comp_plist_out.open('w') { |f| f.write Jamf.xml_plist_from(comp_plist) }
145
145
  comp_plist_arg = "--component-plist '#{comp_plist_out}'"
146
146
  end
147
147
 
data/lib/jamf/utility.rb CHANGED
@@ -187,19 +187,26 @@ module Jamf
187
187
  { stringform: valstr, arrayform: valarr }
188
188
  end # to_s_and_a
189
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.
190
+ # Parse a plist into a Ruby data structure. The plist parameter may be
191
+ # a String containing an XML plist, or a path to a plist file, or it may be
192
+ # a Pathname object pointing to a plist file. The plist files may be XML or
193
+ # binary.
193
194
  #
194
195
  # @param plist[Pathname, String] the plist XML, or the path to a plist file
195
196
  #
197
+ # @param symbol_keys[Boolean] should any Hash keys in the result be converted
198
+ # into Symbols rather than remain as Strings?
199
+ #
196
200
  # @return [Object] the parsed plist as a ruby hash,array, etc.
197
201
  #
198
- def self.parse_plist(plist)
202
+ def self.parse_plist(plist, symbol_keys: false)
203
+ require 'cfpropertylist'
204
+
199
205
  # did we get a string of xml, or a string pathname?
200
206
  case plist
201
207
  when String
202
- return Plist.parse_xml plist if plist.include? '</plist>'
208
+ return CFPropertyList.native_types(CFPropertyList::List.new(data: plist).value, symbol_keys) if plist.include? '</plist>'
209
+
203
210
  plist = Pathname.new plist
204
211
  when Pathname
205
212
  true
@@ -208,11 +215,32 @@ module Jamf
208
215
  end # case plist
209
216
 
210
217
  # if we're here, its a Pathname
211
- raise Jamf::MissingDataError, "No such file: #{plist}" unless plist.file?
218
+ raise JSS::MissingDataError, "No such file: #{plist}" unless plist.file?
212
219
 
213
- Plist.parse_xml `/usr/libexec/PlistBuddy -x -c print #{Shellwords.escape(plist.to_s)}`.force_encoding('UTF-8')
220
+ CFPropertyList.native_types(CFPropertyList::List.new(file: plist).value, symbol_keys)
214
221
  end # parse_plist
215
222
 
223
+ # Convert any ruby data to an XML plist.
224
+ #
225
+ # NOTE: Binary data is tricky. Easiest way is to pass in a
226
+ # Pathname or IO object (anything that responds to `read` and
227
+ # returns a bytestring)
228
+ # and then the CFPropertyList.guess method will read it and
229
+ # convert it to a Plist <data> element with base64 encoded
230
+ # data.
231
+ # For more info, see CFPropertyList.guess
232
+ #
233
+ # @param data [Object] the data to be converted, usually a Hash
234
+ #
235
+ # @return [String] the object converted into an XML plist
236
+ #
237
+ def self.xml_plist_from(data)
238
+ require 'cfpropertylist'
239
+ plist = CFPropertyList::List.new
240
+ plist.value = CFPropertyList.guess(data, convert_unknown_to_string: true)
241
+ plist.to_str(CFPropertyList::List::FORMAT_XML)
242
+ end
243
+
216
244
  # TODO: Sill needed in Jamf API?
217
245
  #
218
246
  # Converts anything that responds to #to_s to a Time, or nil
data/lib/jamf/validate.rb CHANGED
@@ -37,7 +37,7 @@ module Jamf
37
37
  module Validate
38
38
 
39
39
  # The regular expression that matches a valid MAC address.
40
- MAC_ADDR_RE = /^[a-f0-9]{2}(:[a-f0-9]{2}){5}$/i
40
+ MAC_ADDR_RE = /^[a-f0-9]{2}(:[a-f0-9]{2}){5}$/i.freeze
41
41
 
42
42
  # Validate the format and content of a MAC address
43
43
  #
@@ -50,6 +50,7 @@ module Jamf
50
50
  def self.mac_address(val, msg = nil)
51
51
  msg ||= "Not a valid MAC address: '#{val}'"
52
52
  raise Jamf::InvalidDataError, msg unless val =~ MAC_ADDR_RE
53
+
53
54
  val
54
55
  end
55
56
 
@@ -68,10 +69,11 @@ module Jamf
68
69
  ok = false unless parts.size == 4
69
70
  parts.each { |p| ok = false unless p.j_integer? && p.to_i < 256 && p.to_i >= 0 }
70
71
  raise Jamf::InvalidDataError, msg unless ok
72
+
71
73
  val
72
74
  end
73
75
 
74
- # Does a give JSONObject class have a given JSON attribute?
76
+ # Does a given JSONObject class have a given JSON attribute?
75
77
  #
76
78
  # @param klass [<JSONObject] A class descended from JSONObject
77
79
  #
@@ -83,9 +85,24 @@ module Jamf
83
85
  raise "#{klass} is not a descendent of JSONObject" unless klass < Jamf::JSONObject
84
86
 
85
87
  raise Jamf::NoSuchItemError, "No attribute #{attr_name} for class #{klass}" unless klass::OBJECT_MODEL.key? attrib
88
+
86
89
  attr_name
87
90
  end
88
91
 
92
+ # Does a value exist in a given enum array?
93
+ #
94
+ # @param klass [<JSONObject] A class descended from JSONObject
95
+ #
96
+ # @param attr_name [Symbol] The attribute to validate
97
+ #
98
+ # @return [Symbol] The valid attribute
99
+ #
100
+ def self.in_enum(val, enum)
101
+ raise Jamf::InvalidDataError, "Value must be one of: #{enum.join ', '}" unless enum.include? val
102
+
103
+ val
104
+ end
105
+
89
106
  # Validate that a value doesn't already exist for a given identifier of
90
107
  # a given CollectionResource class
91
108
  #
@@ -116,14 +133,12 @@ module Jamf
116
133
  raise Jamf::AlreadyExistsError, msg
117
134
  end
118
135
 
136
+ TRUE_FALSE = [true, false].freeze
137
+
119
138
  # Confirm that the given value is a boolean value, accepting
120
- # Strings and Symbols, returning real booleans as needed
121
- #
122
- # Accepted True values: true, 'true', :true, 'yes', :yes
123
- #
124
- # Accepted False values: false, 'false', :false, 'no', :no
125
- #
126
- # all Strings and Symbols are case insensitive
139
+ # strings and symbols and returning real booleans as needed
140
+ # Accepts: true, false, 'true', 'false', 'yes', 'no', 't','f', 'y', or 'n'
141
+ # as strings or symbols, case insensitive
127
142
  #
128
143
  # @param val [Boolean,String,Symbol] The value to validate
129
144
  #
@@ -131,14 +146,36 @@ module Jamf
131
146
  #
132
147
  # @return [Boolean] the valid boolean
133
148
  #
134
- def self.boolean(val, msg = nil)
135
- msg ||= 'Value must be boolean true or false'
136
- return true if val.to_s =~ /^(true|yes)$/i
137
- return false if val.to_s =~ /^(false|no)$/i
149
+ def self.boolean(val, msg = 'Value must be true or false, or equivalent string or symbol')
150
+ return val if TRUE_FALSE.include? val
151
+ return true if val.to_s =~ /^(t(rue)?|y(es)?)$/i
152
+ return false if val.to_s =~ /^(f(alse)?|no?)$/i
138
153
 
139
154
  raise Jamf::InvalidDataError, msg
140
155
  end
141
156
 
157
+ # Confirm that a value provided is an integer or a string version
158
+ # of an integer, and return the string version
159
+ #
160
+ # The JPAPI specs say that all IDs are integers in strings
161
+ # tho, the endpoints are still implementing that in different versions.
162
+ #
163
+ # @param val[Object] the value to validate
164
+ #
165
+ # @param msg[String] A custom error message when the value is invalid
166
+ #
167
+ # @return [String] the valid integer-in-a-string
168
+ #
169
+ def self.j_id(val, msg = 'Value must be an Integer or an Integer in a String, e.g. "42"')
170
+ case val
171
+ when Integer
172
+ return val.to_s
173
+ when String
174
+ return val if val.j_integer?
175
+ end
176
+ raise Jamf::InvalidDataError, msg
177
+ end
178
+
142
179
  # Confirm that a value is an Integer or a String representation of an
143
180
  # Integer. Return the integer, or raise an error
144
181
  #
@@ -148,10 +185,10 @@ module Jamf
148
185
  #
149
186
  # @return [Integer] the valid integer
150
187
  #
151
- def self.integer(val, msg = nil)
152
- msg ||= 'Value must be an Integer'
188
+ def self.integer(val, msg = 'Value must be an Integer')
153
189
  val = val.to_i if val.is_a?(String) && val.j_integer?
154
190
  raise Jamf::InvalidDataError, msg unless val.is_a? Integer
191
+
155
192
  val
156
193
  end
157
194
 
@@ -164,10 +201,10 @@ module Jamf
164
201
  #
165
202
  # @return [Float] the valid float
166
203
  #
167
- def self.float(val, msg = nil)
168
- msg ||= 'Value must be a Floating Point number'
204
+ def self.float(val, msg = 'Value must be a Floating Point number')
169
205
  val = val.to_f if val.is_a?(String) && val.j_float?
170
- raise Jamf::InvalidDataError, msg unless val.is_a? Flot
206
+ raise Jamf::InvalidDataError, msg unless val.is_a? Float
207
+
171
208
  val
172
209
  end
173
210
 
@@ -180,11 +217,12 @@ module Jamf
180
217
  #
181
218
  # @return [String] the valid String
182
219
  #
183
- def self.string(val, msg = nil)
184
- msg ||= 'Value must be a String'
220
+ def self.string(val, msg = 'Value must be a String')
185
221
  return Jamf::BLANK if val.nil?
222
+
186
223
  val = val.to_s if val.is_a? Symbol
187
224
  raise Jamf::InvalidDataError, msg unless val.is_a? String
225
+
188
226
  val
189
227
  end
190
228
 
@@ -197,10 +235,10 @@ module Jamf
197
235
  #
198
236
  # @return [String] the valid non-empty string
199
237
  #
200
- def self.non_empty_string(val, msg = nil)
201
- msg ||= 'value must be a non-empty String'
238
+ def self.non_empty_string(val, msg = 'value must be a non-empty String')
202
239
  val = val.to_s if val.is_a? Symbol
203
240
  raise Jamf::InvalidDataError, msg unless val.is_a?(String) && !val.empty?
241
+
204
242
  val
205
243
  end
206
244
 
@@ -214,11 +252,12 @@ module Jamf
214
252
  #
215
253
  # @return [String] the validated string
216
254
  #
217
- def self.script_contents(val, msg = nil)
218
- msg ||= "value must be a String starting with '#!'"
255
+ def self.script_contents(val, msg = "value must be a String starting with '#!'")
219
256
  raise Jamf::InvalidDataError, msg unless val.is_a?(String) && val.start_with?(SCRIPT_SHEBANG)
257
+
220
258
  val
221
259
  end
260
+
222
261
  end # module validate
223
262
 
224
263
  end # module JSS
data/lib/jamf/version.rb CHANGED
@@ -27,6 +27,6 @@
27
27
  module Jamf
28
28
 
29
29
  ### The version of the Jamf module
30
- VERSION = '0.0.3'.freeze
30
+ VERSION = '0.0.6a1'.freeze
31
31
 
32
32
  end # module
data/lib/jss.rb CHANGED
@@ -58,8 +58,8 @@ module JSS
58
58
 
59
59
  ###################
60
60
  ### Gems
61
- require 'rest-client'
62
- require 'plist'
61
+ require 'faraday'
62
+ require 'faraday_middleware'
63
63
  require 'immutable-struct'
64
64
  require 'recursive-open-struct'
65
65
 
@@ -25,18 +25,6 @@
25
25
  ###
26
26
  module JSS
27
27
 
28
- # Constants
29
- #####################################
30
-
31
- # Module Variables
32
- #####################################
33
-
34
- # Module Methods
35
- #####################################
36
-
37
- # Classes
38
- #####################################
39
-
40
28
  # Instances of this class represent a REST connection to a JSS API.
41
29
  #
42
30
  # For most cases, a single connection to a single JSS is all you need, and
@@ -227,42 +215,6 @@ module JSS
227
215
  # # the variable 'prod2_victim_md' now contains a JSS::MobileDevice queried
228
216
  # # through the connection 'production_api2'.
229
217
  #
230
- # == Using the APIConnection itself to make API calls.
231
- #
232
- # Rather than passing an APIConnection into another method, you can call
233
- # similar methods on the connection itself. For example, these two calls
234
- # have the same result as the two examples above:
235
- #
236
- # prod2_computer_sns = production_api2.all :Computer, only: :serial_numbers
237
- # prod2_victim_md = production_api2.fetch :MobileDevice, id: 832
238
- #
239
- # Here are the API calls you can make directly from an APIConnection object.
240
- # They behave practically identically to the same methods in the APIObject
241
- # subclasses, since they just call those methods, passing themselves in as the
242
- # APIConnection to use.
243
- #
244
- # - {#all} The 'list' methods of the various APIObject classes. Use the 'only:'
245
- # parameter to specify one of the sub-list-methods, like #all_ids or
246
- # #all_laptops, e.g. `my_connection.all :computers, only: :id`
247
- # - {#map_all_ids} the equivalent of #map_all_ids_to in the APIObject classes
248
- # - {#valid_id} given a class and an identifier (like macaddress or udid)
249
- # return a valid id or nil
250
- # - {#exist?} given a class and an identifier (like macaddress or udid) does
251
- # the identifier exist for the class in the JSS
252
- # - {#match} list items in the JSS matching a query
253
- # (if the object is {Matchable})
254
- # - {#fetch} retrieve an object from the JSS
255
- # - {#make} instantiate an object to be created in the JSS
256
- # - {#computer_checkin_settings} same as {Computer.checkin_settings}
257
- # - {#computer_inventory_collection_settings} same as {Computer.inventory_collection_settings}
258
- # - {#computer_application_usage} same as {Computer.application_usage}
259
- # - {#computer_management_data} same as {Computer.management_data}
260
- # - {#master_distribution_point} same as {DistributionPoint.master_distribution_point}
261
- # - {#my_distribution_point} same as {DistributionPoint.my_distribution_point}
262
- # - {#network_ranges} same as {NetworkSegment.network_ranges}
263
- # - {#network_segments_for_ip} same as {NetworkSegment.segments_for_ip}
264
- # - {#my_network_segments} same as {NetworkSegment.my_network_segments}
265
- #
266
218
  # == Low-level use of APIConnection instances.
267
219
  #
268
220
  # For most cases, using APIConnection instances as mentioned above
@@ -271,7 +223,7 @@ module JSS
271
223
  # {#get_rsrc}, {#put_rsrc}, {#post_rsrc}, & {#delete_rsrc}
272
224
  # documented below.
273
225
  #
274
- # For even lower-level work, you can access the underlying RestClient::Resource
226
+ # For even lower-level work, you can access the underlying Faraday::Connection
275
227
  # inside the APIConnection via the connection's {#cnx} attribute.
276
228
  #
277
229
  # APIConnection instances also have a {#server} attribute which contains an
@@ -330,6 +282,12 @@ module JSS
330
282
  # values for the format param of get_rsrc
331
283
  GET_FORMATS = %i[json xml].freeze
332
284
 
285
+ HTTP_ACCEPT_HEADER = 'Accept'.freeze
286
+ HTTP_CONTENT_TYPE_HEADER = 'Content-Type'.freeze
287
+
288
+ MIME_JSON = 'application/json'.freeze
289
+ MIME_XML = 'application/xml'.freeze
290
+
333
291
  # Attributes
334
292
  #####################################
335
293
 
@@ -337,7 +295,7 @@ module JSS
337
295
  attr_reader :user
338
296
  alias jss_user user
339
297
 
340
- # @return [RestClient::Resource] the underlying connection resource
298
+ # @return [Faraday::Connection] the underlying connection resource
341
299
  attr_reader :cnx
342
300
 
343
301
  # @return [Boolean] are we connected right now?
@@ -359,7 +317,7 @@ module JSS
359
317
  # @return [String] the protocol being used: http or https
360
318
  attr_reader :protocol
361
319
 
362
- # @return [RestClient::Response] The response from the most recent API call
320
+ # @return [Faraday::Response] The response from the most recent API call
363
321
  attr_reader :last_http_response
364
322
 
365
323
  # @return [String] The base URL to to the current REST API
@@ -428,6 +386,7 @@ module JSS
428
386
  @name = args.delete :name
429
387
  @name ||= :unknown
430
388
  @connected = false
389
+ @object_list_cache = {}
431
390
  connect args unless args.empty?
432
391
  end # init
433
392
 
@@ -453,8 +412,6 @@ module JSS
453
412
  # @option args :use_ssl[Boolean] should the connection be made over SSL? Defaults to true.
454
413
  #
455
414
  # @option args :verify_cert[Boolean] should HTTPS SSL certificates be verified. Defaults to true.
456
- # If your connection raises RestClient::SSLCertificateNotVerified, and you don't care about the
457
- # validity of the SSL cert. just set this explicitly to false.
458
415
  #
459
416
  # @option args :user[String] a JSS user who has API privs, required if not defined in JSS::CONFIG
460
417
  #
@@ -476,6 +433,8 @@ module JSS
476
433
 
477
434
  args[:no_port_specified] = args[:port].to_s.empty?
478
435
  args = apply_connection_defaults args
436
+ @timeout = args[:timeout]
437
+ @open_timeout = args[:open_timeout]
479
438
 
480
439
  # ensure an integer
481
440
  args[:port] &&= args[:port].to_i
@@ -494,7 +453,7 @@ module JSS
494
453
  args[:password] = acquire_password args
495
454
 
496
455
  # heres our connection
497
- @cnx = RestClient::Resource.new(@rest_url.to_s, args)
456
+ @cnx = create_connection args[:password]
498
457
 
499
458
  verify_server_version
500
459
 
@@ -543,8 +502,7 @@ module JSS
543
502
  @connected = false
544
503
  end # disconnect
545
504
 
546
- # Get an arbitrary JSS resource
547
- #
505
+ # Get a JSS resource
548
506
  # The first argument is the resource to get (the part of the API url
549
507
  # after the 'JSSResource/' ) The resource must be properly URL escaped
550
508
  # beforehand. Note: URL.encode is deprecated, use CGI.escape
@@ -572,14 +530,19 @@ module JSS
572
530
  validate_connected
573
531
  raise JSS::InvalidDataError, 'format must be :json or :xml' unless GET_FORMATS.include? format
574
532
 
575
- begin
576
- @last_http_response = @cnx[rsrc].get(accept: format)
577
- return JSON.parse(@last_http_response.body, symbolize_names: true) if format == :json && !raw_json
533
+ @last_http_response =
534
+ @cnx.get(rsrc) do |req|
535
+ req.headers[HTTP_ACCEPT_HEADER] = format == :json ? MIME_JSON : MIME_XML
536
+ end
578
537
 
579
- @last_http_response.body
580
- rescue RestClient::ExceptionWithResponse => e
581
- handle_http_error e
538
+ unless @last_http_response.success?
539
+ handle_http_error
540
+ return
582
541
  end
542
+
543
+ return JSON.parse(@last_http_response.body, symbolize_names: true) if format == :json && !raw_json
544
+
545
+ @last_http_response.body
583
546
  end
584
547
 
585
548
  # Update an existing JSS resource
@@ -597,10 +560,18 @@ module JSS
597
560
  xml.gsub!(/\r/, '&#13;')
598
561
 
599
562
  # send the data
600
- @last_http_response = @cnx[rsrc].put(xml, content_type: 'text/xml')
563
+ @last_http_response =
564
+ @cnx.put(rsrc) do |req|
565
+ req.headers[HTTP_CONTENT_TYPE_HEADER] = MIME_XML
566
+ req.headers[HTTP_ACCEPT_HEADER] = MIME_XML
567
+ req.body = xml
568
+ end
569
+ unless @last_http_response.success?
570
+ handle_http_error
571
+ return
572
+ end
573
+
601
574
  @last_http_response.body
602
- rescue RestClient::ExceptionWithResponse => e
603
- handle_http_error e
604
575
  end
605
576
 
606
577
  # Create a new JSS resource
@@ -611,17 +582,24 @@ module JSS
611
582
  #
612
583
  # @return [String] the xml response from the server.
613
584
  #
614
- def post_rsrc(rsrc, xml = '')
585
+ def post_rsrc(rsrc, xml)
615
586
  validate_connected
616
587
 
617
588
  # convert CRs & to &#13;
618
- xml.gsub!(/\r/, '&#13;') if xml
589
+ xml&.gsub!(/\r/, '&#13;')
619
590
 
620
591
  # send the data
621
- @last_http_response = @cnx[rsrc].post(xml, content_type: 'text/xml', accept: :json)
592
+ @last_http_response =
593
+ @cnx.post(rsrc) do |req|
594
+ req.headers[HTTP_CONTENT_TYPE_HEADER] = MIME_XML
595
+ req.headers[HTTP_ACCEPT_HEADER] = MIME_XML
596
+ req.body = xml
597
+ end
598
+ unless @last_http_response.success?
599
+ handle_http_error
600
+ return
601
+ end
622
602
  @last_http_response.body
623
- rescue RestClient::ExceptionWithResponse => e
624
- handle_http_error e
625
603
  end # post_rsrc
626
604
 
627
605
  # Delete a resource from the JSS
@@ -630,18 +608,23 @@ module JSS
630
608
  #
631
609
  # @return [String] the xml response from the server.
632
610
  #
633
- def delete_rsrc(rsrc, xml = nil)
611
+ def delete_rsrc(rsrc)
634
612
  validate_connected
635
613
  raise MissingDataError, 'Missing :rsrc' if rsrc.nil?
636
614
 
637
- # payload?
638
- return delete_with_payload rsrc, xml if xml
639
-
640
615
  # delete the resource
641
- @last_http_response = @cnx[rsrc].delete
616
+ @last_http_response =
617
+ @cnx.delete(rsrc) do |req|
618
+ req.headers[HTTP_CONTENT_TYPE_HEADER] = MIME_XML
619
+ req.headers[HTTP_ACCEPT_HEADER] = MIME_XML
620
+ end
621
+
622
+ unless @last_http_response.success?
623
+ handle_http_error
624
+ return
625
+ end
626
+
642
627
  @last_http_response.body
643
- rescue RestClient::ExceptionWithResponse => e
644
- handle_http_error e
645
628
  end # delete_rsrc
646
629
 
647
630
  # Test that a given hostname & port is a JSS API server
@@ -657,25 +640,8 @@ module JSS
657
640
  # ssl_options like :OP_NO_SSLv2 and :OP_NO_SSLv3 will take time to figure out..
658
641
  return true if `/usr/bin/curl -s 'https://#{server}:#{port}/#{TEST_PATH}'`.include? TEST_CONTENT
659
642
  return true if `/usr/bin/curl -s 'http://#{server}:#{port}/#{TEST_PATH}'`.include? TEST_CONTENT
660
- false
661
643
 
662
- # # try ssl first
663
- # # NOTE: doesn't work if we can't disallow SSLv3 or force TLSv1
664
- # # See cheat above.
665
- # begin
666
- # return true if open("https://#{server}:#{port}/#{TEST_PATH}", ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE).read.include? TEST_CONTENT
667
- #
668
- # rescue
669
- # # then regular http
670
- # begin
671
- # return true if open("http://#{server}:#{port}/#{TEST_PATH}").read.include? TEST_CONTENT
672
- # rescue
673
- # # any errors = no API
674
- # return false
675
- # end # begin
676
- # end # begin
677
- # # if we're here, no API
678
- # false
644
+ false
679
645
  end
680
646
 
681
647
  # The server to which we are connected, or will
@@ -686,267 +652,13 @@ module JSS
686
652
  #
687
653
  def hostname
688
654
  return @server_host if @server_host
655
+
689
656
  srvr = JSS::CONFIG.api_server_name
690
657
  srvr ||= JSS::Client.jss_server
691
658
  srvr
692
659
  end
693
660
  alias host hostname
694
661
 
695
- #################
696
-
697
- # Call one of the 'all*' methods on a JSS::APIObject subclass
698
- # using this APIConnection.
699
- #
700
- #
701
- # @deprecated please use the .all class method of the desired class
702
- #
703
- # @param class_name[String,Symbol] The name of a JSS::APIObject subclass
704
- # see {JSS.api_object_class}
705
- #
706
- # @param refresh[Boolean] Should the data be re-read from the API?
707
- #
708
- # @param only[String,Symbol] Limit the output to subset or data. All
709
- # APIObject subclasses can take :ids or :names, which calls the .all_ids
710
- # and .all_names methods. Some subclasses can take other options, e.g.
711
- # MobileDevice can take :udids
712
- #
713
- # @return [Array] The list of items for the class
714
- #
715
- def all(class_name, refresh = false, only: nil)
716
- the_class = JSS.api_object_class(class_name)
717
- list_method = only ? :"all_#{only}" : :all
718
-
719
- raise ArgumentError, "Unknown identifier: #{only} for #{the_class}" unless
720
- the_class.respond_to? list_method
721
-
722
- the_class.send list_method, refresh, api: self
723
- end
724
-
725
- # Call the 'map_all_ids_to' method on a JSS::APIObject subclass
726
- # using this APIConnection.
727
- #
728
- # @deprecated please use the .map_all_ids_to class method of the desired class
729
- #
730
- #
731
- # @param class_name[String,Symbol] The name of a JSS::APIObject subclass
732
- # see {JSS.api_object_class}
733
- #
734
- # @param refresh[Boolean] Should the data be re-read from the API?
735
- #
736
- # @param to[String,Symbol] the value to which the ids should be mapped
737
- #
738
- # @return [Hash] The ids for the class keyed to the requested identifier
739
- #
740
- def map_all_ids(class_name, refresh = false, to: nil)
741
- raise "'to:' value must be provided for mapping ids." unless to
742
- the_class = JSS.api_object_class(class_name)
743
- the_class.map_all_ids_to to, refresh, api: self
744
- end
745
-
746
- # Call the 'valid_id' method on a JSS::APIObject subclass
747
- # using this APIConnection. See {JSS::APIObject.valid_id}
748
- #
749
- # @deprecated please use the .valid_id class method of the desired class
750
- #
751
- #
752
- # @param class_name[String,Symbol] The name of a JSS::APIObject subclass,
753
- # see {JSS.api_object_class}
754
- #
755
- # @param identifier[String,Symbol] the value to which the ids should be mapped
756
- #
757
- # @param refresh[Boolean] Should the data be re-read from the API?
758
- #
759
- # @return [Integer, nil] the id of the matching object of the class,
760
- # or nil if there isn't one
761
- #
762
- def valid_id(class_name, identifier, refresh = true)
763
- the_class = JSS.api_object_class(class_name)
764
- the_class.valid_id identifier, refresh, api: self
765
- end
766
-
767
- # Call the 'exist?' method on a JSS::APIObject subclass
768
- # using this APIConnection. See {JSS::APIObject.exist?}
769
- #
770
- # @deprecated please use the .exist class method of the desired class
771
- #
772
- # @param class_name[String,Symbol] The name of a JSS::APIObject subclass
773
- # see {JSS.api_object_class}
774
- #
775
- # @param identifier[String,Symbol] the value to which the ids should be mapped
776
- #
777
- # @param refresh[Boolean] Should the data be re-read from the API?
778
- #
779
- # @return [Boolean] Is there an object of this class in the JSS matching
780
- # this indentifier?
781
- #
782
- def exist?(class_name, identifier, refresh = false)
783
- !valid_id(class_name, identifier, refresh).nil?
784
- end
785
-
786
- # Call {Matchable.match} for the given class.
787
- #
788
- # See {Matchable.match}
789
- #
790
- # @deprecated Please use the .match class method of the desired class
791
- #
792
- # @param class_name[String,Symbol] The name of a JSS::APIObject subclass
793
- # see {JSS.api_object_class}
794
- #
795
- # @return (see Matchable.match)
796
- #
797
- def match(class_name, term)
798
- the_class = JSS.api_object_class(class_name)
799
- raise JSS::UnsupportedError, "Class #{the_class} is not matchable" unless the_class.respond_to? :match
800
- the_class.match term, api: self
801
- end
802
-
803
- # Retrieve an object of a given class from the API
804
- # See {APIObject.fetch}
805
- #
806
- # @deprecated Please use the .fetch class method of the desired class
807
- #
808
- #
809
- # @param class_name[String,Symbol] The name of a JSS::APIObject subclass
810
- # see {JSS.api_object_class}
811
- #
812
- # @return [APIObject] The ruby-instance of the object.
813
- #
814
- def fetch(class_name, arg)
815
- the_class = JSS.api_object_class(class_name)
816
- the_class.fetch arg, api: self
817
- end
818
-
819
- # Make a ruby instance of a not-yet-existing APIObject
820
- # of the given class
821
- # See {APIObject.make}
822
- #
823
- # @deprecated Please use the .make class method of the desired class
824
- #
825
- # @param class_name[String,Symbol] The name of a JSS::APIObject subclass
826
- # see {JSS.api_object_class}
827
- #
828
- # @return [APIObject] The un-created ruby-instance of the object.
829
- #
830
- def make(class_name, **args)
831
- the_class = JSS.api_object_class(class_name)
832
- args[:api] = self
833
- the_class.make args
834
- end
835
-
836
- # Call {JSS::Computer.checkin_settings} q.v., passing this API
837
- # connection
838
- # @deprecated Please use JSS::Computer.checkin_settings
839
- #
840
- def computer_checkin_settings
841
- JSS::Computer.checkin_settings api: self
842
- end
843
-
844
- # Call {JSS::Computer.inventory_collection_settings} q.v., passing this API
845
- # connection
846
- # @deprecated Please use JSS::Computer.inventory_collection_settings
847
- #
848
- def computer_inventory_collection_settings
849
- JSS::Computer.inventory_collection_settings api: self
850
- end
851
-
852
- # Call {JSS::Computer.application_usage} q.v., passing this API
853
- # connection
854
- # @deprecated Please use JSS::Computer.application_usage
855
- #
856
- def computer_application_usage(ident, start_date, end_date = nil)
857
- JSS::Computer.application_usage ident, start_date, end_date, api: self
858
- end
859
-
860
- # Call {JSS::Computer.management_data} q.v., passing this API
861
- # connection
862
- #
863
- # @deprecated Please use JSS::Computer.management_data
864
- #
865
- def computer_management_data(ident, subset: nil, only: nil)
866
- JSS::Computer.management_data ident, subset: subset, only: only, api: self
867
- end
868
-
869
- # Call {JSS::Computer.history} q.v., passing this API
870
- # connection
871
- #
872
- # @deprecated Please use JSS::Computer.management_history or its
873
- # convenience methods. @see JSS::ManagementHistory
874
- #
875
- def computer_history(ident, subset: nil)
876
- JSS::Computer.history ident, subset, api: self
877
- end
878
-
879
- # Call {JSS::Computer.send_mdm_command} q.v., passing this API
880
- # connection
881
- #
882
- # @deprecated Please use JSS::Computer.send_mdm_command or its
883
- # convenience methods. @see JSS::MDM
884
- #
885
- def send_computer_mdm_command(targets, command, passcode = nil)
886
- opts = passcode ? { passcode: passcode } : {}
887
- JSS::Computer.send_mdm_command targets, command, opts: opts, api: self
888
- end
889
-
890
- # Get the DistributionPoint instance for the master
891
- # distribution point in the JSS. If there's only one
892
- # in the JSS, return it even if not marked as master.
893
- #
894
- # @param refresh[Boolean] re-read from the API?
895
- #
896
- # @return [JSS::DistributionPoint]
897
- #
898
- def master_distribution_point(refresh = false)
899
- JSS::DistributionPoint.master_distribution_point refresh, api: self
900
- end
901
-
902
- # Get the DistributionPoint instance for the machine running
903
- # this code, based on its IP address. If none is defined for this IP address,
904
- # use the result of master_distribution_point
905
- #
906
- # @param refresh[Boolean] should the distribution point be re-queried?
907
- #
908
- # @return [JSS::DistributionPoint]
909
- #
910
- def my_distribution_point(refresh = false)
911
- JSS::DistributionPoint.my_distribution_point refresh, api: self
912
- end
913
-
914
- # @deprecated
915
- #
916
- # @see {JSS::NetworkSegment.network_ranges}
917
- #
918
- def network_ranges(refresh = false)
919
- JSS::NetworkSegment.network_ranges refresh, api: self
920
- end # def network_segments
921
-
922
- # @deprecated
923
- #
924
- # @see {JSS::NetworkSegment.network_segments_for_ip}
925
- #
926
- def network_segments_for_ip(ip, refresh = false)
927
- JSS::NetworkSegment.network_segments_for_ip ip, refresh, api: self
928
- end
929
-
930
- # @deprecated
931
- #
932
- # @see {JSS::NetworkSegment.my_network_segments}
933
- #
934
- def my_network_segments
935
- network_segments_for_ip JSS::Client.my_ip_address
936
- end
937
-
938
- # Send an MDM command to one or more mobile devices managed by
939
- # this JSS
940
- #
941
- # see {JSS::MobileDevice.send_mdm_command}
942
- #
943
- # @deprecated Please use JSS::MobileDevice.send_mdm_command or its
944
- # convenience methods. @see JSS::MDM
945
- #
946
- def send_mobiledevice_mdm_command(targets, command, data = {})
947
- JSS::MobileDevice.send_mdm_command(targets, command, opts: data, api: self)
948
- end
949
-
950
662
  # Empty all cached lists from this connection
951
663
  # then run garbage collection to clear any available memory
952
664
  #
@@ -1052,6 +764,7 @@ module JSS
1052
764
  #
1053
765
  def apply_defaults_from_client(args)
1054
766
  return unless JSS::Client.installed?
767
+
1055
768
  # these settings can come from the jamf binary config, if this machine is a JSS client.
1056
769
  args[:server] ||= JSS::Client.jss_server
1057
770
  args[:port] ||= JSS::Client.jss_port.to_i
@@ -1105,11 +818,13 @@ module JSS
1105
818
  # keep this basic level of info available for basic authentication
1106
819
  # and JSS version checking.
1107
820
  begin
1108
- @server = JSS::Server.new get_rsrc('jssuser')[:user], self
1109
- rescue RestClient::Unauthorized
821
+ data = get_rsrc('jssuser')
822
+ rescue JSS::AuthorizationError
1110
823
  raise JSS::AuthenticationError, "Incorrect JSS username or password for '#{@user}@#{@server_host}:#{@port}'."
1111
824
  end
1112
825
 
826
+ @server = JSS::Server.new data[:user], self
827
+
1113
828
  min_vers = JSS.parse_jss_version(JSS::MINIMUM_SERVER_VERSION)[:version]
1114
829
  return if @server.version >= min_vers # we're good...
1115
830
 
@@ -1178,77 +893,69 @@ module JSS
1178
893
  if SSL_PORTS.include? args[:port]
1179
894
  args[:use_ssl] = true unless args[:use_ssl] == false
1180
895
  end
896
+ return unless args[:use_ssl]
897
+
1181
898
  # if verify_cert is anything but false, we will verify
1182
- args[:verify_ssl] = args[:verify_cert] == false ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER
899
+ args[:verify_ssl] = args[:verify_cert] != false
900
+
901
+ # ssl version if not specified
902
+ args[:ssl_version] ||= DFT_SSL_VERSION
903
+
904
+ @ssl_options = {
905
+ verify: args[:verify_ssl],
906
+ version: args[:ssl_version]
907
+ }
1183
908
  end
1184
909
 
1185
- # Parses the HTTP body of a RestClient::ExceptionWithResponse
1186
- # (the parent of all HTTP error responses) and its subclasses
1187
- # and re-raises a JSS::APIError with a more
1188
- # useful error message.
1189
- #
1190
- # @param exception[RestClient::ExceptionWithResponse] the exception to parse
910
+ # Parses the @last_http_response
911
+ # and raises a JSS::APIError with a useful error message.
1191
912
  #
1192
913
  # @return [void]
1193
914
  #
1194
- def handle_http_error(exception)
1195
- @last_http_response = exception.response
1196
- case exception
1197
- when RestClient::ResourceNotFound
1198
- # other methods catch this and report more details
1199
- raise exception
1200
- when RestClient::Conflict
915
+ def handle_http_error
916
+ return if @last_http_response.success?
917
+
918
+ case @last_http_response.status
919
+ when 404
920
+ err = JSS::NoSuchItemError
921
+ msg = 'Not Found'
922
+ when 409
1201
923
  err = JSS::ConflictError
1202
- msg_matcher = /<p>Error:(.*?)(<|$)/m
1203
- when RestClient::BadRequest
924
+ @last_http_response.body =~ /<p>(The server has not .*?)(<|$)/m
925
+ Regexp.last_match(1) || @last_http_response.body =~ %r{<p>Error: (.*?)</p>}
926
+ msg = Regexp.last_match(1)
927
+ when 400
1204
928
  err = JSS::BadRequestError
1205
- msg_matcher = %r{>Bad Request</p>\n<p>(.*?)</p>\n<p>You can get technical detail}m
1206
- when RestClient::Unauthorized
1207
- raise
929
+ @last_http_response.body =~ %r{>Bad Request</p>\n<p>(.*?)</p>\n<p>You can get technical detail}m
930
+ msg = Regexp.last_match(1)
931
+ when 401
932
+ err = JSS::AuthorizationError
933
+ msg = 'You are not authorized to do that.'
934
+ when (500..599)
935
+ err = JSS::APIRequestError
936
+ msg = 'There was an internal server error'
1208
937
  else
1209
938
  err = JSS::APIRequestError
1210
- msg_matcher = %r{<body.*?>(.*?)</body>}m
939
+ msg = "There was a error processing your request, status: #{@last_http_response.status}"
1211
940
  end
1212
- exception.http_body =~ msg_matcher
1213
- msg = Regexp.last_match(1)
1214
- msg ||= exception.http_body
1215
941
  raise err, msg
1216
942
  end
1217
943
 
1218
- # RestClient::Resource#delete doesn't take an HTTP payload,
1219
- # but some JSS API resources require it (notably, logflush).
1220
- #
1221
- # This method uses RestClient::Request#execute
1222
- # to do the same thing that RestClient::Resource#delete does, but
1223
- # adding the payload.
1224
- #
1225
- # @param rsrc[String] the sub-resource we're DELETEing
1226
- #
1227
- # @param payload[String] The XML to be passed with the DELETE
1228
- #
1229
- # @param additional_headers[Type] See RestClient::Request#execute
1230
- #
1231
- # @param &block[Type] See RestClient::Request#execute
1232
- #
1233
- # @return [String] the XML response from the server.
1234
- #
1235
- def delete_with_payload(rsrc, payload, additional_headers = {}, &block)
1236
- headers = (@cnx.options[:headers] || {}).merge(additional_headers)
1237
- @last_http_response = RestClient::Request.execute(
1238
- @cnx.options.merge(
1239
- method: :delete,
1240
- url: @cnx[rsrc].url,
1241
- payload: payload,
1242
- headers: headers
1243
- ),
1244
- &(block || @block)
1245
- )
1246
- rescue RestClient::ExceptionWithResponse => e
1247
- handle_http_error e
1248
- end # delete_with_payload
944
+ # create the faraday connection object
945
+ def create_connection(pw)
946
+ Faraday.new(@rest_url, ssl: @ssl_options) do |cnx|
947
+ cnx.basic_auth @user, pw
948
+ cnx.options[:timeout] = @timeout
949
+ cnx.options[:open_timeout] = @open_timeout
950
+ cnx.adapter Faraday::Adapter::NetHttp
951
+ end
952
+ end
1249
953
 
1250
954
  end # class APIConnection
1251
955
 
956
+ # JSS MODULE METHODS
957
+ ######################
958
+
1252
959
  # Create a new APIConnection object and use it for all
1253
960
  # future API calls. If connection options are provided,
1254
961
  # they are passed to the connect method immediately, otherwise
@@ -1276,6 +983,7 @@ module JSS
1276
983
  #
1277
984
  def self.use_api_connection(connection)
1278
985
  raise 'API connections must be instances of JSS::APIConnection' unless connection.is_a? JSS::APIConnection
986
+
1279
987
  @api = connection
1280
988
  end
1281
989