Convert VM functions to API client

This commit is contained in:
Joshua Boniface 2019-12-27 09:52:16 -05:00
parent f4ef08df49
commit d0b6bb4cc3
2 changed files with 407 additions and 174 deletions

View File

@ -21,6 +21,7 @@
############################################################################### ###############################################################################
import time import time
import re
import subprocess import subprocess
import click import click
import requests import requests
@ -45,6 +46,291 @@ def get_request_uri(config, endpoint):
# #
# Primary functions # Primary functions
# #
def vm_info(config, vm):
"""
Get information about VM
API endpoint: GET /api/v1/vm/{vm}
API arguments:
API schema: {json_data_object}
"""
request_uri = get_request_uri(config, '/vm/{vm}'.format(vm=vm))
response = requests.get(
request_uri
)
if config['debug']:
print('API endpoint: POST {}'.format(request_uri))
print('Response code: {}'.format(response.status_code))
print('Response headers: {}'.format(response.headers))
if response.status_code == 200:
return True, response.json()
else:
return False, response.json()['message']
def vm_list(config, limit, target_node, target_state):
"""
Get list information about nodes (limited by {limit}, {target_node}, or {target_state})
API endpoint: GET /api/v1/vm
API arguments: limit={limit}, node={target_node}, state={target_state}
API schema: [{json_data_object},{json_data_object},etc.]
"""
params = dict()
if limit:
params['limit'] = limit
if target_node:
params['node'] = target_node
if target_state:
params['state'] = target_state
request_uri = get_request_uri(config, '/vm')
response = requests.get(
request_uri,
params=params
)
if config['debug']:
print('API endpoint: POST {}'.format(request_uri))
print('Response code: {}'.format(response.status_code))
print('Response headers: {}'.format(response.headers))
if response.status_code == 200:
return True, response.json()
else:
return False, response.json()['message']
def vm_define(config, xml, node, node_limit, node_selector, node_autostart):
"""
Define a new VM on the cluster
API endpoint: POST /vm
API arguments: xml={xml}, node={node}, limit={node_limit}, selector={node_selector}, autostart={node_autostart}
API schema: {"message":"{data}"}
"""
request_uri = get_request_uri(config, '/vm')
response = requests.post(
request_uri,
params={
'xml': xml,
'node': node,
'limit': node_limit,
'selector': node_selector,
'autostart': node_autostart
}
)
if config['debug']:
print('API endpoint: POST {}'.format(request_uri))
print('Response code: {}'.format(response.status_code))
print('Response headers: {}'.format(response.headers))
if response.status_code == 200:
retstatus = True
else:
retstatus = False
return retstatus, response.json()['message']
def vm_modify(config, vm, xml, restart):
"""
Modify the configuration of VM
API endpoint: POST /vm/{vm}
API arguments: xml={xml}, restart={restart}
API schema: {"message":"{data}"}
"""
request_uri = get_request_uri(config, '/vm/{vm}'.format(vm=vm))
response = requests.post(
request_uri,
params={
'xml': xml,
'restart': restart
}
)
if config['debug']:
print('API endpoint: POST {}'.format(request_uri))
print('Response code: {}'.format(response.status_code))
print('Response headers: {}'.format(response.headers))
if response.status_code == 200:
retstatus = True
else:
retstatus = False
return retstatus, response.json()['message']
def vm_metadata(config, vm, node_limit, node_selector, node_autostart):
"""
Modify PVC metadata of a VM
API endpoint: GET /vm/{vm}/meta, POST /vm/{vm}/meta
API arguments: limit={node_limit}, selector={node_selector}, autostart={node_autostart}
API schema: {"message":"{data}"}
"""
request_uri = get_request_uri(config, '/vm/{vm}/meta'.format(vm=vm))
# Get the existing metadata so we can perform a fully dynamic update
response = requests.get(
request_uri
)
if config['debug']:
print('API endpoint: GET {}'.format(request_uri))
print('Response code: {}'.format(response.status_code))
print('Response headers: {}'.format(response.headers))
metadata = response.json()
# Update any params that we've sent
if node_limit is not None:
metadata['node_limit'] = node_limit
else:
# Collapse the existing list back down to a CSV
metadata['node_limit'] = ','.join(metadata['node_limit'])
if node_selector is not None:
metadata['node_selector'] = node_selector
if node_autostart is not None:
metadata['node_autostart'] = node_autostart
# Write the new metadata
print(metadata['node_limit'])
response = requests.post(
request_uri,
params={
'limit': metadata['node_limit'],
'selector': metadata['node_selector'],
'autostart': metadata['node_autostart']
}
)
if config['debug']:
print('API endpoint: POST {}'.format(request_uri))
print('Response code: {}'.format(response.status_code))
print('Response headers: {}'.format(response.headers))
if response.status_code == 200:
retstatus = True
else:
retstatus = False
return retstatus, response.json()['message']
def vm_remove(config, vm, delete_disks=False):
"""
Remove a VM
API endpoint: DELETE /vm/{vm}
API arguments: delete_disks={delete_disks}
API schema: {"message":"{data}"}
"""
request_uri = get_request_uri(config, '/vm/{vm}'.format(vm=vm))
response = requests.delete(
request_uri,
params={
'delete_disks': delete_disks
}
)
if config['debug']:
print('API endpoint: DELETE {}'.format(request_uri))
print('Response code: {}'.format(response.status_code))
print('Response headers: {}'.format(response.headers))
if response.status_code == 200:
retstatus = True
else:
retstatus = False
return retstatus, response.json()['message']
def vm_state(config, vm, target_state):
"""
Modify the current state of VM
API endpoint: POST /vm/{vm}/state
API arguments: state={state}
API schema: {"message":"{data}"}
"""
request_uri = get_request_uri(config, '/vm/{vm}/state'.format(vm=vm))
response = requests.post(
request_uri,
params={
'state': target_state,
}
)
if config['debug']:
print('API endpoint: POST {}'.format(request_uri))
print('Response code: {}'.format(response.status_code))
print('Response headers: {}'.format(response.headers))
if response.status_code == 200:
retstatus = True
else:
retstatus = False
return retstatus, response.json()['message']
def vm_node(config, vm, target_node, action, force=False):
"""
Modify the current node of VM via {action}
API endpoint: POST /vm/{vm}/node
API arguments: node={target_node}, action={action}, force={force}
API schema: {"message":"{data}"}
"""
request_uri = get_request_uri(config, '/vm/{vm}/node'.format(vm=vm))
response = requests.post(
request_uri,
params={
'node': target_node,
'action': action,
'force': force
}
)
if config['debug']:
print('API endpoint: POST {}'.format(request_uri))
print('Response code: {}'.format(response.status_code))
print('Response headers: {}'.format(response.headers))
if response.status_code == 200:
retstatus = True
else:
retstatus = False
return retstatus, response.json()['message']
def vm_locks(config, vm):
"""
Flush RBD locks of (stopped) VM
API endpoint: POST /vm/{vm}/locks
API arguments:
API schema: {"message":"{data}"}
"""
request_uri = get_request_uri(config, '/vm/{vm}/locks'.format(vm=vm))
response = requests.post(
request_uri
)
if config['debug']:
print('API endpoint: POST {}'.format(request_uri))
print('Response code: {}'.format(response.status_code))
print('Response headers: {}'.format(response.headers))
if response.status_code == 200:
retstatus = True
else:
retstatus = False
return retstatus, response.json()['message']
def view_console_log(config, vm, lines=100): def view_console_log(config, vm, lines=100):
""" """
Return console log lines from the API and display them in a pager Return console log lines from the API and display them in a pager
@ -54,28 +340,15 @@ def view_console_log(config, vm, lines=100):
API schema: {"name":"{vmname}","data":"{console_log}"} API schema: {"name":"{vmname}","data":"{console_log}"}
""" """
request_uri = get_request_uri(config, '/vm/{vm}/console'.format(vm=vm)) request_uri = get_request_uri(config, '/vm/{vm}/console'.format(vm=vm))
if config['debug']:
print(
'API endpoint: GET {}'.format(request_uri)
)
# Get the data from the API
response = requests.get( response = requests.get(
request_uri, request_uri,
params={'lines': lines} params={'lines': lines}
) )
if config['debug']: if config['debug']:
print( print('API endpoint: GET {}'.format(request_uri))
'Response code: {}'.format( print('Response code: {}'.format(response.status_code))
response.status_code print('Response headers: {}'.format(response.headers))
)
)
print(
'Response headers: {}'.format(
response.headers
)
)
console_log = response.json()['data'] console_log = response.json()['data']
@ -102,28 +375,15 @@ def follow_console_log(config, vm, lines=10):
API schema: {"name":"{vmname}","data":"{console_log}"} API schema: {"name":"{vmname}","data":"{console_log}"}
""" """
request_uri = get_request_uri(config, '/vm/{vm}/console'.format(vm=vm)) request_uri = get_request_uri(config, '/vm/{vm}/console'.format(vm=vm))
if config['debug']:
print(
'API endpoint: GET {}'.format(request_uri)
)
# Get the (initial) data from the API
response = requests.get( response = requests.get(
request_uri, request_uri,
params={'lines': lines} params={'lines': lines}
) )
if config['debug']: if config['debug']:
print( print('API endpoint: GET {}'.format(request_uri))
'Response code: {}'.format( print('Response code: {}'.format(response.status_code))
response.status_code print('Response headers: {}'.format(response.headers))
)
)
print(
'Response headers: {}'.format(
response.headers
)
)
console_log = response.json()['data'] console_log = response.json()['data']
@ -261,11 +521,16 @@ def format_info(config, domain_information, long_output):
net_vni = net_vnis[0] net_vni = net_vnis[0]
else: else:
net_vni = re.sub('br', '', net['source']) net_vni = re.sub('br', '', net['source'])
net_exists = zkhandler.exists(zk_conn, '/networks/{}'.format(net_vni))
if not net_exists and net_vni != 'cluster': request_uri = get_request_uri(config, '/network/{net}'.format(net=net_vni))
response = requests.get(
request_uri
)
if response.status_code != 200 and net_vni != 'cluster':
net_list.append(ansiprint.red() + net_vni + ansiprint.end() + ' [invalid]') net_list.append(ansiprint.red() + net_vni + ansiprint.end() + ' [invalid]')
else: else:
net_list.append(net_vni) net_list.append(net_vni)
ainformation.append('') ainformation.append('')
ainformation.append('{}Networks:{} {}'.format(ansiprint.purple(), ansiprint.end(), ', '.join(net_list))) ainformation.append('{}Networks:{} {}'.format(ansiprint.purple(), ansiprint.end(), ', '.join(net_list)))
@ -383,6 +648,8 @@ def format_list(config, vm_list, raw):
) )
) )
# Keep track of nets we found to be valid to cut down on duplicate API hits
valid_net_list = []
# Format the string (elements) # Format the string (elements)
for domain_information in vm_list: for domain_information in vm_list:
if domain_information['state'] == 'start': if domain_information['state'] == 'start':
@ -403,9 +670,16 @@ def format_list(config, vm_list, raw):
net_list = [] net_list = []
vm_net_colour = '' vm_net_colour = ''
for net_vni in raw_net_list: for net_vni in raw_net_list:
net_exists = zkhandler.exists(zk_conn, '/networks/{}'.format(net_vni)) if not net_vni in valid_net_list:
if not net_exists and net_vni != 'cluster': request_uri = get_request_uri(config, '/network/{net}'.format(net=net_vni))
response = requests.get(
request_uri
)
if response.status_code != 200 and net_vni != 'cluster':
vm_net_colour = ansiprint.red() vm_net_colour = ansiprint.red()
else:
valid_net_list.append(net_vni)
net_list.append(net_vni) net_list.append(net_vni)
vm_list_output.append( vm_list_output.append(
@ -442,4 +716,3 @@ def format_list(config, vm_list, raw):
click.echo('\n'.join(sorted(vm_list_output))) click.echo('\n'.join(sorted(vm_list_output)))
return True, '' return True, ''

View File

@ -29,6 +29,7 @@ import difflib
import re import re
import colorama import colorama
import yaml import yaml
import lxml.etree as etree
import requests import requests
import cli_lib.ansiprint as ansiprint import cli_lib.ansiprint as ansiprint
@ -232,16 +233,12 @@ def vm_define(config, target_node, node_limit, node_selector, node_autostart):
Define a new virtual machine from Libvirt XML configuration file CONFIG. Define a new virtual machine from Libvirt XML configuration file CONFIG.
""" """
if node_limit:
node_limit = node_limit.split(',')
# Open the XML file # Open the XML file
config_data = config.read() config_data = config.read()
config.close() config.close()
zk_conn = pvc_common.startZKConnection(zk_host)
retcode, retmsg = pvc_vm.define_vm(zk_conn, config_data, target_node, node_limit, node_selector, node_autostart) retcode, retmsg = pvc_vm.define_vm(zk_conn, config_data, target_node, node_limit, node_selector, node_autostart)
cleanup(retcode, retmsg, zk_conn) cleanup(retcode, retmsg)
############################################################################### ###############################################################################
# pvc vm meta # pvc vm meta
@ -271,12 +268,8 @@ def vm_meta(domain, node_limit, node_selector, node_autostart):
if node_limit is None and node_selector is None and node_autostart is None: if node_limit is None and node_selector is None and node_autostart is None:
cleanup(False, 'At least one metadata option must be specified to update.') cleanup(False, 'At least one metadata option must be specified to update.')
if node_limit: retcode, retmsg = pvc_vm.vm_metadata(config, domain, node_limit, node_selector, node_autostart)
node_limit = node_limit.split(',') cleanup(retcode, retmsg)
zk_conn = pvc_common.startZKConnection(zk_host)
retcode, retmsg = pvc_vm.modify_vm_metadata(zk_conn, domain, node_limit, node_selector, node_autostart)
cleanup(retcode, retmsg, zk_conn)
############################################################################### ###############################################################################
# pvc vm modify # pvc vm modify
@ -294,31 +287,33 @@ def vm_meta(domain, node_limit, node_selector, node_autostart):
'domain' 'domain'
) )
@click.argument( @click.argument(
'config', type=click.File(), default=None, required=False 'cfgfile', type=click.File(), default=None, required=False
) )
def vm_modify(domain, config, editor, restart): def vm_modify(domain, cfgfile, editor, restart):
""" """
Modify existing virtual machine DOMAIN, either in-editor or with replacement CONFIG. DOMAIN may be a UUID or name. Modify existing virtual machine DOMAIN, either in-editor or with replacement CONFIG. DOMAIN may be a UUID or name.
""" """
if editor == False and config == None: if editor == False and cfgfile == None:
cleanup(False, 'Either an XML config file or the "--editor" option must be specified.') cleanup(False, 'Either an XML config file or the "--editor" option must be specified.')
zk_conn = pvc_common.startZKConnection(zk_host) retcode, vm_information = pvc_vm.vm_info(config, domain)
if not retcode and not vm_information.get('name', None):
dom_uuid = pvc_vm.getDomainUUID(zk_conn, domain)
if dom_uuid == None:
cleanup(False, 'ERROR: Could not find VM "{}" in the cluster!'.format(domain)) cleanup(False, 'ERROR: Could not find VM "{}" in the cluster!'.format(domain))
dom_name = pvc_vm.getDomainName(zk_conn, dom_uuid)
dom_uuid = vm_information.get('uuid')
dom_name = vm_information.get('name')
if editor == True: if editor == True:
# Grab the current config # Grab the current config
current_vm_config = zk_conn.get('/domains/{}/xml'.format(dom_uuid))[0].decode('ascii') current_vm_cfg_raw = vm_information.get('xml')
xml_data = etree.fromstring(current_vm_cfg_raw)
current_vm_cfgfile = etree.tostring(xml_data, pretty_print=True).decode('utf8')
# Write it to a tempfile # Write it to a tempfile
fd, path = tempfile.mkstemp() fd, path = tempfile.mkstemp()
fw = os.fdopen(fd, 'w') fw = os.fdopen(fd, 'w')
fw.write(current_vm_config) fw.write(current_vm_cfgfile.strip())
fw.close() fw.close()
# Edit it # Edit it
@ -327,14 +322,14 @@ def vm_modify(domain, config, editor, restart):
# Open the tempfile to read # Open the tempfile to read
with open(path, 'r') as fr: with open(path, 'r') as fr:
new_vm_config = fr.read() new_vm_cfgfile = fr.read()
fr.close() fr.close()
# Delete the tempfile # Delete the tempfile
os.unlink(path) os.unlink(path)
# Show a diff and confirm # Show a diff and confirm
diff = list(difflib.unified_diff(current_vm_config.split('\n'), new_vm_config.split('\n'), fromfile='current', tofile='modified', fromfiledate='', tofiledate='', n=3, lineterm='')) diff = list(difflib.unified_diff(current_vm_cfgfile.split('\n'), new_vm_cfgfile.split('\n'), fromfile='current', tofile='modified', fromfiledate='', tofiledate='', n=3, lineterm=''))
if len(diff) < 1: if len(diff) < 1:
click.echo('Aborting with no modifications.') click.echo('Aborting with no modifications.')
exit(0) exit(0)
@ -355,23 +350,23 @@ def vm_modify(domain, config, editor, restart):
click.confirm('Write modifications to Zookeeper?', abort=True) click.confirm('Write modifications to Zookeeper?', abort=True)
if restart: if restart:
click.echo('Writing modified config of VM "{}" and restarting.'.format(dom_name)) click.echo('Writing modified configuration of VM "{}" and restarting.'.format(dom_name))
else: else:
click.echo('Writing modified config of VM "{}".'.format(dom_name)) click.echo('Writing modified configuration of VM "{}".'.format(dom_name))
# We're operating in replace mode # We're operating in replace mode
else: else:
# Open the XML file # Open the XML file
new_vm_config = config.read() new_vm_cfgfile = cfgfile.read()
config.close() cfgfile.close()
if restart: if restart:
click.echo('Replacing config of VM "{}" with file "{}" and restarting.'.format(dom_name, config.name)) click.echo('Replacing configuration of VM "{}" with file "{}" and restarting.'.format(dom_name, cfgfile.name))
else: else:
click.echo('Replacing config of VM "{}" with file "{}".'.format(dom_name, config.name)) click.echo('Replacing configuration of VM "{}" with file "{}".'.format(dom_name, cfgfile.name))
retcode, retmsg = pvc_vm.modify_vm(zk_conn, domain, restart, new_vm_config) retcode, retmsg = pvc_vm.vm_modify(config, domain, new_vm_config, restart)
cleanup(retcode, retmsg, zk_conn) cleanup(retcode, retmsg)
############################################################################### ###############################################################################
# pvc vm undefine # pvc vm undefine
@ -385,15 +380,8 @@ def vm_undefine(domain):
Stop virtual machine DOMAIN and remove it from the cluster database, preserving disks. DOMAIN may be a UUID or name. Stop virtual machine DOMAIN and remove it from the cluster database, preserving disks. DOMAIN may be a UUID or name.
""" """
# Ensure at least one search method is set retcode, retmsg = pvc_vm.vm_remove(config, domain, delete_disks=False)
if domain == None: cleanup(retcode, retmsg)
click.echo("ERROR: You must specify either a name or UUID value.")
exit(1)
# Open a Zookeeper connection
zk_conn = pvc_common.startZKConnection(zk_host)
retcode, retmsg = pvc_vm.undefine_vm(zk_conn, domain, is_cli=True)
cleanup(retcode, retmsg, zk_conn)
############################################################################### ###############################################################################
# pvc vm remove # pvc vm remove
@ -407,37 +395,8 @@ def vm_remove(domain):
Stop virtual machine DOMAIN and remove it, along with all disks, from the cluster. DOMAIN may be a UUID or name. Stop virtual machine DOMAIN and remove it, along with all disks, from the cluster. DOMAIN may be a UUID or name.
""" """
# Ensure at least one search method is set retcode, retmsg = pvc_vm.vm_remove(config, domain, delete_disks=True)
if domain == None: cleanup(retcode, retmsg)
click.echo("ERROR: You must specify either a name or UUID value.")
exit(1)
# Open a Zookeeper connection
zk_conn = pvc_common.startZKConnection(zk_host)
retcode, retmsg = pvc_vm.remove_vm(zk_conn, domain, is_cli=True)
cleanup(retcode, retmsg, zk_conn)
###############################################################################
# pvc vm dump
###############################################################################
@click.command(name='dump', short_help='Dump a virtual machine XML to stdout.')
@click.argument(
'domain'
)
def vm_dump(domain):
"""
Dump the Libvirt XML definition of virtual machine DOMAIN to stdout. DOMAIN may be a UUID or name.
"""
# Ensure at least one search method is set
if domain == None:
click.echo("ERROR: You must specify either a name or UUID value.")
exit(1)
# Open a Zookeeper connection
zk_conn = pvc_common.startZKConnection(zk_host)
retcode, retmsg = pvc_vm.dump_vm(zk_conn, domain)
cleanup(retcode, retmsg, zk_conn)
############################################################################### ###############################################################################
# pvc vm start # pvc vm start
@ -451,10 +410,8 @@ def vm_start(domain):
Start virtual machine DOMAIN on its configured node. DOMAIN may be a UUID or name. Start virtual machine DOMAIN on its configured node. DOMAIN may be a UUID or name.
""" """
# Open a Zookeeper connection retcode, retmsg = pvc_vm.vm_state(config, domain, 'start')
zk_conn = pvc_common.startZKConnection(zk_host) cleanup(retcode, retmsg)
retcode, retmsg = pvc_vm.start_vm(zk_conn, domain)
cleanup(retcode, retmsg, zk_conn)
############################################################################### ###############################################################################
# pvc vm restart # pvc vm restart
@ -468,10 +425,8 @@ def vm_restart(domain):
Restart running virtual machine DOMAIN. DOMAIN may be a UUID or name. Restart running virtual machine DOMAIN. DOMAIN may be a UUID or name.
""" """
# Open a Zookeeper connection retcode, retmsg = pvc_vm.vm_state(config, domain, 'restart')
zk_conn = pvc_common.startZKConnection(zk_host) cleanup(retcode, retmsg)
retcode, retmsg = pvc_vm.restart_vm(zk_conn, domain)
cleanup(retcode, retmsg, zk_conn)
############################################################################### ###############################################################################
# pvc vm shutdown # pvc vm shutdown
@ -485,10 +440,8 @@ def vm_shutdown(domain):
Gracefully shut down virtual machine DOMAIN. DOMAIN may be a UUID or name. Gracefully shut down virtual machine DOMAIN. DOMAIN may be a UUID or name.
""" """
# Open a Zookeeper connection retcode, retmsg = pvc_vm.vm_state(config, domain, 'shutdown')
zk_conn = pvc_common.startZKConnection(zk_host) cleanup(retcode, retmsg)
retcode, retmsg = pvc_vm.shutdown_vm(zk_conn, domain)
cleanup(retcode, retmsg, zk_conn)
############################################################################### ###############################################################################
# pvc vm stop # pvc vm stop
@ -502,10 +455,8 @@ def vm_stop(domain):
Forcibly halt (destroy) running virtual machine DOMAIN. DOMAIN may be a UUID or name. Forcibly halt (destroy) running virtual machine DOMAIN. DOMAIN may be a UUID or name.
""" """
# Open a Zookeeper connection retcode, retmsg = pvc_vm.vm_state(config, domain, 'stop')
zk_conn = pvc_common.startZKConnection(zk_host) cleanup(retcode, retmsg)
retcode, retmsg = pvc_vm.stop_vm(zk_conn, domain)
cleanup(retcode, retmsg, zk_conn)
############################################################################### ###############################################################################
# pvc vm disable # pvc vm disable
@ -521,10 +472,8 @@ def vm_disable(domain):
Use this option for VM that are stopped intentionally or long-term and which should not impact cluster health if stopped. A VM can be started directly from disable state. Use this option for VM that are stopped intentionally or long-term and which should not impact cluster health if stopped. A VM can be started directly from disable state.
""" """
# Open a Zookeeper connection retcode, retmsg = pvc_vm.vm_state(config, domain, 'disable')
zk_conn = pvc_common.startZKConnection(zk_host) cleanup(retcode, retmsg)
retcode, retmsg = pvc_vm.disable_vm(zk_conn, domain)
cleanup(retcode, retmsg, zk_conn)
############################################################################### ###############################################################################
# pvc vm move # pvc vm move
@ -542,10 +491,8 @@ def vm_move(domain, target_node):
Permanently move virtual machine DOMAIN, via live migration if running and possible, to another node. DOMAIN may be a UUID or name. Permanently move virtual machine DOMAIN, via live migration if running and possible, to another node. DOMAIN may be a UUID or name.
""" """
# Open a Zookeeper connection retcode, retmsg = pvc_vm.vm_node(config, domain, target_node, 'move', force=False)
zk_conn = pvc_common.startZKConnection(zk_host) cleanup(retcode, retmsg)
retcode, retmsg = pvc_vm.move_vm(zk_conn, domain, target_node)
cleanup(retcode, retmsg, zk_conn)
############################################################################### ###############################################################################
# pvc vm migrate # pvc vm migrate
@ -567,10 +514,8 @@ def vm_migrate(domain, target_node, force_migrate):
Temporarily migrate running virtual machine DOMAIN, via live migration if possible, to another node. DOMAIN may be a UUID or name. If DOMAIN is not running, it will be started on the target node. Temporarily migrate running virtual machine DOMAIN, via live migration if possible, to another node. DOMAIN may be a UUID or name. If DOMAIN is not running, it will be started on the target node.
""" """
# Open a Zookeeper connection retcode, retmsg = pvc_vm.vm_node(config, domain, target_node, 'migrate', force=force_migrate)
zk_conn = pvc_common.startZKConnection(zk_host) cleanup(retcode, retmsg)
retcode, retmsg = pvc_vm.migrate_vm(zk_conn, domain, target_node, force_migrate, is_cli=True)
cleanup(retcode, retmsg, zk_conn)
############################################################################### ###############################################################################
# pvc vm unmigrate # pvc vm unmigrate
@ -584,10 +529,8 @@ def vm_unmigrate(domain):
Restore previously migrated virtual machine DOMAIN, via live migration if possible, to its original node. DOMAIN may be a UUID or name. If DOMAIN is not running, it will be started on the target node. Restore previously migrated virtual machine DOMAIN, via live migration if possible, to its original node. DOMAIN may be a UUID or name. If DOMAIN is not running, it will be started on the target node.
""" """
# Open a Zookeeper connection retcode, retmsg = pvc_vm.vm_node(config, domain, None, 'unmigrate', force=False)
zk_conn = pvc_common.startZKConnection(zk_host) cleanup(retcode, retmsg)
retcode, retmsg = pvc_vm.unmigrate_vm(zk_conn, domain)
cleanup(retcode, retmsg, zk_conn)
############################################################################### ###############################################################################
# pvc vm flush-locks # pvc vm flush-locks
@ -601,34 +544,8 @@ def vm_flush_locks(domain):
Flush stale RBD locks for virtual machine DOMAIN. DOMAIN may be a UUID or name. DOMAIN must be in a stopped state before flushing locks. Flush stale RBD locks for virtual machine DOMAIN. DOMAIN may be a UUID or name. DOMAIN must be in a stopped state before flushing locks.
""" """
# Open a Zookeeper connection retcode, retmsg = pvc_vm.vm_locks(config, domain)
zk_conn = pvc_common.startZKConnection(zk_host) cleanup(retcode, retmsg)
retcode, retmsg = pvc_vm.flush_locks(zk_conn, domain)
cleanup(retcode, retmsg, zk_conn)
###############################################################################
# pvc vm info
###############################################################################
@click.command(name='info', short_help='Show details of a VM object.')
@click.argument(
'domain'
)
@click.option(
'-l', '--long', 'long_output', is_flag=True, default=False,
help='Display more detailed information.'
)
def vm_info(domain, long_output):
"""
Show information about virtual machine DOMAIN. DOMAIN may be a UUID or name.
"""
zk_conn = pvc_common.startZKConnection(zk_host)
retcode, retdata = pvc_vm.get_info(zk_conn, domain)
if retcode:
pvc_vm.format_info(zk_conn, retdata, long_output)
retdata = ''
cleanup(retcode, retdata, zk_conn)
############################################################################### ###############################################################################
# pvc vm log # pvc vm log
@ -656,6 +573,50 @@ def vm_log(domain, lines, follow):
retcode, retmsg = pvc_vm.view_console_log(config, domain, lines) retcode, retmsg = pvc_vm.view_console_log(config, domain, lines)
cleanup(retcode, retmsg) cleanup(retcode, retmsg)
###############################################################################
# pvc vm info
###############################################################################
@click.command(name='info', short_help='Show details of a VM object.')
@click.argument(
'domain'
)
@click.option(
'-l', '--long', 'long_output', is_flag=True, default=False,
help='Display more detailed information.'
)
def vm_info(domain, long_output):
"""
Show information about virtual machine DOMAIN. DOMAIN may be a UUID or name.
"""
retcode, retdata = pvc_vm.vm_info(config, domain)
if retcode:
pvc_vm.format_info(config, retdata, long_output)
retdata = ''
cleanup(retcode, retdata)
###############################################################################
# pvc vm dump
###############################################################################
@click.command(name='dump', short_help='Dump a virtual machine XML to stdout.')
@click.argument(
'domain'
)
def vm_dump(domain):
"""
Dump the Libvirt XML definition of virtual machine DOMAIN to stdout. DOMAIN may be a UUID or name.
"""
retcode, vm_information = pvc_vm.vm_info(config, domain)
if not retcode and not vm_information.get('name', None):
cleanup(False, 'ERROR: Could not find VM "{}" in the cluster!'.format(domain))
# Grab the current config
current_vm_cfg_raw = vm_information.get('xml')
xml_data = etree.fromstring(current_vm_cfg_raw)
current_vm_cfgfile = etree.tostring(xml_data, pretty_print=True).decode('utf8')
click.echo(current_vm_cfgfile.strip())
############################################################################### ###############################################################################
# pvc vm list # pvc vm list
############################################################################### ###############################################################################
@ -682,12 +643,11 @@ def vm_list(target_node, target_state, limit, raw):
NOTE: Red-coloured network lists indicate one or more configured networks are missing/invalid. NOTE: Red-coloured network lists indicate one or more configured networks are missing/invalid.
""" """
zk_conn = pvc_common.startZKConnection(zk_host) retcode, retdata = pvc_vm.vm_list(config, limit, target_node, target_state)
retcode, retdata = pvc_vm.get_list(zk_conn, target_node, target_state, limit)
if retcode: if retcode:
pvc_vm.format_list(zk_conn, retdata, raw) pvc_vm.format_list(config, retdata, raw)
retdata = '' retdata = ''
cleanup(retcode, retdata, zk_conn) cleanup(retcode, retdata)
############################################################################### ###############################################################################
# pvc network # pvc network