¡@

Home 

OpenStack Study: remotefs.py

OpenStack Index

**** CubicPower OpenStack Study ****

# Copyright (c) 2013 OpenStack Foundation

# All Rights Reserved

#

# Licensed under the Apache License, Version 2.0 (the "License"); you may

# not use this file except in compliance with the License. You may obtain

# a copy of the License at

#

# http://www.apache.org/licenses/LICENSE-2.0

#

# Unless required by applicable law or agreed to in writing, software

# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT

# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the

# License for the specific language governing permissions and limitations

# under the License.

"""Remote filesystem client utilities."""

import hashlib

import os

import re

import six

from cinder.brick import exception

from cinder.openstack.common.gettextutils import _

from cinder.openstack.common import log as logging

from cinder.openstack.common import processutils as putils

LOG = logging.getLogger(__name__)

**** CubicPower OpenStack Study ****

class RemoteFsClient(object):

**** CubicPower OpenStack Study ****

    def __init__(self, mount_type, root_helper,

                 execute=putils.execute, *args, **kwargs):

        self._mount_type = mount_type

        if mount_type == "nfs":

            self._mount_base = kwargs.get('nfs_mount_point_base', None)

            if not self._mount_base:

                raise exception.InvalidParameterValue(

                    err=_('nfs_mount_point_base required'))

            self._mount_options = kwargs.get('nfs_mount_options', None)

            self._check_nfs_options()

        elif mount_type == "glusterfs":

            self._mount_base = kwargs.get('glusterfs_mount_point_base', None)

            if not self._mount_base:

                raise exception.InvalidParameterValue(

                    err=_('glusterfs_mount_point_base required'))

            self._mount_options = None

        else:

            raise exception.ProtocolNotSupported(protocol=mount_type)

        self.root_helper = root_helper

        self.set_execute(execute)

**** CubicPower OpenStack Study ****

    def set_execute(self, execute):

        self._execute = execute

**** CubicPower OpenStack Study ****

    def _get_hash_str(self, base_str):

        """Return a string that represents hash of base_str

        (in a hex format).

        """

        return hashlib.md5(base_str).hexdigest()

**** CubicPower OpenStack Study ****

    def get_mount_point(self, device_name):

        """Get Mount Point.

        :param device_name: example 172.18.194.100:/var/nfs

        """

        return os.path.join(self._mount_base,

                            self._get_hash_str(device_name))

**** CubicPower OpenStack Study ****

    def _read_mounts(self):

        (out, err) = self._execute('mount', check_exit_code=0)

        lines = out.split('\n')

        mounts = {}

        for line in lines:

            tokens = line.split()

            if 2 < len(tokens):

                device = tokens[0]

                mnt_point = tokens[2]

                mounts[mnt_point] = device

        return mounts

**** CubicPower OpenStack Study ****

    def mount(self, share, flags=None):

        """Mount given share."""

        mount_path = self.get_mount_point(share)

        if mount_path in self._read_mounts():

            LOG.info(_('Already mounted: %s') % mount_path)

            return

        self._execute('mkdir', '-p', mount_path, check_exit_code=0)

        if self._mount_type == 'nfs':

            self._mount_nfs(share, mount_path, flags)

        else:

            self._do_mount(self._mount_type, share, mount_path,

                           self._mount_options, flags)

**** CubicPower OpenStack Study ****

    def _do_mount(self, mount_type, share, mount_path, mount_options=None,

                  flags=None):

        """Mounts share based on the specified params."""

        mnt_cmd = ['mount', '-t', mount_type]

        if mount_options is not None:

            mnt_cmd.extend(['-o', mount_options])

        if flags is not None:

            mnt_cmd.extend(flags)

        mnt_cmd.extend([share, mount_path])

        self._execute(*mnt_cmd, root_helper=self.root_helper,

                      run_as_root=True, check_exit_code=0)

**** CubicPower OpenStack Study ****

    def _mount_nfs(self, nfs_share, mount_path, flags=None):

        """Mount nfs share using present mount types."""

        mnt_errors = {}

        # This loop allows us to first try to mount with NFS 4.1 for pNFS

        # support but falls back to mount NFS 4 or NFS 3 if either the client

        # or server do not support it.

        for mnt_type in sorted(self._nfs_mount_type_opts.keys(), reverse=True):

            options = self._nfs_mount_type_opts[mnt_type]

            try:

                self._do_mount('nfs', nfs_share, mount_path, options, flags)

                LOG.debug(_('Mounted %(sh)s using %(mnt_type)s.')

                          % {'sh': nfs_share, 'mnt_type': mnt_type})

                return

            except Exception as e:

                mnt_errors[mnt_type] = six.text_type(e)

                LOG.debug(_('Failed to do %s mount.'), mnt_type)

        raise exception.BrickException(_("NFS mount failed for share %(sh)s."

                                         "Error - %(error)s")

                                       % {'sh': nfs_share,

                                          'error': mnt_errors})

**** CubicPower OpenStack Study ****

    def _check_nfs_options(self):

        """Checks and prepares nfs mount type options."""

        self._nfs_mount_type_opts = {'nfs': self._mount_options}

        nfs_vers_opt_patterns = ['^nfsvers', '^vers', '^v[\d]']

        for opt in nfs_vers_opt_patterns:

            if self._option_exists(self._mount_options, opt):

                return

        # pNFS requires NFS 4.1. The mount.nfs4 utility does not automatically

        # negotiate 4.1 support, we have to ask for it by specifying two

        # options: vers=4 and minorversion=1.

        pnfs_opts = self._update_option(self._mount_options, 'vers', '4')

        pnfs_opts = self._update_option(pnfs_opts, 'minorversion', '1')

        self._nfs_mount_type_opts['pnfs'] = pnfs_opts

**** CubicPower OpenStack Study ****

    def _option_exists(self, options, opt_pattern):

        """Checks if the option exists in nfs options and returns position."""

        options = [x.strip() for x in options.split(',')] if options else []

        pos = 0

        for opt in options:

            pos = pos + 1

            if re.match(opt_pattern, opt, flags=0):

                return pos

        return 0

**** CubicPower OpenStack Study ****

    def _update_option(self, options, option, value=None):

        """Update option if exists else adds it and returns new options."""

        opts = [x.strip() for x in options.split(',')] if options else []

        pos = self._option_exists(options, option)

        if pos:

            opts.pop(pos - 1)

        opt = '%s=%s' % (option, value) if value else option

        opts.append(opt)

        return ",".join(opts) if len(opts) > 1 else opts[0]