parent
9de14c46fb
commit
f46c2e7f6a
|
@ -1804,6 +1804,45 @@ class API_VM_Console(Resource):
|
|||
api.add_resource(API_VM_Console, '/vm/<vm>/console')
|
||||
|
||||
|
||||
# /vm/<vm>/rename
|
||||
class API_VM_Rename(Resource):
|
||||
@RequestParser([
|
||||
{'name': 'new_name'}
|
||||
])
|
||||
@Authenticator
|
||||
def post(self, vm, reqargs):
|
||||
"""
|
||||
Rename VM {vm}, and all connected disk volumes which include this name, to {new_name}
|
||||
---
|
||||
tags:
|
||||
- vm
|
||||
parameters:
|
||||
- in: query
|
||||
name: new_name
|
||||
type: string
|
||||
required: true
|
||||
description: The new name of the VM
|
||||
responses:
|
||||
200:
|
||||
description: OK
|
||||
schema:
|
||||
type: object
|
||||
id: Message
|
||||
400:
|
||||
description: Bad request
|
||||
schema:
|
||||
type: object
|
||||
id: Message
|
||||
"""
|
||||
return api_helper.vm_rename(
|
||||
vm,
|
||||
reqargs.get('new_name', None)
|
||||
)
|
||||
|
||||
|
||||
api.add_resource(API_VM_Rename, '/vm/<vm>/rename')
|
||||
|
||||
|
||||
##########################################################
|
||||
# Client API - Network
|
||||
##########################################################
|
||||
|
|
|
@ -601,6 +601,37 @@ def vm_modify(name, restart, xml):
|
|||
return output, retcode
|
||||
|
||||
|
||||
def vm_rename(name, new_name):
|
||||
"""
|
||||
Rename a VM in the PVC cluster.
|
||||
"""
|
||||
if new_name is None:
|
||||
output = {
|
||||
'message': 'A new VM name must be specified'
|
||||
}
|
||||
return 400, output
|
||||
|
||||
zk_conn = pvc_common.startZKConnection(config['coordinators'])
|
||||
if pvc_vm.searchClusterByName(zk_conn, new_name) is not None:
|
||||
output = {
|
||||
'message': 'A VM named \'{}\' is already present in the cluster'.format(new_name)
|
||||
}
|
||||
return 400, output
|
||||
|
||||
retflag, retdata = pvc_vm.rename_vm(zk_conn, name, new_name)
|
||||
pvc_common.stopZKConnection(zk_conn)
|
||||
|
||||
if retflag:
|
||||
retcode = 200
|
||||
else:
|
||||
retcode = 400
|
||||
|
||||
output = {
|
||||
'message': retdata.replace('\"', '\'')
|
||||
}
|
||||
return output, retcode
|
||||
|
||||
|
||||
def vm_undefine(name):
|
||||
"""
|
||||
Undefine a VM from the PVC cluster.
|
||||
|
|
|
@ -130,6 +130,27 @@ def vm_modify(config, vm, xml, restart):
|
|||
return retstatus, response.json().get('message', '')
|
||||
|
||||
|
||||
def vm_rename(config, vm, new_name):
|
||||
"""
|
||||
Rename VM to new name
|
||||
|
||||
API endpoint: POST /vm/{vm}/rename
|
||||
API arguments: new_name={new_name}
|
||||
API schema: {"message":"{data}"}
|
||||
"""
|
||||
params = {
|
||||
'new_name': new_name
|
||||
}
|
||||
response = call_api(config, 'post', '/vm/{vm}/rename'.format(vm=vm), params=params)
|
||||
|
||||
if response.status_code == 200:
|
||||
retstatus = True
|
||||
else:
|
||||
retstatus = False
|
||||
|
||||
return retstatus, response.json().get('message', '')
|
||||
|
||||
|
||||
def vm_metadata(config, vm, node_limit, node_selector, node_autostart, migration_method, provisioner_profile):
|
||||
"""
|
||||
Modify PVC metadata of a VM
|
||||
|
|
|
@ -790,6 +790,36 @@ def vm_modify(domain, cfgfile, editor, restart, confirm_flag):
|
|||
cleanup(retcode, retmsg)
|
||||
|
||||
|
||||
###############################################################################
|
||||
# pvc vm rename
|
||||
###############################################################################
|
||||
@click.command(name='rename', short_help='Rename a virtual machine.')
|
||||
@click.argument(
|
||||
'domain'
|
||||
)
|
||||
@click.argument(
|
||||
'new_name'
|
||||
)
|
||||
@click.option(
|
||||
'-y', '--yes', 'confirm_flag',
|
||||
is_flag=True, default=False,
|
||||
help='Confirm the rename'
|
||||
)
|
||||
@cluster_req
|
||||
def vm_rename(domain, new_name, confirm_flag):
|
||||
"""
|
||||
Rename virtual machine DOMAIN, and all its connected disk volumes, to NEW_NAME. DOMAIN may be a UUID or name.
|
||||
"""
|
||||
if not confirm_flag and not config['unsafe']:
|
||||
try:
|
||||
click.confirm('Rename VM {} to {}'.format(domain, new_name), prompt_suffix='? ', abort=True)
|
||||
except Exception:
|
||||
exit(0)
|
||||
|
||||
retcode, retmsg = pvc_vm.vm_rename(config, domain, new_name)
|
||||
cleanup(retcode, retmsg)
|
||||
|
||||
|
||||
###############################################################################
|
||||
# pvc vm undefine
|
||||
###############################################################################
|
||||
|
@ -4395,6 +4425,7 @@ vm_volume.add_command(vm_volume_remove)
|
|||
cli_vm.add_command(vm_define)
|
||||
cli_vm.add_command(vm_meta)
|
||||
cli_vm.add_command(vm_modify)
|
||||
cli_vm.add_command(vm_rename)
|
||||
cli_vm.add_command(vm_undefine)
|
||||
cli_vm.add_command(vm_remove)
|
||||
cli_vm.add_command(vm_dump)
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
import time
|
||||
import re
|
||||
import lxml.objectify
|
||||
import lxml.etree
|
||||
|
||||
import daemon_lib.zkhandler as zkhandler
|
||||
import daemon_lib.common as common
|
||||
|
@ -299,6 +300,55 @@ def dump_vm(zk_conn, domain):
|
|||
return True, vm_xml
|
||||
|
||||
|
||||
def rename_vm(zk_conn, domain, new_domain):
|
||||
dom_uuid = getDomainUUID(zk_conn, domain)
|
||||
if not dom_uuid:
|
||||
return False, 'ERROR: Could not find VM "{}" in the cluster!'.format(domain)
|
||||
|
||||
# Verify that the VM is in a stopped state; renaming is not supported otherwise
|
||||
state = zkhandler.readdata(zk_conn, '/domains/{}/state'.format(dom_uuid))
|
||||
if state != 'stop':
|
||||
return False, 'ERROR: VM "{}" is not in stopped state; VMs cannot be renamed while running.'.format(domain)
|
||||
|
||||
# Parse and valiate the XML
|
||||
vm_config = common.getDomainXML(zk_conn, dom_uuid)
|
||||
|
||||
# Obtain the RBD disk list using the common functions
|
||||
ddisks = common.getDomainDisks(vm_config, {})
|
||||
pool_list = []
|
||||
rbd_list = []
|
||||
for disk in ddisks:
|
||||
if disk['type'] == 'rbd':
|
||||
pool_list.append(disk['name'].split('/')[0])
|
||||
rbd_list.append(disk['name'].split('/')[1])
|
||||
|
||||
# Rename each volume in turn
|
||||
for idx, rbd in enumerate(rbd_list):
|
||||
rbd_new = re.sub(r"{}".format(domain), new_domain, rbd)
|
||||
# Skip renaming if nothing changed
|
||||
if rbd_new == rbd:
|
||||
continue
|
||||
ceph.rename_volume(zk_conn, pool_list[idx], rbd, rbd_new)
|
||||
|
||||
# Replace the name in the config
|
||||
vm_config_new = lxml.etree.tostring(vm_config, encoding='ascii', method='xml').decode().replace(domain, new_domain)
|
||||
|
||||
# Get VM information
|
||||
_b, dom_info = get_info(zk_conn, dom_uuid)
|
||||
|
||||
# Undefine the old VM
|
||||
undefine_vm(zk_conn, dom_uuid)
|
||||
|
||||
# Define the new VM
|
||||
define_vm(zk_conn, vm_config_new, dom_info['node'], dom_info['node_limit'], dom_info['node_selector'], dom_info['node_autostart'], migration_method=dom_info['migration_method'], profile=dom_info['profile'], initial_state='stop')
|
||||
|
||||
# If the VM is migrated, store that
|
||||
if dom_info['migrated'] != 'no':
|
||||
zkhandler.writedata(zk_conn, {'/domains/{}/lastnode'.format(dom_uuid): dom_info['last_node']})
|
||||
|
||||
return True, 'Successfully renamed VM "{}" to "{}".'.format(domain, new_domain)
|
||||
|
||||
|
||||
def undefine_vm(zk_conn, domain):
|
||||
# Validate that VM exists in cluster
|
||||
dom_uuid = getDomainUUID(zk_conn, domain)
|
||||
|
|
|
@ -6035,6 +6035,38 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"/api/v1/vm/{vm}/rename": {
|
||||
"post": {
|
||||
"description": "",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "The new name of the VM",
|
||||
"in": "query",
|
||||
"name": "new_name",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Message"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Message"
|
||||
}
|
||||
}
|
||||
},
|
||||
"summary": "Rename VM {vm}, and all connected disk volumes which include this name, to {new_name}",
|
||||
"tags": [
|
||||
"vm"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/v1/vm/{vm}/state": {
|
||||
"get": {
|
||||
"description": "",
|
||||
|
|
Loading…
Reference in New Issue