#!/usr/bin/python -tt # skvidal # take builder/instance name # look for it on buildvmhost boxes # if it is there/up # confirm to kill it # destroy it # lvremove the disk # undefine it # import os import sys import socket from socket import gaierror import ansible import ansible.runner import ansible.playbook import time from ansible import callbacks from pprint import pprint import optparse def get_ans_results(results, hostname): if hostname in results['dark']: return results['dark'][hostname] if hostname in results['contacted']: return results['contacted'][hostname] return {} def confirm(): ans = raw_input() if ans.lower() == 'yes': return True return False def find_instance(conn, instance): vmdict = get_vm_to_host_map(conn) if instance in vmdict: return vmdict[instance] return None def get_vm_to_host_map(conn): conn.module_name='virt' conn.module_args='command=list_vms' res = conn.run() vm_to_host = {} for (host,data) in sorted(res['contacted'].items()): for vm in data['list_vms']: vm_to_host[vm] = host return vm_to_host def check_for_ans_error(results, hostname, err_codes=[], success_codes=[0], return_on_error=['stdout', 'stderr']): # returns True or False + dict # dict includes 'msg' # may include 'rc', 'stderr', 'stdout' and any other # requested result codes err_results = {} if 'dark' in results and hostname in results['dark']: err_results['msg'] = "Error: Could not contact/connect to %s." % hostname return (True, err_results) error = False if err_codes or success_codes: if hostname in results['contacted']: if 'rc' in results['contacted'][hostname]: rc = int(results['contacted'][hostname]['rc']) err_results['rc'] = rc # check for err codes first if rc in err_codes: error = True err_results['msg'] = 'rc %s matched err_codes' % rc elif rc not in success_codes: error = True err_results['msg'] = 'rc %s not in success_codes' % rc elif 'failed' in results['contacted'][hostname] and results['contacted'][hostname]['failed']: error = True err_results['msg'] = 'results included failed as true' if error: for item in return_on_error: if item in results['contacted'][hostname]: err_results[item] = results['contacted'][hostname][item] return error, err_results def vm_is_defined(conn, vm, vmhost): # get list of vms conn.module_name = 'virt' conn.module_args = 'command=list_vms' results = get_ans_results(conn.run(), vmhost) # if vm is in in there if vm in results.get('list_vms', []): return True return False def vm_is_alive(conn, vm, vmhost): if not vm_is_defined(conn, vm, vmhost): return False conn.module_name = 'virt' conn.module_args = 'command=status guest=%s' % vm results = get_ans_results(conn.run(), vmhost) if results.get('status', None) == 'running': return True return False def wait_for_host(hn, timeout=300): # watch for that host ssh to come up conn = ansible.runner.Runner(host_list=hn +',', pattern=hn, remote_user='root') is_up = False start = time.time() while not is_up: if time.time() - start >= timeout: raise Exception, "Hit Timeout waiting for %s to boot" % hn conn.module_name='ping' res = get_ans_results(conn.run(), hn) if res.get('ping'): is_up=True else: time.sleep(2) def parse_args(args): parser = optparse.OptionParser('\nkillvm [options] vm') parser.add_option('-i', '--inventory', default='/srv/web/infra/ansible/inventory', help="path to ansible inventory file") parser.add_option('-p', '--pattern', default='buildvmhost:bvirthost:virthost:colo-virt', help="ansible host pattern to use to look up vmhosts") parser.add_option('-y', '--yes', default=False, dest='yes', action="store_true", help='Do not confirm any of the destructive actions - just do them') parser.add_option('--vg', default='/dev/vg_host01', dest='vg', help='path to volumegroup to use on vmhost for vm disk: %default') opts, args = parser.parse_args(args) if not os.path.exists(opts.inventory): print "Could not find ansible inventory at: %s" % opts.inventory sys.exit(1) if len(args) != 1: parser.print_usage() sys.exit(1) return opts, args def main(): opts, args = parse_args(sys.argv[1:]) # args vm = args[0] try: ip = socket.gethostbyname(vm) except gaierror,e: print 'Could not find ip for %s' % vm return 1 if vm.find('.') == -1: print '%s was not a fqdn, cmon!' % vm return 1 s_vm = vm.split('.')[0] print 'Checking for %s' % vm conn = ansible.runner.Runner(host_list=opts.inventory, pattern=opts.pattern, timeout=20, forks=30, remote_user='root') vmhost = find_instance(conn, instance=vm) if not vmhost: print 'Could not find vm %s on any virthost in %s' % (vm, opts.pattern) sys.exit(1) print 'Found on %s' % vmhost vmhost_conn = ansible.runner.Runner(host_list=vmhost+',', pattern=vmhost, remote_user='root') if vm_is_defined(vmhost_conn, vm, vmhost): if vm_is_alive(vmhost_conn, vm, vmhost): if not opts.yes: print "%s is running. Okay to Destroy? ('yes' to confirm): " % vm, if not confirm(): print 'Exiting on user input' return 1 # destroy it vmhost_conn.module_args = "command=destroy guest=%s" % vm err, err_res = check_for_ans_error(vmhost_conn.run(), vmhost) if err: print 'Error destroying %s on %s' % (vm, vmhost) print err_res return 1 # undefine it if not opts.yes: print "%s is defined. Okay to Undefine? ('yes' to confirm): " % vm, if not confirm(): print 'Exiting on user input' return 1 vmhost_conn.module_args = "command=undefine guest=%s" % vm err, err_res = check_for_ans_error(vmhost_conn.run(), vmhost) if err: print 'Error undefining %s on %s' % (vm, vmhost) print err_res return 1 # check for the lv being allocated already lv_check = '/sbin/lvs %s/%s --noheadings' % (opts.vg, s_vm) vmhost_conn.module_name='command' vmhost_conn.module_args=lv_check results = get_ans_results(vmhost_conn.run(), vmhost) if 'rc' not in results: print 'Could not talk to vmhost about disks' return 1 if results['rc'] == 0: print 'Removing old disk: %s/%s' % (opts.vg, s_vm) # lvremove its disk lvrm='/sbin/lvremove -f %s/%s' % (opts.vg, s_vm) vmhost_conn.module_name='command' vmhost_conn.module_args=lvrm results = get_ans_results(vmhost_conn.run(), vmhost) if results.get('rc', None) != 0: print "Could not remove lv for old vm %s" % vm print results return 1 if __name__ == "__main__": sys.exit(main())