ruby-jss 1.2.10 → 1.5.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.
- checksums.yaml +4 -4
- data/CHANGES.md +208 -1
- data/lib/jamf.rb +18 -16
- data/lib/jamf/api/base_classes/collection_resource.rb +613 -0
- data/lib/jamf/api/{abstract_classes → base_classes}/json_object.rb +110 -102
- data/lib/jamf/api/{abstract_classes → base_classes}/prestage.rb +56 -31
- data/lib/jamf/api/{abstract_classes → base_classes}/resource.rb +10 -6
- data/lib/jamf/api/{abstract_classes → base_classes}/singleton_resource.rb +4 -3
- data/lib/jamf/api/connection.rb +20 -12
- data/lib/jamf/api/connection/api_error.rb +8 -8
- data/lib/jamf/api/connection/token.rb +36 -15
- data/lib/jamf/api/json_objects/device_enrollment_device.rb +14 -7
- data/lib/jamf/api/json_objects/{location.rb → device_enrollment_device_sync_state.rb} +27 -41
- data/lib/jamf/api/json_objects/device_enrollment_sync_status.rb +1 -1
- data/lib/jamf/api/json_objects/{attachment.rb → locale.rb} +14 -23
- data/lib/jamf/api/json_objects/md_prestage_name.rb +1 -1
- data/lib/jamf/api/json_objects/md_prestage_names.rb +2 -2
- data/lib/jamf/api/json_objects/md_prestage_skip_setup_items.rb +50 -1
- data/lib/jamf/api/json_objects/prestage_assignment.rb +2 -2
- data/lib/jamf/api/json_objects/prestage_location.rb +3 -3
- data/lib/jamf/api/json_objects/prestage_purchasing_data.rb +7 -7
- data/lib/jamf/api/json_objects/prestage_scope.rb +1 -1
- data/lib/jamf/api/{resources/collection_resources → json_objects}/time_zone.rb +9 -23
- data/lib/jamf/api/mixins/{abstract.rb → base_class.rb} +34 -16
- data/lib/jamf/api/mixins/bulk_deletable.rb +27 -6
- data/lib/jamf/api/mixins/change_log.rb +201 -51
- data/lib/jamf/api/{resources/collection_resources/extension_attribute.rb → mixins/filterable.rb} +20 -14
- data/lib/jamf/api/mixins/pageable.rb +208 -0
- data/lib/jamf/api/{json_objects/installed_application.rb → mixins/sortable.rb} +33 -33
- data/lib/jamf/api/resources/collection_resources/building.rb +16 -9
- data/lib/jamf/api/resources/collection_resources/category.rb +5 -4
- data/lib/jamf/api/resources/collection_resources/computer_prestage.rb +12 -5
- data/lib/jamf/api/resources/collection_resources/department.rb +1 -3
- data/lib/jamf/api/resources/collection_resources/device_enrollment.rb +13 -13
- data/lib/jamf/api/resources/collection_resources/inventory_preload_record.rb +11 -3
- data/lib/jamf/api/resources/collection_resources/mobile_device_prestage.rb +25 -23
- data/lib/jamf/api/resources/collection_resources/script.rb +61 -25
- data/lib/jamf/api/resources/singleton_resources/app_store_country_codes.rb +15 -5
- data/lib/jamf/api/resources/singleton_resources/locales.rb +155 -0
- data/lib/jamf/api/resources/singleton_resources/time_zones.rb +213 -0
- data/lib/jamf/configuration.rb +7 -9
- data/lib/jamf/ruby_extensions.rb +1 -0
- data/lib/jamf/ruby_extensions/array.rb +1 -1
- data/lib/jamf/ruby_extensions/array/utils.rb +3 -3
- data/lib/jamf/{api/resources/collection_resources/computer.rb → ruby_extensions/dig.rb} +22 -19
- data/lib/jamf/validate.rb +63 -24
- data/lib/jamf/version.rb +1 -1
- data/lib/jss.rb +4 -1
- data/lib/jss/api_connection.rb +111 -433
- data/lib/jss/api_object.rb +16 -13
- data/lib/jss/api_object/advanced_search.rb +27 -26
- data/lib/jss/api_object/app_store_country_codes.rb +298 -0
- data/lib/jss/api_object/categorizable.rb +1 -1
- data/lib/jss/api_object/computer.rb +13 -0
- data/lib/jss/api_object/configuration_profile.rb +60 -4
- data/lib/jss/api_object/directory_binding.rb +273 -0
- data/lib/jss/api_object/directory_binding_type.rb +96 -0
- data/lib/jss/api_object/directory_binding_type/active_directory.rb +539 -0
- data/lib/jss/api_object/directory_binding_type/admitmac.rb +594 -0
- data/lib/jss/api_object/directory_binding_type/centrify.rb +226 -0
- data/lib/jss/api_object/directory_binding_type/open_directory.rb +178 -0
- data/lib/jss/api_object/directory_binding_type/powerbroker_identity_services.rb +73 -0
- data/lib/jss/api_object/disk_encryption_configurations.rb +114 -0
- data/lib/jss/api_object/distribution_point.rb +97 -37
- data/lib/jss/api_object/dock_item.rb +143 -0
- data/lib/jss/api_object/ebook.rb +1 -2
- data/lib/jss/api_object/extendable.rb +1 -1
- data/lib/jss/api_object/extension_attribute.rb +4 -3
- data/lib/jss/api_object/group.rb +33 -2
- data/lib/jss/api_object/mac_application.rb +107 -8
- data/lib/jss/api_object/mobile_device_application.rb +12 -0
- data/lib/jss/api_object/network_segment.rb +195 -70
- data/lib/jss/api_object/package.rb +105 -40
- data/lib/jss/api_object/patch_source.rb +10 -9
- data/lib/jss/api_object/policy.rb +596 -32
- data/lib/jss/api_object/printer.rb +446 -0
- data/lib/jss/api_object/scopable.rb +10 -15
- data/lib/jss/api_object/scopable/scope.rb +371 -55
- data/lib/jss/api_object/self_servable.rb +17 -9
- data/lib/jss/api_object/uploadable.rb +1 -1
- data/lib/jss/api_object/user.rb +42 -1
- data/lib/jss/api_object/vpp_account.rb +209 -0
- data/lib/jss/api_object/vppable.rb +169 -13
- data/lib/jss/composer.rb +1 -1
- data/lib/jss/exceptions.rb +3 -0
- data/lib/jss/server.rb +15 -0
- data/lib/jss/utility.rb +143 -52
- data/lib/jss/validate.rb +53 -10
- data/lib/jss/version.rb +1 -1
- metadata +56 -61
- data/lib/jamf/api/abstract_classes/advanced_search.rb +0 -86
- data/lib/jamf/api/abstract_classes/collection_resource.rb +0 -433
- data/lib/jamf/api/abstract_classes/generic_reference.rb +0 -145
- data/lib/jamf/api/abstract_classes/prestage_skip_setup_items.rb +0 -126
- data/lib/jamf/api/json_objects/account_prefs.rb +0 -79
- data/lib/jamf/api/json_objects/android_details.rb +0 -139
- data/lib/jamf/api/json_objects/appletv_details.rb +0 -110
- data/lib/jamf/api/json_objects/cellular_network.rb +0 -151
- data/lib/jamf/api/json_objects/computer_prestage_skip_setup_items.rb +0 -67
- data/lib/jamf/api/json_objects/criterion.rb +0 -152
- data/lib/jamf/api/json_objects/extension_attribute_value.rb +0 -128
- data/lib/jamf/api/json_objects/installed_certificate.rb +0 -53
- data/lib/jamf/api/json_objects/installed_configuration_profile.rb +0 -67
- data/lib/jamf/api/json_objects/installed_ebook.rb +0 -58
- data/lib/jamf/api/json_objects/installed_provisioning_profile.rb +0 -59
- data/lib/jamf/api/json_objects/ios_details.rb +0 -244
- data/lib/jamf/api/json_objects/mobile_device_details.rb +0 -219
- data/lib/jamf/api/json_objects/mobile_device_security.rb +0 -101
- data/lib/jamf/api/json_objects/purchasing_data.rb +0 -125
- data/lib/jamf/api/mixins/locatable.rb +0 -124
- data/lib/jamf/api/mixins/referable.rb +0 -92
- data/lib/jamf/api/resources/collection_resources/account.rb +0 -163
- data/lib/jamf/api/resources/collection_resources/advanced_mobile_device_search.rb +0 -52
- data/lib/jamf/api/resources/collection_resources/advanced_user_search.rb +0 -52
- data/lib/jamf/api/resources/collection_resources/mobile_device.rb +0 -315
- data/lib/jamf/api/resources/collection_resources/site.rb +0 -77
- data/lib/jamf/api/resources/singleton_resources/authorization.rb +0 -88
- data/lib/jamf/api/resources/singleton_resources/client_checkin_settings.rb +0 -139
- data/lib/jamf/api/resources/singleton_resources/reenrollment_settings.rb +0 -95
|
@@ -121,9 +121,31 @@ module JSS
|
|
|
121
121
|
# @return [Array<String>] The current file names
|
|
122
122
|
#
|
|
123
123
|
def self.all_filenames(api: JSS.api)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
124
|
+
all_filenames_by(:id, api: api).values
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# A Hash of all dist-point filenames used by all JSS packages, keyed by
|
|
128
|
+
# package name or id
|
|
129
|
+
#
|
|
130
|
+
# Slow cuz we have to instantiate every pkg
|
|
131
|
+
#
|
|
132
|
+
# @param key[Symbol] either :id, or :name
|
|
133
|
+
#
|
|
134
|
+
# @param api[JSS::APIConnection] an API connection to use
|
|
135
|
+
# Defaults to the corrently active API. See {JSS::APIConnection}
|
|
136
|
+
#
|
|
137
|
+
# @return [Hash{Ingeter,String => String}] The current file names by key
|
|
138
|
+
#
|
|
139
|
+
def self.all_filenames_by(key, api: JSS.api)
|
|
140
|
+
raise ArgumentError, 'key must be :id or :name' unless %i[id name].include? key
|
|
141
|
+
|
|
142
|
+
files_in_use = {}
|
|
143
|
+
all_ids(:refresh).each do |pkg_id|
|
|
144
|
+
pkg = fetch id: pkg_id, api: api
|
|
145
|
+
files_in_use[pkg.send(key)] = pkg.filename
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
files_in_use
|
|
127
149
|
end
|
|
128
150
|
|
|
129
151
|
# An array of String filenames for all files DIST_POINT_PKGS_FOLDER
|
|
@@ -140,14 +162,17 @@ module JSS
|
|
|
140
162
|
# @param api[JSS::APIConnection] an API connection to use
|
|
141
163
|
# Defaults to the corrently active API. See {JSS::APIConnection}
|
|
142
164
|
#
|
|
165
|
+
# @param dist_point [String,Integer] the name or id of the distribution
|
|
166
|
+
# point to use. Defaults to the Master Dist. Point
|
|
167
|
+
#
|
|
143
168
|
# @return [Array<String>] The orphaned files
|
|
144
169
|
#
|
|
145
|
-
def self.orphaned_files(ro_pw, unmount = true, api: JSS.api)
|
|
146
|
-
|
|
147
|
-
pkgs_dir =
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
170
|
+
def self.orphaned_files(ro_pw, unmount = true, api: JSS.api, dist_point: nil)
|
|
171
|
+
dp = fetch_dist_point(dist_point, api: api)
|
|
172
|
+
pkgs_dir = dp.mount(ro_pw, :ro) + DIST_POINT_PKGS_FOLDER
|
|
173
|
+
files_on_dp = pkgs_dir.children.map { |f| f.basename.to_s }
|
|
174
|
+
dp.unmount if unmount
|
|
175
|
+
files_on_dp - all_filenames(api: api)
|
|
151
176
|
end
|
|
152
177
|
|
|
153
178
|
# An array of String filenames for all filenames in any
|
|
@@ -164,14 +189,18 @@ module JSS
|
|
|
164
189
|
# @param api[JSS::APIConnection] an API connection to use
|
|
165
190
|
# Defaults to the corrently active API. See {JSS::APIConnection}
|
|
166
191
|
#
|
|
192
|
+
# @param dist_point [String,Integer] the name or id of the distribution
|
|
193
|
+
# point to use. Defaults to the Master Dist. Point
|
|
194
|
+
#
|
|
195
|
+
#
|
|
167
196
|
# @return [Array<String>] The orphaned files
|
|
168
197
|
#
|
|
169
|
-
def self.missing_files(ro_pw, unmount = true, api: JSS.api)
|
|
170
|
-
|
|
171
|
-
pkgs_dir =
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
all_filenames(api: api) -
|
|
198
|
+
def self.missing_files(ro_pw, unmount = true, api: JSS.api, dist_point: nil)
|
|
199
|
+
dp = fetch_dist_point(dist_point, api: api)
|
|
200
|
+
pkgs_dir = dp.mount(ro_pw, :ro) + DIST_POINT_PKGS_FOLDER
|
|
201
|
+
files_on_dp = pkgs_dir.children.map { |f| f.basename.to_s }
|
|
202
|
+
dp.unmount if unmount
|
|
203
|
+
all_filenames(api: api) - files_on_dp
|
|
175
204
|
end
|
|
176
205
|
|
|
177
206
|
# Given a file path, and hash type, generate the checksum for an arbitrary
|
|
@@ -189,6 +218,18 @@ module JSS
|
|
|
189
218
|
CHECKSUM_HASH_TYPES[type].file(filepath).hexdigest
|
|
190
219
|
end
|
|
191
220
|
|
|
221
|
+
# @param dist_point [String,Integer] the name or id of the distribution
|
|
222
|
+
# point to use. Defaults to the Master Dist. Point
|
|
223
|
+
#
|
|
224
|
+
# @return [JSS::DistributionPoint]
|
|
225
|
+
def self.fetch_dist_point(dist_point, api: JSS.api)
|
|
226
|
+
if dist_point
|
|
227
|
+
JSS::DistributionPoint.fetch dist_point, api: api
|
|
228
|
+
else
|
|
229
|
+
JSS::DistributionPoint.master_distribution_point api: api
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
192
233
|
# Attributes
|
|
193
234
|
#####################################
|
|
194
235
|
|
|
@@ -324,7 +365,7 @@ module JSS
|
|
|
324
365
|
new_val = nil if new_val == ''
|
|
325
366
|
new_val ||= @name
|
|
326
367
|
return nil if new_val == @filename
|
|
327
|
-
|
|
368
|
+
|
|
328
369
|
@filename = new_val
|
|
329
370
|
@need_to_update = true
|
|
330
371
|
end
|
|
@@ -590,13 +631,17 @@ module JSS
|
|
|
590
631
|
# @param chksum [String] the constants CHECKSUM_HASH_TYPE_SHA512 or
|
|
591
632
|
# CHECKSUM_HASH_TYPE_MD5. Anything else means don't calc.
|
|
592
633
|
#
|
|
634
|
+
# @param dist_point [String,Integer] the name or id of the distribution
|
|
635
|
+
# point to use. Defaults to the Master Dist. Point
|
|
636
|
+
#
|
|
593
637
|
# @return [void]
|
|
594
638
|
#
|
|
595
|
-
def upload_master_file(local_file_path, rw_pw, unmount = true, chksum: DEFAULT_CHECKSUM_HASH_TYPE )
|
|
639
|
+
def upload_master_file(local_file_path, rw_pw, unmount = true, chksum: DEFAULT_CHECKSUM_HASH_TYPE, dist_point: nil)
|
|
596
640
|
raise JSS::NoSuchItemError, 'Please create this package in the JSS before uploading it.' unless @in_jss
|
|
597
641
|
|
|
598
|
-
|
|
599
|
-
|
|
642
|
+
dp = self.class.fetch_dist_point(dist_point, api: @api)
|
|
643
|
+
|
|
644
|
+
destination = dp.mount(rw_pw, :rw) + "#{DIST_POINT_PKGS_FOLDER}/#{@filename}"
|
|
600
645
|
|
|
601
646
|
local_path = Pathname.new local_file_path
|
|
602
647
|
raise JSS::NoSuchItemError, "Local file '#{@local_file}' doesn't exist" unless local_path.exist?
|
|
@@ -637,11 +682,11 @@ module JSS
|
|
|
637
682
|
|
|
638
683
|
if CHECKSUM_HASH_TYPES.keys.include? chksum
|
|
639
684
|
@checksum_type = chksum
|
|
640
|
-
@checksum = calculate_checksum local_file: local_path, type: chksum, unmount: false
|
|
685
|
+
@checksum = calculate_checksum local_file: local_path, type: chksum, unmount: false, dist_point: dist_point
|
|
641
686
|
@need_to_update = true
|
|
642
687
|
end
|
|
643
688
|
update if @need_to_update
|
|
644
|
-
|
|
689
|
+
dp.unmount if unmount
|
|
645
690
|
end # upload master file
|
|
646
691
|
|
|
647
692
|
# Using either a local file, or the file on the master dist. point,
|
|
@@ -658,7 +703,7 @@ module JSS
|
|
|
658
703
|
#
|
|
659
704
|
# @return [void]
|
|
660
705
|
#
|
|
661
|
-
def reset_checksum(type: nil, local_file: nil, rw_pw: nil, ro_pw: nil, unmount: true)
|
|
706
|
+
def reset_checksum(type: nil, local_file: nil, rw_pw: nil, ro_pw: nil, unmount: true, dist_point: nil )
|
|
662
707
|
type ||= DEFAULT_CHECKSUM_HASH_TYPE
|
|
663
708
|
|
|
664
709
|
new_checksum = calculate_checksum(
|
|
@@ -666,7 +711,8 @@ module JSS
|
|
|
666
711
|
local_file: local_file,
|
|
667
712
|
rw_pw: rw_pw,
|
|
668
713
|
ro_pw: ro_pw,
|
|
669
|
-
unmount: unmount
|
|
714
|
+
unmount: unmount,
|
|
715
|
+
dist_point: dist_point
|
|
670
716
|
)
|
|
671
717
|
return if @checksum == new_checksum
|
|
672
718
|
|
|
@@ -694,11 +740,14 @@ module JSS
|
|
|
694
740
|
# @param unmount [Boolean] Unmount the master dist point after using it.
|
|
695
741
|
# Only used if the dist point is mounted. default: true
|
|
696
742
|
#
|
|
743
|
+
# @param dist_point [String,Integer] the name or id of the distribution
|
|
744
|
+
# point to use. Defaults to the Master Dist. Point
|
|
745
|
+
#
|
|
697
746
|
# @return [String] The calculated checksum
|
|
698
747
|
#
|
|
699
|
-
def calculate_checksum(type: nil, local_file: nil, rw_pw: nil, ro_pw: nil, unmount: true )
|
|
748
|
+
def calculate_checksum(type: nil, local_file: nil, rw_pw: nil, ro_pw: nil, unmount: true, dist_point: nil )
|
|
700
749
|
type ||= DEFAULT_CHECKSUM_HASH_TYPE
|
|
701
|
-
|
|
750
|
+
dp = self.class.fetch_dist_point(dist_point, api: @api)
|
|
702
751
|
|
|
703
752
|
if local_file
|
|
704
753
|
file_to_calc = local_file
|
|
@@ -712,10 +761,10 @@ module JSS
|
|
|
712
761
|
else
|
|
713
762
|
raise ArgumentError, 'Either rw_pw: or ro_pw: must be provided'
|
|
714
763
|
end
|
|
715
|
-
file_to_calc =
|
|
764
|
+
file_to_calc = dp.mount(dppw, mnt) + "#{DIST_POINT_PKGS_FOLDER}/#{@filename}"
|
|
716
765
|
end
|
|
717
766
|
new_checksum = self.class.calculate_checksum(file_to_calc, type)
|
|
718
|
-
|
|
767
|
+
dp.unmount if unmount && dp.mounted?
|
|
719
768
|
new_checksum
|
|
720
769
|
end
|
|
721
770
|
|
|
@@ -734,17 +783,21 @@ module JSS
|
|
|
734
783
|
# @param unmount [Boolean] Unmount the master dist point after using it.
|
|
735
784
|
# Only used if the dist point is mounted. default: true
|
|
736
785
|
#
|
|
786
|
+
# @param dist_point [String,Integer] the name or id of the distribution
|
|
787
|
+
# point to use. Defaults to the Master Dist. Point
|
|
788
|
+
#
|
|
737
789
|
# @return [Boolean] false if there is no checksum for this pkg, otherwise,
|
|
738
790
|
# does the calculated checksum match the one stored for the pkg?
|
|
739
791
|
#
|
|
740
|
-
def checksum_valid?(local_file: nil, rw_pw: nil, ro_pw: nil, unmount: true)
|
|
792
|
+
def checksum_valid?(local_file: nil, rw_pw: nil, ro_pw: nil, unmount: true, dist_point: nil )
|
|
741
793
|
return false unless @checksum
|
|
742
794
|
new_checksum = calculate_checksum(
|
|
743
795
|
type: @checksum_type,
|
|
744
796
|
local_file: local_file,
|
|
745
797
|
rw_pw: rw_pw,
|
|
746
798
|
ro_pw: ro_pw,
|
|
747
|
-
unmount: unmount
|
|
799
|
+
unmount: unmount,
|
|
800
|
+
dist_point: dist_point
|
|
748
801
|
)
|
|
749
802
|
new_checksum == @checksum
|
|
750
803
|
end
|
|
@@ -760,12 +813,16 @@ module JSS
|
|
|
760
813
|
# @param rw_pw[String,Symbol] the password for the read/write account on the master Distribution Point,
|
|
761
814
|
# or :prompt, or :stdin# where # is the line of stdin containing the password See {JSS::DistributionPoint#mount}
|
|
762
815
|
#
|
|
816
|
+
# @param dist_point [String,Integer] the name or id of the distribution
|
|
817
|
+
# point to use. Defaults to the Master Dist. Point
|
|
818
|
+
#
|
|
763
819
|
# @return [nil]
|
|
764
820
|
#
|
|
765
|
-
def update_master_filename(old_file_name, new_file_name, rw_pw, unmount = true)
|
|
821
|
+
def update_master_filename(old_file_name, new_file_name, rw_pw, unmount = true, dist_point: nil)
|
|
766
822
|
raise JSS::NoSuchItemError, "#{old_file_name} does not exist in the jss." unless @in_jss
|
|
767
|
-
|
|
768
|
-
|
|
823
|
+
dp = self.class.fetch_dist_point(dist_point, api: @api)
|
|
824
|
+
|
|
825
|
+
pkgs_dir = dp.mount(rw_pw, :rw) + DIST_POINT_PKGS_FOLDER.to_s
|
|
769
826
|
old_file = pkgs_dir + old_file_name
|
|
770
827
|
raise JSS::NoSuchItemError, "File not found on the master distribution point at #{DIST_POINT_PKGS_FOLDER}/#{old_file_name}." unless \
|
|
771
828
|
old_file.exist?
|
|
@@ -775,7 +832,7 @@ module JSS
|
|
|
775
832
|
new_file = pkgs_dir + (new_file_name + old_file.extname) if new_file.extname.empty?
|
|
776
833
|
|
|
777
834
|
old_file.rename new_file
|
|
778
|
-
|
|
835
|
+
dp.unmount if unmount
|
|
779
836
|
nil
|
|
780
837
|
end # update_master_filename
|
|
781
838
|
|
|
@@ -791,18 +848,21 @@ module JSS
|
|
|
791
848
|
#
|
|
792
849
|
# @param unmount[Boolean] whether or not ot unount the distribution point when finished.
|
|
793
850
|
#
|
|
851
|
+
# @param dist_point [String,Integer] the name or id of the distribution
|
|
852
|
+
# point to use. Defaults to the Master Dist. Point
|
|
853
|
+
#
|
|
794
854
|
# @return [Boolean] was the file deleted?
|
|
795
855
|
#
|
|
796
|
-
def delete_master_file(rw_pw, unmount = true)
|
|
797
|
-
|
|
798
|
-
file =
|
|
856
|
+
def delete_master_file(rw_pw, unmount = true, dist_point: nil)
|
|
857
|
+
dp = self.class.fetch_dist_point(dist_point, api: @api)
|
|
858
|
+
file = dp.mount(rw_pw, :rw) + "#{DIST_POINT_PKGS_FOLDER}/#{@filename}"
|
|
799
859
|
if file.exist?
|
|
800
860
|
file.delete
|
|
801
861
|
did_it = true
|
|
802
862
|
else
|
|
803
863
|
did_it = false
|
|
804
864
|
end # if exists
|
|
805
|
-
|
|
865
|
+
dp.unmount if unmount
|
|
806
866
|
did_it
|
|
807
867
|
end # delete master file
|
|
808
868
|
|
|
@@ -816,9 +876,13 @@ module JSS
|
|
|
816
876
|
#
|
|
817
877
|
# @param unmount[Boolean] whether or not ot unount the distribution point when finished.
|
|
818
878
|
#
|
|
819
|
-
|
|
879
|
+
# @param dist_point [String,Integer] the name or id of the distribution
|
|
880
|
+
# point to use. Defaults to the Master Dist. Point
|
|
881
|
+
#
|
|
882
|
+
# @return [void]
|
|
883
|
+
def delete(delete_file: false, rw_pw: nil, unmount: true, dist_point: nil)
|
|
820
884
|
super()
|
|
821
|
-
delete_master_file(rw_pw, unmount) if delete_file
|
|
885
|
+
delete_master_file(rw_pw, unmount, dist_point: dist_point) if delete_file
|
|
822
886
|
end
|
|
823
887
|
|
|
824
888
|
# Install this package via the jamf binary 'install' command from the
|
|
@@ -885,7 +949,7 @@ module JSS
|
|
|
885
949
|
|
|
886
950
|
# we'll re-add the filename below if needed.
|
|
887
951
|
src_path = args[:alt_download_url].chomp "/#{@filename}"
|
|
888
|
-
|
|
952
|
+
using_http = true
|
|
889
953
|
# use our appropriate dist. point for download
|
|
890
954
|
else
|
|
891
955
|
mdp = JSS::DistributionPoint.my_distribution_point api: @api
|
|
@@ -1021,6 +1085,7 @@ module JSS
|
|
|
1021
1085
|
|
|
1022
1086
|
private
|
|
1023
1087
|
|
|
1088
|
+
|
|
1024
1089
|
# Return the REST XML for this pkg, with the current values,
|
|
1025
1090
|
# for saving or updating
|
|
1026
1091
|
#
|
|
@@ -120,30 +120,31 @@ module JSS
|
|
|
120
120
|
|
|
121
121
|
# Fetch either an internal or external patch source
|
|
122
122
|
#
|
|
123
|
-
# BUG: there's an API bug: fetching a non-existent
|
|
123
|
+
# BUG: there's an API bug: fetching a non-existent
|
|
124
124
|
# which is why we rescue internal server errors.
|
|
125
125
|
#
|
|
126
126
|
# @see APIObject.fetch
|
|
127
127
|
#
|
|
128
|
-
def self.fetch(
|
|
128
|
+
def self.fetch(searchterm = nil, **args)
|
|
129
129
|
if self == JSS::PatchSource
|
|
130
130
|
begin
|
|
131
|
-
fetched = JSS::PatchInternalSource.fetch
|
|
132
|
-
rescue
|
|
131
|
+
fetched = JSS::PatchInternalSource.fetch searchterm, **args
|
|
132
|
+
rescue
|
|
133
133
|
fetched = nil
|
|
134
134
|
end
|
|
135
135
|
unless fetched
|
|
136
136
|
begin
|
|
137
|
-
fetched = JSS::PatchExternalSource.fetch
|
|
138
|
-
rescue
|
|
137
|
+
fetched = JSS::PatchExternalSource.fetch searchterm, **args
|
|
138
|
+
rescue
|
|
139
139
|
raise JSS::NoSuchItemError, 'No matching PatchSource found'
|
|
140
140
|
end
|
|
141
141
|
end
|
|
142
142
|
return fetched
|
|
143
143
|
end # if self == JSS::PatchSource
|
|
144
|
+
|
|
144
145
|
begin
|
|
145
|
-
super
|
|
146
|
-
rescue
|
|
146
|
+
super searchterm, **args
|
|
147
|
+
rescue JSS::NoSuchItemError
|
|
147
148
|
raise JSS::NoSuchItemError, "No matching #{self::RSRC_OBJECT_KEY} found"
|
|
148
149
|
end
|
|
149
150
|
end
|
|
@@ -211,7 +212,7 @@ module JSS
|
|
|
211
212
|
begin
|
|
212
213
|
# TODO: remove this and adjust parsing when jamf fixes the JSON
|
|
213
214
|
raw = JSS::XMLWorkaround.data_via_xml(rsrc, AVAILABLE_TITLES_DATA_MAP, api)
|
|
214
|
-
rescue
|
|
215
|
+
rescue JSS::NoSuchItemError
|
|
215
216
|
return []
|
|
216
217
|
end
|
|
217
218
|
|
|
@@ -148,6 +148,12 @@ module JSS
|
|
|
148
148
|
monthly: 'Once every month'
|
|
149
149
|
}.freeze
|
|
150
150
|
|
|
151
|
+
RETRY_EVENTS = {
|
|
152
|
+
none: 'none',
|
|
153
|
+
checkin: 'check-in',
|
|
154
|
+
trigger: 'trigger'
|
|
155
|
+
}.freeze
|
|
156
|
+
|
|
151
157
|
RESTART_WHEN = {
|
|
152
158
|
if_pkg_requires: 'Restart if a package or update requires it',
|
|
153
159
|
now: 'Restart immediately',
|
|
@@ -174,7 +180,9 @@ module JSS
|
|
|
174
180
|
change_pw: 'specified',
|
|
175
181
|
generate_pw: 'random',
|
|
176
182
|
enable_fv2: 'fileVaultEnable',
|
|
177
|
-
disable_fv2: 'fileVaultDisable'
|
|
183
|
+
disable_fv2: 'fileVaultDisable',
|
|
184
|
+
reset_random: 'resetRandom',
|
|
185
|
+
reset_pw: 'reset'
|
|
178
186
|
}.freeze
|
|
179
187
|
|
|
180
188
|
PACKAGE_ACTIONS = {
|
|
@@ -191,6 +199,12 @@ module JSS
|
|
|
191
199
|
after: 'After'
|
|
192
200
|
}.freeze
|
|
193
201
|
|
|
202
|
+
DISK_ENCRYPTION_ACTIONS = {
|
|
203
|
+
apply: "apply",
|
|
204
|
+
remediate: "remediate",
|
|
205
|
+
none: "none"
|
|
206
|
+
}
|
|
207
|
+
|
|
194
208
|
PRINTER_ACTIONS = {
|
|
195
209
|
map: 'install',
|
|
196
210
|
unmap: 'uninstall'
|
|
@@ -249,14 +263,14 @@ module JSS
|
|
|
249
263
|
}.freeze
|
|
250
264
|
|
|
251
265
|
LOG_FLUSH_INTERVAL_PERIODS = {
|
|
252
|
-
day: '
|
|
253
|
-
days: '
|
|
254
|
-
week: '
|
|
255
|
-
weeks: '
|
|
256
|
-
month: '
|
|
257
|
-
months: '
|
|
258
|
-
year: '
|
|
259
|
-
years: '
|
|
266
|
+
day: 'Days',
|
|
267
|
+
days: 'Days',
|
|
268
|
+
week: 'Weeks',
|
|
269
|
+
weeks: 'Weeks',
|
|
270
|
+
month: 'Months',
|
|
271
|
+
months: 'Months',
|
|
272
|
+
year: 'Years',
|
|
273
|
+
years: 'Years'
|
|
260
274
|
}.freeze
|
|
261
275
|
|
|
262
276
|
# the object type for this object in
|
|
@@ -273,6 +287,83 @@ module JSS
|
|
|
273
287
|
# How is the category stored in the API data?
|
|
274
288
|
CATEGORY_DATA_TYPE = Hash
|
|
275
289
|
|
|
290
|
+
# Class Methods
|
|
291
|
+
######################
|
|
292
|
+
|
|
293
|
+
# Flush logs for a given policy older than some number of days, weeks,
|
|
294
|
+
# months or years, possibly limited to one or more computers.
|
|
295
|
+
#
|
|
296
|
+
# With no parameters, flushes all logs for the policy for all computers.
|
|
297
|
+
#
|
|
298
|
+
# NOTE: Currently the API doesn't have a way to flush only failed policies.
|
|
299
|
+
#
|
|
300
|
+
# WARNING: Log flushing can take a long time, and the API call doesnt return
|
|
301
|
+
# until its finished. The connection timeout will be temporarily raised to
|
|
302
|
+
# 30 minutes, unless it's already higher.
|
|
303
|
+
#
|
|
304
|
+
# @param policy[Integer,String] The id or name of the policy to flush
|
|
305
|
+
#
|
|
306
|
+
# @param older_than[Integer] 0, 1, 2, 3, or 6
|
|
307
|
+
#
|
|
308
|
+
# @param period[Symbol] :days, :weeks, :months, or :years
|
|
309
|
+
#
|
|
310
|
+
# @param computers[Array<Integer,String>] Identifiers of the target computers
|
|
311
|
+
# either ids, names, SNs, macaddrs, or UDIDs. If omitted, flushes logs for
|
|
312
|
+
# all computers
|
|
313
|
+
#
|
|
314
|
+
# @param api [JSS::APIConnection] the API connection to use.
|
|
315
|
+
#
|
|
316
|
+
# @return [void]
|
|
317
|
+
#
|
|
318
|
+
def self.flush_logs(policy, older_than: 0, period: :days, computers: [], api: JSS.api)
|
|
319
|
+
orig_timeout = api.cnx.options.timeout
|
|
320
|
+
pol_id = valid_id policy
|
|
321
|
+
raise JSS::NoSuchItemError, "No Policy identified by '#{policy}'." unless pol_id
|
|
322
|
+
|
|
323
|
+
older_than = LOG_FLUSH_INTERVAL_INTEGERS[older_than]
|
|
324
|
+
raise JSS::InvalidDataError, "older_than must be one of these integers: #{LOG_FLUSH_INTERVAL_INTEGERS.keys.join ', '}" unless older_than
|
|
325
|
+
|
|
326
|
+
period = LOG_FLUSH_INTERVAL_PERIODS[period]
|
|
327
|
+
raise JSS::InvalidDataError, "period must be one of these symbols: :#{LOG_FLUSH_INTERVAL_PERIODS.keys.join ', :'}" unless period
|
|
328
|
+
|
|
329
|
+
computers = [computers] unless computers.is_a? Array
|
|
330
|
+
|
|
331
|
+
# log flushes can be really slow
|
|
332
|
+
api.timeout = 1800 unless orig_timeout > 1800
|
|
333
|
+
|
|
334
|
+
return api.delete_rsrc "#{LOG_FLUSH_RSRC}/policy/id/#{pol_id}/interval/#{older_than}+#{period}" if computers.empty?
|
|
335
|
+
|
|
336
|
+
flush_logs_for_specific_computers pol_id, older_than, period, computers, api
|
|
337
|
+
ensure
|
|
338
|
+
api.timeout = orig_timeout
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
# use an XML body in a DELETE request to flush logs for
|
|
342
|
+
# a list of computers - used by the flush_logs class method
|
|
343
|
+
def self.flush_logs_for_specific_computers(pol_id, older_than, period, computers, api)
|
|
344
|
+
# build the xml body for a DELETE request
|
|
345
|
+
xml_doc = REXML::Document.new JSS::APIConnection::XML_HEADER
|
|
346
|
+
lf = xml_doc.add_element 'logflush'
|
|
347
|
+
lf.add_element('log').text = 'policy'
|
|
348
|
+
lf.add_element('log_id').text = pol_id.to_s
|
|
349
|
+
lf.add_element('interval').text = "#{older_than} #{period}"
|
|
350
|
+
comps_elem = lf.add_element 'computers'
|
|
351
|
+
computers.each do |c|
|
|
352
|
+
id = JSS::Computer.valid_id c
|
|
353
|
+
next unless id
|
|
354
|
+
|
|
355
|
+
ce = comps_elem.add_element 'computer'
|
|
356
|
+
ce.add_element('id').text = id.to_s
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
# Do a DELETE request with a body.
|
|
360
|
+
api.cnx.delete(LOG_FLUSH_RSRC) do |req|
|
|
361
|
+
req.headers[JSS::APIConnection::HTTP_CONTENT_TYPE_HEADER] = JSS::APIConnection::MIME_XML
|
|
362
|
+
req.body = xml_doc.to_s
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
private_class_method :flush_logs_for_specific_computers
|
|
366
|
+
|
|
276
367
|
# Attributes
|
|
277
368
|
######################
|
|
278
369
|
|
|
@@ -541,6 +632,7 @@ module JSS
|
|
|
541
632
|
|
|
542
633
|
# @return [String] the message shown the user at policy end
|
|
543
634
|
attr_reader :user_message_finish
|
|
635
|
+
alias user_message_end user_message_finish
|
|
544
636
|
|
|
545
637
|
# @return [Hash]
|
|
546
638
|
#
|
|
@@ -604,7 +696,6 @@ module JSS
|
|
|
604
696
|
|
|
605
697
|
if @in_jss
|
|
606
698
|
gen = @init_data[:general]
|
|
607
|
-
@frequency = gen[:frequency]
|
|
608
699
|
@target_drive = gen[:target_drive]
|
|
609
700
|
@offline = gen[:offline]
|
|
610
701
|
@enabled = gen[:enabled]
|
|
@@ -620,6 +711,10 @@ module JSS
|
|
|
620
711
|
trigger_enrollment_complete: gen[:trigger_enrollment_complete],
|
|
621
712
|
trigger_other: gen[:trigger_other]
|
|
622
713
|
}
|
|
714
|
+
@frequency = gen[:frequency]
|
|
715
|
+
@retry_event = gen[:retry_event]
|
|
716
|
+
@retry_attempts = gen[:retry_attempts]
|
|
717
|
+
@notify_failed_retries = gen[:notify_on_each_failed_retry]
|
|
623
718
|
|
|
624
719
|
dtl = gen[:date_time_limitations]
|
|
625
720
|
|
|
@@ -670,6 +765,7 @@ module JSS
|
|
|
670
765
|
@disk_encryption = @init_data[:disk_encryption]
|
|
671
766
|
|
|
672
767
|
@printers = @init_data[:printers]
|
|
768
|
+
@printers.shift
|
|
673
769
|
|
|
674
770
|
# Not in jss yet
|
|
675
771
|
end
|
|
@@ -735,8 +831,93 @@ module JSS
|
|
|
735
831
|
# @return [void]
|
|
736
832
|
#
|
|
737
833
|
def frequency=(freq)
|
|
738
|
-
raise JSS::InvalidDataError, "New frequency must be one of :#{FREQUENCIES.keys.join ', :'}" unless FREQUENCIES.key?(freq)
|
|
739
|
-
|
|
834
|
+
raise JSS::InvalidDataError, "New frequency must be one of :#{FREQUENCIES.keys.join ', :'}" unless FREQUENCIES.key?(freq) || FREQUENCIES.value?(freq)
|
|
835
|
+
|
|
836
|
+
freq = freq.is_a?(Symbol) ? FREQUENCIES[freq] : freq
|
|
837
|
+
return if freq == @frequency
|
|
838
|
+
|
|
839
|
+
@frequency = freq
|
|
840
|
+
@need_to_update = true
|
|
841
|
+
end
|
|
842
|
+
|
|
843
|
+
# @return [String] The event that causes a policy retry
|
|
844
|
+
def retry_event
|
|
845
|
+
return RETRY_EVENTS[:none] unless FREQUENCIES[:once_per_computer] == @frequency
|
|
846
|
+
|
|
847
|
+
@retry_event
|
|
848
|
+
end
|
|
849
|
+
|
|
850
|
+
# Set the event that causes a retry if the policy fails.
|
|
851
|
+
# One of the ways to turn off policy retry is to set this to :none
|
|
852
|
+
# The other is to set the retry_attempts to 0
|
|
853
|
+
#
|
|
854
|
+
# @param [Symbol, String] A key or value from RETRY_EVENTS
|
|
855
|
+
# @return [void]
|
|
856
|
+
#
|
|
857
|
+
def retry_event=(evt)
|
|
858
|
+
validate_retry_opt
|
|
859
|
+
raise JSS::InvalidDataError, "Retry event must be one of :#{RETRY_EVENTS.keys.join ', :'}" unless RETRY_EVENTS.key?(evt) || RETRY_EVENTS.value?(evt)
|
|
860
|
+
|
|
861
|
+
evt = evt.is_a?(Symbol) ? RETRY_EVENTS[evt] : evt
|
|
862
|
+
return if evt == @retry_event
|
|
863
|
+
|
|
864
|
+
# if the event is not 'none' and attempts is <= 0,
|
|
865
|
+
# set events to 1, or the API won't accept it
|
|
866
|
+
unless evt == RETRY_EVENTS[:none]
|
|
867
|
+
@retry_attempts = 1 unless @retry_attempts.positive?
|
|
868
|
+
end
|
|
869
|
+
|
|
870
|
+
@retry_event = evt
|
|
871
|
+
@need_to_update = true
|
|
872
|
+
end
|
|
873
|
+
|
|
874
|
+
# @return [Integer] How many times wil the policy be retried if it fails.
|
|
875
|
+
# -1 means no retries, otherwise, an integer from 1 to 10
|
|
876
|
+
def retry_attempts
|
|
877
|
+
return 0 unless FREQUENCIES[:once_per_computer] == @frequency
|
|
878
|
+
|
|
879
|
+
@retry_attempts
|
|
880
|
+
end
|
|
881
|
+
|
|
882
|
+
# Set the number of times to retry if the policy fails.
|
|
883
|
+
# One of the ways to turn off policy retry is to set this to 0 or -1
|
|
884
|
+
# The other is to set retry_event to :none
|
|
885
|
+
#
|
|
886
|
+
# @param [Integer] From -1 to 10
|
|
887
|
+
# @return [void]
|
|
888
|
+
#
|
|
889
|
+
def retry_attempts=(int)
|
|
890
|
+
validate_retry_opt
|
|
891
|
+
raise JSS::InvalidDataError, 'Retry attempts must be an integer from 0-10' unless int.is_a?(Integer) && (-1..10).include?(int)
|
|
892
|
+
|
|
893
|
+
# if zero or -1, turn off retries
|
|
894
|
+
if int <= 0
|
|
895
|
+
@retry_event = RETRY_EVENTS[:none]
|
|
896
|
+
int = -1
|
|
897
|
+
end
|
|
898
|
+
return if @retry_attempts == int
|
|
899
|
+
|
|
900
|
+
@retry_attempts = int
|
|
901
|
+
@need_to_update = true
|
|
902
|
+
end
|
|
903
|
+
|
|
904
|
+
# @return [Boolean] Should admins be notified of failed retry attempts
|
|
905
|
+
def notify_failed_retries?
|
|
906
|
+
return false unless FREQUENCIES[:once_per_computer] == @frequency
|
|
907
|
+
|
|
908
|
+
@notify_failed_retries
|
|
909
|
+
end
|
|
910
|
+
alias notify_failed_retries notify_failed_retries?
|
|
911
|
+
alias notify_on_each_failed_retry notify_failed_retries?
|
|
912
|
+
|
|
913
|
+
# @param bool[Boolean] Should admins be notified of failed retry attempts
|
|
914
|
+
# @return [void]
|
|
915
|
+
def notify_failed_retries=(bool)
|
|
916
|
+
validate_retry_opt
|
|
917
|
+
bool = JSS::Validate.boolean bool
|
|
918
|
+
return if @notify_failed_retries == bool
|
|
919
|
+
|
|
920
|
+
@notify_failed_retries = bool
|
|
740
921
|
@need_to_update = true
|
|
741
922
|
end
|
|
742
923
|
|
|
@@ -914,6 +1095,30 @@ module JSS
|
|
|
914
1095
|
end
|
|
915
1096
|
alias message= reboot_message=
|
|
916
1097
|
|
|
1098
|
+
# Set User Start Message
|
|
1099
|
+
#
|
|
1100
|
+
# @param user_message[String] Text of User Message
|
|
1101
|
+
#
|
|
1102
|
+
# @return [void] description of returned object
|
|
1103
|
+
def user_message_start=(message)
|
|
1104
|
+
raise JSS::InvalidDataError, 'User message must be a String' unless message.is_a? String
|
|
1105
|
+
@user_message_start = message
|
|
1106
|
+
@need_to_update = true
|
|
1107
|
+
end
|
|
1108
|
+
|
|
1109
|
+
# Set User Finish Message
|
|
1110
|
+
#
|
|
1111
|
+
# @param user_message[String] Text of User Message
|
|
1112
|
+
#
|
|
1113
|
+
# @return [void] description of returned object
|
|
1114
|
+
def user_message_end=(message)
|
|
1115
|
+
raise JSS::InvalidDataError, 'User message must be a String' unless message.is_a? String
|
|
1116
|
+
@user_message_finish = message
|
|
1117
|
+
@need_to_update = true
|
|
1118
|
+
end
|
|
1119
|
+
|
|
1120
|
+
alias user_message_finish= user_message_end=
|
|
1121
|
+
|
|
917
1122
|
# Set Startup Disk
|
|
918
1123
|
# Only Supports 'Specify Local Startup Disk' at the moment
|
|
919
1124
|
#
|
|
@@ -1180,7 +1385,7 @@ module JSS
|
|
|
1180
1385
|
|
|
1181
1386
|
# Remove a package from this policy by name or id
|
|
1182
1387
|
#
|
|
1183
|
-
# @param
|
|
1388
|
+
# @param identifier [String,Integer] the name or id of the package to remove
|
|
1184
1389
|
#
|
|
1185
1390
|
# @return [Array, nil] the new packages array or nil if no change
|
|
1186
1391
|
#
|
|
@@ -1270,7 +1475,7 @@ module JSS
|
|
|
1270
1475
|
|
|
1271
1476
|
# Remove a script from this policy by name or id
|
|
1272
1477
|
#
|
|
1273
|
-
# @param
|
|
1478
|
+
# @param identifier [String,Integer] the name or id of the script to remove
|
|
1274
1479
|
#
|
|
1275
1480
|
# @return [Array, nil] the new scripts array or nil if no change
|
|
1276
1481
|
#
|
|
@@ -1292,6 +1497,49 @@ module JSS
|
|
|
1292
1497
|
@directory_bindings.map { |p| p[:name] }
|
|
1293
1498
|
end
|
|
1294
1499
|
|
|
1500
|
+
# Add a Directory Bidning to the list of directory_bindings handled by this policy.
|
|
1501
|
+
# If the directory binding already exists in the policy, nil is returned and
|
|
1502
|
+
# no changes are made.
|
|
1503
|
+
#
|
|
1504
|
+
# @param [String,Integer] identifier the name or id of the directory binding to add to this policy
|
|
1505
|
+
#
|
|
1506
|
+
# @param position [Symbol, Integer] where to add this directory binding among the list of
|
|
1507
|
+
# directory_bindings. Zero-based, :start and 0 are the same, as are :end and -1.
|
|
1508
|
+
# Defaults to :end
|
|
1509
|
+
#
|
|
1510
|
+
# @return [Array, nil] the new @directory_bindings array, nil if directory_binding was already in the policy
|
|
1511
|
+
#
|
|
1512
|
+
def add_directory_binding(identifier, **opts)
|
|
1513
|
+
id = validate_directory_binding_opts identifier, opts
|
|
1514
|
+
|
|
1515
|
+
return nil if @directory_bindings.map { |s| s[:id] }.include? id
|
|
1516
|
+
|
|
1517
|
+
name = JSS::DirectoryBinding.map_all_ids_to(:name, api: @api)[id]
|
|
1518
|
+
|
|
1519
|
+
directory_binding_data = {
|
|
1520
|
+
id: id,
|
|
1521
|
+
name: name
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
@directory_bindings.insert opts[:position], directory_binding_data
|
|
1525
|
+
|
|
1526
|
+
@need_to_update = true
|
|
1527
|
+
@directory_bindings
|
|
1528
|
+
end
|
|
1529
|
+
|
|
1530
|
+
|
|
1531
|
+
# Remove a directory binding from this policy by name or id
|
|
1532
|
+
#
|
|
1533
|
+
# @param identifier [String,Integer] the name or id of the directory binding to remove
|
|
1534
|
+
#
|
|
1535
|
+
# @return [Array, nil] the new directory bindings array or nil if no change
|
|
1536
|
+
#
|
|
1537
|
+
def remove_directory_binding(identifier)
|
|
1538
|
+
removed = @directory_bindings.delete_if { |s| s[:id] == identifier || s[:name] == identifier }
|
|
1539
|
+
@need_to_update = true if removed
|
|
1540
|
+
removed
|
|
1541
|
+
end
|
|
1542
|
+
|
|
1295
1543
|
###### Dock items
|
|
1296
1544
|
|
|
1297
1545
|
# @return [Array] the id's of the dock_items handled by the policy
|
|
@@ -1304,6 +1552,86 @@ module JSS
|
|
|
1304
1552
|
@dock_items.map { |p| p[:name] }
|
|
1305
1553
|
end
|
|
1306
1554
|
|
|
1555
|
+
|
|
1556
|
+
###### Printers
|
|
1557
|
+
|
|
1558
|
+
# Add a specific printer object to the policy.
|
|
1559
|
+
#
|
|
1560
|
+
# @author Tyler Morgan
|
|
1561
|
+
#
|
|
1562
|
+
# @param newvalue [String,Integer] The name or the id of the printer to be added to this policy.
|
|
1563
|
+
#
|
|
1564
|
+
# @param position [Symbol, Integer] where to add this printer object among the list of printer
|
|
1565
|
+
# objects. Zero-based, :start and 0 are the same, as are :end and -1.
|
|
1566
|
+
# Defaults to :end
|
|
1567
|
+
#
|
|
1568
|
+
# @param action [Symbol] One of the PRINTER_ACTIONS symbols. What you want done with the printer object upon policy execution.
|
|
1569
|
+
#
|
|
1570
|
+
# @param make_default [TrueClass,FalseClass] Should this printer object be set to default.
|
|
1571
|
+
# Defaults to false
|
|
1572
|
+
#
|
|
1573
|
+
# @return [String] The new printers array or nil if the printer was already in the policy
|
|
1574
|
+
def add_printer(identifier, **opts)
|
|
1575
|
+
id = validate_printer_opts identifier, opts
|
|
1576
|
+
|
|
1577
|
+
return nil if @printers.map { |p| p[:id] }.include? id
|
|
1578
|
+
|
|
1579
|
+
name = JSS::Printer.map_all_ids_to(:name, api: @api)[id]
|
|
1580
|
+
|
|
1581
|
+
printer_data = {
|
|
1582
|
+
id: id,
|
|
1583
|
+
name: name,
|
|
1584
|
+
action: PRINTER_ACTIONS[opts[:action]],
|
|
1585
|
+
make_default: opts[:make_default]
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
@printers.insert opts[:position], printer_data
|
|
1589
|
+
|
|
1590
|
+
@need_to_update = true
|
|
1591
|
+
@printers
|
|
1592
|
+
end
|
|
1593
|
+
|
|
1594
|
+
|
|
1595
|
+
# Remove a specific printer object from the policy.
|
|
1596
|
+
#
|
|
1597
|
+
# @author Tyler Morgan
|
|
1598
|
+
#
|
|
1599
|
+
# @param identifier [String,Integer] The name or id of the printer to be removed.
|
|
1600
|
+
#
|
|
1601
|
+
# @return [Array, nil] The new printers array or nil if no change.
|
|
1602
|
+
def remove_printer(identifier)
|
|
1603
|
+
removed = @printers.delete_if { |p| p[:id] == identifier || p[:name] == identifier }
|
|
1604
|
+
|
|
1605
|
+
@need_to_update = true
|
|
1606
|
+
removed
|
|
1607
|
+
end
|
|
1608
|
+
|
|
1609
|
+
# Add a dock item to the policy
|
|
1610
|
+
def add_dock_item(identifier, action)
|
|
1611
|
+
id = JSS::DockItem.valid_id identifier, api: @api
|
|
1612
|
+
|
|
1613
|
+
raise JSS::NoSuchItemError, "No Dock Item matches '#{identifier}'" unless id
|
|
1614
|
+
|
|
1615
|
+
raise JSS::InvalidDataError, "Action must be one of: :#{DOCK_ITEM_ACTIONS.keys.join ', :'}" unless DOCK_ITEM_ACTIONS.include? action
|
|
1616
|
+
|
|
1617
|
+
return nil if @dock_items.map { |d| d[:id] }.include? id
|
|
1618
|
+
|
|
1619
|
+
name = JSS::DockItem.map_all_ids_to(:name, api: @api)[id]
|
|
1620
|
+
|
|
1621
|
+
@dock_items << {id: id, name: name, action: DOCK_ITEM_ACTIONS[action]}
|
|
1622
|
+
|
|
1623
|
+
@need_to_update = true
|
|
1624
|
+
@dock_items
|
|
1625
|
+
end
|
|
1626
|
+
|
|
1627
|
+
# Remove a dock item from the policy
|
|
1628
|
+
def remove_dock_item(identifier)
|
|
1629
|
+
# TODO: Add validation against JSS::DockItem
|
|
1630
|
+
removed = @dock_items.delete_if { |d| d[:id] == identifier || d[:name] == identifier }
|
|
1631
|
+
@need_to_update = true if removed
|
|
1632
|
+
removed
|
|
1633
|
+
end
|
|
1634
|
+
|
|
1307
1635
|
# @return [Array] the id's of the printers handled by the policy
|
|
1308
1636
|
def printer_ids
|
|
1309
1637
|
begin
|
|
@@ -1312,7 +1640,7 @@ module JSS
|
|
|
1312
1640
|
return []
|
|
1313
1641
|
end
|
|
1314
1642
|
end
|
|
1315
|
-
|
|
1643
|
+
|
|
1316
1644
|
# @return [Array] the names of the printers handled by the policy
|
|
1317
1645
|
def printer_names
|
|
1318
1646
|
begin
|
|
@@ -1322,6 +1650,130 @@ module JSS
|
|
|
1322
1650
|
end
|
|
1323
1651
|
end
|
|
1324
1652
|
|
|
1653
|
+
|
|
1654
|
+
|
|
1655
|
+
###### Disk Encryption
|
|
1656
|
+
|
|
1657
|
+
# Sets the Disk Encryption application to "Remediate" and sets the remediation key type to individual.
|
|
1658
|
+
#
|
|
1659
|
+
# @author Tyler Morgan
|
|
1660
|
+
#
|
|
1661
|
+
# @return [Void]
|
|
1662
|
+
#
|
|
1663
|
+
def reissue_key()
|
|
1664
|
+
if @disk_encryption[:action] != DISK_ENCRYPTION_ACTIONS[:remediate]
|
|
1665
|
+
# Setting New Action
|
|
1666
|
+
hash = {
|
|
1667
|
+
action: DISK_ENCRYPTION_ACTIONS[:remediate],
|
|
1668
|
+
remediate_key_type: "Individual"
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
@disk_encryption = hash
|
|
1672
|
+
@need_to_update = true
|
|
1673
|
+
|
|
1674
|
+
else
|
|
1675
|
+
# Update
|
|
1676
|
+
return
|
|
1677
|
+
end
|
|
1678
|
+
|
|
1679
|
+
end
|
|
1680
|
+
|
|
1681
|
+
|
|
1682
|
+
# Sets the Disk Encryption application to "Apply" and sets the correct disk encryption configuration ID using either the name or id.
|
|
1683
|
+
#
|
|
1684
|
+
# @author Tyler Morgan
|
|
1685
|
+
#
|
|
1686
|
+
# @return [Void]
|
|
1687
|
+
#
|
|
1688
|
+
def apply_encryption_configuration(identifier)
|
|
1689
|
+
|
|
1690
|
+
id = JSS::DiskEncryptionConfiguration.valid_id identifier
|
|
1691
|
+
|
|
1692
|
+
return if id.nil?
|
|
1693
|
+
|
|
1694
|
+
hash = {
|
|
1695
|
+
action: DISK_ENCRYPTION_ACTIONS[:apply],
|
|
1696
|
+
disk_encryption_configuration_id: id,
|
|
1697
|
+
auth_restart: false
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
@disk_encryption = hash
|
|
1701
|
+
@need_to_update = true
|
|
1702
|
+
end
|
|
1703
|
+
|
|
1704
|
+
|
|
1705
|
+
# Removes the Disk Encryption settings associated with this specific policy.
|
|
1706
|
+
#
|
|
1707
|
+
# @author Tyler Morgan
|
|
1708
|
+
#
|
|
1709
|
+
# @return [Void]
|
|
1710
|
+
#
|
|
1711
|
+
def remove_encryption_configuration()
|
|
1712
|
+
hash = {
|
|
1713
|
+
action: DISK_ENCRYPTION_ACTIONS[:none]
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
@disk_encryption = hash
|
|
1717
|
+
@need_to_update = true
|
|
1718
|
+
end
|
|
1719
|
+
|
|
1720
|
+
# Interact with management account settings
|
|
1721
|
+
#
|
|
1722
|
+
# @param action [Key] one of the MGMT_ACCOUNT_ACTIONS keys
|
|
1723
|
+
#
|
|
1724
|
+
# @return The current specified management settings.
|
|
1725
|
+
#
|
|
1726
|
+
# Reference: https://developer.jamf.com/documentation#resources-with-passwords
|
|
1727
|
+
#
|
|
1728
|
+
def set_management_account(action, **opts)
|
|
1729
|
+
# TODO: Add proper error handling
|
|
1730
|
+
raise JSS::InvalidDataError, "Action must be one of: :#{MGMT_ACCOUNT_ACTIONS.keys.join ', :'}" unless MGMT_ACCOUNT_ACTIONS.include? action
|
|
1731
|
+
|
|
1732
|
+
management_data = {}
|
|
1733
|
+
|
|
1734
|
+
if action == :change_pw || action == :reset_pw
|
|
1735
|
+
raise JSS::MissingDataError, ":password must be provided when changing management account password" if opts[:password].nil?
|
|
1736
|
+
|
|
1737
|
+
management_data = {
|
|
1738
|
+
action: MGMT_ACCOUNT_ACTIONS[action],
|
|
1739
|
+
managed_password: opts[:password]
|
|
1740
|
+
}
|
|
1741
|
+
elsif action == :reset_random || action == :generate_pw
|
|
1742
|
+
raise JSS::MissingDataError, ":password_length must be provided when setting a random password" if opts[:password_length].nil?
|
|
1743
|
+
raise JSS::InvalidDataError, ":password_length must be an Integer" unless opts[:password_length].is_a? Integer
|
|
1744
|
+
|
|
1745
|
+
management_data = {
|
|
1746
|
+
action: MGMT_ACCOUNT_ACTIONS[action],
|
|
1747
|
+
managed_password_length: opts[:password_length]
|
|
1748
|
+
}
|
|
1749
|
+
else
|
|
1750
|
+
management_data = {
|
|
1751
|
+
action: MGMT_ACCOUNT_ACTIONS[action]
|
|
1752
|
+
}
|
|
1753
|
+
end
|
|
1754
|
+
|
|
1755
|
+
@management_account = management_data
|
|
1756
|
+
|
|
1757
|
+
@need_to_update = true
|
|
1758
|
+
|
|
1759
|
+
@management_account
|
|
1760
|
+
|
|
1761
|
+
end
|
|
1762
|
+
|
|
1763
|
+
# Check if management password matches provided password
|
|
1764
|
+
#
|
|
1765
|
+
# @param password[String] the password that is SHA256'ed to compare to the one from the API.
|
|
1766
|
+
#
|
|
1767
|
+
# @return [Boolean] The result of the comparison of the management password and provided text.
|
|
1768
|
+
#
|
|
1769
|
+
def verify_management_password(password)
|
|
1770
|
+
raise JSS::InvalidDataError, "Management password must be a string." unless password.is_a? String
|
|
1771
|
+
|
|
1772
|
+
raise JSS::UnsupportedError, "'#{@management_account[:action].to_s}' does not support management passwords." unless @management_account[:action] == MGMT_ACCOUNT_ACTIONS[:change_pw] || @management_account[:action] == MGMT_ACCOUNT_ACTIONS[:reset_pw]
|
|
1773
|
+
|
|
1774
|
+
return Digest::SHA256.hexdigest(password).to_s == @management_account[:managed_password_sha256].to_s
|
|
1775
|
+
end
|
|
1776
|
+
|
|
1325
1777
|
###### Actions
|
|
1326
1778
|
|
|
1327
1779
|
# Try to execute this policy on this machine.
|
|
@@ -1340,34 +1792,37 @@ module JSS
|
|
|
1340
1792
|
end
|
|
1341
1793
|
alias execute run
|
|
1342
1794
|
|
|
1343
|
-
# Flush
|
|
1344
|
-
# some number of days, weeks, months or years
|
|
1795
|
+
# Flush logs for this policy older than
|
|
1796
|
+
# some number of days, weeks, months or years, possibly limited to
|
|
1797
|
+
# one or more computers
|
|
1345
1798
|
#
|
|
1346
|
-
# With no parameters, flushes all logs
|
|
1799
|
+
# With no parameters, flushes all logs for all computers
|
|
1347
1800
|
#
|
|
1348
|
-
# NOTE: Currently the API doesn't have a way to
|
|
1349
|
-
#
|
|
1801
|
+
# NOTE: Currently the API doesn't have a way to flush only failed policies.
|
|
1802
|
+
#
|
|
1803
|
+
# WARNING: Log flushing can take a long time, and the API call doesnt return
|
|
1804
|
+
# until its finished. The connection timeout will be temporarily raised to
|
|
1805
|
+
# 30 minutes, unless it's already higher.
|
|
1350
1806
|
#
|
|
1351
1807
|
# @param older_than[Integer] 0, 1, 2, 3, or 6
|
|
1352
1808
|
#
|
|
1353
1809
|
# @param period[Symbol] :days, :weeks, :months, or :years
|
|
1354
1810
|
#
|
|
1811
|
+
# @param computers[Array<Integer,String>] Identifiers of the target computers
|
|
1812
|
+
# either ids, names, SNs, macaddrs, or UDIDs
|
|
1813
|
+
#
|
|
1355
1814
|
# @return [void]
|
|
1356
1815
|
#
|
|
1357
|
-
def flush_logs(older_than: 0, period: :days)
|
|
1816
|
+
def flush_logs(older_than: 0, period: :days, computers: [])
|
|
1358
1817
|
raise JSS::NoSuchItemError, "Policy doesn't exist in the JSS. Use #create first." unless @in_jss
|
|
1359
1818
|
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
interval = "#{LOG_FLUSH_INTERVAL_INTEGERS[older_than]}+#{LOG_FLUSH_INTERVAL_PERIODS[period]}"
|
|
1369
|
-
|
|
1370
|
-
@api.delete_rsrc "#{LOG_FLUSH_RSRC}/policy/id/#{@id}/interval/#{interval}"
|
|
1819
|
+
JSS::Policy.flush_logs(
|
|
1820
|
+
@id,
|
|
1821
|
+
older_than: older_than,
|
|
1822
|
+
period: period,
|
|
1823
|
+
computers: computers,
|
|
1824
|
+
api: @api
|
|
1825
|
+
)
|
|
1371
1826
|
end
|
|
1372
1827
|
|
|
1373
1828
|
# Private Instance Methods
|
|
@@ -1375,6 +1830,17 @@ module JSS
|
|
|
1375
1830
|
|
|
1376
1831
|
private
|
|
1377
1832
|
|
|
1833
|
+
# raise an error if a trying to set retry options when
|
|
1834
|
+
# frequency is not 'once per comptuer'
|
|
1835
|
+
#
|
|
1836
|
+
# @return [void]
|
|
1837
|
+
#
|
|
1838
|
+
def validate_retry_opt
|
|
1839
|
+
return if FREQUENCIES[:once_per_computer] == @frequency
|
|
1840
|
+
|
|
1841
|
+
raise JSS::UnsupportedError, 'Policy retry is only available when frequency is set to :once_per_computer'
|
|
1842
|
+
end
|
|
1843
|
+
|
|
1378
1844
|
# raise an error if a package being added isn't valid
|
|
1379
1845
|
#
|
|
1380
1846
|
# @see #add_package
|
|
@@ -1439,6 +1905,64 @@ module JSS
|
|
|
1439
1905
|
id
|
|
1440
1906
|
end
|
|
1441
1907
|
|
|
1908
|
+
# raise an error if the directory binding being added isn't valid
|
|
1909
|
+
#
|
|
1910
|
+
# @see #add_directory_binding
|
|
1911
|
+
#
|
|
1912
|
+
# @return [Integer, nil] the valid id for the package
|
|
1913
|
+
#
|
|
1914
|
+
def validate_directory_binding_opts(identifier, opts)
|
|
1915
|
+
opts[:position] ||= -1
|
|
1916
|
+
|
|
1917
|
+
opts[:position] =
|
|
1918
|
+
case opts[:position]
|
|
1919
|
+
when :start then 0
|
|
1920
|
+
when :end then -1
|
|
1921
|
+
else JSS::Validate.integer(opts[:position])
|
|
1922
|
+
end
|
|
1923
|
+
|
|
1924
|
+
# if the given position is past the end, set it to -1 (the end)
|
|
1925
|
+
opts[:position] = -1 if opts[:position] > @directory_bindings.size
|
|
1926
|
+
|
|
1927
|
+
id = JSS::DirectoryBinding.valid_id identifier, api: @api
|
|
1928
|
+
raise JSS::NoSuchItemError, "No directory binding matches '#{identifier}'" unless id
|
|
1929
|
+
id
|
|
1930
|
+
end
|
|
1931
|
+
|
|
1932
|
+
# Raises an error if the printer being added isn't valid, additionally checks the options and sets defaults where possible.
|
|
1933
|
+
#
|
|
1934
|
+
# @see #add_printer
|
|
1935
|
+
#
|
|
1936
|
+
# @return [Integer, nil] the valid id for the package
|
|
1937
|
+
#
|
|
1938
|
+
def validate_printer_opts(identifier, opts)
|
|
1939
|
+
opts[:position] ||= -1
|
|
1940
|
+
|
|
1941
|
+
opts[:position] =
|
|
1942
|
+
case opts[:position]
|
|
1943
|
+
when :start then 0
|
|
1944
|
+
when :end then -1
|
|
1945
|
+
else JSS::Validate.integer(opts[:position])
|
|
1946
|
+
end
|
|
1947
|
+
|
|
1948
|
+
# If the given position is past the end, set it to -1 (the end)
|
|
1949
|
+
opts[:position] = -1 if opts[:position] > @printers.size
|
|
1950
|
+
|
|
1951
|
+
# Checks if action to be done with the printer object is provided and valid.
|
|
1952
|
+
raise JSS::MissingDataError, "action must be provided, must be one of :#{PRINTER_ACTIONS.keys.join(':,')}." if opts[:action].nil?
|
|
1953
|
+
raise JSS::InvalidDataError, "action must be one of :#{PRINTER_ACTIONS.keys.join(',:')}." unless PRINTER_ACTIONS.keys.include? opts[:action]
|
|
1954
|
+
|
|
1955
|
+
|
|
1956
|
+
# Checks if the make_default option is valid, and sets the default if needed.
|
|
1957
|
+
raise JSS::InvalidDataError, "make_default must be either true or false." unless opts[:make_default].is_a?(TrueClass) || opts[:make_default].is_a?(FalseClass) || opts[:make_default].nil?
|
|
1958
|
+
|
|
1959
|
+
opts[:make_default] = false if opts[:make_default].nil?
|
|
1960
|
+
|
|
1961
|
+
id = JSS::Printer.valid_id identifier, api: @api
|
|
1962
|
+
raise JSS::NoSuchItemError, "No printer matches '#{identifier}'" unless id
|
|
1963
|
+
id
|
|
1964
|
+
end
|
|
1965
|
+
|
|
1442
1966
|
def rest_xml
|
|
1443
1967
|
doc = REXML::Document.new APIConnection::XML_HEADER
|
|
1444
1968
|
obj = doc.add_element RSRC_OBJECT_KEY.to_s
|
|
@@ -1447,6 +1971,10 @@ module JSS
|
|
|
1447
1971
|
general.add_element('name').text = @name
|
|
1448
1972
|
general.add_element('enabled').text = @enabled
|
|
1449
1973
|
general.add_element('frequency').text = @frequency
|
|
1974
|
+
general.add_element('retry_event').text = @retry_event
|
|
1975
|
+
general.add_element('retry_attempts').text = @retry_attempts.to_s
|
|
1976
|
+
general.add_element('notify_on_each_failed_retry').text = @notify_failed_retries.to_s
|
|
1977
|
+
|
|
1450
1978
|
general.add_element('target_drive').text = @target_drive
|
|
1451
1979
|
general.add_element('offline').text = @offline
|
|
1452
1980
|
|
|
@@ -1475,6 +2003,22 @@ module JSS
|
|
|
1475
2003
|
maint.add_element('user_cache').text = @user_cache.to_s
|
|
1476
2004
|
maint.add_element('verify').text = @verify_startup_disk.to_s
|
|
1477
2005
|
|
|
2006
|
+
acct_maint = obj.add_element 'account_maintenance'
|
|
2007
|
+
|
|
2008
|
+
mgmt_acct = acct_maint.add_element 'management_account'
|
|
2009
|
+
JSS.hash_to_rexml_array(@management_account).each { |x| mgmt_acct << x }
|
|
2010
|
+
|
|
2011
|
+
directory_bindings = acct_maint.add_element 'directory_bindings'
|
|
2012
|
+
@directory_bindings.each do |b|
|
|
2013
|
+
directory_binding = directory_bindings.add_element 'binding'
|
|
2014
|
+
dbdeets = JSS.hash_to_rexml_array b
|
|
2015
|
+
dbdeets.each { |d| directory_binding << d }
|
|
2016
|
+
end
|
|
2017
|
+
|
|
2018
|
+
user_interaction = obj.add_element 'user_interaction'
|
|
2019
|
+
user_interaction.add_element('message_start').text = @user_message_start.to_s
|
|
2020
|
+
user_interaction.add_element('message_finish').text = @user_message_finish.to_s
|
|
2021
|
+
|
|
1478
2022
|
files_processes = obj.add_element 'files_processes'
|
|
1479
2023
|
JSS.hash_to_rexml_array(@files_processes).each { |f| files_processes << f }
|
|
1480
2024
|
|
|
@@ -1493,6 +2037,26 @@ module JSS
|
|
|
1493
2037
|
sdeets.each { |d| script << d }
|
|
1494
2038
|
end
|
|
1495
2039
|
|
|
2040
|
+
disk_encryption = obj.add_element 'disk_encryption'
|
|
2041
|
+
|
|
2042
|
+
@disk_encryption.each do |k,v|
|
|
2043
|
+
disk_encryption.add_element(k.to_s).text = v.to_s
|
|
2044
|
+
end
|
|
2045
|
+
|
|
2046
|
+
printers = obj.add_element 'printers'
|
|
2047
|
+
@printers.each do |pr|
|
|
2048
|
+
printer = printers.add_element 'printer'
|
|
2049
|
+
pdeets = JSS.hash_to_rexml_array pr
|
|
2050
|
+
pdeets.each { |d| printer << d }
|
|
2051
|
+
end
|
|
2052
|
+
|
|
2053
|
+
dock_items = obj.add_element 'dock_items'
|
|
2054
|
+
@dock_items.each do |d|
|
|
2055
|
+
dock_item = dock_items.add_element 'dock_item'
|
|
2056
|
+
ddeets = JSS.hash_to_rexml_array d
|
|
2057
|
+
ddeets.each { |de| dock_item << de }
|
|
2058
|
+
end
|
|
2059
|
+
|
|
1496
2060
|
add_self_service_xml doc
|
|
1497
2061
|
add_site_to_xml doc
|
|
1498
2062
|
|