Support per-VM migration type selectors

Allow a VM to specify its migration type as a default choice. The valid
options are "default" (i.e. behave as now), "live" which forces a live
migration only, and "shutdown" which forces a shutdown migration only.
The new option is treated as a VM meta option and is set to default if
not found.
This commit is contained in:
2020-10-29 11:31:32 -04:00
parent d2c0d868c4
commit ec0b8acf90
11 changed files with 236 additions and 61 deletions

View File

@ -834,6 +834,9 @@ class API_VM_Root(Resource):
node_autostart:
type: boolean
description: Whether to autostart the VM when its node returns to ready domain state
migration_method:
type: string
description: The preferred migration method (live, shutdown, none)
description:
type: string
description: The description of the VM
@ -1036,6 +1039,7 @@ class API_VM_Root(Resource):
{ 'name': 'node' },
{ 'name': 'selector', 'choices': ('mem', 'vcpus', 'load', 'vms'), 'helptext': "A valid selector must be specified" },
{ 'name': 'autostart' },
{ 'name': 'migration_method', 'choices': ('live', 'shutdown', 'none'), 'helptext': "A valid migration_method must be specified" },
{ 'name': 'xml', 'required': True, 'helptext': "A Libvirt XML document must be specified" },
])
@Authenticator
@ -1077,6 +1081,16 @@ class API_VM_Root(Resource):
type: boolean
required: false
description: Whether to autostart the VM when its node returns to ready domain state
- in: query
name: migration_method
type: string
required: false
description: The preferred migration method (live, shutdown, none)
default: none
enum:
- live
- shutdown
- none
responses:
200:
description: OK
@ -1094,7 +1108,8 @@ class API_VM_Root(Resource):
reqargs.get('node', None),
reqargs.get('limit', None),
reqargs.get('selector', 'mem'),
bool(strtobool(reqargs.get('autostart', 'false')))
bool(strtobool(reqargs.get('autostart', 'false'))),
reqargs.get('migration_method', 'none')
)
api.add_resource(API_VM_Root, '/vm')
@ -1125,6 +1140,7 @@ class API_VM_Element(Resource):
{ 'name': 'node' },
{ 'name': 'selector', 'choices': ('mem', 'vcpus', 'load', 'vms'), 'helptext': "A valid selector must be specified" },
{ 'name': 'autostart' },
{ 'name': 'migration_method', 'choices': ('live', 'shutdown', 'none'), 'helptext': "A valid migration_method must be specified" },
{ 'name': 'xml', 'required': True, 'helptext': "A Libvirt XML document must be specified" },
])
@Authenticator
@ -1168,6 +1184,16 @@ class API_VM_Element(Resource):
type: boolean
required: false
description: Whether to autostart the VM when its node returns to ready domain state
- in: query
name: migration_method
type: string
required: false
description: The preferred migration method (live, shutdown, none)
default: none
enum:
- live
- shutdown
- none
responses:
200:
description: OK
@ -1185,7 +1211,8 @@ class API_VM_Element(Resource):
reqargs.get('node', None),
reqargs.get('limit', None),
reqargs.get('selector', 'mem'),
bool(strtobool(reqargs.get('autostart', 'false')))
bool(strtobool(reqargs.get('autostart', 'false'))),
reqargs.get('migration_method', 'none')
)
@RequestParser([
@ -1296,6 +1323,9 @@ class API_VM_Metadata(Resource):
node_autostart:
type: string
description: Whether to autostart the VM when its node returns to ready domain state
migration_method:
type: string
description: The preferred migration method (live, shutdown, none)
404:
description: Not found
schema:
@ -1309,6 +1339,7 @@ class API_VM_Metadata(Resource):
{ 'name': 'selector', 'choices': ('mem', 'vcpus', 'load', 'vms'), 'helptext': "A valid selector must be specified" },
{ 'name': 'autostart' },
{ 'name': 'profile' },
{ 'name': 'migration_method', 'choices': ('live', 'shutdown', 'none'), 'helptext': "A valid migration_method must be specified" },
])
@Authenticator
def post(self, vm, reqargs):
@ -1343,6 +1374,16 @@ class API_VM_Metadata(Resource):
type: string
required: false
description: The PVC provisioner profile for the VM
- in: query
name: migration_method
type: string
required: false
description: The preferred migration method (live, shutdown, none)
default: none
enum:
- live
- shutdown
- none
responses:
200:
description: OK
@ -1360,7 +1401,8 @@ class API_VM_Metadata(Resource):
reqargs.get('limit', None),
reqargs.get('selector', None),
reqargs.get('autostart', None),
reqargs.get('profile', None)
reqargs.get('profile', None),
reqargs.get('migration_method', None)
)
api.add_resource(API_VM_Metadata, '/vm/<vm>/meta')
@ -4057,6 +4099,9 @@ class API_Provisioner_Template_System_Root(Resource):
node_autostart:
type: boolean
description: Whether to start VM with node ready state (one-time)
migration_method:
type: string
description: The preferred migration method (live, shutdown, none)
parameters:
- in: query
name: limit
@ -4084,7 +4129,8 @@ class API_Provisioner_Template_System_Root(Resource):
{ 'name': 'vnc_bind' },
{ 'name': 'node_limit' },
{ 'name': 'node_selector' },
{ 'name': 'node_autostart' }
{ 'name': 'node_autostart' },
{ 'name': 'migration_method' }
])
@Authenticator
def post(self, reqargs):
@ -4139,6 +4185,11 @@ class API_Provisioner_Template_System_Root(Resource):
type: boolean
required: false
description: Whether to start VM with node ready state (one-time)
- in: query
name: migration_method
type: string
required: false
description: The preferred migration method (live, shutdown, none)
responses:
200:
description: OK
@ -4185,7 +4236,8 @@ class API_Provisioner_Template_System_Root(Resource):
vnc_bind,
reqargs.get('node_limit', None),
reqargs.get('node_selector', None),
node_autostart
node_autostart,
reqargs.get('migration_method', None),
)
api.add_resource(API_Provisioner_Template_System_Root, '/provisioner/template/system')
@ -4222,7 +4274,8 @@ class API_Provisioner_Template_System_Element(Resource):
{ 'name': 'vnc_bind' },
{ 'name': 'node_limit' },
{ 'name': 'node_selector' },
{ 'name': 'node_autostart' }
{ 'name': 'node_autostart' },
{ 'name': 'migration_method' }
])
@Authenticator
def post(self, template, reqargs):
@ -4272,6 +4325,11 @@ class API_Provisioner_Template_System_Element(Resource):
type: boolean
required: false
description: Whether to start VM with node ready state (one-time)
- in: query
name: migration_method
type: string
required: false
description: The preferred migration method (live, shutdown, none)
responses:
200:
description: OK
@ -4318,7 +4376,8 @@ class API_Provisioner_Template_System_Element(Resource):
vnc_bind,
reqargs.get('node_limit', None),
reqargs.get('node_selector', None),
node_autostart
node_autostart,
reqargs.get('migration_method', None),
)
@RequestParser([
@ -4329,7 +4388,8 @@ class API_Provisioner_Template_System_Element(Resource):
{ 'name': 'vnc_bind' },
{ 'name': 'node_limit' },
{ 'name': 'node_selector' },
{ 'name': 'node_autostart' }
{ 'name': 'node_autostart' },
{ 'name': 'migration_method' }
])
@Authenticator
def put(self, template, reqargs):
@ -4371,6 +4431,10 @@ class API_Provisioner_Template_System_Element(Resource):
name: node_autostart
type: boolean
description: Whether to start VM with node ready state (one-time)
- in: query
name: migration_method
type: string
description: The preferred migration method (live, shutdown, none)
responses:
200:
description: OK
@ -4392,7 +4456,8 @@ class API_Provisioner_Template_System_Element(Resource):
reqargs.get('vnc_bind'),
reqargs.get('node_limit', None),
reqargs.get('node_selector', None),
reqargs.get('node_autostart', None)
reqargs.get('node_autostart', None),
reqargs.get('migration_method', None)
)
@Authenticator

View File

@ -431,7 +431,7 @@ def vm_list(node=None, state=None, limit=None, is_fuzzy=True):
return retdata, retcode
def vm_define(xml, node, limit, selector, autostart):
def vm_define(xml, node, limit, selector, autostart, migration_method):
"""
Define a VM from Libvirt XML in the PVC cluster.
"""
@ -443,7 +443,7 @@ def vm_define(xml, node, limit, selector, autostart):
return { 'message': 'XML is malformed or incorrect: {}'.format(e) }, 400
zk_conn = pvc_common.startZKConnection(config['coordinators'])
retflag, retdata = pvc_vm.define_vm(zk_conn, new_cfg, node, limit, selector, autostart, profile=None)
retflag, retdata = pvc_vm.define_vm(zk_conn, new_cfg, node, limit, selector, autostart, migration_method, profile=None)
pvc_common.stopZKConnection(zk_conn)
if retflag:
@ -475,7 +475,8 @@ def get_vm_meta(vm):
'name': vm,
'node_limit': retdata['node_limit'],
'node_selector': retdata['node_selector'],
'node_autostart': retdata['node_autostart']
'node_autostart': retdata['node_autostart'],
'migration_method': retdata['migration_method']
}
else:
retcode = 404
@ -490,7 +491,7 @@ def get_vm_meta(vm):
return retdata, retcode
def update_vm_meta(vm, limit, selector, autostart, provisioner_profile):
def update_vm_meta(vm, limit, selector, autostart, provisioner_profile, migration_method):
"""
Update metadata of a VM.
"""
@ -500,7 +501,7 @@ def update_vm_meta(vm, limit, selector, autostart, provisioner_profile):
autostart = bool(strtobool(autostart))
except:
autostart = False
retflag, retdata = pvc_vm.modify_vm_metadata(zk_conn, vm, limit, selector, autostart, provisioner_profile)
retflag, retdata = pvc_vm.modify_vm_metadata(zk_conn, vm, limit, selector, autostart, provisioner_profile, migration_method)
pvc_common.stopZKConnection(zk_conn)
if retflag:

View File

@ -35,9 +35,10 @@ class DBSystemTemplate(db.Model):
node_limit = db.Column(db.Text)
node_selector = db.Column(db.Text)
node_autostart = db.Column(db.Boolean, nullable=False)
migration_method = db.Column(db.Text)
ova = db.Column(db.Integer, db.ForeignKey("ova.id"), nullable=True)
def __init__(self, name, vcpu_count, vram_mb, serial, vnc, vnc_bind, node_limit, node_selector, node_autostart, ova=None):
def __init__(self, name, vcpu_count, vram_mb, serial, vnc, vnc_bind, node_limit, node_selector, node_autostart, migration_method, ova=None):
self.name = name
self.vcpu_count = vcpu_count
self.vram_mb = vram_mb
@ -47,6 +48,7 @@ class DBSystemTemplate(db.Model):
self.node_limit = node_limit
self.node_selector = node_selector
self.node_autostart = node_autostart
self.migration_method = migration_method
self.ova = ova
def __repr__(self):

View File

@ -214,14 +214,14 @@ def template_list(limit):
#
# Template Create functions
#
def create_template_system(name, vcpu_count, vram_mb, serial=False, vnc=False, vnc_bind=None, node_limit=None, node_selector=None, node_autostart=False, ova=None):
def create_template_system(name, vcpu_count, vram_mb, serial=False, vnc=False, vnc_bind=None, node_limit=None, node_selector=None, node_autostart=False, migration_method=None, ova=None):
if list_template_system(name, is_fuzzy=False)[-1] != 404:
retmsg = { 'message': 'The system template "{}" already exists.'.format(name) }
retcode = 400
return retmsg, retcode
query = "INSERT INTO system_template (name, vcpu_count, vram_mb, serial, vnc, vnc_bind, node_limit, node_selector, node_autostart, ova) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s);"
args = (name, vcpu_count, vram_mb, serial, vnc, vnc_bind, node_limit, node_selector, node_autostart, ova)
query = "INSERT INTO system_template (name, vcpu_count, vram_mb, serial, vnc, vnc_bind, node_limit, node_selector, node_autostart, migration_method, ova) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s);"
args = (name, vcpu_count, vram_mb, serial, vnc, vnc_bind, node_limit, node_selector, node_autostart, migration_method, ova)
conn, cur = open_database(config)
try:
@ -359,7 +359,7 @@ def create_template_storage_element(name, disk_id, pool, source_volume=None, dis
#
# Template Modify functions
#
def modify_template_system(name, vcpu_count=None, vram_mb=None, serial=None, vnc=None, vnc_bind=None, node_limit=None, node_selector=None, node_autostart=None):
def modify_template_system(name, vcpu_count=None, vram_mb=None, serial=None, vnc=None, vnc_bind=None, node_limit=None, node_selector=None, node_autostart=None, migration_method=None):
if list_profile(name, is_fuzzy=False)[-1] != 200:
retmsg = { 'message': 'The system template "{}" does not exist.'.format(name) }
retcode = 400
@ -420,6 +420,9 @@ def modify_template_system(name, vcpu_count=None, vram_mb=None, serial=None, vnc
retcode = 400
fields.append({'field': 'node_autostart', 'data': node_autostart})
if migration_method is not None:
fields.append({'field': 'migration_method', 'data': migration_method})
conn, cur = open_database(config)
try:
for field in fields:
@ -1403,7 +1406,8 @@ def create_vm(self, vm_name, vm_profile, define_vm=True, start_vm=True, script_r
node_limit = node_limit.split(',')
node_selector = vm_data['system_details']['node_selector']
node_autostart = vm_data['system_details']['node_autostart']
retcode, retmsg = pvc_vm.define_vm(zk_conn, vm_schema.strip(), target_node, node_limit, node_selector, node_autostart, vm_profile, initial_state='provision')
migration_method = vm_data['system_details']['migration_method']
retcode, retmsg = pvc_vm.define_vm(zk_conn, vm_schema.strip(), target_node, node_limit, node_selector, node_autostart, migration_method, vm_profile, initial_state='provision')
print(retmsg)
else:
print("Skipping VM definition")