From 74b5c614b0c9d2d3f5eff091be26c960e0a238c0 Mon Sep 17 00:00:00 2001 From: Arshad Ansari Date: Mon, 5 Nov 2018 06:26:30 -0500 Subject: [PATCH 1/4] Added remote_copy_manager.rb file --- lib/Hpe3parSdk/remote_copy_manager.rb | 131 ++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 lib/Hpe3parSdk/remote_copy_manager.rb diff --git a/lib/Hpe3parSdk/remote_copy_manager.rb b/lib/Hpe3parSdk/remote_copy_manager.rb new file mode 100644 index 0000000..99c7bd3 --- /dev/null +++ b/lib/Hpe3parSdk/remote_copy_manager.rb @@ -0,0 +1,131 @@ +require_relative 'util' +require_relative 'constants' +require_relative 'exceptions' +require_relative 'ssh' +require_relative 'models' + +module Hpe3parSdk + class RemoteCopyManager + def initialize(http, ssh) + @http = http + @ssh = ssh + end + + def get_remote_copy_info() + response, body = @http.get('/remotecopy') + body + end + + def get_remote_copy_groups() + response, body = @http.get('/remotecopygroups', body: info) + body + end + + def get_remote_copy_group(name) + response, body = @http.get('/remotecopygroups/#{name}') + body + end + + def create_remote_copy_group(name, targets, optional = nil) + info = { 'name' => name, + 'targets' => targets + } + info = Util.merge_hash(info, optional) if optional + response, body = @http.post('/remotecopygroups', body: info) + body + end + + def remove_remote_copy_group(name, keep_snap = false) + if keep_snap + snap_query = true + else + snap_query = false + end + response, body = @http.delete('/remotecopygroups/#{name}?keepSnap=#{snap_query}') + body + end + + def modify_remote_copy_group(name, optional = nil) + info = {} + info = Util.merge_hash(info, optional) if optional + response, body = @http.put('/remotecopygroups/#{name}', body: info) + body + end + + def add_volume_to_remote_copy_group(name, volumeName, targets, optional = nil, useHttpPost = false) + if not useHttpPost + info = { 'action' => 1, + 'volumeName' => volumeName, + 'targets' => targets + } + + info = Util.merge_hash(info, optional) if optional + + response, body = @http.put('/remotecopygroups/#{name}/volumes', body: info) + else + info = { 'volumeName' => volumeName, + 'targets' => targets + } + + info = Util.merge_hash(info, optional) if optional + + response, body = @http.post('/remotecopygroups/#{name}/volumes', body: info) + body + end + + def remove_volume_from_remote_copy_group(name, volumeName, optional = nil, removeFromTarget = false, useHttpDelete = false) + if not useHttpDelete + if removeFromTarget + if optional + keep_snap = optional.fetch('keepSnap', false) + else + keep_snap = false + end + + if keep_snap + cmd = ['dismissrcopyvv', '-f', '-keepsnap', '-removevv', volumeName, name] + command = cmd.join(" ") + else + cmd = ['dismissrcopyvv', '-f', '-removevv', volumeName, name] + command = cmd.join(" ") + end + @ssh.run(command) + else + info = { 'action' => 2, 'volumeName': volumeName } + info = Util.merge_hash(info, optional) if optional + @http.put('/remotecopygroups/#{name}', body: info) + end + else + #Need to add else part + + end + + def start_remote_copy_group(name, optional = nil) + info = { 'action' => 3 } + info = Util.merge_hash(info, optional) if optional + response, body = @http.put('/remotecopygroups/#{name}', body: info) + body + end + + def stop_remote_copy_group(name, optional = nil) + info = { 'action' => 4 } + info = Util.merge_hash(info, optional) if optional + response, body = @http.put('/remotecopygroups/#{name}', body: info) + body + end + + def synchronize_remote_copy_group(name, optional = nil) + info = { 'action' => 5 } + info = Util.merge_hash(info, optional) if optional + volumes_url = '/remotecopygroups/#{name}' + @http.put(volumes_url, body: info) + end + + def recover_remote_copy_group(name, action, optional = nil) + info = { 'action' => action } + info = Util.merge_hash(info, optional) if optional + volumes_url = '/remotecopygroups/#{name}' + response, body = @http.put(volumes_url, body: info) + body + end + From 5112729dad12413f4857a8a173f4a76790d0b371 Mon Sep 17 00:00:00 2001 From: Arshad Ansari Date: Tue, 6 Nov 2018 04:56:46 -0500 Subject: [PATCH 2/4] Added remote copy link related functions --- lib/Hpe3parSdk/remote_copy_manager.rb | 183 ++++++++++++++++++++++---- 1 file changed, 158 insertions(+), 25 deletions(-) diff --git a/lib/Hpe3parSdk/remote_copy_manager.rb b/lib/Hpe3parSdk/remote_copy_manager.rb index 99c7bd3..461b1a2 100644 --- a/lib/Hpe3parSdk/remote_copy_manager.rb +++ b/lib/Hpe3parSdk/remote_copy_manager.rb @@ -58,46 +58,57 @@ def add_volume_to_remote_copy_group(name, volumeName, targets, optional = nil, u 'volumeName' => volumeName, 'targets' => targets } - info = Util.merge_hash(info, optional) if optional - response, body = @http.put('/remotecopygroups/#{name}/volumes', body: info) else info = { 'volumeName' => volumeName, 'targets' => targets } - info = Util.merge_hash(info, optional) if optional - response, body = @http.post('/remotecopygroups/#{name}/volumes', body: info) + end body end def remove_volume_from_remote_copy_group(name, volumeName, optional = nil, removeFromTarget = false, useHttpDelete = false) if not useHttpDelete - if removeFromTarget - if optional - keep_snap = optional.fetch('keepSnap', false) - else - keep_snap = false - end + if removeFromTarget + if optional + keep_snap = optional.fetch('keepSnap', false) + else + keep_snap = false + end - if keep_snap - cmd = ['dismissrcopyvv', '-f', '-keepsnap', '-removevv', volumeName, name] - command = cmd.join(" ") - else - cmd = ['dismissrcopyvv', '-f', '-removevv', volumeName, name] - command = cmd.join(" ") - end - @ssh.run(command) - else - info = { 'action' => 2, 'volumeName': volumeName } - info = Util.merge_hash(info, optional) if optional - @http.put('/remotecopygroups/#{name}', body: info) - end + if keep_snap + cmd = ['dismissrcopyvv', '-f', '-keepsnap', '-removevv', volumeName, name] + command = cmd.join(" ") + else + cmd = ['dismissrcopyvv', '-f', '-removevv', volumeName, name] + command = cmd.join(" ") + end + @ssh.run(command) + else + info = { 'action' => 2, 'volumeName': volumeName } + info = Util.merge_hash(info, optional) if optional + response, body = @http.put('/remotecopygroups/#{name}', body: info) + end else - #Need to add else part - + option = nil + if optional and optional.get('keepSnap') and removeFromTarget + raise "keepSnap and removeFromTarget cannot be bpoth\ + true while removing the volume from remote copy group" + else if optional and optional.get('keepSnap') + option = 'keepSnap' + else if removeFromTarget + option = 'removeSecondaryVolume' + end + delete_url = '/remotecopygroups/#{name}/volumes/#{volumeName}' + if option + delete_url += '?#{option}=true' + end + response, body = @http.delete(delete_url) + end + body end def start_remote_copy_group(name, optional = nil) @@ -129,3 +140,125 @@ def recover_remote_copy_group(name, action, optional = nil) body end + def admit_remote_copy_links( targetName, source_port, target_port_wwn_or_ip) + source_target_port_pair = source_port + ':' + target_port_wwn_or_ip + begin + cmd = ['admitrcopylink', targetName, source_target_port_pair] + command = cmd.join(" ") + response = @ssh.run(command) + if response != [] + raise Hpe3parSdk::HPE3PARException(message: response) + end + rescue Hpe3parSdk::HPE3PARException => ex + raise Hpe3parSdk::HPE3PARException(ex.message) + end + response + end + + def dismiss_remote_copy_links( targetName, source_port, target_port_wwn_or_ip) + source_target_port_pair = source_port + ':' + target_port_wwn_or_ip + begin + cmd = ['dismissrcopylink', targetName, source_target_port_pair] + command = cmd.join(" ") + response = @ssh.run(command) + if response != [] + raise Hpe3parSdk::HPE3PARException(message: response) + end + rescue Hpe3parSdk::HPE3PARException => ex + raise Hpe3parSdk::HPE3PARException(ex.message) + end + response + end + + def start_rcopy() + begin + cmd = ['startrcopy'] + response = @ssh.run(cmd) + if response != [] + raise Hpe3parSdk::HPE3PARException(message: response) + end + rescue Hpe3parSdk::HPE3PARException => ex + raise Hpe3parSdk::HPE3PARException(ex.message) + end + response + end + + def rcopy_service_exists() + cmd = ['showrcopy'] + response = @ssh.run(cmd) + rcopyservice_status = false + if response[2].include?('Started') + rcopyservice_status = true + end + rcopyservice_status + end + + def get_remote_copy_link(link_name) + response, body = @http.get('/remotecopylinks/#{link_name}') + body + end + + def rcopy_link_exists(targetName, local_port, target_system_peer_port) + rcopylink_exits = false + link_name = targetName + '_' + local_port.replace(':', '_') + begin + response = self.get_remote_copy_link(link_name) + if response and response['address'] == target_system_peer_port + rcopylink_exits = true + end + rescue Hpe3parSdk::HTTPNotFound => ex + pass + end + rcopylink_exits + end + + def admit_remote_copy_target( targetName, mode, remote_copy_group_name, + source_target_volume_pairs_list=[]) + if source_target_volume_pairs_list == [] + cmd = ['admitrcopytarget', targetName, mode, remote_copy_group_name] + else + cmd = ['admitrcopytarget', targetName, mode, remote_copy_group_name] + for volume_pair_tuple in source_target_volume_pairs_list + source_target_pair = volume_pair_tuple[0] + ':' + volume_pair_tuple[1] + cmd << source_target_pair + end + end + begin + command = cmd.join(" ") + response = @ssh.run(command) + if response != [] + raise Hpe3parSdk::HPE3PARException(message: response) + end + rescue Hpe3parSdk::HPE3PARException => ex + raise Hpe3parSdk::HPE3PARException(ex.message) + end + response + end + + def dismiss_remote_copy_target( targetName, remote_copy_group_name) + option = '-f' + cmd = ['dismissrcopytarget', option, targetName, remote_copy_group_name] + begin + command = cmd.join(" ") + response = @ssh.run(command) + if response != [] + raise Hpe3parSdk::HPE3PARException(message: response) + end + rescue Hpe3parSdk::HPE3PARException => ex + raise Hpe3parSdk::HPE3PARException(ex.message) + end + response + end + + def target_in_remote_copy_group_exists( target_name, remote_copy_group_name) + begin + contents = self.get_remote_copy_group(remote_copy_group_name) + for item in contents['targets'] + if item['target'] == target_name + return true + end + end + rescue Hpe3parSdk::HPE3PARException => ex + end + return false + end From ce5aba9af59c7ea3dea1d6d116990d8661df61c9 Mon Sep 17 00:00:00 2001 From: Arshad Ansari Date: Tue, 6 Nov 2018 06:54:35 -0500 Subject: [PATCH 3/4] Added create_schedule function --- lib/Hpe3parSdk/remote_copy_manager.rb | 31 ++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/lib/Hpe3parSdk/remote_copy_manager.rb b/lib/Hpe3parSdk/remote_copy_manager.rb index 461b1a2..44767b3 100644 --- a/lib/Hpe3parSdk/remote_copy_manager.rb +++ b/lib/Hpe3parSdk/remote_copy_manager.rb @@ -202,7 +202,7 @@ def rcopy_link_exists(targetName, local_port, target_system_peer_port) rcopylink_exits = false link_name = targetName + '_' + local_port.replace(':', '_') begin - response = self.get_remote_copy_link(link_name) + response = get_remote_copy_link(link_name) if response and response['address'] == target_system_peer_port rcopylink_exits = true end @@ -262,3 +262,32 @@ def target_in_remote_copy_group_exists( target_name, remote_copy_group_name) end return false end + + def check_response(resp) + for r in resp + if 'error' in r.downcase or 'invalid' in r.downcase or 'the schedule format' in r.downcase + return r.strip + end + end + end + + def create_schedule(schedule_name, task, taskfreq='@hourly') + cmd = ['createsched'] + cmd << "\""+task+"\"" + if '@' not in taskfreq + cmd << "\""+taskfreq+"\"" + else + cmd << taskfreq + end + cmd << schedule_name + begin + command = cmd.join(" ") + response = @ssh.run(command) + err_resp = check_response(response) + if err_resp + raise Hpe3parSdk::HPE3PARException(message: err_resp) + end + rescue Hpe3parSdk::HPE3PARException => ex + raise Hpe3parSdk::HPE3PARException(ex.message) + end + end From 682a6db014ed57c09faf72a0b038831b2f3b75a5 Mon Sep 17 00:00:00 2001 From: Arshad Ansari Date: Mon, 12 Nov 2018 06:25:41 -0500 Subject: [PATCH 4/4] Added snapshot scheduling related functions in volume_manager.rb --- lib/Hpe3parSdk/remote_copy_manager.rb | 40 +++----- lib/Hpe3parSdk/volume_manager.rb | 133 ++++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 29 deletions(-) diff --git a/lib/Hpe3parSdk/remote_copy_manager.rb b/lib/Hpe3parSdk/remote_copy_manager.rb index 44767b3..025554a 100644 --- a/lib/Hpe3parSdk/remote_copy_manager.rb +++ b/lib/Hpe3parSdk/remote_copy_manager.rb @@ -26,6 +26,16 @@ def get_remote_copy_group(name) body end + def get_remote_copy_group_volumes(remoteCopyGroupName) + response, body = @http.get('/remotecopygroups/#{remoteCopyGroupName}/volumes') + body + end + + def get_remote_copy_group_volume(remoteCopyGroupName, volumeName) + response, body = @http.get('/remotecopygroups/#{remoteCopyGroupName}/volumes/#{volumeName}') + body + end + def create_remote_copy_group(name, targets, optional = nil) info = { 'name' => name, 'targets' => targets @@ -86,7 +96,7 @@ def remove_volume_from_remote_copy_group(name, volumeName, optional = nil, remov cmd = ['dismissrcopyvv', '-f', '-removevv', volumeName, name] command = cmd.join(" ") end - @ssh.run(command) + @ssh.run(command) else info = { 'action' => 2, 'volumeName': volumeName } info = Util.merge_hash(info, optional) if optional @@ -263,31 +273,3 @@ def target_in_remote_copy_group_exists( target_name, remote_copy_group_name) return false end - def check_response(resp) - for r in resp - if 'error' in r.downcase or 'invalid' in r.downcase or 'the schedule format' in r.downcase - return r.strip - end - end - end - - def create_schedule(schedule_name, task, taskfreq='@hourly') - cmd = ['createsched'] - cmd << "\""+task+"\"" - if '@' not in taskfreq - cmd << "\""+taskfreq+"\"" - else - cmd << taskfreq - end - cmd << schedule_name - begin - command = cmd.join(" ") - response = @ssh.run(command) - err_resp = check_response(response) - if err_resp - raise Hpe3parSdk::HPE3PARException(message: err_resp) - end - rescue Hpe3parSdk::HPE3PARException => ex - raise Hpe3parSdk::HPE3PARException(ex.message) - end - end diff --git a/lib/Hpe3parSdk/volume_manager.rb b/lib/Hpe3parSdk/volume_manager.rb index 0e52c87..126e9a3 100644 --- a/lib/Hpe3parSdk/volume_manager.rb +++ b/lib/Hpe3parSdk/volume_manager.rb @@ -302,5 +302,138 @@ def offline_physical_copy_exists?(src_name, phy_copy_name) return false end end + + def check_response(resp) + for r in resp + if 'error' in r.downcase or 'invalid' in r.downcase or 'the schedule format' in r.downcase + return r.strip + end + end + end + + def createSchedule(schedule_name, task, taskfreq='@hourly') + cmd = ['createsched'] + cmd << "\""+task+"\"" + if '@' not in taskfreq + cmd << "\""+taskfreq+"\"" + else + cmd << taskfreq + end + cmd << schedule_name + begin + command = cmd.join(" ") + response = @ssh.run(command) + err_resp = check_response(response) + if err_resp + raise Hpe3parSdk::HPE3PARException(message: err_resp) + else + for r in resp + if r.downcase.include? 'The schedule format is '\ +' or by @hourly @daily @monthly @weekly @monthly @yearly'.downcase + raise Hpe3parSdk::HPE3PARException(message: r.strip) + end + end + end + rescue Hpe3parSdk::HPE3PARException => ex + raise Hpe3parSdk::HPE3PARException(ex.message) + end + end + + def deleteSchedule(schedule_name) + cmd = ['removesched', '-f', schedule_name] + begin + command = cmd.join(" ") + response = @ssh.run(command) + err_resp = check_response(response) + if err_resp + err = 'Delete snapschedule failed Error is #{err_resp}' + raise Hpe3parSdk::HPE3PARException(message: err) + end + rescue Hpe3parSdk::HPE3PARException => ex + raise Hpe3parSdk::HPE3PARException(ex.message) + end + end + + def getSchedule(schedule_name) + cmd = ['showsched ', schedule_name] + begin + command = cmd.join(" ") + response = @ssh.run(command) + for r in response + if 'No scheduled tasks ' in r + msg = "Couldn't find the schedule #{schedule_name}" + raise Hpe3parSdk::HPE3PARException(message: msg) + end + end + rescue Hpe3parSdk::HPE3PARException => ex + raise Hpe3parSdk::HPE3PARException(ex.message) + end + response + end + + def modifySchedule(name, schedule_opt) + cmd = ['setsched'] + if 'newName' in schedule_opt + cmd << '-name' + cmd << schedule_opt['newName'] + end + if 'taskFrequency' in schedule_opt + cmd << '-s' + if '@' not in schedule_opt['taskFrequency'] + cmd << "\"" + schedule_opt['taskFrequency'] + "\"" + else + cmd << schedule_opt['taskFrequency'] + end + end + cmd << name + begin + command = cmd.join(" ") + response = @ssh.run(command) + err_resp = check_response(response) + if err_resp + raise Hpe3parSdk::HPE3PARException(message: err_resp) + else + for r in response + if r.downcase.include? 'The schedule format is '\ +' or by @hourly @daily @monthly @weekly @monthly @yearly'.downcase + raise Hpe3parSdk::HPE3PARException(message: r.strip) + end + end + end + rescue Hpe3parSdk::HPE3PARException => ex + raise Hpe3parSdk::HPE3PARException(ex.message) + end + end + + def suspendSchedule(schedule_name) + cmd = ['setsched', '-suspend', schedule_name] + begin + command = cmd.join(" ") + response = @ssh.run(command) + err_resp = check_response(response) + if err_resp + err = 'Schedule suspend failed Error is #{err_resp}' + raise Hpe3parSdk::HPE3PARException(message: err) + end + rescue Hpe3parSdk::HPE3PARException => ex + raise Hpe3parSdk::HPE3PARException(ex.message) + end + end + + def resumeSchedule(schedule_name) + cmd = ['setsched', '-resume', schedule_name] + begin + command = cmd.join(" ") + response = @ssh.run(command) + err_resp = check_response(response) + if err_resp + err = 'Schedule resume failed Error is #{err_resp}' + raise Hpe3parSdk::HPE3PARException(message: err) + end + rescue Hpe3parSdk::HPE3PARException => ex + raise Hpe3parSdk::HPE3PARException(ex.message) + end + end + end end