ruby-jss 1.2.3 → 1.2.4a1
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.
- checksums.yaml +4 -4
- data/lib/jamf.rb +169 -0
- data/lib/jamf/api/abstract_classes/collection_resource.rb +422 -0
- data/lib/jamf/api/abstract_classes/generic_reference.rb +145 -0
- data/lib/jamf/api/abstract_classes/json_object.rb +1074 -0
- data/lib/jamf/api/abstract_classes/prestage.rb +219 -0
- data/lib/jamf/api/abstract_classes/prestage_skip_setup_items.rb +126 -0
- data/lib/jamf/api/abstract_classes/resource.rb +250 -0
- data/lib/jamf/api/abstract_classes/singleton_resource.rb +87 -0
- data/lib/jamf/api/attribute_classes/ip_address.rb +66 -0
- data/lib/jamf/api/attribute_classes/timestamp.rb +144 -0
- data/lib/jamf/api/connection.rb +734 -0
- data/lib/jamf/api/connection/api_error.rb +111 -0
- data/lib/jamf/api/connection/api_error_styleguide.rb +96 -0
- data/lib/jamf/api/connection/token.rb +220 -0
- data/lib/jamf/api/json_objects/account_prefs.rb +79 -0
- data/lib/jamf/api/json_objects/android_details.rb +139 -0
- data/lib/jamf/api/json_objects/appletv_details.rb +110 -0
- data/lib/jamf/api/json_objects/attachment.rb +68 -0
- data/lib/jamf/api/json_objects/cellular_network.rb +151 -0
- data/lib/jamf/api/json_objects/change_log_entry.rb +77 -0
- data/lib/jamf/api/json_objects/computer_prestage_skip_setup_items.rb +67 -0
- data/lib/jamf/api/json_objects/country.rb +51 -0
- data/lib/jamf/api/json_objects/extension_attribute_value.rb +128 -0
- data/lib/jamf/api/json_objects/installed_application.rb +59 -0
- data/lib/jamf/api/json_objects/installed_certificate.rb +53 -0
- data/lib/jamf/api/json_objects/installed_configuration_profile.rb +67 -0
- data/lib/jamf/api/json_objects/installed_ebook.rb +58 -0
- data/lib/jamf/api/json_objects/installed_provisioning_profile.rb +59 -0
- data/lib/jamf/api/json_objects/inventory_preload_extension_attribute.rb +52 -0
- data/lib/jamf/api/json_objects/ios_details.rb +244 -0
- data/lib/jamf/api/json_objects/location.rb +95 -0
- data/lib/jamf/api/json_objects/md_prestage_name.rb +57 -0
- data/lib/jamf/api/json_objects/md_prestage_names.rb +82 -0
- data/lib/jamf/api/json_objects/md_prestage_skip_setup_items.rb +165 -0
- data/lib/jamf/api/json_objects/mobile_device_details.rb +219 -0
- data/lib/jamf/api/json_objects/mobile_device_security.rb +101 -0
- data/lib/jamf/api/json_objects/prestage_assignment.rb +61 -0
- data/lib/jamf/api/json_objects/prestage_location.rb +104 -0
- data/lib/jamf/api/json_objects/prestage_purchasing_data.rb +132 -0
- data/lib/jamf/api/json_objects/prestage_scope.rb +54 -0
- data/lib/jamf/api/json_objects/prestage_sync_status.rb +63 -0
- data/lib/jamf/api/json_objects/purchasing_data.rb +125 -0
- data/lib/jamf/api/mixins/abstract.rb +58 -0
- data/lib/jamf/api/mixins/bulk_deletable.rb +39 -0
- data/lib/jamf/api/mixins/change_log.rb +136 -0
- data/lib/jamf/api/mixins/extendable.rb +75 -0
- data/lib/jamf/api/mixins/immutable.rb +39 -0
- data/lib/jamf/api/mixins/locatable.rb +124 -0
- data/lib/jamf/api/mixins/lockable.rb +48 -0
- data/lib/jamf/api/mixins/referable.rb +92 -0
- data/lib/jamf/api/mixins/searchable.rb +202 -0
- data/lib/jamf/api/mixins/uncreatable.rb +40 -0
- data/lib/jamf/api/mixins/undeletable.rb +40 -0
- data/lib/jamf/api/resources/collection_resources/account.rb +163 -0
- data/lib/jamf/api/resources/collection_resources/building.rb +114 -0
- data/lib/jamf/api/resources/collection_resources/category.rb +82 -0
- data/lib/jamf/api/resources/collection_resources/computer.rb +49 -0
- data/lib/jamf/api/resources/collection_resources/computer_prestage.rb +80 -0
- data/lib/jamf/api/resources/collection_resources/department.rb +79 -0
- data/lib/jamf/api/resources/collection_resources/extension_attribute.rb +45 -0
- data/lib/jamf/api/resources/collection_resources/inventory_preload_record.rb +274 -0
- data/lib/jamf/api/resources/collection_resources/md_prestage.rb +139 -0
- data/lib/jamf/api/resources/collection_resources/mobile_device.rb +315 -0
- data/lib/jamf/api/resources/collection_resources/script.rb +190 -0
- data/lib/jamf/api/resources/collection_resources/site.rb +77 -0
- data/lib/jamf/api/resources/singleton_resources/app_store_country_codes.rb +131 -0
- data/lib/jamf/api/resources/singleton_resources/authorization.rb +88 -0
- data/lib/jamf/api/resources/singleton_resources/client_checkin_settings.rb +139 -0
- data/lib/jamf/api/resources/singleton_resources/reenrollment_settings.rb +95 -0
- data/lib/jamf/client.rb +301 -0
- data/lib/jamf/client/jamf_binary.rb +132 -0
- data/lib/jamf/client/jamf_helper.rb +298 -0
- data/lib/jamf/client/management_action.rb +114 -0
- data/lib/jamf/compatibility.rb +88 -0
- data/lib/jamf/composer.rb +190 -0
- data/lib/jamf/configuration.rb +281 -0
- data/lib/jamf/exceptions.rb +107 -0
- data/lib/jamf/ruby_extensions.rb +36 -0
- data/lib/jamf/ruby_extensions/array.rb +35 -0
- data/lib/jamf/ruby_extensions/array/predicates.rb +46 -0
- data/lib/jamf/ruby_extensions/array/utils.rb +47 -0
- data/lib/jamf/ruby_extensions/filetest.rb +32 -0
- data/lib/jamf/ruby_extensions/filetest/predicates.rb +46 -0
- data/lib/jamf/ruby_extensions/hash.rb +33 -0
- data/lib/jamf/ruby_extensions/hash/backports.rb +92 -0
- data/lib/jamf/ruby_extensions/ipaddr.rb +37 -0
- data/lib/jamf/ruby_extensions/ipaddr/utils.rb +95 -0
- data/lib/jamf/ruby_extensions/object.rb +30 -0
- data/lib/jamf/ruby_extensions/object/predicates.rb +51 -0
- data/lib/jamf/ruby_extensions/pathname.rb +39 -0
- data/lib/jamf/ruby_extensions/pathname/predicates.rb +50 -0
- data/lib/jamf/ruby_extensions/pathname/utils.rb +75 -0
- data/lib/jamf/ruby_extensions/string.rb +35 -0
- data/lib/jamf/ruby_extensions/string/backports.rb +66 -0
- data/lib/jamf/ruby_extensions/string/conversions.rb +65 -0
- data/lib/jamf/ruby_extensions/string/predicates.rb +47 -0
- data/lib/jamf/utility.rb +423 -0
- data/lib/jamf/validate.rb +224 -0
- data/lib/jamf/version.rb +32 -0
- data/lib/jpapi.rb +26 -0
- data/lib/jss/version.rb +1 -1
- metadata +104 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 25d16b4c34d2790bdf6175543f81a2125e80ddf0c2c49cbb76d340b76dd562df
|
4
|
+
data.tar.gz: a09cfceaaecd6c3109cafbd0d7912a1c66326c6c5ddaae479a4260816c50ede9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb2e1e6fb575db16ade4b819bbea3cfb73ce6956c1012569f2be10d757ed05f31c4671605065a6c619667afa3a2540119af0afee5cf506d1ae8455d4aa42d4c0
|
7
|
+
data.tar.gz: 4af7406b1457c0c70d4873578920938b942ed7b6ea15702898f74450453720f30b24803addf8762426f617b7e223ef34ae2d51453df5cf283da35c32d27a8854
|
data/lib/jamf.rb
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
# Copyright 2019 Pixar
|
2
|
+
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "Apache License")
|
5
|
+
# with the following modification; you may not use this file except in
|
6
|
+
# compliance with the Apache License and the following modification to it:
|
7
|
+
# Section 6. Trademarks. is deleted and replaced with:
|
8
|
+
#
|
9
|
+
# 6. Trademarks. This License does not grant permission to use the trade
|
10
|
+
# names, trademarks, service marks, or product names of the Licensor
|
11
|
+
# and its affiliates, except as required to comply with Section 4(c) of
|
12
|
+
# the License and to reproduce the content of the NOTICE file.
|
13
|
+
#
|
14
|
+
# You may obtain a copy of the Apache License at
|
15
|
+
#
|
16
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
17
|
+
#
|
18
|
+
# Unless required by applicable law or agreed to in writing, software
|
19
|
+
# distributed under the Apache License with the above modification is
|
20
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
21
|
+
# KIND, either express or implied. See the Apache License for the specific
|
22
|
+
# language governing permissions and limitations under the Apache License.
|
23
|
+
#
|
24
|
+
#
|
25
|
+
|
26
|
+
#
|
27
|
+
# JAMF, A Ruby module for interacting with a JAMF Pro Server via the JAMF API
|
28
|
+
#
|
29
|
+
|
30
|
+
### Standard Libraries
|
31
|
+
require 'English'
|
32
|
+
require 'json'
|
33
|
+
require 'yaml'
|
34
|
+
require 'pathname'
|
35
|
+
require 'time'
|
36
|
+
require 'singleton'
|
37
|
+
require 'open-uri'
|
38
|
+
require 'ipaddr'
|
39
|
+
require 'base64'
|
40
|
+
require 'shellwords'
|
41
|
+
require 'digest'
|
42
|
+
require 'open3'
|
43
|
+
|
44
|
+
|
45
|
+
### Gems
|
46
|
+
require 'rest-client'
|
47
|
+
require 'plist'
|
48
|
+
|
49
|
+
# Used, among other places, in the Connection::APIError class
|
50
|
+
require 'immutable-struct'
|
51
|
+
|
52
|
+
# TODO: needed?
|
53
|
+
# require 'recursive-open-struct'
|
54
|
+
|
55
|
+
# non-api parts of Jamf module
|
56
|
+
require 'jamf/configuration'
|
57
|
+
require 'jamf/exceptions'
|
58
|
+
require 'jamf/utility'
|
59
|
+
require 'jamf/validate'
|
60
|
+
require 'jamf/version'
|
61
|
+
|
62
|
+
# backports and extensions to existing Ruby classes
|
63
|
+
require 'jamf/compatibility'
|
64
|
+
require 'jamf/ruby_extensions'
|
65
|
+
|
66
|
+
# API connection
|
67
|
+
require 'jamf/api/connection'
|
68
|
+
|
69
|
+
|
70
|
+
# The main module.
|
71
|
+
# See README.md
|
72
|
+
#
|
73
|
+
module Jamf
|
74
|
+
|
75
|
+
# The minimum Ruby version that works with this gem
|
76
|
+
# 2.3 allows us to start using some nice features like the safe-navigation
|
77
|
+
# operator and Array#dig & Hash#dig, and such.
|
78
|
+
#
|
79
|
+
# For a list of features, see https://github.com/ruby/ruby/blob/v2_3_0/NEWS
|
80
|
+
# and http://nithinbekal.com/posts/ruby-2-3-features/
|
81
|
+
#
|
82
|
+
MINIMUM_RUBY_VERSION = '2.3'.freeze
|
83
|
+
|
84
|
+
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new(MINIMUM_RUBY_VERSION)
|
85
|
+
raise "Can't use the JAMF module, ruby itself must be version #{MINIMUM_RUBY_VERSION} or greater."
|
86
|
+
end
|
87
|
+
|
88
|
+
# AUTOLOADING
|
89
|
+
##################################
|
90
|
+
|
91
|
+
# Top-level API Abstract Classes
|
92
|
+
autoload :JSONObject, 'jamf/api/abstract_classes/json_object'
|
93
|
+
autoload :Resource, 'jamf/api/abstract_classes/resource'
|
94
|
+
autoload :SingletonResource, 'jamf/api/abstract_classes/singleton_resource'
|
95
|
+
autoload :CollectionResource, 'jamf/api/abstract_classes/collection_resource'
|
96
|
+
|
97
|
+
# Abstract Classes used for JSONObject subclasses
|
98
|
+
autoload :Prestage, 'jamf/api/abstract_classes/prestage'
|
99
|
+
autoload :PrestageSkipSetupItems, 'jamf/api/abstract_classes/prestage_skip_setup_items'
|
100
|
+
|
101
|
+
# Abstract Classes not used for JSONObject subclasses
|
102
|
+
autoload :GenericReference, 'jamf/api/abstract_classes/generic_reference'
|
103
|
+
|
104
|
+
# MixIn Modules
|
105
|
+
autoload :ChangeLog, 'jamf/api/mixins/change_log'
|
106
|
+
autoload :Extendable, 'jamf/api/mixins/extendable'
|
107
|
+
autoload :Locatable, 'jamf/api/mixins/locatable'
|
108
|
+
autoload :Referable, 'jamf/api/mixins/referable'
|
109
|
+
autoload :Searchable, 'jamf/api/mixins/searchable'
|
110
|
+
autoload :Lockable, 'jamf/api/mixins/lockable'
|
111
|
+
autoload :UnCreatable, 'jamf/api/mixins/uncreatable'
|
112
|
+
autoload :Immutable, 'jamf/api/mixins/immutable'
|
113
|
+
autoload :UnDeletable, 'jamf/api/mixins/undeletable'
|
114
|
+
autoload :Abstract, 'jamf/api/mixins/abstract'
|
115
|
+
|
116
|
+
# Utility modules
|
117
|
+
autoload :Validate, 'jamf/validate'
|
118
|
+
|
119
|
+
# Subclasses of JSONObject, but not Resource
|
120
|
+
autoload :AndroidDetails, 'jamf/api/json_objects/android_details'
|
121
|
+
autoload :AppleTVDetails, 'jamf/api/json_objects/appletv_details'
|
122
|
+
autoload :CellularNetwork, 'jamf/api/json_objects/cellular_network'
|
123
|
+
autoload :ChangeLogEntry, 'jamf/api/json_objects/change_log_entry'
|
124
|
+
autoload :ComputerPrestageSkipSetupItems, 'jamf/api/json_objects/computer_prestage_skip_setup_items'
|
125
|
+
autoload :Country, 'jamf/api/json_objects/country'
|
126
|
+
autoload :ExtensionAttributeValue, 'jamf/api/json_objects/extension_attribute_value'
|
127
|
+
autoload :InstalledApplication, 'jamf/api/json_objects/installed_application'
|
128
|
+
autoload :InstalledCertificate, 'jamf/api/json_objects/installed_certificate'
|
129
|
+
autoload :InstalledConfigurationProfile, 'jamf/api/json_objects/installed_configuration_profile'
|
130
|
+
autoload :InstalledEBook, 'jamf/api/json_objects/installed_ebook'
|
131
|
+
autoload :InstalledProvisioningProfile, 'jamf/api/json_objects/installed_provisioning_profile'
|
132
|
+
autoload :InventoryPreloadExtensionAttribute, 'jamf/api/json_objects/inventory_preload_extension_attribute'
|
133
|
+
autoload :IosDetails, 'jamf/api/json_objects/ios_details'
|
134
|
+
autoload :Location, 'jamf/api/json_objects/location'
|
135
|
+
autoload :PrestageLocation, 'jamf/api/json_objects/prestage_location'
|
136
|
+
autoload :PrestageSyncStatus, 'jamf/api/json_objects/prestage_sync_status'
|
137
|
+
autoload :MobileDeviceDetails, 'jamf/api/json_objects/mobile_device_details'
|
138
|
+
autoload :MobileDeviceSecurity, 'jamf/api/json_objects/mobile_device_security'
|
139
|
+
autoload :MobileDevicePrestageName, 'jamf/api/json_objects/md_prestage_name'
|
140
|
+
autoload :MobileDevicePrestageNames, 'jamf/api/json_objects/md_prestage_names'
|
141
|
+
autoload :MobileDevicePrestageSkipSetupItems, 'jamf/api/json_objects/md_prestage_skip_setup_items'
|
142
|
+
autoload :PurchasingData, 'jamf/api/json_objects/purchasing_data'
|
143
|
+
autoload :PrestagePurchasingData, 'jamf/api/json_objects/prestage_purchasing_data'
|
144
|
+
autoload :PrestageScope, 'jamf/api/json_objects/prestage_scope'
|
145
|
+
autoload :PrestageAssignment, 'jamf/api/json_objects/prestage_assignment'
|
146
|
+
|
147
|
+
# Subclasses of SingletonResource
|
148
|
+
autoload :ClientCheckInSettings, 'jamf/api/resources/singleton_resources/client_checkin_settings'
|
149
|
+
autoload :ReEnrollmentSettings, 'jamf/api/resources/singleton_resources/reenrollment_settings'
|
150
|
+
autoload :AppStoreCountryCodes, 'jamf/api/resources/singleton_resources/app_store_country_codes'
|
151
|
+
|
152
|
+
# Subclasses of CollectionResource
|
153
|
+
autoload :Attachment, 'jamf/api/resources/collection_resources/attachment'
|
154
|
+
autoload :Building, 'jamf/api/resources/collection_resources/building'
|
155
|
+
autoload :Computer, 'jamf/api/resources/collection_resources/computer'
|
156
|
+
autoload :ComputerPrestage, 'jamf/api/resources/collection_resources/computer_prestage'
|
157
|
+
autoload :Department, 'jamf/api/resources/collection_resources/department'
|
158
|
+
autoload :ExtensionAttribute, 'jamf/api/resources/collection_resources/extension_attribute'
|
159
|
+
autoload :InventoryPreloadRecord, 'jamf/api/resources/collection_resources/inventory_preload_record'
|
160
|
+
autoload :MobileDevice, 'jamf/api/resources/collection_resources/mobile_device'
|
161
|
+
autoload :MobileDevicePrestage, 'jamf/api/resources/collection_resources/md_prestage'
|
162
|
+
autoload :Site, 'jamf/api/resources/collection_resources/site'
|
163
|
+
autoload :Script, 'jamf/api/resources/collection_resources/script'
|
164
|
+
|
165
|
+
# other classes used as attributes inside the resource classes
|
166
|
+
autoload :IPAddress, 'jamf/api/attribute_classes/ip_address'
|
167
|
+
autoload :Timestamp, 'jamf/api/attribute_classes/timestamp'
|
168
|
+
|
169
|
+
end # module
|
@@ -0,0 +1,422 @@
|
|
1
|
+
# Copyright 2019 Pixar
|
2
|
+
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "Apache License")
|
5
|
+
# with the following modification; you may not use this file except in
|
6
|
+
# compliance with the Apache License and the following modification to it:
|
7
|
+
# Section 6. Trademarks. is deleted and replaced with:
|
8
|
+
#
|
9
|
+
# 6. Trademarks. This License does not grant permission to use the trade
|
10
|
+
# names, trademarks, service marks, or product names of the Licensor
|
11
|
+
# and its affiliates, except as required to comply with Section 4(c) of
|
12
|
+
# the License and to reproduce the content of the NOTICE file.
|
13
|
+
#
|
14
|
+
# You may obtain a copy of the Apache License at
|
15
|
+
#
|
16
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
17
|
+
#
|
18
|
+
# Unless required by applicable law or agreed to in writing, software
|
19
|
+
# distributed under the Apache License with the above modification is
|
20
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
21
|
+
# KIND, either express or implied. See the Apache License for the specific
|
22
|
+
# language governing permissions and limitations under the Apache License.
|
23
|
+
#
|
24
|
+
#
|
25
|
+
|
26
|
+
# The module
|
27
|
+
module Jamf
|
28
|
+
|
29
|
+
# A Collection Resource in Jamf Pro
|
30
|
+
#
|
31
|
+
# See {Jamf::Resource} for general info about API resources.
|
32
|
+
#
|
33
|
+
# Collection resources have more than one resource within them, and those
|
34
|
+
# can (usually) be created and deleted as well as fetched and updated.
|
35
|
+
# The entire collection (or a part of it) can also be fetched as an Array.
|
36
|
+
# When the whole collection is fetched, the result is cached for future use.
|
37
|
+
#
|
38
|
+
# # Subclassing
|
39
|
+
#
|
40
|
+
# ## Creatability, & Deletability
|
41
|
+
#
|
42
|
+
# Sometimes the API doesn't support creation of new members of the collection.
|
43
|
+
# If that's the case, just extend the subclass with Jamf::UnCreatable
|
44
|
+
# and the '.create' class method will raise an error.
|
45
|
+
#
|
46
|
+
# Similarly for deletion of members: if the API doesn't have a way to delete
|
47
|
+
# them, extend the subclass with Jamf::UnDeletable
|
48
|
+
#
|
49
|
+
# See also Jamf::JSONObject, which talks about extending subclasses
|
50
|
+
# with Jamf::Immutable
|
51
|
+
#
|
52
|
+
# ## Bulk Deletion
|
53
|
+
#
|
54
|
+
# Some collection resources have a resource for bulk deletion, passing in
|
55
|
+
# a JSON array of ids to delete.
|
56
|
+
#
|
57
|
+
# If so, just define a BULK_DELETE_RSRC, and the .delete class method
|
58
|
+
# will use it, rather than making multiple calls to delete individual
|
59
|
+
# items. See Jamf::Category::BULK_DELETE_RSRC for an example
|
60
|
+
#
|
61
|
+
# @abstract
|
62
|
+
#
|
63
|
+
class CollectionResource < Jamf::Resource
|
64
|
+
|
65
|
+
extend Jamf::Abstract
|
66
|
+
include Comparable
|
67
|
+
|
68
|
+
# Public Class Methods
|
69
|
+
#####################################
|
70
|
+
|
71
|
+
# @return [Array<Symbol>] the attribute names that are marked as identifiers
|
72
|
+
#
|
73
|
+
def self.identifiers
|
74
|
+
self::OBJECT_MODEL.select { |_attr, deets| deets[:identifier] }.keys
|
75
|
+
end
|
76
|
+
|
77
|
+
# An array of attribute names that are required when
|
78
|
+
# making new CollectionResources
|
79
|
+
# See the OBJECT_MODEL documentation in {Jamf::JSONObject}
|
80
|
+
def self.required_attributes
|
81
|
+
self::OBJECT_MODEL.select { |_attr, deets| deets[:required] }.keys
|
82
|
+
end
|
83
|
+
|
84
|
+
# The Collection members Array for this class, retrieved from
|
85
|
+
# the RSRC_PATH as Parsed JSON, but not instantiated into instances
|
86
|
+
# unless instantiate: is truthy.
|
87
|
+
#
|
88
|
+
# E.g. for {Jamf::Settings::Building}, this would be the Array of Hashes
|
89
|
+
# returned by GETing the resource .../settings/obj/building
|
90
|
+
#
|
91
|
+
# This Array is cached in the {Jamf::Connection} instance used to
|
92
|
+
# retrieve it, and future calls to .all will return the cached Array
|
93
|
+
# unless refresh is truthy.
|
94
|
+
#
|
95
|
+
# TODO: Investigate https://www.rubydoc.info/github/mloughran/api_cache
|
96
|
+
#
|
97
|
+
# @param refresh[Boolean] re-read the data from the API?
|
98
|
+
#
|
99
|
+
# @param cnx[Jamf::Connection] an API connection to use for the query.
|
100
|
+
# Defaults to the corrently active connection. See {Jamf::Connection}
|
101
|
+
#
|
102
|
+
# @param instantiate[Boolean] The Array contains instances of this class
|
103
|
+
# rather than the JSON Hashes from the API.
|
104
|
+
#
|
105
|
+
# @return [Array<Object>] An Array of all objects of this class in the JSS.
|
106
|
+
#
|
107
|
+
def self.all(refresh = false, cnx: Jamf.cnx, instantiate: false)
|
108
|
+
validate_not_abstract
|
109
|
+
cnx.collection_cache[self] = nil if refresh
|
110
|
+
return cnx.collection_cache[self] if cnx.collection_cache[self]
|
111
|
+
|
112
|
+
raw = cnx.get rsrc_path
|
113
|
+
cnx.collection_cache[self] =
|
114
|
+
if raw.is_a?(Hash) && raw[:results]
|
115
|
+
raw[:results]
|
116
|
+
else
|
117
|
+
raw
|
118
|
+
end
|
119
|
+
|
120
|
+
return cnx.collection_cache[self] unless instantiate
|
121
|
+
|
122
|
+
cnx.collection_cache[self].map { |m| new m }
|
123
|
+
end
|
124
|
+
|
125
|
+
# An array of the ids for all collection members
|
126
|
+
#
|
127
|
+
# @param refresh (see .all)
|
128
|
+
#
|
129
|
+
# @param cnx (see .all)
|
130
|
+
#
|
131
|
+
# @return [Array<Integer>]
|
132
|
+
#
|
133
|
+
def self.all_ids(refresh = false, cnx: Jamf.cnx)
|
134
|
+
all(refresh, cnx: cnx).map { |m| m[:id] }
|
135
|
+
end
|
136
|
+
|
137
|
+
# rubocop:disable Naming/UncommunicativeMethodParamName
|
138
|
+
|
139
|
+
# A Hash of all members of this collection where the keys are some
|
140
|
+
# identifier and values are any other attribute.
|
141
|
+
#
|
142
|
+
# @param ident [Symbol] An identifier of this Class, used as the key
|
143
|
+
# for the mapping Hash.
|
144
|
+
#
|
145
|
+
# @param to [Symbol] The attribute to which the ident will be mapped
|
146
|
+
#
|
147
|
+
# @param refresh (see .all)
|
148
|
+
#
|
149
|
+
# @param cnx (see .all)
|
150
|
+
#
|
151
|
+
# @return [Hash {Symbol: Object}] A Hash of identifier mapped to attribute
|
152
|
+
#
|
153
|
+
def self.map_all(ident, to:, cnx: Jamf.cnx, refresh: false)
|
154
|
+
raise Jamf::InvalidDataError, "No identifier #{ident} for class #{self}" unless
|
155
|
+
identifiers.include? ident
|
156
|
+
|
157
|
+
raise Jamf::NoSuchItemError, "No attribute #{to} for class #{self}" unless self::OBJECT_MODEL.key? to
|
158
|
+
|
159
|
+
list = all refresh, cnx: cnx
|
160
|
+
to_class = self::OBJECT_MODEL[to][:class]
|
161
|
+
mapped = list.map do |i|
|
162
|
+
[
|
163
|
+
i[ident],
|
164
|
+
to_class.is_a?(Symbol) ? i[to] : to_class.new(i[to])
|
165
|
+
]
|
166
|
+
end # do i
|
167
|
+
mapped.to_h
|
168
|
+
end
|
169
|
+
# rubocop:enable Naming/UncommunicativeMethodParamName
|
170
|
+
|
171
|
+
# Given any identfier value for this collection, return the valid
|
172
|
+
# id, or nil if there's no match for the given value.
|
173
|
+
#
|
174
|
+
# If you know the value is a certain identifier, e.g. a serial_number
|
175
|
+
# then you can specify the identifier, for a faster search:
|
176
|
+
#
|
177
|
+
# valid_id serial_number: 'AB12DE34' # => Int or nil
|
178
|
+
#
|
179
|
+
# If you don't know wich identifier you have, just pass the value and
|
180
|
+
# all identifiers are searched
|
181
|
+
#
|
182
|
+
# valid_id 'AB12DE34' # => Int or nil
|
183
|
+
# valid_id 'SomeComputerName' # => Int or nil
|
184
|
+
#
|
185
|
+
# When the value is a string, the seach is case-insensitive
|
186
|
+
#
|
187
|
+
# TODO: When 'Searchability' is more dialed in via the searchable
|
188
|
+
# mixin, which implements enpoints like 'POST /v1/search-mobile-devices'
|
189
|
+
# then use that before using the 'all' list.
|
190
|
+
#
|
191
|
+
# @param value [Object] A value to search for as an identifier.
|
192
|
+
#
|
193
|
+
# @param refresh[Boolean] Reload the list data from the API
|
194
|
+
#
|
195
|
+
# @param ident: [Symbol] Restrict the search to this identifier.
|
196
|
+
# E.g. if :serial_number, then the value must be
|
197
|
+
# a known serial number, it is not checked against other identifiers
|
198
|
+
#
|
199
|
+
# @param cnx: (see .all)
|
200
|
+
#
|
201
|
+
# @return [Object, nil] the primary identifier of the matching object,
|
202
|
+
# or nil if it doesn't exist
|
203
|
+
#
|
204
|
+
def self.valid_id(value = nil, refresh: true, cnx: Jamf.cnx, **ident_hash)
|
205
|
+
unless ident_hash.empty?
|
206
|
+
ident, value = ident_hash.first
|
207
|
+
return id_from_other_ident ident, value, refresh, cnx: cnx
|
208
|
+
end
|
209
|
+
|
210
|
+
# check the id itself first
|
211
|
+
return value if all_ids(refresh, cnx: cnx).include? value
|
212
|
+
|
213
|
+
idents = identifiers - [:id]
|
214
|
+
val_is_str = value.is_a? String
|
215
|
+
|
216
|
+
idents.each do |ident|
|
217
|
+
match = all(cnx: cnx).select do |m|
|
218
|
+
val_is_str ? m[ident].to_s.casecmp?(value) : m[ident] == value
|
219
|
+
end.first
|
220
|
+
return match[:id] if match
|
221
|
+
end # identifiers.each do |ident|
|
222
|
+
|
223
|
+
nil
|
224
|
+
end
|
225
|
+
|
226
|
+
# Bu default, subclasses are creatable, i.e. new instances can be created
|
227
|
+
# with .create, and added to the JSS with .save
|
228
|
+
# If a subclass is NOT creatble for any reason, just add
|
229
|
+
# extend Jamf::UnCreatable
|
230
|
+
# and this method will return false
|
231
|
+
#
|
232
|
+
# @return [Boolean]
|
233
|
+
def self.creatable?
|
234
|
+
true
|
235
|
+
end
|
236
|
+
|
237
|
+
# Make a new thing to be added to the API
|
238
|
+
def self.create(params, cnx: Jamf.cnx)
|
239
|
+
raise Jamf::UnsupportedError, "#{self}'s are not currently creatable via the API" unless self.creatable?
|
240
|
+
|
241
|
+
validate_not_abstract
|
242
|
+
|
243
|
+
validate_required_attributes params
|
244
|
+
|
245
|
+
params.delete :id # no such animal when .creating
|
246
|
+
params[:creating_from_create] = true
|
247
|
+
new params, cnx: cnx
|
248
|
+
end
|
249
|
+
|
250
|
+
# Retrieve a member of a CollectionResource from the API
|
251
|
+
#
|
252
|
+
# To create new members to be added to the JSS, use
|
253
|
+
# {Jamf::CollectionResource.create}
|
254
|
+
#
|
255
|
+
# If you know the specific identifier attribute you're looking up, e.g.
|
256
|
+
# :id or :name or :udid, (or an aliase thereof) then you can specify it like
|
257
|
+
# `.fetch name: 'somename'`, or `.fetch udid: 'someudid'`
|
258
|
+
#
|
259
|
+
# If you don't know if (or don't want to type it) you can just use
|
260
|
+
# `.fetch 'somename'`, or `.fetch 'someudid'` and all identifiers will be
|
261
|
+
# searched for a match.
|
262
|
+
#
|
263
|
+
# @param ident_value[Object] A value for any identifier for this subclass.
|
264
|
+
# All identifier attributes will be searched for a match.
|
265
|
+
#
|
266
|
+
# @param cnx[Jamf::Connection] the connection to use to fetch the object
|
267
|
+
#
|
268
|
+
# @param ident_hash[Hash] an identifier attribute key and a search value
|
269
|
+
#
|
270
|
+
# @return [CollectionResource] The ruby-instance of a Jamf object
|
271
|
+
#
|
272
|
+
def self.fetch(ident_value = nil, cnx: Jamf.cnx, **ident_hash)
|
273
|
+
validate_not_abstract
|
274
|
+
id =
|
275
|
+
if ident_value == :random
|
276
|
+
all_ids.sample
|
277
|
+
elsif ident_value
|
278
|
+
valid_id ident_value
|
279
|
+
elsif ident_hash.empty?
|
280
|
+
nil
|
281
|
+
else
|
282
|
+
ident, lookup_value = ident_hash.first
|
283
|
+
valid_id ident => lookup_value
|
284
|
+
end
|
285
|
+
|
286
|
+
raise Jamf::NoSuchItemError, "No matching #{self}" unless id
|
287
|
+
|
288
|
+
data = cnx.get "#{rsrc_path}/#{id}"
|
289
|
+
new data, cnx: cnx
|
290
|
+
end # fetch
|
291
|
+
|
292
|
+
# By default, CollectionResource subclass instances are deletable.
|
293
|
+
# If not, just extend the subclass with Jamf::UnDeletable, and this
|
294
|
+
# will return false, and .delete & #delete will raise errors
|
295
|
+
def self.deletable?
|
296
|
+
true
|
297
|
+
end
|
298
|
+
|
299
|
+
# Delete one or more objects by identifier
|
300
|
+
# Any valid identifier for the class can be used (id, name, udid, etc)
|
301
|
+
# Identifiers can be provided as an array or as separate parameters
|
302
|
+
#
|
303
|
+
# e.g. .delete [1,3, 34, 4]
|
304
|
+
# or .delete 'myComputer', 'that-computer', 'OtherComputer'
|
305
|
+
#
|
306
|
+
# @param idents[Array<integer>, Integer]
|
307
|
+
#
|
308
|
+
# @param cnx[Jamf::Connection]
|
309
|
+
#
|
310
|
+
# @return [Array] the identifiers that were not found, so couldn't be deleted
|
311
|
+
#
|
312
|
+
def self.delete(*idents, cnx: Jamf.cnx)
|
313
|
+
raise Jamf::UnsupportedError, "Deleting #{self} objects is not currently supported" unless deletable?
|
314
|
+
|
315
|
+
idents.flatten!
|
316
|
+
no_valid_ids = []
|
317
|
+
|
318
|
+
idents.map do |ident|
|
319
|
+
id = valid_id ident
|
320
|
+
no_valid_ids << ident unless id
|
321
|
+
id
|
322
|
+
end
|
323
|
+
idents.compact!
|
324
|
+
|
325
|
+
# TODO: some rsrcs have a 'bulk delete' version...
|
326
|
+
idents.each { |id| cnx.delete "#{rsrc_path}/#{id}" }
|
327
|
+
|
328
|
+
no_valid_ids
|
329
|
+
end
|
330
|
+
|
331
|
+
# Private Class Methods
|
332
|
+
#####################################
|
333
|
+
|
334
|
+
# TODO: better pluralizing?
|
335
|
+
#
|
336
|
+
def self.create_list_methods(attr_name, attr_def)
|
337
|
+
list_method_name = "all_#{attr_name}s"
|
338
|
+
|
339
|
+
define_singleton_method(list_method_name) do |refresh = false, cnx: Jamf.cnx|
|
340
|
+
all_list = all(refresh, cnx: cnx)
|
341
|
+
if attr_def[:class].is_a? Symbol
|
342
|
+
all_list.map { |i| i[attr_name] }.uniq
|
343
|
+
else
|
344
|
+
all_list.map { |i| attr_def[:class].new i[attr_name] }
|
345
|
+
end
|
346
|
+
end # define_singleton_method
|
347
|
+
|
348
|
+
return unless attr_def[:aliases]
|
349
|
+
|
350
|
+
# aliases - TODO: is there a more elegant way?
|
351
|
+
attr_def[:aliases].each do |a|
|
352
|
+
define_singleton_method("all_#{a}s") do |refresh = false, cnx: Jamf.cnx|
|
353
|
+
send list_method_name, refresh, cnx: cnx
|
354
|
+
end # define_singleton_method
|
355
|
+
end # each alias
|
356
|
+
end # create_list_methods
|
357
|
+
private_class_method :create_list_methods
|
358
|
+
|
359
|
+
# validate that our .create data has the required attribute values.
|
360
|
+
# They can't be nil or empty.
|
361
|
+
#
|
362
|
+
def self.validate_required_attributes(data)
|
363
|
+
required_attributes.each do |atr|
|
364
|
+
raise Jamf::MissingDataError, "Required attribute '#{atr}:' may not be nil or empty" if data[atr].to_s.empty?
|
365
|
+
end
|
366
|
+
end
|
367
|
+
private_class_method :validate_required_attributes
|
368
|
+
|
369
|
+
# Given an indentier attr. key, and a value,
|
370
|
+
# return the id where that ident has that value, or nil
|
371
|
+
#
|
372
|
+
def self.id_from_other_ident(ident, value, refresh = true, cnx: Jamf.cnx)
|
373
|
+
raise ArgumentError, "Unknown identifier '#{ident}' for #{self}" unless identifiers.include? ident
|
374
|
+
|
375
|
+
# check the id itself first
|
376
|
+
return value if ident == :id && all_ids(refresh, cnx: cnx).include?(value)
|
377
|
+
|
378
|
+
# all ident values => ids
|
379
|
+
ident_map = map_all(ident, to: :id, cnx: cnx, refresh: refresh)
|
380
|
+
|
381
|
+
# case-insensitivity for string values
|
382
|
+
value = ident_map.keys.j_ci_fetch_string(value) if value.is_a? String
|
383
|
+
|
384
|
+
ident_map[value]
|
385
|
+
end
|
386
|
+
private_class_method :id_from_other_ident
|
387
|
+
|
388
|
+
|
389
|
+
# Instance Methods
|
390
|
+
#####################################
|
391
|
+
|
392
|
+
def exist?
|
393
|
+
!@id.nil?
|
394
|
+
end
|
395
|
+
|
396
|
+
def rsrc_path
|
397
|
+
return unless exist?
|
398
|
+
"#{self.class.rsrc_path}/#{@id}"
|
399
|
+
end
|
400
|
+
|
401
|
+
def delete
|
402
|
+
raise Jamf::UnsupportedError, "Deleting #{self} objects is not currently supported" unless self.class.deletable?
|
403
|
+
@cnx.delete rsrc_path
|
404
|
+
end
|
405
|
+
|
406
|
+
# Two collection resource objects are the same if their id's are the same
|
407
|
+
def <=>(other)
|
408
|
+
id <=> other.id
|
409
|
+
end
|
410
|
+
|
411
|
+
# Private Instance Methods
|
412
|
+
############################################
|
413
|
+
private
|
414
|
+
|
415
|
+
def create_in_jamf
|
416
|
+
result = @cnx.post self.class.rsrc_path, to_jamf
|
417
|
+
@id = result[:id]
|
418
|
+
end
|
419
|
+
|
420
|
+
end # class CollectionResource
|
421
|
+
|
422
|
+
end # module JAMF
|