###############################################################################
##
##   Copyright (C) 2008 Virtual Iron Software, Inc.
##
##                          All Rights Reserved
##
##   This program is free software; you can redistribute it and/or modify
##   it under the terms of the GNU General Public License and GNU Library
##   General Public License as published by the Free Software Foundation;
##   either version 2, or (at your option) any later version.
##
##   This program is distributed in the hope that it will be useful,
##   but WITHOUT ANY WARRANTY; without even the implied warranty of
##   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
##   GNU General Public License and GNU Library General Public License
##   for more details.
##
##   You should have received a copy of the GNU General Public License
##   and GNU Library General Public License along with this program; if
##   not, write to the Free Software Foundation, 51 Franklin Street, 
##   Fifth Floor, Boston, MA 02110-1301 
##
###############################################################################
##
##  Script      : snapshotClone
##  Description : snapshot a VS's logical disks and clone to diskgroup
##
##  Requirements: VI version 4.4 or greater
##                only LogicalDisks are supported
##                DiskGroup may be specified as GUID or Alias
##
##  Note1: due to runner.sh(.bat) limitations, VS can't have spaces in its name
##  Note2: customer must pause VS guest apps prior to running script
##
###############################################################################
from com.virtualiron.vce.mgmt.api import VirtualizationManager
from com.virtualiron.vce.mgmt.api.physical import LogicalDisk, LvmGroup, Lvm
from com.virtualiron.vce.mgmt.api.virtual import VirtualServer
from com.virtualiron.vce.mgmt.api.util import Units
import java.lang
import os
import string
import sys
import traceback

def Usage():
	if os.name == 'nt':
		command = 'runner.bat'
	else:
		command = 'runner.sh'
	print 'Usage: %s --inputfile=snapshotClone.py --vs=<VirtualServer> --diskgroup=<DiskGroup>' % (command)
	sys.exit(1)

#
#  fraction of logical disk size for snapshot disk (default: 10%)
#
snapshotPercent = 0.1

#
# deleteLogicalDisk() - delete LogicalDisk in DiskGroup
#
isOnline = 1	

#
# parse command line arguments
#         --vs        :  name of VirtualServer 
#         --diskgroup :  name of DiskGroup
#
vsName   = None
dgName   = None
for arg in sys.argv[1:]:
	if string.find(arg, "--vs=") != -1:
		tokens = string.splitfields(arg, "=")
		vsName = tokens[1]
	elif string.find(arg, "--diskgroup=") != -1:
		tokens = string.splitfields(arg, "=")
		dgName = tokens[1]

#
# check if required arguments were specified
#
if vsName is None or dgName is None:
	Usage()

#
# get connection to Database
#
configurationManager = VirtualizationManager.getConfigurationManager()

#
# find VirtualServer 
#
vs = configurationManager.findObject(VirtualServer, vsName)
if vs is None:
	print 'FAIL to find VirtualServer: %s' % (vsName)
	sys.exit(1)

#
# find DiskGroup by GUID or alias
#
diskgroup = configurationManager.findObject(LvmGroup, dgName)
if diskgroup is None:
	# check all the diskgroup aliases too
	found = 0
	for diskgroup in configurationManager.getObjects(LvmGroup):
		if diskgroup.getAlias() and diskgroup.getAlias() == dgName:
			found = 1
			break
	if not found:
		print 'FAIL to find DiskGroup: %s' % (dgName)
		sys.exit(1)

#
# find all logical disks
#
diskList = java.util.ArrayList()
for device in vs.getStorageDevices():
	if LogicalDisk.isAssignableFrom(device.getKind()):
		diskList.add(device)
	else:
		print 'StorageDevice %s is not a LogicalDisk.  Ignore.' % (device)

if diskList.size() == 0:
	print 'No LogicalDisks to snapshot and export'
	sys.exit(0)


#
# snapshot logical disks.  Applications running on the VS should be shutdown 
#  and their data quiesent prior to create a clean snapshot.

print 'Step: Snapshot all Logical Disks of VS %s' % (vs.getName())

exportList = java.util.ArrayList()
for disk in diskList:

	bytes = long(disk.getSize(Units.StorageUnit.BYTE) * snapshotPercent)

	print ' Job: Create Snapshot of %s' % (disk)
	try:
		jobName = java.lang.Long.toString(configurationManager.getLocalTime())
		job = configurationManager.createJob(jobName)
		job.begin()

		#
	        snapdisk = disk.createSnapshot(bytes, Units.StorageUnit.BYTE)
		job.addOperationDescription("Snapshot " + disk.getName(), disk, disk, disk)

		try:
			job.commit()
			exportList.add(snapdisk)
		except java.lang.Throwable, throw:
			throw.printStackTrace()
		print "Result:", job.getStatusEvent()

	except java.lang.Throwable, throw:
		job.abort()		# if job fails, rollback
		throw.printStackTrace()
	except:
		job.abort()		# if job fails, rollback
		traceback.print_exc()


#
# fail if all snapshots failed
#
if exportList.size() == 0:
	print 'FAIL to snapshot any disks.  Stop'
	sys.exit(1)

#
#  clone all snapshots on this list
#
print "Step: Clone Snapshots to DiskGroup"

for disk in exportList:
	
	print ' Job: Clone Snapshot of %s to %s' % (disk.getSnapshotParent(), diskgroup) 
	try:
		jobName = java.lang.Long.toString(configurationManager.getLocalTime())
		job = configurationManager.createJob(jobName)
		job.begin()

        	clonedisk = disk.clone(diskgroup, Lvm.LvmType.LogicalDisk)
		job.addOperationDescription("Clone " + disk + " to " + diskgroup, disk, disk, disk)
	
		try:
			job.commit()
		except java.lang.Throwable, throw:
			throw.printStackTrace()
		print "Result:", job.getStatusEvent()

	except java.lang.Throwable, throw:
		job.abort()		# if job fails, rollback
		throw.printStackTrace()
	except:
		job.abort()		# if job fails, rollback
		traceback.print_exc()


#
# delete logical disk snapshots
#
print 'Step: Delete LogicalDisk Snapshots for VS %s' % (vs)
for disk in exportList:
	try:
		jobName = java.lang.Long.toString(configurationManager.getLocalTime())
		job = configurationManager.createJob(jobName)
		job.begin()

  		lvmDiskGroup = disk.getParentLvmDiskGroup()
		lvmDiskGroup.deleteLogicalDisk(disk, isOnline)
		job.addOperationDescription("Delete Snapshot Disk" + disk, disk, disk, disk)
		print " Job: Delete Snapshot of %s" % (disk.getSnapshotParent())

		job.commit()

	except java.lang.Throwable, throw:
		job.abort()		# if job fails, rollback
		throw.printStackTrace()
	except:
		job.abort()		# if job fails, rollback
		traceback.print_exc()

sys.exit(0)
