ruby-jss 0.6.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ruby-jss might be problematic. Click here for more details.

Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +7 -0
  3. data/CHANGES.md +112 -0
  4. data/LICENSE.txt +174 -0
  5. data/README.md +426 -0
  6. data/THANKS.md +6 -0
  7. data/bin/cgrouper +485 -0
  8. data/bin/subnet-update +400 -0
  9. data/lib/jss-api.rb +2 -0
  10. data/lib/jss.rb +190 -0
  11. data/lib/jss/api_connection.rb +410 -0
  12. data/lib/jss/api_object.rb +616 -0
  13. data/lib/jss/api_object/advanced_search.rb +389 -0
  14. data/lib/jss/api_object/advanced_search/advanced_computer_search.rb +95 -0
  15. data/lib/jss/api_object/advanced_search/advanced_mobile_device_search.rb +96 -0
  16. data/lib/jss/api_object/advanced_search/advanced_user_search.rb +95 -0
  17. data/lib/jss/api_object/building.rb +92 -0
  18. data/lib/jss/api_object/category.rb +147 -0
  19. data/lib/jss/api_object/computer.rb +852 -0
  20. data/lib/jss/api_object/creatable.rb +98 -0
  21. data/lib/jss/api_object/criteriable.rb +189 -0
  22. data/lib/jss/api_object/criteriable/criteria.rb +231 -0
  23. data/lib/jss/api_object/criteriable/criterion.rb +228 -0
  24. data/lib/jss/api_object/department.rb +93 -0
  25. data/lib/jss/api_object/distribution_point.rb +560 -0
  26. data/lib/jss/api_object/extendable.rb +221 -0
  27. data/lib/jss/api_object/extension_attribute.rb +466 -0
  28. data/lib/jss/api_object/extension_attribute/computer_extension_attribute.rb +362 -0
  29. data/lib/jss/api_object/extension_attribute/mobile_device_extension_attribute.rb +189 -0
  30. data/lib/jss/api_object/extension_attribute/user_extension_attribute.rb +117 -0
  31. data/lib/jss/api_object/group.rb +380 -0
  32. data/lib/jss/api_object/group/computer_group.rb +124 -0
  33. data/lib/jss/api_object/group/mobile_device_group.rb +139 -0
  34. data/lib/jss/api_object/group/user_group.rb +139 -0
  35. data/lib/jss/api_object/ldap_server.rb +535 -0
  36. data/lib/jss/api_object/locatable.rb +286 -0
  37. data/lib/jss/api_object/matchable.rb +97 -0
  38. data/lib/jss/api_object/mobile_device.rb +556 -0
  39. data/lib/jss/api_object/netboot_server.rb +148 -0
  40. data/lib/jss/api_object/network_segment.rb +414 -0
  41. data/lib/jss/api_object/osx_configuration_profile.rb +262 -0
  42. data/lib/jss/api_object/package.rb +839 -0
  43. data/lib/jss/api_object/peripheral.rb +335 -0
  44. data/lib/jss/api_object/peripheral_type.rb +295 -0
  45. data/lib/jss/api_object/policy.rb +898 -0
  46. data/lib/jss/api_object/purchasable.rb +316 -0
  47. data/lib/jss/api_object/removable_macaddr.rb +98 -0
  48. data/lib/jss/api_object/scopable.rb +136 -0
  49. data/lib/jss/api_object/scopable/scope.rb +621 -0
  50. data/lib/jss/api_object/script.rb +631 -0
  51. data/lib/jss/api_object/self_servable.rb +356 -0
  52. data/lib/jss/api_object/site.rb +93 -0
  53. data/lib/jss/api_object/software_update_server.rb +109 -0
  54. data/lib/jss/api_object/updatable.rb +117 -0
  55. data/lib/jss/api_object/uploadable.rb +138 -0
  56. data/lib/jss/api_object/user.rb +272 -0
  57. data/lib/jss/client.rb +504 -0
  58. data/lib/jss/compatibility.rb +66 -0
  59. data/lib/jss/composer.rb +185 -0
  60. data/lib/jss/configuration.rb +306 -0
  61. data/lib/jss/db_connection.rb +298 -0
  62. data/lib/jss/exceptions.rb +95 -0
  63. data/lib/jss/ruby_extensions.rb +35 -0
  64. data/lib/jss/ruby_extensions/filetest.rb +43 -0
  65. data/lib/jss/ruby_extensions/hash.rb +79 -0
  66. data/lib/jss/ruby_extensions/ipaddr.rb +91 -0
  67. data/lib/jss/ruby_extensions/pathname.rb +77 -0
  68. data/lib/jss/ruby_extensions/string.rb +59 -0
  69. data/lib/jss/ruby_extensions/time.rb +63 -0
  70. data/lib/jss/server.rb +108 -0
  71. data/lib/jss/utility.rb +478 -0
  72. data/lib/jss/version.rb +31 -0
  73. metadata +187 -0
@@ -0,0 +1,621 @@
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
+ module Scopable
29
+
30
+ #####################################
31
+ ### Classes
32
+ #####################################
33
+
34
+ ###
35
+ ### This class represents a Scope in the JSS, as can be applied to Scopable objects like
36
+ ### Policies, Profiles, etc. Instances of this class are generally used as the value of the @scope attribute
37
+ ### of those objects.
38
+ ###
39
+ ### Scope data comes from the API as a hash within the overall object data. The main keys of the hash
40
+ ### define the included targets of the scope. A sub-hash defines limitations on those inclusions,
41
+ ### and another sub-hash defines explicit exclusions.
42
+ ###
43
+ ### This class provides methods for adding, removing, or fully replacing the
44
+ ### various parts of the scope's inclusions, limitations, and exclusions.
45
+ ###
46
+ ### @todo Implement simple LDAP queries using the defined {LDAPServer}s to confirm the
47
+ ### existance of users or groups used in limitations and exclusions. As things are now
48
+ ### if you add invalid user or group names, you'll get a 409 conflict error when you try
49
+ ### to save your changes to the JSS.
50
+ ###
51
+ ### @see JSS::Scopable
52
+ ###
53
+ class Scope
54
+
55
+ #####################################
56
+ ### Mix-Ins
57
+ #####################################
58
+
59
+ #####################################
60
+ ### Class Methods
61
+ #####################################
62
+
63
+ #####################################
64
+ ### Class Constants
65
+ #####################################
66
+
67
+ ### These are the classes that Scopes can use for defining a scope,
68
+ ### keyed by appropriate symbols.
69
+ SCOPING_CLASSES ={
70
+ :computers => JSS::Computer,
71
+ :computer => JSS::Computer,
72
+ :computer_groups => JSS::ComputerGroup,
73
+ :computer_group => JSS::ComputerGroup,
74
+ :mobile_devices => JSS::MobileDevice,
75
+ :mobile_device => JSS::MobileDevice,
76
+ :mobile_device_groups => JSS::MobileDeviceGroup,
77
+ :mobile_device_group => JSS::MobileDeviceGroup,
78
+ :buildings => JSS::Building,
79
+ :building => JSS::Building,
80
+ :departments => JSS::Department,
81
+ :department => JSS::Department,
82
+ :network_segments => JSS::NetworkSegment,
83
+ :network_segment => JSS::NetworkSegment,
84
+ :users => JSS::User,
85
+ :user => JSS::User,
86
+ :user_groups => JSS::UserGroup,
87
+ :user_group => JSS::UserGroup
88
+ }
89
+
90
+ ### Some things get checked in LDAP as well as the JSS
91
+ LDAP_USER_KEYS = [:user, :users]
92
+ LDAP_GROUP_KEYS = [:user_groups, :user_group]
93
+ CHECK_LDAP_KEYS = LDAP_USER_KEYS + LDAP_GROUP_KEYS
94
+
95
+ ### This hash maps the availble Scope Target keys from SCOPING_CLASSES to
96
+ ### their corresponding target group keys from SCOPING_CLASSES.
97
+ TARGETS_AND_GROUPS = {:computers => :computer_groups, :mobile_devices => :mobile_device_groups }
98
+
99
+ ### These can be part of the base inclusion list of the scope,
100
+ ### along with the appropriate target and target group keys
101
+ INCLUSIONS = [:buildings, :departments]
102
+
103
+ ### These can limit the inclusion list
104
+ LIMITATIONS = [:network_segments, :users, :user_groups]
105
+
106
+ ### any of them can be excluded
107
+ EXCLUSIONS = INCLUSIONS + LIMITATIONS
108
+
109
+ ### Here's a default scope as it might come from the API.
110
+ DEFAULT_SCOPE = {
111
+ :all_computers => true,
112
+ :all_mobile_devices => true,
113
+ :limitations => {},
114
+ :exclusions => {}
115
+ }
116
+
117
+
118
+
119
+ ######################
120
+ ### Attributes
121
+ ######################
122
+
123
+ ### @return [JSS::APIObject subclass]
124
+ ###
125
+ ### A reference to the object that contains this Scope
126
+ ###
127
+ ### For telling it when a change is made and an update needed
128
+ attr_accessor :container
129
+
130
+ ### @return [Boolean] should we expect a potential 409 Conflict
131
+ ### if we can't connect to LDAP servers for verification?
132
+ attr_accessor :unable_to_verify_ldap_entries
133
+
134
+ ### what type of target is this scope for? Computers or Mobiledevices?
135
+ attr_reader :target_class
136
+
137
+ ### @return [Hash<Array>]
138
+ ###
139
+ ### The items which form the base scope of included targets
140
+ ###
141
+ ### This is the group of targets to which the limitations and exclusions apply.
142
+ ### they keys are:
143
+ ### - :targets
144
+ ### - :target_groups
145
+ ### - :departments
146
+ ### - :buildings
147
+ ### and the values are Arrays of names of those things.
148
+ ###
149
+ attr_reader :inclusions
150
+
151
+ ### @return [Boolean]
152
+ ###
153
+ ### Does this scope cover all targets?
154
+ ###
155
+ ### If this is true, the @inclusions Hash is ignored, and all
156
+ ### targets in the JSS form the base scope.
157
+ ###
158
+ attr_reader :all_targets
159
+
160
+
161
+
162
+ ### @return [Hash<Array>]
163
+ ###
164
+ ### The items in these arrays are the limitations applied to targets in the @inclusions .
165
+ ###
166
+ ### The arrays of names are:
167
+ ### - :network_segments
168
+ ### - :users
169
+ ### - :user_groups
170
+ ###
171
+ attr_reader :limitations
172
+
173
+ ### @return [Hash<Array>]
174
+ ###
175
+ ### The items in these arrays are the exclusions applied to targets in the @inclusions .
176
+ ###
177
+ ### The arrays of names are:
178
+ ### - :targets
179
+ ### - :target_groups
180
+ ### - :departments
181
+ ### - :buildings
182
+ ### - :network_segments
183
+ ### - :users
184
+ ### - :user_groups
185
+ ###
186
+ attr_reader :exclusions
187
+
188
+
189
+ #####################################
190
+ ### Public Instance Methods
191
+ #####################################
192
+
193
+ ###
194
+ ### If api_scope is empty, a default scope, scoped to all targets, is created, and can be modified
195
+ ### as needed.
196
+ ###
197
+ ### @param target_key[Symbol] the kind of thing we're scopeing, one of {TARGETS_AND_GROUPS}
198
+ ###
199
+ ### @param api_scope[Hash] the JSON :scope data from an API query that is scopable, e.g. a Policy.
200
+ ###
201
+ def initialize(target_key, api_scope = DEFAULT_SCOPE)
202
+
203
+ raise JSS::InvalidDataError, "The target class of a Scope must be one of the symbols :#{TARGETS_AND_GROUPS.keys.join(', :')}" unless TARGETS_AND_GROUPS.keys.include? target_key
204
+
205
+ @target_key = target_key
206
+ @target_class = SCOPING_CLASSES[@target_key]
207
+ @group_key = TARGETS_AND_GROUPS[@target_key]
208
+ @group_class = SCOPING_CLASSES[@group_key]
209
+
210
+ @inclusion_keys = [@target_key, @group_key] + INCLUSIONS
211
+ @exclusion_keys = [@target_key, @group_key] + EXCLUSIONS
212
+
213
+ @all_key = "all_#{target_key}".to_sym
214
+ @all_targets = api_scope[@all_key]
215
+
216
+ ### Everything gets mapped from an Array of Hashes to an Array of names (or an empty array)
217
+ ### since names are all that really matter when submitting the scope.
218
+ @inclusions = {}
219
+ @inclusion_keys.each{|k| @inclusions[k] = api_scope[k] ? api_scope[k].map{|n| n[:name]} : [] }
220
+
221
+ @limitations = {}
222
+ if api_scope[:limitations]
223
+ LIMITATIONS.each{|k| @limitations[k] = api_scope[:limitations][k] ? api_scope[:limitations][k].map{|n| n[:name]} : [] }
224
+ end
225
+
226
+ @exclusions = {}
227
+ if api_scope[:exclusions]
228
+ @exclusion_keys.each{|k| @exclusions[k] = api_scope[:exclusions][k] ? api_scope[:exclusions][k].map{|n| n[:name]} : [] }
229
+ end
230
+
231
+ @container = nil
232
+
233
+ end # init
234
+
235
+ ###
236
+ ### Set the scope's inclusions to all targets.
237
+ ###
238
+ ### By default, the limitations and exclusions remain.
239
+ ### If a non-false parameter is provided, they will be removed also.
240
+ ###
241
+ ### @param clear[Boolean] Should the limitations and exclusions be removed also?
242
+ ###
243
+ ### @return [void]
244
+ ###
245
+ def include_all(clear = false)
246
+ @inclusions = {}
247
+ @inclusion_keys.each{|k| @inclusions[k] = []}
248
+ @all_targets = true
249
+ if clear
250
+ @limitations = {}
251
+ LIMITATIONS.each{|k| @limitations[k] = []}
252
+
253
+ @exclusions = {}
254
+ @exclusion_keys.each{|k| @exclusions[k] = []}
255
+ end
256
+ @container.should_update if @container
257
+ end
258
+
259
+
260
+ ###
261
+ ### Replace a list of item names for inclusion in this scope.
262
+ ###
263
+ ### The list must be an Array of names of items of the Class represented by the key.
264
+ ### Each will be checked for existence in the JSS, and an exception raised if the item doesn't exist.
265
+ ###
266
+ ### @param key[Symbol] the key from #{SCOPING_CLASSES} for the kind of items being included, :computer, :building, etc...
267
+ ###
268
+ ### @param list[Array] the names of the items being added
269
+ ###
270
+ ### @example
271
+ ### set_inclusion(:computers, ['kimchi','mantis'])
272
+ ###
273
+ ### @return [void]
274
+ ###
275
+ def set_inclusion(key, list)
276
+ raise JSS::InvalidDataError, "Inclusion key must be one of :#{@inclusion_keys.join(', :')}" unless @inclusion_keys.include? key
277
+ raise JSS::InvalidDataError, "List must be an Array of #{key} names, it may be empty." unless list.kind_of? Array
278
+
279
+ return nil if list.sort == @inclusions[key].sort
280
+
281
+ # emptying the list?
282
+ if list.empty?
283
+ @inclusion[key] = list
284
+ # if ALL the @inclusion keys are empty, then set all targets to true.
285
+ @all_targets = @inclusions.values.reject{|a| a.nil? or a.empty?}.empty?
286
+ @container.should_update if @container
287
+ return list
288
+ end
289
+
290
+ ### check the names
291
+ list.each do |name|
292
+ raise JSS::NoSuchItemError, "No existing #{key} with name '#{name}'" unless check_name key, name
293
+ raise JSS::AlreadyExistsError, "Can't set #{key} scope to '#{name}' because it's already an explicit exclusion." if @exclusions[key] and @exclusions[key].include? name
294
+ end # each
295
+
296
+ @inclusions[key] = list
297
+ @all_targets = false
298
+ @container.should_update if @container
299
+ end # sinclude_in_scope
300
+
301
+
302
+ ###
303
+ ### Add a single item for this inclusion in this scope.
304
+ ###
305
+ ### The item name will be checked for existence in the JSS, and an exception raised if the item doesn't exist.
306
+ ###
307
+ ### @param key[Symbol] the key from #{SCOPING_CLASSES} for the kind of item being added, :computer, :building, etc...
308
+ ###
309
+ ### @param item[String] the name of the item being added
310
+ ###
311
+ ### @example
312
+ ### add_inclusion(:computer, "mantis")
313
+ ###
314
+ ### @return [void]
315
+ ###
316
+ def add_inclusion (key, item)
317
+ raise JSS::InvalidDataError, "Inclusion key must be one of :#{@inclusion_keys.join(', :')}" unless @inclusion_keys.include? key
318
+ raise JSS::InvalidDataError, "Item must be a #{key} name." unless item.kind_of? String
319
+
320
+ return nil if @inclusions[key] and @inclusions[key].include? item
321
+
322
+ ### check the name
323
+ raise JSS::NoSuchItemError, "No existing #{key} with name '#{item}'" unless check_name key, item
324
+ raise JSS::AlreadyExistsError, "Can't set #{key} scope to '#{item}' because it's already an explicit exclusion." if @exclusions[key] and @exclusions[key].include? item
325
+
326
+
327
+ @inclusions[key] << item
328
+ @all_targets = false
329
+ @container.should_update if @container
330
+ end
331
+
332
+ ###
333
+ ### Remove a single item for this scope.
334
+ ###
335
+ ### @param key[Symbol] the key from #{SCOPING_CLASSES} for the kind of item being removed, :computer, :building, etc...
336
+ ###
337
+ ### @param item[String] the name of the item being removed
338
+ ###
339
+ ### @example
340
+ ### remove_inclusion(:computer, "mantis")
341
+ ###
342
+ ### @return [void]
343
+ ###
344
+ def remove_inclusion (key, item)
345
+ raise JSS::InvalidDataError, "Inclusion key must be one of :#{@inclusion_keys.join(', :')}" unless @inclusion_keys.include? key
346
+ raise JSS::InvalidDataError, "Item must be a #{key} name." unless item.kind_of? String
347
+
348
+ return nil unless @inclusions[key] and @inclusions[key].include? item
349
+
350
+ @inclusions[key] -= [item]
351
+
352
+ # if ALL the @inclusion keys are empty, then set all targets to true.
353
+ @all_targets = @inclusions.values.reject{|a| a.nil? or a.empty?}.empty?
354
+
355
+ @container.should_update if @container
356
+ end
357
+
358
+
359
+ ###
360
+ ### Replace a limitation list for this scope.
361
+ ###
362
+ ### The list must be an Array of names of items of the Class represented by the key.
363
+ ### Each will be checked for existence in the JSS, and an exception raised if the item doesn't exist.
364
+ ###
365
+ ### @param key[Symbol] the type of items being set as limitations, :network_segments, :users, etc...
366
+ ###
367
+ ### @param list[Array] the names of the items being set as limitations
368
+ ###
369
+ ### @example
370
+ ### set_limitation(:network_segments, ['foo','bar'])
371
+ ###
372
+ ### @return [void]
373
+ ###
374
+ ### @todo handle ldap user group lookups
375
+ ###
376
+ def set_limitation (key, list)
377
+ raise JSS::InvalidDataError, "Limitation key must be one of :#{LIMITATIONS.join(', :')}" unless LIMITATIONS.include? key
378
+ raise JSS::InvalidDataError, "List must be an Array of #{key} names, it may be empty." unless list.kind_of? Array
379
+ return nil if list.sort == @limitations[key].sort
380
+
381
+ if list.empty?
382
+ @limitations[key] = []
383
+ @container.should_update if @container
384
+ return list
385
+ end
386
+
387
+ ### check the names
388
+ list.each do |name|
389
+ raise JSS::NoSuchItemError, "No existing #{key} with name '#{name}'" unless check_name key, name
390
+ raise JSS::AlreadyExistsError, "Can't set #{key} limitation for '#{name}' because it's already an explicit exclusion." if @exclusions[key] and @exclusions[key].include? name
391
+ end # each
392
+
393
+ @limitations[key] = list
394
+ @container.should_update if @container
395
+ end # limit scope
396
+
397
+
398
+ ###
399
+ ### Add a single item for limiting this scope.
400
+ ###
401
+ ### The item name will be checked for existence in the JSS, and an exception raised if the item doesn't exist.
402
+ ###
403
+ ### @param key[Symbol] the type of item being added, :computer, :building, etc...
404
+ ###
405
+ ### @param item[String] the name of the item being added
406
+ ###
407
+ ### @example
408
+ ### add_limitation(:network_segments, "foo")
409
+ ###
410
+ ### @return [void]
411
+ ###
412
+ ### @todo handle ldap user/group lookups
413
+ ###
414
+ def add_limitation (key, item)
415
+ raise JSS::InvalidDataError, "Limitation key must be one of :#{LIMITATIONS.join(', :')}" unless LIMITATIONS.include? key
416
+ raise JSS::InvalidDataError, "Item must be a #{key} name." unless item.kind_of? String
417
+
418
+ return nil if @limitations[key] and @limitations[key].include? item
419
+
420
+ ### check the name
421
+ raise JSS::NoSuchItemError, "No existing #{key} with name '#{item}'" unless check_name key, item
422
+ raise JSS::AlreadyExistsError, "Can't set #{key} limitation for '#{name}' because it's already an explicit exclusion." if @exclusions[key] and @exclusions[key].include? item
423
+
424
+
425
+ @limitations[key] << item
426
+ @container.should_update if @container
427
+ end
428
+
429
+ ###
430
+ ### Remove a single item for limiting this scope.
431
+ ###
432
+ ### @param key[Symbol] the type of item being removed, :computer, :building, etc...
433
+ ###
434
+ ### @param item[String] the name of the item being removed
435
+ ###
436
+ ### @example
437
+ ### remove_limitation(:network_segments, "foo")
438
+ ###
439
+ ### @return [void]
440
+ ###
441
+ ### @todo handle ldap user/group lookups
442
+ ###
443
+ def remove_limitation( key, item)
444
+ raise JSS::InvalidDataError, "Limitation key must be one of :#{LIMITATIONS.join(', :')}" unless LIMITATIONS.include? key
445
+ raise JSS::InvalidDataError, "Item must be a #{key} name." unless item.kind_of? String
446
+
447
+ return nil unless @limitations[key] and @limitations[key].include? item
448
+
449
+ @limitations[key] -= [item]
450
+ @container.should_update if @container
451
+ end
452
+
453
+
454
+
455
+ ###
456
+ ### Replace an exclusion list for this scope
457
+ ###
458
+ ### The list must be an Array of names of items of the Class being excluded from the scope
459
+ ### Each will be checked for existence in the JSS, and an exception raised if the item doesn't exist.
460
+ ###
461
+ ### @param key[Symbol] the type of item being excluded, :computer, :building, etc...
462
+ ###
463
+ ### @param list[Array] the names of the items being added
464
+ ###
465
+ ### @example
466
+ ### set_exclusion(:network_segments, ['foo','bar'])
467
+ ###
468
+ ### @return [void]
469
+ ###
470
+ def set_exclusion (key, list)
471
+ raise JSS::InvalidDataError, "Exclusion key must be one of :#{@exclusion_keys.join(', :')}" unless @exclusion_keys.include? key
472
+ raise JSS::InvalidDataError, "List must be an Array of #{key} names, it may be empty." unless list.kind_of? Array
473
+ return nil if list.sort == @exclusions[key].sort
474
+
475
+ if list.empty?
476
+ @exclusions[key] = []
477
+ @container.should_update if @container
478
+ return list
479
+ end
480
+
481
+ ### check the names
482
+ list.each do |name|
483
+ raise JSS::NoSuchItemError, "No existing #{key} with name '#{name}'" unless check_name key, name
484
+ case key
485
+ when *@inclusion_keys
486
+ raise JSS::AlreadyExistsError, "Can't exclude #{key} '#{name}' because it's already explicitly included." if @inclusions[key] and @inclusions[key].include? name
487
+ when *LIMITATIONS
488
+ raise JSS::AlreadyExistsError, "Can't exclude #{key} '#{name}' because it's already an explicit limitation." if @limitations[key] and @limitations[key].include? name
489
+ end
490
+
491
+ end # each
492
+
493
+ @exclusions[key] = list
494
+ @container.should_update if @container
495
+ end # limit scope
496
+
497
+ ###
498
+ ### Add a single item for exclusions of this scope.
499
+ ###
500
+ ### The item name will be checked for existence in the JSS, and an exception raised if the item doesn't exist.
501
+ ###
502
+ ### @param key[Symbol] the type of item being added to the exclusions, :computer, :building, etc...
503
+ ###
504
+ ### @param item[String] the name of the item being added
505
+ ###
506
+ ### @example
507
+ ### add_exclusion(:network_segments, "foo")
508
+ ###
509
+ ### @return [void]
510
+ ###
511
+ def add_exclusion (key, item)
512
+ raise JSS::InvalidDataError, "Exclusion key must be one of :#{@exclusion_keys.join(', :')}" unless @exclusion_keys.include? key
513
+ raise JSS::InvalidDataError, "Item must be a #{key} name." unless item.kind_of? String
514
+
515
+ return nil if @exclusions[key] and @exclusions[key].include? item
516
+
517
+ ### check the name
518
+ raise JSS::NoSuchItemError, "No existing #{key} with name '#{item}'" unless check_name key, item
519
+ raise JSS::AlreadyExistsError, "Can't exclude #{key} scope to '#{item}' because it's already explicitly included." if @inclusions[key] and @inclusions[key].include? item
520
+ raise JSS::AlreadyExistsError, "Can't exclude #{key} '#{item}' because it's already an explicit limitation." if @limitations[key] and @limitations[key].include? item
521
+
522
+ @exclusions[key] << item
523
+ @container.should_update if @container
524
+ end
525
+
526
+ ###
527
+ ### Remove a single item for exclusions of this scope
528
+ ###
529
+ ### @param key[Symbol] the type of item being removed from the excludions, :computer, :building, etc...
530
+ ###
531
+ ### @param item[String] the name of the item being removed
532
+ ###
533
+ ### @example
534
+ ### remove_exclusion(:network_segments, "foo")
535
+ ###
536
+ ### @return [void]
537
+ ###
538
+ def remove_exclusion (key, item)
539
+ raise JSS::InvalidDataError, "Exclusion key must be one of :#{@exclusion_keys.join(', :')}" unless @exclusion_keys.include? key
540
+ raise JSS::InvalidDataError, "Item must be a #{key} name." unless item.kind_of? String
541
+
542
+ return nil unless @exclusions[key] and @exclusions[key].include? item
543
+
544
+ @exclusions[key] -= [item]
545
+ @container.should_update if @container
546
+ end
547
+
548
+ ###
549
+ ### @api private
550
+ ### Return a REXML Element containing the current state of the Scope
551
+ ### for adding into the XML of the container.
552
+ ###
553
+ ### @return [REXML::Element]
554
+ ###
555
+ def scope_xml
556
+ scope = REXML::Element.new "scope"
557
+ scope.add_element(@all_key.to_s).text = @all_targets
558
+
559
+ @inclusions.each do |klass,list|
560
+ list_as_hash = list.map{|i| {:name => i} }
561
+ scope << SCOPING_CLASSES[klass].xml_list( list_as_hash, :name)
562
+ end
563
+
564
+ limitations = scope.add_element('limitations')
565
+ @limitations.each do |klass,list|
566
+ list_as_hash = list.map{|i| {:name => i} }
567
+ limitations << SCOPING_CLASSES[klass].xml_list( list_as_hash, :name)
568
+ end
569
+
570
+ exclusions = scope.add_element('exclusions')
571
+ @exclusions.each do |klass,list|
572
+ list_as_hash = list.map{|i| {:name => i} }
573
+ exclusions << SCOPING_CLASSES[klass].xml_list( list_as_hash, :name)
574
+ end
575
+ return scope
576
+ end #scope_xml
577
+
578
+
579
+ ### Aliases
580
+
581
+ alias all_targets? all_targets
582
+
583
+
584
+ #####################################
585
+ ### Private Instance Methods
586
+ #####################################
587
+ private
588
+
589
+ ###
590
+ ### Given a name of some class of item to be used in the scope, check that it
591
+ ### exists in the JSS.
592
+ ###
593
+ ### @return [Boolean] does the name exist for the key in JSS or LDAP?
594
+ ###
595
+ def check_name(key, name)
596
+
597
+ found_in_jss = SCOPING_CLASSES[key].all_names.include?(name)
598
+
599
+ return true if found_in_jss
600
+
601
+ return false unless CHECK_LDAP_KEYS.include?(key)
602
+
603
+ begin
604
+ return JSS::LDAPServer.user_in_ldap?(name) if LDAP_USER_KEYS.include?(key)
605
+ return JSS::LDAPServer.group_in_ldap?(name) if LDAP_GROUP_KEYS.include?(key)
606
+
607
+ # if an ldap server isn't connected, make a note of it and return true
608
+ rescue JSS::InvalidConnectionError
609
+ @unable_to_verify_ldap_entries = true
610
+ return true
611
+ end # begin
612
+
613
+ return false
614
+ end
615
+
616
+
617
+
618
+ end # class Scope
619
+ end #module Scopable
620
+ end # module
621
+