
This patch fixes the backend code in order to allow create templates with multiple disks and update them correctly. Backend supports adding multiple disks with a json like: "disks": [{"size": 3, "format": "qcow"}, {"size": 5, "pool": {"name": "/plugins/kimchi/storagepools/poolX"}}, {"size": 7, "format": "raw", "pool": {"name": "/plugins/kimchi/storagepools/poolY"}} ] If any information is missing, Kimchi will use values from template.conf. Kimchi will expose template disk data like: "disks": [{"index" : ... , "size" : ... , "format" : ... , "pool" : { "name" : ... , "type" : ... } , }, ... ] Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> --- API.json | 31 ++++++++++++++++++++++++++++++- docs/API.md | 8 ++++++++ model/templates.py | 9 +++++---- osinfo.py | 14 +++++++------- template.conf | 7 ++++--- vmtemplate.py | 26 +++++++++++++++++++++----- 6 files changed, 75 insertions(+), 20 deletions(-) diff --git a/API.json b/src/wok/plugins/kimchi/API.json index 7addfc7..265ae36 100644 --- a/API.json +++ b/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,19 @@ "type": "string", "pattern": "^/.+$", "error": "KCHTMPL0023E" + }, + "pool": { + "description": "Storage pool information", + "type": "object", + "properties": { + "name": { + "description": "Location (URI) of the storage pool", + "type": "string", + "pattern": "^/plugins/kimchi/storagepools/[^/]+/?$", + "error": "KCHTMPL0015E" + } + } } - } }, "minItems": 1, @@ -660,6 +677,18 @@ "type": "string", "pattern": "^(bochs|cloop|cow|dmg|qcow|qcow2|qed|raw|vmdk|vpc)$", "error": "KCHTMPL0027E" + }, + "pool": { + "description": "Storage pool information", + "type": "object", + "properties": { + "name": { + "description": "Location (URI) of the storage pool", + "type": "string", + "pattern": "^/plugins/kimchi/storagepools/[^/]+/?$", + "error": "KCHTMPL0015E" + } + } } } }, diff --git a/docs/API.md b/src/wok/plugins/kimchi/docs/API.md index 1e7d8ca..8ef48d6 100644 --- a/docs/API.md +++ b/docs/API.md @@ -289,6 +289,9 @@ 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 + * pool: Storage pool information + * name: URI of the storagepool where disk will be created * base: Base image of this disk * graphics *(optional)*: The graphics paramenters of this template @@ -388,6 +391,9 @@ 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. + * pool: Information about the pool where disk or volume will be created + * name: URI of the storagepool + * type: Type of the storagepool (dir, nfs, scsci, iscsi, etc) * graphics: 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 @@ -422,6 +428,8 @@ 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. + * pool: Storage pool information + * name: 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/model/templates.py b/src/wok/plugins/kimchi/model/templates.py index 47b2c9e..bac6e47 100644 --- a/model/templates.py +++ b/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/osinfo.py b/src/wok/plugins/kimchi/osinfo.py index 30ecd4f..1891398 100644 --- a/osinfo.py +++ b/osinfo.py @@ -118,8 +118,8 @@ def _get_tmpl_defaults(): The default values should be like below: {'main': {'networks': ['default'], 'memory': '1024'}, - 'storage': {'pool': 'default', - 'disk.0': {'format': 'qcow2', 'size': '10'}}, + 'storage': { 'disk.0': {'format': 'qcow2', 'size': '10', + 'pool': '/plugins/kimchi/storagepools/default'}}, 'processor': {'cpus': '1'}, 'graphics': {'type': 'spice', 'listen': '127.0.0.1'}} """ @@ -127,8 +127,8 @@ def _get_tmpl_defaults(): tmpl_defaults = defaultdict(dict) tmpl_defaults['main']['networks'] = ['default'] tmpl_defaults['main']['memory'] = _get_default_template_mem() - tmpl_defaults['storage']['pool'] = 'default' - tmpl_defaults['storage']['disk.0'] = {'size': 10, 'format': 'qcow2'} + tmpl_defaults['storage']['disk.0'] = {'size': 10, 'format': 'qcow2', + 'pool': 'default'} tmpl_defaults['processor']['cpus'] = 1 tmpl_defaults['graphics'] = {'type': 'vnc', 'listen': '127.0.0.1'} @@ -150,14 +150,14 @@ def _get_tmpl_defaults(): main_section = default_config.pop('main') defaults.update(main_section) - # Parse storage section to get storage pool and disks values + # Parse storage section to get disks values storage_section = default_config.pop('storage') - defaults['storagepool'] = '/plugins/kimchi/storagepools/' + \ - storage_section.pop('pool') defaults['disks'] = [] for disk in storage_section.keys(): data = storage_section[disk] data['index'] = int(disk.split('.')[1]) + data['pool'] = {"name": '/plugins/kimchi/storagepools/' + + storage_section[disk].pop('pool')} defaults['disks'].append(data) # Parse processor section to get cpus and cpu_topology values diff --git a/template.conf b/src/wok/plugins/kimchi/template.conf index f3615e6..37fadb8 100644 --- a/template.conf +++ b/template.conf @@ -11,11 +11,9 @@ #networks = default, [storage] -# Storage pool used to handle the guest disk -#pool = default # Specify multiple [[disk.X]] sub-sections to add multiples disks to guest -# All the disk files will be created in the same storage pool as set above +# Each disk files will be created in respective storage pool set [[disk.0]] # Disk size in GB #size = 10 @@ -23,6 +21,9 @@ # Disk format #format = qcow2 +# Storage pool used to handle the guest disk +#pool = default + [graphics] # Graphics type # Valid options: vnc | spice diff --git a/vmtemplate.py b/src/wok/plugins/kimchi/vmtemplate.py index 3097b66..c7635b0 100644 --- a/vmtemplate.py +++ b/vmtemplate.py @@ -76,14 +76,30 @@ class VMTemplate(object): graphics.update(graph_args) args['graphics'] = graphics - # Merge disks dict + # Provide compatibility with old template version and sets data to + # correct output format if necessary + def _fix_disk_compatibilities(disks): + for i, disk in enumerate(disks): + if 'pool' not in disk: + disk['pool'] = {'name': self.info['storagepool']} + if (isinstance(disk['pool'], str) or + isinstance(disk['pool'], unicode)): + disk['pool'] = {'name': disk['pool']} + disk['pool']['type'] = \ + self._get_storage_type(disk['pool']['name']) + + if self.info.get('disks') is not None: + _fix_disk_compatibilities(self.info['disks']) + if args.get('disks') is not None: + _fix_disk_compatibilities(args['disks']) + + # Merge disks dict with disks provided by user default_disk = self.info['disks'][0] for i, d in enumerate(args.get('disks', [])): disk = dict(default_disk) + disk['index'] = i disk.update(d) - - # Assign right disk format to logical and [i]scsi storagepools - if self._get_storage_type() in ['logical', 'iscsi', 'scsi']: + if disk['pool']['type'] in ['logical', 'iscsi', 'scsi']: disk['format'] = 'raw' args['disks'][i] = disk @@ -401,7 +417,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