[PATCH 0/4 - v333] Add multiple disks in Template

V3 - Addresses Aline's comments * fixes backend, API.md and API.json * fixes test cases and add new test V2 - Rebase over latest new UI patches V1 - Initial version Rodrigo Trujillo (4): Fix Template backend create/update for multiple disks UI - Implement multiple disks support in Template edit window Test: Fix and add test related to disks in templates Fix pep8 problems src/wok/plugins/kimchi/API.json | 19 +- src/wok/plugins/kimchi/docs/API.md | 3 + src/wok/plugins/kimchi/model/templates.py | 9 +- src/wok/plugins/kimchi/model/vms.py | 6 +- src/wok/plugins/kimchi/osinfo.py | 1 + src/wok/plugins/kimchi/tests/test_rest.py | 8 +- src/wok/plugins/kimchi/tests/test_template.py | 36 ++- .../kimchi/ui/js/src/kimchi.template_edit_main.js | 246 ++++++++++----------- .../kimchi/ui/pages/template-edit.html.tmpl | 5 +- src/wok/plugins/kimchi/vmtemplate.py | 13 +- 10 files changed, 204 insertions(+), 142 deletions(-) -- 2.1.0

This patch fixes the backend code in order to allow create templates with multiple disks and update them correctly. Backend supports disks jsons like: "disks": [{"size": 3, "format": "qcow"}, {"size": 5, "storagepool":"/plugins/kimchi/storagepools/poolX"}, {"size": 7, "format": "raw", "storagepool": "/plugins/kimchi/storagepools/poolY"} ] If any information is missing, Kimchi will use values from template.conf. Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> --- src/wok/plugins/kimchi/API.json | 19 ++++++++++++++++++- src/wok/plugins/kimchi/docs/API.md | 3 +++ src/wok/plugins/kimchi/model/templates.py | 9 +++++---- src/wok/plugins/kimchi/osinfo.py | 1 + src/wok/plugins/kimchi/vmtemplate.py | 13 ++++++++++--- 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/wok/plugins/kimchi/API.json b/src/wok/plugins/kimchi/API.json index ab9ac9b..e4cabd6 100644 --- a/src/wok/plugins/kimchi/API.json +++ b/src/wok/plugins/kimchi/API.json @@ -477,6 +477,12 @@ "type": "integer", "minimum": 0 }, + "format": { + "description": "Type of the image of the disk", + "type": "string", + "pattern": "^(bochs|cloop|cow|dmg|qcow|qcow2|qed|raw|vmdk|vpc)$", + "error": "KCHTMPL0027E" + }, "size": { "description": "Size (GB) of the disk", "type": "number", @@ -488,8 +494,13 @@ "type": "string", "pattern": "^/.+$", "error": "KCHTMPL0023E" + }, + "storagepool": { + "description": "Location of the storage pool", + "type": "string", + "pattern": "^/plugins/kimchi/storagepools/[^/]+/?$", + "error": "KCHTMPL0015E" } - } }, "minItems": 1, @@ -660,6 +671,12 @@ "type": "string", "pattern": "^(bochs|cloop|cow|dmg|qcow|qcow2|qed|raw|vmdk|vpc)$", "error": "KCHTMPL0027E" + }, + "storagepool": { + "description": "Location of the storage pool", + "type": "string", + "pattern": "^/plugins/kimchi/storagepools/[^/]+/?$", + "error": "KCHTMPL0015E" } } }, diff --git a/src/wok/plugins/kimchi/docs/API.md b/src/wok/plugins/kimchi/docs/API.md index 5787755..93da547 100644 --- a/src/wok/plugins/kimchi/docs/API.md +++ b/src/wok/plugins/kimchi/docs/API.md @@ -289,6 +289,8 @@ Represents a snapshot of the Virtual Machine's primary monitor. (either *size* or *volume* must be specified): * index: The device index * size: The device size in GB + * format: Format of the image. Valid formats: bochs, cloop, cow, dmg, qcow, qcow2, qed, raw, vmdk, vpc + * storagepool: URI of the storagepool where disk will be created * base: Base image of this disk * graphics *(optional)*: The graphics paramenters of this template @@ -422,6 +424,7 @@ A interface represents available network interface on VM. * size: The device size in GB * volume: A volume name that contains the initial disk contents * format: Format of the image. Valid formats: bochs, cloop, cow, dmg, qcow, qcow2, qed, raw, vmdk, vpc. + * storagepool: URI of the storagepool where template allocates vm disk. * graphics *(optional)*: A dict of graphics paramenters of this template * type: The type of graphics. It can be VNC or spice or None. * vnc: Graphical display using the Virtual Network diff --git a/src/wok/plugins/kimchi/model/templates.py b/src/wok/plugins/kimchi/model/templates.py index 47b2c9e..bac6e47 100644 --- a/src/wok/plugins/kimchi/model/templates.py +++ b/src/wok/plugins/kimchi/model/templates.py @@ -234,8 +234,9 @@ class LibvirtVMTemplate(VMTemplate): self.conn = conn VMTemplate.__init__(self, args, scan) - def _storage_validate(self): - pool_uri = self.info['storagepool'] + def _storage_validate(self, pool_uri=None): + if pool_uri is None: + pool_uri = self.info['storagepool'] pool_name = pool_name_from_uri(pool_uri) try: conn = self.conn.get() @@ -278,8 +279,8 @@ class LibvirtVMTemplate(VMTemplate): xml = pool.XMLDesc(0) return xpath_get_text(xml, "/pool/target/path")[0] - def _get_storage_type(self): - pool = self._storage_validate() + def _get_storage_type(self, pool_uri=None): + pool = self._storage_validate(pool_uri) xml = pool.XMLDesc(0) return xpath_get_text(xml, "/pool/@type")[0] diff --git a/src/wok/plugins/kimchi/osinfo.py b/src/wok/plugins/kimchi/osinfo.py index 30ecd4f..12e5b4b 100644 --- a/src/wok/plugins/kimchi/osinfo.py +++ b/src/wok/plugins/kimchi/osinfo.py @@ -158,6 +158,7 @@ def _get_tmpl_defaults(): for disk in storage_section.keys(): data = storage_section[disk] data['index'] = int(disk.split('.')[1]) + data['storagepool'] = defaults['storagepool'] defaults['disks'].append(data) # Parse processor section to get cpus and cpu_topology values diff --git a/src/wok/plugins/kimchi/vmtemplate.py b/src/wok/plugins/kimchi/vmtemplate.py index 3097b66..35210a3 100644 --- a/src/wok/plugins/kimchi/vmtemplate.py +++ b/src/wok/plugins/kimchi/vmtemplate.py @@ -76,14 +76,21 @@ class VMTemplate(object): graphics.update(graph_args) args['graphics'] = graphics + # Support to create Template with multiple disks + for i, disk in enumerate(self.info['disks']): + self.info['disks'][i]['storagepooltype'] = \ + self._get_storage_type(disk['storagepool']) + # Merge disks dict default_disk = self.info['disks'][0] for i, d in enumerate(args.get('disks', [])): disk = dict(default_disk) + disk['index'] = i disk.update(d) - + disk['storagepooltype'] = self._get_storage_type( + disk['storagepool']) # Assign right disk format to logical and [i]scsi storagepools - if self._get_storage_type() in ['logical', 'iscsi', 'scsi']: + if disk['storagepooltype'] in ['logical', 'iscsi', 'scsi']: disk['format'] = 'raw' args['disks'][i] = disk @@ -401,7 +408,7 @@ class VMTemplate(object): def _get_storage_path(self): return '' - def _get_storage_type(self): + def _get_storage_type(self, pool=None): return '' def _get_volume_path(self): -- 2.1.0

On 25/11/2015 04:45, Rodrigo Trujillo wrote:
This patch fixes the backend code in order to allow create templates with multiple disks and update them correctly. Backend supports disks jsons like:
"disks": [{"size": 3, "format": "qcow"}, {"size": 5, "storagepool":"/plugins/kimchi/storagepools/poolX"}, {"size": 7, "format": "raw", "storagepool": "/plugins/kimchi/storagepools/poolY"} ]
If any information is missing, Kimchi will use values from template.conf.
Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> --- src/wok/plugins/kimchi/API.json | 19 ++++++++++++++++++- src/wok/plugins/kimchi/docs/API.md | 3 +++ src/wok/plugins/kimchi/model/templates.py | 9 +++++---- src/wok/plugins/kimchi/osinfo.py | 1 + src/wok/plugins/kimchi/vmtemplate.py | 13 ++++++++++--- 5 files changed, 37 insertions(+), 8 deletions(-)
diff --git a/src/wok/plugins/kimchi/API.json b/src/wok/plugins/kimchi/API.json index ab9ac9b..e4cabd6 100644 --- a/src/wok/plugins/kimchi/API.json +++ b/src/wok/plugins/kimchi/API.json @@ -477,6 +477,12 @@ "type": "integer", "minimum": 0 }, + "format": { + "description": "Type of the image of the disk", + "type": "string", + "pattern": "^(bochs|cloop|cow|dmg|qcow|qcow2|qed|raw|vmdk|vpc)$", + "error": "KCHTMPL0027E" + }, "size": { "description": "Size (GB) of the disk", "type": "number", @@ -488,8 +494,13 @@ "type": "string", "pattern": "^/.+$", "error": "KCHTMPL0023E" + }, + "storagepool": { + "description": "Location of the storage pool", + "type": "string", + "pattern": "^/plugins/kimchi/storagepools/[^/]+/?$", + "error": "KCHTMPL0015E" } - } }, "minItems": 1, @@ -660,6 +671,12 @@ "type": "string", "pattern": "^(bochs|cloop|cow|dmg|qcow|qcow2|qed|raw|vmdk|vpc)$", "error": "KCHTMPL0027E" + }, + "storagepool": { + "description": "Location of the storage pool", + "type": "string", + "pattern": "^/plugins/kimchi/storagepools/[^/]+/?$", + "error": "KCHTMPL0015E" } } }, diff --git a/src/wok/plugins/kimchi/docs/API.md b/src/wok/plugins/kimchi/docs/API.md index 5787755..93da547 100644 --- a/src/wok/plugins/kimchi/docs/API.md +++ b/src/wok/plugins/kimchi/docs/API.md @@ -289,6 +289,8 @@ Represents a snapshot of the Virtual Machine's primary monitor. (either *size* or *volume* must be specified): * index: The device index * size: The device size in GB + * format: Format of the image. Valid formats: bochs, cloop, cow, dmg, qcow, qcow2, qed, raw, vmdk, vpc + * storagepool: URI of the storagepool where disk will be created * base: Base image of this disk
* graphics *(optional)*: The graphics paramenters of this template @@ -422,6 +424,7 @@ A interface represents available network interface on VM. * size: The device size in GB * volume: A volume name that contains the initial disk contents * format: Format of the image. Valid formats: bochs, cloop, cow, dmg, qcow, qcow2, qed, raw, vmdk, vpc. + * storagepool: URI of the storagepool where template allocates vm disk. * graphics *(optional)*: A dict of graphics paramenters of this template * type: The type of graphics. It can be VNC or spice or None. * vnc: Graphical display using the Virtual Network diff --git a/src/wok/plugins/kimchi/model/templates.py b/src/wok/plugins/kimchi/model/templates.py index 47b2c9e..bac6e47 100644 --- a/src/wok/plugins/kimchi/model/templates.py +++ b/src/wok/plugins/kimchi/model/templates.py @@ -234,8 +234,9 @@ class LibvirtVMTemplate(VMTemplate): self.conn = conn VMTemplate.__init__(self, args, scan)
- def _storage_validate(self): - pool_uri = self.info['storagepool'] + def _storage_validate(self, pool_uri=None): + if pool_uri is None: + pool_uri = self.info['storagepool'] pool_name = pool_name_from_uri(pool_uri) try: conn = self.conn.get() @@ -278,8 +279,8 @@ class LibvirtVMTemplate(VMTemplate): xml = pool.XMLDesc(0) return xpath_get_text(xml, "/pool/target/path")[0]
- def _get_storage_type(self): - pool = self._storage_validate() + def _get_storage_type(self, pool_uri=None): + pool = self._storage_validate(pool_uri) xml = pool.XMLDesc(0) return xpath_get_text(xml, "/pool/@type")[0]
diff --git a/src/wok/plugins/kimchi/osinfo.py b/src/wok/plugins/kimchi/osinfo.py index 30ecd4f..12e5b4b 100644 --- a/src/wok/plugins/kimchi/osinfo.py +++ b/src/wok/plugins/kimchi/osinfo.py @@ -158,6 +158,7 @@ def _get_tmpl_defaults(): for disk in storage_section.keys(): data = storage_section[disk] data['index'] = int(disk.split('.')[1]) + data['storagepool'] = defaults['storagepool'] defaults['disks'].append(data)
# Parse processor section to get cpus and cpu_topology values diff --git a/src/wok/plugins/kimchi/vmtemplate.py b/src/wok/plugins/kimchi/vmtemplate.py index 3097b66..35210a3 100644 --- a/src/wok/plugins/kimchi/vmtemplate.py +++ b/src/wok/plugins/kimchi/vmtemplate.py @@ -76,14 +76,21 @@ class VMTemplate(object): graphics.update(graph_args) args['graphics'] = graphics
+ # Support to create Template with multiple disks + for i, disk in enumerate(self.info['disks']): + self.info['disks'][i]['storagepooltype'] = \ + self._get_storage_type(disk['storagepool']) +
So the pool type will be also returned in the API, right? I think I have already suggested it before, but.... Keep the data grouped, ie, for the storage pool information use a single JSON object to care about that information: disk: {pool: {name:..., 'type':...}, index: ..., size:... } Also update the docs/API.md to reflect the addition of 'type'
# Merge disks dict default_disk = self.info['disks'][0] for i, d in enumerate(args.get('disks', [])): disk = dict(default_disk) + disk['index'] = i disk.update(d) - + disk['storagepooltype'] = self._get_storage_type( + disk['storagepool']) # Assign right disk format to logical and [i]scsi storagepools - if self._get_storage_type() in ['logical', 'iscsi', 'scsi']: + if disk['storagepooltype'] in ['logical', 'iscsi', 'scsi']: disk['format'] = 'raw' args['disks'][i] = disk
@@ -401,7 +408,7 @@ class VMTemplate(object): def _get_storage_path(self): return ''
- def _get_storage_type(self): + def _get_storage_type(self, pool=None): return ''
def _get_volume_path(self):

On 11/25/2015 03:40 PM, Aline Manera wrote:
On 25/11/2015 04:45, Rodrigo Trujillo wrote:
This patch fixes the backend code in order to allow create templates with multiple disks and update them correctly. Backend supports disks jsons like:
"disks": [{"size": 3, "format": "qcow"}, {"size": 5, "storagepool":"/plugins/kimchi/storagepools/poolX"}, {"size": 7, "format": "raw", "storagepool": "/plugins/kimchi/storagepools/poolY"} ]
If any information is missing, Kimchi will use values from template.conf.
Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> --- src/wok/plugins/kimchi/API.json | 19 ++++++++++++++++++- src/wok/plugins/kimchi/docs/API.md | 3 +++ src/wok/plugins/kimchi/model/templates.py | 9 +++++---- src/wok/plugins/kimchi/osinfo.py | 1 + src/wok/plugins/kimchi/vmtemplate.py | 13 ++++++++++--- 5 files changed, 37 insertions(+), 8 deletions(-)
diff --git a/src/wok/plugins/kimchi/API.json b/src/wok/plugins/kimchi/API.json index ab9ac9b..e4cabd6 100644 --- a/src/wok/plugins/kimchi/API.json +++ b/src/wok/plugins/kimchi/API.json @@ -477,6 +477,12 @@ "type": "integer", "minimum": 0 }, + "format": { + "description": "Type of the image of the disk", + "type": "string", + "pattern": "^(bochs|cloop|cow|dmg|qcow|qcow2|qed|raw|vmdk|vpc)$", + "error": "KCHTMPL0027E" + }, "size": { "description": "Size (GB) of the disk", "type": "number", @@ -488,8 +494,13 @@ "type": "string", "pattern": "^/.+$", "error": "KCHTMPL0023E" + }, + "storagepool": { + "description": "Location of the storage pool", + "type": "string", + "pattern": "^/plugins/kimchi/storagepools/[^/]+/?$", + "error": "KCHTMPL0015E" } - } }, "minItems": 1, @@ -660,6 +671,12 @@ "type": "string", "pattern": "^(bochs|cloop|cow|dmg|qcow|qcow2|qed|raw|vmdk|vpc)$", "error": "KCHTMPL0027E" + }, + "storagepool": { + "description": "Location of the storage pool", + "type": "string", + "pattern": "^/plugins/kimchi/storagepools/[^/]+/?$", + "error": "KCHTMPL0015E" } } }, diff --git a/src/wok/plugins/kimchi/docs/API.md b/src/wok/plugins/kimchi/docs/API.md index 5787755..93da547 100644 --- a/src/wok/plugins/kimchi/docs/API.md +++ b/src/wok/plugins/kimchi/docs/API.md @@ -289,6 +289,8 @@ Represents a snapshot of the Virtual Machine's primary monitor. (either *size* or *volume* must be specified): * index: The device index * size: The device size in GB + * format: Format of the image. Valid formats: bochs, cloop, cow, dmg, qcow, qcow2, qed, raw, vmdk, vpc + * storagepool: URI of the storagepool where disk will be created * base: Base image of this disk
* graphics *(optional)*: The graphics paramenters of this template @@ -422,6 +424,7 @@ A interface represents available network interface on VM. * size: The device size in GB * volume: A volume name that contains the initial disk contents * format: Format of the image. Valid formats: bochs, cloop, cow, dmg, qcow, qcow2, qed, raw, vmdk, vpc. + * storagepool: URI of the storagepool where template allocates vm disk. * graphics *(optional)*: A dict of graphics paramenters of this template * type: The type of graphics. It can be VNC or spice or None. * vnc: Graphical display using the Virtual Network diff --git a/src/wok/plugins/kimchi/model/templates.py b/src/wok/plugins/kimchi/model/templates.py index 47b2c9e..bac6e47 100644 --- a/src/wok/plugins/kimchi/model/templates.py +++ b/src/wok/plugins/kimchi/model/templates.py @@ -234,8 +234,9 @@ class LibvirtVMTemplate(VMTemplate): self.conn = conn VMTemplate.__init__(self, args, scan)
- def _storage_validate(self): - pool_uri = self.info['storagepool'] + def _storage_validate(self, pool_uri=None): + if pool_uri is None: + pool_uri = self.info['storagepool'] pool_name = pool_name_from_uri(pool_uri) try: conn = self.conn.get() @@ -278,8 +279,8 @@ class LibvirtVMTemplate(VMTemplate): xml = pool.XMLDesc(0) return xpath_get_text(xml, "/pool/target/path")[0]
- def _get_storage_type(self): - pool = self._storage_validate() + def _get_storage_type(self, pool_uri=None): + pool = self._storage_validate(pool_uri) xml = pool.XMLDesc(0) return xpath_get_text(xml, "/pool/@type")[0]
diff --git a/src/wok/plugins/kimchi/osinfo.py b/src/wok/plugins/kimchi/osinfo.py index 30ecd4f..12e5b4b 100644 --- a/src/wok/plugins/kimchi/osinfo.py +++ b/src/wok/plugins/kimchi/osinfo.py @@ -158,6 +158,7 @@ def _get_tmpl_defaults(): for disk in storage_section.keys(): data = storage_section[disk] data['index'] = int(disk.split('.')[1]) + data['storagepool'] = defaults['storagepool'] defaults['disks'].append(data)
# Parse processor section to get cpus and cpu_topology values diff --git a/src/wok/plugins/kimchi/vmtemplate.py b/src/wok/plugins/kimchi/vmtemplate.py index 3097b66..35210a3 100644 --- a/src/wok/plugins/kimchi/vmtemplate.py +++ b/src/wok/plugins/kimchi/vmtemplate.py @@ -76,14 +76,21 @@ class VMTemplate(object): graphics.update(graph_args) args['graphics'] = graphics
+ # Support to create Template with multiple disks + for i, disk in enumerate(self.info['disks']): + self.info['disks'][i]['storagepooltype'] = \ + self._get_storage_type(disk['storagepool']) +
So the pool type will be also returned in the API, right?
I think I have already suggested it before, but.... Keep the data grouped, ie, for the storage pool information use a single JSON object to care about that information:
disk: {pool: {name:..., 'type':...}, index: ..., size:... }
Also update the docs/API.md to reflect the addition of 'type'
Done in previous patch
# Merge disks dict default_disk = self.info['disks'][0] for i, d in enumerate(args.get('disks', [])): disk = dict(default_disk) + disk['index'] = i disk.update(d) - + disk['storagepooltype'] = self._get_storage_type( + disk['storagepool']) # Assign right disk format to logical and [i]scsi storagepools - if self._get_storage_type() in ['logical', 'iscsi', 'scsi']: + if disk['storagepooltype'] in ['logical', 'iscsi', 'scsi']: disk['format'] = 'raw' args['disks'][i] = disk
@@ -401,7 +408,7 @@ class VMTemplate(object): def _get_storage_path(self): return ''
- def _get_storage_type(self): + def _get_storage_type(self, pool=None): return ''
def _get_volume_path(self):
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel

To avoid confusion, request is done in patchset "v4", which I have just submitted. Rodrigo Trujillo On 11/30/2015 01:34 AM, Rodrigo Trujillo wrote:
On 11/25/2015 03:40 PM, Aline Manera wrote:
On 25/11/2015 04:45, Rodrigo Trujillo wrote:
This patch fixes the backend code in order to allow create templates with multiple disks and update them correctly. Backend supports disks jsons like:
"disks": [{"size": 3, "format": "qcow"}, {"size": 5, "storagepool":"/plugins/kimchi/storagepools/poolX"}, {"size": 7, "format": "raw", "storagepool": "/plugins/kimchi/storagepools/poolY"} ]
If any information is missing, Kimchi will use values from template.conf.
Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> --- src/wok/plugins/kimchi/API.json | 19 ++++++++++++++++++- src/wok/plugins/kimchi/docs/API.md | 3 +++ src/wok/plugins/kimchi/model/templates.py | 9 +++++---- src/wok/plugins/kimchi/osinfo.py | 1 + src/wok/plugins/kimchi/vmtemplate.py | 13 ++++++++++--- 5 files changed, 37 insertions(+), 8 deletions(-)
diff --git a/src/wok/plugins/kimchi/API.json b/src/wok/plugins/kimchi/API.json index ab9ac9b..e4cabd6 100644 --- a/src/wok/plugins/kimchi/API.json +++ b/src/wok/plugins/kimchi/API.json @@ -477,6 +477,12 @@ "type": "integer", "minimum": 0 }, + "format": { + "description": "Type of the image of the disk", + "type": "string", + "pattern": "^(bochs|cloop|cow|dmg|qcow|qcow2|qed|raw|vmdk|vpc)$", + "error": "KCHTMPL0027E" + }, "size": { "description": "Size (GB) of the disk", "type": "number", @@ -488,8 +494,13 @@ "type": "string", "pattern": "^/.+$", "error": "KCHTMPL0023E" + }, + "storagepool": { + "description": "Location of the storage pool", + "type": "string", + "pattern": "^/plugins/kimchi/storagepools/[^/]+/?$", + "error": "KCHTMPL0015E" } - } }, "minItems": 1, @@ -660,6 +671,12 @@ "type": "string", "pattern": "^(bochs|cloop|cow|dmg|qcow|qcow2|qed|raw|vmdk|vpc)$", "error": "KCHTMPL0027E" + }, + "storagepool": { + "description": "Location of the storage pool", + "type": "string", + "pattern": "^/plugins/kimchi/storagepools/[^/]+/?$", + "error": "KCHTMPL0015E" } } }, diff --git a/src/wok/plugins/kimchi/docs/API.md b/src/wok/plugins/kimchi/docs/API.md index 5787755..93da547 100644 --- a/src/wok/plugins/kimchi/docs/API.md +++ b/src/wok/plugins/kimchi/docs/API.md @@ -289,6 +289,8 @@ Represents a snapshot of the Virtual Machine's primary monitor. (either *size* or *volume* must be specified): * index: The device index * size: The device size in GB + * format: Format of the image. Valid formats: bochs, cloop, cow, dmg, qcow, qcow2, qed, raw, vmdk, vpc + * storagepool: URI of the storagepool where disk will be created * base: Base image of this disk
* graphics *(optional)*: The graphics paramenters of this template @@ -422,6 +424,7 @@ A interface represents available network interface on VM. * size: The device size in GB * volume: A volume name that contains the initial disk contents * format: Format of the image. Valid formats: bochs, cloop, cow, dmg, qcow, qcow2, qed, raw, vmdk, vpc. + * storagepool: URI of the storagepool where template allocates vm disk. * graphics *(optional)*: A dict of graphics paramenters of this template * type: The type of graphics. It can be VNC or spice or None. * vnc: Graphical display using the Virtual Network diff --git a/src/wok/plugins/kimchi/model/templates.py b/src/wok/plugins/kimchi/model/templates.py index 47b2c9e..bac6e47 100644 --- a/src/wok/plugins/kimchi/model/templates.py +++ b/src/wok/plugins/kimchi/model/templates.py @@ -234,8 +234,9 @@ class LibvirtVMTemplate(VMTemplate): self.conn = conn VMTemplate.__init__(self, args, scan)
- def _storage_validate(self): - pool_uri = self.info['storagepool'] + def _storage_validate(self, pool_uri=None): + if pool_uri is None: + pool_uri = self.info['storagepool'] pool_name = pool_name_from_uri(pool_uri) try: conn = self.conn.get() @@ -278,8 +279,8 @@ class LibvirtVMTemplate(VMTemplate): xml = pool.XMLDesc(0) return xpath_get_text(xml, "/pool/target/path")[0]
- def _get_storage_type(self): - pool = self._storage_validate() + def _get_storage_type(self, pool_uri=None): + pool = self._storage_validate(pool_uri) xml = pool.XMLDesc(0) return xpath_get_text(xml, "/pool/@type")[0]
diff --git a/src/wok/plugins/kimchi/osinfo.py b/src/wok/plugins/kimchi/osinfo.py index 30ecd4f..12e5b4b 100644 --- a/src/wok/plugins/kimchi/osinfo.py +++ b/src/wok/plugins/kimchi/osinfo.py @@ -158,6 +158,7 @@ def _get_tmpl_defaults(): for disk in storage_section.keys(): data = storage_section[disk] data['index'] = int(disk.split('.')[1]) + data['storagepool'] = defaults['storagepool'] defaults['disks'].append(data)
# Parse processor section to get cpus and cpu_topology values diff --git a/src/wok/plugins/kimchi/vmtemplate.py b/src/wok/plugins/kimchi/vmtemplate.py index 3097b66..35210a3 100644 --- a/src/wok/plugins/kimchi/vmtemplate.py +++ b/src/wok/plugins/kimchi/vmtemplate.py @@ -76,14 +76,21 @@ class VMTemplate(object): graphics.update(graph_args) args['graphics'] = graphics
+ # Support to create Template with multiple disks + for i, disk in enumerate(self.info['disks']): + self.info['disks'][i]['storagepooltype'] = \ + self._get_storage_type(disk['storagepool']) +
So the pool type will be also returned in the API, right?
I think I have already suggested it before, but.... Keep the data grouped, ie, for the storage pool information use a single JSON object to care about that information:
disk: {pool: {name:..., 'type':...}, index: ..., size:... }
Also update the docs/API.md to reflect the addition of 'type'
Done in previous patch
# Merge disks dict default_disk = self.info['disks'][0] for i, d in enumerate(args.get('disks', [])): disk = dict(default_disk) + disk['index'] = i disk.update(d) - + disk['storagepooltype'] = self._get_storage_type( + disk['storagepool']) # Assign right disk format to logical and [i]scsi storagepools - if self._get_storage_type() in ['logical', 'iscsi', 'scsi']: + if disk['storagepooltype'] in ['logical', 'iscsi', 'scsi']: disk['format'] = 'raw' args['disks'][i] = disk
@@ -401,7 +408,7 @@ class VMTemplate(object): def _get_storage_path(self): return ''
- def _get_storage_type(self): + def _get_storage_type(self, pool=None): return ''
def _get_volume_path(self):
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel

- This patch implements necessary changes in frontend to allow users to edit and add extra disks to a chosen Template. - This patch also refactor the UI code in order to avoid lots of backend calls, improving performance. - Template disks data saved in objectstore have new fields: * 'size' is always recorded, even for ISCSI/SCSI types; * 'storagepooltype' is always recorded; * example: "disks":[ { "index":0, "format":"raw", "storagepooltype":"iscsi", "volume":"unit:0:0:2", "storagepool":"/plugins/kimchi/storagepools/test-iscsi", "size":7 }, { "index":1, "format":"qcow2", "storagepooltype":"dir", "storagepool":"/plugins/kimchi/storagepools/default", "size":3 } ] Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> --- .../kimchi/ui/js/src/kimchi.template_edit_main.js | 246 ++++++++++----------- .../kimchi/ui/pages/template-edit.html.tmpl | 5 +- 2 files changed, 124 insertions(+), 127 deletions(-) diff --git a/src/wok/plugins/kimchi/ui/js/src/kimchi.template_edit_main.js b/src/wok/plugins/kimchi/ui/js/src/kimchi.template_edit_main.js index 5b77892..dfe770b 100644 --- a/src/wok/plugins/kimchi/ui/js/src/kimchi.template_edit_main.js +++ b/src/wok/plugins/kimchi/ui/js/src/kimchi.template_edit_main.js @@ -22,7 +22,6 @@ kimchi.template_edit_main = function() { var origNetworks; var templateDiskSize; $('#template-name', templateEditMain).val(kimchi.selectedTemplate); - //templateEditMain.tabs(); $('#edit-template-tabs a[data-toggle="tab"]').on('shown.bs.tab', function (e) { var target = $(this).attr('href'); @@ -68,134 +67,132 @@ kimchi.template_edit_main = function() { return false; } enableSpice(); + var initStorage = function(result) { - var scsipools = {}; + // Gather storage pool data + var storagePoolsInfo = new Object(); + $.each(result, function(index, pool) { + if (pool.state === 'active' && pool.type != 'kimchi-iso') { + if (pool.type === 'iscsi' || pool.type === 'scsi') { + volumes = new Object(); + kimchi.listStorageVolumes(pool.name, function(vols) { + $.each(vols, function(i, vol) { + storagePoolsInfo[pool.name + "/" + vol.name] = { + 'type' : pool.type, + 'volSize': vol.capacity / Math.pow(1024, 3)}; + }); + }, null, true); + } else { + storagePoolsInfo[pool.name] = { 'type' : pool.type }; + } + } + }); + var addStorageItem = function(storageData) { var thisName = storageData.storageName; + // Compatibility with old versions + if (storageData.storageVolume) { + storageData.storageDisk = storagePoolsInfo[thisName].volSize; + } + if (!storageData.storageType) { + storageData.storageType = storagePoolsInfo[thisName].type; + } + var nodeStorage = $.parseHTML(wok.substitute($('#template-storage-pool-tmpl').html(), storageData)); $('.template-tab-body', '#form-template-storage').append(nodeStorage); + var storageRow = '#storageRow' + storageData.storageIndex; + var storageOptions = ''; - var scsiOptions = ''; - $('#selectStorageName').find('option').remove(); - $.each(result, function(index, storageEntities) { - if((storageEntities.state === 'active') && (storageEntities.type != 'kimchi-iso')) { - if(storageEntities.type === 'iscsi' || storageEntities.type === 'scsi') { - kimchi.listStorageVolumes(storageEntities.name, function(currentVolume) { - $.each(currentVolume, function(indexSCSI, scsiEntities) { - var tmpPath = storageEntities.name + '/' + scsiEntities.name; - var isSlected = tmpPath === thisName ? ' selected' : ''; - scsiOptions += '<option' + isSlected + '>' + tmpPath + '</option>'; - }); - $('#selectStorageName').append(scsiOptions); - }, function() {}); - } else { - var isSlected = storageEntities.name === thisName ? ' selected' : ''; - storageOptions += '<option' + isSlected + '>' + storageEntities.name + '</option>'; - } - } + $.each(storagePoolsInfo, function(poolName, value) { + storageOptions += '<option value="' + poolName + '">' + poolName + '</option>'; }); - $('#selectStorageName').append(storageOptions); - $('select','#form-template-storage').selectpicker(); + + $(storageRow + ' #selectStorageName').append(storageOptions); + $(storageRow + ' #selectStorageName').val(storageData.storageName); + $(storageRow + ' #selectStorageName').selectpicker(); + + if (storageData.storageType === 'iscsi' || storageData.storageType === 'scsi') { + $(storageRow + ' .template-storage-disk').attr('readonly', true).prop('disabled', true); + $(storageRow + ' #diskFormat').val('raw'); + $(storageRow + ' #diskFormat').prop('disabled', true).change(); + } else if (storageData.storageType === 'logical') { + $(storageRow + ' #diskFormat').val('raw'); + $(storageRow + ' #diskFormat').prop('disabled', true).change(); + } // Set disk format if (isImageBasedTemplate()) { - $('#diskFormat').val('qcow2'); - $('#diskFormat').prop('disabled', 'disabled'); + $(storageRow + ' #diskFormat').val('qcow2'); + $(storageRow + ' #diskFormat').prop('disabled', 'disabled'); } else { - $('#diskFormat').val(storageData.storageDiskFormat); - $('#diskFormat').on('change', function() { - $('.template-storage-disk-format').val($(this).val()); + $(storageRow + ' #diskFormat').val(storageData.storageDiskFormat); + $(storageRow + ' #diskFormat').on('change', function() { + $(storageRow + ' .template-storage-disk-format').val($(this).val()); }); } + $(storageRow + ' #diskFormat').selectpicker(); - $('#selectStorageName').change(function() { - var selectedItem = $(this).parent().parent(); - var tempStorageNameFull = $(this).val(); - var tempName = tempStorageNameFull.split('/'); - var tempStorageName = tempName[0]; - $('.template-storage-name').val(tempStorageNameFull); - kimchi.getStoragePool(tempStorageName, function(info) { - tempType = info.type; - selectedItem.find('.template-storage-type').val(tempType); - if (tempType === 'iscsi' || tempType === 'scsi') { - kimchi.getStoragePoolVolume(tempStorageName, tempName[tempName.length-1], function(info) { - volSize = info.capacity / Math.pow(1024, 3); - $('.template-storage-disk', selectedItem).attr('readonly', true).val(volSize); - if (!isImageBasedTemplate()) { - $('#diskFormat').val('raw'); - $('#diskFormat').prop('disabled', true).change(); - } - }); - } else if (tempType === 'logical') { - $('.template-storage-disk', selectedItem).attr('readonly', false); - if (!isImageBasedTemplate()) { - $('#diskFormat').val('raw'); - $('#diskFormat').prop('disabled', true).change(); - } - } else { - $('.template-storage-disk', selectedItem).attr('readonly', false); - if ($('#diskFormat').prop('disabled') == true && - !isImageBasedTemplate()) { - $('#diskFormat').val('qcow2'); - $('#diskFormat').prop('disabled', false).change(); - } - } - }); + $('.delete', '#form-template-storage').on( "click",function(event) { + event.preventDefault(); + $(this).parent().parent().remove(); }); - }; - - if ((origDisks && origDisks.length) && (origPool && origPool.length)) { - splitPool = origPool.split('/'); - var defaultPool = splitPool[splitPool.length-1]; - var defaultType; - kimchi.getStoragePool(defaultPool, function(info) { - defaultType = info.type; - $.each(origDisks, function(index, diskEntities) { - var storageNodeData = { - viewMode : '', - editMode : 'hide', - storageName : defaultPool, - storageType : defaultType, - storageDisk : diskEntities.size, - storageDiskFormat : diskEntities.format ? diskEntities.format : 'qcow2' + $(storageRow + ' #selectStorageName').change(function() { + var poolType = storagePoolsInfo[$(this).val()].type; + $(storageRow + ' .template-storage-name').val($(this).val()); + $(storageRow + ' .template-storage-type').val(poolType); + if (poolType === 'iscsi' || poolType === 'scsi') { + $(storageRow + ' .template-storage-disk').attr('readonly', true).prop('disabled', true).val(storagePoolsInfo[$(this).val()].volSize); + if (!isImageBasedTemplate()) { + $(storageRow + ' #diskFormat').val('raw').prop('disabled', true).change(); } - - if (diskEntities.volume) { - kimchi.getStoragePoolVolume(defaultPool, diskEntities.volume, function(info) { - var volSize = info.capacity / Math.pow(1024, 3); - var nodeData = storageNodeData - nodeData.storageName = defaultPool + '/' + diskEntities.volume; - nodeData.storageDisk = volSize; - addStorageItem(nodeData); - $('.template-storage-disk').attr('readonly', true); - $('#diskFormat').val('raw'); - $('#diskFormat').prop('disabled', true).change(); - }); - } else if (defaultType === 'logical') { - addStorageItem(storageNodeData); - $('#diskFormat').val('raw'); - $('#diskFormat').prop('disabled', true).change(); - } else { - addStorageItem(storageNodeData); + } else if (poolType === 'logical') { + $(storageRow + ' .template-storage-disk').attr('readonly', false).prop('disabled', false); + if (!isImageBasedTemplate()) { + $(storageRow + ' #diskFormat').val('raw').prop('disabled', true).change(); } - }); + } else { + $(storageRow + ' .template-storage-disk').attr('readonly', false).prop('disabled', false); + if ($(storageRow + ' #diskFormat').prop('disabled') == true && !isImageBasedTemplate()) { + $(storageRow + ' #diskFormat').val('qcow2').prop('disabled', false).change(); + } + } + $(storageRow + ' #diskFormat').selectpicker('refresh'); + }); + }; // End of addStorageItem funtion + + if ((origDisks && origDisks.length) && (origPool && origPool.length)) { + origDisks.sort(function(a, b){return a.index-b.index}); + $.each(origDisks, function(index, diskEntities) { + var defaultPool = diskEntities.storagepool ? diskEntities.storagepool.split('/').pop() : origPool.split('/').pop() + var storageNodeData = { + storageIndex : diskEntities.index, + storageName : diskEntities.volume ? defaultPool + '/' + diskEntities.volume : defaultPool, + storageType : diskEntities.storagepooltype, + storageDisk : diskEntities.size, + storageDiskFormat : diskEntities.format ? diskEntities.format : 'qcow2', + storageVolume : diskEntities.volume + } + addStorageItem(storageNodeData); }); } + var storageID = origDisks.length -1; $('#template-edit-storage-add-button').on("click", function(event) { event.preventDefault(); + storageID = storageID + 1; var storageNodeData = { - viewMode : 'hide', - editMode : '', - storageName : 'null', + storageName : 'default', storageType : 'dir', - storageDisk : '10' + storageDisk : '10', + storageDiskFormat : 'qcow2', + storageIndex : storageID } addStorageItem(storageNodeData); }); }; + var initInterface = function(result) { var networkItemNum = 0; var addInterfaceItem = function(networkData) { @@ -235,6 +232,7 @@ kimchi.template_edit_main = function() { }); }); }; + var initProcessor = function(){ var setCPUValue = function(){ if(!$('#cores').hasClass("invalid-field")&&$('#cores').val()!=""){ @@ -278,36 +276,32 @@ kimchi.template_edit_main = function() { }; kimchi.retrieveTemplate(kimchi.selectedTemplate, initTemplate); - $('#tmpl-edit-button-save').on('click', function() { - var editableFields = [ 'name', 'memory', 'disks', 'graphics']; + var editableFields = [ 'name', 'memory', 'graphics']; var data = {}; - //Fix me: Only support one storage pool now - var storages = $('.template-tab-body .item', '#form-template-storage'); - var tempName = $('.template-storage-name', storages).val(); - var tmpItem = $('#form-template-storage .item'); - tempName = tempName.split('/'); - var tempNameHead = tempName[0]; - var tempNameTail = tempNameHead; - if($('.template-storage-type', tmpItem).val() === 'iscsi' || $('.template-storage-type', tmpItem).val() == 'scsi') { - tempNameTail = tempName[tempName.length-1]; - } - tempName = '/plugins/kimchi/storagepools/' + tempNameHead; - data['storagepool'] = tempName; - $.each(editableFields, function(i, field) { - /* Support only 1 disk at this moment */ - if (field == 'disks') { - if($('.template-storage-type', tmpItem).val() === 'iscsi' || $('.template-storage-type', tmpItem).val() == 'scsi') { - origDisks[0]['size'] && delete origDisks[0]['size']; - origDisks[0]['volume'] = tempNameTail; - } else { - origDisks[0]['volume'] && delete origDisks[0]['volume']; - origDisks[0].size = Number($('.template-storage-disk', tmpItem).val()); - } - origDisks[0].format = $('.template-storage-disk-format', tmpItem).val(); - data[field] = origDisks; + var disks = $('.template-tab-body .item', '#form-template-storage'); + var disksForUpdate = new Array(); + $.each(disks, function(index, diskEntity) { + var newDisk = { + 'index' : index, + 'storagepool' : '/plugins/kimchi/storagepools/' + $(diskEntity).find('.template-storage-name').val(), + 'size' : Number($(diskEntity).find('.template-storage-disk').val()), + 'format' : $(diskEntity).find('.template-storage-disk-format').val() + }; + + var storageType = $(diskEntity).find('.template-storage-type').val(); + newDisk['storagepooltype'] = storageType; + + if(storageType === 'iscsi' || storageType === 'scsi') { + newDisk['volume'] = newDisk['storagepool'].split('/').pop(); + newDisk['storagepool'] = newDisk['storagepool'].slice(0, newDisk['storagepool'].lastIndexOf('/')); } - else if (field == 'graphics') { + disksForUpdate.push(newDisk); + }); + data.disks = disksForUpdate; + + $.each(editableFields, function(i, field) { + if (field == 'graphics') { var type = $('#form-template-general [name="' + field + '"]').val(); data[field] = {'type': type}; } diff --git a/src/wok/plugins/kimchi/ui/pages/template-edit.html.tmpl b/src/wok/plugins/kimchi/ui/pages/template-edit.html.tmpl index 59a2cfa..dc6b762 100644 --- a/src/wok/plugins/kimchi/ui/pages/template-edit.html.tmpl +++ b/src/wok/plugins/kimchi/ui/pages/template-edit.html.tmpl @@ -156,7 +156,7 @@ kimchi.template_edit_main(); </script> <script id="template-storage-pool-tmpl" type="text/html"> - <div class='item'> + <div id="storageRow{storageIndex}" class='item'> <span class="template-storage-cell storage-pool"> <input class="template-storage-name" value={storageName} type="text" style="display:none" /> <select id="selectStorageName"></select> @@ -182,6 +182,9 @@ <option value="vpc">vpc</option> </select> </span> + <span class="pull-right"> + <button class="delete btn-primary btn"><i class="fa fa-minus-circle"></i> $_("Delete")</button> + </span> </div> </script> <script id="template-interface-tmpl" type="text/html"> -- 2.1.0

This patch fixes problems in test cases after change the way Kimchi updates the disks in the Templates. Now disks have the storagepool assigned in its data. Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> --- src/wok/plugins/kimchi/tests/test_rest.py | 7 +++++- src/wok/plugins/kimchi/tests/test_template.py | 34 ++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/wok/plugins/kimchi/tests/test_rest.py b/src/wok/plugins/kimchi/tests/test_rest.py index 544f2e6..2aabbc0 100644 --- a/src/wok/plugins/kimchi/tests/test_rest.py +++ b/src/wok/plugins/kimchi/tests/test_rest.py @@ -33,7 +33,7 @@ from tests.utils import run_server, wait_task from wok.rollbackcontext import RollbackContext from wok.utils import add_task -from wok.plugins.kimchi import mockmodel +from wok.plugins.kimchi import mockmodel, osinfo from wok.plugins.kimchi.osinfo import get_template_default import iso_gen @@ -47,6 +47,9 @@ ssl_port = None cherrypy_port = None fake_iso = '/tmp/fake.iso' +# Set default test pool, as it is used and checked in every template creation +osinfo.defaults['disks'][0]['storagepool'] = \ + '/plugins/kimchi/storagepools/default-pool' def setUpModule(): global test_server, model, host, port, ssl_port, cherrypy_port @@ -220,6 +223,8 @@ class RestTests(unittest.TestCase): vm = json.loads( self.request('/plugins/kimchi/vms/∨м-црdαtеd', req).read() ) + # Memory was hot plugged + params['memory'] += 1024 for key in params.keys(): self.assertEquals(params[key], vm[key]) diff --git a/src/wok/plugins/kimchi/tests/test_template.py b/src/wok/plugins/kimchi/tests/test_template.py index 5e89d22..af6352d 100644 --- a/src/wok/plugins/kimchi/tests/test_template.py +++ b/src/wok/plugins/kimchi/tests/test_template.py @@ -38,6 +38,11 @@ ssl_port = None cherrypy_port = None +DEFAULT_POOL = '/plugins/kimchi/storagepools/default-pool' +# Set default test pool, as it is used and checked in every template creation +osinfo.defaults['disks'][0]['storagepool'] = DEFAULT_POOL + + def setUpModule(): global test_server, model, host, port, ssl_port, cherrypy_port @@ -89,6 +94,10 @@ class TemplateTests(unittest.TestCase): ) self.assertEquals(sorted(tmpl.keys()), sorted(keys)) + disk_keys = ['index', 'storagepool', 'storagepooltype', 'size', + 'format'] + self.assertEquals(sorted(tmpl['disks'][0].keys()), sorted(disk_keys)) + # Verify if default disk format was configured default_disk_format = osinfo.defaults['disks'][0]['format'] self.assertEquals(tmpl['disks'][0]['format'], default_disk_format) @@ -212,8 +221,10 @@ class TemplateTests(unittest.TestCase): self.assertEquals(update_tmpl['cdrom'], cdrom_data['cdrom']) # Update disks - disk_data = {'disks': [{'index': 0, 'size': 10, 'format': 'raw'}, - {'index': 1, 'size': 20, 'format': 'raw'}]} + disk_data = {'disks': [{'index': 0, 'size': 10, 'format': 'raw', + 'storagepool': DEFAULT_POOL, 'storagepooltype': 'dir'}, + {'index': 1, 'size': 20, 'format': 'raw', + 'storagepool': DEFAULT_POOL, 'storagepooltype': 'dir'}]} resp = self.request(new_tmpl_uri, json.dumps(disk_data), 'PUT') self.assertEquals(200, resp.status) resp = self.request(new_tmpl_uri) @@ -227,7 +238,8 @@ class TemplateTests(unittest.TestCase): 'qed', 'raw', 'vmdk', 'vpc'] for disk_type in disk_types: disk_data = {'disks': [{'index': 0, 'format': disk_type, - 'size': 10}]} + 'size': 10, 'storagepool': DEFAULT_POOL, + 'storagepooltype': 'dir'}]} resp = self.request(new_tmpl_uri, json.dumps(disk_data), 'PUT') self.assertEquals(200, resp.status) @@ -346,6 +358,22 @@ class TemplateTests(unittest.TestCase): 'PUT') self.assertEquals(200, resp.status) + # Test disl template update with different pool + disk_data = {'disks': [{'size': 5, 'format': 'qcow2', + 'storagepool': u'/plugins/kimchi/storagepools/kīмсhīUnitTestDirPool', + }]} + req = json.dumps(disk_data) + resp = self.request('/plugins/kimchi/templates/test', req, 'PUT') + self.assertEquals(200, resp.status) + disk_data['disks'][0]['index'] = 0 + disk_data['disks'][0]['storagepooltype'] = 'dir' + tmpl = json.loads( + self.request('/plugins/kimchi/templates/test').read()) + self.assertEquals(sorted(disk_data['disks'][0].keys()), + sorted(tmpl['disks'][0].keys())) + self.assertEquals(sorted(disk_data['disks'][0].values()), + sorted(tmpl['disks'][0].values())) + def test_tmpl_integrity(self): # Create a network and a pool for testing template integrity net = {'name': u'nat-network', 'connection': 'nat'} -- 2.1.0

Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> --- src/wok/plugins/kimchi/model/vms.py | 6 +++--- src/wok/plugins/kimchi/tests/test_rest.py | 3 ++- src/wok/plugins/kimchi/tests/test_template.py | 14 ++++++++------ src/wok/plugins/kimchi/vmtemplate.py | 4 ++-- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/wok/plugins/kimchi/model/vms.py b/src/wok/plugins/kimchi/model/vms.py index 7e12b91..366f1b4 100644 --- a/src/wok/plugins/kimchi/model/vms.py +++ b/src/wok/plugins/kimchi/model/vms.py @@ -1520,9 +1520,9 @@ class VMModel(object): def migration_pre_check(self, remote_host, user, password): self._check_if_host_not_localhost(remote_host) self._check_if_password_less_login_enabled( - remote_host, - user, - password + remote_host, + user, + password ) self._check_if_migrating_same_arch_hypervisor(remote_host, user) diff --git a/src/wok/plugins/kimchi/tests/test_rest.py b/src/wok/plugins/kimchi/tests/test_rest.py index 2aabbc0..592162e 100644 --- a/src/wok/plugins/kimchi/tests/test_rest.py +++ b/src/wok/plugins/kimchi/tests/test_rest.py @@ -49,7 +49,8 @@ fake_iso = '/tmp/fake.iso' # Set default test pool, as it is used and checked in every template creation osinfo.defaults['disks'][0]['storagepool'] = \ - '/plugins/kimchi/storagepools/default-pool' + '/plugins/kimchi/storagepools/default-pool' + def setUpModule(): global test_server, model, host, port, ssl_port, cherrypy_port diff --git a/src/wok/plugins/kimchi/tests/test_template.py b/src/wok/plugins/kimchi/tests/test_template.py index af6352d..e128267 100644 --- a/src/wok/plugins/kimchi/tests/test_template.py +++ b/src/wok/plugins/kimchi/tests/test_template.py @@ -222,9 +222,11 @@ class TemplateTests(unittest.TestCase): # Update disks disk_data = {'disks': [{'index': 0, 'size': 10, 'format': 'raw', - 'storagepool': DEFAULT_POOL, 'storagepooltype': 'dir'}, + 'storagepool': DEFAULT_POOL, + 'storagepooltype': 'dir'}, {'index': 1, 'size': 20, 'format': 'raw', - 'storagepool': DEFAULT_POOL, 'storagepooltype': 'dir'}]} + 'storagepool': DEFAULT_POOL, + 'storagepooltype': 'dir'}]} resp = self.request(new_tmpl_uri, json.dumps(disk_data), 'PUT') self.assertEquals(200, resp.status) resp = self.request(new_tmpl_uri) @@ -238,8 +240,8 @@ class TemplateTests(unittest.TestCase): 'qed', 'raw', 'vmdk', 'vpc'] for disk_type in disk_types: disk_data = {'disks': [{'index': 0, 'format': disk_type, - 'size': 10, 'storagepool': DEFAULT_POOL, - 'storagepooltype': 'dir'}]} + 'size': 10, 'storagepool': DEFAULT_POOL, + 'storagepooltype': 'dir'}]} resp = self.request(new_tmpl_uri, json.dumps(disk_data), 'PUT') self.assertEquals(200, resp.status) @@ -359,9 +361,9 @@ class TemplateTests(unittest.TestCase): self.assertEquals(200, resp.status) # Test disl template update with different pool + pool_uri = u'/plugins/kimchi/storagepools/kīмсhīUnitTestDirPool' disk_data = {'disks': [{'size': 5, 'format': 'qcow2', - 'storagepool': u'/plugins/kimchi/storagepools/kīмсhīUnitTestDirPool', - }]} + 'storagepool': pool_uri}]} req = json.dumps(disk_data) resp = self.request('/plugins/kimchi/templates/test', req, 'PUT') self.assertEquals(200, resp.status) diff --git a/src/wok/plugins/kimchi/vmtemplate.py b/src/wok/plugins/kimchi/vmtemplate.py index 35210a3..746ed2f 100644 --- a/src/wok/plugins/kimchi/vmtemplate.py +++ b/src/wok/plugins/kimchi/vmtemplate.py @@ -79,7 +79,7 @@ class VMTemplate(object): # Support to create Template with multiple disks for i, disk in enumerate(self.info['disks']): self.info['disks'][i]['storagepooltype'] = \ - self._get_storage_type(disk['storagepool']) + self._get_storage_type(disk['storagepool']) # Merge disks dict default_disk = self.info['disks'][0] @@ -88,7 +88,7 @@ class VMTemplate(object): disk['index'] = i disk.update(d) disk['storagepooltype'] = self._get_storage_type( - disk['storagepool']) + disk['storagepool']) # Assign right disk format to logical and [i]scsi storagepools if disk['storagepooltype'] in ['logical', 'iscsi', 'scsi']: disk['format'] = 'raw' -- 2.1.0
participants (2)
-
Aline Manera
-
Rodrigo Trujillo