Skip to content

Instantly share code, notes, and snippets.

@marcaurele
Last active April 1, 2017 17:17
Show Gist options
  • Save marcaurele/dc1774b1ea13d81be702faf235bf2afe to your computer and use it in GitHub Desktop.
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
#!/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