[PATCH V2 0/5] vm ticket in backend

From: ShaoHe Feng <shaohef@linux.vnet.ibm.com> V1 -> V2: make ticket as sub-resource of a VM A ticket is the credential to access VM. Only who get the ticket can access a VM. test this patch set: set the ticket $sudo curl -k -u <user>:<password> -H "Content-Type: application/json" -H \ "Accept: application/json" https://localhost:8001/vms/test-vm-8/ticket/ \ -X PUT -d '{"passwd": "abcd"}' get the ticket $sudo curl -k -u <user>:<password> -H "Content-Type: application/json" -H \ "Accept: application/json" https://localhost:8001/vms/test-vm-8/ticket/ ShaoHe Feng (5): vm ticket in backend: update API.md vm ticket in backend: update controller and API.json vm ticket in backend: update model vm ticket in backend: update mockmodel vm ticket in backend: update test case docs/API.md | 20 +++++++++++++++ src/kimchi/API.json | 14 ++++++++++ src/kimchi/control/vms.py | 13 ++++++++++ src/kimchi/i18n.py | 1 + src/kimchi/mockmodel.py | 18 +++++++++++++ src/kimchi/model/vms.py | 65 +++++++++++++++++++++++++++++++++++++++++++++++ tests/test_model.py | 31 ++++++++++++++++++++++ tests/test_rest.py | 36 ++++++++++++++++++++++++++ 8 files changed, 198 insertions(+) -- 1.9.3

From: ShaoHe Feng <shaohef@linux.vnet.ibm.com> A ticket is the credential to access VM. Only who get the ticket can access a VM. test this patch set: set the ticket $sudo curl -k -u <user>:<password> -H "Content-Type: application/json" -H \ "Accept: application/json" https://localhost:8001/vms/test-vm-8/ticket/ \ -X PUT -d '{"passwd": "abcd"}' get the ticket $sudo curl -k -u <user>:<password> -H "Content-Type: application/json" -H \ "Accept: application/json" https://localhost:8001/vms/test-vm-8/ticket/ Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> --- docs/API.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docs/API.md b/docs/API.md index 1a228df..5256f26 100644 --- a/docs/API.md +++ b/docs/API.md @@ -247,6 +247,26 @@ A interface represents available network interface on VM. *No actions defined* +### Sub-Resource: Virtual Machine Ticket + +**URI:** /vms/*:name*/ticket + +A ticket represents credentials to access VM. + +**Methods:** + +* **GET**: get the ticket of a VM + * password: the password of the ticket. One with the password can access a VM. + +* **PUT**: update the parameters of a VM ticket. + * password *(optional)*: the password of a ticket. + * expire *(optional)*: lifetime of a ticket. + +**Actions (POST):** + +*No actions defined* + + ### Resource: Template **URI:** /templates/*:name* -- 1.9.3

From: ShaoHe Feng <shaohef@linux.vnet.ibm.com> we set ticket as sub-resource of vm resource. Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> --- src/kimchi/API.json | 14 ++++++++++++++ src/kimchi/control/vms.py | 13 +++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/kimchi/API.json b/src/kimchi/API.json index 3616509..f5087e7 100644 --- a/src/kimchi/API.json +++ b/src/kimchi/API.json @@ -328,6 +328,20 @@ } } }, + "vmticket_update": { + "type": "object", + "properties": { + "passwd": { + "description": "the password of ticket.", + "minLength": 1, + "type": "string" + }, + "expire": { + "description": "lifetime of a ticket.", + "type": "number" + } + } + }, "templates_create": { "type": "object", "error": "KCHTMPL0016E", diff --git a/src/kimchi/control/vms.py b/src/kimchi/control/vms.py index 508f478..acc4a1f 100644 --- a/src/kimchi/control/vms.py +++ b/src/kimchi/control/vms.py @@ -34,6 +34,7 @@ def __init__(self, model, ident): super(VM, self).__init__(model, ident) self.update_params = ["name", "users", "groups", "cpus", "memory"] self.screenshot = VMScreenShot(model, ident) + self.ticket = VMTicket(model, ident) self.uri_fmt = '/vms/%s' for ident, node in sub_nodes.items(): setattr(self, ident, node(model, self.ident)) @@ -55,3 +56,15 @@ def __init__(self, model, ident): def get(self): self.lookup() raise internal_redirect(self.info) + + +class VMTicket(Resource): + def __init__(self, model, ident): + super(VMTicket, self).__init__(model, ident) + self.update_params = ["passwd", "expire"] + self.uri_fmt = '/vms/%s/ticket' + self.reset = self.generate_action_handler('reset') + + @property + def data(self): + return self.info -- 1.9.3

On 07/15/2014 12:45 PM, shaohef@linux.vnet.ibm.com wrote:
From: ShaoHe Feng <shaohef@linux.vnet.ibm.com>
we set ticket as sub-resource of vm resource.
Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> --- src/kimchi/API.json | 14 ++++++++++++++ src/kimchi/control/vms.py | 13 +++++++++++++ 2 files changed, 27 insertions(+)
diff --git a/src/kimchi/API.json b/src/kimchi/API.json index 3616509..f5087e7 100644 --- a/src/kimchi/API.json +++ b/src/kimchi/API.json @@ -328,6 +328,20 @@ } } }, + "vmticket_update": { + "type": "object", + "properties": { + "passwd": { + "description": "the password of ticket.", + "minLength": 1, + "type": "string"
You need to set the "error" string for invalid inputs
+ }, + "expire": { + "description": "lifetime of a ticket.", + "type": "number"
Same for expire
+ } + } + }, "templates_create": { "type": "object", "error": "KCHTMPL0016E", diff --git a/src/kimchi/control/vms.py b/src/kimchi/control/vms.py index 508f478..acc4a1f 100644 --- a/src/kimchi/control/vms.py +++ b/src/kimchi/control/vms.py @@ -34,6 +34,7 @@ def __init__(self, model, ident): super(VM, self).__init__(model, ident) self.update_params = ["name", "users", "groups", "cpus", "memory"] self.screenshot = VMScreenShot(model, ident) + self.ticket = VMTicket(model, ident) self.uri_fmt = '/vms/%s' for ident, node in sub_nodes.items(): setattr(self, ident, node(model, self.ident)) @@ -55,3 +56,15 @@ def __init__(self, model, ident): def get(self): self.lookup() raise internal_redirect(self.info) + + +class VMTicket(Resource): + def __init__(self, model, ident): + super(VMTicket, self).__init__(model, ident) + self.update_params = ["passwd", "expire"] + self.uri_fmt = '/vms/%s/ticket' + self.reset = self.generate_action_handler('reset') + + @property + def data(self): + return self.info

On 07/17/2014 08:44 AM, Aline Manera wrote:
On 07/15/2014 12:45 PM, shaohef@linux.vnet.ibm.com wrote:
From: ShaoHe Feng <shaohef@linux.vnet.ibm.com>
we set ticket as sub-resource of vm resource.
Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> --- src/kimchi/API.json | 14 ++++++++++++++ src/kimchi/control/vms.py | 13 +++++++++++++ 2 files changed, 27 insertions(+)
diff --git a/src/kimchi/API.json b/src/kimchi/API.json index 3616509..f5087e7 100644 --- a/src/kimchi/API.json +++ b/src/kimchi/API.json @@ -328,6 +328,20 @@ } } }, + "vmticket_update": { + "type": "object", + "properties": { + "passwd": { + "description": "the password of ticket.", + "minLength": 1, + "type": "string"
You need to set the "error" string for invalid inputs
during your vocation, we have discuss this problem: here is the log of our discussion. http://lists.ovirt.org/pipermail/kimchi-devel/2014-May/005306.html and it is improved for this "error" string http://lists.ovirt.org/pipermail/kimchi-devel/2014-May/005377.html we think for some schema item, we do not need "error". we let kimchi catch this error, and generates an common exception string. The generated exception string can not be translated by kimchi, it just depends on jsonschema to translate it.
+ }, + "expire": { + "description": "lifetime of a ticket.", + "type": "number"
Same for expire
+ } + } + }, "templates_create": { "type": "object", "error": "KCHTMPL0016E", diff --git a/src/kimchi/control/vms.py b/src/kimchi/control/vms.py index 508f478..acc4a1f 100644 --- a/src/kimchi/control/vms.py +++ b/src/kimchi/control/vms.py @@ -34,6 +34,7 @@ def __init__(self, model, ident): super(VM, self).__init__(model, ident) self.update_params = ["name", "users", "groups", "cpus", "memory"] self.screenshot = VMScreenShot(model, ident) + self.ticket = VMTicket(model, ident) self.uri_fmt = '/vms/%s' for ident, node in sub_nodes.items(): setattr(self, ident, node(model, self.ident)) @@ -55,3 +56,15 @@ def __init__(self, model, ident): def get(self): self.lookup() raise internal_redirect(self.info) + + +class VMTicket(Resource): + def __init__(self, model, ident): + super(VMTicket, self).__init__(model, ident) + self.update_params = ["passwd", "expire"] + self.uri_fmt = '/vms/%s/ticket' + self.reset = self.generate_action_handler('reset') + + @property + def data(self): + return self.info
-- Thanks and best regards! Sheldon Feng(冯少合)<shaohef@linux.vnet.ibm.com> IBM Linux Technology Center

On 2014年07月17日 11:10, Sheldon wrote:
On 07/17/2014 08:44 AM, Aline Manera wrote:
On 07/15/2014 12:45 PM, shaohef@linux.vnet.ibm.com wrote:
From: ShaoHe Feng <shaohef@linux.vnet.ibm.com>
we set ticket as sub-resource of vm resource.
Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> --- src/kimchi/API.json | 14 ++++++++++++++ src/kimchi/control/vms.py | 13 +++++++++++++ 2 files changed, 27 insertions(+)
diff --git a/src/kimchi/API.json b/src/kimchi/API.json index 3616509..f5087e7 100644 --- a/src/kimchi/API.json +++ b/src/kimchi/API.json @@ -328,6 +328,20 @@ } } }, + "vmticket_update": { + "type": "object", + "properties": { + "passwd": { + "description": "the password of ticket.", + "minLength": 1, + "type": "string"
You need to set the "error" string for invalid inputs
during your vocation, we have discuss this problem: here is the log of our discussion. http://lists.ovirt.org/pipermail/kimchi-devel/2014-May/005306.html and it is improved for this "error" string http://lists.ovirt.org/pipermail/kimchi-devel/2014-May/005377.html
we think for some schema item, we do not need "error". we let kimchi catch this error, and generates an common exception string.
The generated exception string can not be translated by kimchi, it just depends on jsonschema to translate it. According to me, params type errors and other obvious error can be handled by json schema validator automatically. For errors need special explaination, such as "patter not match :"pattern": "^[^ ]+( +[^ ]+)*$"" which cannot be understood from schema error report, I think we can specify an error number to it.
So for this one the error is: { "reason":"KCHAPI0008E: Parameters does not match requirement in schema: 1234 is not of type u'string'", "code":"400 Bad Request", "call_stack":"Traceback (most recent call last):\n File \"/usr/lib/python2.7/site-packages/cherrypy/_cprequest.py\", line 656, in respond\n response.body = self.handler()\n File \"/usr/lib/python2.7/site-packages/cherrypy/lib/encoding.py\", line 188, in __call__\n self.body = self.oldhandler(*args, **kwargs)\n File \"/usr/lib/python2.7/site-packages/cherrypy/_cpdispatch.py\", line 34, in __call__\n return self.callable(*self.args, **self.kwargs)\n File \"/home/shhfeng/work/workdir/kimchi/src/kimchi/control/base.py\", line 129, in index\n raise cherrypy.HTTPError(400, e.message)\nHTTPError: (400, u\"KCHAPI0008E: Parameters does not match requirement in schema: 1234 is not of type u'string'\")\n" } For me, Parameters does not match requirement in schema: 1234 is not of type u'string'", is a quite clear error msg which does not need manual handling. What do you think?
+ }, + "expire": { + "description": "lifetime of a ticket.", + "type": "number"
Same for expire
+ } + } + }, "templates_create": { "type": "object", "error": "KCHTMPL0016E", diff --git a/src/kimchi/control/vms.py b/src/kimchi/control/vms.py index 508f478..acc4a1f 100644 --- a/src/kimchi/control/vms.py +++ b/src/kimchi/control/vms.py @@ -34,6 +34,7 @@ def __init__(self, model, ident): super(VM, self).__init__(model, ident) self.update_params = ["name", "users", "groups", "cpus", "memory"] self.screenshot = VMScreenShot(model, ident) + self.ticket = VMTicket(model, ident) self.uri_fmt = '/vms/%s' for ident, node in sub_nodes.items(): setattr(self, ident, node(model, self.ident)) @@ -55,3 +56,15 @@ def __init__(self, model, ident): def get(self): self.lookup() raise internal_redirect(self.info) + + +class VMTicket(Resource): + def __init__(self, model, ident): + super(VMTicket, self).__init__(model, ident) + self.update_params = ["passwd", "expire"] + self.uri_fmt = '/vms/%s/ticket' + self.reset = self.generate_action_handler('reset') + + @property + def data(self): + return self.info

On 07/17/2014 07:04 AM, Royce Lv wrote:
On 2014年07月17日 11:10, Sheldon wrote:
On 07/17/2014 08:44 AM, Aline Manera wrote:
On 07/15/2014 12:45 PM, shaohef@linux.vnet.ibm.com wrote:
From: ShaoHe Feng <shaohef@linux.vnet.ibm.com>
we set ticket as sub-resource of vm resource.
Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> --- src/kimchi/API.json | 14 ++++++++++++++ src/kimchi/control/vms.py | 13 +++++++++++++ 2 files changed, 27 insertions(+)
diff --git a/src/kimchi/API.json b/src/kimchi/API.json index 3616509..f5087e7 100644 --- a/src/kimchi/API.json +++ b/src/kimchi/API.json @@ -328,6 +328,20 @@ } } }, + "vmticket_update": { + "type": "object", + "properties": { + "passwd": { + "description": "the password of ticket.", + "minLength": 1, + "type": "string"
You need to set the "error" string for invalid inputs
during your vocation, we have discuss this problem: here is the log of our discussion. http://lists.ovirt.org/pipermail/kimchi-devel/2014-May/005306.html and it is improved for this "error" string http://lists.ovirt.org/pipermail/kimchi-devel/2014-May/005377.html
we think for some schema item, we do not need "error". we let kimchi catch this error, and generates an common exception string.
The generated exception string can not be translated by kimchi, it just depends on jsonschema to translate it. According to me, params type errors and other obvious error can be handled by json schema validator automatically. For errors need special explaination, such as "patter not match :"pattern": "^[^ ]+( +[^ ]+)*$"" which cannot be understood from schema error report, I think we can specify an error number to it.
So for this one the error is:
{ "reason":"KCHAPI0008E: Parameters does not match requirement in schema: 1234 is not of type u'string'", "code":"400 Bad Request", "call_stack":"Traceback (most recent call last):\n File \"/usr/lib/python2.7/site-packages/cherrypy/_cprequest.py\", line 656, in respond\n response.body = self.handler()\n File \"/usr/lib/python2.7/site-packages/cherrypy/lib/encoding.py\", line 188, in __call__\n self.body = self.oldhandler(*args, **kwargs)\n File \"/usr/lib/python2.7/site-packages/cherrypy/_cpdispatch.py\", line 34, in __call__\n return self.callable(*self.args, **self.kwargs)\n File \"/home/shhfeng/work/workdir/kimchi/src/kimchi/control/base.py\", line 129, in index\n raise cherrypy.HTTPError(400, e.message)\nHTTPError: (400, u\"KCHAPI0008E: Parameters does not match requirement in schema: 1234 is not of type u'string'\")\n" }
For me, Parameters does not match requirement in schema: 1234 is not of type u'string'", is a quite clear error msg which does not need manual handling. What do you think?
The idea behind "error" parameter is to always display a translated message to the user. Without it, we will have in Portuguese: KCHAPI0008E: Parametros não satisfazem o requisito: 1234 is not of type u'string' Look, this is not a Portuguese message. If I am using Kimchi in Portuguese I want to see it in Portuguese instead of part in Portuguese and part in English. Please, keep using the "error" parameter on jsonschema to avoid those kind of untranslated messages.
+ }, + "expire": { + "description": "lifetime of a ticket.", + "type": "number"
Same for expire
+ } + } + }, "templates_create": { "type": "object", "error": "KCHTMPL0016E", diff --git a/src/kimchi/control/vms.py b/src/kimchi/control/vms.py index 508f478..acc4a1f 100644 --- a/src/kimchi/control/vms.py +++ b/src/kimchi/control/vms.py @@ -34,6 +34,7 @@ def __init__(self, model, ident): super(VM, self).__init__(model, ident) self.update_params = ["name", "users", "groups", "cpus", "memory"] self.screenshot = VMScreenShot(model, ident) + self.ticket = VMTicket(model, ident) self.uri_fmt = '/vms/%s' for ident, node in sub_nodes.items(): setattr(self, ident, node(model, self.ident)) @@ -55,3 +56,15 @@ def __init__(self, model, ident): def get(self): self.lookup() raise internal_redirect(self.info) + + +class VMTicket(Resource): + def __init__(self, model, ident): + super(VMTicket, self).__init__(model, ident) + self.update_params = ["passwd", "expire"] + self.uri_fmt = '/vms/%s/ticket' + self.reset = self.generate_action_handler('reset') + + @property + def data(self): + return self.info

On 07/17/2014 08:20 PM, Aline Manera wrote:
On 07/17/2014 07:04 AM, Royce Lv wrote:
On 2014年07月17日 11:10, Sheldon wrote:
On 07/17/2014 08:44 AM, Aline Manera wrote:
On 07/15/2014 12:45 PM, shaohef@linux.vnet.ibm.com wrote:
From: ShaoHe Feng <shaohef@linux.vnet.ibm.com>
we set ticket as sub-resource of vm resource.
Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> --- src/kimchi/API.json | 14 ++++++++++++++ src/kimchi/control/vms.py | 13 +++++++++++++ 2 files changed, 27 insertions(+)
diff --git a/src/kimchi/API.json b/src/kimchi/API.json index 3616509..f5087e7 100644 --- a/src/kimchi/API.json +++ b/src/kimchi/API.json @@ -328,6 +328,20 @@ } } }, + "vmticket_update": { + "type": "object", + "properties": { + "passwd": { + "description": "the password of ticket.", + "minLength": 1, + "type": "string"
You need to set the "error" string for invalid inputs
during your vocation, we have discuss this problem: here is the log of our discussion. http://lists.ovirt.org/pipermail/kimchi-devel/2014-May/005306.html and it is improved for this "error" string http://lists.ovirt.org/pipermail/kimchi-devel/2014-May/005377.html
we think for some schema item, we do not need "error". we let kimchi catch this error, and generates an common exception string.
The generated exception string can not be translated by kimchi, it just depends on jsonschema to translate it. According to me, params type errors and other obvious error can be handled by json schema validator automatically. For errors need special explaination, such as "patter not match :"pattern": "^[^ ]+( +[^ ]+)*$"" which cannot be understood from schema error report, I think we can specify an error number to it.
So for this one the error is:
{ "reason":"KCHAPI0008E: Parameters does not match requirement in schema: 1234 is not of type u'string'", "code":"400 Bad Request", "call_stack":"Traceback (most recent call last):\n File \"/usr/lib/python2.7/site-packages/cherrypy/_cprequest.py\", line 656, in respond\n response.body = self.handler()\n File \"/usr/lib/python2.7/site-packages/cherrypy/lib/encoding.py\", line 188, in __call__\n self.body = self.oldhandler(*args, **kwargs)\n File \"/usr/lib/python2.7/site-packages/cherrypy/_cpdispatch.py\", line 34, in __call__\n return self.callable(*self.args, **self.kwargs)\n File \"/home/shhfeng/work/workdir/kimchi/src/kimchi/control/base.py\", line 129, in index\n raise cherrypy.HTTPError(400, e.message)\nHTTPError: (400, u\"KCHAPI0008E: Parameters does not match requirement in schema: 1234 is not of type u'string'\")\n" }
For me, Parameters does not match requirement in schema: 1234 is not of type u'string'", is a quite clear error msg which does not need manual handling. What do you think?
The idea behind "error" parameter is to always display a translated message to the user. Without it, we will have in Portuguese:
KCHAPI0008E: Parametros não satisfazem o requisito: 1234 is not of type u'string'
Look, this is not a Portuguese message. If I am using Kimchi in Portuguese I want to see it in Portuguese instead of part in Portuguese and part in English.
Please, keep using the "error" parameter on jsonschema to avoid those kind of untranslated messages.
OK , I can add an "error" parameter. But the UI developers should double check the format of "passwd". They should not let users type an valid input. Do you agree? That means really kimchi user should not get this error message from backend. This message is just for developers. "KCHAPI0008E: Parameters does not match requirement in schema: 1234 is not of type u'string'\"
+ }, + "expire": { + "description": "lifetime of a ticket.", + "type": "number"
Same for expire
+ } + } + }, "templates_create": { "type": "object", "error": "KCHTMPL0016E", diff --git a/src/kimchi/control/vms.py b/src/kimchi/control/vms.py index 508f478..acc4a1f 100644 --- a/src/kimchi/control/vms.py +++ b/src/kimchi/control/vms.py @@ -34,6 +34,7 @@ def __init__(self, model, ident): super(VM, self).__init__(model, ident) self.update_params = ["name", "users", "groups", "cpus", "memory"] self.screenshot = VMScreenShot(model, ident) + self.ticket = VMTicket(model, ident) self.uri_fmt = '/vms/%s' for ident, node in sub_nodes.items(): setattr(self, ident, node(model, self.ident)) @@ -55,3 +56,15 @@ def __init__(self, model, ident): def get(self): self.lookup() raise internal_redirect(self.info) + + +class VMTicket(Resource): + def __init__(self, model, ident): + super(VMTicket, self).__init__(model, ident) + self.update_params = ["passwd", "expire"] + self.uri_fmt = '/vms/%s/ticket' + self.reset = self.generate_action_handler('reset') + + @property + def data(self): + return self.info
-- Thanks and best regards! Sheldon Feng(冯少合)<shaohef@linux.vnet.ibm.com> IBM Linux Technology Center

On 07/17/2014 11:27 AM, Sheldon wrote:
On 07/17/2014 08:20 PM, Aline Manera wrote:
On 07/17/2014 07:04 AM, Royce Lv wrote:
On 2014年07月17日 11:10, Sheldon wrote:
On 07/17/2014 08:44 AM, Aline Manera wrote:
On 07/15/2014 12:45 PM, shaohef@linux.vnet.ibm.com wrote:
From: ShaoHe Feng <shaohef@linux.vnet.ibm.com>
we set ticket as sub-resource of vm resource.
Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> --- src/kimchi/API.json | 14 ++++++++++++++ src/kimchi/control/vms.py | 13 +++++++++++++ 2 files changed, 27 insertions(+)
diff --git a/src/kimchi/API.json b/src/kimchi/API.json index 3616509..f5087e7 100644 --- a/src/kimchi/API.json +++ b/src/kimchi/API.json @@ -328,6 +328,20 @@ } } }, + "vmticket_update": { + "type": "object", + "properties": { + "passwd": { + "description": "the password of ticket.", + "minLength": 1, + "type": "string"
You need to set the "error" string for invalid inputs
during your vocation, we have discuss this problem: here is the log of our discussion. http://lists.ovirt.org/pipermail/kimchi-devel/2014-May/005306.html and it is improved for this "error" string http://lists.ovirt.org/pipermail/kimchi-devel/2014-May/005377.html
we think for some schema item, we do not need "error". we let kimchi catch this error, and generates an common exception string.
The generated exception string can not be translated by kimchi, it just depends on jsonschema to translate it. According to me, params type errors and other obvious error can be handled by json schema validator automatically. For errors need special explaination, such as "patter not match :"pattern": "^[^ ]+( +[^ ]+)*$"" which cannot be understood from schema error report, I think we can specify an error number to it.
So for this one the error is:
{ "reason":"KCHAPI0008E: Parameters does not match requirement in schema: 1234 is not of type u'string'", "code":"400 Bad Request", "call_stack":"Traceback (most recent call last):\n File \"/usr/lib/python2.7/site-packages/cherrypy/_cprequest.py\", line 656, in respond\n response.body = self.handler()\n File \"/usr/lib/python2.7/site-packages/cherrypy/lib/encoding.py\", line 188, in __call__\n self.body = self.oldhandler(*args, **kwargs)\n File \"/usr/lib/python2.7/site-packages/cherrypy/_cpdispatch.py\", line 34, in __call__\n return self.callable(*self.args, **self.kwargs)\n File \"/home/shhfeng/work/workdir/kimchi/src/kimchi/control/base.py\", line 129, in index\n raise cherrypy.HTTPError(400, e.message)\nHTTPError: (400, u\"KCHAPI0008E: Parameters does not match requirement in schema: 1234 is not of type u'string'\")\n" }
For me, Parameters does not match requirement in schema: 1234 is not of type u'string'", is a quite clear error msg which does not need manual handling. What do you think?
The idea behind "error" parameter is to always display a translated message to the user. Without it, we will have in Portuguese:
KCHAPI0008E: Parametros não satisfazem o requisito: 1234 is not of type u'string'
Look, this is not a Portuguese message. If I am using Kimchi in Portuguese I want to see it in Portuguese instead of part in Portuguese and part in English.
Please, keep using the "error" parameter on jsonschema to avoid those kind of untranslated messages.
OK , I can add an "error" parameter.
But the UI developers should double check the format of "passwd". They should not let users type an valid input.
Do you agree?
Yeap! You should have input verification in both - backend and frontend
That means really kimchi user should not get this error message from backend. This message is just for developers. "KCHAPI0008E: Parameters does not match requirement in schema: 1234 is not of type u'string'\"
For developer and whoever using the Kimchi REST API.
+ }, + "expire": { + "description": "lifetime of a ticket.", + "type": "number"
Same for expire
+ } + } + }, "templates_create": { "type": "object", "error": "KCHTMPL0016E", diff --git a/src/kimchi/control/vms.py b/src/kimchi/control/vms.py index 508f478..acc4a1f 100644 --- a/src/kimchi/control/vms.py +++ b/src/kimchi/control/vms.py @@ -34,6 +34,7 @@ def __init__(self, model, ident): super(VM, self).__init__(model, ident) self.update_params = ["name", "users", "groups", "cpus", "memory"] self.screenshot = VMScreenShot(model, ident) + self.ticket = VMTicket(model, ident) self.uri_fmt = '/vms/%s' for ident, node in sub_nodes.items(): setattr(self, ident, node(model, self.ident)) @@ -55,3 +56,15 @@ def __init__(self, model, ident): def get(self): self.lookup() raise internal_redirect(self.info) + + +class VMTicket(Resource): + def __init__(self, model, ident): + super(VMTicket, self).__init__(model, ident) + self.update_params = ["passwd", "expire"] + self.uri_fmt = '/vms/%s/ticket' + self.reset = self.generate_action_handler('reset') + + @property + def data(self): + return self.info

On 07/17/2014 12:10 AM, Sheldon wrote:
On 07/17/2014 08:44 AM, Aline Manera wrote:
On 07/15/2014 12:45 PM, shaohef@linux.vnet.ibm.com wrote:
From: ShaoHe Feng <shaohef@linux.vnet.ibm.com>
we set ticket as sub-resource of vm resource.
Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> --- src/kimchi/API.json | 14 ++++++++++++++ src/kimchi/control/vms.py | 13 +++++++++++++ 2 files changed, 27 insertions(+)
diff --git a/src/kimchi/API.json b/src/kimchi/API.json index 3616509..f5087e7 100644 --- a/src/kimchi/API.json +++ b/src/kimchi/API.json @@ -328,6 +328,20 @@ } } }, + "vmticket_update": { + "type": "object", + "properties": { + "passwd": { + "description": "the password of ticket.", + "minLength": 1, + "type": "string"
You need to set the "error" string for invalid inputs
during your vocation, we have discuss this problem: here is the log of our discussion. http://lists.ovirt.org/pipermail/kimchi-devel/2014-May/005306.html and it is improved for this "error" string http://lists.ovirt.org/pipermail/kimchi-devel/2014-May/005377.html
we think for some schema item, we do not need "error". we let kimchi catch this error, and generates an common exception string.
The generated exception string can not be translated by kimchi, it just depends on jsonschema to translate it.
Because of the exception error can not be translated by Kimchi, we have the "error" parameter With the error parameter the whole message is translated
+ }, + "expire": { + "description": "lifetime of a ticket.", + "type": "number"
Same for expire
+ } + } + }, "templates_create": { "type": "object", "error": "KCHTMPL0016E", diff --git a/src/kimchi/control/vms.py b/src/kimchi/control/vms.py index 508f478..acc4a1f 100644 --- a/src/kimchi/control/vms.py +++ b/src/kimchi/control/vms.py @@ -34,6 +34,7 @@ def __init__(self, model, ident): super(VM, self).__init__(model, ident) self.update_params = ["name", "users", "groups", "cpus", "memory"] self.screenshot = VMScreenShot(model, ident) + self.ticket = VMTicket(model, ident) self.uri_fmt = '/vms/%s' for ident, node in sub_nodes.items(): setattr(self, ident, node(model, self.ident)) @@ -55,3 +56,15 @@ def __init__(self, model, ident): def get(self): self.lookup() raise internal_redirect(self.info) + + +class VMTicket(Resource): + def __init__(self, model, ident): + super(VMTicket, self).__init__(model, ident) + self.update_params = ["passwd", "expire"] + self.uri_fmt = '/vms/%s/ticket' + self.reset = self.generate_action_handler('reset') + + @property + def data(self): + return self.info

From: ShaoHe Feng <shaohef@linux.vnet.ibm.com> Support lookup and update method for ticket. when set a ticket, it will take effect on both persistent and live configure. raise an exception if ticket expires when lookup it. Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> --- src/kimchi/i18n.py | 1 + src/kimchi/model/vms.py | 65 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py index 0c76145..a35bfde 100644 --- a/src/kimchi/i18n.py +++ b/src/kimchi/i18n.py @@ -89,6 +89,7 @@ "KCHVM0028E": _("Group(s) '%(groups)s' do not exist"), "KCHVM0029E": _("Unable to shutdown virtual machine %(name)s. Details: %(err)s"), "KCHVM0030E": _("Unable to get access metadata of virtual machine %(name)s. Details: %(err)s"), + "KCHVM0031E": _("The password of virtual machine %(name)s is invalid, please reset it."), "KCHVMIF0001E": _("Interface %(iface)s does not exist in virtual machine %(name)s"), "KCHVMIF0002E": _("Network %(network)s specified for virtual machine %(name)s does not exist"), diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py index 17bda04..2b919ad 100644 --- a/src/kimchi/model/vms.py +++ b/src/kimchi/model/vms.py @@ -19,7 +19,10 @@ from lxml.builder import E import lxml.etree as ET +from lxml import etree, objectify import os +import random +import string import time import uuid from xml.etree import ElementTree @@ -527,6 +530,68 @@ def _vmscreenshot_delete(self, vm_uuid): 'database due error: %s', e.message) +class VMTicketModel(object): + def __init__(self, **kargs): + self.objstore = kargs['objstore'] + self.conn = kargs['conn'] + + def lookup(self, name): + dom = VMModel.get_vm(name, self.conn) + xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE) + root = objectify.fromstring(xml) + graphic = root.devices.find("graphics") + passwd = graphic.attrib.get('passwd') + valid_to = graphic.attrib.get('passwdValidTo') + if valid_to is not None: + to = time.mktime(time.strptime(valid_to, '%Y-%m-%dT%H:%M:%S')) + if to - time.time() <= 0: + raise OperationFailed("KCHVM0031E", {'name': name}) + return {"passwd": passwd} + + def _libvirt_set_ticket(self, dom, password, expire, flag=0): + DEFAULT_VALID_TO = 30 + xml = dom.XMLDesc(flag) + root = objectify.fromstring(xml) + graphic = root.devices.find("graphics") + graphic.attrib['passwd'] = password + to = graphic.attrib.get('passwdValidTo') + valid_to = None + # will not set the passwdValidTo of persistent configure + if expire is not None: + valid_to = time.strftime( + '%Y-%m-%dT%H:%M:%S', + time.gmtime(time.time() + float(expire))) + if to is not None: + if (time.mktime(time.strptime(to, '%Y-%m-%dT%H:%M:%S')) + - time.time() <= 0): + valid_to = time.strftime( + '%Y-%m-%dT%H:%M:%S', + time.gmtime(time.time() + float(DEFAULT_VALID_TO))) + if valid_to is not None: + graphic.attrib['passwdValidTo'] = valid_to + + return root if flag == 0 else graphic + + def update(self, name, params): + dom = VMModel.get_vm(name, self.conn) + + password = params.get("passwd") + password = password if password is not None else "".join( + random.sample(string.ascii_letters + string.digits, 8)) + expire = params.get("expire") + + # for libvirt updateDeviceFlags do not support update persistent ticket + if dom.isPersistent(): + node = self._libvirt_set_ticket(dom, password, None) + conn = self.conn.get() + conn.defineXML(ET.tostring(node, encoding="utf-8")) + if dom.isActive(): + flag = libvirt.VIR_DOMAIN_XML_SECURE + node = self._libvirt_set_ticket(dom, password, expire, flag) + dom.updateDeviceFlags(etree.tostring(node), + libvirt.VIR_DOMAIN_AFFECT_LIVE) + + class VMScreenshotModel(object): def __init__(self, **kargs): self.objstore = kargs['objstore'] -- 1.9.3

On 07/15/2014 12:45 PM, shaohef@linux.vnet.ibm.com wrote:
From: ShaoHe Feng <shaohef@linux.vnet.ibm.com>
Support lookup and update method for ticket.
when set a ticket, it will take effect on both persistent and live configure.
raise an exception if ticket expires when lookup it.
Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> --- src/kimchi/i18n.py | 1 + src/kimchi/model/vms.py | 65 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+)
diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py index 0c76145..a35bfde 100644 --- a/src/kimchi/i18n.py +++ b/src/kimchi/i18n.py @@ -89,6 +89,7 @@ "KCHVM0028E": _("Group(s) '%(groups)s' do not exist"), "KCHVM0029E": _("Unable to shutdown virtual machine %(name)s. Details: %(err)s"), "KCHVM0030E": _("Unable to get access metadata of virtual machine %(name)s. Details: %(err)s"), + "KCHVM0031E": _("The password of virtual machine %(name)s is invalid, please reset it."),
"KCHVMIF0001E": _("Interface %(iface)s does not exist in virtual machine %(name)s"), "KCHVMIF0002E": _("Network %(network)s specified for virtual machine %(name)s does not exist"), diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py index 17bda04..2b919ad 100644 --- a/src/kimchi/model/vms.py +++ b/src/kimchi/model/vms.py @@ -19,7 +19,10 @@
from lxml.builder import E import lxml.etree as ET +from lxml import etree, objectify import os +import random +import string import time import uuid from xml.etree import ElementTree @@ -527,6 +530,68 @@ def _vmscreenshot_delete(self, vm_uuid): 'database due error: %s', e.message)
+class VMTicketModel(object): + def __init__(self, **kargs): + self.objstore = kargs['objstore'] + self.conn = kargs['conn'] + + def lookup(self, name): + dom = VMModel.get_vm(name, self.conn) + xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE) + root = objectify.fromstring(xml) + graphic = root.devices.find("graphics") + passwd = graphic.attrib.get('passwd') + valid_to = graphic.attrib.get('passwdValidTo') + if valid_to is not None: + to = time.mktime(time.strptime(valid_to, '%Y-%m-%dT%H:%M:%S')) + if to - time.time() <= 0: + raise OperationFailed("KCHVM0031E", {'name': name}) + return {"passwd": passwd} + + def _libvirt_set_ticket(self, dom, password, expire, flag=0): + DEFAULT_VALID_TO = 30 + xml = dom.XMLDesc(flag) + root = objectify.fromstring(xml) + graphic = root.devices.find("graphics") + graphic.attrib['passwd'] = password + to = graphic.attrib.get('passwdValidTo') + valid_to = None + # will not set the passwdValidTo of persistent configure + if expire is not None:
+ valid_to = time.strftime( + '%Y-%m-%dT%H:%M:%S', + time.gmtime(time.time() + float(expire)))
Maybe splitting this code into variables make it easier to read expire_time = time.gmtime(time.time() + float(expire)) valid_to = time.strftime('%Y-%m-%dT%H:%M:%S', expire_time)
+ if to is not None:
+ if (time.mktime(time.strptime(to, '%Y-%m-%dT%H:%M:%S')) + - time.time() <= 0): + valid_to = time.strftime( + '%Y-%m-%dT%H:%M:%S', + time.gmtime(time.time() + float(DEFAULT_VALID_TO)))
Same I commented above
+ if valid_to is not None: + graphic.attrib['passwdValidTo'] = valid_to + + return root if flag == 0 else graphic + + def update(self, name, params): + dom = VMModel.get_vm(name, self.conn) + + password = params.get("passwd") + password = password if password is not None else "".join( + random.sample(string.ascii_letters + string.digits, 8)) + expire = params.get("expire") + + # for libvirt updateDeviceFlags do not support update persistent ticket + if dom.isPersistent(): + node = self._libvirt_set_ticket(dom, password, None) + conn = self.conn.get() + conn.defineXML(ET.tostring(node, encoding="utf-8")) + if dom.isActive(): + flag = libvirt.VIR_DOMAIN_XML_SECURE + node = self._libvirt_set_ticket(dom, password, expire, flag) + dom.updateDeviceFlags(etree.tostring(node), + libvirt.VIR_DOMAIN_AFFECT_LIVE) + + class VMScreenshotModel(object): def __init__(self, **kargs): self.objstore = kargs['objstore']

On 07/17/2014 08:49 AM, Aline Manera wrote:
On 07/15/2014 12:45 PM, shaohef@linux.vnet.ibm.com wrote:
From: ShaoHe Feng <shaohef@linux.vnet.ibm.com>
Support lookup and update method for ticket.
when set a ticket, it will take effect on both persistent and live configure.
raise an exception if ticket expires when lookup it.
Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> --- src/kimchi/i18n.py | 1 + src/kimchi/model/vms.py | 65 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+)
diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py index 0c76145..a35bfde 100644 --- a/src/kimchi/i18n.py +++ b/src/kimchi/i18n.py @@ -89,6 +89,7 @@ "KCHVM0028E": _("Group(s) '%(groups)s' do not exist"), "KCHVM0029E": _("Unable to shutdown virtual machine %(name)s. Details: %(err)s"), "KCHVM0030E": _("Unable to get access metadata of virtual machine %(name)s. Details: %(err)s"), + "KCHVM0031E": _("The password of virtual machine %(name)s is invalid, please reset it."),
"KCHVMIF0001E": _("Interface %(iface)s does not exist in virtual machine %(name)s"), "KCHVMIF0002E": _("Network %(network)s specified for virtual machine %(name)s does not exist"), diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py index 17bda04..2b919ad 100644 --- a/src/kimchi/model/vms.py +++ b/src/kimchi/model/vms.py @@ -19,7 +19,10 @@
from lxml.builder import E import lxml.etree as ET +from lxml import etree, objectify import os +import random +import string import time import uuid from xml.etree import ElementTree @@ -527,6 +530,68 @@ def _vmscreenshot_delete(self, vm_uuid): 'database due error: %s', e.message)
+class VMTicketModel(object): + def __init__(self, **kargs): + self.objstore = kargs['objstore'] + self.conn = kargs['conn'] + + def lookup(self, name): + dom = VMModel.get_vm(name, self.conn) + xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE) + root = objectify.fromstring(xml) + graphic = root.devices.find("graphics") + passwd = graphic.attrib.get('passwd') + valid_to = graphic.attrib.get('passwdValidTo') + if valid_to is not None: + to = time.mktime(time.strptime(valid_to, '%Y-%m-%dT%H:%M:%S')) + if to - time.time() <= 0: + raise OperationFailed("KCHVM0031E", {'name': name}) + return {"passwd": passwd} + + def _libvirt_set_ticket(self, dom, password, expire, flag=0): + DEFAULT_VALID_TO = 30 + xml = dom.XMLDesc(flag) + root = objectify.fromstring(xml) + graphic = root.devices.find("graphics") + graphic.attrib['passwd'] = password + to = graphic.attrib.get('passwdValidTo') + valid_to = None + # will not set the passwdValidTo of persistent configure + if expire is not None:
+ valid_to = time.strftime( + '%Y-%m-%dT%H:%M:%S', + time.gmtime(time.time() + float(expire)))
Maybe splitting this code into variables make it easier to read
expire_time = time.gmtime(time.time() + float(expire)) valid_to = time.strftime('%Y-%m-%dT%H:%M:%S', expire_time)
looks good.
+ if to is not None:
+ if (time.mktime(time.strptime(to, '%Y-%m-%dT%H:%M:%S')) + - time.time() <= 0): + valid_to = time.strftime( + '%Y-%m-%dT%H:%M:%S', + time.gmtime(time.time() + float(DEFAULT_VALID_TO)))
Same I commented above
+ if valid_to is not None: + graphic.attrib['passwdValidTo'] = valid_to + + return root if flag == 0 else graphic + + def update(self, name, params): + dom = VMModel.get_vm(name, self.conn) + + password = params.get("passwd") + password = password if password is not None else "".join( + random.sample(string.ascii_letters + string.digits, 8)) + expire = params.get("expire") + + # for libvirt updateDeviceFlags do not support update persistent ticket + if dom.isPersistent(): + node = self._libvirt_set_ticket(dom, password, None) + conn = self.conn.get() + conn.defineXML(ET.tostring(node, encoding="utf-8")) + if dom.isActive(): + flag = libvirt.VIR_DOMAIN_XML_SECURE + node = self._libvirt_set_ticket(dom, password, expire, flag) + dom.updateDeviceFlags(etree.tostring(node), + libvirt.VIR_DOMAIN_AFFECT_LIVE) + + class VMScreenshotModel(object): def __init__(self, **kargs): self.objstore = kargs['objstore']
-- Thanks and best regards! Sheldon Feng(冯少合)<shaohef@linux.vnet.ibm.com> IBM Linux Technology Center

On 07/15/2014 11:45 PM, shaohef@linux.vnet.ibm.com wrote:
+class VMTicketModel(object): + def __init__(self, **kargs): + self.objstore = kargs['objstore'] + self.conn = kargs['conn'] + + def lookup(self, name): + dom = VMModel.get_vm(name, self.conn) + xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE) + root = objectify.fromstring(xml) + graphic = root.devices.find("graphics") + passwd = graphic.attrib.get('passwd') + valid_to = graphic.attrib.get('passwdValidTo') + if valid_to is not None: + to = time.mktime(time.strptime(valid_to, '%Y-%m-%dT%H:%M:%S')) + if to - time.time() <= 0: + raise OperationFailed("KCHVM0031E", {'name': name}) + return {"passwd": passwd} Here, when ticket expire, I report an error to user. Tell him, he should reset the password.
Now I will change the API as follow: GET /vms/<my-vm> { "name": my-vm, "cpu": 1, "memory": 512, "passwd": "abcd" } data = GET /vms/<my-vm> data.passwd when when ticket expire, what should I do? still an error report. Or GET /vms/<my-vm> { "name": my-vm, "cpu": 1, "memory": 512, "passwd": None } But this will be confused with a VM that has no password. so { "name": my-vm, "cpu": 1, "memory": 512, "passwd": None, ... } means ticket expire. { "name": my-vm, "cpu": 1, "memory": 512, ... } means no passwd is set? or { "name": my-vm, "cpu": 1, "memory": 512, "ticket": {"passwd": None, "expire": True}, ... } -- Thanks and best regards! Sheldon Feng(冯少合)<shaohef@linux.vnet.ibm.com> IBM Linux Technology Center

On 07/17/2014 12:10 PM, Sheldon wrote:
On 07/15/2014 11:45 PM, shaohef@linux.vnet.ibm.com wrote:
+class VMTicketModel(object): + def __init__(self, **kargs): + self.objstore = kargs['objstore'] + self.conn = kargs['conn'] + + def lookup(self, name): + dom = VMModel.get_vm(name, self.conn) + xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE) + root = objectify.fromstring(xml) + graphic = root.devices.find("graphics") + passwd = graphic.attrib.get('passwd') + valid_to = graphic.attrib.get('passwdValidTo') + if valid_to is not None: + to = time.mktime(time.strptime(valid_to, '%Y-%m-%dT%H:%M:%S')) + if to - time.time() <= 0: + raise OperationFailed("KCHVM0031E", {'name': name}) + return {"passwd": passwd} Here, when ticket expire, I report an error to user. Tell him, he should reset the password.
Now I will change the API as follow: GET /vms/<my-vm> {
"name": my-vm, "cpu": 1, "memory": 512, "passwd": "abcd"
}
data = GET /vms/<my-vm> data.passwd
when when ticket expire, what should I do? still an error report.
Or GET /vms/<my-vm> {
"name": my-vm, "cpu": 1, "memory": 512, "passwd": None
}
But this will be confused with a VM that has no password.
so {
"name": my-vm, "cpu": 1, "memory": 512, "passwd": None, ...
} means ticket expire.
{
"name": my-vm, "cpu": 1, "memory": 512, ...
} means no passwd is set?
or {
"name": my-vm, "cpu": 1, "memory": 512, "ticket": {"passwd": None, "expire": True}, ...
}
I think this last one can solve the problems But set "expire" to None when "passwd" is None
-- Thanks and best regards!
Sheldon Feng(冯少合)<shaohef@linux.vnet.ibm.com> IBM Linux Technology Center

On 07/18/2014 01:13 AM, Aline Manera wrote:
On 07/17/2014 12:10 PM, Sheldon wrote:
On 07/15/2014 11:45 PM, shaohef@linux.vnet.ibm.com wrote:
+class VMTicketModel(object): + def __init__(self, **kargs): + self.objstore = kargs['objstore'] + self.conn = kargs['conn'] + + def lookup(self, name): + dom = VMModel.get_vm(name, self.conn) + xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE) + root = objectify.fromstring(xml) + graphic = root.devices.find("graphics") + passwd = graphic.attrib.get('passwd') + valid_to = graphic.attrib.get('passwdValidTo') + if valid_to is not None: + to = time.mktime(time.strptime(valid_to, '%Y-%m-%dT%H:%M:%S')) + if to - time.time() <= 0: + raise OperationFailed("KCHVM0031E", {'name': name}) + return {"passwd": passwd} Here, when ticket expire, I report an error to user. Tell him, he should reset the password.
Now I will change the API as follow: GET /vms/<my-vm> {
"name": my-vm, "cpu": 1, "memory": 512, "passwd": "abcd"
}
data = GET /vms/<my-vm> data.passwd
when when ticket expire, what should I do? still an error report.
Or GET /vms/<my-vm> {
"name": my-vm, "cpu": 1, "memory": 512, "passwd": None
}
But this will be confused with a VM that has no password.
so {
"name": my-vm, "cpu": 1, "memory": 512, "passwd": None, ...
} means ticket expire.
{
"name": my-vm, "cpu": 1, "memory": 512, ...
} means no passwd is set?
or {
"name": my-vm, "cpu": 1, "memory": 512, "ticket": {"passwd": None, "expire": True}, ...
}
I think this last one can solve the problems But set "expire" to None when "passwd" is None
OK. Will change it in next version. but we should remember, the ticket in vm info may make no sense in most time, so we must get the whole vm info when connection. For UI, when connection, after get the vm info, it should check the expire of passwd data = GET /vms/my-vm data.ticket.expire == True By the way, IMHO, an prompt of error message is friendly for whoever using the Kimchi REST API.
-- Thanks and best regards!
Sheldon Feng(冯少合)<shaohef@linux.vnet.ibm.com> IBM Linux Technology Center
-- Thanks and best regards! Sheldon Feng(冯少合)<shaohef@linux.vnet.ibm.com> IBM Linux Technology Center

From: ShaoHe Feng <shaohef@linux.vnet.ibm.com> Support lookup and update method for ticket. Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> --- src/kimchi/mockmodel.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/kimchi/mockmodel.py b/src/kimchi/mockmodel.py index d1cec70..3309759 100644 --- a/src/kimchi/mockmodel.py +++ b/src/kimchi/mockmodel.py @@ -782,6 +782,23 @@ def vmiface_update(self, vm, mac, params): info['model'] = params['model'] return mac + def vmticket_lookup(self, vm): + dom = self._get_vm(vm) + to = dom.ticket.get('passwdValidTo') + if to is not None and to <= time.time(): + raise OperationFailed("KCHVM0031E", {'name': vm}) + return {"passwd": dom.ticket['passwd']} + + def vmticket_update(self, vm, params): + dom = self._get_vm(vm) + password = params.get("passwd") + password = password if password is not None else "".join( + random.sample(string.ascii_letters + string.digits, 8)) + expire = params.get("expire") + dom.ticket['passwd'] = password + if expire is not None: + dom.ticket['passwdValidTo'] = time.time() + expire + def tasks_get_list(self): with self.objstore as session: return session.get_list('task') @@ -1033,6 +1050,7 @@ def __init__(self, uuid, name, template_info): self.networks = template_info['networks'] ifaces = [MockVMIface(net) for net in self.networks] self.storagedevices = {} + self.ticket = {"passwd": "123456"} self.ifaces = dict([(iface.info['mac'], iface) for iface in ifaces]) stats = {'cpu_utilization': 20, -- 1.9.3

From: ShaoHe Feng <shaohef@linux.vnet.ibm.com> update test_model and test_rest Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> --- tests/test_model.py | 31 +++++++++++++++++++++++++++++++ tests/test_rest.py | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/tests/test_model.py b/tests/test_model.py index 2c77514..c182752 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -183,6 +183,37 @@ def test_vm_ifaces(self): self.assertEquals("e1000", iface["model"]) @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') + def test_vm_ticket(self): + inst = model.Model(objstore_loc=self.tmp_store) + with RollbackContext() as rollback: + params = {'name': 'test', 'disks': [], 'cdrom': self.kimchi_iso} + inst.templates_create(params) + rollback.prependDefer(inst.template_delete, 'test') + params = {'name': 'kimchi-ticket', 'template': '/templates/test'} + inst.vms_create(params) + rollback.prependDefer(inst.vm_delete, 'kimchi-ticket') + + # update vm persistent ticket configure + ticket_args = {"passwd": "123456"} + inst.vmticket_update('kimchi-ticket', ticket_args) + ticket = inst.vmticket_lookup('kimchi-ticket') + self.assertEquals("123456", ticket['passwd']) + + inst.vm_start('kimchi-ticket') + rollback.prependDefer(inst.vm_poweroff, 'kimchi-ticket') + # update live vm ticket configure + ticket_args = {"passwd": "abcdef"} + inst.vmticket_update('kimchi-ticket', ticket_args) + ticket = inst.vmticket_lookup('kimchi-ticket') + self.assertEquals("abcdef", ticket['passwd']) + + ticket_args = {"passwd": "123456", "expire": 0.1} + inst.vmticket_update('kimchi-ticket', ticket_args) + time.sleep(0.2) + self.assertRaises(OperationFailed, inst.vmticket_lookup, + 'kimchi-ticket') + + @unittest.skipUnless(utils.running_as_root(), 'Must be run as root') def test_vm_disk(self): disk_path = '/tmp/existent2.iso' open(disk_path, 'w').close() diff --git a/tests/test_rest.py b/tests/test_rest.py index 694d907..460177e 100644 --- a/tests/test_rest.py +++ b/tests/test_rest.py @@ -624,6 +624,42 @@ def test_vm_iface(self): '{}', 'DELETE') self.assertEquals(204, resp.status) + def test_vm_ticket(self): + + with RollbackContext() as rollback: + # Create a template as a base for our VMs + req = json.dumps({'name': 'test', 'cdrom': '/nonexistent.iso'}) + resp = self.request('/templates', req, 'POST') + self.assertEquals(201, resp.status) + # Delete the template + rollback.prependDefer(self.request, + '/templates/test', '{}', 'DELETE') + + # Create a VM with default args + req = json.dumps({'name': 'test-vm', + 'template': '/templates/test'}) + resp = self.request('/vms', req, 'POST') + self.assertEquals(201, resp.status) + # Delete the VM + rollback.prependDefer(self.request, + '/vms/test-vm', '{}', 'DELETE') + + ticket = json.loads(self.request('/vms/test-vm/ticket').read()) + self.assertEquals('123456', ticket['passwd']) + + # update vm ticket + req = json.dumps({"passwd": "abcdef"}) + resp = self.request('/vms/test-vm/ticket', req, 'PUT') + ticket = json.loads(resp.read()) + self.assertEquals('abcdef', ticket['passwd']) + + # ticket expire take effect + req = json.dumps({"passwd": "abcdef", "expire": 0.1}) + resp = self.request('/vms/test-vm/ticket', req, 'PUT') + time.sleep(0.2) + resp = self.request('/vms/test-vm/ticket') + self.assertEquals(500, resp.status) + def test_vm_customise_storage(self): # Create a Template req = json.dumps({'name': 'test', 'cdrom': '/nonexistent.iso', -- 1.9.3

On 07/15/2014 12:45 PM, shaohef@linux.vnet.ibm.com wrote:
From: ShaoHe Feng <shaohef@linux.vnet.ibm.com>
V1 -> V2: make ticket as sub-resource of a VM
Do we need a new sub-resource? Why not use PUT /vms/<my-vm> {passwd:...} ?
A ticket is the credential to access VM. Only who get the ticket can access a VM.
test this patch set: set the ticket $sudo curl -k -u <user>:<password> -H "Content-Type: application/json" -H \ "Accept: application/json" https://localhost:8001/vms/test-vm-8/ticket/ \ -X PUT -d '{"passwd": "abcd"}'
get the ticket $sudo curl -k -u <user>:<password> -H "Content-Type: application/json" -H \ "Accept: application/json" https://localhost:8001/vms/test-vm-8/ticket/
ShaoHe Feng (5): vm ticket in backend: update API.md vm ticket in backend: update controller and API.json vm ticket in backend: update model vm ticket in backend: update mockmodel vm ticket in backend: update test case
docs/API.md | 20 +++++++++++++++ src/kimchi/API.json | 14 ++++++++++ src/kimchi/control/vms.py | 13 ++++++++++ src/kimchi/i18n.py | 1 + src/kimchi/mockmodel.py | 18 +++++++++++++ src/kimchi/model/vms.py | 65 +++++++++++++++++++++++++++++++++++++++++++++++ tests/test_model.py | 31 ++++++++++++++++++++++ tests/test_rest.py | 36 ++++++++++++++++++++++++++ 8 files changed, 198 insertions(+)

On 07/16/2014 09:35 PM, Aline Manera wrote:
On 07/15/2014 12:45 PM, shaohef@linux.vnet.ibm.com wrote:
From: ShaoHe Feng <shaohef@linux.vnet.ibm.com>
V1 -> V2: make ticket as sub-resource of a VM
Do we need a new sub-resource? Why not use PUT /vms/<my-vm> {passwd:...} ?
Using the PUT /vms/<my-vm> also can make the UI logic simpler as the console password will be changed on VM Edit dialog (which already uses this PUT method)
A ticket is the credential to access VM. Only who get the ticket can access a VM.
test this patch set: set the ticket $sudo curl -k -u <user>:<password> -H "Content-Type: application/json" -H \ "Accept: application/json" https://localhost:8001/vms/test-vm-8/ticket/ \ -X PUT -d '{"passwd": "abcd"}'
get the ticket $sudo curl -k -u <user>:<password> -H "Content-Type: application/json" -H \ "Accept: application/json" https://localhost:8001/vms/test-vm-8/ticket/
ShaoHe Feng (5): vm ticket in backend: update API.md vm ticket in backend: update controller and API.json vm ticket in backend: update model vm ticket in backend: update mockmodel vm ticket in backend: update test case
docs/API.md | 20 +++++++++++++++ src/kimchi/API.json | 14 ++++++++++ src/kimchi/control/vms.py | 13 ++++++++++ src/kimchi/i18n.py | 1 + src/kimchi/mockmodel.py | 18 +++++++++++++ src/kimchi/model/vms.py | 65 +++++++++++++++++++++++++++++++++++++++++++++++ tests/test_model.py | 31 ++++++++++++++++++++++ tests/test_rest.py | 36 ++++++++++++++++++++++++++ 8 files changed, 198 insertions(+)
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel

On 07/17/2014 08:54 AM, Aline Manera wrote:
On 07/16/2014 09:35 PM, Aline Manera wrote:
On 07/15/2014 12:45 PM, shaohef@linux.vnet.ibm.com wrote:
From: ShaoHe Feng <shaohef@linux.vnet.ibm.com>
V1 -> V2: make ticket as sub-resource of a VM
Do we need a new sub-resource? Why not use PUT /vms/<my-vm> {passwd:...} ?
How do we get the passwd? GET /vms/<my-vm> { "name": my-vm, "cpu": 1, "memory": 512, "passwd": "abcd" }
Using the PUT /vms/<my-vm> also can make the UI logic simpler as the console password will be changed on VM Edit dialog
at VM Edit dialog, the disks and ifaces are all sub-collection. PUT /vms/<my-vm>/ifaces/iface1
(which already uses this PUT method)
A ticket is the credential to access VM. Only who get the ticket can access a VM.
test this patch set: set the ticket $sudo curl -k -u <user>:<password> -H "Content-Type: application/json" -H \ "Accept: application/json" https://localhost:8001/vms/test-vm-8/ticket/ \ -X PUT -d '{"passwd": "abcd"}'
get the ticket $sudo curl -k -u <user>:<password> -H "Content-Type: application/json" -H \ "Accept: application/json" https://localhost:8001/vms/test-vm-8/ticket/
ShaoHe Feng (5): vm ticket in backend: update API.md vm ticket in backend: update controller and API.json vm ticket in backend: update model vm ticket in backend: update mockmodel vm ticket in backend: update test case
docs/API.md | 20 +++++++++++++++ src/kimchi/API.json | 14 ++++++++++ src/kimchi/control/vms.py | 13 ++++++++++ src/kimchi/i18n.py | 1 + src/kimchi/mockmodel.py | 18 +++++++++++++ src/kimchi/model/vms.py | 65 +++++++++++++++++++++++++++++++++++++++++++++++ tests/test_model.py | 31 ++++++++++++++++++++++ tests/test_rest.py | 36 ++++++++++++++++++++++++++ 8 files changed, 198 insertions(+)
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel
-- Thanks and best regards! Sheldon Feng(???)<shaohef@linux.vnet.ibm.com> IBM Linux Technology Center

On 07/17/2014 08:54 AM, Aline Manera wrote:
On 07/16/2014 09:35 PM, Aline Manera wrote:
On 07/15/2014 12:45 PM, shaohef@linux.vnet.ibm.com wrote:
From: ShaoHe Feng <shaohef@linux.vnet.ibm.com>
V1 -> V2: make ticket as sub-resource of a VM
Do we need a new sub-resource? Why not use PUT /vms/<my-vm> {passwd:...} ?
How do we get the passwd? GET /vms/<my-vm> {
"name": my-vm, "cpu": 1, "memory": 512, "passwd": "abcd"
} I think this make some sense to me when considering this from 2
On 2014?07?17? 12:24, Sheldon wrote: perspectives: 1. if we put passwd in vm info, we need to parse passwd every time list_vms. If make it a subresource, we just manipulate it when connect vnc. 2. If we are controlled API level, we need to control vm_edit API for passwd set. But we may want to control set passwd for special user. What do you think?
Using the PUT /vms/<my-vm> also can make the UI logic simpler as the console password will be changed on VM Edit dialog
at VM Edit dialog, the disks and ifaces are all sub-collection. PUT /vms/<my-vm>/ifaces/iface1
(which already uses this PUT method)
A ticket is the credential to access VM. Only who get the ticket can access a VM.
test this patch set: set the ticket $sudo curl -k -u <user>:<password> -H "Content-Type: application/json" -H \ "Accept: application/json" https://localhost:8001/vms/test-vm-8/ticket/ \ -X PUT -d '{"passwd": "abcd"}'
get the ticket $sudo curl -k -u <user>:<password> -H "Content-Type: application/json" -H \ "Accept: application/json" https://localhost:8001/vms/test-vm-8/ticket/
ShaoHe Feng (5): vm ticket in backend: update API.md vm ticket in backend: update controller and API.json vm ticket in backend: update model vm ticket in backend: update mockmodel vm ticket in backend: update test case
docs/API.md | 20 +++++++++++++++ src/kimchi/API.json | 14 ++++++++++ src/kimchi/control/vms.py | 13 ++++++++++ src/kimchi/i18n.py | 1 + src/kimchi/mockmodel.py | 18 +++++++++++++ src/kimchi/model/vms.py | 65 +++++++++++++++++++++++++++++++++++++++++++++++ tests/test_model.py | 31 ++++++++++++++++++++++ tests/test_rest.py | 36 ++++++++++++++++++++++++++ 8 files changed, 198 insertions(+)
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel
-- Thanks and best regards!
Sheldon Feng(???)<shaohef@linux.vnet.ibm.com> IBM Linux Technology Center
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel

On 07/17/2014 01:24 AM, Sheldon wrote:
On 07/17/2014 08:54 AM, Aline Manera wrote:
On 07/16/2014 09:35 PM, Aline Manera wrote:
On 07/15/2014 12:45 PM, shaohef@linux.vnet.ibm.com wrote:
From: ShaoHe Feng <shaohef@linux.vnet.ibm.com>
V1 -> V2: make ticket as sub-resource of a VM
Do we need a new sub-resource? Why not use PUT /vms/<my-vm> {passwd:...} ?
How do we get the passwd? GET /vms/<my-vm> {
"name": my-vm, "cpu": 1, "memory": 512, "passwd": "abcd"
}
data = GET /vms/<my-vm> data.passwd
Using the PUT /vms/<my-vm> also can make the UI logic simpler as the console password will be changed on VM Edit dialog
at VM Edit dialog, the disks and ifaces are all sub-collection. PUT /vms/<my-vm>/ifaces/iface1
You are correct, but disks and ifaces have their own tab on VM Edit I was thinking in add the password in the VM configuration tab, which means use the PUT method
(which already uses this PUT method)
A ticket is the credential to access VM. Only who get the ticket can access a VM.
test this patch set: set the ticket $sudo curl -k -u <user>:<password> -H "Content-Type: application/json" -H \ "Accept: application/json" https://localhost:8001/vms/test-vm-8/ticket/ \ -X PUT -d '{"passwd": "abcd"}'
get the ticket $sudo curl -k -u <user>:<password> -H "Content-Type: application/json" -H \ "Accept: application/json" https://localhost:8001/vms/test-vm-8/ticket/
ShaoHe Feng (5): vm ticket in backend: update API.md vm ticket in backend: update controller and API.json vm ticket in backend: update model vm ticket in backend: update mockmodel vm ticket in backend: update test case
docs/API.md | 20 +++++++++++++++ src/kimchi/API.json | 14 ++++++++++ src/kimchi/control/vms.py | 13 ++++++++++ src/kimchi/i18n.py | 1 + src/kimchi/mockmodel.py | 18 +++++++++++++ src/kimchi/model/vms.py | 65 +++++++++++++++++++++++++++++++++++++++++++++++ tests/test_model.py | 31 ++++++++++++++++++++++ tests/test_rest.py | 36 ++++++++++++++++++++++++++ 8 files changed, 198 insertions(+)
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel
-- Thanks and best regards!
Sheldon Feng(???)<shaohef@linux.vnet.ibm.com> IBM Linux Technology Center

On 07/17/2014 09:25 PM, Aline Manera wrote:
On 07/17/2014 01:24 AM, Sheldon wrote:
On 07/17/2014 08:54 AM, Aline Manera wrote:
On 07/16/2014 09:35 PM, Aline Manera wrote:
On 07/15/2014 12:45 PM, shaohef@linux.vnet.ibm.com wrote:
From: ShaoHe Feng <shaohef@linux.vnet.ibm.com>
V1 -> V2: make ticket as sub-resource of a VM
Do we need a new sub-resource? Why not use PUT /vms/<my-vm> {passwd:...} ?
How do we get the passwd? GET /vms/<my-vm> {
"name": my-vm, "cpu": 1, "memory": 512, "passwd": "abcd"
}
data = GET /vms/<my-vm> data.passwd
Using the PUT /vms/<my-vm> also can make the UI logic simpler as the console password will be changed on VM Edit dialog
at VM Edit dialog, the disks and ifaces are all sub-collection. PUT /vms/<my-vm>/ifaces/iface1
You are correct, but disks and ifaces have their own tab on VM Edit I was thinking in add the password in the VM configuration tab, which means use the PUT method
I have no preference. I can change it in the next version. But we had better to get agreement before our patches. Though it is difficult sometimes. In my V1 version I did take passwd as an attribute of VM instead of sub-resource. Anyway we have get agreement that "have their own tab" is the criterion of sub-collection and sub-resource.
(which already uses this PUT method)
A ticket is the credential to access VM. Only who get the ticket can access a VM.
test this patch set: set the ticket $sudo curl -k -u <user>:<password> -H "Content-Type: application/json" -H \ "Accept: application/json" https://localhost:8001/vms/test-vm-8/ticket/ \ -X PUT -d '{"passwd": "abcd"}'
get the ticket $sudo curl -k -u <user>:<password> -H "Content-Type: application/json" -H \ "Accept: application/json" https://localhost:8001/vms/test-vm-8/ticket/
ShaoHe Feng (5): vm ticket in backend: update API.md vm ticket in backend: update controller and API.json vm ticket in backend: update model vm ticket in backend: update mockmodel vm ticket in backend: update test case
docs/API.md | 20 +++++++++++++++ src/kimchi/API.json | 14 ++++++++++ src/kimchi/control/vms.py | 13 ++++++++++ src/kimchi/i18n.py | 1 + src/kimchi/mockmodel.py | 18 +++++++++++++ src/kimchi/model/vms.py | 65 +++++++++++++++++++++++++++++++++++++++++++++++ tests/test_model.py | 31 ++++++++++++++++++++++ tests/test_rest.py | 36 ++++++++++++++++++++++++++ 8 files changed, 198 insertions(+)
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel
-- Thanks and best regards!
Sheldon Feng(???)<shaohef@linux.vnet.ibm.com> IBM Linux Technology Center
-- Thanks and best regards! Sheldon Feng(???)<shaohef@linux.vnet.ibm.com> IBM Linux Technology Center

On 07/17/2014 12:00 PM, Sheldon wrote:
On 07/17/2014 09:25 PM, Aline Manera wrote:
On 07/17/2014 01:24 AM, Sheldon wrote:
On 07/17/2014 08:54 AM, Aline Manera wrote:
On 07/16/2014 09:35 PM, Aline Manera wrote:
On 07/15/2014 12:45 PM, shaohef@linux.vnet.ibm.com wrote:
From: ShaoHe Feng <shaohef@linux.vnet.ibm.com>
V1 -> V2: make ticket as sub-resource of a VM
Do we need a new sub-resource? Why not use PUT /vms/<my-vm> {passwd:...} ?
How do we get the passwd? GET /vms/<my-vm> {
"name": my-vm, "cpu": 1, "memory": 512, "passwd": "abcd"
}
data = GET /vms/<my-vm> data.passwd
Using the PUT /vms/<my-vm> also can make the UI logic simpler as the console password will be changed on VM Edit dialog
at VM Edit dialog, the disks and ifaces are all sub-collection. PUT /vms/<my-vm>/ifaces/iface1
You are correct, but disks and ifaces have their own tab on VM Edit I was thinking in add the password in the VM configuration tab, which means use the PUT method
I have no preference. I can change it in the next version.
But we had better to get agreement before our patches. Though it is difficult sometimes.
Agree
In my V1 version I did take passwd as an attribute of VM instead of sub-resource.
Sorry I haven't had chance to review the V1
Anyway we have get agreement that "have their own tab" is the criterion of sub-collection and sub-resource.
(which already uses this PUT method)
A ticket is the credential to access VM. Only who get the ticket can access a VM.
test this patch set: set the ticket $sudo curl -k -u <user>:<password> -H "Content-Type: application/json" -H \ "Accept: application/json" https://localhost:8001/vms/test-vm-8/ticket/ \ -X PUT -d '{"passwd": "abcd"}'
get the ticket $sudo curl -k -u <user>:<password> -H "Content-Type: application/json" -H \ "Accept: application/json" https://localhost:8001/vms/test-vm-8/ticket/
ShaoHe Feng (5): vm ticket in backend: update API.md vm ticket in backend: update controller and API.json vm ticket in backend: update model vm ticket in backend: update mockmodel vm ticket in backend: update test case
docs/API.md | 20 +++++++++++++++ src/kimchi/API.json | 14 ++++++++++ src/kimchi/control/vms.py | 13 ++++++++++ src/kimchi/i18n.py | 1 + src/kimchi/mockmodel.py | 18 +++++++++++++ src/kimchi/model/vms.py | 65 +++++++++++++++++++++++++++++++++++++++++++++++ tests/test_model.py | 31 ++++++++++++++++++++++ tests/test_rest.py | 36 ++++++++++++++++++++++++++ 8 files changed, 198 insertions(+)
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel
-- Thanks and best regards!
Sheldon Feng(???)<shaohef@linux.vnet.ibm.com> IBM Linux Technology Center
-- Thanks and best regards!
Sheldon Feng(???)<shaohef@linux.vnet.ibm.com> IBM Linux Technology Center
participants (4)
-
Aline Manera
-
Royce Lv
-
shaohef@linux.vnet.ibm.com
-
Sheldon