[Kimchi-devel] [PATCH][Kimchi 4/6] Identify installation media while creating template

Aline Manera alinefm at linux.vnet.ibm.com
Wed Mar 23 20:21:43 UTC 2016



On 03/22/2016 04:20 PM, Ramon Medeiros wrote:
> First, improve functions inside class. This will improve code reading,
> also, make more functions to split procedures like: validating disks,
> graphics xml and distro checking.
>
> Add separate function to identify the installation media.
>
> Signed-off-by: Ramon Medeiros <ramonn at linux.vnet.ibm.com>
> ---
>   model/templates.py |   4 ++
>   vmtemplate.py      | 142 +++++++++++++++++++++++++++++++++++++++++++++++------
>   2 files changed, 132 insertions(+), 14 deletions(-)
>
> diff --git a/model/templates.py b/model/templates.py
> index b49ac50..a03a7cf 100644
> --- a/model/templates.py
> +++ b/model/templates.py
> @@ -196,6 +196,10 @@ class TemplateModel(object):
>               params['memory'].update(new_mem)
>               validate_memory(params['memory'])


> +        # params are cdrom or disk: add it to source_media
> +        if "cdrom" in params:
> +            params["source_media"] = params.get("cdrom")
> +

Is it 'source_media' ou 'installation_media'?

I prefer 'source_media' but if so, you need to update API.json (first 
patch) to reflect it.

Also, if the user is already using the 'cdrom' or base disk as 
parameter, why do you need to check the media type?

>           new_t.update(params)
>
>           for net_name in params.get(u'networks', []):
> diff --git a/vmtemplate.py b/vmtemplate.py
> index 4bcf324..8572dfe 100644
> --- a/vmtemplate.py
> +++ b/vmtemplate.py
> @@ -17,6 +17,7 @@
>   # License along with this library; if not, write to the Free Software
>   # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
>
> +import magic
>   import os
>   import platform
>   import stat
> @@ -29,10 +30,13 @@ from lxml.builder import E
>   from wok.exception import InvalidParameter, ImageFormatError, IsoFormatError
>   from wok.exception import MissingParameter, OperationFailed
>
> +from wok.xmlutils.utils import xpath_get_text
>   from wok.plugins.kimchi import imageinfo
>   from wok.plugins.kimchi import osinfo
>   from wok.plugins.kimchi.isoinfo import IsoImage

> +from wok.plugins.kimchi.model.libvirtconnection import LibvirtConnection

VMTemplate must be independent of Model. Instead of doing that, you 
should pass the data you want as parameter to the function.

>   from wok.plugins.kimchi.utils import check_url_path, pool_name_from_uri
> +from wok.plugins.kimchi.utils import get_template_by_name
>   from wok.plugins.kimchi.xmlutils.cpu import get_cpu_xml
>   from wok.plugins.kimchi.xmlutils.disk import get_disk_xml
>   from wok.plugins.kimchi.xmlutils.graphics import get_graphics_xml
> @@ -40,6 +44,9 @@ from wok.plugins.kimchi.xmlutils.interface import get_iface_xml
>   from wok.plugins.kimchi.xmlutils.qemucmdline import get_qemucmdline_xml
>   from wok.plugins.kimchi.xmlutils.serial import get_serial_xml
>
> +DISK_TYPE = {"QEMU QCOW Image": "qcow2",
> +             "data": "raw"}
> +ISO_TYPE = "ISO 9660 CD-ROM"
>
>   class VMTemplate(object):
>       def __init__(self, args, scan=False):
> @@ -54,20 +61,16 @@ class VMTemplate(object):
>           self.info = {}
>           self.fc_host_support = args.get('fc_host_support')
>
> -        # Fetch defaults based on the os distro and version
> -        try:
> -            distro, version = self._get_os_info(args, scan)
> -        except ImageFormatError as e:
> -            raise OperationFailed('KCHTMPL0020E', {'err': e.message})
> -        os_distro = args.get('os_distro', distro)
> -        os_version = args.get('os_version', version)
> -        entry = osinfo.lookup(os_distro, os_version)
> -        self.info.update(entry)

> +        # search for template with the same name
> +        template = get_template_by_name(args.get("name"))

You are mixing the Template resource provided by model/templates.py to 
VMTemplate.
VMTemplate is a dict of information. At this point, there is no 
information stored anywhere.


I think you are doing it to do no scan the source_media multiple times, 
but for that the 'scan' parameter was used. You should continue to use it.

>
> -        # Auto-generate a template name if no one is passed
> -        if 'name' not in args or args['name'] == '':
> -            args['name'] = self._gen_name(distro, version)
> -        self.name = args['name']
> +        # no record found: create template
> +        if len(template) == 0:
> +            self._create_template(args, scan)
> +
> +        # template already exists: load it
> +        else:
> +            self.info.update(args)
>
>           # Merge graphics settings
>           graph_args = args.get('graphics')
> @@ -87,6 +90,35 @@ class VMTemplate(object):
>
>           # Override template values according to 'args'
>           self.info.update(args)
> +
> +        # validate disks
> +        self._validate_disks(default_disk)
> +
> +    def _create_template(self, args, scan=False):
> +        """
> +        Creates a new template
> +        """
> +        # identify installation media
> +        self._identify_installation_media(args)
> +
> +        # Fetch defaults based on the os distro and version
> +        try:
> +            distro, version = self._get_os_info(args, scan)
> +        except ImageFormatError as e:
> +            raise OperationFailed('KCHTMPL0020E', {'err': e.message})
> +        os_distro = args.get('os_distro', distro)
> +        os_version = args.get('os_version', version)
> +        entry = osinfo.lookup(os_distro, os_version)
> +
> +        # update info
> +        self.info.update(entry)
> +
> +        # Auto-generate a template name if no one is passed
> +        if 'name' not in args or args['name'] == '':
> +            args['name'] = self._gen_name(distro, version)
> +        self.info["name"] = args['name']
> +
> +    def _validate_disks(self, default_disk):
>           disks = self.info.get('disks')
>
>           basic_disk = ['index', 'format', 'pool', 'size']
> @@ -95,7 +127,6 @@ class VMTemplate(object):
>
>           for index, disk in enumerate(disks):
>               disk_info = dict(default_disk)
> -
>               pool_type = self._get_storage_type(disk['pool']['name'])
>               if pool_type in ['iscsi', 'scsi']:
>                   disk_info = {'index': 0, 'format': 'raw', 'volume': None}
> @@ -118,6 +149,89 @@ class VMTemplate(object):
>               disk_info['index'] = disk_info.get('index', index)
>               self.info['disks'][index] = disk_info
>
> +    def _identify_installation_media(self, args):

Why a new function is needed? Can't we only use the existing functions 
to identify an ISO or image?

> +        path = args.get("installation_media")
> +

You are mixing 'installation_media' with 'source_media'

> +        # user did not passed installation media: return
> +        if path is None:
> +            return
> +
> +        # create magic object to discover file type
> +        file_type = magic.open(magic.MAGIC_NONE)
> +        file_type.load()
> +
> +        # file is local and exists: check if it's disk or cdrom
> +        if path.startswith("/") and os.path.exists(path):
> +            ftype = file_type.file(path)
> +
> +            # cdrom
> +            if ISO_TYPE in ftype:
> +                args["cdrom"] = path
> +                return
> +
> +            # disk
> +            for types in DISK_TYPE.keys():
> +                if types in ftype:
> +
> +                    # no disk list: create it
> +                    if args.get("disks") is None:
> +                        args["disks"] = []
> +
> +                    # append disk to the list
> +                    args["disks"].insert(0,
> +                        {"base": path,
> +                         "format": DISK_TYPE[types],
> +                         "index": 0,
> +                         "pool": {"name":
> +                                  "/plugins/kimchi/storagepools/default",
> +                                  "type":"dir"}})
> +
> +                    # get storage pool
> +                    pool = self._get_storagepool_from_storagevolume(path)
> +
> +                    # image not in any pool: get default pool
> +                    if len(pool) == 0:
> +                        os_info = osinfo.lookup("unknow", "unknow")["disks"][0]["pool"]
> +
> +                        # os_info has default pool: get it
> +                        if os_info != None:
> +                            args["disks"][0]["pool"] = os_info
> +                            return
> +
> +                    # pool available
> +                    args["disks"][0]["pool"] = pool
> +

> +        # not local image: set as remote ISO
> +        elif path.startswith("http") or path.startswith("ftp"):
> +            args["cdrom"] = path
> +            return
> +

There is a function on utils.py for that - check_url_path()

> +    def _get_storagepool_from_storagevolume(self, storagevolume_path):
> +        conn = LibvirtConnection('qemu:///system').get()
> +        storagepools = conn.listStoragePools()
> +        storagepools += conn.listDefinedStoragePools()
> +
> +        # discover storagepool
> +        for storagepool in storagepools:
> +            pool = conn.storagePoolLookupByName(storagepool)
> +            spath = xpath_get_text(pool.XMLDesc(), "/pool/target/path")[0]
> +            pool_type = xpath_get_text(pool.XMLDesc(), "/pool/@type")[0]
> +            storagevolumes = sorted(map(lambda x: x.decode('utf-8'),
> +                                        pool.listVolumes()))
> +            for storagevolume in storagevolumes:
> +
> +                # path does not exists: continue to the next
> +                if not os.path.exists("%s/%s" % (spath, storagevolume)):
> +                    continue
> +
> +                # storagepool found: return
> +                volume = "%s/%s" % (spath, storagevolume)
> +                if os.path.samefile(storagevolume_path, volume):
> +                    pool_uri = "/plugins/kimchi/storagepools/%s" % storagepool
> +                    return {"name": pool_uri,
> +                            "type": pool_type}
> +        return {}
> +

All that should not be on VMTemplate.
As I said before VMTemplate is independent of Model.
Any information you want should go through Model via parameter.

>       def _get_os_info(self, args, scan):
>           distro = version = 'unknown'
>




More information about the Kimchi-devel mailing list