ruby-jss 0.10.2a5 → 0.10.2
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.
- checksums.yaml +4 -4
- data/CHANGES.md +5 -0
- data/lib/jss/api_connection.rb +19 -38
- data/lib/jss/api_object/advanced_search.rb +1 -5
- data/lib/jss/api_object/computer.rb +292 -316
- data/lib/jss/api_object/computer_invitation.rb +3 -5
- data/lib/jss/api_object/ebook.rb +0 -5
- data/lib/jss/api_object/group/computer_group.rb +0 -4
- data/lib/jss/api_object/group/mobile_device_group.rb +1 -4
- data/lib/jss/api_object/group.rb +1 -6
- data/lib/jss/api_object/mac_application.rb +0 -5
- data/lib/jss/api_object/mobile_device.rb +336 -57
- data/lib/jss/api_object/mobile_device_application.rb +0 -6
- data/lib/jss/api_object/mobile_device_configuration_profile.rb +0 -36
- data/lib/jss/api_object/osx_configuration_profile.rb +151 -115
- data/lib/jss/api_object/peripheral.rb +7 -5
- data/lib/jss/api_object/policy.rb +0 -5
- data/lib/jss/api_object/restricted_software.rb +0 -5
- data/lib/jss/api_object/scopable/scope.rb +411 -367
- data/lib/jss/api_object/self_servable.rb +4 -15
- data/lib/jss/api_object/site.rb +76 -45
- data/lib/jss/api_object/user.rb +3 -7
- data/lib/jss/api_object.rb +4 -74
- data/lib/jss/utility.rb +0 -21
- data/lib/jss/version.rb +1 -1
- data/lib/jss.rb +0 -4
- metadata +6 -10
- data/lib/jss/api_object/mdm.rb +0 -1268
- data/lib/jss/api_object/patch.rb +0 -38
- data/lib/jss/api_object/patch_policy.rb +0 -38
- data/lib/jss/api_object/sitable.rb +0 -197
@@ -63,24 +63,31 @@ module JSS
|
|
63
63
|
#
|
64
64
|
# === MDM Commands
|
65
65
|
#
|
66
|
-
#
|
67
|
-
#
|
66
|
+
# The following methods can be used to send an APNS command to the
|
67
|
+
# computer represented by an instance of JSS::Computer, equivalent to
|
68
|
+
# clicking one of the buttons on the Management Commands section of the
|
69
|
+
# Management tab of the Computer details page in the JSS UI.
|
68
70
|
#
|
69
|
-
#
|
70
|
-
#
|
71
|
+
# - {#blank_push} (aliases blank, noop, send_blank_push)
|
72
|
+
# - {#device_lock} (aliases lock, lock_device)
|
73
|
+
# - {#erase_device} (aliases wipe)
|
74
|
+
# - {#remove_mdm_profile}
|
71
75
|
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
+
# To send an MDM command without making a Computer instance, use the class
|
77
|
+
# {JSS::Computer.send_mdm_command} which can take multiple computer
|
78
|
+
# identifiers at once.
|
79
|
+
#
|
80
|
+
# NOTE: the poorly named 'UnmanageDevice' command via the API is implemented
|
81
|
+
# as the {#remove_mdm_profile} method (which is its name in the webUI).
|
82
|
+
# Calling that method will NOT unmanage the machine from the JSS's point
|
76
83
|
# of view, it will just remove the mdm management profile from the machine
|
77
84
|
# and all configuration profiles that were installed via the JSS. Those
|
78
85
|
# profiles may be re-installed automatically later if the computer is still in
|
79
86
|
# scope for them
|
80
87
|
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
#
|
88
|
+
# The {#make_unmanaged} method also removes the mdm profile, but actually
|
89
|
+
# does make the machine unmanged by the JSS, setting the management acct to
|
90
|
+
# nil, and requring re-enrollment.
|
84
91
|
#
|
85
92
|
# === Computer History
|
86
93
|
#
|
@@ -167,8 +174,6 @@ module JSS
|
|
167
174
|
include JSS::Purchasable
|
168
175
|
include JSS::Uploadable
|
169
176
|
include JSS::Extendable
|
170
|
-
include JSS::Sitable
|
171
|
-
include JSS::MDM
|
172
177
|
|
173
178
|
extend JSS::Matchable
|
174
179
|
|
@@ -188,9 +193,6 @@ module JSS
|
|
188
193
|
# It's also used in various error messages
|
189
194
|
RSRC_OBJECT_KEY = :computer
|
190
195
|
|
191
|
-
# Where is the Site data in the API JSON?
|
192
|
-
SITE_SUBSET = :general
|
193
|
-
|
194
196
|
# these keys, as well as :id and :name, are present in valid API JSON data for this class
|
195
197
|
# DEPRECATED, with be removed in a future release.
|
196
198
|
VALID_DATA_KEYS = %i[sus distribution_point alt_mac_address].freeze
|
@@ -216,8 +218,32 @@ module JSS
|
|
216
218
|
# file uploads can send attachments to the JSS using :computers as the sub-resource.
|
217
219
|
UPLOAD_TYPES = { attachment: :computers }.freeze
|
218
220
|
|
219
|
-
#
|
220
|
-
|
221
|
+
# The base REST resource for sending computer MDM commands
|
222
|
+
COMPUTER_MDM_RSRC = 'computercommands/command'.freeze
|
223
|
+
|
224
|
+
# A mapping of Symbols available to the send_mdm_command class method, to
|
225
|
+
# the String commands actuallly sent via the API.
|
226
|
+
COMPUTER_MDM_COMMANDS = {
|
227
|
+
blank_push: 'BlankPush',
|
228
|
+
blankpush: 'BlankPush',
|
229
|
+
send_blank_push: 'BlankPush',
|
230
|
+
blank: 'BlankPush',
|
231
|
+
noop: 'BlankPush',
|
232
|
+
device_lock: 'DeviceLock',
|
233
|
+
devicelock: 'DeviceLock',
|
234
|
+
lock: 'DeviceLock',
|
235
|
+
lock_device: 'DeviceLock',
|
236
|
+
erase_device: 'EraseDevice',
|
237
|
+
erasedevice: 'EraseDevice',
|
238
|
+
erase: 'EraseDevice',
|
239
|
+
wipe: 'EraseDevice',
|
240
|
+
unmanage_device: 'UnmanageDevice',
|
241
|
+
unmanagedevice: 'UnmanageDevice',
|
242
|
+
unmanage: 'UnmanageDevice'
|
243
|
+
}.freeze
|
244
|
+
|
245
|
+
# these MDM commands require a passcode
|
246
|
+
COMPUTER_MDM_COMMANDS_NEEDING_PASSCODE = %w[DeviceLock EraseDevice].freeze
|
221
247
|
|
222
248
|
# The API resource for app usage
|
223
249
|
APPLICATION_USAGE_RSRC = 'computerapplicationusage'.freeze
|
@@ -273,6 +299,8 @@ module JSS
|
|
273
299
|
# converted to strings) and the second-level hash key of the
|
274
300
|
# returned subset data.
|
275
301
|
#
|
302
|
+
# The values are the key within each history item that contains the
|
303
|
+
# 'epoch' timestamp, for conver
|
276
304
|
HISTORY_SUBSETS = %i[
|
277
305
|
computer_usage_logs
|
278
306
|
audits
|
@@ -285,29 +313,17 @@ module JSS
|
|
285
313
|
mac_app_store_applications
|
286
314
|
].freeze
|
287
315
|
|
288
|
-
#
|
289
|
-
#
|
290
|
-
#
|
291
|
-
#
|
292
|
-
#
|
293
|
-
#
|
294
|
-
#
|
295
|
-
#
|
296
|
-
#
|
297
|
-
#
|
298
|
-
#
|
299
|
-
# :pending - An array of hashes about apps pending installation
|
300
|
-
# :failed - An array of hashes about apps that failed to install.
|
301
|
-
#
|
302
|
-
# The .history class and instance methods for JSS::Computer re-organize
|
303
|
-
# those data structures to be consistent with the other subsets of history
|
304
|
-
# data by turning them into an Array of Hashes, where each hash has a
|
305
|
-
# :status key containing :completed/:installed, :pending, or :failed
|
306
|
-
#
|
307
|
-
# See {JSS::Computer.full_history}, {JSS::Computer.history_subset} and
|
308
|
-
# {JSS::Computer.standardize_history_subset} class methods for details.
|
309
|
-
#
|
310
|
-
HISTORY_INCONSISTENT_SUBSETS = %i[commands mac_app_store_applications].freeze
|
316
|
+
# HISTORY_SUBSETS = %i(
|
317
|
+
# computer_usage_logs date_time_epoch
|
318
|
+
# audits
|
319
|
+
# policy_logs date_completed_epoch
|
320
|
+
# casper_remote_logs date_time_epoch
|
321
|
+
# screen_sharing_logs date_time_epoch
|
322
|
+
# casper_imaging_logs
|
323
|
+
# commands completed_epoch
|
324
|
+
# user_location
|
325
|
+
# mac_app_store_applications
|
326
|
+
# ).freeze
|
311
327
|
|
312
328
|
POLICY_STATUS_COMPLETED = 'Completed'.freeze
|
313
329
|
|
@@ -315,23 +331,12 @@ module JSS
|
|
315
331
|
|
316
332
|
POLICY_STATUS_PENDING = 'Pending'.freeze
|
317
333
|
|
318
|
-
COMMAND_STATUS_COMPLETED = :completed
|
319
|
-
|
320
|
-
COMMAND_STATUS_PENDING = :pending
|
321
|
-
|
322
|
-
COMMAND_STATUS_FAILED = :failed
|
323
|
-
|
324
|
-
APP_STORE_APP_STATUS_INSTALLED = :installed
|
325
|
-
|
326
|
-
APP_STORE_APP_STATUS_PENDING = :pending
|
327
|
-
|
328
|
-
APP_STORE_APP_STATUS_FAILED = :failed
|
329
|
-
|
330
334
|
# the object type for this object in
|
331
335
|
# the object history table.
|
332
336
|
# See {APIObject#add_object_history_entry}
|
333
337
|
OBJECT_HISTORY_OBJECT_TYPE = 1
|
334
338
|
|
339
|
+
|
335
340
|
# Class Methods
|
336
341
|
#####################################
|
337
342
|
|
@@ -458,191 +463,56 @@ module JSS
|
|
458
463
|
all(refresh, api: api).select { |d| d[:model] =~ /^macpro/i }
|
459
464
|
end
|
460
465
|
|
461
|
-
#
|
462
|
-
# instantiation.
|
466
|
+
# Send an MDM command to one or more managed computers by id or name
|
463
467
|
#
|
464
|
-
# @param ident [Integer,String] An identifier (id, name, serialnumber,
|
465
|
-
# macadress or udid) of the computer for which to retrieve Application Usage
|
466
468
|
#
|
467
|
-
# @param
|
469
|
+
# @param targets[String,Integer,Array<String,Integer>]
|
470
|
+
# the name or id of the computer to receive the command, or
|
471
|
+
# an array of such names or ids, or a comma-separated string
|
472
|
+
# of them.
|
473
|
+
# @param command[Symbol] the command to send, one of the keys
|
474
|
+
# of COMPUTER_MDM_COMMANDS
|
468
475
|
#
|
469
|
-
# @param
|
476
|
+
# @param passcode[String] some commands require a 6-character passcode
|
470
477
|
#
|
471
478
|
# @param api[JSS::APIConnection] an API connection to use for the query.
|
472
479
|
# Defaults to the corrently active API. See {JSS::APIConnection}
|
473
480
|
#
|
474
|
-
# @return [
|
475
|
-
#
|
481
|
+
# @return [String] The uuid of the MDM command sent, if applicable
|
482
|
+
# (blank pushes do not generate uuids)
|
476
483
|
#
|
477
|
-
|
478
|
-
|
479
|
-
#
|
480
|
-
# Each item in the array is a hash of data about the app.
|
481
|
-
# Those hash keys are:
|
482
|
-
# :name => String, the name of the app
|
483
|
-
# :version => String ,the version of the app
|
484
|
-
# :foreground => Integer, the minutes it was in the foreground
|
485
|
-
# :open => Integer, the minutes it was running.
|
486
|
-
#
|
487
|
-
def self.application_usage(ident, start_date, end_date = nil, api: JSS.api)
|
488
|
-
id = valid_id ident, api: api
|
489
|
-
raise "No computer matches identifier: #{ident}" unless id
|
490
|
-
end_date ||= start_date
|
491
|
-
start_date = Time.parse start_date if start_date.is_a? String
|
492
|
-
end_date = Time.parse end_date if end_date.is_a? String
|
493
|
-
unless ([start_date.class, end_date.class] - APPLICATION_USAGE_DATE_CLASSES).empty?
|
494
|
-
raise JSS::InvalidDataError, 'Invalid Start or End Date'
|
495
|
-
end
|
496
|
-
start_date = start_date.strftime APPLICATION_USAGE_DATE_FMT
|
497
|
-
end_date = end_date.strftime APPLICATION_USAGE_DATE_FMT
|
498
|
-
data = api.get_rsrc(APPLICATION_USAGE_RSRC + "/id/#{id}/#{start_date}_#{end_date}")
|
499
|
-
parsed_data = {}
|
500
|
-
data[APPLICATION_USAGE_KEY].each do |day_hash|
|
501
|
-
date = Date.parse day_hash[:date]
|
502
|
-
parsed_data[date] = day_hash[:apps]
|
503
|
-
end
|
504
|
-
parsed_data
|
505
|
-
end # app usage
|
484
|
+
def self.send_mdm_command(targets, command, passcode = nil, api: JSS.api)
|
485
|
+
raise JSS::NoSuchItemError, "Unknown command '#{command}'" unless COMPUTER_MDM_COMMANDS.keys.include? command
|
506
486
|
|
507
|
-
|
508
|
-
|
509
|
-
#
|
510
|
-
# Without specifying a subset:, the entire dataset is returned as a hash of
|
511
|
-
# arrays, one per subset
|
512
|
-
#
|
513
|
-
# If a subset is given then only that array is returned, and it contains
|
514
|
-
# hashes with data about each item (usually :name and :id)
|
515
|
-
#
|
516
|
-
# If the only: param is provided with a subset, it is used as a hash-key to
|
517
|
-
# map the array to just those values, so subset: :smart_groups, only: :name
|
518
|
-
# will return an array of names of smartgroups that contain the computer.
|
519
|
-
#
|
520
|
-
# @param ident [Integer,String] An identifier (id, name, serialnumber,
|
521
|
-
# macadress or udid) of the computer for which to retrieve Application Usage
|
522
|
-
#
|
523
|
-
# @param subset[Symbol] Fetch only a subset of data, as an array.
|
524
|
-
# must be one of the symbols in MGMT_DATA_SUBSETS
|
525
|
-
#
|
526
|
-
# @param only[Symbol] When fetching a subset, only return one value
|
527
|
-
# per item in the array. meaningless without a subset.
|
528
|
-
#
|
529
|
-
# @param api[JSS::APIConnection] an API connection to use for the query.
|
530
|
-
# Defaults to the corrently active API. See {JSS::APIConnection}
|
531
|
-
#
|
532
|
-
# @return [Hash] Without a subset:, a hash of all subsets, each of which is
|
533
|
-
# an Array
|
534
|
-
#
|
535
|
-
# @return [Array] With a subset:, an array of items in that subset, possibly
|
536
|
-
# limited to just certain values with only:
|
537
|
-
#
|
538
|
-
def self.management_data(ident, subset: nil, only: nil, api: JSS.api)
|
539
|
-
id = valid_id ident, api: api
|
540
|
-
raise "No computer matches identifier: #{ident}" unless id
|
541
|
-
if subset
|
542
|
-
management_data_subset id, subset: subset, only: only, api: api
|
543
|
-
else
|
544
|
-
full_management_data id, api: api
|
545
|
-
end
|
546
|
-
end
|
547
|
-
|
548
|
-
# The full set of management data for a given computer.
|
549
|
-
# This private method is called by self.management_data, q.v.
|
550
|
-
#
|
551
|
-
def self.full_management_data(id, api: JSS.api)
|
552
|
-
mgmt_rsrc = MGMT_DATA_RSRC + "/id/#{id}"
|
553
|
-
api.get_rsrc(mgmt_rsrc)[MGMT_DATA_KEY]
|
554
|
-
end
|
555
|
-
private_class_method :full_management_data
|
556
|
-
|
557
|
-
# A subset of management data for a given computer.
|
558
|
-
# This private method is called by self.management_data, q.v.
|
559
|
-
#
|
560
|
-
def self.management_data_subset(id, subset: nil, only: nil, api: JSS.api)
|
561
|
-
raise "Subset must be one of :#{MGMT_DATA_SUBSETS.join ', :'}" unless MGMT_DATA_SUBSETS.include? subset
|
562
|
-
subset_rsrc = MGMT_DATA_RSRC + "/id/#{id}/subset/#{subset}"
|
563
|
-
subset_data = api.get_rsrc(subset_rsrc)[MGMT_DATA_KEY]
|
564
|
-
return subset_data unless only
|
565
|
-
subset_data.map { |d| d[only] }
|
566
|
-
end
|
567
|
-
private_class_method :management_data_subset
|
487
|
+
command = COMPUTER_MDM_COMMANDS[command]
|
488
|
+
cmd_rsrc = "#{COMPUTER_MDM_RSRC}/#{command}"
|
568
489
|
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
# See {JSS::Computer::HISTORY_INCONSISTENT_SUBSETS} for details
|
575
|
-
#
|
576
|
-
# @param ident [Integer,String] An identifier (id, name, serialnumber,
|
577
|
-
# macadress or udid) of the computer for which to retrieve Application Usage
|
578
|
-
#
|
579
|
-
# @param subset[Symbol] the subset to return, rather than full history.
|
580
|
-
#
|
581
|
-
# @param api[JSS::APIConnection] an API connection to use for the query.
|
582
|
-
# Defaults to the corrently active API. See {JSS::APIConnection}
|
583
|
-
#
|
584
|
-
# @return [Hash] The full history.
|
585
|
-
#
|
586
|
-
# @return [Array] The requested subset.
|
587
|
-
#
|
588
|
-
def self.history(ident, subset: nil, api: JSS.api)
|
589
|
-
id = valid_id ident, api: api
|
590
|
-
raise JSS::NoSuchItemError, "No Computer matches identifier: #{ident}" unless id
|
591
|
-
|
592
|
-
if subset
|
593
|
-
history_subset id, subset: subset, api: api
|
594
|
-
else
|
595
|
-
full_history id, api: api
|
490
|
+
if COMPUTER_MDM_COMMANDS_NEEDING_PASSCODE.include? command
|
491
|
+
unless passcode && passcode.is_a?(String) && passcode.length == 6
|
492
|
+
raise JSS::MissingDataError, "Command '#{command}' requires a 6-character passcode"
|
493
|
+
end
|
494
|
+
cmd_rsrc << "/passcode/#{passcode}"
|
596
495
|
end
|
597
|
-
end
|
598
496
|
|
599
|
-
|
600
|
-
# This private method is called by self.history, q.v.
|
601
|
-
#
|
602
|
-
def self.full_history(id, api: JSS.api)
|
603
|
-
hist = api.get_rsrc(HISTORY_RSRC + "/id/#{id}")[HISTORY_KEY]
|
497
|
+
targets = JSS.to_s_and_a(targets.to_s)[:arrayform] unless targets.is_a? Array
|
604
498
|
|
605
|
-
#
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
499
|
+
# make sure its an array of ids
|
500
|
+
targets.map! do |comp|
|
501
|
+
if all_ids(api: api).include? comp.to_i
|
502
|
+
comp.to_i
|
503
|
+
elsif all_names(api: api).include? comp
|
504
|
+
map_all_ids_to(:name, api: api).invert[comp]
|
505
|
+
else
|
506
|
+
raise JSS::NoSuchItemError, "No computer found matching '#{comp}'"
|
507
|
+
end # if
|
508
|
+
end # map!
|
612
509
|
|
613
|
-
|
614
|
-
# This private method is called by self.history, q.v.
|
615
|
-
#
|
616
|
-
def self.history_subset(id, subset: nil, api: JSS.api)
|
617
|
-
raise "Subset must be one of :#{HISTORY_SUBSETS.join ', :'}" unless HISTORY_SUBSETS.include? subset
|
618
|
-
subset_rsrc = HISTORY_RSRC + "/id/#{id}/subset/#{subset}"
|
619
|
-
subset_data = api.get_rsrc(subset_rsrc)[HISTORY_KEY][subset]
|
620
|
-
return standardize_history_subset(subset_data) if HISTORY_INCONSISTENT_SUBSETS.include? subset
|
621
|
-
subset_data
|
622
|
-
end
|
623
|
-
private_class_method :history_subset
|
510
|
+
cmd_rsrc << "/id/#{targets.join ','}"
|
624
511
|
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
#
|
629
|
-
# @param raw_data [Hash] The raw, inconsistent data structure from the API
|
630
|
-
#
|
631
|
-
# @return [Array] the same data restructured to match the rest of the
|
632
|
-
# computer history subsets: An Array of Hashes, one per event, each with
|
633
|
-
# a :status key.
|
634
|
-
#
|
635
|
-
def self.standardize_history_subset(raw_data)
|
636
|
-
consistency_array = []
|
637
|
-
raw_data.each do |status, events|
|
638
|
-
events.each do |evt|
|
639
|
-
evt[:status] = status
|
640
|
-
consistency_array << evt
|
641
|
-
end # cmd_events.each
|
642
|
-
end # raw_hist[:commands].each
|
643
|
-
consistency_array
|
644
|
-
end
|
645
|
-
private_class_method :standardize_history_subset
|
512
|
+
result = api.post_rsrc cmd_rsrc, nil
|
513
|
+
result =~ %r{<command_uuid>(.*)</command_uuid>}
|
514
|
+
Regexp.last_match(1)
|
515
|
+
end # send mdm command
|
646
516
|
|
647
517
|
|
648
518
|
# Attributes
|
@@ -970,173 +840,239 @@ module JSS
|
|
970
840
|
|
971
841
|
# Get application usage data for this computer
|
972
842
|
# for a given date range.
|
973
|
-
#
|
843
|
+
#
|
844
|
+
# TODO: Make this a class method so we can retrieve it without
|
845
|
+
# instantiating the Computer.
|
846
|
+
#
|
847
|
+
# @param start_date [String,Date,DateTime,Time]
|
848
|
+
#
|
849
|
+
# @param end_date [String,Date,DateTime,Time] Defaults to start_date
|
850
|
+
#
|
851
|
+
# @return [Hash{Date=>Array<Hash>}] For each day in the range, an Array
|
852
|
+
# with one Hash per application used. The hash keys are:
|
853
|
+
# :name => String, the name of the app
|
854
|
+
# :version => String ,the version of the app
|
855
|
+
# :foreground => Integer, the minutes it was in the foreground
|
856
|
+
# :open => Integer, the minutes it was running.
|
974
857
|
#
|
975
858
|
def application_usage(start_date, end_date = nil)
|
976
|
-
|
859
|
+
end_date ||= start_date
|
860
|
+
start_date = Time.parse start_date if start_date.is_a? String
|
861
|
+
end_date = Time.parse end_date if end_date.is_a? String
|
862
|
+
unless ([start_date.class, end_date.class] - APPLICATION_USAGE_DATE_CLASSES).empty?
|
863
|
+
raise JSS::InvalidDataError, 'Invalid Start or End Date'
|
864
|
+
end
|
865
|
+
start_date = start_date.strftime APPLICATION_USAGE_DATE_FMT
|
866
|
+
end_date = end_date.strftime APPLICATION_USAGE_DATE_FMT
|
867
|
+
data = @api.get_rsrc(APPLICATION_USAGE_RSRC + "/id/#{@id}/#{start_date}_#{end_date}")
|
868
|
+
parsed_data = {}
|
869
|
+
data[APPLICATION_USAGE_KEY].each do |day_hash|
|
870
|
+
date = Date.parse day_hash[:date]
|
871
|
+
parsed_data[date] = day_hash[:apps]
|
872
|
+
end
|
873
|
+
parsed_data
|
977
874
|
end # app usage
|
978
875
|
|
979
|
-
# The 'computer management' data for this computer
|
876
|
+
# The 'computer management' data for this computer, looked up on the fly.
|
877
|
+
#
|
878
|
+
# Without specifying a subset:, the entire dataset is returned as a hash of
|
879
|
+
# arrays, one per subset
|
880
|
+
# If a subset is given then only that array is returned, and it contains
|
881
|
+
# hashes with data about each item (usually :name and :id)
|
882
|
+
#
|
883
|
+
# If the only: param is provided with a subset, it is used as a hash-key to
|
884
|
+
# map the array to just those values, so subset: :smart_groups, only: :name
|
885
|
+
# will return an array of names of smartgroups that contain this computer.
|
886
|
+
#
|
887
|
+
# TODO: Make this a class method so we can retrieve it without
|
888
|
+
# instantiating the Computer.
|
889
|
+
#
|
890
|
+
# @param subset[Symbol] Fetch only a subset of data, as an array.
|
891
|
+
# must be one of the symbols in MGMT_DATA_SUBSETS
|
980
892
|
#
|
981
|
-
#
|
893
|
+
# @param only[Symbol] When fetching a subset, only return one value
|
894
|
+
# per item in the array. meaningless without a subset.
|
982
895
|
#
|
983
|
-
#
|
896
|
+
# @param refresh[Boolean] should the data be re-cached from the API?
|
984
897
|
#
|
985
|
-
|
986
|
-
|
987
|
-
|
898
|
+
# @return [Hash] Without a subset:, a hash of all subsets, each of which is
|
899
|
+
# an Array
|
900
|
+
#
|
901
|
+
# @return [Array] With a subset:, an array of items in that subset.
|
902
|
+
#
|
903
|
+
def management_data(subset: nil, only: nil, refresh: false)
|
904
|
+
@management_data ||= {}
|
905
|
+
if subset
|
906
|
+
management_data_subset(subset: subset, only: only, refresh: refresh)
|
907
|
+
else
|
908
|
+
full_management_data refresh
|
909
|
+
end
|
988
910
|
end
|
989
911
|
|
912
|
+
def full_management_data(refresh = false)
|
913
|
+
@management_data[:full] = nil if refresh
|
914
|
+
return @management_data[:full] if @management_data[:full]
|
915
|
+
mgmt_rsrc = MGMT_DATA_RSRC + "/id/#{@id}"
|
916
|
+
@management_data[:full] = @api.get_rsrc(mgmt_rsrc)[MGMT_DATA_KEY]
|
917
|
+
@management_data[:full]
|
918
|
+
end
|
919
|
+
private :full_management_data
|
920
|
+
|
921
|
+
def management_data_subset(subset: nil, only: nil, refresh: false)
|
922
|
+
raise "Subset must be one of :#{MGMT_DATA_SUBSETS.join ', :'}" unless MGMT_DATA_SUBSETS.include? subset
|
923
|
+
@management_data[subset] = nil if refresh
|
924
|
+
return @management_data[subset] if @management_data[subset]
|
925
|
+
subset_rsrc = MGMT_DATA_RSRC + "/id/#{@id}/subset/#{subset}"
|
926
|
+
@management_data[subset] = @api.get_rsrc(subset_rsrc)[MGMT_DATA_KEY]
|
927
|
+
return @management_data[subset] unless only
|
928
|
+
@management_data[subset].map { |d| d[only] }
|
929
|
+
end
|
930
|
+
private :management_data_subset
|
931
|
+
|
990
932
|
# A shortcut for 'management_data subset: :smart_groups'
|
991
933
|
#
|
992
|
-
def smart_groups(only: nil)
|
993
|
-
management_data subset: :smart_groups, only: only
|
934
|
+
def smart_groups(only: nil, refresh: false)
|
935
|
+
management_data subset: :smart_groups, only: only, refresh: refresh
|
994
936
|
end
|
995
937
|
|
996
938
|
# A shortcut for 'management_data subset: :static_groups'
|
997
939
|
#
|
998
|
-
def static_groups(only: nil)
|
999
|
-
management_data subset: :static_groups, only: only
|
940
|
+
def static_groups(only: nil, refresh: false)
|
941
|
+
management_data subset: :static_groups, only: only, refresh: refresh
|
1000
942
|
end
|
1001
943
|
|
1002
944
|
# A shortcut for 'management_data subset: :policies'
|
1003
945
|
#
|
1004
|
-
def policies(only: nil)
|
1005
|
-
management_data subset: :policies, only: only
|
946
|
+
def policies(only: nil, refresh: false)
|
947
|
+
management_data subset: :policies, only: only, refresh: refresh
|
1006
948
|
end
|
1007
949
|
|
1008
950
|
# A shortcut for 'management_data subset: :os_x_configuration_profiles'
|
1009
951
|
#
|
1010
|
-
def configuration_profiles(only: nil)
|
1011
|
-
management_data subset: :os_x_configuration_profiles, only: only
|
952
|
+
def configuration_profiles(only: nil, refresh: false)
|
953
|
+
management_data subset: :os_x_configuration_profiles, only: only, refresh: refresh
|
1012
954
|
end
|
1013
955
|
|
1014
956
|
# A shortcut for 'management_data subset: :ebooks'
|
1015
957
|
#
|
1016
|
-
def ebooks(only: nil)
|
958
|
+
def ebooks(only: nil, refresh: false)
|
1017
959
|
management_data subset: :ebooks, only: only, refresh: refresh
|
1018
960
|
end
|
1019
961
|
|
1020
962
|
# A shortcut for 'management_data subset: :mac_app_store_apps'
|
1021
963
|
#
|
1022
|
-
def app_store_apps(only: nil)
|
1023
|
-
management_data subset: :mac_app_store_apps, only: only
|
964
|
+
def app_store_apps(only: nil, refresh: false)
|
965
|
+
management_data subset: :mac_app_store_apps, only: only, refresh: refresh
|
1024
966
|
end
|
1025
967
|
|
1026
968
|
# A shortcut for 'management_data subset: :restricted_software'
|
1027
969
|
#
|
1028
|
-
def restricted_software(only: nil)
|
1029
|
-
management_data subset: :restricted_software, only: only
|
970
|
+
def restricted_software(only: nil, refresh: false)
|
971
|
+
management_data subset: :restricted_software, only: only, refresh: refresh
|
1030
972
|
end
|
1031
973
|
|
1032
974
|
# A shortcut for 'management_data subset: :patch_reporting_software_titles'
|
1033
975
|
#
|
1034
|
-
def patch_titles(only: nil)
|
1035
|
-
management_data subset: :patch_reporting_software_titles, only: only
|
976
|
+
def patch_titles(only: nil, refresh: false)
|
977
|
+
management_data subset: :patch_reporting_software_titles, only: only, refresh: refresh
|
1036
978
|
end
|
1037
979
|
|
1038
|
-
# Return this computer's
|
1039
|
-
# WARNING
|
980
|
+
# Return this computer's history.
|
981
|
+
# WARNING! Its huge, better to use a subset a
|
982
|
+
# nd one of the shortcut methods.
|
983
|
+
#
|
984
|
+
# TODO: Make this a class method so we can retrieve it without
|
985
|
+
# instantiating the Computer.
|
1040
986
|
#
|
1041
|
-
#
|
987
|
+
# @param subset[Symbol] the subset to return, rather than full history.
|
988
|
+
#
|
989
|
+
# @param refresh[Boolean] should we re-cache the data from the API?
|
1042
990
|
#
|
1043
|
-
#
|
991
|
+
# @return [Hash] The full history
|
1044
992
|
#
|
1045
|
-
#
|
993
|
+
# @return [Array] The history subset requested
|
1046
994
|
#
|
1047
|
-
def history(subset: nil)
|
1048
|
-
|
995
|
+
def history(subset: nil, refresh: false)
|
996
|
+
@history ||= {}
|
997
|
+
if subset
|
998
|
+
history_subset(subset: subset, refresh: refresh)
|
999
|
+
else
|
1000
|
+
full_history refresh
|
1001
|
+
end
|
1002
|
+
end
|
1003
|
+
|
1004
|
+
def full_history(refresh = false)
|
1005
|
+
@history[:full] = nil if refresh
|
1006
|
+
return @history[:full] if @history[:full]
|
1007
|
+
history_rsrc = HISTORY_RSRC + "/id/#{@id}"
|
1008
|
+
@history[:full] = @api.get_rsrc(history_rsrc)[HISTORY_KEY]
|
1009
|
+
@history[:full]
|
1010
|
+
end
|
1011
|
+
private :full_history
|
1012
|
+
|
1013
|
+
def history_subset(subset: nil, refresh: false)
|
1014
|
+
raise "Subset must be one of :#{HISTORY_SUBSETS.join ', :'}" unless HISTORY_SUBSETS.include? subset
|
1015
|
+
@history[subset] = nil if refresh
|
1016
|
+
return @history[subset] if @history[subset]
|
1017
|
+
subset_rsrc = HISTORY_RSRC + "/id/#{@id}/subset/#{subset}"
|
1018
|
+
@history[subset] = @api.get_rsrc(subset_rsrc)[HISTORY_KEY]
|
1019
|
+
@history[subset]
|
1049
1020
|
end
|
1021
|
+
private :history_subset
|
1050
1022
|
|
1051
1023
|
# Shortcut for history(:computer_usage_logs)
|
1052
|
-
def usage_logs
|
1053
|
-
history
|
1024
|
+
def usage_logs(refresh = false)
|
1025
|
+
history(subset: :computer_usage_logs, refresh: refresh)
|
1054
1026
|
end
|
1055
1027
|
|
1056
1028
|
# Shortcut for history(:audits)
|
1057
|
-
def audits
|
1058
|
-
history
|
1029
|
+
def audits(refresh = false)
|
1030
|
+
history(subset: :audits, refresh: refresh)
|
1059
1031
|
end
|
1060
1032
|
|
1061
1033
|
# Shortcut for history(:policy_logs)
|
1062
|
-
def policy_logs
|
1063
|
-
history
|
1034
|
+
def policy_logs(refresh = false)
|
1035
|
+
history(subset: :policy_logs, refresh: refresh)
|
1064
1036
|
end
|
1065
1037
|
|
1066
1038
|
# Shortcut for history(:policy_logs), but just the completed policies
|
1067
|
-
def completed_policies
|
1068
|
-
policy_logs.select { |pl| pl[:status] == POLICY_STATUS_COMPLETED }
|
1039
|
+
def completed_policies(refresh = false)
|
1040
|
+
policy_logs(refresh).select { |pl| pl[:status] == POLICY_STATUS_COMPLETED }
|
1069
1041
|
end
|
1070
1042
|
|
1071
1043
|
# Shortcut for history(:policy_logs), but just the failes policies
|
1072
|
-
def failed_policies
|
1073
|
-
|
1044
|
+
def failed_policies(refresh = false)
|
1045
|
+
policy_log(refresh).select { |pl| pl[:status] == POLICY_STATUS_FAILED }
|
1074
1046
|
end
|
1075
1047
|
|
1076
1048
|
# Shortcut for history(:casper_remote_logs)
|
1077
|
-
def casper_remote_logs
|
1078
|
-
history
|
1049
|
+
def casper_remote_logs(refresh = false)
|
1050
|
+
history(subset: :casper_remote_logs, refresh: refresh)
|
1079
1051
|
end
|
1080
1052
|
|
1081
1053
|
# Shortcut for history(:screen_sharing_logs)
|
1082
|
-
def screen_sharing_logs
|
1083
|
-
history
|
1054
|
+
def screen_sharing_logs(refresh = false)
|
1055
|
+
history(subset: :screen_sharing_logs, refresh: refresh)
|
1084
1056
|
end
|
1085
1057
|
|
1086
1058
|
# Shortcut for history(:casper_imaging_logs)
|
1087
|
-
def casper_imaging_logs
|
1088
|
-
history
|
1059
|
+
def casper_imaging_logs(refresh = false)
|
1060
|
+
history(subset: :casper_imaging_logs, refresh: refresh)
|
1089
1061
|
end
|
1090
1062
|
|
1091
1063
|
# Shortcut for history(:commands)
|
1092
|
-
def commands
|
1093
|
-
history
|
1094
|
-
end
|
1095
|
-
|
1096
|
-
# Shortcut for history(:commands) but just the completed commands
|
1097
|
-
#
|
1098
|
-
def completed_commands
|
1099
|
-
commands.select { |cmd| cmd[:status] == COMMAND_STATUS_COMPLETED }
|
1100
|
-
end
|
1101
|
-
|
1102
|
-
# Shortcut for history(:commands) but just the pending commands
|
1103
|
-
#
|
1104
|
-
def pending_commands
|
1105
|
-
commands.select { |cmd| cmd[:status] == COMMAND_STATUS_PENDING }
|
1106
|
-
end
|
1107
|
-
|
1108
|
-
# Shortcut for history(:commands) but just the failed commands
|
1109
|
-
#
|
1110
|
-
def failed_commands
|
1111
|
-
commands.select { |cmd| cmd[:status] == COMMAND_STATUS_FAILED }
|
1064
|
+
def commands(refresh = false)
|
1065
|
+
history(subset: :commands, refresh: refresh)
|
1112
1066
|
end
|
1113
1067
|
|
1114
1068
|
# Shortcut for history(:user_location)
|
1115
|
-
def user_location_history
|
1116
|
-
history
|
1069
|
+
def user_location_history(refresh = false)
|
1070
|
+
history(subset: :user_location, refresh: refresh)
|
1117
1071
|
end
|
1118
1072
|
|
1119
1073
|
# Shortcut for history(:mac_app_store_applications)
|
1120
|
-
def app_store_app_history
|
1121
|
-
history
|
1122
|
-
end
|
1123
|
-
|
1124
|
-
# Shortcut for history(:mac_app_store_applications) but just the installed apps
|
1125
|
-
#
|
1126
|
-
def installed_app_store_apps
|
1127
|
-
app_store_app_history.select { |app| app[:status] == APP_STORE_APP_STATUS_INSTALLED }
|
1128
|
-
end
|
1129
|
-
|
1130
|
-
# Shortcut for history(:mac_app_store_applications) but just the pending apps
|
1131
|
-
#
|
1132
|
-
def pending_app_store_apps
|
1133
|
-
app_store_app_history.select { |app| app[:status] == APP_STORE_APP_STATUS_PENDING }
|
1134
|
-
end
|
1135
|
-
|
1136
|
-
# Shortcut for history(:mac_app_store_applications) but just the failed apps
|
1137
|
-
#
|
1138
|
-
def failed_app_store_apps
|
1139
|
-
app_store_app_history.select { |app| app[:status] == APP_STORE_APP_STATUS_FAILED }
|
1074
|
+
def app_store_app_history(refresh = false)
|
1075
|
+
history(subset: :mac_app_store_applications, refresh: refresh)
|
1140
1076
|
end
|
1141
1077
|
|
1142
1078
|
# Set or unset management acct and password for this computer
|
@@ -1241,9 +1177,10 @@ module JSS
|
|
1241
1177
|
# @return [void]
|
1242
1178
|
#
|
1243
1179
|
def update
|
1244
|
-
|
1180
|
+
id = super
|
1181
|
+
remove_mdm_profile if mdm_capable && managed? && @unmange_at_update
|
1245
1182
|
@unmange_at_update = false
|
1246
|
-
|
1183
|
+
id
|
1247
1184
|
end
|
1248
1185
|
|
1249
1186
|
# Delete this computer from the JSS
|
@@ -1291,6 +1228,47 @@ module JSS
|
|
1291
1228
|
@software = nil
|
1292
1229
|
end # delete
|
1293
1230
|
|
1231
|
+
# Send a blank_push MDM command
|
1232
|
+
#
|
1233
|
+
# See JSS::Computer.send_mdm_command
|
1234
|
+
#
|
1235
|
+
def blank_push
|
1236
|
+
self.class.send_mdm_command @id, :blank_push, api: @api
|
1237
|
+
end
|
1238
|
+
alias noop blank_push
|
1239
|
+
alias send_blank_push blank_push
|
1240
|
+
|
1241
|
+
# Send a device_lock MDM command
|
1242
|
+
#
|
1243
|
+
# See JSS::Computer.send_mdm_command
|
1244
|
+
#
|
1245
|
+
def device_lock(passcode)
|
1246
|
+
self.class.send_mdm_command @id, :device_lock, passcode, api: @api
|
1247
|
+
end
|
1248
|
+
alias lock device_lock
|
1249
|
+
alias lock_device device_lock
|
1250
|
+
|
1251
|
+
# Send an erase_device MDM command
|
1252
|
+
#
|
1253
|
+
# See JSS::Computer.send_mdm_command
|
1254
|
+
#
|
1255
|
+
def erase_device(passcode)
|
1256
|
+
self.class.send_mdm_command @id, :erase_device, passcode, api: @api
|
1257
|
+
end
|
1258
|
+
alias erase erase_device
|
1259
|
+
alias wipe erase_device
|
1260
|
+
|
1261
|
+
# Remove MDM management profile without
|
1262
|
+
# un-enrolling from the JSS or
|
1263
|
+
# resetting the JSS management acct.
|
1264
|
+
#
|
1265
|
+
# To do those things as well, see {#make_unmanaged}
|
1266
|
+
#
|
1267
|
+
# See JSS::Computer.send_mdm_command
|
1268
|
+
#
|
1269
|
+
def remove_mdm_profile
|
1270
|
+
self.class.send_mdm_command @id, :unmanage_device, api: @api
|
1271
|
+
end
|
1294
1272
|
|
1295
1273
|
# aliases
|
1296
1274
|
alias alt_macaddress alt_mac_address
|
@@ -1336,14 +1314,12 @@ module JSS
|
|
1336
1314
|
rmgmt.add_element('management_username').text = @management_username
|
1337
1315
|
rmgmt.add_element('management_password').text = @management_password if @management_password
|
1338
1316
|
|
1339
|
-
computer << ext_attr_xml
|
1317
|
+
computer << ext_attr_xml if @changed_eas && !@changed_eas.empty?
|
1340
1318
|
|
1341
1319
|
computer << location_xml if has_location?
|
1342
1320
|
|
1343
1321
|
computer << purchasing_xml if has_purchasing?
|
1344
1322
|
|
1345
|
-
add_site_to_xml(doc)
|
1346
|
-
|
1347
1323
|
doc.to_s
|
1348
1324
|
end # rest_xml
|
1349
1325
|
|