hpe3par_sdk 1.0.0

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.
@@ -0,0 +1,292 @@
1
+ # (c) Copyright 2016-2017 Hewlett Packard Enterprise Development LP
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software distributed
8
+ # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
9
+ # CONDITIONS OF ANY KIND, either express or implied. See the License for the
10
+ # specific language governing permissions and limitations under the License.
11
+
12
+ require_relative 'util'
13
+ require_relative 'constants'
14
+ require_relative 'exceptions'
15
+ require_relative 'task_manager'
16
+ require_relative 'ssh'
17
+ require_relative 'volume_set_manager'
18
+ require_relative 'models'
19
+
20
+ module Hpe3parSdk
21
+ class VolumeManager
22
+ def initialize(http, ssh, app_type)
23
+ @http = http
24
+ @ssh = ssh
25
+ @task = TaskManager.new(http)
26
+ @volume_set = VolumeSetManager.new(http)
27
+ @app_type = app_type
28
+ end
29
+
30
+ def get_volumes(volume_type)
31
+ volumes = Array[]
32
+ response = @http.get('/volumes')
33
+ response[1]['members'].each do |member|
34
+ volumes.push(VirtualVolume.new(member)) if member['copyType'] == volume_type
35
+ end
36
+ volumes
37
+ end
38
+
39
+ def get_volume(name)
40
+ if name.nil? || name.strip.empty?
41
+ raise 'Volume name cannot be nil or empty'
42
+ else
43
+ VirtualVolume.new(@http.get("/volumes/#{name}")[1])
44
+ end
45
+ end
46
+
47
+ def get_volume_by_wwn(wwn)
48
+ response = @http.get("/volumes?query=\"wwn EQ #{wwn}\"")
49
+ if response[1].key?('members') && !response[1]['members'].empty?
50
+ return VirtualVolume.new(response[1]['members'][0])
51
+ else
52
+ raise HTTPNotFound.new(nil, "Volume with WWN #{wwn} does not exist", nil, 404)
53
+ end
54
+ end
55
+
56
+ def create_volume(name, cpg_name, size_mib, optional = nil)
57
+ info = { 'name' => name,
58
+ 'cpg' => cpg_name,
59
+ 'sizeMiB' => size_mib,
60
+ #Adding information related to telemetry
61
+ 'objectKeyValues' => [
62
+ {
63
+ 'key' => 'type' ,
64
+ 'value' => @app_type
65
+ }
66
+ ]
67
+ }
68
+
69
+ info = Util.merge_hash(info, optional) if optional
70
+ volumes_url = '/volumes'
71
+ @http.post(volumes_url, body: info)
72
+ end
73
+
74
+ def get_volume_snapshot_names(name)
75
+ snapshots = []
76
+ headers, body = @http.get("/volumes?query=\"copyOf EQ #{name}\"")
77
+ for member in body['members']
78
+ snapshots.push(member['name'])
79
+ end
80
+ snapshots
81
+ end
82
+
83
+ def get_volume_snapshots(name)
84
+ response = @http.get("/volumes?query=\"copyOf EQ #{name}\"")
85
+ volume_snapshots = []
86
+ response[1]['members'].each do |snapshot|
87
+ volume_snapshots.push(VirtualVolume.new(snapshot))
88
+ end
89
+ volume_snapshots
90
+ end
91
+
92
+ def delete_volume(name)
93
+ response = @http.delete("/volumes/#{name}")
94
+ response[1]
95
+ end
96
+
97
+ def modify_volume(name, volume_mods)
98
+ @http.put("/volumes/#{name}", body: volume_mods)
99
+ if volume_mods.key? ('newName') && !volume_mods['newName'].nil?
100
+ name = volume_mods['newName']
101
+ end
102
+ setVolumeMetaData(name, 'type', @app_type)
103
+ end
104
+
105
+ def grow_volume(name, amount)
106
+ info = { 'action' => VolumeCustomAction::GROW_VOLUME, 'sizeMiB' => amount }
107
+ response = @http.put("/volumes/#{name}", body: info)
108
+ response[1]
109
+ end
110
+
111
+ def create_physical_copy(src_name, dest_name, dest_cpg, optional = nil)
112
+ parameters = { :destVolume => dest_name, :destCPG => dest_cpg }
113
+ parameters = Util.merge_hash(parameters, optional) if optional
114
+
115
+
116
+ if !parameters.key?(:online) || !((parameters[:online]))
117
+ # 3Par won't allow destCPG to be set if it's not an online copy.
118
+ parameters.delete(:destCPG)
119
+ end
120
+
121
+ info = { :action => 'createPhysicalCopy', :parameters => parameters }
122
+
123
+ response = @http.post("/volumes/#{src_name}", body: info)
124
+ response[1]
125
+ end
126
+
127
+ def stop_offline_physical_copy(volume_name)
128
+ _sync_physical_copy(volume_name, VolumeCustomAction::STOP_PHYSICAL_COPY)
129
+ end
130
+
131
+ def is_online_physical_copy(name)
132
+ task = _find_task(name, active=true)
133
+ if task.nil?
134
+ false
135
+ else
136
+ true
137
+ end
138
+ end
139
+
140
+ def stop_online_physical_copy(name)
141
+ task = _find_task(name, active=false)
142
+ unless task.nil?
143
+ task_id = task[0].split(",")[0]
144
+ unless task_id.nil?
145
+ cmd = ['canceltask', '-f', task_id]
146
+ command = cmd.join(" ")
147
+ result = @ssh.run(command)
148
+ unless result.include? "is not active"
149
+ ready = false
150
+ while ready == false
151
+ sleep(1)
152
+ task = _find_task(name, false)
153
+ if task.nil?
154
+ ready = true
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
161
+
162
+ def _find_task(name, active=false)
163
+ cmd = ['showtask']
164
+ if active
165
+ cmd.push('-active')
166
+ end
167
+ cmd.push(name)
168
+ command = cmd.join(" ")
169
+
170
+ result = @ssh.run(command).split("\n")
171
+ if result[0].gsub("\n",'') =='No tasks.'
172
+ return nil
173
+ end
174
+ result
175
+ end
176
+
177
+ def resync_physical_copy(volume_name)
178
+ _sync_physical_copy(volume_name, VolumeCustomAction::RESYNC_PHYSICAL_COPY)
179
+ end
180
+
181
+ def _sync_physical_copy(volume_name, action)
182
+ info = { 'action' => action }
183
+ response = @http.put("/volumes/#{volume_name}", body: info)
184
+ response[1]
185
+ end
186
+
187
+ def get_online_physical_copy_status(name)
188
+ status = nil
189
+ tasks = @task.get_all_tasks
190
+ tasks.each do |task|
191
+ status = task['status'] if task['name'] == name &&
192
+ task['type'] == TaskType::ONLINE_COPY
193
+ end
194
+ raise HPE3PARException.new(nil, 'Volume not an online physical copy') if status.nil?
195
+ status
196
+ end
197
+
198
+ def tune_volume(name, tune_operation, optional = nil)
199
+ info = { 'action' => VolumeCustomAction::TUNE_VOLUME,
200
+ 'tuneOperation' => tune_operation }
201
+ info = Util.merge_hash(info, optional) if optional
202
+ response = @http.put("/volumes/#{name}", body: info)
203
+ response[1]
204
+ end
205
+
206
+
207
+
208
+ def create_snapshot(name, copy_of_name, optional = nil)
209
+ parameters = { 'name' => name }
210
+ parameters = Util.merge_hash(parameters, optional) if optional
211
+ info = { 'action' => 'createSnapshot',
212
+ 'parameters' => parameters }
213
+
214
+ response = @http.post("/volumes/#{copy_of_name}", body: info)
215
+ response[1]
216
+ end
217
+
218
+ def restore_snapshot(name, optional = nil)
219
+ info = { 'action' => VolumeCustomAction::PROMOTE_VIRTUAL_COPY }
220
+ info = Util.merge_hash(info, optional) if optional
221
+
222
+ response = @http.put("/volumes/#{name}", body: info)
223
+ response[1]
224
+ end
225
+
226
+ def setVolumeMetaData(name, key, value)
227
+ key_exists = false
228
+ info = {
229
+ 'key' => key,
230
+ 'value' => value
231
+ }
232
+
233
+ begin
234
+ response = @http.post("/volumes/#{name}/objectKeyValues", body: info)
235
+ rescue Hpe3parSdk::HTTPConflict => ex
236
+ key_exists = true
237
+ rescue
238
+ end
239
+
240
+ if key_exists
241
+ info = {
242
+ 'value' => value
243
+ }
244
+ begin
245
+ response = @http.put("/volumes/#{name}/objectKeyValues/#{key}", body: info)
246
+ rescue; end
247
+ end
248
+ end
249
+
250
+ def volume_exists?(name)
251
+ begin
252
+ get_volume(name)
253
+ return true
254
+ rescue Hpe3parSdk::HTTPNotFound => ex
255
+ return false
256
+ end
257
+ end
258
+
259
+ def volume_set_exists?(name)
260
+ begin
261
+ get_volume_set(name)
262
+ return true
263
+ rescue Hpe3parSdk::HTTPNotFound => ex
264
+ return false
265
+ end
266
+ end
267
+
268
+ def online_physical_copy_exists?(src_name, phy_copy_name)
269
+ begin
270
+ if volume_exists?(src_name) and volume_exists?(phy_copy_name) and !_find_task(phy_copy_name,true).nil?
271
+ return true
272
+ else
273
+ return false
274
+ end
275
+ rescue Hpe3parSdk::HTTPNotFound => ex
276
+ return false
277
+ end
278
+ end
279
+
280
+ def offline_physical_copy_exists?(src_name, phy_copy_name)
281
+ begin
282
+ if volume_exists?(src_name) and volume_exists?(phy_copy_name) and !_find_task(src_name + "->" + phy_copy_name,true).nil?
283
+ return true
284
+ else
285
+ return false
286
+ end
287
+ rescue Hpe3parSdk::HTTPNotFound => ex
288
+ return false
289
+ end
290
+ end
291
+ end
292
+ end
@@ -0,0 +1,126 @@
1
+ # (c) Copyright 2016-2017 Hewlett Packard Enterprise Development LP
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software distributed
8
+ # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
9
+ # CONDITIONS OF ANY KIND, either express or implied. See the License for the
10
+ # specific language governing permissions and limitations under the License.
11
+
12
+ require_relative 'util'
13
+ require_relative 'constants'
14
+ require_relative 'models'
15
+
16
+ module Hpe3parSdk
17
+ class VolumeSetManager
18
+ def initialize(http, host_and_vv_set_filter_supported = false)
19
+ @http = http
20
+ @vv_set_filter_supported = host_and_vv_set_filter_supported
21
+ end
22
+
23
+ def find_all_volume_sets(name)
24
+ vv_sets = []
25
+ if @vv_set_filter_supported
26
+ query = %("setmembers EQ #{name}")
27
+ response = @http.get("/volumesets?query=#{query}")
28
+ volume_sets = response[1]['members']
29
+ volume_sets.each do |volume_set|
30
+ vv_sets.push(VolumeSet.new(volume_set))
31
+ end
32
+ else
33
+ volume_sets = get_volume_sets
34
+ volume_sets.each do |volume_set|
35
+ if !volume_set.setmembers.nil? && !volume_set.setmembers.empty? && volume_set.setmembers.include?(name)
36
+ vv_sets.push(volume_set)
37
+ end
38
+ end
39
+ end
40
+ vv_sets
41
+ end
42
+
43
+ def get_volume_sets
44
+ response = @http.get('/volumesets')
45
+ volume_set_members = []
46
+ response[1]['members'].each do |volume_set_member|
47
+ volume_set_members.push(VolumeSet.new(volume_set_member))
48
+ end
49
+ volume_set_members
50
+ end
51
+
52
+ def get_volume_set(name)
53
+ if name.nil? || name.strip.empty?
54
+ raise 'Volume set name cannot be nil or empty'
55
+ else
56
+ response = @http.get('/volumesets/' + name)
57
+ VolumeSet.new(response[1])
58
+ end
59
+ end
60
+
61
+ def create_volume_set(name, domain = nil, comment = nil, setmembers = nil)
62
+ info = { 'name' => name }
63
+
64
+ info['domain'] = domain if domain
65
+
66
+ info['comment'] = comment if comment
67
+
68
+ if setmembers
69
+ members = { 'setmembers' => setmembers }
70
+ info = Util.merge_hash(info, members)
71
+ end
72
+ @http.post('/volumesets', body: info)
73
+ end
74
+
75
+ def delete_volume_set(name)
76
+ @http.delete("/volumesets/#{name}")[1]
77
+ end
78
+
79
+ def modify_volume_set(name, action = nil, newName = nil, comment = nil, flash_cache_policy = nil, setmembers = nil)
80
+ info = {}
81
+
82
+ info['action'] = action if action
83
+
84
+ info['newName'] = newName if newName
85
+
86
+ info['comment'] = comment if comment
87
+
88
+ info['flashCachePolicy'] = flash_cache_policy if flash_cache_policy
89
+
90
+ if setmembers
91
+ members = { 'setmembers' => setmembers }
92
+ info = Util.merge_hash(info, members)
93
+ end
94
+
95
+ @http.put("/volumesets/#{name}", body: info)[1]
96
+ end
97
+
98
+ # QoS Priority Optimization methods
99
+ def add_volumes_to_volume_set(set_name, setmembers)
100
+ modify_volume_set(set_name, SetCustomAction::MEM_ADD, nil, nil, nil, setmembers)
101
+ end
102
+
103
+ def remove_volumes_from_volume_set(set_name, setmembers)
104
+ modify_volume_set(set_name, SetCustomAction::MEM_REMOVE, nil, nil, nil, setmembers)
105
+ end
106
+
107
+ def create_snapshot_of_volume_set(name, copy_of_name, optional = nil)
108
+ parameters = { 'name' => name }
109
+ parameters = Util.merge_hash(parameters, optional) if optional
110
+
111
+ info = { 'action' => 'createSnapshot', 'parameters' => parameters }
112
+
113
+ response = @http.post("/volumesets/#{copy_of_name}", body: info)
114
+ response[1]
115
+ end
116
+
117
+ def volume_set_exists?(name)
118
+ begin
119
+ get_volume_set(name)
120
+ return true
121
+ rescue Hpe3parSdk::HTTPNotFound => ex
122
+ return false
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,73 @@
1
+ # (c) Copyright 2016-2017 Hewlett Packard Enterprise Development LP
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software distributed
8
+ # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
9
+ # CONDITIONS OF ANY KIND, either express or implied. See the License for the
10
+ # specific language governing permissions and limitations under the License.
11
+
12
+ module Hpe3parSdk
13
+ class WSAPIVersion
14
+ include Comparable
15
+ attr_accessor :major, :minor, :revision
16
+
17
+ def self.parse(version)
18
+ version_parts = version.split('.')
19
+ validate_version(version, version_parts)
20
+
21
+ @major = version_parts[0].to_i
22
+ @minor = version_parts[1].to_i
23
+ @revision = version_parts[2].to_i
24
+ obj_version = WSAPIVersion.new(@major, @minor, @revision)
25
+ return obj_version
26
+ end
27
+
28
+ def initialize(major, minor, revision)
29
+ @major = major
30
+ @minor = minor
31
+ @revision = revision
32
+ end
33
+
34
+ def <=>(other_version)
35
+ if major < other_version.major
36
+ return -1
37
+ end
38
+
39
+ if major > other_version.major
40
+ return 1
41
+ end
42
+
43
+ if minor < other_version.minor
44
+ return -1
45
+ end
46
+
47
+ if minor > other_version.minor
48
+ return 1
49
+ end
50
+
51
+ if revision < other_version.revision
52
+ return -1
53
+ end
54
+
55
+ if revision > other_version.revision
56
+ return 1
57
+ end
58
+
59
+ return 0
60
+ end
61
+
62
+ def to_s
63
+ major.to_s + '.' + minor.to_s + '.' + revision.to_s
64
+ end
65
+
66
+ private
67
+ def self.validate_version(version, version_parts)
68
+ if version_parts.length != 3
69
+ raise 'Invalid Version detected ' + version
70
+ end
71
+ end
72
+ end
73
+ end