[Kimchi-devel] [v3 1/1] Virtual machine migration

simonjin simonjin at linux.vnet.ibm.com
Fri Nov 14 09:04:23 UTC 2014


Thanks for your review.

于 2014年11月14日 01:54, Crístian Viana 写道:
> On 13-11-2014 05:02, simonjin at linux.vnet.ibm.com wrote:
>
>> +    "KCHVM0043E": _("Failed destory vm %(name)s from migration 
>> recover. Details: %(err)s"),
>
> *destroy
>
>> @@ -33,6 +33,7 @@ from cherrypy.process.plugins import BackgroundTask
>>   from kimchi import model, 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.tasks import TaskModel
>
> We keep import statements sorted in alphabetical order. You need to 
> move the line "from kimchi.model.libvirtconnection..." two lines 
> below, right between "from kimchi.model.config..." and "from 
> kimchi.model.tasks...", in alphabetical order.
>
OK
>> +            raise OperationFailed("KCHVM0036E", {'name': name,
>> +                                                 'remoteHost': 
>> remoteHost})
>
> The error message KCHVM0036E, in src/kimchi/i18n.py, doesn't contain 
> the format masks 'name' and 'remoteHost' as provided in the exception 
> above:
>
>> "KCHVM0036E": _("Can't migrate to localhost."),
>
> You need to provide exactly the same parameters declared in the error 
> message. You either don't pass 'name' and 'remoteHost' when building 
> that exception or you add 'name' and 'remoteHost' somewhere in the 
> error message.
>
>> +        destarch = _destConn.getInfo()[0]
>> +        if self.conn.get().getInfo()[0] != destarch:
>> +            kimchi_log.debug('vm %s can not migrate to different 
>> arch server.' % (name, destarch))
>> +            raise OperationFailed("KCHVM0037E", {'name': name,
>> +                                          'srcarch': 
>> self.conn.get().getInfo()[0],
>> +                                          'destarch': destarch})
>
> The code above is running "self.conn.get().getInfo()" more than once. 
> You can store that value in a variable so you don't have to talk to 
> libvirt multiple times.
> Actually, "self.conn" is used in more places later in the code, so 
> that value can also be stored in a separate value. Try not to contact 
> libvirt several times for the same information, it has a performance 
> cost.
>
self.conn it self doesn't cost anything.
>> +        desthyp = _destConn.getType()
>> +        if self.conn.get().getType() != desthyp:
>> +            kimchi_log.debug('vm %s can not migrate to a different 
>> hypervisor' % name)
>> +            raise OperationFailed("KCHVM0038E", {'name': self.name,
>> + 'srchyp':self.conn.get().getType(),
>> +                                            'desthyp':desthyp})
>
> Again, store the value from "self.conn.getType()" in a local variable 
> so you don't need to contact libvirt repeatedly. "self.conn" should 
> already be in a separate variable according to my comment above.
>
> Also, the error message KCHVM0038E contains the format masks 'srchyp' 
> and 'desthyp' but you're providing 'name' as well. Those parameters 
> don't match.
>
> And "self.name" is an invalid reference, you need to use the local 
> variable "name".
>
>> +        #check if there is any passthrough devices belong to this vm
>> +        vmhostdevs = VMHostDevsModel(conn = self.conn)
>
> Usually we keep the model objects as instance variables. That means 
> that "vmhostdevs" should be declared in VMModel's constructor - along 
> with many other model variables - as "self.vmhostdevs".
>
Due to the reason in code that VMHostDevsModel can't be imported at the 
top of the class, the workaround is import and get the instance here.
> Another useful verification to be added to "_preCheck" is to allow 
> only one migration per VM happening at the same time. In order to do 
> that, you need to check if a task with the 'target_uri' = 
> '/vms/<vm-name>/migrate' is already running; that's the URI used when 
> creating a migration task later in this code.
>
Will do.
>> +    #open destination connect to migrate
>> +    @staticmethod
>> +    def _getRemoteConn(self, remoteHost, user, transport = 'ssh'):
>> +        duri = 'qemu+%s://%s@%s/system' % (transport,
>> +                                user,remoteHost)
>> +        conn = LibvirtConnection(duri)
>> +        return conn
>
> A @staticmethod shouldn't receive the parameter "self". You can read 
> the section 
> https://docs.python.org/2/library/functions.html#staticmethod to learn 
> more about static methods in Python. When you need to call it, do 
> something like:
>
> VMModel._getRemoteConn(...)
>
> Notice that the function is prefixed with the class, not the object 
> instance, as its implementation doesn't depend on a specific instance.
>
OK
>> def _do_migrate(self, name, destConn, remoteHost, secure, cb):
>
> This function is supposed to be executed from inside a Task. The 
> parameters of such function should be, in that exact order:
>
> def fn(cb, params):
>
> where "params" is a dict containing the other parameters. That means 
> that the parameters "name", "destConn", "remoteHost" and "secure" 
> should be inside the dict "params", and you need to extract them from 
> the dict before using them inside "_do_migrate".
>
OK
>> +        else:
>> +            kimchi_log.debug('Can not migrate vm %s when its in %s.' 
>> % (name, state))
>> +            raise OperationFailed("KCHVM0041E", {'name': self.name})
>
> The error message KCHVM0041E contains the format masks 'name' and 
> 'state'. You need to provide both parameters when creating an 
> exception with that message (i.e.'state' is missing).
>
> Also, "self.name" is an invalid reference - use "name" instead.
>
OK
>> +        except libvirt.libvirtError as e:
>> +            kimchi_log.error('migrate %s to %s failed' % (name,
>> + remoteHost))
>> +            self._recover(cb)
>> +            raise OperationFailed('KCHVM0042E', {'err': e.message,
>
> Are you sure that if an error occurs during migration, we need to 
> undefine the remote domain? In my view, if the migration failed, there 
> won't be a remote domain to undefine - well, it failed. And I couldn't 
> find this on libvirt's documentation so I'm not sure of the behaviour 
> in that case.
>
OK
>> +        finally:
>> +            self._finish(name, destConn, cb)
>
> The function "_finish" is called from inside the "finally" block, 
> which means it will be called regardless of whether an exception was 
> raised or not. However, that function calls "cb(..., True)", which 
> indicates that the task has finished successfully. We should not call 
> "cb(..., True)" if an exception was raised and the migration failed.
>
>> +        destconn = self._getRemoteConn(remoteHost, user, passwd)
>
> The function "_getRemoteConn" was defined as:
>
>> def _getRemoteConn(self, remoteHost, user, transport = 'ssh'):
>
> The parameters provided above don't match the defined parameters. The 
> function expects a transport method in its last parameter but the code 
> above is passing a password instead.
>
>> +        # 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})
>
> As I commented in the previous e-mail thread, the function "add_task" 
> will add the task to the object store. You don't need to do that.
>
Will need this to verify whether the vm is already in migration, right ?

> Before sending every patch, you need to make sure it follows our code 
> guideline. You can run the command "make check-local" on your shell 
> and check its output. There are a few errors pointed out by that tool 
> for this patch, so be sure to fix every one of them.
>
> How do you test this code? Were you able to perform a VM migration 
> successfully using this patch? You can try running the command below 
> on your shell:
>
> $ curl -s -k -u <username>:<password> -H 'Content-Type: 
> application/json' -H 'Accept: application/json' 
> https://localhost:8001/vms/<vm-name>/migrate -X POST -d 
> '{"remoteHost": "<remote-host>", "user": "<remote-user>", "password": 
> "<remote-password>", "secure": True}'
>
> and make sure the migration actually happened.
>
> Best regards,
> Crístian.




More information about the Kimchi-devel mailing list