ruby-jss 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

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
+