ruby-jss 0.9.2 → 0.10.0a1

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 (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