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.
- checksums.yaml +7 -0
- data/.yardopts +7 -0
- data/CHANGES.md +112 -0
- data/LICENSE.txt +174 -0
- data/README.md +426 -0
- data/THANKS.md +6 -0
- data/bin/cgrouper +485 -0
- data/bin/subnet-update +400 -0
- data/lib/jss-api.rb +2 -0
- data/lib/jss.rb +190 -0
- data/lib/jss/api_connection.rb +410 -0
- data/lib/jss/api_object.rb +616 -0
- data/lib/jss/api_object/advanced_search.rb +389 -0
- data/lib/jss/api_object/advanced_search/advanced_computer_search.rb +95 -0
- data/lib/jss/api_object/advanced_search/advanced_mobile_device_search.rb +96 -0
- data/lib/jss/api_object/advanced_search/advanced_user_search.rb +95 -0
- data/lib/jss/api_object/building.rb +92 -0
- data/lib/jss/api_object/category.rb +147 -0
- data/lib/jss/api_object/computer.rb +852 -0
- data/lib/jss/api_object/creatable.rb +98 -0
- data/lib/jss/api_object/criteriable.rb +189 -0
- data/lib/jss/api_object/criteriable/criteria.rb +231 -0
- data/lib/jss/api_object/criteriable/criterion.rb +228 -0
- data/lib/jss/api_object/department.rb +93 -0
- data/lib/jss/api_object/distribution_point.rb +560 -0
- data/lib/jss/api_object/extendable.rb +221 -0
- data/lib/jss/api_object/extension_attribute.rb +466 -0
- data/lib/jss/api_object/extension_attribute/computer_extension_attribute.rb +362 -0
- data/lib/jss/api_object/extension_attribute/mobile_device_extension_attribute.rb +189 -0
- data/lib/jss/api_object/extension_attribute/user_extension_attribute.rb +117 -0
- data/lib/jss/api_object/group.rb +380 -0
- data/lib/jss/api_object/group/computer_group.rb +124 -0
- data/lib/jss/api_object/group/mobile_device_group.rb +139 -0
- data/lib/jss/api_object/group/user_group.rb +139 -0
- data/lib/jss/api_object/ldap_server.rb +535 -0
- data/lib/jss/api_object/locatable.rb +286 -0
- data/lib/jss/api_object/matchable.rb +97 -0
- data/lib/jss/api_object/mobile_device.rb +556 -0
- data/lib/jss/api_object/netboot_server.rb +148 -0
- data/lib/jss/api_object/network_segment.rb +414 -0
- data/lib/jss/api_object/osx_configuration_profile.rb +262 -0
- data/lib/jss/api_object/package.rb +839 -0
- data/lib/jss/api_object/peripheral.rb +335 -0
- data/lib/jss/api_object/peripheral_type.rb +295 -0
- data/lib/jss/api_object/policy.rb +898 -0
- data/lib/jss/api_object/purchasable.rb +316 -0
- data/lib/jss/api_object/removable_macaddr.rb +98 -0
- data/lib/jss/api_object/scopable.rb +136 -0
- data/lib/jss/api_object/scopable/scope.rb +621 -0
- data/lib/jss/api_object/script.rb +631 -0
- data/lib/jss/api_object/self_servable.rb +356 -0
- data/lib/jss/api_object/site.rb +93 -0
- data/lib/jss/api_object/software_update_server.rb +109 -0
- data/lib/jss/api_object/updatable.rb +117 -0
- data/lib/jss/api_object/uploadable.rb +138 -0
- data/lib/jss/api_object/user.rb +272 -0
- data/lib/jss/client.rb +504 -0
- data/lib/jss/compatibility.rb +66 -0
- data/lib/jss/composer.rb +185 -0
- data/lib/jss/configuration.rb +306 -0
- data/lib/jss/db_connection.rb +298 -0
- data/lib/jss/exceptions.rb +95 -0
- data/lib/jss/ruby_extensions.rb +35 -0
- data/lib/jss/ruby_extensions/filetest.rb +43 -0
- data/lib/jss/ruby_extensions/hash.rb +79 -0
- data/lib/jss/ruby_extensions/ipaddr.rb +91 -0
- data/lib/jss/ruby_extensions/pathname.rb +77 -0
- data/lib/jss/ruby_extensions/string.rb +59 -0
- data/lib/jss/ruby_extensions/time.rb +63 -0
- data/lib/jss/server.rb +108 -0
- data/lib/jss/utility.rb +478 -0
- data/lib/jss/version.rb +31 -0
- metadata +187 -0
@@ -0,0 +1,228 @@
|
|
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 Criteriable
|
29
|
+
|
30
|
+
#####################################
|
31
|
+
### Module Variables
|
32
|
+
#####################################
|
33
|
+
|
34
|
+
#####################################
|
35
|
+
### Module Methods
|
36
|
+
#####################################
|
37
|
+
|
38
|
+
#####################################
|
39
|
+
### Classes
|
40
|
+
#####################################
|
41
|
+
|
42
|
+
### This class defines a single criterion used in advanced searches and
|
43
|
+
### smart groups throughout the JSS module.
|
44
|
+
###
|
45
|
+
### They are used within {JSS::Criteriable::Criteria} instances which store an
|
46
|
+
### array of these objects and provides methods for working with them as a group.
|
47
|
+
###
|
48
|
+
### The classes that mix-in {JSS::Criteriable} each have a :criteria attribute which
|
49
|
+
### holds one {JSS::Criteriable::Criteria}
|
50
|
+
###
|
51
|
+
### See {JSS::Criteriable} for examples
|
52
|
+
###
|
53
|
+
class Criterion
|
54
|
+
|
55
|
+
#####################################
|
56
|
+
### Mix Ins
|
57
|
+
#####################################
|
58
|
+
|
59
|
+
include Comparable # this allows us compare instances using <=>
|
60
|
+
|
61
|
+
#####################################
|
62
|
+
### Class Constants
|
63
|
+
#####################################
|
64
|
+
|
65
|
+
### These are the available search-types for building criteria
|
66
|
+
SEARCH_TYPES = [
|
67
|
+
"is",
|
68
|
+
"is not",
|
69
|
+
"like",
|
70
|
+
"not like",
|
71
|
+
"has",
|
72
|
+
"does not have",
|
73
|
+
"more than",
|
74
|
+
"less than",
|
75
|
+
"before (yyyy-mm-dd)",
|
76
|
+
"after (yyyy-mm-dd)",
|
77
|
+
"more than x days ago",
|
78
|
+
"less than x days ago",
|
79
|
+
"in more than x days",
|
80
|
+
"in less than x days",
|
81
|
+
"member of",
|
82
|
+
"not member of",
|
83
|
+
"current",
|
84
|
+
"not current"
|
85
|
+
]
|
86
|
+
|
87
|
+
### the acceptable symboles for and/or
|
88
|
+
AND_OR = [:and, :or]
|
89
|
+
|
90
|
+
#####################################
|
91
|
+
### Attributes
|
92
|
+
#####################################
|
93
|
+
|
94
|
+
### @return [Integer] zero-based index of this criterion within an array of criteria
|
95
|
+
### used for an advanced search or smart group.
|
96
|
+
### This is maintained automaticaly by the enclosing Criteria object
|
97
|
+
attr_accessor :priority
|
98
|
+
|
99
|
+
### @return [Symbol] :and or :or - the and_or value for associating this criterion with the previous one
|
100
|
+
attr_reader :and_or
|
101
|
+
|
102
|
+
### @return [String] the name of the field being searched
|
103
|
+
attr_accessor :name
|
104
|
+
|
105
|
+
### @return [String] the comparator between the field and the value, must be one of SEARCH_TYPES
|
106
|
+
### @see #criteria=
|
107
|
+
attr_reader :search_type
|
108
|
+
|
109
|
+
### @return [String] the value being searched for in the field named by :name
|
110
|
+
attr_reader :value
|
111
|
+
|
112
|
+
###
|
113
|
+
### @param args[Hash] a hash of settings for the new criterion
|
114
|
+
### @option args :and_or [String, Symbol] :and, or :or. How should this criterion be join with its predecessor?
|
115
|
+
### @option args :name [String] the name of a Criterion as is visible in the JSS webapp.
|
116
|
+
### @option args :search_type [String] one of SEARCH_TYPES, the comparison between the stored value and :value
|
117
|
+
### @option args :value [String] the value to compare with that stored for :name
|
118
|
+
###
|
119
|
+
### @note :priority is maintained by the JSS::Criteriable::Criteria object holding this instance
|
120
|
+
###
|
121
|
+
def initialize(args = {})
|
122
|
+
|
123
|
+
@priority = args[:priority]
|
124
|
+
|
125
|
+
if args[:and_or]
|
126
|
+
@and_or = args[:and_or].to_sym
|
127
|
+
raise JSS::InvalidDataError, ":and_or must be 'and' or 'or'." unless AND_OR.include? @and_or
|
128
|
+
end
|
129
|
+
|
130
|
+
@name = args[:name]
|
131
|
+
|
132
|
+
if args[:search_type]
|
133
|
+
raise JSS::InvalidDataError, "Invalid :search_type" unless SEARCH_TYPES.include? args[:search_type]
|
134
|
+
@search_type = args[:search_type]
|
135
|
+
end
|
136
|
+
|
137
|
+
@value = args[:value]
|
138
|
+
end # init
|
139
|
+
|
140
|
+
###
|
141
|
+
### Set a new and_or for the criteron
|
142
|
+
###
|
143
|
+
### @param new_val[Symbol] the new and_or
|
144
|
+
###
|
145
|
+
### @return [void]
|
146
|
+
###
|
147
|
+
def and_or= (new_val)
|
148
|
+
@and_or = new_val.to_sym
|
149
|
+
raise JSS::InvalidDataError, ":and_or must be 'and' or 'or'." unless AND_OR.include? @and_or.to_sym
|
150
|
+
end
|
151
|
+
|
152
|
+
###
|
153
|
+
### Set a new search type for the criteron
|
154
|
+
###
|
155
|
+
### @param new_val[String] the new search type
|
156
|
+
###
|
157
|
+
### @return [void]
|
158
|
+
###
|
159
|
+
def search_type= (new_val)
|
160
|
+
raise JSS::InvalidDataError, "Invalid :search_type" unless SEARCH_TYPES.include? new_val
|
161
|
+
@search_type = new_val
|
162
|
+
end
|
163
|
+
|
164
|
+
###
|
165
|
+
### Set a new value for the criteron
|
166
|
+
###
|
167
|
+
### @param new_val[Integer,String] the new value
|
168
|
+
###
|
169
|
+
### @return [void]
|
170
|
+
###
|
171
|
+
def value=(new_val)
|
172
|
+
case @search_type
|
173
|
+
|
174
|
+
when *["more than", "less than", "more than x days ago", "less than x days ago"]
|
175
|
+
raise JSS::InvalidDataError, "Value must be an integer for search type '#{new_val}'" unless new_val =~ /^\d+$/
|
176
|
+
|
177
|
+
when *["before (yyyy-mm-dd)", "after (yyyy-mm-dd)"]
|
178
|
+
raise JSS::InvalidDataError, "Value must be a a date in the format yyyy-mm-dd for search type '#{new_val}'" unless new_val =~ /^\d\d\d\d-\d\d-\d\d$/
|
179
|
+
|
180
|
+
end # case
|
181
|
+
|
182
|
+
@value = new_val
|
183
|
+
|
184
|
+
end
|
185
|
+
|
186
|
+
###
|
187
|
+
### @return [String] All our values except priority joined together
|
188
|
+
### for comparing this Criterion to another for equality and order
|
189
|
+
###
|
190
|
+
### @see #<=>
|
191
|
+
###
|
192
|
+
def signature
|
193
|
+
[@and_or, @name, @search_type, @value].join ","
|
194
|
+
end
|
195
|
+
|
196
|
+
|
197
|
+
###
|
198
|
+
### Comparison - allows the Comparable module to do its work
|
199
|
+
###
|
200
|
+
### @return [Integer] -1, 0, or 1
|
201
|
+
###
|
202
|
+
### @see Comparable
|
203
|
+
###
|
204
|
+
def <=>(other)
|
205
|
+
self.signature <=> other.signature
|
206
|
+
end
|
207
|
+
|
208
|
+
###
|
209
|
+
### @api private
|
210
|
+
###
|
211
|
+
### @return [REXML::Element] The xml element for the criterion, to be embeded in that of
|
212
|
+
### a Criteria instance
|
213
|
+
###
|
214
|
+
### @note For this class, rest_xml can't be a private method.
|
215
|
+
###
|
216
|
+
def rest_xml
|
217
|
+
crn = REXML::Element.new 'criterion'
|
218
|
+
crn.add_element('priority').text = @priority
|
219
|
+
crn.add_element('and_or').text = @and_or
|
220
|
+
crn.add_element('name').text = @name
|
221
|
+
crn.add_element('search_type').text = @search_type
|
222
|
+
crn.add_element('value').text = @value
|
223
|
+
return crn
|
224
|
+
end
|
225
|
+
|
226
|
+
end # class criterion
|
227
|
+
end # module Criteriable
|
228
|
+
end # module
|
@@ -0,0 +1,93 @@
|
|
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
|
+
### Classes
|
38
|
+
#####################################
|
39
|
+
|
40
|
+
###
|
41
|
+
### A department in the JSS.
|
42
|
+
### These are simple, in that they only have an ID and a name
|
43
|
+
###
|
44
|
+
### @see JSS::APIObject
|
45
|
+
###
|
46
|
+
class Department < JSS::APIObject
|
47
|
+
|
48
|
+
#####################################
|
49
|
+
### Mix-Ins
|
50
|
+
#####################################
|
51
|
+
include JSS::Creatable
|
52
|
+
include JSS::Updatable
|
53
|
+
|
54
|
+
#####################################
|
55
|
+
### Class Methods
|
56
|
+
#####################################
|
57
|
+
|
58
|
+
#####################################
|
59
|
+
### Class Constants
|
60
|
+
#####################################
|
61
|
+
|
62
|
+
### The base for REST resources of this class
|
63
|
+
RSRC_BASE = "departments"
|
64
|
+
|
65
|
+
### the hash key used for the JSON list output of all objects in the JSS
|
66
|
+
RSRC_LIST_KEY = :departments
|
67
|
+
|
68
|
+
### The hash key used for the JSON object output.
|
69
|
+
### It's also used in various error messages
|
70
|
+
RSRC_OBJECT_KEY = :department
|
71
|
+
|
72
|
+
### these keys, as well as :id and :name, are present in valid API JSON data for this class
|
73
|
+
VALID_DATA_KEYS = []
|
74
|
+
|
75
|
+
#####################################
|
76
|
+
### Attributes
|
77
|
+
#####################################
|
78
|
+
|
79
|
+
#####################################
|
80
|
+
### Constructor
|
81
|
+
#####################################
|
82
|
+
|
83
|
+
###
|
84
|
+
### See JSS::APIObject#initialize
|
85
|
+
###
|
86
|
+
|
87
|
+
#####################################
|
88
|
+
### Public Instance Methods
|
89
|
+
#####################################
|
90
|
+
|
91
|
+
end # class department
|
92
|
+
|
93
|
+
end # module
|
@@ -0,0 +1,560 @@
|
|
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
|
+
### the master dist. point, see JSS.master_distribution_point
|
33
|
+
@@master_distribution_point = nil
|
34
|
+
|
35
|
+
### the dist point for this machine right now
|
36
|
+
@@my_distribution_point =nil
|
37
|
+
|
38
|
+
#####################################
|
39
|
+
### Module Methods
|
40
|
+
#####################################
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
###
|
45
|
+
### A Distribution Point in the JSS
|
46
|
+
###
|
47
|
+
### As well as the normal Class and Instance methods for {APIObject} subclasses, the
|
48
|
+
### DistributionPoint class provides more interaction with other parts of the API.
|
49
|
+
###
|
50
|
+
### Beyond the standard listing methods DistributionPoint.all, .all_ids, etc, every JSS
|
51
|
+
### has a single "master" distribution point. The Class method {DistributionPoint.master_distribution_point} will
|
52
|
+
### return the JSS::DistributionPoint object for that master.
|
53
|
+
###
|
54
|
+
### Also, some network segments have specific DistributionPoints assigned to them. Calling the Class method
|
55
|
+
### {DistributionPoint.my_distribution_point} will return a JSS::DistributionPoint object for your local IP address.
|
56
|
+
###
|
57
|
+
### Once you have an instance of JSS::DistributionPoint, you can mount it (on a Mac) by calling its {#mount} method
|
58
|
+
### and unmount it with {#unmount}. The {JSS::Package} and possibly {JSS::Script} classes use this to upload
|
59
|
+
### items to the master.
|
60
|
+
###
|
61
|
+
### @see JSS::APIObject
|
62
|
+
###
|
63
|
+
class DistributionPoint < JSS::APIObject
|
64
|
+
|
65
|
+
#####################################
|
66
|
+
### Mix-Ins
|
67
|
+
#####################################
|
68
|
+
|
69
|
+
#####################################
|
70
|
+
### Class Constants
|
71
|
+
#####################################
|
72
|
+
|
73
|
+
### The base for REST resources of this class
|
74
|
+
RSRC_BASE = "distributionpoints"
|
75
|
+
|
76
|
+
### the hash key used for the JSON list output of all objects in the JSS
|
77
|
+
### its also used in various error messages
|
78
|
+
RSRC_LIST_KEY = :distribution_points
|
79
|
+
|
80
|
+
### The hash key used for the JSON object output.
|
81
|
+
### It's also used in various error messages
|
82
|
+
RSRC_OBJECT_KEY = :distribution_point
|
83
|
+
|
84
|
+
### these keys, as well as :id and :name, are present in valid API JSON data for this class
|
85
|
+
VALID_DATA_KEYS = [:read_only_username, :ssh_username, :is_master ]
|
86
|
+
|
87
|
+
### what are the mount options? these are comma-separated, and are passed with -o
|
88
|
+
MOUNT_OPTIONS = 'nobrowse'
|
89
|
+
|
90
|
+
### An empty SHA256 digest
|
91
|
+
EMPTY_PW_256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
92
|
+
|
93
|
+
|
94
|
+
|
95
|
+
#####################################
|
96
|
+
### Class Variables
|
97
|
+
#####################################
|
98
|
+
|
99
|
+
@@master_distribution_point = nil
|
100
|
+
|
101
|
+
@@my_distribution_point = nil
|
102
|
+
|
103
|
+
#####################################
|
104
|
+
### Class Methods
|
105
|
+
#####################################
|
106
|
+
|
107
|
+
### Get the DistributionPoint instance for the master
|
108
|
+
### distribution point in the JSS. If there's only one
|
109
|
+
### in the JSS, return it even if not marked as master.
|
110
|
+
###
|
111
|
+
### @return [JSS::DistributionPoint]
|
112
|
+
###
|
113
|
+
def self.master_distribution_point(refresh = false)
|
114
|
+
@@master_distribution_point = nil if refresh
|
115
|
+
return @@master_distribution_point if @@master_distribution_point
|
116
|
+
|
117
|
+
case self.all.count
|
118
|
+
when 0
|
119
|
+
raise JSS::NoSuchItemError, "No distribution points defined"
|
120
|
+
when 1
|
121
|
+
self.new :id => self.all_ids[0]
|
122
|
+
else
|
123
|
+
self.new :id => :master
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
### Get the DistributionPoint instance for the machine running
|
128
|
+
### this code, based on its IP address. If none is defined for this IP address,
|
129
|
+
### use the result of master_distribution_point
|
130
|
+
###
|
131
|
+
### @param refresh[Boolean] should the distribution point be re-queried?
|
132
|
+
###
|
133
|
+
### @return [JSS::DistributionPoint]
|
134
|
+
###
|
135
|
+
def self.my_distribution_point(refresh = false)
|
136
|
+
@@my_distribution_point = nil if refresh
|
137
|
+
return @@my_distribution_point if @@my_distribution_point
|
138
|
+
|
139
|
+
my_net_seg = JSS::NetworkSegment.my_network_segment[0]
|
140
|
+
specific = if my_net_seg
|
141
|
+
JSS::NetworkSegment.new(:id => my_net_seg).distribution_point
|
142
|
+
else
|
143
|
+
nil
|
144
|
+
end
|
145
|
+
return specific ? self.new(:name => specific) : self.master_distribution_point
|
146
|
+
end
|
147
|
+
|
148
|
+
#####################################
|
149
|
+
### Class Attributes
|
150
|
+
#####################################
|
151
|
+
|
152
|
+
### @return [String] the hostname of this DP
|
153
|
+
attr_reader :ip_address
|
154
|
+
|
155
|
+
### @return [String] the local path on the server to the distribution point directory
|
156
|
+
attr_reader :local_path
|
157
|
+
|
158
|
+
### @return [String] load balanacing enabled?
|
159
|
+
attr_reader :enable_load_balancing
|
160
|
+
|
161
|
+
### @return [Integer] the id of the DP to use for failover
|
162
|
+
attr_reader :failover_point
|
163
|
+
|
164
|
+
### @return [Boolean] is this the master DP?
|
165
|
+
attr_reader :is_master
|
166
|
+
|
167
|
+
### FileService Access
|
168
|
+
|
169
|
+
### @return [String] Protocol for fileservice access (e.g. AFP, SMB)
|
170
|
+
attr_reader :connection_type
|
171
|
+
|
172
|
+
### @return [Integer] the port for fileservice access
|
173
|
+
attr_reader :share_port
|
174
|
+
|
175
|
+
### @return [String] the name of the fileservice sharepoint
|
176
|
+
attr_reader :share_name
|
177
|
+
|
178
|
+
### @return [String] the read-write username for fileservice access
|
179
|
+
attr_reader :read_write_username
|
180
|
+
|
181
|
+
### @return [String] the read-write password as a SHA256 digest
|
182
|
+
attr_reader :read_write_password_sha256
|
183
|
+
|
184
|
+
### @return [String] read-only username for fileservice
|
185
|
+
attr_reader :read_only_username
|
186
|
+
|
187
|
+
### @return [String] read-only password as a SHA256 digest
|
188
|
+
attr_reader :read_only_password_sha256
|
189
|
+
|
190
|
+
### @return [String] work group or domain for SMB
|
191
|
+
attr_reader :workgroup_or_domain
|
192
|
+
|
193
|
+
### http(s) access
|
194
|
+
|
195
|
+
### @return [Boolean] are http downloads available from this DP?
|
196
|
+
attr_reader :http_downloads_enabled
|
197
|
+
|
198
|
+
### @return [String] the protocol to use for http downloads (http/https)
|
199
|
+
attr_reader :protocol
|
200
|
+
|
201
|
+
### @return [Integer] the port for http access
|
202
|
+
attr_reader :port
|
203
|
+
|
204
|
+
### @return [String] the "context" for http downloads (what goes after the hostname part of the URL)
|
205
|
+
attr_reader :context
|
206
|
+
|
207
|
+
### @return [Boolean] do http downloads work without auth?
|
208
|
+
attr_reader :no_authentication_required
|
209
|
+
|
210
|
+
### @return [Boolean] do http downloads use cert. authentication?
|
211
|
+
attr_reader :certificate_required
|
212
|
+
|
213
|
+
### @return [Boolean] do http downloads use user/pw auth?
|
214
|
+
attr_reader :username_password_required
|
215
|
+
|
216
|
+
### @return [String] the username to use for http downloads if needed for user/pw auth
|
217
|
+
attr_reader :http_username
|
218
|
+
|
219
|
+
### @return [String] the password for http downloads, if needed, as a SHA256 digest
|
220
|
+
attr_reader :http_password_sha256
|
221
|
+
|
222
|
+
### @return [String] the name of the cert. used for http cert. auth.
|
223
|
+
attr_reader :certificate
|
224
|
+
|
225
|
+
### @return [String] the URL for http downloads
|
226
|
+
attr_reader :http_url
|
227
|
+
|
228
|
+
### @return [String] the URL to use if this one doesn't work
|
229
|
+
attr_reader :failover_point_url
|
230
|
+
|
231
|
+
### ssh (scp, rsync, sftp) access
|
232
|
+
|
233
|
+
### @return [String] ssh username
|
234
|
+
attr_reader :ssh_username
|
235
|
+
|
236
|
+
### @return [String] the ssh password as a SHA256 digest
|
237
|
+
attr_reader :ssh_password_sha256
|
238
|
+
|
239
|
+
###
|
240
|
+
### As well as the standard :id, :name, and :data, you can
|
241
|
+
### instantiate this class with :id => :master, in which case you'll
|
242
|
+
### get the Master Distribution Point as defined in the JSS.
|
243
|
+
### An error will be raised if one hasn't been defined.
|
244
|
+
###
|
245
|
+
### You can also do this more easily by calling JSS.master_distribution_point
|
246
|
+
###
|
247
|
+
def initialize(args = {})
|
248
|
+
|
249
|
+
@init_data = nil
|
250
|
+
|
251
|
+
### looking for master?
|
252
|
+
if args[:id] == :master
|
253
|
+
|
254
|
+
self.class.all_ids.each do |id|
|
255
|
+
@init_data = JSS::API.get_rsrc("#{RSRC_BASE}/id/#{id}")[RSRC_OBJECT_KEY]
|
256
|
+
if @init_data[:is_master]
|
257
|
+
@id = @init_data[:id]
|
258
|
+
@name = @init_data[:name]
|
259
|
+
break
|
260
|
+
end # if data is master
|
261
|
+
@init_data = nil
|
262
|
+
end # each id
|
263
|
+
end # if args is master
|
264
|
+
|
265
|
+
if @init_data.nil?
|
266
|
+
super(args)
|
267
|
+
end
|
268
|
+
|
269
|
+
@ip_address = @init_data[:ip_address]
|
270
|
+
@local_path = @init_data[:local_path]
|
271
|
+
@enable_load_balancing = @init_data[:enable_load_balancing]
|
272
|
+
@failover_point = @init_data[:failover_point]
|
273
|
+
@is_master = @init_data[:is_master]
|
274
|
+
|
275
|
+
@connection_type = @init_data[:connection_type]
|
276
|
+
@share_port = @init_data[:share_port]
|
277
|
+
@share_name = @init_data[:share_name]
|
278
|
+
@workgroup_or_domain = @init_data[:workgroup_or_domain]
|
279
|
+
|
280
|
+
@read_write_username = @init_data[:read_write_username]
|
281
|
+
@read_write_password_sha256 = @init_data[:read_write_password_sha256]
|
282
|
+
@read_only_username = @init_data[:read_only_username]
|
283
|
+
@read_only_password_sha256 = @init_data[:read_only_password_sha256]
|
284
|
+
@ssh_username = @init_data[:ssh_username]
|
285
|
+
@ssh_password_sha256 = @init_data[:ssh_password_sha256]
|
286
|
+
@http_username = @init_data[:http_username]
|
287
|
+
@http_password_sha256 = @init_data[:http_password_sha256]
|
288
|
+
|
289
|
+
|
290
|
+
@http_downloads_enabled = @init_data[:http_downloads_enabled]
|
291
|
+
@protocol = @init_data[:protocol]
|
292
|
+
@port = @init_data[:port]
|
293
|
+
@context = @init_data[:context]
|
294
|
+
@no_authentication_required = @init_data[:no_authentication_required]
|
295
|
+
@certificate_required = @init_data[:certificate_required]
|
296
|
+
@username_password_required = @init_data[:username_password_required]
|
297
|
+
@certificate = @init_data[:certificate]
|
298
|
+
@http_url = @init_data[:http_url]
|
299
|
+
@failover_point_url = @init_data[:failover_point_url]
|
300
|
+
|
301
|
+
|
302
|
+
@port = @init_data[:ssh_password]
|
303
|
+
|
304
|
+
### Note, as of Casper 9.3:
|
305
|
+
### :management_password_md5=>"xxxxx"
|
306
|
+
### and
|
307
|
+
### :management_password_sha256=> "xxxxxxxxxx"
|
308
|
+
### Are the read/write password
|
309
|
+
###
|
310
|
+
### An empty passwd is
|
311
|
+
### MD5 = d41d8cd98f00b204e9800998ecf8427e
|
312
|
+
### SHA256 = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
313
|
+
###
|
314
|
+
### Seemms the read-only pw isn't available in the API
|
315
|
+
|
316
|
+
|
317
|
+
### if we mount for fileservice, where's the mountpoint?
|
318
|
+
@mountpoint = Pathname.new "/Volumes/CasperDistribution-id-#{@id}"
|
319
|
+
|
320
|
+
end #init
|
321
|
+
|
322
|
+
###
|
323
|
+
### Check the validity of a password.
|
324
|
+
###
|
325
|
+
### @param user[Symbol] one of :ro, :rw, :ssh, :http
|
326
|
+
###
|
327
|
+
### @param pw[String] the password to check for the given user
|
328
|
+
###
|
329
|
+
### @return [Boolean,Nil] was the password correct?
|
330
|
+
### nil is returned if there is no password set in the JSS.
|
331
|
+
###
|
332
|
+
def check_pw(user, pw)
|
333
|
+
raise JSS::InvalidDataError, "The first parameter must be one of :ro, :rw, :ssh, :http" unless [:ro, :rw, :ssh, :http].include? user
|
334
|
+
sha256 = case user
|
335
|
+
when :rw then @read_write_password_sha256
|
336
|
+
when :ro then @read_only_password_sha256
|
337
|
+
when :http then @http_password_sha256
|
338
|
+
when :ssh then @ssh_password_sha256
|
339
|
+
end # case
|
340
|
+
|
341
|
+
return nil if sha256 == EMPTY_PW_256
|
342
|
+
|
343
|
+
sha256 == Digest::SHA2.new(256).update(pw).to_s
|
344
|
+
end
|
345
|
+
|
346
|
+
### Check to see if this dist point is reachable for downloads (read-only)
|
347
|
+
### via either http, if available, or filesharing.
|
348
|
+
###
|
349
|
+
### @param pw[String] the read-only password to use for checking the connection
|
350
|
+
### If http downloads are enabled, and no http password is required
|
351
|
+
### this can be omitted.
|
352
|
+
###
|
353
|
+
### @param check_http[Boolean] should we try the http download first, if enabled?
|
354
|
+
### If you're intentionally using the ro password for filesharing, and want to check
|
355
|
+
### only filesharing, then set this to false.
|
356
|
+
###
|
357
|
+
### @return [FalseClass, Symbol] false if not reachable, otherwise :http or :mountable
|
358
|
+
###
|
359
|
+
def reachable_for_download? (pw = '', check_http = true)
|
360
|
+
pw ||= ''
|
361
|
+
http_checked = ""
|
362
|
+
if check_http && http_downloads_enabled
|
363
|
+
if @username_password_required
|
364
|
+
# we don't check the pw here, because if the connection fails, we'll
|
365
|
+
# drop down below to try the password for mounting.
|
366
|
+
# we'll escape all the chars that aren't unreserved
|
367
|
+
reserved_chars = Regexp.new("[^#{URI::REGEXP::PATTERN::UNRESERVED}]")
|
368
|
+
user_pass = "#{URI.escape @http_username,reserved_chars}:#{URI.escape ro_pw, reserved_chars}@"
|
369
|
+
url = @http_url.sub "://#{@ip_address}", "://#{user_pass}#{@ip_address}"
|
370
|
+
else
|
371
|
+
url = @http_url
|
372
|
+
end
|
373
|
+
|
374
|
+
begin
|
375
|
+
open(url).read
|
376
|
+
return :http
|
377
|
+
rescue
|
378
|
+
http_checked = "http and "
|
379
|
+
end
|
380
|
+
end # if check_http && http_downloads_enabled
|
381
|
+
|
382
|
+
return :mountable if mounted?
|
383
|
+
|
384
|
+
return false unless check_pw :ro , pw
|
385
|
+
|
386
|
+
begin
|
387
|
+
mount pw, :ro
|
388
|
+
return :mountable
|
389
|
+
rescue
|
390
|
+
return false
|
391
|
+
ensure
|
392
|
+
unmount
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
### Check to see if this dist point is reachable for uploads (read-write)
|
397
|
+
### via filesharing.
|
398
|
+
###
|
399
|
+
### @param pw[String] the read-write password to use for checking the connection
|
400
|
+
###
|
401
|
+
### @return [FalseClass, Symbol] false if not reachable, otherwise :mountable
|
402
|
+
###
|
403
|
+
def reachable_for_upload? (pw)
|
404
|
+
return :mountable if mounted?
|
405
|
+
return false unless check_pw :rw , pw
|
406
|
+
begin
|
407
|
+
mount pw, :rw
|
408
|
+
return :mountable
|
409
|
+
rescue
|
410
|
+
return false
|
411
|
+
ensure
|
412
|
+
unmount
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
|
417
|
+
###
|
418
|
+
### Mount this distribution point locally.
|
419
|
+
###
|
420
|
+
### @param pw[String,Symbol] the read-only or read-write password for this DistributionPoint
|
421
|
+
### If :prompt, the user is promted on the commandline to enter the password for the :user.
|
422
|
+
### If :stdin#, the password is read from a line of std in represented by the digits at #,
|
423
|
+
### so :stdin3 reads the passwd from the third line of standard input. defaults to line 2,
|
424
|
+
### if no digit is supplied. see {JSS.stdin}
|
425
|
+
###
|
426
|
+
### @param access[Symbol] how to mount the DistributionPoint, and which password to expect.
|
427
|
+
### :ro (or anything else) = read-only, :rw = read-write
|
428
|
+
###
|
429
|
+
### @return [Pathname] the mountpoint.
|
430
|
+
###
|
431
|
+
def mount(pw = nil, access = :ro)
|
432
|
+
return @mountpoint if mounted?
|
433
|
+
access = :ro unless access == :rw
|
434
|
+
|
435
|
+
password = if pw == :prompt
|
436
|
+
JSS.prompt_for_password "Enter the password for the #{access} user '#{access == :ro ? @read_only_username : @read_write_username }':"
|
437
|
+
elsif pw.is_a?(Symbol) and pw.to_s.start_with?('stdin')
|
438
|
+
pw.to_s =~ /^stdin(\d+)$/
|
439
|
+
line = $1
|
440
|
+
line ||= 2
|
441
|
+
JSS.stdin line
|
442
|
+
else
|
443
|
+
pw
|
444
|
+
end
|
445
|
+
|
446
|
+
pwok = check_pw(access, password)
|
447
|
+
unless pwok
|
448
|
+
msg = pwok.nil? ? "No #{access} password set in the JSS" : "Incorrect password for #{access} account"
|
449
|
+
raise JSS::InvalidDataError, msg
|
450
|
+
end
|
451
|
+
|
452
|
+
username = access == :ro ? @read_only_username : @read_write_username
|
453
|
+
|
454
|
+
safe_pw = URI.escape password, /[^a-zA-Z\d]/
|
455
|
+
|
456
|
+
@mount_url = "#{@connection_type.downcase}://#{username}:#{safe_pw}@#{@ip_address}/#{@share_name}"
|
457
|
+
@mnt_cmd = case @connection_type.downcase
|
458
|
+
when 'smb' then '/sbin/mount_smbfs'
|
459
|
+
when 'afp' then '/sbin/mount_afp'
|
460
|
+
else raise "Can't mount distribution point #{@name}: no known connection type."
|
461
|
+
end
|
462
|
+
|
463
|
+
@mountpoint.mkpath
|
464
|
+
|
465
|
+
mount_out = `#{@mnt_cmd} -o '#{MOUNT_OPTIONS}' '#{@mount_url}' '#{@mountpoint}' 2>&1`
|
466
|
+
if $?.exitstatus == 0 and @mountpoint.mountpoint?
|
467
|
+
#if system @mnt_cmd.to_s, *['-o', MOUNT_OPTIONS, @mount_url, @mountpoint.to_s]
|
468
|
+
@mounted = access
|
469
|
+
else
|
470
|
+
@mountpoint.rmdir if @mountpoint.directory?
|
471
|
+
@mounted = nil
|
472
|
+
raise JSS::FileServiceError, "Can't mount #{@ip_address}: #{mount_out}"
|
473
|
+
end
|
474
|
+
return @mountpoint
|
475
|
+
end # mount
|
476
|
+
|
477
|
+
###
|
478
|
+
### Unmount the distribution point.
|
479
|
+
###
|
480
|
+
### Does nothing if it wasn't mounted with #mount.
|
481
|
+
###
|
482
|
+
### @return [void]
|
483
|
+
###
|
484
|
+
def unmount
|
485
|
+
return nil unless mounted?
|
486
|
+
if system "umount '#{@mountpoint}'"
|
487
|
+
@mountpoint.rmdir if @mountpoint.directory? and (not @mountpoint.mountpoint?)
|
488
|
+
@mounted = false
|
489
|
+
else
|
490
|
+
raise JSS::FileServiceError ,"There was a problem unmounting #{@mountpoint}"
|
491
|
+
end
|
492
|
+
nil
|
493
|
+
end # unmount
|
494
|
+
|
495
|
+
|
496
|
+
###
|
497
|
+
### Is this thing mounted right now?
|
498
|
+
###
|
499
|
+
### @return [Boolean]
|
500
|
+
###
|
501
|
+
def mounted?
|
502
|
+
@mountpoint.directory? and @mountpoint.mountpoint?
|
503
|
+
end
|
504
|
+
|
505
|
+
|
506
|
+
#### aliases
|
507
|
+
alias hostname ip_address
|
508
|
+
alias umount unmount
|
509
|
+
|
510
|
+
######################################
|
511
|
+
### Private Instance Methods
|
512
|
+
######################################
|
513
|
+
private
|
514
|
+
|
515
|
+
###
|
516
|
+
### Unused - until I get around to making DP's updatable
|
517
|
+
###
|
518
|
+
### the XML representation of the current state of this object,
|
519
|
+
### for POSTing or PUTting back to the JSS via the API
|
520
|
+
### Will be supported for Dist Points some day, I'm sure.
|
521
|
+
###
|
522
|
+
def rest_xml
|
523
|
+
doc = REXML::Document.new
|
524
|
+
dp = doc.add_element "distribution_point"
|
525
|
+
dp.add_element(:name.to_s).text = @name
|
526
|
+
dp.add_element(:ip_address.to_s).text = @ip_address
|
527
|
+
dp.add_element(:local_path.to_s).text = @local_path
|
528
|
+
dp.add_element(:enable_load_balancing.to_s).text = @enable_load_balancing
|
529
|
+
dp.add_element(:failover_point.to_s).text = @failover_point
|
530
|
+
dp.add_element(:is_master.to_s).text = @is_master
|
531
|
+
|
532
|
+
dp.add_element(:connection_type.to_s).text = @connection_type
|
533
|
+
dp.add_element(:share_port.to_s).text = @share_port
|
534
|
+
dp.add_element(:share_name.to_s).text = @share_name
|
535
|
+
dp.add_element(:read_write_username.to_s).text = @read_write_username
|
536
|
+
dp.add_element(:read_write_password.to_s).text = @read_write_password
|
537
|
+
dp.add_element(:read_only_username.to_s).text = @read_only_username
|
538
|
+
dp.add_element(:read_only_password.to_s).text = @read_only_password
|
539
|
+
dp.add_element(:workgroup_or_domain.to_s).text = @workgroup_or_domain
|
540
|
+
|
541
|
+
dp.add_element(:http_downloads_enabled.to_s).text = @http_downloads_enabled
|
542
|
+
dp.add_element(:protocol.to_s).text = @protocol
|
543
|
+
dp.add_element(:port.to_s).text = @port
|
544
|
+
dp.add_element(:context.to_s).text = @context
|
545
|
+
dp.add_element(:no_authentication_required.to_s).text = @no_authentication_required
|
546
|
+
dp.add_element(:certificate_required.to_s).text = @certificate_required
|
547
|
+
dp.add_element(:username_password_required.to_s).text = @username_password_required
|
548
|
+
dp.add_element(:http_username.to_s).text = @http_username
|
549
|
+
dp.add_element(:certificate.to_s).text = @certificate
|
550
|
+
dp.add_element(:http_url.to_s).text = @http_url
|
551
|
+
dp.add_element(:failover_point_url.to_s).text = @failover_point_url
|
552
|
+
|
553
|
+
dp.add_element(:ssh_username.to_s).text = @ssh_username
|
554
|
+
dp.add_element(:ssh_password.to_s).text = @ssh_password if @ssh_password
|
555
|
+
|
556
|
+
return doc.to_s
|
557
|
+
end #rest_xml
|
558
|
+
|
559
|
+
end # class
|
560
|
+
end # module
|