ruby-jss 0.6.3

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

Potentially problematic release.


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

Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +7 -0
  3. data/CHANGES.md +112 -0
  4. data/LICENSE.txt +174 -0
  5. data/README.md +426 -0
  6. data/THANKS.md +6 -0
  7. data/bin/cgrouper +485 -0
  8. data/bin/subnet-update +400 -0
  9. data/lib/jss-api.rb +2 -0
  10. data/lib/jss.rb +190 -0
  11. data/lib/jss/api_connection.rb +410 -0
  12. data/lib/jss/api_object.rb +616 -0
  13. data/lib/jss/api_object/advanced_search.rb +389 -0
  14. data/lib/jss/api_object/advanced_search/advanced_computer_search.rb +95 -0
  15. data/lib/jss/api_object/advanced_search/advanced_mobile_device_search.rb +96 -0
  16. data/lib/jss/api_object/advanced_search/advanced_user_search.rb +95 -0
  17. data/lib/jss/api_object/building.rb +92 -0
  18. data/lib/jss/api_object/category.rb +147 -0
  19. data/lib/jss/api_object/computer.rb +852 -0
  20. data/lib/jss/api_object/creatable.rb +98 -0
  21. data/lib/jss/api_object/criteriable.rb +189 -0
  22. data/lib/jss/api_object/criteriable/criteria.rb +231 -0
  23. data/lib/jss/api_object/criteriable/criterion.rb +228 -0
  24. data/lib/jss/api_object/department.rb +93 -0
  25. data/lib/jss/api_object/distribution_point.rb +560 -0
  26. data/lib/jss/api_object/extendable.rb +221 -0
  27. data/lib/jss/api_object/extension_attribute.rb +466 -0
  28. data/lib/jss/api_object/extension_attribute/computer_extension_attribute.rb +362 -0
  29. data/lib/jss/api_object/extension_attribute/mobile_device_extension_attribute.rb +189 -0
  30. data/lib/jss/api_object/extension_attribute/user_extension_attribute.rb +117 -0
  31. data/lib/jss/api_object/group.rb +380 -0
  32. data/lib/jss/api_object/group/computer_group.rb +124 -0
  33. data/lib/jss/api_object/group/mobile_device_group.rb +139 -0
  34. data/lib/jss/api_object/group/user_group.rb +139 -0
  35. data/lib/jss/api_object/ldap_server.rb +535 -0
  36. data/lib/jss/api_object/locatable.rb +286 -0
  37. data/lib/jss/api_object/matchable.rb +97 -0
  38. data/lib/jss/api_object/mobile_device.rb +556 -0
  39. data/lib/jss/api_object/netboot_server.rb +148 -0
  40. data/lib/jss/api_object/network_segment.rb +414 -0
  41. data/lib/jss/api_object/osx_configuration_profile.rb +262 -0
  42. data/lib/jss/api_object/package.rb +839 -0
  43. data/lib/jss/api_object/peripheral.rb +335 -0
  44. data/lib/jss/api_object/peripheral_type.rb +295 -0
  45. data/lib/jss/api_object/policy.rb +898 -0
  46. data/lib/jss/api_object/purchasable.rb +316 -0
  47. data/lib/jss/api_object/removable_macaddr.rb +98 -0
  48. data/lib/jss/api_object/scopable.rb +136 -0
  49. data/lib/jss/api_object/scopable/scope.rb +621 -0
  50. data/lib/jss/api_object/script.rb +631 -0
  51. data/lib/jss/api_object/self_servable.rb +356 -0
  52. data/lib/jss/api_object/site.rb +93 -0
  53. data/lib/jss/api_object/software_update_server.rb +109 -0
  54. data/lib/jss/api_object/updatable.rb +117 -0
  55. data/lib/jss/api_object/uploadable.rb +138 -0
  56. data/lib/jss/api_object/user.rb +272 -0
  57. data/lib/jss/client.rb +504 -0
  58. data/lib/jss/compatibility.rb +66 -0
  59. data/lib/jss/composer.rb +185 -0
  60. data/lib/jss/configuration.rb +306 -0
  61. data/lib/jss/db_connection.rb +298 -0
  62. data/lib/jss/exceptions.rb +95 -0
  63. data/lib/jss/ruby_extensions.rb +35 -0
  64. data/lib/jss/ruby_extensions/filetest.rb +43 -0
  65. data/lib/jss/ruby_extensions/hash.rb +79 -0
  66. data/lib/jss/ruby_extensions/ipaddr.rb +91 -0
  67. data/lib/jss/ruby_extensions/pathname.rb +77 -0
  68. data/lib/jss/ruby_extensions/string.rb +59 -0
  69. data/lib/jss/ruby_extensions/time.rb +63 -0
  70. data/lib/jss/server.rb +108 -0
  71. data/lib/jss/utility.rb +478 -0
  72. data/lib/jss/version.rb +31 -0
  73. metadata +187 -0
@@ -0,0 +1,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