jss-api 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/lib/jss-api.rb +1 -191
  2. metadata +16 -146
  3. data/.yardopts +0 -7
  4. data/CHANGES.md +0 -88
  5. data/LICENSE.txt +0 -174
  6. data/README.md +0 -396
  7. data/THANKS.md +0 -6
  8. data/bin/cgrouper +0 -485
  9. data/bin/subnet-update +0 -400
  10. data/lib/jss-api/api_connection.rb +0 -400
  11. data/lib/jss-api/api_object.rb +0 -616
  12. data/lib/jss-api/api_object/advanced_search.rb +0 -389
  13. data/lib/jss-api/api_object/advanced_search/advanced_computer_search.rb +0 -95
  14. data/lib/jss-api/api_object/advanced_search/advanced_mobile_device_search.rb +0 -96
  15. data/lib/jss-api/api_object/advanced_search/advanced_user_search.rb +0 -95
  16. data/lib/jss-api/api_object/building.rb +0 -92
  17. data/lib/jss-api/api_object/category.rb +0 -147
  18. data/lib/jss-api/api_object/computer.rb +0 -852
  19. data/lib/jss-api/api_object/creatable.rb +0 -98
  20. data/lib/jss-api/api_object/criteriable.rb +0 -189
  21. data/lib/jss-api/api_object/criteriable/criteria.rb +0 -231
  22. data/lib/jss-api/api_object/criteriable/criterion.rb +0 -228
  23. data/lib/jss-api/api_object/department.rb +0 -93
  24. data/lib/jss-api/api_object/distribution_point.rb +0 -560
  25. data/lib/jss-api/api_object/extendable.rb +0 -221
  26. data/lib/jss-api/api_object/extension_attribute.rb +0 -457
  27. data/lib/jss-api/api_object/extension_attribute/computer_extension_attribute.rb +0 -362
  28. data/lib/jss-api/api_object/extension_attribute/mobile_device_extension_attribute.rb +0 -189
  29. data/lib/jss-api/api_object/extension_attribute/user_extension_attribute.rb +0 -117
  30. data/lib/jss-api/api_object/group.rb +0 -380
  31. data/lib/jss-api/api_object/group/computer_group.rb +0 -124
  32. data/lib/jss-api/api_object/group/mobile_device_group.rb +0 -139
  33. data/lib/jss-api/api_object/group/user_group.rb +0 -139
  34. data/lib/jss-api/api_object/ldap_server.rb +0 -535
  35. data/lib/jss-api/api_object/locatable.rb +0 -286
  36. data/lib/jss-api/api_object/matchable.rb +0 -97
  37. data/lib/jss-api/api_object/mobile_device.rb +0 -556
  38. data/lib/jss-api/api_object/netboot_server.rb +0 -148
  39. data/lib/jss-api/api_object/network_segment.rb +0 -414
  40. data/lib/jss-api/api_object/osx_configuration_profile.rb +0 -261
  41. data/lib/jss-api/api_object/package.rb +0 -812
  42. data/lib/jss-api/api_object/peripheral.rb +0 -335
  43. data/lib/jss-api/api_object/peripheral_type.rb +0 -295
  44. data/lib/jss-api/api_object/policy.rb +0 -898
  45. data/lib/jss-api/api_object/purchasable.rb +0 -316
  46. data/lib/jss-api/api_object/removable_macaddr.rb +0 -98
  47. data/lib/jss-api/api_object/scopable.rb +0 -136
  48. data/lib/jss-api/api_object/scopable/scope.rb +0 -621
  49. data/lib/jss-api/api_object/script.rb +0 -631
  50. data/lib/jss-api/api_object/self_servable.rb +0 -355
  51. data/lib/jss-api/api_object/site.rb +0 -93
  52. data/lib/jss-api/api_object/software_update_server.rb +0 -109
  53. data/lib/jss-api/api_object/updatable.rb +0 -117
  54. data/lib/jss-api/api_object/uploadable.rb +0 -138
  55. data/lib/jss-api/api_object/user.rb +0 -272
  56. data/lib/jss-api/client.rb +0 -504
  57. data/lib/jss-api/compatibility.rb +0 -66
  58. data/lib/jss-api/composer.rb +0 -171
  59. data/lib/jss-api/configuration.rb +0 -306
  60. data/lib/jss-api/db_connection.rb +0 -298
  61. data/lib/jss-api/exceptions.rb +0 -95
  62. data/lib/jss-api/ruby_extensions.rb +0 -35
  63. data/lib/jss-api/ruby_extensions/filetest.rb +0 -43
  64. data/lib/jss-api/ruby_extensions/hash.rb +0 -79
  65. data/lib/jss-api/ruby_extensions/ipaddr.rb +0 -91
  66. data/lib/jss-api/ruby_extensions/pathname.rb +0 -77
  67. data/lib/jss-api/ruby_extensions/string.rb +0 -59
  68. data/lib/jss-api/ruby_extensions/time.rb +0 -63
  69. data/lib/jss-api/server.rb +0 -108
  70. data/lib/jss-api/utility.rb +0 -416
  71. data/lib/jss-api/version.rb +0 -31
@@ -1,261 +0,0 @@
1
- ### Copyright 2016 Pixar
2
- ###
3
- ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
- ### with the following modification; you may not use this file except in
5
- ### compliance with the Apache License and the following modification to it:
6
- ### Section 6. Trademarks. is deleted and replaced with:
7
- ###
8
- ### 6. Trademarks. This License does not grant permission to use the trade
9
- ### names, trademarks, service marks, or product names of the Licensor
10
- ### and its affiliates, except as required to comply with Section 4(c) of
11
- ### the License and to reproduce the content of the NOTICE file.
12
- ###
13
- ### You may obtain a copy of the Apache License at
14
- ###
15
- ### http://www.apache.org/licenses/LICENSE-2.0
16
- ###
17
- ### Unless required by applicable law or agreed to in writing, software
18
- ### distributed under the Apache License with the above modification is
19
- ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
- ### KIND, either express or implied. See the Apache License for the specific
21
- ### language governing permissions and limitations under the Apache License.
22
- ###
23
- ###
24
-
25
- ###
26
- module JSS
27
-
28
- #####################################
29
- ### Module Variables
30
- #####################################
31
-
32
- #####################################
33
- ### Module Methods
34
- #####################################
35
-
36
-
37
- #####################################
38
- ### Classes
39
- #####################################
40
-
41
- ###
42
- ### An OS X Configuration Profile in the JSS.
43
- ###
44
- ### Note that the profile payloads and the profile UUID cannot be edited or updated with this via this class.
45
- ### Use the web UI.
46
- ###
47
- ### @see JSS::APIObject
48
- ###
49
- class OSXConfigurationProfile < JSS::APIObject
50
-
51
- #####################################
52
- ### Mix-Ins
53
- #####################################
54
- include JSS::Updatable
55
- include JSS::Scopable
56
- include JSS::SelfServable
57
-
58
- #####################################
59
- ### Class Methods
60
- #####################################
61
-
62
- #####################################
63
- ### Class Constants
64
- #####################################
65
-
66
- ### The base for REST resources of this class
67
- RSRC_BASE = "osxconfigurationprofiles"
68
-
69
- ### the hash key used for the JSON list output of all objects in the JSS
70
- RSRC_LIST_KEY = :os_x_configuration_profiles
71
-
72
- ### The hash key used for the JSON object output.
73
- ### It's also used in various error messages
74
- RSRC_OBJECT_KEY = :os_x_configuration_profile
75
-
76
- ### these keys, as well as :id and :name, are present in valid API JSON data for this class
77
- VALID_DATA_KEYS = [:distribution_method, :scope, :redeploy_on_update]
78
-
79
- ### Our scopes deal with computers
80
- SCOPE_TARGET_KEY = :computers
81
-
82
- ### Our SelfService happens on OSX
83
- SELF_SERVICE_TARGET = :osx
84
-
85
- ### Our SelfService deploys profiles
86
- SELF_SERVICE_PAYLOAD = :profile
87
-
88
- ### The possible values for the :distribution_method
89
- DISTRIBUTION_METHODS = ["Install Automatically", "Make Available in Self Service"]
90
-
91
- SELF_SERVICE_DIST_METHOD = "Make Available in Self Service"
92
-
93
- ### The possible values for :level
94
- LEVELS = ["user", "computer"]
95
-
96
-
97
- #####################################
98
- ### Attributes
99
- #####################################
100
-
101
- ### @return [String] the description of this profile
102
- attr_reader :description
103
-
104
- ### @return [String] the distribution_method of this profile
105
- attr_reader :distribution_method
106
-
107
- ### @return [Boolean] can the user remove this profile
108
- attr_reader :user_removable
109
-
110
- ### @return [String] the level (user/computer) of this profile
111
- attr_reader :level
112
-
113
- ### @return [String] the uuid of this profile. NOT Updatable
114
- attr_reader :uuid
115
-
116
- ### @return [Boolean] Should this profile be redeployed when an inventory update happens?
117
- attr_reader :redeploy_on_update
118
-
119
- ### @return [String] the plist containing the payloads for this profile. NOT Updatable
120
- attr_reader :payloads
121
-
122
- #####################################
123
- ### Constructor
124
- #####################################
125
-
126
- ###
127
- ### See JSS::APIObject#initialize
128
- ###
129
- def initialize (args = {})
130
-
131
- super
132
-
133
- @description = @main_subset[:description]
134
- @distribution_method = @main_subset[:distribution_method]
135
- @user_removable = @main_subset[:user_removable]
136
- @level = @main_subset[:level]
137
- @uuid = @main_subset[:uuid]
138
- @redeploy_on_update = @main_subset[:redeploy_on_update]
139
- @payloads = @main_subset[:payloads]
140
-
141
- self.parse_scope
142
- self.parse_self_service
143
-
144
- end
145
-
146
- #####################################
147
- ### Public Instance Methods
148
- #####################################
149
-
150
- ###
151
- ### @param new_val[String] the new discription
152
- ###
153
- ### @return [void]
154
- ###
155
- def description= (new_val)
156
- return nil if @self_service_description == new_val
157
- @description = new_val.strip!
158
- @need_to_update = true
159
- end
160
-
161
-
162
- ###
163
- ### @param new_val[String] how should this be distributed to clients?
164
- ###
165
- ### @return [void]
166
- ###
167
- def distribution_method= (new_val)
168
- return nil if @distribution_method == new_val
169
- raise JSS::InvalidDataError, "New value must be one of '#{DISTRIBUTION_METHODS.join("' '")}'" unless DISTRIBUTION_METHODS.include? new_val
170
- @distribution_method = new_val
171
- @need_to_update = true
172
- end
173
-
174
- ###
175
- ### @param new_val[Boolean] should the user be able to remove this?
176
- ###
177
- ### @return [void]
178
- ###
179
- def user_removable= (new_val)
180
- return nil if @self_service_feature_on_main_page == new_val
181
- raise JSS::InvalidDataError, "Distribution method must be '#{SELF_SERVICE_DIST_METHOD}' to let the user remove it." unless in_self_service?
182
- raise JSS::InvalidDataError, "New value must be true or false" unless JSS::TRUE_FALSE.include? new_val
183
- @user_removable = new_val
184
- @need_to_update = true
185
- end
186
-
187
- ###
188
- ### @param new_val[String] the new level for this profile (user/computer)
189
- ###
190
- ### @return [void]
191
- ###
192
- def level= (new_val)
193
- return nil if @level == new_val
194
- raise JSS::InvalidDataError, "New value must be one of '#{LEVELS.join("' '")}'" unless LEVELS.include? new_val
195
- @level = new_val
196
- @need_to_update = true
197
- end
198
-
199
-
200
- ###
201
- ### @return [Boolean] is this profile available in Self Service?
202
- ###
203
- def in_self_service?
204
- @distribution_method == SELF_SERVICE_DIST_METHOD
205
- end
206
-
207
-
208
- ###
209
- ### @return [Boolean] is this profile removable by the user?
210
- ###
211
- def user_removable?
212
- @user_removable
213
- end
214
-
215
-
216
- ###
217
- ### @return [Hash] The payload plist parsed into a Ruby hash
218
- ###
219
- def parsed_payloads
220
- Plist.parse_xml @payloads
221
- end
222
-
223
- ###
224
- ### @return [Array<Hash>] the individual payloads from the payload Plist
225
- ###
226
- def payload_content
227
- parsed_payloads['PayloadContent']
228
- end
229
-
230
- ###
231
- ### @return [Array<String>] the PayloadType of each payload (e.g. com.apple.caldav.account)
232
- ###
233
- def payload_types
234
- payload_content.map{|p| p['PayloadType'] }
235
- end
236
-
237
- #####################################
238
- ### Private Instance Methods
239
- #####################################
240
- private
241
-
242
- def rest_xml
243
- doc = REXML::Document.new
244
-
245
- obj = doc.add_element RSRC_OBJECT_KEY.to_s
246
- gen = obj.add_element('general')
247
- gen.add_element('description').text = @description
248
- gen.add_element('distribution_method').text = @distribution_method
249
- gen.add_element('user_removable').text = @user_removable
250
- gen.add_element('level').text = @level
251
- gen.add_element('redeploy_on_update').text = @redeploy_on_update
252
-
253
- obj << @scope.scope_xml
254
- obj << self_service_xml
255
-
256
- return doc.to_s
257
- end
258
-
259
- end # class OSXConfigurationProfile
260
-
261
- end # module
@@ -1,812 +0,0 @@
1
- ### Copyright 2016 Pixar
2
- ###
3
- ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
- ### with the following modification; you may not use this file except in
5
- ### compliance with the Apache License and the following modification to it:
6
- ### Section 6. Trademarks. is deleted and replaced with:
7
- ###
8
- ### 6. Trademarks. This License does not grant permission to use the trade
9
- ### names, trademarks, service marks, or product names of the Licensor
10
- ### and its affiliates, except as required to comply with Section 4(c) of
11
- ### the License and to reproduce the content of the NOTICE file.
12
- ###
13
- ### You may obtain a copy of the Apache License at
14
- ###
15
- ### http://www.apache.org/licenses/LICENSE-2.0
16
- ###
17
- ### Unless required by applicable law or agreed to in writing, software
18
- ### distributed under the Apache License with the above modification is
19
- ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
- ### KIND, either express or implied. See the Apache License for the specific
21
- ### language governing permissions and limitations under the Apache License.
22
- ###
23
- ###
24
-
25
- ###
26
- module JSS
27
-
28
- #####################################
29
- ### Module Constants
30
- #####################################
31
-
32
- #####################################
33
- ### Module Variables
34
- #####################################
35
-
36
- #####################################
37
- ### Module Methods
38
- #####################################
39
-
40
- #####################################
41
- ### Classes
42
- #####################################
43
-
44
- ###
45
- ### A Package in the JSS
46
- ###
47
- ### Also the API provides no access to the package's
48
- ### file list (index), so indexing must be done separately (usually via Casper Admin)
49
- ###
50
- ###
51
- ### @see JSS::APIObject
52
- ###
53
- class Package < JSS::APIObject
54
-
55
- #####################################
56
- ### Mix-Ins
57
- #####################################
58
-
59
- include JSS::Creatable
60
- include JSS::Updatable
61
-
62
- #####################################
63
- ### Class Methods
64
- #####################################
65
-
66
- #####################################
67
- ### Class Constants
68
- #####################################
69
-
70
- ### The base for REST resources of this class
71
- RSRC_BASE = "packages"
72
-
73
- ### the hash key used for the JSON list output of all objects in the JSS
74
- RSRC_LIST_KEY = :packages
75
-
76
- ### The hash key used for the JSON object output.
77
- ### It's also used in various error messages
78
- RSRC_OBJECT_KEY = :package
79
-
80
- ### these keys, as well as :id and :name, are present in valid API JSON data for this class
81
- VALID_DATA_KEYS = [:fill_existing_users, :fill_user_template, :reboot_required ]
82
-
83
- ### The pkg storage folder on the distribution point
84
- DIST_POINT_PKGS_FOLDER = "Packages"
85
-
86
- ### The possible values for cpu_type (required_processor) in a JSS package
87
- CPU_TYPES = ["None", "x86", "ppc"]
88
-
89
- # TO DO - this is redundant with DEFAULT_PROCESSOR, but both are in use
90
- # clean them up!
91
- ### which is default? there must be one to make a new pkg
92
- DEFAULT_CPU_TYPE = "None"
93
-
94
- ### the possible priorities
95
- PRIORITIES = (1..20)
96
-
97
- ### the default priority, since one is needed for making new pkgs
98
- DEFAULT_PRIORITY = 10
99
-
100
- ### by default, no processor requirement
101
- DEFAULT_PROCESSOR = "None"
102
-
103
- ### When we shouldn't install anything (e.g. switch w/package)
104
- DO_NOT_INSTALL = "Do Not Install"
105
-
106
- #####################################
107
- ### Class Variables
108
- #####################################
109
-
110
- #####################################
111
- ### Class Methods
112
- #####################################
113
-
114
- #####################################
115
- ### Attributes
116
- #####################################
117
-
118
- ### @return [String] the filename of the .pkg, .mpkg, or .dmg on the Casper server
119
- attr_reader :filename
120
-
121
- ### @return [Pathname] the local receipt when this pkg is installed
122
- attr_reader :receipt
123
-
124
- ### @return [Boolean] does this item 'Fill Existing Users' when jamf installs it?
125
- attr_reader :fill_existing_users
126
-
127
- ### @return [Boolean] does this pkg also get install in the OS user homedir template
128
- attr_reader :fill_user_template
129
-
130
- ### @return [Boolean] does this item require a reboot after installation? If so, it'll be a puppy-install in d3
131
- attr_reader :reboot_required
132
-
133
- ### @return [Array<String>] the OS versions this can be installed onto. For all minor versions, the format is 10.5.x
134
- attr_reader :os_requirements
135
-
136
- ### @return [String] limit installation to these architectures: 'x86', 'ppc', 'None'
137
- attr_reader :required_processor
138
-
139
- ### @return [String] the name of a pkg to install (or "Do Not Install") when this pkg can't be installed
140
- attr_reader :switch_with_package
141
-
142
- ### @return [Boolean] can this item be uninstalled? Some, e.g. OS Updates, can't
143
- attr_reader :allow_uninstalled
144
-
145
- ### @return [String] the category of this pkg, stored in the JSS as the id number from the categories table
146
- attr_reader :category
147
-
148
- ### @return [String] the info field for this pkg - stores d3's basename & swupdate values
149
- attr_reader :info
150
-
151
- ### @return [String] the notes field for this pkg
152
- attr_reader :notes
153
-
154
- ### @return [Boolean] only install this pkg if it's available in the commandline softwareupdate.
155
- attr_reader :install_if_reported_available
156
-
157
- ### @return [Boolean] should this pkg be installed on the boot volume during imaging
158
- attr_reader :boot_volume_required
159
-
160
- ### @return [Integer] Priority to use for deploying or uninstalling the package
161
- attr_reader :priority
162
-
163
- ### @return [Boolean] does this pkg cause a notification to be sent on self-heal?
164
- attr_reader :send_notification
165
-
166
-
167
- ###
168
- ### @see JSS::APIObject#initialize
169
- ###
170
- def initialize (args = {})
171
-
172
- super
173
-
174
- ### now we have pkg_data with something in it, so fill out the instance vars
175
- @allow_uninstalled = @init_data[:allow_uninstalled]
176
- @boot_volume_required = @init_data[:boot_volume_required]
177
- @category = JSS::APIObject.get_name(@init_data[:category])
178
- @category = nil if @category.to_s.casecmp("No category assigned") == 0
179
- @filename = @init_data[:filename] || @init_data[:name]
180
- @fill_existing_users = @init_data[:fill_existing_users]
181
- @fill_user_template = @init_data[:fill_user_template]
182
- @info = @init_data[:info]
183
- @install_if_reported_available = @init_data[:install_if_reported_available]
184
- @notes = @init_data[:notes]
185
- @os_requirements = @init_data[:os_requirements].split(/\s*,\s*/) if @init_data[:os_requirements]
186
- @os_requirements ||= []
187
-
188
- @priority = @init_data[:priority] || DEFAULT_PRIORITY
189
- @reboot_required = @init_data[:reboot_required]
190
- @required_processor = @init_data[:required_processor] || DEFAULT_CPU_TYPE
191
- @required_processor = nil if @required_processor.to_s.casecmp('none') == 0
192
- @send_notification = @init_data[:send_notification]
193
- @switch_with_package = @init_data[:switch_with_package] || DO_NOT_INSTALL
194
-
195
- # the receipt is the filename with any .zip extension removed.
196
- @receipt = @filename ? (JSS::Client::RECEIPTS_FOLDER + @filename.to_s.sub(/.zip$/, '')) : nil
197
- end # init
198
-
199
-
200
-
201
- ###
202
- ### Change the 'allow to be uninstalled' field in the JSS
203
- ### NOTE The package must be indexed before this works. Right now, that means
204
- ### using CasperAdmin.app
205
- ###
206
- ### @param new_val[Boolean]
207
- ###
208
- ### @return [void]
209
- ###
210
- def allow_uninstalled= (new_val)
211
- return nil if new_val == @allow_uninstalled
212
-
213
- ### removable? defaults to false
214
- ### even though we usually want to be able to ununstall things, it would be
215
- ### dangerous to do on things like OS updates, so it must be turned on explicitly.
216
- ### packages must be indexed with Casper Admin in order to be uninstalled.
217
- new_val = false if new_val.to_s.empty?
218
- raise JSS::InvalidDataError, "allow_uninstalled must be boolean 'true' or 'false'" unless JSS::TRUE_FALSE.include? new_val
219
-
220
- @allow_uninstalled= new_val
221
- @need_to_update = true
222
-
223
- end
224
-
225
-
226
- ###
227
- ### Change the boot volume required field in the JSS
228
- ###
229
- ### @param new_val[Boolean]
230
- ###
231
- ### @return [void]
232
- ###
233
- def boot_volume_required=(new_val)
234
- return nil if new_val == @boot_volume_required
235
- new_val = false if new_val.to_s.empty?
236
- raise JSS::InvalidDataError, "install_if_reported_available must be boolean true or false" unless JSS::TRUE_FALSE.include? new_val
237
- @boot_volume_required = new_val
238
- @need_to_update = true
239
- end
240
-
241
-
242
- ###
243
- ### Change the category in the JSS
244
- ###
245
- ### @param new_val[String] must be one listed by 'JSS::Category.all_names'
246
- ###
247
- ### @return [void]
248
- ###
249
- def category= (new_val)
250
- return nil if new_val == @category
251
- new_val = nil if new_val == ''
252
- new_val ||= JSS::Category::DEFAULT_CATEGORY
253
- raise JSS::InvalidDataError, "Category #{new_val} is not known to the JSS" unless JSS::Category.all_names.include? new_val
254
- @category = new_val
255
- @need_to_update = true
256
- end
257
-
258
- ###
259
- ### Change the package filename.
260
- ### Setting it to nil or empty will make it match the display name
261
- ###
262
- ### @param new_val[String]
263
- ###
264
- ### @return [void]
265
- ###
266
- def filename= (new_val)
267
- new_val = nil if new_val == ''
268
- new_val ||= @name
269
- return nil if new_val == @filename
270
- $stderr.puts "WARNING: you must manualy change the filename on the Distribution Point(s)" if @in_jss
271
- @filename = new_val
272
- @need_to_update = true
273
- end
274
-
275
-
276
- ###
277
- ### Change the Fill Existing Users value
278
- ###
279
- ### @param new_val[Boolean]
280
- ###
281
- ### @return [void]
282
- ###
283
- def fill_existing_users= (new_val)
284
- return nil if new_val == @fill_existing_users
285
- new_val = false if new_val.to_s.empty?
286
- raise JSS::InvalidDataError, "fill_existing_users must be boolean 'true' or 'false'" unless JSS::TRUE_FALSE.include? new_val
287
- @fill_existing_users = new_val
288
- @need_to_update = true
289
- end
290
-
291
- ###
292
- ### Change the fill_user_template value
293
- ###
294
- ### @param new_val[Boolean]
295
- ###
296
- ### @return [void]
297
- ###
298
- def fill_user_template= (new_val)
299
- return nil if new_val == @fill_user_template
300
- new_val = false if new_val.to_s.empty?
301
- raise JSS::InvalidDataError, "fill_user_template must be boolean 'true' or 'false'" unless JSS::TRUE_FALSE.include? new_val
302
- @fill_user_template = new_val
303
- @need_to_update = true
304
- end
305
-
306
-
307
-
308
- ###
309
- ### Change the info field in the JSS.
310
- ###
311
- ### @param new_val[String]
312
- ###
313
- ### @return [void]
314
- ###
315
- def info= (new_val)
316
- return nil if new_val == @info
317
- ### line breaks should be \r
318
- new_val = new_val.to_s.gsub(/\n/, "\r")
319
- @info = new_val
320
- @need_to_update = true
321
- end
322
-
323
-
324
- ###
325
- ### Change the if_in_swupdate field in the JSS
326
- ###
327
- ### @param new_val[Boolean]
328
- ###
329
- ### @return [void]
330
- ###
331
- def install_if_reported_available= (new_val)
332
- return nil if new_val == @install_if_reported_available
333
- new_val = false if new_val.to_s.empty?
334
- raise JSS::InvalidDataError, "install_if_reported_available must be boolean true or false" unless JSS::TRUE_FALSE.include? new_val
335
- @install_if_reported_available = new_val
336
- @need_to_update = true
337
- end
338
-
339
-
340
-
341
- ###
342
- ### Change the notes field in the JSS.NewLines are converted \r.
343
- ###
344
- ### @param new_val[String]
345
- ###
346
- ### @return [void]
347
- ###
348
- def notes= (new_val)
349
- return nil if new_val == @notes
350
- ### line breaks should be \r
351
- new_val = new_val.to_s.gsub(/\n/, "\r")
352
- @notes = new_val
353
- @need_to_update = true
354
- end
355
-
356
- ###
357
- ### Change the os_requirements field in the JSS
358
- ### E.g. 10.5, 10.5.3, 10.6.x
359
- ###
360
- ### @param new_val[String,Array] comma-separated string, or array of os versions
361
- ###
362
- ### @return [void]
363
- ###
364
- ### Extra feature: Minumum OS's can now be specified as a
365
- ### string using the notation ">=10.6.7".
366
- ###
367
- ### @see JSS.expand_min_os
368
- ###
369
- def os_requirements= (new_val)
370
- ### nil should be an empty array
371
- new_val = [] if new_val.to_s.empty?
372
-
373
- ### if any value starts with >=, expand it
374
- case new_val
375
- when String
376
- new_val = JSS.expand_min_os(new_val) if new_val =~ /^>=/
377
- when Array
378
- new_val.map!{|a| a =~ /^>=/ ? JSS.expand_min_os(a) : a }
379
- new_val.flatten!
380
- new_val.uniq!
381
- else
382
- raise JSS::InvalidDataError, "os_requirements must be a String or an Array of strings"
383
- end
384
- ### get the array version
385
- @os_requirements = JSS.to_s_and_a(new_val)[:arrayform]
386
- @need_to_update = true
387
- end
388
-
389
-
390
- ###
391
- ### Change the priority field in the JSS
392
- ###
393
- ### @param new_val[Integer] one of PRIORITIES
394
- ###
395
- ### @return [void]
396
- ###
397
- def priority= (new_val)
398
- return nil if new_val == @priority
399
- new_val = DEFAULT_PRIORITY if new_val.to_s.empty?
400
- raise JSS::InvalidDataError, ":priority must be an integer from 1-20" unless PRIORITIES.include? new_val
401
- @priority = new_val
402
- @need_to_update = true
403
- end
404
-
405
- ###
406
- ### Change the reboot-required field in the JSS
407
- ###
408
- ### @param new_val[Boolean]
409
- ###
410
- ### @return [void]
411
- ###
412
- def reboot_required= (new_val)
413
- return nil if new_val == @reboot_required
414
- new_val = false if new_val.to_s.empty?
415
- raise JSS::InvalidDataError, "reboot must be boolean 'true' or 'false'" unless JSS::TRUE_FALSE.include? new_val
416
- @reboot_required = new_val
417
- @need_to_update = true
418
- end
419
-
420
-
421
-
422
- ###
423
- ### Change the required processor field in the JSS
424
- ###
425
- ### @param new_val[String] one of {CPU_TYPES}
426
- ###
427
- ### @return [void]
428
- ###
429
- def required_processor= (new_val)
430
- return nil if new_val == @required_processor
431
-
432
- new_val = DEFAULT_PROCESSOR if new_val.to_s.empty?
433
- raise JSS::InvalidDataError, "Required_processor must be one of: #{CPU_TYPES.join ', '}" unless CPU_TYPES.include? new_val
434
-
435
- @required_processor = new_val
436
- @need_to_update = true
437
- end
438
-
439
-
440
- ###
441
- ### Change the notify field in the JSS
442
- ###
443
- ### @param new_val[Boolean]
444
- ###
445
- ### @return [void]
446
- ###
447
- def send_notification= (new_val)
448
- return nil if new_val == @send_notification
449
- new_val = false if new_val.to_s.empty?
450
- raise JSS::InvalidDataError, "send_notification must be boolean true or false" unless JSS::TRUE_FALSE.include? new_val
451
- @send_notification = new_val
452
- @need_to_update = true
453
- end
454
-
455
-
456
-
457
- ###
458
- ### Change which pkg should be installed if this one can't.
459
- ###
460
- ### @param new_val[String] the name of an existing package or "Do Not Install"
461
- ###
462
- ### @return [void]
463
- ###
464
- def switch_with_package= (new_val)
465
- return nil if new_val == @switch_with_package
466
- new_val = nil if new_val.to_s.empty?
467
-
468
- raise JSS::NoSuchItemError, "No package named '#{new_val}' exists in the JSS" if new_val and not self.class.all_names.include? new_val
469
-
470
- new_val ||= DO_NOT_INSTALL
471
- @switch_with_package = new_val
472
- @need_to_update = true
473
- end
474
-
475
- ###
476
- ### Is this packaged installed on the current machine (via casper)?
477
- ### We just look for the receipt, which is the @filename less any possible .zip extension.
478
- ###
479
- ### @return [Boolean]
480
- ###
481
- def installed?
482
- @receipt.file?
483
- end
484
-
485
- ###
486
- ### Upload a locally-readable file to the master distribution point.
487
- ### If the file is a directory (like a bundle .pk/.mpkg) it will be zipped before
488
- ### uploading and the @filename will be adjusted accordingly
489
- ###
490
- ### If you'll be uploading several files you can specify unmount as false, and do it manually when all
491
- ### are finished with JSS::DistributionPoint.master_distribution_point.unmount
492
- ###
493
- ### @param local_file_path[String,Pathname] the local path to the file to be uploaded
494
- ###
495
- ### @param rw_pw[String,Symbol] the password for the read/write account on the master Distribution Point,
496
- ### or :prompt, or :stdin# where # is the line of stdin containing the password See {JSS::DistributionPoint#mount}
497
- ###
498
- ### @param unmount[Boolean] whether or not ot unount the distribution point when finished.
499
- ###
500
- ### @return [void]
501
- ###
502
- def upload_master_file (local_file_path, rw_pw, unmount = true)
503
-
504
- raise JSS::NoSuchItemError, "Please create this package in the JSS before uploading it." unless @in_jss
505
-
506
- mdp = JSS::DistributionPoint.master_distribution_point
507
- destination = mdp.mount(rw_pw, :rw) +"#{DIST_POINT_PKGS_FOLDER}/#{@filename}"
508
-
509
- local_path = Pathname.new local_file_path
510
- raise JSS::NoSuchItemError, "Local file '#{@local_file}' doesn't exist" unless local_path.exist?
511
-
512
- ### should we zip it?
513
- if local_path.directory?
514
- begin
515
- zipdir = Pathname.new "/tmp/jssgemtmp-#{Time.new.strftime "%Y%m%d%H%M%S"}-#{$$}"
516
- zipdir.mkpath
517
- zipdir.chmod 0700
518
- zipfile = zipdir + (local_path.basename.to_s + ".zip")
519
-
520
- ### go to the same dir as the local file
521
- wd = Dir.pwd
522
- Dir.chdir local_path.parent
523
-
524
- ### the contents of the zip file have to have the same name as the zip file itself (minus the .zip)
525
- ### so temporarily rename the source
526
- local_path.rename(local_path.parent + @filename)
527
- raise "There was a problem zipping the pkg bundle" unless system "/usr/bin/zip -qr '#{zipfile}' '#{@filename}'"
528
-
529
- ensure
530
- ### rename the source to the original name
531
- (local_path.parent + @filename).rename local_path
532
- ### go back where we started
533
- Dir.chdir wd
534
- end # begin
535
-
536
- ### update our info
537
- local_path = zipfile
538
-
539
- self.filename = zipfile.basename.to_s
540
-
541
- end # if directory
542
- self.update
543
- FileUtils.copy_entry local_path, destination
544
-
545
- mdp.unmount if unmount
546
- end # upload
547
-
548
- ###
549
- ### Delete the filename from the master distribution point, if it exists.
550
- ###
551
- ### If you'll be uploading several files you can specify unmount as false, and do it manually when all
552
- ### are finished.
553
- ###
554
- ### @param rw_pw[String] the password for the read/write account on the master Distribution Point
555
- ### or :prompt, or :stdin# where # is the line of stdin containing the password. See {JSS::DistributionPoint#mount}
556
- ###
557
- ### @param unmount[Boolean] whether or not ot unount the distribution point when finished.
558
- ###
559
- ### @return [Boolean] was the file deleted?
560
- ###
561
- def delete_master_file (rw_pw, unmount = true)
562
- mdp = JSS::DistributionPoint.master_distribution_point
563
- file = mdp.mount(rw_pw, :rw) +"#{DIST_POINT_PKGS_FOLDER}/#{@filename}"
564
- if file.exist?
565
- file.delete
566
- did_it = true
567
- else
568
- did_it = false
569
- end # if exists
570
- mdp.unmount if unmount
571
- return did_it
572
- end # delete master file
573
-
574
-
575
- ### Install this package via the jamf binary 'install' command from the
576
- ### distribution point for this machine.
577
- ### See {JSS::DistributionPoint.my_distribution_point}
578
- ###
579
- ### @note This code must be run as root to install packages
580
- ###
581
- ### The read-only or http passwd for the dist. point must be provided,
582
- ### except for non-authenticated http downloads)
583
- ###
584
- ### @param args[Hash] the arguments for installation
585
- ###
586
- ### @option args :ro_pw[String] the read-only or http password for the
587
- ### distribution point for the local machine
588
- ### (http will be used if available, and may not need a pw)
589
- ###
590
- ### @option args :target[String,Pathname] The drive on which to install
591
- ### the package, defaults to '/'
592
- ###
593
- ### @option args :verbose [Boolean] be verbose to stdout, defaults to false
594
- ###
595
- ### @option args :feu[Boolean] fill existing users, defaults to false
596
- ###
597
- ### @option args :fut[Boolean] fill user template, defaults to false
598
- ###
599
- ### @option args :unmount[Boolean] unmount the distribution point when
600
- ### finished?(if we mounted it), defaults to false
601
- ###
602
- ### @option args :no_http[Boolean] don't use http downloads even if they
603
- ### are enabled for the dist. point.
604
- ###
605
- ### @option args :alt_download_url [String] Use this url for an http
606
- ### download, regardless of distribution point settings. This can be used
607
- ### to access Cloud Distribution Points if the fileshare isn't available.
608
- ### The URL should already be ur
609
- ### The package filename will be removed or appended as needed.
610
- ###
611
- ### @return [Boolean] did the jamf install succeed?
612
- ###
613
- ### @todo deal with cert-based https authentication in dist points
614
- ###
615
- def install (args = {})
616
-
617
- raise JSS::UnsupportedError, "You must have root privileges to install packages" unless JSS.superuser?
618
-
619
- args[:target] ||= '/'
620
-
621
- ro_pw = args[:ro_pw]
622
-
623
- # as of Casper 9.72, with http downloads, the jamf binary requires
624
- # the filename must be at the end of the -path url, but before 9.72
625
- # it can't be.
626
- # e.g.
627
- # in <9.72: jamf install -package foo.pkg -path http://mycasper.myorg.edu/CasperShare/Packages
628
- # but
629
- # in >=9.72: jamf install -package foo.pkg -path http://mycasper.myorg.edu/CasperShare/Packages/foo.pkg
630
- #
631
- append_at_vers = JSS.parse_jss_version("9.72")[:version]
632
- our_vers = JSS.parse_jss_version(JSS::API.server.raw_version)[:version]
633
- no_filename_in_url = (our_vers < append_at_vers)
634
-
635
- # use a provided alternative url for an http download
636
- if args[:alt_download_url]
637
-
638
- # we'll re-add the filename below if needed.
639
- src_path = args[:alt_download_url].chomp "/#{@filename}"
640
-
641
- # use our appropriate dist. point for download
642
- else
643
- mdp = JSS::DistributionPoint.my_distribution_point
644
-
645
- ### how do we access our dist. point? with http?
646
- if mdp.http_downloads_enabled and (not args[:no_http])
647
- using_http = true
648
- src_path = mdp.http_url
649
- if mdp.username_password_required
650
- raise JSS::MissingDataError, "No password provided for http download" unless ro_pw
651
- raise JSS::InvaldDatatError, "Incorrect password for http access to distribution point." unless mdp.check_pw(:http, ro_pw)
652
- # insert the name and pw into the uri
653
- reserved_chars = Regexp.new("[^#{URI::REGEXP::PATTERN::UNRESERVED}]") # we'll escape all the chars that aren't unreserved
654
- src_path = src_path.sub(%r{(https?://)(\S)}, "#{$1}#{URI.escape mdp.http_username,reserved_chars}:#{URI.escape ro_pw, reserved_chars}@#{$2}")
655
- end
656
-
657
- # or with filesharing?
658
- else
659
- using_http = false
660
- src_path = mdp.mount(ro_pw)
661
- end
662
-
663
- # look at the pkgs folder
664
- src_path += "#{DIST_POINT_PKGS_FOLDER}"
665
- end # if args[:alt_download_url]
666
-
667
- src_path += "/#{@filename}" unless no_filename_in_url
668
-
669
-
670
- ### are we doing "fill existing users" or "fill user template"?
671
- do_feu = args[:feu] ? "-feu" : ""
672
- do_fut = args[:fut] ? "-fut" : ""
673
-
674
- ### the install args for jamf
675
- command_args = "-package '#{@filename}' -path '#{src_path}' -target '#{args[:target]}' #{do_feu} #{do_fut} -showProgress -verbose"
676
-
677
- ### run it via a client cmd
678
- install_out = JSS::Client.run_jamf :install, command_args, args[:verbose]
679
-
680
- install_out =~ %r{<exitCode>(\d+)</exitCode>}
681
- install_exit = $1 ? $1.to_i : nil
682
- install_exit ||= $?.exitstatus
683
-
684
-
685
- if (args.include? :unmount)
686
- mdp.unmount unless using_http
687
- end
688
-
689
- return install_exit == 0 ? true : false
690
- end
691
-
692
- ###
693
- ### @note This code must be run as root to uninstall packages
694
- ###
695
- ### Causes the pkg to be uninstalled via the jamf command.
696
- ###
697
- ### @param args[Hash] the arguments for installation
698
- ###
699
- ### @option args :target[String,Pathname] The drive from which to uninstall the package, defaults to '/'
700
- ###
701
- ### @option args :verbose[Boolean] be verbose to stdout, defaults to false
702
- ###
703
- ### @option args :feu[Boolean] fill existing users, defaults to false
704
- ###
705
- ### @option args :fut[Boolean] fill user template, defaults to false
706
- ###
707
- ### @return [Process::Status] the result of the 'jamf uninstall' command
708
- ###
709
- def uninstall (args = {})
710
-
711
- raise JSS::UnsupportedError, \
712
- "This package cannot be uninstalled. Please use CasperAdmin to index it and allow uninstalls" unless removable?
713
- raise JSS::UnsupportedError, "You must have root privileges to uninstall packages" unless JSS.superuser?
714
- args[:target] ||= '/'
715
-
716
- ### are we doing "fill existing users" or "fill user template"?
717
- do_feu = args[:feu] ? "-feu" : ""
718
- do_fut = args[:fut] ? "-fut" : ""
719
-
720
- ### use jamf binary to uninstall the pkg
721
- jamf_opts = "-target '#{args[:target]}' -id '#{@id}' #{do_feu} #{do_fut}"
722
-
723
- ### run it via a client
724
- uninstall_out = JSS::Client.run_jamf "uninstall", jamf_opts, args[:verbose]
725
-
726
- return $?
727
- end
728
-
729
-
730
-
731
- ### What type of package is this?
732
- ###
733
- ### @return [Symbol] :pkg or :dmg or:unknown
734
- ###
735
- def type
736
- case @filename
737
- when /\.m?pkg(\.zip)?$/ then :pkg
738
- when /\.dmg$/ then :dmg
739
- else :unknown
740
- end
741
- end
742
-
743
-
744
- ################################
745
- ### Private Instance Methods
746
- ################################
747
-
748
- private
749
-
750
-
751
- ###
752
- ### Return the REST XML for this pkg, with the current values,
753
- ### for saving or updating
754
- ###
755
- def rest_xml
756
- doc = REXML::Document.new APIConnection::XML_HEADER
757
- pkg = doc.add_element "package"
758
- pkg.add_element('allow_uninstalled').text = @allow_uninstalled
759
- pkg.add_element('boot_volume_required').text = @boot_volume_required
760
- pkg.add_element('category').text = @category.to_s.casecmp("No category assigned") == 0 ? "" : @category
761
- pkg.add_element('filename').text = @filename
762
- pkg.add_element('fill_existing_users').text = @fill_existing_users
763
- pkg.add_element('fill_user_template').text = @fill_user_template
764
- pkg.add_element('info').text = @info
765
- pkg.add_element('install_if_reported_available').text = @install_if_reported_available
766
- pkg.add_element('name').text = @name
767
- pkg.add_element('notes').text = @notes
768
- pkg.add_element('os_requirements').text = JSS.to_s_and_a(@os_requirements)[:stringform]
769
- pkg.add_element('priority').text = @priority
770
- pkg.add_element('reboot_required').text = @reboot_required
771
- pkg.add_element('required_processor').text = @required_processor.to_s.empty? ? "None" : @required_processor
772
- pkg.add_element('send_notification').text = @send_notification
773
- pkg.add_element('switch_with_package').text = @switch_with_package
774
- return doc.to_s
775
- end # rest xml
776
-
777
- public
778
-
779
- # aliases under their methods seem to confuse the YARD documenter, so I'm putting them all here.
780
- alias feu fill_existing_users
781
- alias feu? fill_existing_users
782
- alias fut fill_user_template
783
- alias fut? fill_user_template
784
- alias reboot reboot_required
785
- alias reboot? reboot_required
786
- alias oses os_requirements
787
- alias cpu_type required_processor
788
- alias removable allow_uninstalled
789
- alias removable? allow_uninstalled
790
- alias if_in_swupdate install_if_reported_available
791
- alias if_in_swupdate? install_if_reported_available
792
- alias boot boot_volume_required
793
- alias boot? boot_volume_required
794
- alias notify send_notification
795
-
796
- alias removable= allow_uninstalled=
797
- alias boot= boot_volume_required=
798
- alias feu= fill_existing_users=
799
- alias fut= fill_user_template=
800
- alias if_in_swupdate= install_if_reported_available=
801
- alias oses= os_requirements=
802
- alias reboot= reboot_required=
803
- alias cpu_type= required_processor=
804
- alias notify= send_notification=
805
-
806
-
807
-
808
-
809
-
810
- end # class Package
811
-
812
- end # module jss