#!/usr/bin/env python

# LVHD Reliability test support plugin

import subprocess, sys, socket, struct, time, syslog
import os

import XenAPI, inventory

import XenAPIPlugin

def doexec(args, inputtext=None):
    """Execute a subprocess, then return its return code, stdout and stderr"""
    proc = subprocess.Popen(args,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,close_fds=True)
    (stdout,stderr) = proc.communicate(inputtext)
    rc = proc.returncode
    return (rc,stdout,stderr)

def writestringtofile(stem, string):
    filename = "/tmp/%s.log.%d" % (stem, os.getpid())
    f = file(filename, 'w')
    f.write(string)
    f.close()

def read_refcount_file(session,args):
    filename=args['filename']
    f = file("/var/run/sm/refcount/"+filename, 'r')
    contents = f.read()
    f.close()
    return contents

def mkfistpoint(session, args):
    fistpoint = args['fist_point']
    (rc,stdout,stderr) = doexec(["touch","/tmp/fist_%s" % fistpoint])
    return stdout

def rmfistpoint(session, args):
    fistpoint = args['fist_point']
    (rc,stdout,stderr) = doexec(["rm","-f","/tmp/fist_%s" % fistpoint])
    return stdout

def pattern(session, args):
    dev = args['dev']
    size = args['size']
    action = args['action']
    ty = args['type']
    variant = args['variant']
    (rc,stdout,stderr) = doexec(["/tmp/local/bm/scripts/remote/patterns.py",dev,size,action,ty,variant])
    
    writestringtofile("patterns-stdout", stdout)
    writestringtofile("patterns-stderr", stderr)

    if rc==0:
        return "OK"
    else:
        return "FAIL"
    
def check_zero(session, args):
    dev = args['dev']
    offset = int(args['offset'])
    length = int(args['length'])

    # Open file
    f = file(dev, 'r')
    f.seek(offset)
    
    if 'chunk_size' in args:
      chunk_size = args['chunk_size']
    else:
      chunk_size = 4096

    string_of_zeros = '\0' * chunk_size

    done = 0
    okay = True
    while done < length:
      block_size = min(length-done, chunk_size)
      # Read bytes from device
      b = f.read(block_size)
      # Test that we've got the expected number of bytes, and that they are all zero
      if len(b) < block_size or b <> string_of_zeros[0:block_size]:
        okay = False
	sys.stderr.write("Failed at block beginning at offset %d\n" % (offset+done))
        break
      done += block_size

    if okay:
      return "OK"
    else:
      return "FAIL"
    
def get_vdi_lsize(session, args):
    sruuid = args['sruuid']
    vdiuuid = args['vdiuuid']
    (rc,stdout,stderr) = doexec(["/usr/sbin/lvs","--units","b", "VG_XenStorage-%s" % sruuid])

    # Get the last field of the last line of output
    lines = stdout.rstrip().split('\n')
    # Find the line which contains the VDI
    vdiline = [elem for elem in lines if elem.find('VHD-%s'%vdiuuid)].pop()
    fields = vdiline.rstrip().split(' ')
    lastfield = fields.pop()

    # Remove the trailing "B"
    return lastfield.rstrip('B')

def get_sr_vfree(session, args):
    sruuid = args['sruuid']
    (rc,stdout,stderr) = doexec(["/usr/sbin/vgs","--units","b", "VG_XenStorage-%s" % sruuid])

    # Get the last field of the last line of output
    lines = stdout.rstrip().split('\n')
    lastline = lines.pop()
    fields = lastline.rstrip().split(' ')
    lastfield = fields.pop()

    # Remove the trailing "B"
    return lastfield.rstrip('B')

def get_journals(session, args):
    """Returns the names of any logical volumes which are not called 'MGT' or begin 'VHD-' or 'LV-'"""
    sruuid = args['sruuid']
    (rc,stdout,stderr) = doexec(["/usr/sbin/lvs","--noheadings","VG_XenStorage-%s" % sruuid])

    # Find the volumes which don't begin with 'MGT' or 'VHD-' or 'LV-'
    lines = stdout.rstrip().split('\n')
    volumes = [line.lstrip().split(' ').pop(0) for line in lines]
    journalvolumes = [vol for vol in volumes if vol <> "MGT" and vol.find('VHD-') != 0 and vol.find('LV-') != 0]

    # Return the volume names as a comma-separated list
    return ','.join(journalvolumes)

if __name__ == "__main__":
    XenAPIPlugin.dispatch({"pattern": pattern,
                           "mkfistpoint":mkfistpoint,
                           "rmfistpoint":rmfistpoint,
                           "check_zero":check_zero,
                           "read_refcount_file":read_refcount_file,
                           "get_vdi_lsize":get_vdi_lsize,
                           "get_sr_vfree":get_sr_vfree,
                           "get_journals":get_journals})

