ruby-jss 0.10.2a5 → 0.10.2
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.
- 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
|
|