Last active
April 1, 2017 17:17
-
-
Save marcaurele/dc1774b1ea13d81be702faf235bf2afe to your computer and use it in GitHub Desktop.
Script to live migrate a VM following the anti-affinity groups. You can also force a host for the destination of the migration, which will overrule the anti-affinity check
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# Author: Marc-Aurèle Brothier, Exoscale | |
# June 2016 | |
# Requirements: cs, click | |
import random | |
import time | |
from datetime import datetime, timedelta | |
import click | |
from cs import CloudStack, read_config | |
from requests.exceptions import ReadTimeout | |
@click.command() | |
@click.argument('vmid') | |
@click.option('--hostid', '-h', help='Target host uuid for the VM') | |
@click.option('--exclude', '-e', help='Hosts to exclude for the migration', | |
multiple=True) | |
@click.option('--wait/--nowait', default=True, show_default=True) | |
@click.option('--fake', is_flag=True) | |
def migrate_vm(vmid, hostid, exclude, wait, fake): | |
""" | |
This script connect to cloudstack API and migrate a VM to another host, | |
using the one provided as a parameter or a suitable one. If the VM has | |
anti-affinity groups, a suitable host will be picked up. You can | |
overrule this by specifying a host directly. | |
""" | |
cs = CloudStack(**read_config()) | |
delta = None | |
try: | |
csvm = cs.listVirtualMachines(id=vmid, | |
listall=True)['virtualmachine'][0] | |
print("VM is actually on host:") | |
print("\t* host id: %s" % csvm['hostid']) | |
print("\t* host name: %s" % csvm['hostname']) | |
if (len(csvm['affinitygroup']) > 0 and hostid is None): | |
# Need to list VMs associated to this AG and remove their hosts | |
print("") | |
for ag in csvm['affinitygroup']: | |
vm_ag = cs.listVirtualMachines(affinitygroupid=ag['id'], | |
listall=True)['virtualmachine'] | |
for v in vm_ag: | |
print(("\t+ host {} ({}) added to exclude list due to" | |
" anti-affinity group").format(v['hostname'], | |
v['hostid'])) | |
exclude = exclude + (v['hostid'], ) | |
if hostid is None: | |
hosts = [] | |
h = cs.findHostsForMigration(virtualmachineid=vmid)['host'] | |
for host in h: | |
if host['id'] not in exclude: | |
hosts.append(host) | |
print("Found %d host(s) to migrate the VM, choosing one randomly." | |
% len(hosts)) | |
host = random.choice(hosts) | |
print("VM will be migrated to host:") | |
print("\t* host id: %s" % host['id']) | |
print("\t* host name: %s" % host['name']) | |
print("\t* pod name: %s" % host['podname']) | |
hostid = host['id'] | |
else: | |
host = cs.listHosts(id=hostid)['host'][0] | |
print("VM will be migrated to host:") | |
print("\t* host id: %s" % host['id']) | |
print("\t* host name: %s" % host['name']) | |
print("\t* pod name: %s" % host['podname']) | |
hostid = host['id'] | |
if not fake: | |
job = cs.migrateVirtualMachineWithVolume(hostid=hostid, | |
virtualmachineid=vmid) | |
print("Job uuid: {}".format(job['jobid'])) | |
now = datetime.now() | |
start = now.timestamp() | |
print("Migration started at {}".format(now.isoformat(' '))) | |
if wait: | |
print("Waiting to finish...^C to stop waiting") | |
while True: | |
try: | |
res = cs.queryAsyncJobResult(**job) | |
if res['jobstatus'] != 0: | |
response = res['jobresult'] | |
delta = datetime.now().timestamp() - start | |
break | |
except KeyboardInterrupt: | |
print("\nExit at {}".format(datetime.now().isoformat(' '))) | |
return | |
except ReadTimeout: | |
pass | |
time.sleep(2) | |
try: | |
response = response['virtualmachine'] | |
print("VM has been migrated to:") | |
print("\t* host id: %s" % response['hostid']) | |
print("\t* host name: %s" % response['hostname']) | |
except Exception: | |
print("An error has occured") | |
print(response) | |
else: | |
print(">> FAKE! - VM has not been migrated to the host") | |
except Exception: | |
print("An error occured when migrating VM: %s" % vmid) | |
raise | |
finally: | |
print("Migration finished at {}".format(datetime.now().isoformat(' '))) | |
if delta is not None: | |
print('Took {}'.format( | |
timedelta(seconds=delta))) | |
# main | |
if __name__ == '__main__': | |
migrate_vm() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment