ruby-jss 0.9.2 → 0.10.0a1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +13 -1
  3. data/README.md +7 -7
  4. data/bin/cgrouper +6 -6
  5. data/bin/netseg-update +1 -1
  6. data/lib/jss.rb +1 -0
  7. data/lib/jss/api_connection.rb +428 -44
  8. data/lib/jss/api_object.rb +119 -68
  9. data/lib/jss/api_object/account.rb +12 -12
  10. data/lib/jss/api_object/advanced_search.rb +12 -12
  11. data/lib/jss/api_object/categorizable.rb +4 -4
  12. data/lib/jss/api_object/category.rb +2 -2
  13. data/lib/jss/api_object/computer.rb +111 -58
  14. data/lib/jss/api_object/computer_invitation.rb +2 -2
  15. data/lib/jss/api_object/creatable.rb +19 -8
  16. data/lib/jss/api_object/criteriable/criteria.rb +8 -8
  17. data/lib/jss/api_object/distribution_point.rb +14 -48
  18. data/lib/jss/api_object/extension_attribute.rb +14 -11
  19. data/lib/jss/api_object/extension_attribute/computer_extension_attribute.rb +18 -18
  20. data/lib/jss/api_object/group.rb +7 -7
  21. data/lib/jss/api_object/ldap_server.rb +51 -60
  22. data/lib/jss/api_object/locatable.rb +2 -2
  23. data/lib/jss/api_object/matchable.rb +8 -9
  24. data/lib/jss/api_object/mobile_device.rb +61 -59
  25. data/lib/jss/api_object/mobile_device_application.rb +3 -3
  26. data/lib/jss/api_object/network_segment.rb +24 -19
  27. data/lib/jss/api_object/package.rb +6 -6
  28. data/lib/jss/api_object/peripheral.rb +5 -5
  29. data/lib/jss/api_object/policy.rb +5 -5
  30. data/lib/jss/api_object/restricted_software.rb +4 -4
  31. data/lib/jss/api_object/scopable/scope.rb +3 -3
  32. data/lib/jss/api_object/script.rb +1 -1
  33. data/lib/jss/api_object/self_servable.rb +3 -3
  34. data/lib/jss/api_object/self_servable/icon.rb +7 -2
  35. data/lib/jss/api_object/updatable.rb +2 -2
  36. data/lib/jss/api_object/uploadable.rb +1 -1
  37. data/lib/jss/api_object/user.rb +2 -2
  38. data/lib/jss/composer.rb +37 -10
  39. data/lib/jss/ruby_extensions/string.rb +51 -42
  40. data/lib/jss/server.rb +27 -6
  41. data/lib/jss/utility.rb +44 -0
  42. data/lib/jss/validate.rb +85 -0
  43. data/lib/jss/version.rb +1 -1
  44. metadata +5 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3ea60a35ed980525b262173317034c3b0bde60ef
4
- data.tar.gz: 0f41df06651a7c745d9b1b70aa645a22c0a443f2
3
+ metadata.gz: 3796577e296c595860954645bc0a2596f14245ff
4
+ data.tar.gz: 1ef961ef3629054e53f04415999bb02525c6973a
5
5
  SHA512:
6
- metadata.gz: 51f0c670d7c92df65a3686e7d3d930622095b15dc181bbd3b3d90be7d6e1c478fbf376aede5fa00b143fa60050993eb37c9c6df81d06e9e22883a7e61a343600
7
- data.tar.gz: 60d3ed7275e5dab1f44a36428f72974673967fe02cc4e594309863af2d5581303abb847b0c89f93c325638d41f9227b78ea6e3bb22dd4450f16f279c0576d6b4
6
+ metadata.gz: 449baa374a0229a15335eb9d96e5815fac87537176d7d9abad9cc9e3be39538b11cc575ff2a6651ba5e820e6f9724339fb2e32720f4fa48b431440cc3e32c873
7
+ data.tar.gz: 9c1f058392f666a6bc812beadb9d36891ab6e49df7f4c47e3ecce7faa896e35108ed2a97c32bfdffa5da367f88ff7832f94c01f4ca59bfc4152f0e6b5345f3d0
data/CHANGES.md CHANGED
@@ -1,6 +1,18 @@
1
1
  # Change History
2
2
 
3
- ## v0.9.0
3
+ ## v0.9.3 2017-08-08
4
+
5
+ - Add: JSS::Computer instance now allow you to modify mac_address, alt_mac_address, udid, and serial_number.
6
+ Note: even tho the WebUI doesn't allow editing of the serial_number, the API does and doing so can be useful
7
+ for dealing with duplicate SN's when a new logic board with a new udid creates a new computer entry.
8
+ - Add: JSS::Validate module, to consoliday generic data-validation methods. Methods will be moved to it from
9
+ other places over time.
10
+
11
+ ## v0.9.2 2017-07-25
12
+
13
+ - Fix: parsing of JSS versions > 9.99
14
+
15
+ ## v0.9.0 2017-07-17
4
16
 
5
17
  - Add: JSS::MobileDevice.all_apple_tvs class method
6
18
  - Add: JSS::MobileDevice.management_history method, and related methods in instances
data/README.md CHANGED
@@ -99,11 +99,11 @@ ns.save
99
99
  Before you can work with JSS Objects via the API, you have to connect to it.
100
100
 
101
101
  The constant {JSS::API} contains the connection to the API (a singleton instance of {JSS::APIConnection}). When the JSS Module is first loaded, it isn't
102
- connected. To remedy that, use JSS.api_connection.connect, passing it values for the connection. In this example, those values are stored
102
+ connected. To remedy that, use JSS.api.connect, passing it values for the connection. In this example, those values are stored
103
103
  in the local variables jss_user, jss_user_pw, and jss_server_hostname, and others are left as default.
104
104
 
105
105
  ```ruby
106
- JSS.api_connection.connect user: jss_user, pw: jss_user_pw, server: jss_server_hostname
106
+ JSS.api.connect user: jss_user, pw: jss_user_pw, server: jss_server_hostname
107
107
  ```
108
108
 
109
109
  Make sure the user has privileges in the JSS to do things with desired Objects.
@@ -301,7 +301,7 @@ Other useful classes:
301
301
 
302
302
  The {JSS::Configuration} singleton class is used to read, write, and use site-specific defaults for the JSS module. When the Module is required, the single instance of {JSS::Configuration} is created and stored in the constant {JSS::CONFIG}. At that time the system-wide file /etc/jss_gem.conf is examined if it exists, and the items in it are loaded into the attributes of {JSS::CONFIG}. The user-specific file ~/.jss_gem.conf then is examined if it exists, and any items defined there will override those values from the system-wide file.
303
303
 
304
- The values defined in those files are used as defaults throughout the module. Currently, those values are only related to establishing the API connection. For example, if a server name is defined, then a :server does not have to be specified when calling {JSS::API#connect}. Values provided explicitly when calling JSS.api_connection.connect will override the config values.
304
+ The values defined in those files are used as defaults throughout the module. Currently, those values are only related to establishing the API connection. For example, if a server name is defined, then a :server does not have to be specified when calling {JSS::API#connect}. Values provided explicitly when calling JSS.api.connect will override the config values.
305
305
 
306
306
  While the {JSS::Configuration} class provides methods for changing the values, saving the files, and re-reading them, or reading an arbitrary file, the files are text files with a simple format, and can be created by any means desired. The file format is one attribute per line, thus:
307
307
 
@@ -326,11 +326,11 @@ api_username: readonly-api-user
326
326
  api_verify_cert: false
327
327
  ```
328
328
 
329
- and then any calls to JSS.api_connection.connect will assume that server and username, and won't complain about the self-signed certificate.
329
+ and then any calls to JSS.api.connect will assume that server and username, and won't complain about the self-signed certificate.
330
330
 
331
331
  ### Passwords
332
332
 
333
- The config files don't store passwords and the {JSS::Configuration} instance doesn't work with them. You'll have to use your own methods for acquiring the password for the JSS.api_connection.connect call.
333
+ The config files don't store passwords and the {JSS::Configuration} instance doesn't work with them. You'll have to use your own methods for acquiring the password for the JSS.api.connect call.
334
334
 
335
335
  The {JSS::API#connect} method also accepts the symbols :stdin# and :prompt as values for the :pw argument, which will cause it to read the password from a line of stdin, or prompt for it in the shell.
336
336
 
@@ -340,7 +340,7 @@ Here's an example of how to use a password stored in a file:
340
340
 
341
341
  ```ruby
342
342
  password = File.read "/path/to/secure/password/file" # read the password from a file
343
- JSS.api_connection.connect pw: password # other arguments used from the config settings
343
+ JSS.api.connect pw: password # other arguments used from the config settings
344
344
  ```
345
345
 
346
346
  And here's an example of how to read a password from a web server and use it.
@@ -348,7 +348,7 @@ And here's an example of how to read a password from a web server and use it.
348
348
  ```ruby
349
349
  require 'open-uri'
350
350
  password = open('https://server.org.org/path/to/password').read
351
- JSS.api_connection.connect pw: password # other arguments used from the config settings
351
+ JSS.api.connect pw: password # other arguments used from the config settings
352
352
  ```
353
353
 
354
354
  ## BEYOND THE API
@@ -2,21 +2,21 @@
2
2
 
3
3
  ### Copyright 2017 Pixar
4
4
 
5
- ###
5
+ ###
6
6
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
7
7
  ### with the following modification; you may not use this file except in
8
8
  ### compliance with the Apache License and the following modification to it:
9
9
  ### Section 6. Trademarks. is deleted and replaced with:
10
- ###
10
+ ###
11
11
  ### 6. Trademarks. This License does not grant permission to use the trade
12
12
  ### names, trademarks, service marks, or product names of the Licensor
13
13
  ### and its affiliates, except as required to comply with Section 4(c) of
14
14
  ### the License and to reproduce the content of the NOTICE file.
15
- ###
15
+ ###
16
16
  ### You may obtain a copy of the Apache License at
17
- ###
17
+ ###
18
18
  ### http://www.apache.org/licenses/LICENSE-2.0
19
- ###
19
+ ###
20
20
  ### Unless required by applicable law or agreed to in writing, software
21
21
  ### distributed under the Apache License with the above modification is
22
22
  ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -191,7 +191,7 @@ class App
191
191
  raise JSS::MissingDataError, "No JSS Username provided or found in the JSS gem config." unless @options.user
192
192
  raise JSS::MissingDataError, "No JSS Server provided or found in the JSS gem config." unless @options.server
193
193
 
194
- JSS.api_connection.connect( :server => @options.server,
194
+ JSS.api.connect( :server => @options.server,
195
195
  :port => @options.port,
196
196
  :verify_cert => @options.verify_cert,
197
197
  :user => @options.user,
@@ -148,7 +148,7 @@ class App
148
148
  end # run
149
149
 
150
150
  def connect_to_jss
151
- JSS.api_connection.connect(
151
+ JSS.api.connect(
152
152
  server: @server,
153
153
  port: @port,
154
154
  verify_cert: @verify_cert,
data/lib/jss.rb CHANGED
@@ -196,4 +196,5 @@ require 'jss/server'
196
196
  require 'jss/client'
197
197
  require 'jss/configuration'
198
198
  require 'jss/db_connection'
199
+ require 'jss/validate'
199
200
  require 'jss/version'
@@ -37,49 +37,93 @@ module JSS
37
37
  # Classes
38
38
  #####################################
39
39
 
40
- # Instances of this class represent an API connection to the JSS.
40
+ # Instances of this class represent a REST connection to a JSS API.
41
41
  #
42
- # JSS::APIConnection objects are REST connections to JSS APIs and contain
43
- # (once connected) all the data needed for communication with
44
- # that API, including login credentials, URLs, and so on.
42
+ # For most cases, a single connection to a single JSS is all you need, and
43
+ # this is ruby-jss's default behavior.
45
44
  #
46
- # == The default connection
45
+ # If needed, multiple connections can be made and used sequentially or
46
+ # simultaneously.
47
+ #
48
+ # == Using the default connection
47
49
  #
48
50
  # When ruby-jss is loaded, a not-yet-connected default instance of
49
- # JSS::APIConnection is created, activated, and stored internally.
51
+ # JSS::APIConnection is created and stored in the constant JSS::API.
52
+ # This connection is used as the initial 'active connection' (see below)
53
+ # so all methods that make API calls will use it by default. For most uses,
54
+ # where you're only going to be working with one connection to one JSS, the
55
+ # default connection is all you need.
56
+ #
50
57
  # Before using it you must call its {#connect} method, passing in appropriate
51
58
  # connection details and credentials.
52
59
  #
53
- # Here's how to use the default connection:
60
+ # Example:
54
61
  #
55
- # require 'ruby-jss'
56
- # JSS.api.connect server: 'server.address.edu', user: 'jss-api-user', pw: :prompt
62
+ # require 'ruby-jss'
63
+ # JSS.api.connect server: 'server.address.edu', user: 'jss-api-user', pw: :prompt
64
+ # # (see {JSS::APIConnection#connect} for all the connection options)
57
65
  #
58
- # (see {JSS::APIConnection#connect} for all the connection options)
66
+ # a_phone = JSS::MobileDevice.fetch id: 8743
59
67
  #
60
- # If you're only going to be connecting to one server, or one at a time,
61
- # using the default connection is preferred. You can call its {#connect}
62
- # method at any time to change servers or connection credentials.
68
+ # # the mobile device was fetched through the default connection
63
69
  #
64
- # == Multiple connections & the currently active connection
70
+ # == Using Multiple Simultaneous Connections
65
71
  #
66
72
  # Sometimes you need to connect simultaneously to more than one JSS.
67
- # or to the same JSS with different credentials.
73
+ # or to the same JSS with different credentials. ruby-jss allows you to
74
+ # create as many connections as needed, and gives you three ways to use them:
68
75
  #
69
- # While multiple connection instances can be created, only one is active at
70
- # a time and all API access happens through the currently active connection.
71
- # (See below for how to switch between different connections)
76
+ # 1. Making a connection 'active', after which API calls go thru it
77
+ # automatically
72
78
  #
73
- # The currently-active connection instance is available from the
74
- # `JSS.api` method.
79
+ # Example:
80
+ #
81
+ # a_computer = JSS::Computer.fetch id: 1234
82
+ #
83
+ # # the JSS::Computer with id 1234 is fetched from the active connection
84
+ # # and stored in the variable 'a_computer'
85
+ #
86
+ # NOTE: When ruby-jss is first loaded, the default connection (see above)
87
+ # is the active connection.
88
+ #
89
+ # 2. Passing an APIConnection instance to methods that use the API
90
+ #
91
+ # Example:
92
+ #
93
+ # a_computer = JSS::Computer.fetch id: 1234, api: production_api
94
+ #
95
+ # # the JSS::Computer with id 1234 is fetched from the connection
96
+ # # stored in the variable 'production_api'. The computer is
97
+ # # then stored in the variable 'a_computer'
98
+ #
99
+ # 3. Using the APIConnection instance itself to make API calls.
100
+ #
101
+ # Example:
102
+ #
103
+ # a_computer = production_api.fetch :Computer, id: 1234
104
+ #
105
+ # # the JSS::Computer with id 1234 is fetched from the connection
106
+ # # stored in the variable 'production_api'. The computer is
107
+ # # then stored in the variable 'a_computer'
108
+ #
109
+ # See below for more details about the ways to use multiple connections.
110
+ #
111
+ # NOTE:
112
+ # Objects retrieved or created through an APIConnection store an internal
113
+ # reference to that APIConnection and use that when they make other API
114
+ # calls, thus ensuring data consistency when using multiple connections.
115
+ #
116
+ # Similiarly, the data caches used by APIObject list methods (e.g.
117
+ # JSS::Computer.all, .all_names, and so on) are stored in the APIConnection
118
+ # instance through which they were read, so they won't be incorrect when
119
+ # you use multiple connections.
75
120
  #
76
- # == Making new connection instances
121
+ # == Making new APIConnection instances
77
122
  #
78
- # New connections can be created and stored in a variable using
79
- # the standard ruby 'new' method.
123
+ # New connections can be created using the standard ruby 'new' method.
80
124
  #
81
125
  # If you provide connection details when calling 'new', they will be passed
82
- # to the #connect method immediately.
126
+ # to the {#connect} method immediately. Otherwise you can call {#connect} later.
83
127
  #
84
128
  # production_api = JSS::APIConnection.new(
85
129
  # name: 'prod',
@@ -90,28 +134,46 @@ module JSS
90
134
  #
91
135
  # # the new connection is now stored in the variable 'production_api'.
92
136
  #
93
- # == Switching between multiple connections
137
+ # == Using the 'Active' Connection
94
138
  #
95
- # Only one connection is active at a time and the currently active one is
96
- # returned when you call `JSS.api` or its aliases `JSS.api_connection` or
97
- # `JSS.connection`
139
+ # While multiple connection instances can be created, only one at a time is
140
+ # 'the active connection' and all APIObject-based access methods in ruby-jss
141
+ # will use it automatically. When ruby-jss is loaded, the default connection
142
+ # (see above) is the active connection.
143
+ #
144
+ # To use the active connection, just call a method on an APIObject subclass
145
+ # that uses the API.
146
+ #
147
+ # For example, the various list methods:
148
+ #
149
+ # all_computer_sns = JSS::Computer.all_serial_numbers
150
+ #
151
+ # # the list of all computer serial numbers is read from the active
152
+ # # connection and stored in all_computer_sns
153
+ #
154
+ # Fetching an object from the API:
155
+ #
156
+ # victim_md = JSS::MobileDevice.fetch id: 832
157
+ #
158
+ # # the variable 'victim_md' now contains a JSS::MobileDevice queried
159
+ # # through the active connection.
160
+ #
161
+ # The currently-active connection instance is available from the
162
+ # `JSS.api` method.
163
+ #
164
+ # === Making a Connection Active
165
+ #
166
+ # Only one connection is 'active' at a time and the currently active one is
167
+ # returned when you call `JSS.api` or its alias `JSS.active_connection`
98
168
  #
99
169
  # To activate another connection just pass it to the JSS.use_api method like so:
170
+ #
100
171
  # JSS.use_api production_api
101
172
  # # the connection we stored in 'production_api' is now active
102
173
  #
103
174
  # To re-activate to the default connection, just call
104
175
  # JSS.use_default_connection
105
176
  #
106
- # NOTE:
107
- # The APIObject list methods (e.g. JSS::Computer.all) cache the list
108
- # data from the API the first time they are used, and after that when
109
- # their 'refresh' option is true.
110
- #
111
- # Those caches are stored in the APIConnection instance through-
112
- # which they were read, so they won't be incorrect when you switch
113
- # connections.
114
- #
115
177
  # == Connection Names:
116
178
  #
117
179
  # As seen in the example above, you can provide a 'name:' parameter
@@ -147,9 +209,61 @@ module JSS
147
209
  #
148
210
  # JSS.api.name # => 'prod2'
149
211
  #
212
+ # == Passing an APIConnection object to API-related methods
213
+ #
214
+ # All methods that use the API can take an 'api:' parameter which
215
+ # contains an APIConnection object. When provided, that APIconnection is
216
+ # used rather than the active connection.
217
+ #
218
+ # For example:
219
+ #
220
+ # prod2_computer_sns = JSS::Computer.all_serial_numbers, api: production_api2
221
+ #
222
+ # # the list of all computer serial numbers is read from the connection in
223
+ # # the variable 'production_api2' and stored in 'prod2_computer_sns'
224
+ #
225
+ # prod2_victim_md = JSS::MobileDevice.fetch id: 832, api: production_api2
226
+ #
227
+ # # the variable 'prod2_victim_md' now contains a JSS::MobileDevice queried
228
+ # # through the connection 'production_api2'.
229
+ #
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
+ # Most of them behave identically to the same methods in the APIObject classes
241
+ #
242
+ # - {#all} The 'list' methods of the various APIObject classes. Use the 'only:'
243
+ # parameter to specify one of the sub-list-methods, like #all_ids or
244
+ # #all_laptops
245
+ # - {#map_all_ids} the equivalent of #map_all_ids_to in the APIObject classes
246
+ # - {#valid_id} given a class and an identifier (like macaddress or udid)
247
+ # return a valid id or nil
248
+ # - {#exist?} given a class and an identifier (like macaddress or udid) does
249
+ # the identifier exist for the class in the JSS
250
+ # - {#match} list items in the JSS matching a query
251
+ # (if the object is {Matchable})
252
+ # - {#fetch} retrieve an object from the JSS
253
+ # - {#make} instantiate an object to be created in the JSS
254
+ # - {#send_computer_mdm_command} same as {Computer.send_mdm_command}
255
+ # - {#computer_checkin_settings} same as {Computer.checkin_settings}
256
+ # - {#computer_inventory_collection_settings} same as {Computer.inventory_collection_settings}
257
+ # - {#send_mobiledevice_mdm_command} same as {MobileDevice.send_mdm_command}
258
+ # - {#master_distribution_point} same as {DistributionPoint.master_distribution_point}
259
+ # - {#my_distribution_point} same as {DistributionPoint.my_distribution_point}
260
+ # - {#network_ranges} same as {NetworkSegment.network_ranges}
261
+ # - {#network_segments_for_ip} same as {NetworkSegment.segments_for_ip}
262
+ # - {#my_network_segments} same as {NetworkSegment.my_network_segments}
263
+ #
150
264
  # == Low-level use of APIConnection instances.
151
265
  #
152
- # For most uses, creating, activating, and connecting APIConnection instances
266
+ # For most cases, using APIConnection instances as mentioned above
153
267
  # is all you'll need. However to access API resources that aren't yet
154
268
  # implemented in other parts of ruby-jss, you can use the methods
155
269
  # {#get_rsrc}, {#put_rsrc}, {#post_rsrc}, & {#delete_rsrc}
@@ -378,7 +492,7 @@ module JSS
378
492
  #
379
493
  def get_rsrc(rsrc, format = :json)
380
494
  # puts object_id
381
- raise JSS::InvalidConnectionError, 'Not Connected. Use JSS.api.connect first.' unless @connected
495
+ raise JSS::InvalidConnectionError, 'Not Connected. Use .connect first.' unless @connected
382
496
  rsrc = URI.encode rsrc
383
497
  @last_http_response = @cnx[rsrc].get(accept: format)
384
498
  return JSON.parse(@last_http_response, symbolize_names: true) if format == :json
@@ -393,7 +507,7 @@ module JSS
393
507
  # @return [String] the xml response from the server.
394
508
  #
395
509
  def put_rsrc(rsrc, xml)
396
- raise JSS::InvalidConnectionError, 'Not Connected. Use JSS.api_connection.connect first.' unless @connected
510
+ raise JSS::InvalidConnectionError, 'Not Connected. Use .connect first.' unless @connected
397
511
 
398
512
  # convert CRs & to 
399
513
  xml.gsub!(/\r/, '
')
@@ -413,7 +527,7 @@ module JSS
413
527
  # @return [String] the xml response from the server.
414
528
  #
415
529
  def post_rsrc(rsrc, xml = '')
416
- raise JSS::InvalidConnectionError, 'Not Connected. Use JSS.api_connection.connect first.' unless @connected
530
+ raise JSS::InvalidConnectionError, 'Not Connected. Use .connect first.' unless @connected
417
531
 
418
532
  # convert CRs & to 
419
533
  xml.gsub!(/\r/, '
') if xml
@@ -431,7 +545,7 @@ module JSS
431
545
  # @return [String] the xml response from the server.
432
546
  #
433
547
  def delete_rsrc(rsrc, xml = nil)
434
- raise JSS::InvalidConnectionError, 'Not Connected. Use JSS.api_connection.connect first.' unless @connected
548
+ raise JSS::InvalidConnectionError, 'Not Connected. Use .connect first.' unless @connected
435
549
  raise MissingDataError, 'Missing :rsrc' if rsrc.nil?
436
550
 
437
551
  # payload?
@@ -492,6 +606,274 @@ module JSS
492
606
  alias connected? connected
493
607
  alias host hostname
494
608
 
609
+
610
+ #################
611
+
612
+ # Call one of the 'all*' methods on a JSS::APIObject subclass
613
+ # using this APIConnection.
614
+ #
615
+ # @param class_name[String,Symbol] The name of a JSS::APIObject subclass
616
+ # see {JSS.api_object_class}
617
+ #
618
+ # @param refresh[Boolean] Should the data be re-read from the API?
619
+ #
620
+ # @param only[String,Symbol] Limit the output to subset or data. All
621
+ # APIObject subclasses can take :ids or :names, which calls the .all_ids
622
+ # and .all_names methods. Some subclasses can take other options, e.g.
623
+ # MobileDevice can take :udids
624
+ #
625
+ # @return [Array] The list of items for the class
626
+ #
627
+ def all(class_name, refresh = false, only: nil )
628
+ the_class = JSS.api_object_class(class_name)
629
+ list_method = only ? :"all_#{only}" : :all
630
+
631
+ raise ArgumentError, "Unknown identifier: #{only} for #{the_class}" unless
632
+ the_class.respond_to? list_method
633
+
634
+ the_class.send list_method, refresh, api: self
635
+ end
636
+
637
+ # Call the 'map_all_ids_to' method on a JSS::APIObject subclass
638
+ # using this APIConnection.
639
+ #
640
+ # @param class_name[String,Symbol] The name of a JSS::APIObject subclass
641
+ # see {JSS.api_object_class}
642
+ #
643
+ # @param refresh[Boolean] Should the data be re-read from the API?
644
+ #
645
+ # @param to[String,Symbol] the value to which the ids should be mapped
646
+ #
647
+ # @return [Hash] The ids for the class keyed to the requested identifier
648
+ #
649
+ def map_all_ids(class_name, refresh = false, to: nil)
650
+ raise "'to:' value must be provided for mapping ids." unless to
651
+ the_class = JSS.api_object_class(class_name)
652
+ the_class.map_all_ids_to to, api: self
653
+ end
654
+
655
+ # Call the 'valid_id' method on a JSS::APIObject subclass
656
+ # using this APIConnection. See {JSS::APIObject.valid_id}
657
+ #
658
+ # @param class_name[String,Symbol] The name of a JSS::APIObject subclass,
659
+ # see {JSS.api_object_class}
660
+ #
661
+ # @param identifier[String,Symbol] the value to which the ids should be mapped
662
+ #
663
+ # @param refresh[Boolean] Should the data be re-read from the API?
664
+ #
665
+ # @return [Integer, nil] the id of the matching object of the class,
666
+ # or nil if there isn't one
667
+ #
668
+ def valid_id(class_name, identifier, refresh = true)
669
+ the_class = JSS.api_object_class(class_name)
670
+ the_class.valid_id identifier, refresh, api: self
671
+ end
672
+
673
+ # Call the 'exist?' method on a JSS::APIObject subclass
674
+ # using this APIConnection. See {JSS::APIObject.exist?}
675
+ #
676
+ # @param class_name[String,Symbol] The name of a JSS::APIObject subclass
677
+ # see {JSS.api_object_class}
678
+ #
679
+ # @param identifier[String,Symbol] the value to which the ids should be mapped
680
+ #
681
+ # @param refresh[Boolean] Should the data be re-read from the API?
682
+ #
683
+ # @return [Boolean] Is there an object of this class in the JSS matching
684
+ # this indentifier?
685
+ #
686
+ def exist?(class_name, identifier, refresh = false)
687
+ !valid_id(class_name, identifier, refresh).nil?
688
+ end
689
+
690
+ # Call {Matchable.match} for the given class.
691
+ #
692
+ # See {Matchable.match}
693
+ #
694
+ # @param class_name[String,Symbol] The name of a JSS::APIObject subclass
695
+ # see {JSS.api_object_class}
696
+ #
697
+ # @return (see Matchable.match)
698
+ #
699
+ def match(class_name, term)
700
+ the_class = JSS.api_object_class(class_name)
701
+ raise JSS::UnsupportedError, "Class #{the_class} is not matchable" unless the_class.respond_to? :match
702
+ the_class.match term, api: self
703
+ end
704
+
705
+ # Retrieve an object of a given class from the API
706
+ # See {APIObject.fetch}
707
+ #
708
+ # @param class_name[String,Symbol] The name of a JSS::APIObject subclass
709
+ # see {JSS.api_object_class}
710
+ #
711
+ # @return [APIObject] The ruby-instance of the object.
712
+ #
713
+ def fetch(class_name, arg)
714
+ the_class = JSS.api_object_class(class_name)
715
+ the_class.fetch arg, api: self
716
+ end
717
+
718
+ # Make a ruby instance of a not-yet-existing APIObject
719
+ # of the given class
720
+ # See {APIObject.make}
721
+ #
722
+ # @param class_name[String,Symbol] The name of a JSS::APIObject subclass
723
+ # see {JSS.api_object_class}
724
+ #
725
+ # @return [APIObject] The un-created ruby-instance of the object.
726
+ #
727
+ def make(class_name, **args)
728
+ the_class = JSS.api_object_class(class_name)
729
+ args[:api] = self
730
+ the_class.make args
731
+ end
732
+
733
+ # Call {JSS::Computer.checkin_settings} passing this API
734
+ # connection
735
+ #
736
+ # @return (see JSS::Computer.checkin_settings)
737
+ #
738
+ def computer_checkin_settings
739
+ JSS::Computer.checkin_settings api: self
740
+ end
741
+
742
+
743
+ # Call {JSS::Computer.inventory_collection_settings} passing this API
744
+ # connection
745
+ #
746
+ # @return (see JSS::Computer.checkin_settings)
747
+ #
748
+ def computer_inventory_collection_settings
749
+ JSS::Computer.inventory_collection_settings api: self
750
+ end
751
+
752
+ # Get the DistributionPoint instance for the master
753
+ # distribution point in the JSS. If there's only one
754
+ # in the JSS, return it even if not marked as master.
755
+ #
756
+ # @param refresh[Boolean] re-read from the API?
757
+ #
758
+ # @return [JSS::DistributionPoint]
759
+ #
760
+ def master_distribution_point(refresh = false)
761
+ @master_distribution_point = nil if refresh
762
+ return @master_distribution_point if @master_distribution_point
763
+
764
+ all_dps = JSS::DistributionPoint.all refresh, api: self
765
+
766
+ @master_distribution_point =
767
+ case all_dps.size
768
+ when 0
769
+ raise JSS::NoSuchItemError, "No distribution points defined"
770
+ when 1
771
+ JSS::DistributionPoint.fetch id: all_dps.first[:id], api: self
772
+ else
773
+ JSS::DistributionPoint.fetch id: :master, api: self
774
+ end
775
+ end
776
+
777
+ # Get the DistributionPoint instance for the machine running
778
+ # this code, based on its IP address. If none is defined for this IP address,
779
+ # use the result of master_distribution_point
780
+ #
781
+ # @param refresh[Boolean] should the distribution point be re-queried?
782
+ #
783
+ # @return [JSS::DistributionPoint]
784
+ #
785
+ def my_distribution_point(refresh = false)
786
+ @my_distribution_point = nil if refresh
787
+ return @my_distribution_point if @my_distribution_point
788
+
789
+ my_net_seg = my_network_segments[0]
790
+ @my_distribution_point = JSS::NetworkSegment.fetch(id: my_net_seg, api: self).distribution_point if my_net_seg
791
+ @my_distribution_point ||= master_distribution_point refresh
792
+ @my_distribution_point
793
+ end
794
+
795
+ # All NetworkSegments in this jss as IPAddr object Ranges representing the
796
+ # Segment, e.g. with starting = 10.24.9.1 and ending = 10.24.15.254
797
+ # the range looks like:
798
+ # <IPAddr: IPv4:10.24.9.1/255.255.255.255>..#<IPAddr: IPv4:10.24.15.254/255.255.255.255>
799
+ #
800
+ # Using the #include? method on those Ranges is very useful.
801
+ #
802
+ # @param refresh[Boolean] should the data be re-queried?
803
+ #
804
+ # @return [Hash{Integer => Range}] the network segments as IPv4 address Ranges
805
+ #
806
+ def network_ranges(refresh = false)
807
+ @network_ranges = nil if refresh
808
+ return @network_ranges if @network_ranges
809
+ @network_ranges = {}
810
+ JSS::NetworkSegment.all(refresh, api: self).each do |ns|
811
+ @network_ranges[ns[:id]] = IPAddr.new(ns[:starting_address])..IPAddr.new(ns[:ending_address])
812
+ end
813
+ @network_ranges
814
+ end # def network_segments
815
+
816
+ # Find the ids of the network segments that contain a given IP address.
817
+ #
818
+ # Even tho IPAddr.include? will take a String or an IPAddr
819
+ # I convert the ip to an IPAddr so that an exception will be raised if
820
+ # the ip isn't a valid ip.
821
+ #
822
+ # @param ip[String, IPAddr] the IP address to locate
823
+ #
824
+ # @param refresh[Boolean] should the data be re-queried?
825
+ #
826
+ # @return [Array<Integer>] the ids of the NetworkSegments containing the given ip
827
+ #
828
+ def network_segments_for_ip(ip, refresh = false)
829
+ ok_ip = IPAddr.new(ip)
830
+ matches = []
831
+ network_ranges.each { |id, subnet| matches << id if subnet.include?(ok_ip) }
832
+ matches
833
+ end
834
+
835
+ # Find the current network segment ids for the machine running this code
836
+ #
837
+ # @return [Array<Integer>] the NetworkSegment ids for this machine right now.
838
+ #
839
+ def my_network_segments
840
+ network_segments_for_ip JSS::Client.my_ip_address
841
+ end
842
+
843
+ # Send an MDM command to one or more computers managed by
844
+ # this JSS
845
+ #
846
+ # see {JSS::Computer.send_mdm_command}
847
+ #
848
+ def send_computer_mdm_command(targets, command, passcode = nil)
849
+ JSS::Computer.send_mdm_command(targets, command, passcode, api: self)
850
+ end
851
+
852
+ # Send an MDM command to one or more mobile devices managed by
853
+ # this JSS
854
+ #
855
+ # see {JSS::MobileDevice.send_mdm_command}
856
+ #
857
+ def send_mobiledevice_mdm_command(targets, command, data = nil)
858
+ JSS::MobileDevice.send_mdm_command(targets, command, data, api: self)
859
+ end
860
+
861
+ # Remove the various cached data
862
+ # from the instance_variables used to create
863
+ # pretty-print (pp) output.
864
+ #
865
+ # @return [Array] the desired instance_variables
866
+ #
867
+ def pretty_print_instance_variables
868
+ vars = instance_variables.sort
869
+ vars.delete :@object_list_cache
870
+ vars.delete :@last_http_response
871
+ vars.delete :@network_ranges
872
+ vars.delete :@my_distribution_point
873
+ vars.delete :@master_distribution_point
874
+ vars
875
+ end
876
+
495
877
  # Private Insance Methods
496
878
  ####################################
497
879
  private
@@ -596,9 +978,9 @@ module JSS
596
978
  # keep this basic level of info available for basic authentication
597
979
  # and JSS version checking.
598
980
  begin
599
- @server = JSS::Server.new get_rsrc('jssuser')[:user]
981
+ @server = JSS::Server.new get_rsrc('jssuser')[:user], self
600
982
  rescue RestClient::Unauthorized, RestClient::Request::Unauthorized
601
- raise JSS::AuthenticationError, "Incorrect JSS username or password for '#{JSS.api_connection.jss_user}@#{JSS.api_connection.server_host}'."
983
+ raise JSS::AuthenticationError, "Incorrect JSS username or password for '#{@jss_user}@#{@server_host}:#{@port}'."
602
984
  end
603
985
 
604
986
  min_vers = JSS.parse_jss_version(JSS::MINIMUM_SERVER_VERSION)[:version]
@@ -757,12 +1139,14 @@ module JSS
757
1139
  class << self
758
1140
  alias api_connection api
759
1141
  alias connection api
1142
+ alias active_connection api
760
1143
 
761
1144
  alias new_connection new_api_connection
762
1145
  alias new_api new_api_connection
763
1146
 
764
1147
  alias use_api use_api_connection
765
1148
  alias use_connection use_api_connection
1149
+ alias activate_connection use_api_connection
766
1150
  end
767
1151
 
768
1152
  # create the default connection