#!/usr/bin/env python

# This plugin takes a VDI uuid as a parameter and executes the following steps:
# 1. Copies the data contents to /tmp/*trash-vdi
# 2. Copies random data over the VDI
# 3. Waits for 1s
# 4. Copies the original data contents back
#
# Notes:
# * referenced VDI should be >= 16 MiB in size
# * referenced VDI must be in an LVHD-based SR
# * referenced VDI must be in VHD format (otherwise there is no metadata to corrupt)
# * referenced VDI must be mapped in (either it or a child must have an active device)

mib = 1024L * 1024L
min_vdi_size = 16L * mib # 16MiB otherwise dd might fail
lvhd_sr_types = [ "lvm", "lvmohba", "lvmoiscsi" ]

import os, sys, tempfile
import XenAPI, inventory
import XenAPIPlugin

sm_dir = "@BASE_PATH@/sm"

def dd(input, output):
    os.system("dd if=%s of=%s bs=1M count=16" % (input, output))

def trash(path):
    """Given the path to a LV whose active children *should* be paused, deliberately wipe and then restore
    the contents of the VDI to see whether anyone notices"""
    # 1. Copy the data contents to a temporary path
    tmp_path = tempfile.mktemp("trash-vdi")
    try:
        dd(path, tmp_path)
        try:
            dd("/dev/urandom", path)
        finally:
            # 4. Copy the original data back
            dd(tmp_path, path)
    finally:
        os.unlink(tmp_path)

def path_of_vdi(session, vdi_ref):
    """Given a reference to a VDI, return the path of the VHD-format LV"""
    if not(sm_dir in sys.path):
        sys.path.append(sm_dir)
    import lvhdutil

    sr_ref = session.xenapi.VDI.get_SR(vdi_ref)
    sr_uuid = session.xenapi.SR.get_uuid(sr_ref)
    
    vgname = lvhdutil.VG_PREFIX + sr_uuid
    path = os.path.join(lvhdutil.VG_LOCATION, vgname)

    vdi_uuid = session.xenapi.VDI.get_uuid(vdi_ref)

    return os.path.join(path, lvhdutil.LV_PREFIX[lvhdutil.VDI_TYPE_VHD] + vdi_uuid)

def main(session, args):
    if not('vdi-uuid' in args.keys()):
        raise "Missing parameter 'vdi-uuid'"
    vdi_uuid = args['vdi-uuid']
    vdi_ref = session.xenapi.VDI.get_by_uuid(vdi_uuid)
    size = long(session.xenapi.VDI.get_virtual_size(vdi_ref))
    if size < min_vdi_size:
        raise ("VDI is too small; actual size = %Ld; minimum acceptible size = %Ld" % (size, min_vdi_size))
    sr_ref = session.xenapi.VDI.get_SR(vdi_ref)
    sr_type = session.xenapi.SR.get_type(sr_ref)
    if not(sr_type in lvhd_sr_types):
        raise ("SR has type %s which is not LVHD-based (LVHD-based types are %s)" % (sr_type, repr(lvhd_sr_types)))
    path = path_of_vdi(session, vdi_ref)
    try:
        os.stat(path)
    except:
        # Since plug/unplugs are happening in parallel we'll get some transient glitches like this. Ignore them for now.
        return "LV inactive"
    # We now have the VDI's path
    trash(path)
    return "Data restored"

if __name__ == "__main__":
    XenAPIPlugin.dispatch({"main": main})
