Commit b69acb06 authored by Kristian Feldsam's avatar Kristian Feldsam

3par driver, live snapshot, check and export

Signed-off-by: Kristian Feldsam's avatarKristián Feldsam <feldsam@gmail.com>
parent cb411335
#!/usr/bin/env python
import argparse
import urllib3
import pprint
import config
import pyone
import functions
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# ----------------------------
# Define parser
# ----------------------------
parser = argparse.ArgumentParser(description='OpenNebula Backup Tool')
parser.add_argument('-i', '--image', help='Image id or comma separated list of image ids to backup.'
'Omit for backup all images', type=functions.list_of_int_arg)
parser.add_argument('-S', '--startImage', help='Image id to start backup from. Backups all following images'
'including defined one', type=int)
parser.add_argument('-a', '--datastore', help='Datastore id or comma separated list of datastore ids to backup'
'from. Omit to backup from all datastores to backup',
type=functions.list_of_int_arg)
parser.add_argument('-l', '--label', help='Label or comma separated list of labels of tagged images or datastores',
type=functions.list_arg)
parser.add_argument('-e', '--exclude', help='Skip (exclude) by label or comma separated list of labels of tagged'
'images or datastores', type=functions.list_arg)
parser.add_argument('-D', '--deployments', help='Backup also deployments files from system datastores')
parser.add_argument('-d', '--dryRun', help='Dry run - not execute any commands, all cmds will be just printed')
parser.add_argument('-v', '--verbose', help='Verbose mode')
parser.add_argument('-i', '--image', help='Image id or comma separated list of image ids to backup. Omit for backup all images', type=functions.list_of_int_arg)
parser.add_argument('-S', '--startImage', help='Image id to start backup from. Backups all following images including defined one', type=int)
parser.add_argument('-a', '--dataStore', help='Datastore id or comma separated list of datastore ids to backup from. Omit to backup from all datastores to backup', type=functions.list_of_int_arg)
parser.add_argument('-l', '--label', help='Label or comma separated list of labels of tagged images or datastores', type=functions.list_arg)
parser.add_argument('-e', '--exclude', help='Skip (exclude) by label or comma separated list of labels of tagged images or datastores', type=functions.list_arg)
parser.add_argument('-D', '--deployments', help='Backup also deployments files from system datastores', action='store_true')
parser.add_argument('-d', '--dryRun', help='Dry run - not execute any commands, all cmds will be just printed', action='store_true')
parser.add_argument('-v', '--verbose', help='Verbose mode', action='store_true')
# -------------------------------------
# Parse args and proceed with execution
......@@ -39,7 +31,58 @@ args = parser.parse_args()
# -----------------------
one = pyone.OneServer(config.ONE['address'], session='%s:%s' % (config.ONE['username'], config.ONE['password']))
imagepool = one.imagepool.info(-2, -1, -1)
imagePool = one.imagepool.info(-2, -1, -1)
# connect and login to 3PAR
from drivers import _3par
_3par.login()
for image in imagePool.IMAGE:
dataStore = one.datastore.info(image.DATASTORE_ID)
# skip other datastores
if dataStore.TM_MAD != '3par':
continue
# persistent and attached to VM
if image.PERSISTENT == 1 and image.RUNNING_VMS > 0:
vmId = image.VMS.ID[0]
vm = one.vm.info(vmId)
vmDiskId = None
if isinstance(vm.TEMPLATE.get('DISK'), list):
for vmDisk in vm.TEMPLATE.get('DISK'):
if int(vmDisk.get('IMAGE_ID')) == image.ID:
vmDiskId = int(vmDisk.get('DISK_ID'))
break
else:
vmDiskId = int(vm.TEMPLATE.get('DISK').get('DISK_ID'))
if vmDiskId is None:
# error
print 'Can not found VM Disk ID for image %d:%s attached to VM %d:%s' % (image.ID, image.NAME, vmId, vm.NAME)
continue
if args.verbose:
print 'Backup persistent image %d:%s attached to VM %d:%s as disk %d' % (image.ID, image.NAME, vmId, vm.NAME, vmDiskId)
try:
_3par.backup_live(one, image, dataStore, vm, vmDiskId, args.verbose)
except Exception as ex:
print ex
continue
break
# persistent not attached
elif image.PERSISTENT == 1:
if args.verbose:
print 'Backup persistent not attached image %d:%s' % (image.ID, image.NAME)
# non-persistent
elif image.PERSISTENT == 0:
if args.verbose:
print 'Backup non-persistent image %d:%s' % (image.ID, image.NAME)
for image in imagepool.IMAGE:
print image.PERSISTENT
# disconnect form 3PAR
_3par.logout()
......@@ -20,3 +20,6 @@ _3PAR = {
'password': '3pardata',
'secure': True
}
# export volumes to host - backup host name defined in 3PAR
EXPORT_HOST = 'backup.hostname'
\ No newline at end of file
from hpe3parclient import client, exceptions
import config
# ------------------
# Login to 3PAR
# ------------------
cl = client.HPE3ParClient(config._3PAR['api'], config._3PAR['secure'])
cl.setSSHOptions(config._3PAR['ip'], config._3PAR['username'], config._3PAR['password'])
try:
cl.login(config._3PAR['username'], config._3PAR['password'])
except exceptions.HTTPUnauthorized as ex:
print "Login failed."
cl.logout()
\ No newline at end of file
import time
from hpe3parclient import client, exceptions
import config
cl = client.HPE3ParClient(config._3PAR['api'], False, config._3PAR['secure'], None, True)
def login():
cl.setSSHOptions(config._3PAR['ip'], config._3PAR['username'], config._3PAR['password'])
try:
cl.login(config._3PAR['username'], config._3PAR['password'])
except exceptions.HTTPUnauthorized:
print "Login failed."
def logout():
cl.logout()
def vv_name(source):
ex = source.split(':')
return ex[0]
def create_snapshot_name(src_name, snap_id):
name = '{srcName}.{snapId}'.format(srcName=src_name, snapId=snap_id)
return name
def export_vv(name, host):
# check if VLUN already exists
try:
vluns = cl.getHostVLUNs(host)
for vlun in vluns:
if vlun.get('volumeName') == name:
return int(vlun.get('lun'))
except exceptions.HTTPNotFound:
pass
# create VLUN
done = False
while not done:
try:
location = cl.createVLUN(name, None, host, None, None, None, True)
return int(location.split(',')[1])
except exceptions.HTTPConflict:
time.sleep(5)
def backup_live(one, image, data_store, vm, vm_disk_id, verbose):
# create live snapshot of image
if verbose:
print 'Creating live snapshot...'
snap_id = one.vm.disksnapshotcreate(vm.ID, vm_disk_id, 'Automatic Backup')
if snap_id is False:
raise Exception('Error creating snapshot!')
# get source name and create snap name
name = vv_name(image.SOURCE)
snap_name = create_snapshot_name(name, snap_id)
# wait until snapshot is created
if verbose:
print 'Waiting for snapshot to be created...'
time.sleep(5)
done = False
i = 0
while not done:
try:
volume = cl.getVolume(snap_name)
done = True
except exceptions.HTTPNotFound:
# failed after 60s
if i > 11:
raise Exception('Looks like snapshot is not created. Investigate VM logs')
i += 1
time.sleep(5)
# export VV to backup server
if verbose:
print 'Snapshot %d:%s created.' % (snap_id, snap_name)
print 'Exporting snapshot to backup server...'
lun_no = export_vv(snap_name, config.EXPORT_HOST)
wwn = volume.get('wwn')
if verbose:
print 'Snapshot is exported as LUN %d with WWN %s on %s' % (lun_no, wwn, config.EXPORT_HOST)
......@@ -3,8 +3,17 @@ def bool_arg(string):
return False
return True
def list_of_int_arg(string):
return map(int, string.split(','))
def list_arg(string):
return string.split(',')
\ No newline at end of file
return string.split(',')
def get_vm_hostname(vm):
if isinstance(vm.HISTORY_RECORDS.HISTORY, list):
return vm.HISTORY_RECORDS.HISTORY.pop().HOSTNAME
return vm.HISTORY_RECORDS.HISTORY.HOSTNAME
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment