예제 #1
0
파일: utils.py 프로젝트: openstack/iotronic
def mkfs(fs, path, label=None):
    """Format a file or block device

    :param fs: Filesystem type (examples include 'swap', 'ext3', 'ext4'
               'btrfs', etc.)
    :param path: Path to file or block device to format
    :param label: Volume label to use
    """
    if fs == 'swap':
        args = ['mkswap']
    else:
        args = ['mkfs', '-t', fs]
    # add -F to force no interactive execute on non-block device.
    if fs in ('ext3', 'ext4'):
        args.extend(['-F'])
    if label:
        if fs in ('msdos', 'vfat'):
            label_opt = '-n'
        else:
            label_opt = '-L'
        args.extend([label_opt, label])
    args.append(path)
    try:
        execute(*args, run_as_root=True, use_standard_locale=True)
    except processutils.ProcessExecutionError as e:
        with excutils.save_and_reraise_exception() as ctx:
            if os.strerror(errno.ENOENT) in e.stderr:
                ctx.reraise = False
                LOG.exception(_LE('Failed to make file system. '
                                  'File system %s is not supported.'), fs)
                raise exception.FileSystemNotSupported(fs=fs)
            else:
                LOG.exception(_LE('Failed to create a file system '
                                  'in %(path)s. Error: %(error)s'),
                              {'path': path, 'error': e})
예제 #2
0
def _mount_deploy_iso(deploy_iso, mountdir):
    """This function opens up the deploy iso used for deploy.

    :param: deploy_iso: path to the deploy iso where its
                        contents are fetched to.
    :raises: ImageCreationFailed if mount fails.
    :returns: a tuple consisting of - 1. a dictionary containing
                                         the values as required
                                         by create_isolinux_image,
                                      2. efiboot.img relative path, and
                                      3. grub.cfg relative path.

    """
    e_img_rel_path = None
    e_img_path = None
    grub_rel_path = None
    grub_path = None

    try:
        utils.mount(deploy_iso, mountdir, '-o', 'loop')
    except processutils.ProcessExecutionError as e:
        LOG.exception(_LE("mounting the deploy iso failed."))
        raise exception.ImageCreationFailed(image_type='iso', error=e)

    try:
        for (dir, subdir, files) in os.walk(mountdir):
            if 'efiboot.img' in files:
                e_img_path = os.path.join(dir, 'efiboot.img')
                e_img_rel_path = os.path.relpath(e_img_path,
                                                 mountdir)
            if 'grub.cfg' in files:
                grub_path = os.path.join(dir, 'grub.cfg')
                grub_rel_path = os.path.relpath(grub_path,
                                                mountdir)
    except (OSError, IOError) as e:
        LOG.exception(_LE("examining the deploy iso failed."))
        _umount_without_raise(mountdir)
        raise exception.ImageCreationFailed(image_type='iso', error=e)

    # check if the variables are assigned some values or not during
    # walk of the mountdir.
    if not (e_img_path and e_img_rel_path and grub_path and grub_rel_path):
        error = (_("Deploy iso didn't contain efiboot.img or grub.cfg"))
        _umount_without_raise(mountdir)
        raise exception.ImageCreationFailed(image_type='iso', error=error)

    uefi_path_info = {e_img_path: e_img_rel_path,
                      grub_path: grub_rel_path}

    # Returning a tuple as it makes the code simpler and clean.
    # uefi_path_info: is needed by the caller for _create_root_fs to create
    # appropriate directory structures for uefi boot iso.
    # grub_rel_path: is needed to copy the new grub.cfg generated using
    # generate_cfg() to the same directory path structure where it was
    # present in deploy iso. This path varies for different OS vendors.
    # e_img_rel_path: is required by mkisofs to generate boot iso.
    return uefi_path_info, e_img_rel_path, grub_rel_path
예제 #3
0
def create_isolinux_image_for_bios(output_file, kernel, ramdisk,
                                   kernel_params=None):
    """Creates an isolinux image on the specified file.

    Copies the provided kernel, ramdisk to a directory, generates the isolinux
    configuration file using the kernel parameters provided, and then generates
    a bootable ISO image.

    :param output_file: the path to the file where the iso image needs to be
        created.
    :param kernel: the kernel to use.
    :param ramdisk: the ramdisk to use.
    :param kernel_params: a list of strings(each element being a string like
        'K=V' or 'K' or combination of them like 'K1=V1,K2,...') to be added
        as the kernel cmdline.
    :raises: ImageCreationFailed, if image creation failed while copying files
        or while running command to generate iso.
    """
    ISOLINUX_BIN = 'isolinux/isolinux.bin'
    ISOLINUX_CFG = 'isolinux/isolinux.cfg'

    options = {'kernel': '/vmlinuz', 'ramdisk': '/initrd'}

    with utils.tempdir() as tmpdir:
        files_info = {
            kernel: 'vmlinuz',
            ramdisk: 'initrd',
            CONF.isolinux_bin: ISOLINUX_BIN,
        }
        try:
            _create_root_fs(tmpdir, files_info)
        except (OSError, IOError) as e:
            LOG.exception(_LE("Creating the filesystem root failed."))
            raise exception.ImageCreationFailed(image_type='iso', error=e)

        cfg = _generate_cfg(kernel_params,
                            CONF.isolinux_config_template, options)

        isolinux_cfg = os.path.join(tmpdir, ISOLINUX_CFG)
        utils.write_to_file(isolinux_cfg, cfg)

        try:
            utils.execute('mkisofs', '-r', '-V', "VMEDIA_BOOT_ISO",
                          '-cache-inodes', '-J', '-l', '-no-emul-boot',
                          '-boot-load-size', '4', '-boot-info-table',
                          '-b', ISOLINUX_BIN, '-o', output_file, tmpdir)
        except processutils.ProcessExecutionError as e:
            LOG.exception(_LE("Creating ISO image failed."))
            raise exception.ImageCreationFailed(image_type='iso', error=e)
예제 #4
0
    def __init__(self, message=None, **kwargs):
        self.kwargs = kwargs

        if 'code' not in self.kwargs:
            try:
                self.kwargs['code'] = self.code
            except AttributeError:
                pass

        if not message:
            try:
                message = self.message % kwargs

            except Exception as e:
                # kwargs doesn't match a variable in the message
                # log the issue and the kwargs
                LOG.exception(_LE('Exception in string format operation'))
                for name, value in kwargs.items():
                    LOG.error("%s: %s" % (name, value))

                if CONF.fatal_exception_format_errors:
                    raise e
                else:
                    # at least get the core message out if something happened
                    message = self.message

        super(IotronicException, self).__init__(message)
예제 #5
0
    def obj_class_from_name(cls, objname, objver):
        """Returns a class from the registry based on a name and version."""
        if objname not in cls._obj_classes:
            LOG.error(
                _LE('Unable to instantiate unregistered object type '
                    '%(objtype)s'), dict(objtype=objname))
            raise exception.UnsupportedObjectError(objtype=objname)

        latest = None
        compatible_match = None
        for objclass in cls._obj_classes[objname]:
            if objclass.VERSION == objver:
                return objclass

            version_bits = tuple([int(x) for x in objclass.VERSION.split(".")])
            if latest is None:
                latest = version_bits
            elif latest < version_bits:
                latest = version_bits

            if versionutils.is_compatible(objver, objclass.VERSION):
                compatible_match = objclass

        if compatible_match:
            return compatible_match

        latest_ver = '%i.%i' % latest
        raise exception.IncompatibleObjectVersion(objname=objname,
                                                  objver=objver,
                                                  supported=latest_ver)
예제 #6
0
    def __init__(self, message=None, **kwargs):
        self.kwargs = kwargs

        if 'code' not in self.kwargs:
            try:
                self.kwargs['code'] = self.code
            except AttributeError:
                pass

        if not message:
            try:
                message = self.message % kwargs

            except Exception as e:
                # kwargs doesn't match a variable in the message
                # log the issue and the kwargs
                LOG.exception(_LE('Exception in string format operation'))
                for name, value in kwargs.items():
                    LOG.error("%s: %s" % (name, value))

                if CONF.fatal_exception_format_errors:
                    raise e
                else:
                    # at least get the core message out if something happened
                    message = self.message

        super(IotronicException, self).__init__(message)
예제 #7
0
파일: base.py 프로젝트: openstack/iotronic
    def obj_class_from_name(cls, objname, objver):
        """Returns a class from the registry based on a name and version."""
        if objname not in cls._obj_classes:
            LOG.error(_LE('Unable to instantiate unregistered object type '
                          '%(objtype)s'), dict(objtype=objname))
            raise exception.UnsupportedObjectError(objtype=objname)

        latest = None
        compatible_match = None
        for objclass in cls._obj_classes[objname]:
            if objclass.VERSION == objver:
                return objclass

            version_bits = tuple([int(x) for x in objclass.VERSION.split(".")])
            if latest is None:
                latest = version_bits
            elif latest < version_bits:
                latest = version_bits

            if versionutils.is_compatible(objver, objclass.VERSION):
                compatible_match = objclass

        if compatible_match:
            return compatible_match

        latest_ver = '%i.%i' % latest
        raise exception.IncompatibleObjectVersion(objname=objname,
                                                  objver=objver,
                                                  supported=latest_ver)
예제 #8
0
def create_vfat_image(output_file, files_info=None, parameters=None,
                      parameters_file='parameters.txt', fs_size_kib=100):
    """Creates the fat fs image on the desired file.

    This method copies the given files to a root directory (optional),
    writes the parameters specified to the parameters file within the
    root directory (optional), and then creates a vfat image of the root
    directory.

    :param output_file: The path to the file where the fat fs image needs
        to be created.
    :param files_info: A dict containing absolute path of file to be copied
        -> relative path within the vfat image. For example,
        {
         '/absolute/path/to/file' -> 'relative/path/within/root'
         ...
        }
    :param parameters: A dict containing key-value pairs of parameters.
    :param parameters_file: The filename for the parameters file.
    :param fs_size_kib: size of the vfat filesystem in KiB.
    :raises: ImageCreationFailed, if image creation failed while doing any
        of filesystem manipulation activities like creating dirs, mounting,
        creating filesystem, copying files, etc.
    """
    try:
        utils.dd('/dev/zero', output_file, 'count=1', "bs=%dKiB" % fs_size_kib)
    except processutils.ProcessExecutionError as e:
        raise exception.ImageCreationFailed(image_type='vfat', error=e)

    with utils.tempdir() as tmpdir:

        try:
            # The label helps ramdisks to find the partition containing
            # the parameters (by using /dev/disk/by-label/ir-vfd-dev).
            # NOTE: FAT filesystem label can be up to 11 characters long.
            utils.mkfs('vfat', output_file, label="ir-vfd-dev")
            utils.mount(output_file, tmpdir, '-o', 'umask=0')
        except processutils.ProcessExecutionError as e:
            raise exception.ImageCreationFailed(image_type='vfat', error=e)

        try:
            if files_info:
                _create_root_fs(tmpdir, files_info)

            if parameters:
                parameters_file = os.path.join(tmpdir, parameters_file)
                params_list = ['%(key)s=%(val)s' % {'key': k, 'val': v}
                               for k, v in parameters.items()]
                file_contents = '\n'.join(params_list)
                utils.write_to_file(parameters_file, file_contents)

        except Exception as e:
            LOG.exception(_LE("vfat image creation failed. Error: %s"), e)
            raise exception.ImageCreationFailed(image_type='vfat', error=e)

        finally:
            try:
                utils.umount(tmpdir)
            except processutils.ProcessExecutionError as e:
                raise exception.ImageCreationFailed(image_type='vfat', error=e)
예제 #9
0
 def setter(self, value, name=name, typefn=typefn):
     self._changed_fields.add(name)
     try:
         return setattr(self, get_attrname(name), typefn(value))
     except Exception:
         attr = "%s.%s" % (self.obj_name(), name)
         LOG.exception(_LE('Error setting %(attr)s'), {'attr': attr})
         raise
예제 #10
0
    def stop(self):
        try:
            self.rpcserver.stop()
            self.rpcserver.wait()
        except Exception as e:
            LOG.exception(_LE('Service error occurred when stopping the '
                              'RPC server. Error: %s'), e)
        try:
            self.manager.del_host(deregister=self.deregister)
        except Exception as e:
            LOG.exception(_LE('Service error occurred when cleaning up '
                              'the RPC manager. Error: %s'), e)

        super(RPCService, self).stop(graceful=True)
        LOG.info(_LI('Stopped RPC server for service %(service)s on host '
                     '%(host)s.'),
                 {'service': self.topic, 'host': self.host})
예제 #11
0
    def stop(self):
        try:
            self.rpcserver.stop()
            self.rpcserver.wait()
        except Exception as e:
            LOG.exception(_LE('Service error occurred when stopping the '
                              'RPC server. Error: %s'), e)
        try:
            self.manager.del_host(deregister=self.deregister)
        except Exception as e:
            LOG.exception(_LE('Service error occurred when cleaning up '
                              'the RPC manager. Error: %s'), e)

        super(RPCService, self).stop(graceful=True)
        LOG.info(_LI('Stopped RPC server for service %(service)s on host '
                     '%(host)s.'),
                 {'service': self.topic, 'host': self.host})
예제 #12
0
파일: base.py 프로젝트: openstack/iotronic
 def setter(self, value, name=name, typefn=typefn):
     self._changed_fields.add(name)
     try:
         return setattr(self, get_attrname(name), typefn(value))
     except Exception:
         attr = "%s.%s" % (self.obj_name(), name)
         LOG.exception(_LE('Error setting %(attr)s'),
                       {'attr': attr})
         raise
예제 #13
0
    def __call__(self, environ, start_response):
        # Request for this state, modified by replace_start_response()
        # and used when an error is being reported.
        state = {}

        def replacement_start_response(status, headers, exc_info=None):
            """Overrides the default response to make errors parsable."""
            try:
                status_code = int(status.split(' ')[0])
                state['status_code'] = status_code
            except (ValueError, TypeError):  # pragma: nocover
                raise Exception(
                    _('ErrorDocumentMiddleware received an invalid '
                      'status %s') % status)
            else:
                if (state['status_code'] // 100) not in (2, 3):
                    # Remove some headers so we can replace them later
                    # when we have the full error message and can
                    # compute the length.
                    headers = [(h, v) for (h, v) in headers
                               if h not in ('Content-Length', 'Content-Type')]
                # Save the headers in case we need to modify them.
                state['headers'] = headers
                return start_response(status, headers, exc_info)

        app_iter = self.app(environ, replacement_start_response)
        if (state['status_code'] // 100) not in (2, 3):
            req = webob.Request(environ)
            if (req.accept.best_match(['application/json', 'application/xml'
                                       ]) == 'application/xml'):
                try:
                    # simple check xml is valid
                    body = [
                        et.ElementTree.tostring(
                            et.ElementTree.fromstring('<error_message>' +
                                                      '\n'.join(app_iter) +
                                                      '</error_message>'))
                    ]
                except et.ElementTree.ParseError as err:
                    LOG.error(_LE('Error parsing HTTP response: %s'), err)
                    body = [
                        '<error_message>%s' % state['status_code'] +
                        '</error_message>'
                    ]
                state['headers'].append(('Content-Type', 'application/xml'))
            else:
                if six.PY3:
                    app_iter = [i.decode('utf-8') for i in app_iter]
                body = [json.dumps({'error_message': '\n'.join(app_iter)})]
                if six.PY3:
                    body = [item.encode('utf-8') for item in body]
                state['headers'].append(('Content-Type', 'application/json'))
            state['headers'].append(('Content-Length', str(len(body[0]))))
        else:
            body = app_iter
        return body
예제 #14
0
def tempdir(**kwargs):
    tempfile.tempdir = CONF.tempdir
    tmpdir = tempfile.mkdtemp(**kwargs)
    try:
        yield tmpdir
    finally:
        try:
            shutil.rmtree(tmpdir)
        except OSError as e:
            LOG.error(_LE('Could not remove tmpdir: %s'), e)
예제 #15
0
파일: utils.py 프로젝트: openstack/iotronic
def tempdir(**kwargs):
    tempfile.tempdir = CONF.tempdir
    tmpdir = tempfile.mkdtemp(**kwargs)
    try:
        yield tmpdir
    finally:
        try:
            shutil.rmtree(tmpdir)
        except OSError as e:
            LOG.error(_LE('Could not remove tmpdir: %s'), e)
예제 #16
0
    def __call__(self, environ, start_response):
        # Request for this state, modified by replace_start_response()
        # and used when an error is being reported.
        state = {}

        def replacement_start_response(status, headers, exc_info=None):
            """Overrides the default response to make errors parsable."""
            try:
                status_code = int(status.split(' ')[0])
                state['status_code'] = status_code
            except (ValueError, TypeError):  # pragma: nocover
                raise Exception(_(
                    'ErrorDocumentMiddleware received an invalid '
                    'status %s') % status)
            else:
                if (state['status_code'] // 100) not in (2, 3):
                    # Remove some headers so we can replace them later
                    # when we have the full error message and can
                    # compute the length.
                    headers = [(h, v)
                               for (h, v) in headers
                               if h not in ('Content-Length', 'Content-Type')
                               ]
                # Save the headers in case we need to modify them.
                state['headers'] = headers
                return start_response(status, headers, exc_info)

        app_iter = self.app(environ, replacement_start_response)
        if (state['status_code'] // 100) not in (2, 3):
            req = webob.Request(environ)
            if (req.accept.best_match(
                    ['application/json',
                     'application/xml']) == 'application/xml'):
                try:
                    # simple check xml is valid
                    body = [et.ElementTree.tostring(
                        et.ElementTree.fromstring('<error_message>'
                                                  + '\n'.join(app_iter)
                                                  + '</error_message>'))]
                except et.ElementTree.ParseError as err:
                    LOG.error(_LE('Error parsing HTTP response: %s'), err)
                    body = ['<error_message>%s' % state['status_code']
                            + '</error_message>']
                state['headers'].append(('Content-Type', 'application/xml'))
            else:
                if six.PY3:
                    app_iter = [i.decode('utf-8') for i in app_iter]
                body = [json.dumps({'error_message': '\n'.join(app_iter)})]
                if six.PY3:
                    body = [item.encode('utf-8') for item in body]
                state['headers'].append(('Content-Type', 'application/json'))
            state['headers'].append(('Content-Length', str(len(body[0]))))
        else:
            body = app_iter
        return body
예제 #17
0
def mkfs(fs, path, label=None):
    """Format a file or block device

    :param fs: Filesystem type (examples include 'swap', 'ext3', 'ext4'
               'btrfs', etc.)
    :param path: Path to file or block device to format
    :param label: Volume label to use
    """
    if fs == 'swap':
        args = ['mkswap']
    else:
        args = ['mkfs', '-t', fs]
    # add -F to force no interactive execute on non-block device.
    if fs in ('ext3', 'ext4'):
        args.extend(['-F'])
    if label:
        if fs in ('msdos', 'vfat'):
            label_opt = '-n'
        else:
            label_opt = '-L'
        args.extend([label_opt, label])
    args.append(path)
    try:
        execute(*args, run_as_root=True, use_standard_locale=True)
    except processutils.ProcessExecutionError as e:
        with excutils.save_and_reraise_exception() as ctx:
            if os.strerror(errno.ENOENT) in e.stderr:
                ctx.reraise = False
                LOG.exception(
                    _LE('Failed to make file system. '
                        'File system %s is not supported.'), fs)
                raise exception.FileSystemNotSupported(fs=fs)
            else:
                LOG.exception(
                    _LE('Failed to create a file system '
                        'in %(path)s. Error: %(error)s'), {
                            'path': path,
                            'error': e
                        })
예제 #18
0
    def call(self, method, *args, **kwargs):
        """Call a glance client method.

        If we get a connection error,
        retry the request according to CONF.glance_num_retries.

        :param context: The request context, for access checks.
        :param version: The requested API version.v
        :param method: The method requested to be called.
        :param args: A list of positional arguments for the method called
        :param kwargs: A dict of keyword arguments for the method called

        :raises: GlanceConnectionFailed
        """
        retry_excs = (glance_exc.ServiceUnavailable,
                      glance_exc.InvalidEndpoint,
                      glance_exc.CommunicationError)
        image_excs = (glance_exc.Forbidden,
                      glance_exc.Unauthorized,
                      glance_exc.NotFound,
                      glance_exc.BadRequest)
        num_attempts = 1 + CONF.glance.glance_num_retries

        for attempt in range(1, num_attempts + 1):
            try:
                return getattr(self.client.images, method)(*args, **kwargs)
            except retry_excs as e:
                host = self.glance_host
                port = self.glance_port
                error_msg = _LE("Error contacting glance server "
                                "'%(host)s:%(port)s' for '%(method)s', attempt"
                                " %(attempt)s of %(num_attempts)s failed.")
                LOG.exception(error_msg, {'host': host,
                                          'port': port,
                                          'num_attempts': num_attempts,
                                          'attempt': attempt,
                                          'method': method})
                if attempt == num_attempts:
                    raise exception.GlanceConnectionFailed(host=host,
                                                           port=port,
                                                           reason=str(e))
                time.sleep(1)
            except image_excs as e:
                exc_type, exc_value, exc_trace = sys.exc_info()
                if method == 'list':
                    new_exc = _translate_plain_exception(
                        exc_value)
                else:
                    new_exc = _translate_image_exception(
                        args[0], exc_value)
                six.reraise(type(new_exc), new_exc, exc_trace)
예제 #19
0
def create_isolinux_image_for_uefi(output_file, deploy_iso, kernel, ramdisk,
                                   kernel_params=None):
    """Creates an isolinux image on the specified file.

    Copies the provided kernel, ramdisk, efiboot.img to a directory, creates
    the path for grub config file, generates the isolinux configuration file
    using the kernel parameters provided, generates the grub configuration
    file using kernel parameters and then generates a bootable ISO image
    for uefi.

    :param output_file: the path to the file where the iso image needs to be
        created.
    :param deploy_iso: deploy iso used to initiate the deploy.
    :param kernel: the kernel to use.
    :param ramdisk: the ramdisk to use.
    :param kernel_params: a list of strings(each element being a string like
        'K=V' or 'K' or combination of them like 'K1=V1,K2,...') to be added
        as the kernel cmdline.
    :raises: ImageCreationFailed, if image creation failed while copying files
        or while running command to generate iso.
    """
    ISOLINUX_BIN = 'isolinux/isolinux.bin'
    ISOLINUX_CFG = 'isolinux/isolinux.cfg'

    isolinux_options = {'kernel': '/vmlinuz', 'ramdisk': '/initrd'}
    grub_options = {'linux': '/vmlinuz', 'initrd': '/initrd'}

    with utils.tempdir() as tmpdir:
        files_info = {
            kernel: 'vmlinuz',
            ramdisk: 'initrd',
            CONF.isolinux_bin: ISOLINUX_BIN,
        }

        # Open the deploy iso used to initiate deploy and copy the
        # efiboot.img i.e. boot loader to the current temporary
        # directory.
        with utils.tempdir() as mountdir:
            uefi_path_info, e_img_rel_path, grub_rel_path = (
                _mount_deploy_iso(deploy_iso, mountdir))

            # if either of these variables are not initialized then the
            # uefi efiboot.img cannot be created.
            files_info.update(uefi_path_info)
            try:
                _create_root_fs(tmpdir, files_info)
            except (OSError, IOError) as e:
                LOG.exception(_LE("Creating the filesystem root failed."))
                raise exception.ImageCreationFailed(image_type='iso', error=e)
            finally:
                _umount_without_raise(mountdir)

        cfg = _generate_cfg(kernel_params,
                            CONF.isolinux_config_template, isolinux_options)

        isolinux_cfg = os.path.join(tmpdir, ISOLINUX_CFG)
        utils.write_to_file(isolinux_cfg, cfg)

        # Generate and copy grub config file.
        grub_cfg = os.path.join(tmpdir, grub_rel_path)
        grub_conf = _generate_cfg(kernel_params,
                                  CONF.grub_config_template, grub_options)
        utils.write_to_file(grub_cfg, grub_conf)

        # Create the boot_iso.
        try:
            utils.execute('mkisofs', '-r', '-V', "VMEDIA_BOOT_ISO",
                          '-cache-inodes', '-J', '-l', '-no-emul-boot',
                          '-boot-load-size', '4', '-boot-info-table',
                          '-b', ISOLINUX_BIN, '-eltorito-alt-boot',
                          '-e', e_img_rel_path, '-no-emul-boot',
                          '-o', output_file, tmpdir)
        except processutils.ProcessExecutionError as e:
            LOG.exception(_LE("Creating ISO image failed."))
            raise exception.ImageCreationFailed(image_type='iso', error=e)