[Kimchi-devel] [v2 1/1] Virtual machine migration
simonjin
simonjin at linux.vnet.ibm.com
Tue Nov 11 09:36:29 UTC 2014
Looks like ssh-agent can do the trick, however i didn't make it work.
http://www.sudo.ws/pipermail/sudo-users/2003-April/001479.html
于 2014年11月11日 13:27, simonjin 写道:
>
> 于 2014年11月11日 12:37, simonjin at linux.vnet.ibm.com 写道:
>> From: Simon Jin <simonjin at linux.vnet.ibm.com>
>>
>> Issue:
>> Migraton SSH authentication,
>> even 2 peers have ssh key exchanged, migration still failed due to
>> failed authentication,
>> first of all, still need passwd input to get a remote libvirt connection
>> second, after that, migration still failed with error:
>> libvirt: QEMU Driver error : 操作失败: Failed to connect to remote
>> libvirt URI qemu+ssh://root@9.115.122.75/system: Cannot recv data:
>> Permission denied, please try again.
>> Permission denied, please try again.
>> Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).:
>> Connection reset by peer
> The issue is caused by lunch kimchid with sudo, and ssh will then use
> ssh key under 'simon' but the real
> userid is root, like simon: sudo ssh root at 9.115.122.75
>
> virt-manager use libvirt.openAuth to pass password which from user
> input to libvir like below, but it doesn't work well as expected, the
> _auth_cb doesn't get called:
> import libvirt
> import os
>
> def open(_open_uri, passwordcb):
> def _auth_cb(creds, (passwordcb, passwordcreds)):
> for cred in creds:
> if cred[0] not in passwordcreds:
> raise RuntimeError("Unknown cred type '%s',
> expected only "
> "%s" % (cred[0], passwordcreds))
> return passwordcb(creds)
>
> open_flags = 0
> valid_auth_options = [libvirt.VIR_CRED_AUTHNAME,
> libvirt.VIR_CRED_PASSPHRASE]
>
> authcb = _auth_cb
> authcb_data = passwordcb
>
> conn = libvirt.openAuth(_open_uri,
> [valid_auth_options, authcb,
> (authcb_data, valid_auth_options)],
> open_flags)
>
> print conn.getInfo()
> print conn.listDomainsID()
> return conn
>
>
> conn = open('qemu+ssh://simon@9.115.122.75/system','passwd')
>
>
>> How to test:
>> Apply this patch(did some hack to easy debug)
>> and issue migrate action with:
>> sudo curl -k -u use:password -H "Content-Type: application/json" -H
>> "Accept: application/json" https://localhost:8001/vms/RHEL-7/migrate
>> -X POST -d '{"remoteHost": "9.115.122.75", "user": "root", "passwd":
>> "passwd"}'
>>
>> v2:
>> - use generate_action_handler_task
>> - Fix args in generate_action_handler_task
>> - Remove MigrationError
>> - Put import in alphabetic
>> - Support offline migration
>>
>> Signed-off-by: Simon Jin <simonjin at linux.vnet.ibm.com>
>> ---
>> docs/API.md | 4 ++
>> src/kimchi/control/vms.py | 1 +
>> src/kimchi/i18n.py | 10 ++++
>> src/kimchi/model/vms.py | 145
>> ++++++++++++++++++++++++++++++++++++++++++++++
>> 4 files changed, 160 insertions(+)
>>
>> diff --git a/docs/API.md b/docs/API.md
>> index 9c06f85..36e5ab6 100644
>> --- a/docs/API.md
>> +++ b/docs/API.md
>> @@ -132,6 +132,10 @@ the following general conventions:
>> It emulates the power reset button on a machine. Note that
>> there is a
>> risk of data loss caused by reset without the guest OS
>> shutdown.
>> * connect: Prepare the connection for spice or vnc
>> +* migrate: Migrate a virtual machine to a remote server, only
>> support live mode without block migration.
>> + * remoteHost: IP address or hostname of the remote server.
>> + * user: user of the remote server.
>> + * passwd: passwd of user on remote server.
>> ### Sub-resource: Virtual Machine Screenshot
>> diff --git a/src/kimchi/control/vms.py b/src/kimchi/control/vms.py
>> index 88d8a81..0ab239e 100644
>> --- a/src/kimchi/control/vms.py
>> +++ b/src/kimchi/control/vms.py
>> @@ -42,6 +42,7 @@ class VM(Resource):
>> for ident, node in sub_nodes.items():
>> setattr(self, ident, node(model, self.ident))
>> self.start = self.generate_action_handler('start')
>> + self.migrate = self.generate_action_handler_task('migrate',
>> ['remoteHost', 'user', 'passwd'])
>> self.poweroff = self.generate_action_handler('poweroff')
>> self.shutdown = self.generate_action_handler('shutdown')
>> self.reset = self.generate_action_handler('reset')
>> diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py
>> index f789259..6edc595 100644
>> --- a/src/kimchi/i18n.py
>> +++ b/src/kimchi/i18n.py
>> @@ -101,6 +101,16 @@ messages = {
>> "KCHVM0030E": _("Unable to get access metadata of virtual
>> machine %(name)s. Details: %(err)s"),
>> "KCHVM0031E": _("The guest console password must be a string."),
>> "KCHVM0032E": _("The life time for the guest console password
>> must be a number."),
>> + "KCHVM0033E": _("Can't migrate to localhost."),
>> + "KCHVM0034E": _("Can't migrate vm %(name)s on Hypervisor arch
>> %(srcarch)s.to a different Hypervisor arch %(destarch)s."),
>> + "KCHVM0035E": _("Can't migrate from %(srchyp)s to a different
>> Hypervisor type %(desthyp)s."),
>> + "KCHVM0037E": _("Can't migrate vm %(name)s,which isn't in
>> running state."),
>> + "KCHVM0038E": _("Can't migrate vm %(name)s, vm has passthrough
>> device %(hostdevs)s."),
>> + "KCHVM0039E": _("Can't migrate vm %(name)s, vm already exist on
>> destination server %(remoteHost)s."),
>> + "KCHVM0040E": _("Failed Migrate vm %(name)s due error: %(err)s"),
>> + "KCHVM0041E": _("Failed resume vm %(name)s from migration
>> recover. Details: %(err)s"),
>> + "KCHVM0042E": _("Failed destory vm %(name)s from migration
>> recover. Details: %(err)s"),
>> + "KCHVM0043E": _("Failed disconnect %(remoteuri)s when finish
>> migrate vm %(name)s. Details: %(err)s"),
>> "KCHVMHDEV0001E": _("VM %(vmid)s does not contain directly
>> assigned host device %(dev_name)s."),
>> "KCHVMHDEV0002E": _("The host device %(dev_name)s is not
>> allowed to directly assign to VM."),
>> diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py
>> index f2e4ae3..c6709ca 100644
>> --- a/src/kimchi/model/vms.py
>> +++ b/src/kimchi/model/vms.py
>> @@ -30,16 +30,20 @@ from xml.etree import ElementTree
>> import libvirt
>> from cherrypy.process.plugins import BackgroundTask
>> +from kimchi.utils import add_task
>> from kimchi import vnc
>> from kimchi.config import READONLY_POOL_TYPE
>> from kimchi.exception import InvalidOperation, InvalidParameter
>> +from kimchi.model.libvirtconnection import LibvirtConnection
>> from kimchi.exception import NotFoundError, OperationFailed
>> from kimchi.model.config import CapabilitiesModel
>> from kimchi.model.templates import TemplateModel
>> +from kimchi.model.templates import TemplateModel
>> from kimchi.model.utils import get_vm_name
>> from kimchi.model.utils import get_metadata_node
>> from kimchi.model.utils import set_metadata_node
>> from kimchi.screenshot import VMScreenshot
>> +#from kimchi.model.vmhostdevs import VMHostDevsModel
>> from kimchi.utils import import_class, kimchi_log,
>> run_setfacl_set_attr
>> from kimchi.utils import template_name_from_uri
>> from kimchi.xmlutils.utils import xpath_get_text, xml_item_update
>> @@ -514,6 +518,147 @@ class VMModel(object):
>> except libvirt.libvirtError as e:
>> raise OperationFailed("KCHVM0019E",
>> {'name': name, 'err':
>> e.get_error_message()})
>> +
>> + def _preCheck(self, name, destConn, remoteHost):
>> + kimchi_log.debug('precheck migrate %s' % name)
>> +
>> + _destConn = destConn.get()
>> + if remoteHost in ['localhost', '127.0.0.1']:
>> + kimchi_log.debug('vm %s is not in running, only running
>> vm can be migrated' % name)
>> + raise OperationFailed("KCHVM00033E", {'name': name,
>> + 'remoteHost':
>> remoteHost})
>> +
>> +
>> + if self.conn.get().getInfo()[0] != _destConn.getInfo()[0]:
>> + kimchi_log.debug('vm %s can not migrate to different
>> arch server.' % (name, _destConn.getInfo()[0]))
>> + raise OperationFailed("KCHVM00034E", {'name': name,
>> + 'srcarch':
>> self.conn.get().getType(),
>> + 'destarch':
>> _destConn.getType()})
>> +
>> + if self.conn.get().getType() != _destConn.getType():
>> + kimchi_log.debug('vm %s can not migrate to a different
>> hypervisor' % name)
>> + raise OperationFailed("KCHVM00035E", {'name': self.name,
>> + 'srchyp':self.conn.get().getType(),
>> + 'desthyp':
>> _destConn.getType()})
>> +
>> +
>> + #model.host import DOM_STATE_MAP, vmhostdevs import host,
>> + #to void loop import DOM_STATE_MAP, move import
>> VMHostDevsModel here
>> + from kimchi.model.vmhostdevs import VMHostDevsModel
>> + #check if there is any passthrough devices belong to this vm
>> + vmhostdevs = VMHostDevsModel(conn = self.conn)
>> + hostdevs = vmhostdevs.get_list(name)
>> + if hostdevs:
>> + raise OperationFailed("KCHVM00038E", {'name' : name,
>> + 'hostdevs': hostdevs})
>> + #try: #FIXME
>> + # self.get_vm(name, destConn)
>> + #except NotFoundError as e:
>> + # if e != NotFoundError:
>> + # kimchi_log.debug('migrate vm %s already exist on
>> %s' % (name, destConn.getURI()))
>> + #raise OperationFailed("KCHVM00039E", {'name' : name,
>> + # 'remoteHost': remoteHost})
>> +
>> + def _getRemoteConn(self, remoteHost, user):
>> + #open destination connect to migrate
>> + transport = 'ssh'
>> + duri = 'qemu+%s://%s@%s/system' % (transport,
>> + user,remoteHost)
>> +
>> + conn = LibvirtConnection(duri)
>> + return conn
>> +
>> + def _preMigrate(self, name):
>> + #can't update VM while in Migration source/destination
>> + kimchi_log.debug('prepare migrate %s' % name)
>> + dom = self.get_vm(name, self.conn)
>> + try:
>> + dom.migrateSetMaxDowntime(0)
>> + except libvirt.libvirtError as e:
>> + print e.message
>> +
>> + def _do_migrate(self, name, destConn, remoteHost, cb):
>> + _destConn = destConn.get()
>> + cb('starting a migration')
>> + kimchi_log.debug('migrate %s start' % name)
>> + #import pdb
>> + #pdb.set_trace()
>> + dom = self.get_vm(name, self.conn)
>> + flag = 0
>> + flag |= (libvirt.VIR_MIGRATE_PEER2PEER |
>> + libvirt.VIR_MIGRATE_TUNNELLED)
>> +
>> + state = DOM_STATE_MAP[dom.info()[0]]
>> + if state == 'running':
>> + flag |= libvirt.VIR_MIGRATE_LIVE
>> + try:
>> + dom.migrateSetMaxDowntime(0)
>> + except libvirt.libvirtError as e:
>> + print e.message #FIXME
>> +
>> + elif state == 'shutoff':
>> + flag |= libvirt.VIR_MIGRATE_OFFLINE
>> + else: #FIXME any other state will prevend migration ?
>> + kimchi_log.debug('Can not migrate vm %s when its in %s.'
>> % (name, state))
>> + raise OperationFailed("KCHVM00037E", {'name': self.name})
>> +
>> + try:
>> + dom.migrate(_destConn, flag, None, None, 0)
>> + except libvirt.libvirtError as e:
>> + kimchi_log.error('migrate %s to %s failed' % (name,
>> + remoteHost))
>> + self._recover(cb)
>> + raise OperationFailed('KCHPOOL0040E', {'err': e.message,
>> + 'name': name})
>> + finally:
>> + self._finish(name, destConn, cb)
>> +
>> + def migrate(self, name, remoteHost, user, passwd ):
>> + destconn = self._getRemoteConn(remoteHost, user)
>> +
>> + flag = self._preCheck(name, destconn, remoteHost)
>> + self._preMigrate(name)
>> + def cb(message):
>> + print message
>> +
>> +
>> + self._do_migrate(name, destconn, remoteHost,cb)
>> +
>> + task_id = add_task('/vms/%s/migrate' % name,
>> self._do_migrate, self.objstore,
>> + {'name' : name,
>> 'destconn': destconn,
>> + 'remoteHost':
>> remoteHost})
>> +
>> + # Record vm migrate task for future querying
>> + try:
>> + with self.objstore as session:
>> + session.store('migrate', name, task_id)
>> + return task_id
>> + except Exception as e:
>> + raise OperationFailed('KCHPOOL0037E', {'err': e.message})
>> +
>> + def _recover(self, name, destconn, cb):
>> + destvm = self.get_vm(name, destconn)
>> + #recover
>> + cb('recover from a failed migration',False)
>> + kimchi_log.debug('recover from a failed migrate %s' % name)
>> + try:
>> + destvm.destroy()
>> + kimchi_log.error("destory migrate vm on destination
>> server")
>> + except libvirt.libvirtError as e:
>> + raise OperationFailed('KCHPOOL0042E', {'name' : name,
>> + 'err': e.message})
>> +
>> + def _finish(self, name, destConn, cb):
>> + _destConn = destConn.get()
>> + kimchi_log.debug('finished migrate %s' % name)
>> + try:
>> + _destConn.close()
>> + except libvirt.libvirtError as e:
>> + raise OperationFailed('KCHPOOL0043E', {'name' : name,
>> + 'remoteuri' :
>> _destConn.getURI(),
>> + 'err': e.message})
>> + finally:
>> + cb('Migrate finished', True)
>> def poweroff(self, name):
>> dom = self.get_vm(name, self.conn)
>
> _______________________________________________
> Kimchi-devel mailing list
> Kimchi-devel at ovirt.org
> http://lists.ovirt.org/mailman/listinfo/kimchi-devel
More information about the Kimchi-devel
mailing list