new_contents: #!/usr/bin/env python
  
  # Copyright 2012 OpenStack, LLC
  #
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  #
  # http://www.apache.org/licenses/LICENSE-2.0
  #
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  
  """
  This script is designed to cleanup any VHDs (and their descendents) which have
  a bad parent pointer.
  
  The script needs to be run in the dom0 of the affected host.
  
  The available actions are:
  
      - print: display the filenames of the affected VHDs
      - delete: remove the affected VHDs
      - move: move the affected VHDs out of the SR into another directory
  """
  import glob
  import os
  import subprocess
  import sys
  
  
  class ExecutionFailed(Exception):
      def __init__(self, returncode, stdout, stderr, max_stream_length=32):
          self.returncode = returncode
          self.stdout = stdout[:max_stream_length]
          self.stderr = stderr[:max_stream_length]
          self.max_stream_length = max_stream_length
  
      def __repr__(self):
          return "<ExecutionFailed returncode=%s out='%s' stderr='%s'>" % (
              self.returncode, self.stdout, self.stderr)
  
      __str__ = __repr__
  
  
  def execute(cmd, ok_exit_codes=None):
      if ok_exit_codes is None:
          ok_exit_codes = [0]
  
      proc = subprocess.Popen(
          cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  
      (stdout, stderr) = proc.communicate()
  
      if proc.returncode not in ok_exit_codes:
          raise ExecutionFailed(proc.returncode, stdout, stderr)
  
      return proc.returncode, stdout, stderr
  
  
  def usage():
      print "usage: %s <SR PATH> <print|delete|move>" % sys.argv[0]
      sys.exit(1)
  
  
  def main():
      if len(sys.argv) < 3:
          usage()
  
      sr_path = sys.argv[1]
      action = sys.argv[2]
  
      if action not in ('print', 'delete', 'move'):
          usage()
  
      if action == 'move':
          if len(sys.argv) < 4:
              print "error: must specify where to move bad VHDs"
              sys.exit(1)
  
          bad_vhd_path = sys.argv[3]
          if not os.path.exists(bad_vhd_path):
              os.makedirs(bad_vhd_path)
  
      bad_leaves = []
      descendents = {}
  
      for fname in glob.glob(os.path.join(sr_path, "*.vhd")):
          (returncode, stdout, stderr) = execute(
              ['vhd-util', 'query', '-n', fname, '-p'], ok_exit_codes=[0, 22])
  
          stdout = stdout.strip()
  
          if  stdout.endswith('.vhd'):
              try:
                  descendents[stdout].append(fname)
              except KeyError:
                  descendents[stdout] = [fname]
          elif 'query failed' in stdout:
              bad_leaves.append(fname)
  
      def walk_vhds(root):
          yield root
          if root in descendents:
              for child in descendents[root]:
                  for vhd in walk_vhds(child):
                      yield vhd
  
      for bad_leaf in bad_leaves:
          for bad_vhd in walk_vhds(bad_leaf):
              print bad_vhd
              if action == "print":
                  pass
              elif action == "delete":
                  os.unlink(bad_vhd)
              elif action == "move":
                  new_path = os.path.join(bad_vhd_path,
                                          os.path.basename(bad_vhd))
                  os.rename(bad_vhd, new_path)
              else:
                  raise Exception("invalid action %s" % action)
  
  
  if __name__ == '__main__':
      main()
  
subject: Add VDI chain cleanup script.